Ver código fonte

Fix some problems revealed by test262 suite (#1371)

Marko Lahma 2 anos atrás
pai
commit
a73f0a17d3

+ 1 - 1
Jint.Benchmark/EngineComparisonBenchmark.cs

@@ -47,7 +47,7 @@ public class EngineComparisonBenchmark
                 script = _dromaeoHelpers + Environment.NewLine + Environment.NewLine + script;
             }
             _files[fileName] = script;
-            _parsedScripts[fileName] = javaScriptParser.ParseScript(script);
+            _parsedScripts[fileName] = javaScriptParser.ParseScript(script, strict: true);
         }
     }
 

+ 1 - 1
Jint.Benchmark/SingleScriptBenchmark.cs

@@ -15,7 +15,7 @@ public abstract class SingleScriptBenchmark
     public void Setup()
     {
         _script = File.ReadAllText($"Scripts/{FileName}");
-        _parsedScript = Engine.PrepareScript(_script);
+        _parsedScript = Engine.PrepareScript(_script, strict: true);
     }
 
     [Benchmark]

+ 0 - 13
Jint.Tests.Test262/Test262Harness.settings.json

@@ -413,14 +413,6 @@
     "language/expressions/object/scope-meth-param-elem-var-open.js",
     "language/expressions/object/scope-meth-param-rest-elem-var-close.js",
     "language/expressions/object/scope-meth-param-rest-elem-var-open.js",
-    "language/expressions/postfix-decrement/operator-x-postfix-decrement-calls-putvalue-lhs-newvalue--1.js",
-    "language/expressions/postfix-decrement/operator-x-postfix-decrement-calls-putvalue-lhs-newvalue-.js",
-    "language/expressions/postfix-increment/operator-x-postfix-increment-calls-putvalue-lhs-newvalue--1.js",
-    "language/expressions/postfix-increment/operator-x-postfix-increment-calls-putvalue-lhs-newvalue-.js",
-    "language/expressions/prefix-decrement/operator-prefix-decrement-x-calls-putvalue-lhs-newvalue--1.js",
-    "language/expressions/prefix-decrement/operator-prefix-decrement-x-calls-putvalue-lhs-newvalue-.js",
-    "language/expressions/prefix-increment/operator-prefix-increment-x-calls-putvalue-lhs-newvalue--1.js",
-    "language/expressions/prefix-increment/operator-prefix-increment-x-calls-putvalue-lhs-newvalue-.js",
     "language/expressions/super/call-proto-not-ctor.js",
     "language/expressions/template-literal/tv-line-continuation.js",
     "language/function-code/eval-param-env-with-computed-key.js",
@@ -463,7 +455,6 @@
     "language/statements/for-of/dstr/obj-prop-elem-target-obj-literal-prop-ref-init.js",
     "language/statements/for-of/head-lhs-async-dot.js",
     "language/statements/for-of/head-lhs-async-escaped.js",
-    "language/statements/function/13.0-12-s.js",
     "language/statements/function/cptn-decl.js",
     "language/statements/function/dstr/ary-init-iter-get-err-array-prototype.js",
     "language/statements/function/dstr/dflt-ary-init-iter-get-err-array-prototype.js",
@@ -473,10 +464,6 @@
     "language/statements/function/scope-param-elem-var-open.js",
     "language/statements/function/scope-param-rest-elem-var-close.js",
     "language/statements/function/scope-param-rest-elem-var-open.js",
-    "language/statements/if/cptn-else-false-abrupt-empty.js",
-    "language/statements/if/cptn-else-true-abrupt-empty.js",
-    "language/statements/if/cptn-no-else-false.js",
-    "language/statements/if/cptn-no-else-true-abrupt-empty.js",
     "language/statements/variable/12.2.1-10-s.js",
     "language/statements/variable/12.2.1-17-s.js",
     "language/statements/variable/12.2.1-21-s.js",

+ 2 - 2
Jint/Engine.Ast.cs

@@ -15,12 +15,12 @@ public partial class Engine
     /// <remarks>
     /// Returned instance is reusable and thread-safe. You should prepare scripts only once and then reuse them.
     /// </remarks>
