Преглед изворни кода

Slim down Completion and ExpressionResult struct sizes (#1270)

Marko Lahma пре 2 година
родитељ
комит
3e0902c2e6
44 измењених фајлова са 145 додато и 107 уклоњено
  1. 1 2
      Jint.Tests/Runtime/Debugger/BreakPointTests.cs
  2. 6 2
      Jint.Tests/Runtime/EngineLimitTests.cs
  3. 1 2
      Jint.Tests/Runtime/NullPropagation.cs
  4. 3 1
      Jint/Engine.Modules.cs
  5. 2 2
      Jint/Engine.cs
  6. 18 2
      Jint/EsprimaExtensions.cs
  7. 1 1
      Jint/Native/Error/ErrorConstructor.cs
  8. 2 2
      Jint/Native/Function/ClassDefinition.cs
  9. 22 15
      Jint/Runtime/Completion.cs
  10. 1 1
      Jint/Runtime/Interpreter/EvaluationContext.cs
  11. 2 2
      Jint/Runtime/Interpreter/Expressions/BindingPatternAssignmentExpression.cs
  12. 1 1
      Jint/Runtime/Interpreter/Expressions/JintAssignmentExpression.cs
  13. 2 2
      Jint/Runtime/Interpreter/Expressions/JintConstantExpression.cs
  14. 18 11
      Jint/Runtime/Interpreter/Expressions/JintExpression.cs
  15. 1 1
      Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs
  16. 3 3
      Jint/Runtime/Interpreter/Expressions/JintIdentifierExpression.cs
  17. 2 2
      Jint/Runtime/Interpreter/Expressions/JintLiteralExpression.cs
  18. 1 1
      Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs
  19. 1 1
      Jint/Runtime/Interpreter/Expressions/JintNewExpression.cs
  20. 2 2
      Jint/Runtime/Interpreter/Expressions/JintSpreadExpression.cs
  21. 2 2
      Jint/Runtime/Interpreter/Expressions/JintThisExpression.cs
  22. 2 2
      Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs
  23. 2 2
      Jint/Runtime/Interpreter/Expressions/NullishCoalescingExpression.cs
  24. 2 2
      Jint/Runtime/Interpreter/JintFunctionDefinition.cs
  25. 12 8
      Jint/Runtime/Interpreter/JintStatementList.cs
  26. 1 1
      Jint/Runtime/Interpreter/Statements/JintBreakStatement.cs
  27. 1 1
      Jint/Runtime/Interpreter/Statements/JintClassDeclarationStatement.cs
  28. 1 1
      Jint/Runtime/Interpreter/Statements/JintContinueStatement.cs
  29. 1 1
      Jint/Runtime/Interpreter/Statements/JintDebuggerStatement.cs
  30. 1 1
      Jint/Runtime/Interpreter/Statements/JintDoWhileStatement.cs
  31. 1 1
      Jint/Runtime/Interpreter/Statements/JintEmptyStatement.cs
  32. 1 1
      Jint/Runtime/Interpreter/Statements/JintExpressionStatement.cs
  33. 4 4
      Jint/Runtime/Interpreter/Statements/JintForInForOfStatement.cs
  34. 1 1
      Jint/Runtime/Interpreter/Statements/JintIfStatement.cs
  35. 1 1
      Jint/Runtime/Interpreter/Statements/JintImportDeclaration.cs
  36. 1 1
      Jint/Runtime/Interpreter/Statements/JintLabeledStatement.cs
  37. 1 1
      Jint/Runtime/Interpreter/Statements/JintReturnStatement.cs
  38. 6 6
      Jint/Runtime/Interpreter/Statements/JintStatement.cs
  39. 3 3
      Jint/Runtime/Interpreter/Statements/JintSwitchBlock.cs
  40. 1 1
      Jint/Runtime/Interpreter/Statements/JintThrowStatement.cs
  41. 1 3
      Jint/Runtime/Interpreter/Statements/JintVariableDeclaration.cs
  42. 2 2
      Jint/Runtime/Interpreter/Statements/JintWhileStatement.cs
  43. 1 1
      Jint/Runtime/Interpreter/Statements/JintWithStatement.cs
  44. 6 4
      Jint/Runtime/JavaScriptException.cs

+ 1 - 2
Jint.Tests/Runtime/Debugger/BreakPointTests.cs

@@ -1,5 +1,4 @@
-using Esprima;
-using Jint.Runtime.Debugger;
+using Jint.Runtime.Debugger;
 
 namespace Jint.Tests.Runtime.Debugger
 {

+ 6 - 2
Jint.Tests/Runtime/EngineLimitTests.cs

@@ -1,3 +1,5 @@
+#if !NETFRAMEWORK
+
 using System.Text;
 
 namespace Jint.Tests.Runtime;
@@ -8,9 +10,9 @@ public class EngineLimitTests
     public void ShouldAllowReasonableCallStackDepth()
     {
 #if RELEASE
-        const int FunctionNestingCount = 350;
+        const int FunctionNestingCount = 650;
 #else
-        const int FunctionNestingCount = 170;
+        const int FunctionNestingCount = 340;
 #endif
 
         // generate call tree
@@ -41,3 +43,5 @@ public class EngineLimitTests
         Assert.Equal(123, engine.Evaluate("func1(123);").AsNumber());
     }
 }
+
+#endif

+ 1 - 2
Jint.Tests/Runtime/NullPropagation.cs

@@ -1,5 +1,4 @@
-using Esprima;
-using Jint.Native;
+using Jint.Native;
 using Jint.Runtime;
 using Jint.Runtime.Interop;
 using Jint.Runtime.References;

+ 3 - 1
Jint/Engine.Modules.cs

@@ -1,4 +1,5 @@
 using Esprima;
+using Esprima.Ast;
 using Jint.Native;
 using Jint.Native.Object;
 using Jint.Native.Promise;
@@ -149,7 +150,8 @@ namespace Jint
             }
             else if (promise.State == PromiseState.Rejected)
             {
-                ExceptionHelper.ThrowJavaScriptException(this, promise.Value, new Completion(CompletionType.Throw, promise.Value, null, Location.From(new Position(), new Position(), specifier)));
+                var node = EsprimaExtensions.CreateLocationNode(Location.From(new Position(), new Position(), specifier));
+                ExceptionHelper.ThrowJavaScriptException(this, promise.Value, new Completion(CompletionType.Throw, promise.Value, null, node));
             }
             else if (promise.State != PromiseState.Fulfilled)
             {

+ 2 - 2
Jint/Engine.cs

@@ -735,9 +735,9 @@ namespace Jint
         /// <summary>
         /// Gets the last evaluated <see cref="Node"/>.
         /// </summary>
-        internal Node? GetLastSyntaxNode()
+        internal SyntaxElement? GetLastSyntaxElement()
         {
-            return _activeEvaluationContext?.LastSyntaxNode;
+            return _activeEvaluationContext?.LastSyntaxElement;
         }
 
         /// <summary>

+ 18 - 2
Jint/EsprimaExtensions.cs

@@ -52,7 +52,7 @@ namespace Jint
             {
                 key = JsValue.Undefined;
             }
-            return new Completion(CompletionType.Normal, key, expression.Location);
+            return new Completion(CompletionType.Normal, key, expression);
         }
 
         private static Completion TryGetComputedPropertyKey<T>(T expression, Engine engine)
