Przeglądaj źródła

Fixing Global member configurability

Sebastien Ros 11 lat temu
rodzic
commit
ce52901d34

+ 1 - 0
Jint.Tests.Ecma/Ecma/10.4.cs

@@ -2,6 +2,7 @@ using Xunit;
 
 namespace Jint.Tests.Ecma
 {
+    [Trait("Category", "Pass")]
     public class Test_10_4 : EcmaTest
     {
         [Fact]

+ 1 - 0
Jint.Tests.Ecma/Ecma/15.4.4.1.cs

@@ -2,6 +2,7 @@ using Xunit;
 
 namespace Jint.Tests.Ecma
 {
+    [Trait("Category", "Pass")]
     public class Test_15_4_4_1 : EcmaTest
     {
         [Fact]

+ 1 - 0
Jint.Tests.Ecma/Ecma/8.5.1.cs

@@ -2,6 +2,7 @@ using Xunit;
 
 namespace Jint.Tests.Ecma
 {
+    [Trait("Category", "Pass")]
     public class Test_8_5_1 : EcmaTest
     {
         [Fact(Skip = "C# can't distinguish 1.797693134862315808e+308 and 1.797693134862315708145274237317e+308")]

+ 9 - 0
Jint/DeclarationBindingType.cs

@@ -0,0 +1,9 @@
+namespace Jint
+{
+    public enum DeclarationBindingType
+    {
+        GlobalCode,
+        FunctionCode,
+        EvalCode
+    }
+}

+ 56 - 13
Jint/Engine.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using Jint.Native;
+using Jint.Native.Argument;
 using Jint.Native.Array;
 using Jint.Native.Boolean;
 using Jint.Native.Date;
@@ -177,6 +178,8 @@ namespace Jint
         {
             using (new StrictModeScope(Options.IsStrict() || program.Strict))
             {
+                DeclarationBindingInstantiation(DeclarationBindingType.GlobalCode, program.FunctionDeclarations, program.VariableDeclarations, null, null);
+
                 var result = _statements.ExecuteProgram(program);
                 if (result.Type == Completion.Throw)
                 {
@@ -485,16 +488,35 @@ namespace Jint
             return GetValue(Global.Get(propertyName));
         }
 
-        public void FunctionDeclarationBindings(IFunctionScope functionScope, LexicalEnvironment localEnv, bool configurableBindings, bool strict)
+        //  http://www.ecma-international.org/ecma-262/5.1/#sec-10.5
+        public void DeclarationBindingInstantiation(DeclarationBindingType declarationBindingType, IList<FunctionDeclaration> functionDeclarations, IList<VariableDeclaration> variableDeclarations, FunctionInstance functionInstance, object[] arguments)
         {
-            // Declaration Binding Instantiation http://www.ecma-international.org/ecma-262/5.1/#sec-10.5
-            var env = localEnv.Record;
+            var env = ExecutionContext.VariableEnvironment.Record;
+            bool configurableBindings = declarationBindingType == DeclarationBindingType.EvalCode;
+            var strict = StrictModeScope.IsStrictModeCode;
 
-            // process all function declarations in the current parser scope
-            foreach (var functionDeclaration in functionScope.FunctionDeclarations)
+            if (declarationBindingType == DeclarationBindingType.FunctionCode)
             {
-                var fn = functionDeclaration.Id.Name;
-                var fo = Function.CreateFunctionObject(functionDeclaration);
+                var argCount = arguments.Length;
+                var n = 0;
+                foreach (var argName in functionInstance.FormalParameters)
+                {
+                    n++;
+                    var v = n > argCount ? Undefined.Instance : arguments[n - 1];
+                    var argAlreadyDeclared = env.HasBinding(argName);
+                    if (!argAlreadyDeclared)
+                    {
+                        env.CreateMutableBinding(argName);
+                    }
+
+                    env.SetMutableBinding(argName, v, strict);
+                }
+            }
+
+            foreach (var f in functionDeclarations)
+            {
+                var fn = f.Id.Name;
+                var fo = Function.CreateFunctionObject(f);
                 var funcAlreadyDeclared = env.HasBinding(fn);
                 if (!funcAlreadyDeclared)
                 {
@@ -506,7 +528,7 @@ namespace Jint
                     {
                         var go = Global;
                         var existingProp = go.GetProperty(fn);
-                        if (existingProp.ConfigurableIsSet)
+                        if (existingProp.ConfigurableIsSetToTrue)
                         {
                             go.DefineOwnProperty(fn,
                                                  new DataDescriptor(Undefined.Instance)
@@ -528,12 +550,34 @@ namespace Jint
 
                 env.SetMutableBinding(fn, fo, strict);
             }
-        }
 
-        public void VariableDeclarationBinding(IEnumerable<VariableDeclaration> declarations, EnvironmentRecord env, bool configurableBindings, bool strict)
-        {
+            var argumentsAlreadyDeclared = env.HasBinding("arguments");
+
+            if (declarationBindingType == DeclarationBindingType.FunctionCode && !argumentsAlreadyDeclared)
+            {
+                var argsObj = ArgumentsInstance.CreateArgumentsObject(this, functionInstance, functionInstance.FormalParameters, arguments, env, strict);
+
+                if (strict)
+                {
+                    var declEnv = env as DeclarativeEnvironmentRecord;
+
+                    if (declEnv == null)
+                    {
+                        throw new ArgumentException();
+                    }
+
+                    declEnv.CreateImmutableBinding("arguments");
+                    declEnv.InitializeImmutableBinding("arguments", argsObj);
+                }
+                else
+                {
+                    env.CreateMutableBinding("arguments");
+                    env.SetMutableBinding("arguments", argsObj, false);
+                }
+            }
+
             // process all variable declarations in the current parser scope
-            foreach (var d in declarations.SelectMany(x => x.Declarations))
+            foreach (var d in variableDeclarations.SelectMany(x => x.Declarations))
             {
                 var dn = d.Id.Name;
                 var varAlreadyDeclared = env.HasBinding(dn);
@@ -544,6 +588,5 @@ namespace Jint
                 }
             }
         }
-
     }
 }

+ 62 - 0
Jint/EvalCodeScope.cs

@@ -0,0 +1,62 @@
+using System;
+
+namespace Jint
+{
+    public class EvalCodeScope : IDisposable
+    {
+        private readonly bool _eval;
+        private readonly bool _force;
+        private readonly int _forcedRefCount;
+
+        [ThreadStatic] 
+        private static int _refCount;
+
+        public EvalCodeScope(bool eval = true, bool force = false)
+        {
+            _eval = eval;
+            _force = force;
+
+            if (_force)
+            {
+                _forcedRefCount = _refCount;
+                _refCount = 0;
+            }
+
+            if (_eval)
+            {
+                _refCount++;
+            }
+
+        }
+
+        public void Dispose()
+        {
+            if (_eval)
+            {
+                _refCount--;
+            }
+
+            if (_force)
+            {
+                _refCount = _forcedRefCount;
+            } 
+        }
+
+        public static bool IsEvalCode
+        {
+            get { return _refCount > 0; }
+        }
+
+        public static int RefCount
+        {
+            get
+            {
+                return _refCount;
+            }
+            set
+            {
+                _refCount = value;
+            }
+        }
+    }
+}

+ 2 - 0
Jint/Jint.csproj

@@ -36,6 +36,8 @@
     <!-- A reference to the entire .NET Framework is automatically included -->
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="DeclarationBindingType.cs" />
+    <Compile Include="EvalCodeScope.cs" />
     <Compile Include="Engine.cs" />
     <Compile Include="Native\Array\ArrayConstructor.cs" />
     <Compile Include="Native\Array\ArrayInstance.cs" />

+ 33 - 9
Jint/Native/Function/EvalFunctionInstance.cs

@@ -1,4 +1,5 @@
-using Jint.Native.Object;
+using System.Net.NetworkInformation;
+using Jint.Native.Object;
 using Jint.Parser;
 using Jint.Runtime;
 using Jint.Runtime.Environments;
@@ -24,15 +25,38 @@ namespace Jint.Native.Function
                 var program = parser.Parse(code);
                 using (new StrictModeScope(program.Strict))
                 {
-                    var result = _engine.ExecuteStatement(program);
-
-                    if (result.Type == Completion.Throw)
-                    {
-                        throw new JavaScriptException(result.Value);
-                    }
-                    else
+                    using (new EvalCodeScope())
                     {
-                        return result.Value ?? Undefined.Instance;
+                        LexicalEnvironment strictVarEnv = null;
+
+                        try
+                        {
+                            if (StrictModeScope.IsStrictModeCode)
+                            {
+                                strictVarEnv = LexicalEnvironment.NewDeclarativeEnvironment(Engine, Engine.ExecutionContext.LexicalEnvironment);
+                                Engine.EnterExecutionContext(strictVarEnv, strictVarEnv, Engine.ExecutionContext.ThisBinding);
+                            }
+
+                            Engine.DeclarationBindingInstantiation(DeclarationBindingType.EvalCode, program.FunctionDeclarations, program.VariableDeclarations, this, arguments);
+                            
+                            var result = _engine.ExecuteStatement(program);
+
+                            if (result.Type == Completion.Throw)
+                            {
+                                throw new JavaScriptException(result.Value);
+                            }
+                            else
+                            {
+                                return result.Value ?? Undefined.Instance;
+                            }
+                        }
+                        finally
+                        {
+                            if (strictVarEnv != null)
+                            {
+                                Engine.LeaveExecutionContext();
+                            }
+                        }
                     }
                 }
             }

+ 3 - 55
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -61,6 +61,8 @@ namespace Jint.Native.Function
 
             using (new StrictModeScope(Strict, true))
             {
+                var strict = StrictModeScope.IsStrictModeCode;
+
                 // setup new execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.3
                 if (StrictModeScope.IsStrictModeCode)
                 {
@@ -83,61 +85,7 @@ namespace Jint.Native.Function
 
                 Engine.EnterExecutionContext(localEnv, localEnv, thisBinding);
 
-                // Declaration Binding Instantiation http://www.ecma-international.org/ecma-262/5.1/#sec-10.5
-                var env = localEnv.Record;
-                var configurableBindings = false;
-
-                //if (/* todo: if code is eval code */)
-                //{
-                //    configurableBindings = true;
-                //}
-
-                var argCount = arguments.Length;
-                var n = 0;
-                foreach (var argName in FormalParameters)
-                {
-                    n++;
-                    var v = n > argCount ? Undefined.Instance : arguments[n - 1];
-                    var argAlreadyDeclared = env.HasBinding(argName);
-                    if (!argAlreadyDeclared)
-                    {
-                        env.CreateMutableBinding(argName);
-                    }
-
-                    env.SetMutableBinding(argName, v, Strict);
-                }
-
-                Engine.FunctionDeclarationBindings(_functionDeclaration, localEnv, true, Strict);
-
-                var argumentsAlreadyDeclared = env.HasBinding("arguments");
-
-                if (!argumentsAlreadyDeclared)
-                {
-                    var argsObj = ArgumentsInstance.CreateArgumentsObject(Engine, this, FormalParameters, arguments, env,
-                        Strict);
-
-                    if (Strict)
-                    {
-                        var declEnv = env as DeclarativeEnvironmentRecord;
-
-                        if (declEnv == null)
-                        {
-                            throw new ArgumentException();
-                        }
-
-                        declEnv.CreateImmutableBinding("arguments");
-                        declEnv.InitializeImmutableBinding("arguments", argsObj);
-                    }
-                    else
-                    {
-                        env.CreateMutableBinding("arguments");
-                        env.SetMutableBinding("arguments", argsObj, false);
-                    }
-                }
-
-                // process all variable declarations in the current parser scope
-                Engine.VariableDeclarationBinding(_functionDeclaration.VariableDeclarations, env, configurableBindings,
-                    Strict);
+                Engine.DeclarationBindingInstantiation(DeclarationBindingType.FunctionCode, _functionDeclaration.FunctionDeclarations, _functionDeclaration.VariableDeclarations, this, arguments);
 
                 var result = Engine.ExecuteStatement(_functionDeclaration.Body);
 

+ 4 - 4
Jint/Native/Object/ObjectConstructor.cs

@@ -236,7 +236,7 @@ namespace Jint.Native.Object
 
             foreach (var prop in o.Properties)
             {
-                if (prop.Value.ConfigurableIsSet)
+                if (prop.Value.ConfigurableIsSetToTrue)
                 {
                     prop.Value.Configurable = false;
                 }
@@ -271,7 +271,7 @@ namespace Jint.Native.Object
                         datadesc.Writable = false;
                     }
                 }
-                if (prop.ConfigurableIsSet)
+                if (prop.ConfigurableIsSetToTrue)
                 {
                     prop.Configurable = false;
                 }
@@ -310,7 +310,7 @@ namespace Jint.Native.Object
 
             foreach (var prop in o.Properties)
             {
-                if (prop.Value.ConfigurableIsSet)
+                if (prop.Value.ConfigurableIsSetToTrue)
                 {
                     return false;
                 }
@@ -343,7 +343,7 @@ namespace Jint.Native.Object
                         return false;
                     }
                 }
-                if (prop.Value.ConfigurableIsSet)
+                if (prop.Value.ConfigurableIsSetToTrue)
                 {
                     return false;
                 }

+ 7 - 7
Jint/Native/Object/ObjectInstance.cs

@@ -269,7 +269,7 @@ namespace Jint.Native.Object
                 return true;
             }
 
-            if (desc.ConfigurableIsSet)
+            if (desc.ConfigurableIsSetToTrue)
             {
                 Properties.Remove(propertyName);
                 return true;
@@ -391,9 +391,9 @@ namespace Jint.Native.Object
 
             // todo: if desc and current are the same, return true
 
-            if (!current.ConfigurableIsSet)
+            if (current.ConfigurableIsSetToFalse)
             {
-                if (desc.ConfigurableIsSet)
+                if (desc.ConfigurableIsSetToTrue)
                 {
                     if (throwOnError)
                     {
@@ -403,7 +403,7 @@ namespace Jint.Native.Object
                     return false;
                 }
 
-                if (desc.EnumerableIsSet != current.EnumerableIsSet)
+                if (desc.Enumerable.HasValue && desc.Enumerable.Value != current.Enumerable.Value)
                 {
                     if (throwOnError)
                     {
@@ -421,7 +421,7 @@ namespace Jint.Native.Object
 
             if (current.IsDataDescriptor() != desc.IsDataDescriptor())
             {
-                if (!current.ConfigurableIsSet)
+                if (!current.ConfigurableIsSetToTrue)
                 {
                     if (throwOnError)
                     {
@@ -441,7 +441,7 @@ namespace Jint.Native.Object
                 var cd = current.As<DataDescriptor>();
                 var dd = current.As<DataDescriptor>();
 
-                if (!current.ConfigurableIsSet)
+                if (!current.ConfigurableIsSetToTrue)
                 {
                     if (!cd.WritableIsSet && dd.WritableIsSet)
                     {
@@ -464,7 +464,7 @@ namespace Jint.Native.Object
                 var ca = current.As<AccessorDescriptor>();
                 var da = desc.As<AccessorDescriptor>();
 
-                if (!current.ConfigurableIsSet)
+                if (!current.ConfigurableIsSetToTrue)
                 {
                     if ( (da.Set != null && da.Set != ca.Set)
                         || (da.Get != null && da.Get != ca.Get))

+ 10 - 8
Jint/Runtime/Descriptors/DataDescriptor.cs

@@ -2,18 +2,20 @@
 {
     public class DataDescriptor : PropertyDescriptor
     {
-        public DataDescriptor(object value)
+        public DataDescriptor(object value) : this(value, true, null, null)
         {
-            Value = value;
-            Writable = true;
         }
 
-        public DataDescriptor(DataDescriptor d)
+        public DataDescriptor(DataDescriptor d) : this(d.Value, d.Writable, d.Enumerable, d.Configurable)
         {
-            Value = d.Value;
-            Writable = d.Writable;
-            Configurable = d.Configurable;
-            Enumerable = d.Enumerable;
+        }
+
+        public DataDescriptor(object value, bool? writable, bool? enumerable, bool? configurable)
+        {
+            Value = value;
+            Writable = writable;
+            Enumerable = enumerable;
+            Configurable = configurable;
         }
 
         public object Value { get; set; }

+ 7 - 2
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -29,11 +29,16 @@ namespace Jint.Runtime.Descriptors
         /// </summary>
         public bool? Configurable { get; set; }
 
-        public bool ConfigurableIsSet
+        public bool ConfigurableIsSetToTrue
         {
             get { return Configurable.HasValue && Configurable.Value; }
         }
 
+        public bool ConfigurableIsSetToFalse
+        {
+            get { return Configurable.HasValue && !Configurable.Value; }
+        }
+
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.10.1
         /// </summary>
@@ -142,7 +147,7 @@ namespace Jint.Runtime.Descriptors
             }
 
             obj.DefineOwnProperty("enumerable", new DataDescriptor(desc.EnumerableIsSet) { Writable = true, Enumerable = true, Configurable = true }, false);
-            obj.DefineOwnProperty("configurable", new DataDescriptor(desc.ConfigurableIsSet) { Writable = true, Enumerable = true, Configurable = true }, false);
+            obj.DefineOwnProperty("configurable", new DataDescriptor(desc.ConfigurableIsSetToTrue) { Writable = true, Enumerable = true, Configurable = true }, false);
 
             return obj;
         }

+ 1 - 8
Jint/Runtime/Environments/ObjectEnvironmentRecord.cs

@@ -33,14 +33,7 @@ namespace Jint.Runtime.Environments
         /// <param name="configurable"></param>
         public override void CreateMutableBinding(string name, bool configurable = true)
         {
-            var property = new DataDescriptor(Undefined.Instance)
-                {
-                    Writable = true,
-                    Enumerable = true,
-                    Configurable = configurable
-                };
-
-            _bindingObject.DefineOwnProperty(name, property, true);
+            _bindingObject.DefineOwnProperty(name, new DataDescriptor(Undefined.Instance, true, true, configurable), true);
         }
 
         public override void SetMutableBinding(string name, object value, bool strict)

+ 0 - 3
Jint/Runtime/StatementInterpreter.cs

@@ -456,9 +456,6 @@ namespace Jint.Runtime
 
         public Completion ExecuteProgram(Program program)
         {
-            _engine.FunctionDeclarationBindings(program, _engine.ExecutionContext.LexicalEnvironment, true, program.Strict);
-            _engine.VariableDeclarationBinding(program.VariableDeclarations, _engine.ExecutionContext.LexicalEnvironment.Record, true, program.Strict);
-
             return ExecuteStatementList(program.Body);
         }