-    public static Script PrepareScript(string script, string? source = null)
+    public static Script PrepareScript(string script, string? source = null, bool strict = false)
     {
         var astAnalyzer = new AstAnalyzer();
         var options = ParserOptions.Default with { OnNodeCreated = astAnalyzer.NodeVisitor };
 
-        return new JavaScriptParser(options).ParseScript(script, source);
+        return new JavaScriptParser(options).ParseScript(script, source, strict);
     }
 
     /// <summary>

+ 4 - 7
Jint/Engine.cs

@@ -40,7 +40,7 @@ namespace Jint
         internal readonly IObjectConverter[]? _objectConverters;
         internal readonly Constraint[] _constraints;
         internal readonly bool _isDebugMode;
-        internal bool _isStrict;
+        internal readonly bool _isStrict;
         internal readonly IReferenceResolver _referenceResolver;
         internal readonly ReferencePool _referencePool;
         internal readonly ArgumentsInstancePool _argumentsInstancePool;
@@ -254,7 +254,7 @@ namespace Jint
                 ? _defaultParser
                 : new JavaScriptParser(parserOptions);
 
-            var script = parser.ParseScript(code, source);
+            var script = parser.ParseScript(code, source, _isStrict);
 
             return Evaluate(script);
         }
@@ -274,7 +274,7 @@ namespace Jint
                 ? _defaultParser
                 : new JavaScriptParser(parserOptions);
 
-            var script = parser.ParseScript(code, source);
+            var script = parser.ParseScript(code, source, _isStrict);
 
             return Execute(script);
         }
@@ -663,11 +663,9 @@ namespace Jint
             var ownsContext = _activeEvaluationContext is null;
             _activeEvaluationContext ??= new EvaluationContext(this);
 
-            var oldStrict = _isStrict;
             try
             {
-                _isStrict = strict;
-                using (new StrictModeScope(_isStrict))
+                using (new StrictModeScope(strict))
                 {
                     return callback();
                 }
@@ -678,7 +676,6 @@ namespace Jint
                 {
                     _activeEvaluationContext = null!;
                 }
-                _isStrict = oldStrict;
                 ResetConstraints();
                 _agent.ClearKeptObjects();
             }

+ 1 - 1
Jint/Native/Function/FunctionInstance.Dynamic.cs

@@ -139,7 +139,7 @@ public partial class FunctionInstance
             }
 
             JavaScriptParser parser = new(new ParserOptions { Tolerant = false });