@@ -75,7 +75,7 @@ namespace Jint
                 return JintExpression.Build(engine, expression).GetValue(context!);
             }
 
-            return new Completion(CompletionType.Normal, JsValue.Undefined, expression.Location);
+            return new Completion(CompletionType.Normal, JsValue.Undefined, expression);
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -429,5 +429,21 @@ namespace Jint
         }
 
         internal readonly record struct Record(JsValue Key, ScriptFunctionInstance Closure);
+
+        /// <summary>
+        /// Creates a dummy node that can be used when only location available and node is required.
+        /// </summary>
+        internal static SyntaxElement CreateLocationNode(in Location location)
+        {
+            return new MinimalSyntaxElement(location);
+        }
+    }
+
+    internal sealed class MinimalSyntaxElement : SyntaxElement
+    {
+        public MinimalSyntaxElement(in Location location)
+        {
+            Location = location;
+        }
     }
 }

+ 1 - 1
Jint/Native/Error/ErrorConstructor.cs

@@ -68,7 +68,7 @@ namespace Jint.Native.Error
 
             JsValue BuildStackString()
             {
-                var lastSyntaxNode = _engine.GetLastSyntaxNode();
+                var lastSyntaxNode = _engine.GetLastSyntaxElement();
                 if (lastSyntaxNode == null)
                     return Undefined;
 

+ 2 - 2
Jint/Native/Function/ClassDefinition.cs

@@ -198,7 +198,7 @@ namespace Jint.Native.Function
 
             engine.UpdatePrivateEnvironment(outerPrivateEnvironment);
 
-            return new Completion(CompletionType.Normal, F, _body.Location);
+            return new Completion(CompletionType.Normal, F, _body);
         }
 
         /// <summary>
@@ -247,7 +247,7 @@ namespace Jint.Native.Function
                 obj.DefinePropertyOrThrow(propKey, propDesc);
             }
 
-            return new Completion(CompletionType.Normal, obj, method.Location);
+            return new Completion(CompletionType.Normal, obj, method);
         }
     }
 }

+ 22 - 15
Jint/Runtime/Completion.cs

@@ -1,11 +1,13 @@
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using Esprima;
+using Esprima.Ast;
 using Jint.Native;
 using Jint.Runtime.Interpreter.Expressions;
 
 namespace Jint.Runtime
 {
-    public enum CompletionType
+    public enum CompletionType : byte
     {
         Normal = 0,
         Return = 1,
@@ -17,23 +19,29 @@ namespace Jint.Runtime
     /// <summary>
     /// https://tc39.es/ecma262/#sec-completion-record-specification-type
     /// </summary>
+    [StructLayout(LayoutKind.Auto)]
     public readonly struct Completion
     {
-        internal Completion(CompletionType type, JsValue value, string? target, in Location location)
+        internal static readonly Node _emptyNode = new Identifier("");
+        private static readonly Completion _emptyCompletion = new(CompletionType.Normal, null!, _emptyNode);
+
+        internal readonly SyntaxElement _source;
+
+        internal Completion(CompletionType type, JsValue value, string? target, SyntaxElement source)
         {
             Type = type;
             Value = value;
             Target = target;
-            Location = location;
+            _source = source;
         }
 
-        public Completion(CompletionType type, JsValue value, in Location location)
-            : this(type, value, null, location)
+        public Completion(CompletionType type, JsValue value, SyntaxElement source)
+            : this(type, value, null, source)
         {
         }
 
-        public Completion(CompletionType type, string target, in Location location)
-            : this(type, null!, target, location)
+        public Completion(CompletionType type, string target, SyntaxElement source)
+            : this(type, null!, target, source)
         {
         }
 
@@ -43,19 +51,18 @@ namespace Jint.Runtime
             // this cast protects us from getting from type
             Value = (JsValue) result.Value;
             Target = null;
-            Location = result.Location;
+            _source = result._source;
         }
 
         public readonly CompletionType Type;
         public readonly JsValue Value;
         public readonly string? Target;
-        public readonly Location Location;
+        public ref readonly Location Location => ref _source.Location;
 
-        public static Completion Normal(JsValue value, in Location location)
-            => new Completion(CompletionType.Normal, value, location);
+        public static Completion Normal(JsValue value, Node source)
+            => new Completion(CompletionType.Normal, value, source);
 
-        public static Completion Empty()
-            => new Completion(CompletionType.Normal, null!, default);
+        public static ref readonly Completion Empty() => ref _emptyCompletion;
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public JsValue GetValueOrDefault()
@@ -79,7 +86,7 @@ namespace Jint.Runtime
                 return this;
             }
 
-            return new Completion(Type, value, Target, Location);
+            return new Completion(Type, value, Target, _source);
         }
     }
-}
+}

+ 1 - 1
Jint/Runtime/Interpreter/EvaluationContext.cs

@@ -19,7 +19,7 @@ namespace Jint.Runtime.Interpreter
         public Completion ResumedCompletion { get; }
         public bool DebugMode { get; }
 
-        public Node LastSyntaxNode { get; set; } = null!;
+        public SyntaxElement LastSyntaxElement { get; set; } = null!;
         public bool OperatorOverloadingAllowed { get; }
     }
 }

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

@@ -285,7 +285,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 }
             }
 
-            return new Completion(CompletionType.Normal, JsValue.Undefined, pattern.Location);
+            return new Completion(CompletionType.Normal, JsValue.Undefined, pattern);
         }
 
         private static Completion HandleObjectPattern(
@@ -398,7 +398,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 }
             }
 
-            return new Completion(CompletionType.Normal, JsValue.Undefined, pattern.Location);
+            return new Completion(CompletionType.Normal, JsValue.Undefined, pattern);
         }
 
         private static void AssignToReference(

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintAssignmentExpression.cs

@@ -415,7 +415,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                     }
 
                     environmentRecord.SetMutableBinding(left._expressionName, rval, strict);
-                    return new Completion(CompletionType.Normal, rval, default);
+                    return ExpressionResult.Normal(rval, completion._source);
                 }
 
                 return null;

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

@@ -18,9 +18,9 @@ namespace Jint.Runtime.Interpreter.Expressions
         public override Completion GetValue(EvaluationContext context)
         {
             // need to notify correct node when taking shortcut
-            context.LastSyntaxNode = _expression;
+            context.LastSyntaxElement = _expression;
 
-            return Completion.Normal(_value, _expression.Location);
+            return Completion.Normal(_value, _expression);
         }
 
         protected override ExpressionResult EvaluateInternal(EvaluationContext context) => NormalCompletion(_value);

+ 18 - 11
Jint/Runtime/Interpreter/Expressions/JintExpression.cs

@@ -1,7 +1,7 @@
 using System.Diagnostics;
 using System.Numerics;
 using System.Runtime.CompilerServices;
-using Esprima;
+using System.Runtime.InteropServices;
 using Esprima.Ast;
 using Jint.Native;
 using Jint.Native.Array;
@@ -14,24 +14,31 @@ namespace Jint.Runtime.Interpreter.Expressions
     /// <summary>
     /// Adapter to get different types of results, including Reference which is not a JsValue.
     /// </summary>