-            function = (IFunction) parser.ParseScript(functionExpression).Body[0];
+            function = (IFunction) parser.ParseScript(functionExpression, source: null, _engine._isStrict).Body[0];
         }
         catch (ParserException ex)
         {

+ 1 - 2
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -42,7 +42,6 @@ namespace Jint.Native.Function
             _length = new LazyPropertyDescriptor(null, _ => JsNumber.Create(function.Initialize().Length), PropertyFlag.Configurable);
 
             if (!function.Strict
-                && !engine._isStrict
                 && function.Function is not ArrowFunctionExpression
                 && !function.Function.Generator)
             {
@@ -56,7 +55,7 @@ namespace Jint.Native.Function
         /// </summary>
         protected internal override JsValue Call(JsValue thisArgument, JsValue[] arguments)
         {
-            var strict = _thisMode == FunctionThisMode.Strict || _engine._isStrict;
+            var strict = _functionDefinition.Strict || _thisMode == FunctionThisMode.Strict;
             using (new StrictModeScope(strict, true))
             {
                 try

+ 5 - 1
Jint/Native/Global/GlobalObject.cs

@@ -796,13 +796,17 @@ namespace Jint.Native.Global
             return descriptor ?? PropertyDescriptor.Undefined;
         }
 
-        internal bool SetFromMutableBinding(Key property, JsValue value)
+        internal bool SetFromMutableBinding(Key property, JsValue value, bool strict)
         {
             // here we are called only from global environment record context
             // we can take some shortcuts to be faster
 
             if (!_properties!.TryGetValue(property, out var existingDescriptor))
             {
+                if (strict)
+                {
+                    ExceptionHelper.ThrowReferenceNameError(_realm, property.Name);
+                }
                 _properties[property] = new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable | PropertyFlag.MutableBinding);
                 return true;
             }

+ 1 - 1
Jint/Native/ShadowRealm/ShadowRealm.cs

@@ -51,7 +51,7 @@ public sealed class ShadowRealm : ObjectInstance
         Script script;
         try
         {
-            script = _parser.ParseScript(sourceText);
+            script = _parser.ParseScript(sourceText, source: null, _engine._isStrict);
         }
         catch (ParserException e)
         {

+ 2 - 2
Jint/Runtime/Environments/GlobalEnvironmentRecord.cs

@@ -165,7 +165,7 @@ namespace Jint.Runtime.Environments
                 if (_globalObject is not null)
                 {
                     // fast inlined path as we know we target global
-                    if (!_globalObject.SetFromMutableBinding(name, value) && strict)
+                    if (!_globalObject.SetFromMutableBinding(name, value, strict) && strict)
                     {
                         ExceptionHelper.ThrowTypeError(_engine.Realm);
                     }
@@ -188,7 +188,7 @@ namespace Jint.Runtime.Environments
                 if (_globalObject is not null)
                 {
                     // fast inlined path as we know we target global
-                    if (!_globalObject.SetFromMutableBinding(name.Key, value) && strict)
+                    if (!_globalObject.SetFromMutableBinding(name.Key, value, strict) && strict)
                     {
                         ExceptionHelper.ThrowTypeError(_engine.Realm);
                     }

+ 2 - 2
Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs

@@ -54,7 +54,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
             var privateScope = runningExecutionContext.PrivateEnvironment;
 
-            var thisMode = _function.Strict || engine._isStrict
+            var thisMode = _function.Strict
                 ? FunctionThisMode.Strict
                 : FunctionThisMode.Global;
 
@@ -96,7 +96,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
             var privateScope = runningExecutionContext.PrivateEnvironment;
 
-            var thisMode = _function.Strict || engine._isStrict
+            var thisMode = _function.Strict
                 ? FunctionThisMode.Strict
                 : FunctionThisMode.Global;
 

+ 41 - 42
Jint/Runtime/Interpreter/Statements/JintDoWhileStatement.cs

@@ -2,63 +2,62 @@ using Esprima.Ast;
 using Jint.Native;
 using Jint.Runtime.Interpreter.Expressions;
 
-namespace Jint.Runtime.Interpreter.Statements
+namespace Jint.Runtime.Interpreter.Statements;
+
+/// <summary>
+/// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.1
+/// </summary>
+internal sealed class JintDoWhileStatement : JintStatement<DoWhileStatement>
 {
-    /// <summary>
-    /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.1
-    /// </summary>
-    internal sealed class JintDoWhileStatement : JintStatement<DoWhileStatement>
+    private ProbablyBlockStatement _body;
+    private string? _labelSetName;
+    private JintExpression _test = null!;
+
+    public JintDoWhileStatement(DoWhileStatement statement) : base(statement)
     {
-        private ProbablyBlockStatement _body;
-        private string? _labelSetName;
-        private JintExpression _test = null!;
+    }
 
-        public JintDoWhileStatement(DoWhileStatement statement) : base(statement)
-        {
-        }
+    protected override void Initialize(EvaluationContext context)
+    {
+        _body = new ProbablyBlockStatement(_statement.Body);
+        _test = JintExpression.Build(_statement.Test);
+        _labelSetName = _statement.LabelSet?.Name;
+    }
 
-        protected override void Initialize(EvaluationContext context)
-        {
-            _body = new ProbablyBlockStatement(_statement.Body);
-            _test = JintExpression.Build(_statement.Test);
-            _labelSetName = _statement.LabelSet?.Name;
-        }
+    protected override Completion ExecuteInternal(EvaluationContext context)
+    {
+        JsValue v = JsValue.Undefined;
+        bool iterating;
 
-        protected override Completion ExecuteInternal(EvaluationContext context)
+        do
         {
-            JsValue v = JsValue.Undefined;
-            bool iterating;
+            var completion = _body.Execute(context);
+            if (!ReferenceEquals(completion.Value, null))
+            {
+                v = completion.Value;
+            }
 
-            do
+            if (completion.Type != CompletionType.Continue || context.Target != _labelSetName)
             {
-                var completion = _body.Execute(context);
-                if (!ReferenceEquals(completion.Value, null))
+                if (completion.Type == CompletionType.Break && (context.Target == null || context.Target == _labelSetName))
                 {
-                    v = completion.Value;
+                    return new Completion(CompletionType.Normal, v, _statement);
                 }
 
-                if (completion.Type != CompletionType.Continue || context.Target != _labelSetName)
+                if (completion.Type != CompletionType.Normal)
                 {
-                    if (completion.Type == CompletionType.Break && (context.Target == null || context.Target == _labelSetName))
-                    {
-                        return new Completion(CompletionType.Normal, v, _statement);
-                    }
-
-                    if (completion.Type != CompletionType.Normal)
-                    {
-                        return completion;
-                    }
+                    return completion;
                 }
+            }
 
-                if (context.DebugMode)
-                {
-                    context.Engine.DebugHandler.OnStep(_test._expression);
-                }
+            if (context.DebugMode)
+            {
+                context.Engine.DebugHandler.OnStep(_test._expression);
+            }
 
-                iterating = TypeConverter.ToBoolean(_test.GetValue(context));
-            } while (iterating);
+            iterating = TypeConverter.ToBoolean(_test.GetValue(context));
+        } while (iterating);
 
-            return new Completion(CompletionType.Normal, v, ((JintStatement) this)._statement);
-        }
+        return new Completion(CompletionType.Normal, v, ((JintStatement) this)._statement);
     }
 }

+ 25 - 29
Jint/Runtime/Interpreter/Statements/JintIfStatement.cs

@@ -1,42 +1,38 @@
 using Esprima.Ast;
+using Jint.Native;
 using Jint.Runtime.Interpreter.Expressions;
 
-namespace Jint.Runtime.Interpreter.Statements
+namespace Jint.Runtime.Interpreter.Statements;
+
+internal sealed class JintIfStatement : JintStatement<IfStatement>
 {
-    internal sealed class JintIfStatement : JintStatement<IfStatement>
+    private ProbablyBlockStatement _statementConsequent;
+    private JintExpression _test = null!;
+    private ProbablyBlockStatement? _alternate;
+
+    public JintIfStatement(IfStatement statement) : base(statement)
     {
-        private ProbablyBlockStatement _statementConsequent;
-        private JintExpression _test = null!;
-        private ProbablyBlockStatement? _alternate;
+    }
 
-        public JintIfStatement(IfStatement statement) : base(statement)
-        {
-        }
+    protected override void Initialize(EvaluationContext context)
+    {
+        _statementConsequent = new ProbablyBlockStatement(_statement.Consequent);
+        _test = JintExpression.Build(_statement.Test);
+        _alternate = _statement.Alternate != null ? new ProbablyBlockStatement(_statement.Alternate) : null;
+    }
 
-        protected override void Initialize(EvaluationContext context)
+    protected override Completion ExecuteInternal(EvaluationContext context)
+    {
+        Completion result = default;
+        if (TypeConverter.ToBoolean(_test.GetValue(context)))
         {
-            _statementConsequent = new ProbablyBlockStatement(_statement.Consequent);
-            _test = JintExpression.Build(_statement.Test);
-            _alternate = _statement.Alternate != null ? new ProbablyBlockStatement(_statement.Alternate) : null;
+            result = _statementConsequent.Execute(context);
         }
-
-        protected override Completion ExecuteInternal(EvaluationContext context)
+        else if (_alternate != null)
         {
-            Completion result;
-            if (TypeConverter.ToBoolean(_test.GetValue(context)))
-            {
-                result = _statementConsequent.Execute(context);
-            }
-            else if (_alternate != null)
-            {
-                result = _alternate.Value.Execute(context);
-            }
-            else
-            {
-                result = new Completion(CompletionType.Normal, null!, _statement);
-            }
-
-            return result;
+            result = _alternate.Value.Execute(context);
         }
+
+        return result.UpdateEmpty(JsValue.Undefined);
     }
 }