+    [StructLayout(LayoutKind.Auto)]
     internal readonly struct ExpressionResult
     {
+        internal readonly SyntaxElement _source;
+
         public readonly ExpressionCompletionType Type;
-        public readonly Location Location;
         public readonly object Value;
 
-        public ExpressionResult(ExpressionCompletionType type, object value, in Location location)
+        public ExpressionResult(ExpressionCompletionType type, object value, SyntaxElement source)
         {
             Type = type;
             Value = value;
-            Location = location;
+            _source = source;
         }
 
         public bool IsAbrupt() => Type != ExpressionCompletionType.Normal && Type != ExpressionCompletionType.Reference;
 
         public static implicit operator ExpressionResult(in Completion result)
         {
-            return new ExpressionResult((ExpressionCompletionType) result.Type, result.Value, result.Location);
+            return new ExpressionResult((ExpressionCompletionType) result.Type, result.Value, result._source);
+        }
+
+        public static ExpressionResult? Normal(JsValue value, SyntaxElement source)
+        {
+            return new ExpressionResult(ExpressionCompletionType.Normal, value, source);
         }
     }
 
@@ -66,17 +73,17 @@ namespace Jint.Runtime.Interpreter.Expressions
             var result = Evaluate(context);
             if (result.Type != ExpressionCompletionType.Reference)
             {
-                return new Completion((CompletionType) result.Type, (JsValue) result.Value, result.Location);
+                return new Completion((CompletionType) result.Type, (JsValue) result.Value, result._source);
             }
 
             var jsValue = context.Engine.GetValue((Reference) result.Value, true);
-            return new Completion(CompletionType.Normal, jsValue, null, _expression.Location);
+            return new Completion(CompletionType.Normal, jsValue, null, _expression);
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public ExpressionResult Evaluate(EvaluationContext context)
         {
-            context.LastSyntaxNode = _expression;
+            context.LastSyntaxElement = _expression;
             if (!_initialized)
             {
                 Initialize(context);
@@ -105,12 +112,12 @@ namespace Jint.Runtime.Interpreter.Expressions
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         protected ExpressionResult NormalCompletion(JsValue value)
         {
-            return new ExpressionResult(ExpressionCompletionType.Normal, value, _expression.Location);
+            return new ExpressionResult(ExpressionCompletionType.Normal, value, _expression);
         }
 
         protected ExpressionResult NormalCompletion(Reference value)
         {
-            return new ExpressionResult(ExpressionCompletionType.Reference, value, _expression.Location);
+            return new ExpressionResult(ExpressionCompletionType.Reference, value, _expression);
         }
 
         /// <summary>
@@ -123,7 +130,7 @@ namespace Jint.Runtime.Interpreter.Expressions
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         protected ExpressionResult ThrowCompletion(JsValue value)
         {
-            return new ExpressionResult(ExpressionCompletionType.Throw, value, _expression.Location);
+            return new ExpressionResult(ExpressionCompletionType.Throw, value, _expression);
         }
 
         /// <summary>

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

@@ -24,7 +24,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 ? InstantiateOrdinaryFunctionExpression(context, _function.Name!)
                 : InstantiateGeneratorFunctionExpression(context, _function.Name!);
 
-            return Completion.Normal(closure, _expression.Location);
+            return Completion.Normal(closure, _expression);
         }
 
         /// <summary>

+ 3 - 3
Jint/Runtime/Interpreter/Expressions/JintIdentifierExpression.cs

@@ -37,11 +37,11 @@ namespace Jint.Runtime.Interpreter.Expressions
         public override Completion GetValue(EvaluationContext context)
         {
             // need to notify correct node when taking shortcut
-            context.LastSyntaxNode = _expression;
+            context.LastSyntaxElement = _expression;
 
             if (_calculatedValue is not null)
             {
-                return Completion.Normal(_calculatedValue, _expression.Location);
+                return Completion.Normal(_calculatedValue, _expression);
             }
 
             var strict = StrictModeScope.IsStrictModeCode;
@@ -72,7 +72,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 argumentsInstance.Materialize();
             }
 
-            return Completion.Normal(value, _expression.Location);
+            return Completion.Normal(value, _expression);
         }
     }
 }

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

@@ -61,9 +61,9 @@ namespace Jint.Runtime.Interpreter.Expressions
         public override Completion GetValue(EvaluationContext context)
         {
             // need to notify correct node when taking shortcut
-            context.LastSyntaxNode = _expression;
+            context.LastSyntaxElement = _expression;
 
-            return Completion.Normal(ResolveValue(context), _expression.Location);
+            return Completion.Normal(ResolveValue(context), _expression);
         }
 
         protected override ExpressionResult EvaluateInternal(EvaluationContext context) => NormalCompletion(ResolveValue(context));

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs

@@ -116,7 +116,7 @@ namespace Jint.Runtime.Interpreter.Expressions
             return new ExpressionResult(
                 ExpressionCompletionType.Reference,
                 rent,
-                _expression.Location);
+                _expression);
         }
     }
 }

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintNewExpression.cs

@@ -59,7 +59,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
             // Reset the location to the "new" keyword so that if an Error object is
             // constructed below, the stack trace will capture the correct location.
-            context.LastSyntaxNode = _expression;
+            context.LastSyntaxElement = _expression;
 
             if (!jsValue.IsConstructor)
             {

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

@@ -24,10 +24,10 @@ namespace Jint.Runtime.Interpreter.Expressions
         public override Completion GetValue(EvaluationContext context)
         {
             // need to notify correct node when taking shortcut
-            context.LastSyntaxNode = _expression;
+            context.LastSyntaxElement = _expression;
 
             GetValueAndCheckIterator(context, out var objectInstance, out var iterator);
-            return Completion.Normal(objectInstance, _expression.Location);
+            return Completion.Normal(objectInstance, _expression);
         }
 
         internal void GetValueAndCheckIterator(EvaluationContext context, out JsValue instance, out IteratorInstance? iterator)

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

@@ -16,9 +16,9 @@ namespace Jint.Runtime.Interpreter.Expressions
         public override Completion GetValue(EvaluationContext context)
         {
             // need to notify correct node when taking shortcut
-            context.LastSyntaxNode = _expression;
+            context.LastSyntaxElement = _expression;
 
-            return Completion.Normal(context.Engine.ResolveThisBinding(), _expression.Location);
+            return Completion.Normal(context.Engine.ResolveThisBinding(), _expression);
         }
     }
 }

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

@@ -44,9 +44,9 @@ namespace Jint.Runtime.Interpreter.Expressions
         public override Completion GetValue(EvaluationContext context)
         {
             // need to notify correct node when taking shortcut
-            context.LastSyntaxNode = _expression;
+            context.LastSyntaxElement = _expression;
 
-            return Completion.Normal(EvaluateJsValue(context), _expression.Location);
+            return Completion.Normal(EvaluateJsValue(context), _expression);
         }
 
         protected override ExpressionResult EvaluateInternal(EvaluationContext context)

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

@@ -28,8 +28,8 @@ namespace Jint.Runtime.Interpreter.Expressions
         public override Completion GetValue(EvaluationContext context)
         {
             // need to notify correct node when taking shortcut
-            context.LastSyntaxNode = _expression;
-            return Completion.Normal(EvaluateConstantOrExpression(context), _expression.Location);
+            context.LastSyntaxElement = _expression;
+            return Completion.Normal(EvaluateConstantOrExpression(context), _expression);
         }
 
         protected override ExpressionResult EvaluateInternal(EvaluationContext context)

+ 2 - 2
Jint/Runtime/Interpreter/JintFunctionDefinition.cs

@@ -56,7 +56,7 @@ namespace Jint.Runtime.Interpreter
                 result = EvaluateFunctionBody(context, functionObject, argumentsList);
             }
 
-            return new Completion(result.Type, result.GetValueOrDefault().Clone(), result.Target, result.Location);
+            return new Completion(result.Type, result.GetValueOrDefault().Clone(), result.Target, result._source);
         }
 
         /// <summary>
@@ -77,7 +77,7 @@ namespace Jint.Runtime.Interpreter
             _bodyExpression ??= JintExpression.Build(_engine, (Expression) Function.Body);
             var jsValue = _bodyExpression?.GetValue(context).Value ?? Undefined.Instance;
             argumentsInstance?.FunctionWasCalled();
-            return new Completion(CompletionType.Return, jsValue, null, Function.Body.Location);
+            return new Completion(CompletionType.Return, jsValue, null, Function.Body);
         }
 
         /// <summary>

+ 12 - 8
Jint/Runtime/Interpreter/JintStatementList.cs

@@ -73,12 +73,12 @@ namespace Jint.Runtime.Interpreter
             var engine = context.Engine;
             if (_statement != null)
             {
-                context.LastSyntaxNode = _statement;
+                context.LastSyntaxElement = _statement;
                 engine.RunBeforeExecuteStatementChecks(_statement);
             }
 
             JintStatement? s = null;
-            var c = new Completion(CompletionType.Normal, null!, null, context.LastSyntaxNode?.Location ?? default);
+            var c = new Completion(CompletionType.Normal, null!, null, context.LastSyntaxElement);
             Completion sl = c;
 
             // The value of a StatementList is the value of the last value-producing item in the StatementList
@@ -96,7 +96,7 @@ namespace Jint.Runtime.Interpreter
                             c.Type,
                             c.Value ?? sl.Value,
                             c.Target,
-                            c.Location);
+                            c._source);
                     }
                     sl = c;
                     lastValue = c.Value ?? lastValue;
@@ -104,8 +104,12 @@ namespace Jint.Runtime.Interpreter
             }
             catch (JavaScriptException v)
             {
-                var location = v.Location == default ? s!.Location : v.Location;
-                var completion = new Completion(CompletionType.Throw, v.Error, null, location);
+                SyntaxElement source = s!._statement;
+                if (v.Location != default)
+                {
+                    source = EsprimaExtensions.CreateLocationNode(v.Location);
+                }
+                var completion = new Completion(CompletionType.Throw, v.Error, null, source);
                 return completion;
             }
             catch (TypeErrorException e)
@@ -114,7 +118,7 @@ namespace Jint.Runtime.Interpreter
                 {
                     e.Message
                 });
-                return new Completion(CompletionType.Throw, error, null, s!.Location);
+                return new Completion(CompletionType.Throw, error, null, s!._statement);
             }
             catch (RangeErrorException e)
             {
@@ -122,9 +126,9 @@ namespace Jint.Runtime.Interpreter
                 {
                     e.Message
                 });
-                c = new Completion(CompletionType.Throw, error, null, s!.Location);
+                c = new Completion(CompletionType.Throw, error, null, s!._statement);
             }
-            return new Completion(c.Type, lastValue ?? JsValue.Undefined, c.Target, c.Location);
+            return new Completion(c.Type, lastValue ?? JsValue.Undefined, c.Target, c._source);
         }
 
         /// <summary>

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintBreakStatement.cs

@@ -16,7 +16,7 @@ namespace Jint.Runtime.Interpreter.Statements
 
         protected override Completion ExecuteInternal(EvaluationContext context)
         {
-            return new Completion(CompletionType.Break, null!, _label, Location);
+            return new Completion(CompletionType.Break, null!, _label, _statement);
         }
     }
 }

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintClassDeclarationStatement.cs

@@ -29,7 +29,7 @@ namespace Jint.Runtime.Interpreter.Statements
                 env.InitializeBinding(classBinding, completion.Value);
             }
 
-            return new Completion(CompletionType.Normal, null!, null, Location);
+            return new Completion(CompletionType.Normal, null!, null, _statement);
         }
     }
 }

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintContinueStatement.cs

@@ -16,7 +16,7 @@ namespace Jint.Runtime.Interpreter.Statements
 
         protected override Completion ExecuteInternal(EvaluationContext context)
         {
-            return new Completion(CompletionType.Continue, _labelName!, Location);
+            return new Completion(CompletionType.Continue, _labelName!, _statement);
         }
     }
 }

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintDebuggerStatement.cs

@@ -29,7 +29,7 @@ namespace Jint.Runtime.Interpreter.Statements
                     break;
             }
 
-            return new Completion(CompletionType.Normal, null!, null, Location);
+            return new Completion(CompletionType.Normal, null!, null, _statement);
         }
     }
 }

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintDoWhileStatement.cs

@@ -41,7 +41,7 @@ namespace Jint.Runtime.Interpreter.Statements
                 {
                     if (completion.Type == CompletionType.Break && (completion.Target == null || completion.Target == _labelSetName))
                     {
-                        return new Completion(CompletionType.Normal, v, null, Location);
+                        return new Completion(CompletionType.Normal, v, null, _statement);
                     }
 
                     if (completion.Type != CompletionType.Normal)

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintEmptyStatement.cs

@@ -10,7 +10,7 @@ namespace Jint.Runtime.Interpreter.Statements
 
         protected override Completion ExecuteInternal(EvaluationContext context)
         {
-            return new Completion(CompletionType.Normal, null!, null, Location);
+            return new Completion(CompletionType.Normal, null!, null, _statement);
         }
     }
 }

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintExpressionStatement.cs

@@ -26,7 +26,7 @@ namespace Jint.Runtime.Interpreter.Statements
                 return new Completion(result);
             }
 
-            return new Completion(CompletionType.Normal, context.Engine.GetValue((Reference) result.Value, true), null, Location);
+            return new Completion(CompletionType.Normal, context.Engine.GetValue((Reference) result.Value, true), null, _statement);
         }
     }
 }

+ 4 - 4
Jint/Runtime/Interpreter/Statements/JintForInForOfStatement.cs

@@ -95,7 +95,7 @@ namespace Jint.Runtime.Interpreter.Statements
         {
             if (!HeadEvaluation(context, out var keyResult))
             {
-                return new Completion(CompletionType.Normal, JsValue.Undefined, null, Location);
+                return new Completion(CompletionType.Normal, JsValue.Undefined, null, _statement);
             }
 
             return BodyEvaluation(context, _expr, _body, keyResult, IterationKind.Enumerate, _lhsKind);
@@ -170,7 +170,7 @@ namespace Jint.Runtime.Interpreter.Statements
                     if (!iteratorRecord.TryIteratorStep(out var nextResult))
                     {
                         close = true;
-                        return new Completion(CompletionType.Normal, v, null, Location);
+                        return new Completion(CompletionType.Normal, v, null, _statement!);
                     }
 
                     if (iteratorKind == IteratorKind.Async)
@@ -203,7 +203,7 @@ namespace Jint.Runtime.Interpreter.Statements
                         {
                             var identifier = (Identifier) ((VariableDeclaration) _leftNode).Declarations[0].Id;
                             lhsName ??= identifier.Name;
-                            lhsRef = new ExpressionResult(ExpressionCompletionType.Normal, engine.ResolveBinding(lhsName), identifier.Location);
+                            lhsRef = new ExpressionResult(ExpressionCompletionType.Normal, engine.ResolveBinding(lhsName), identifier);
                         }
                     }
 
@@ -281,7 +281,7 @@ namespace Jint.Runtime.Interpreter.Statements
                     if (result.Type == CompletionType.Break && (result.Target == null || result.Target == _statement?.LabelSet?.Name))
                     {
                         completionType = CompletionType.Normal;
-                        return new Completion(CompletionType.Normal, v, null, Location);
+                        return new Completion(CompletionType.Normal, v, null, _statement!);
                     }
 
                     if (result.Type != CompletionType.Continue || (result.Target != null && result.Target != _statement?.LabelSet?.Name))

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintIfStatement.cs

@@ -33,7 +33,7 @@ namespace Jint.Runtime.Interpreter.Statements
             }
             else
             {
-                return new Completion(CompletionType.Normal, null!, Location);
+                return new Completion(CompletionType.Normal, null!, _statement);
             }
 
             return result;

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintImportDeclaration.cs

@@ -15,7 +15,7 @@ internal sealed class JintImportDeclaration : JintStatement<ImportDeclaration>
     protected override Completion ExecuteInternal(EvaluationContext context)
     {
         // just to ensure module context or valid
-        context.Engine.GetActiveScriptOrModule().AsModule(context.Engine, context.LastSyntaxNode.Location);
+        context.Engine.GetActiveScriptOrModule().AsModule(context.Engine, context.LastSyntaxElement.Location);
         return Completion.Empty();
     }
 }

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintLabeledStatement.cs

@@ -26,7 +26,7 @@ namespace Jint.Runtime.Interpreter.Statements
             if (result.Type == CompletionType.Break && result.Target == _labelName)
             {
                 var value = result.Value;
-                return new Completion(CompletionType.Normal, value, null, Location);
+                return new Completion(CompletionType.Normal, value, null, _statement);
             }
 
             return result;

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintReturnStatement.cs

@@ -25,7 +25,7 @@ namespace Jint.Runtime.Interpreter.Statements
         protected override Completion ExecuteInternal(EvaluationContext context)
         {
             var jsValue = _argument?.GetValue(context).Value ?? Undefined.Instance;
-            return new Completion(CompletionType.Return, jsValue, null, Location);
+            return new Completion(CompletionType.Return, jsValue, null, _statement);
         }
     }
 }

+ 6 - 6
Jint/Runtime/Interpreter/Statements/JintStatement.cs

@@ -9,7 +9,7 @@ namespace Jint.Runtime.Interpreter.Statements
 {
     internal abstract class JintStatement<T> : JintStatement where T : Statement
     {
-        internal readonly T _statement;
+        internal new readonly T _statement;
 
         protected JintStatement(T statement) : base(statement)
         {
@@ -19,7 +19,7 @@ namespace Jint.Runtime.Interpreter.Statements
 
     internal abstract class JintStatement
     {
-        private readonly Statement _statement;
+        internal readonly Statement _statement;
         private bool _initialized;
 
         protected JintStatement(Statement statement)
@@ -32,7 +32,7 @@ namespace Jint.Runtime.Interpreter.Statements
         {
             if (_statement.Type != Nodes.BlockStatement)
             {
-                context.LastSyntaxNode = _statement;
+                context.LastSyntaxElement = _statement;
                 context.Engine.RunBeforeExecuteStatementChecks(_statement);
             }
 
@@ -54,7 +54,7 @@ namespace Jint.Runtime.Interpreter.Statements
 
         protected abstract Completion ExecuteInternal(EvaluationContext context);
 
-        public Location Location => _statement.Location;
+        public ref readonly Location Location => ref _statement.Location;
 
         /// <summary>
         /// Opportunity to build one-time structures and caching based on lexical context.
@@ -111,7 +111,7 @@ namespace Jint.Runtime.Interpreter.Statements
                 var jsValue = JintLiteralExpression.ConvertToJsValue(l);
                 if (jsValue is not null)
                 {
-                    return new Completion(CompletionType.Return, jsValue, null, rs.Location);
+                    return new Completion(CompletionType.Return, jsValue, null, rs);
                 }
             }
 
@@ -128,7 +128,7 @@ namespace Jint.Runtime.Interpreter.Statements
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         protected Completion NormalCompletion(JsValue value)
         {
-            return new Completion(CompletionType.Normal, value, _statement.Location);
+            return new Completion(CompletionType.Normal, value, _statement);
         }
     }
 }

+ 3 - 3
Jint/Runtime/Interpreter/Statements/JintSwitchBlock.cs

@@ -37,7 +37,7 @@ namespace Jint.Runtime.Interpreter.Statements
 
             var engine = context.Engine;
             JsValue v = Undefined.Instance;
-            Location l = context.LastSyntaxNode.Location;
+            SyntaxElement l = context.LastSyntaxElement;
             JintSwitchCase? defaultCase = null;
             bool hit = false;
 
@@ -81,7 +81,7 @@ namespace Jint.Runtime.Interpreter.Statements
                         return r;
                     }
 
-                    l = r.Location;
+                    l = r._source;
                     v = r.Value ?? Undefined.Instance;
                 }
             }
@@ -109,7 +109,7 @@ namespace Jint.Runtime.Interpreter.Statements
                     return r;
                 }
 
-                l = r.Location;
+                l = r._source;
                 v = r.Value ?? Undefined.Instance;
             }
 

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintThrowStatement.cs

@@ -22,7 +22,7 @@ namespace Jint.Runtime.Interpreter.Statements
         protected override Completion ExecuteInternal(EvaluationContext context)
         {
             var completion = _argument.GetValue(context);
-            return new Completion(CompletionType.Throw, completion.Value, null, completion.Location);
+            return new Completion(CompletionType.Throw, completion.Value, null, completion._source);
         }
     }
 }

+ 1 - 3
Jint/Runtime/Interpreter/Statements/JintVariableDeclaration.cs

@@ -8,8 +8,6 @@ namespace Jint.Runtime.Interpreter.Statements
 {
     internal sealed class JintVariableDeclaration : JintStatement<VariableDeclaration>
     {
-        private static readonly Completion VoidCompletion = new(CompletionType.Normal, null!, default);
-
         private ResolvedDeclaration[] _declarations = Array.Empty<ResolvedDeclaration>();
 
         private sealed class ResolvedDeclaration
@@ -127,7 +125,7 @@ namespace Jint.Runtime.Interpreter.Statements
                 }
             }
 
-            return VoidCompletion;
+            return Completion.Empty();
         }
     }
 }

+ 2 - 2
Jint/Runtime/Interpreter/Statements/JintWhileStatement.cs

@@ -37,7 +37,7 @@ namespace Jint.Runtime.Interpreter.Statements
                 var jsValue = _test.GetValue(context).Value;
                 if (!TypeConverter.ToBoolean(jsValue))
                 {
-                    return new Completion(CompletionType.Normal, v, null, Location);
+                    return new Completion(CompletionType.Normal, v, null, _statement);
                 }
 
                 var completion = _body.Execute(context);
@@ -51,7 +51,7 @@ namespace Jint.Runtime.Interpreter.Statements
                 {
                     if (completion.Type == CompletionType.Break && (completion.Target == null || completion.Target == _labelSetName))
                     {
-                        return new Completion(CompletionType.Normal, v, null, Location);
+                        return new Completion(CompletionType.Normal, v, null, _statement);
                     }
 
                     if (completion.Type != CompletionType.Normal)

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintWithStatement.cs

@@ -38,7 +38,7 @@ namespace Jint.Runtime.Interpreter.Statements
             }
             catch (JavaScriptException e)
             {
-                c = new Completion(CompletionType.Throw, e.Error, _statement.Location);
+                c = new Completion(CompletionType.Throw, e.Error, _statement);
             }
             finally
             {

+ 6 - 4
Jint/Runtime/JavaScriptException.cs

@@ -26,7 +26,7 @@ public class JavaScriptException : JintException
     private readonly JavaScriptErrorWrapperException _jsErrorException;
 
     public string? JavaScriptStackTrace => _jsErrorException.StackTrace;
-    public Location Location => _jsErrorException.Location;
+    public ref readonly Location Location => ref _jsErrorException.Location;
     public JsValue Error => _jsErrorException.Error;
 
     internal JavaScriptException(ErrorConstructor errorConstructor)
@@ -64,9 +64,11 @@ public class JavaScriptException : JintException
     private class JavaScriptErrorWrapperException : JintException
     {
         private string? _callStack;
+        private Location _location;
 
         public JsValue Error { get; }
-        public Location Location { get; private set; }
+
+        public ref readonly Location Location => ref _location;
 
         internal JavaScriptErrorWrapperException(JsValue error, string? message = null)
             : base(message ?? GetMessage(error))
@@ -76,12 +78,12 @@ public class JavaScriptException : JintException
 
         internal void SetLocation(Location location)
         {
-            Location = location;
+            _location = location;
         }
 
         internal void SetCallstack(Engine engine, Location location, bool overwriteExisting)
         {
-            Location = location;
+            _location = location;
 
             var errObj = Error.IsObject() ? Error.AsObject() : null;
             if (errObj is null)