Skip to content

Commit

Permalink
Move data from Completion and ExpressionResult to context (#1291)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Sep 10, 2022
1 parent e38849e commit b3154ca
Show file tree
Hide file tree
Showing 29 changed files with 219 additions and 246 deletions.
4 changes: 2 additions & 2 deletions Jint.Tests/Runtime/EngineLimitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ public class EngineLimitTests
public void ShouldAllowReasonableCallStackDepth()
{
#if RELEASE
const int FunctionNestingCount = 740;
const int FunctionNestingCount = 810;
#else
const int FunctionNestingCount = 400;
const int FunctionNestingCount = 460;
#endif

// generate call tree
Expand Down
2 changes: 1 addition & 1 deletion Jint/Engine.Modules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ private JsValue EvaluateModule(string specifier, ModuleRecord cyclicModule)
else if (promise.State == PromiseState.Rejected)
{
var node = EsprimaExtensions.CreateLocationNode(Location.From(new Position(), new Position(), specifier));
ExceptionHelper.ThrowJavaScriptException(this, promise.Value, new Completion(CompletionType.Throw, promise.Value, null, node));
ExceptionHelper.ThrowJavaScriptException(this, promise.Value, new Completion(CompletionType.Throw, promise.Value, node));
}
else if (promise.State != PromiseState.Fulfilled)
{
Expand Down
121 changes: 46 additions & 75 deletions Jint/Runtime/Completion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,93 +3,64 @@
using Esprima;
using Esprima.Ast;
using Jint.Native;
using Jint.Runtime.Interpreter.Expressions;

namespace Jint.Runtime
{
public enum CompletionType : byte
{
Normal = 0,
Return = 1,
Throw = 2,
Break,
Continue
}

/// <summary>
/// https://tc39.es/ecma262/#sec-completion-record-specification-type
/// </summary>
[StructLayout(LayoutKind.Auto)]
public readonly struct Completion
{
private static readonly Node _emptyNode = new Identifier("");
private static readonly Completion _emptyCompletion = new(CompletionType.Normal, null!, _emptyNode);
namespace Jint.Runtime;

internal readonly SyntaxElement _source;
public enum CompletionType : byte
{
Normal = 0,
Return = 1,
Throw = 2,
Break,
Continue
}

internal Completion(CompletionType type, JsValue value, string? target, SyntaxElement source)
{
Type = type;
Value = value;
Target = target;
_source = source;
}
/// <summary>
/// https://tc39.es/ecma262/#sec-completion-record-specification-type
/// </summary>
[StructLayout(LayoutKind.Auto)]
public readonly struct Completion
{
private static readonly Node _emptyNode = new Identifier("");
private static readonly Completion _emptyCompletion = new(CompletionType.Normal, null!, _emptyNode);

public Completion(CompletionType type, JsValue value, SyntaxElement source)
{
Type = type;
Value = value;
Target = null;
_source = source;
}
internal readonly SyntaxElement _source;

public Completion(CompletionType type, string target, SyntaxElement source)
{
Type = type;
Value = null!;
Target = target;
_source = source;
}
public Completion(CompletionType type, JsValue value, SyntaxElement source)
{
Type = type;
Value = value;
_source = source;
}

internal Completion(in ExpressionResult result)
{
Type = (CompletionType) result.Type;
// this cast protects us from getting from type
Value = (JsValue) result.Value;
Target = null;
_source = result._source;
}
public readonly CompletionType Type;
public readonly JsValue Value;
public ref readonly Location Location => ref _source.Location;

public readonly CompletionType Type;
public readonly JsValue Value;
public readonly string? Target;
public ref readonly Location Location => ref _source.Location;
public static ref readonly Completion Empty() => ref _emptyCompletion;

public static ref readonly Completion Empty() => ref _emptyCompletion;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public JsValue GetValueOrDefault()
{
return Value ?? Undefined.Instance;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public JsValue GetValueOrDefault()
{
return Value ?? Undefined.Instance;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsAbrupt()
{
return Type != CompletionType.Normal;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsAbrupt()
/// <summary>
/// https://tc39.es/ecma262/#sec-updateempty
/// </summary>
internal Completion UpdateEmpty(JsValue value)
{
if (Value is not null)
{
return Type != CompletionType.Normal;
return this;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-updateempty
/// </summary>
internal Completion UpdateEmpty(JsValue value)
{
if (Value is not null)
{
return this;
}

return new Completion(Type, value, Target, _source);
}
return new Completion(Type, value, _source);
}
}
101 changes: 51 additions & 50 deletions Jint/Runtime/Environments/ExecutionContext.cs
Original file line number Diff line number Diff line change
@@ -1,67 +1,68 @@
using System.Runtime.InteropServices;
using Jint.Native.Function;

namespace Jint.Runtime.Environments
namespace Jint.Runtime.Environments;

[StructLayout(LayoutKind.Auto)]
internal readonly struct ExecutionContext
{
internal readonly struct ExecutionContext
internal ExecutionContext(
IScriptOrModule? scriptOrModule,
EnvironmentRecord lexicalEnvironment,
EnvironmentRecord variableEnvironment,
PrivateEnvironmentRecord? privateEnvironment,
Realm realm,
FunctionInstance? function = null)
{
internal ExecutionContext(
IScriptOrModule? scriptOrModule,
EnvironmentRecord lexicalEnvironment,
EnvironmentRecord variableEnvironment,
PrivateEnvironmentRecord? privateEnvironment,
Realm realm,
FunctionInstance? function = null)
{
ScriptOrModule = scriptOrModule;
LexicalEnvironment = lexicalEnvironment;
VariableEnvironment = variableEnvironment;
PrivateEnvironment = privateEnvironment;
Realm = realm;
Function = function;
}
ScriptOrModule = scriptOrModule;
LexicalEnvironment = lexicalEnvironment;
VariableEnvironment = variableEnvironment;
PrivateEnvironment = privateEnvironment;
Realm = realm;
Function = function;
}

public readonly IScriptOrModule? ScriptOrModule;
public readonly EnvironmentRecord LexicalEnvironment;
public readonly EnvironmentRecord VariableEnvironment;
public readonly PrivateEnvironmentRecord? PrivateEnvironment;
public readonly Realm Realm;
public readonly FunctionInstance? Function;
public readonly IScriptOrModule? ScriptOrModule;
public readonly EnvironmentRecord LexicalEnvironment;
public readonly EnvironmentRecord VariableEnvironment;
public readonly PrivateEnvironmentRecord? PrivateEnvironment;
public readonly Realm Realm;
public readonly FunctionInstance? Function;

public ExecutionContext UpdateLexicalEnvironment(EnvironmentRecord lexicalEnvironment)
{
return new ExecutionContext(ScriptOrModule, lexicalEnvironment, VariableEnvironment, PrivateEnvironment, Realm, Function);
}
public ExecutionContext UpdateLexicalEnvironment(EnvironmentRecord lexicalEnvironment)
{
return new ExecutionContext(ScriptOrModule, lexicalEnvironment, VariableEnvironment, PrivateEnvironment, Realm, Function);
}

public ExecutionContext UpdateVariableEnvironment(EnvironmentRecord variableEnvironment)
{
return new ExecutionContext(ScriptOrModule, LexicalEnvironment, variableEnvironment, PrivateEnvironment, Realm, Function);
}
public ExecutionContext UpdateVariableEnvironment(EnvironmentRecord variableEnvironment)
{
return new ExecutionContext(ScriptOrModule, LexicalEnvironment, variableEnvironment, PrivateEnvironment, Realm, Function);
}

public ExecutionContext UpdatePrivateEnvironment(PrivateEnvironmentRecord? privateEnvironment)
{
return new ExecutionContext(ScriptOrModule, LexicalEnvironment, VariableEnvironment, privateEnvironment, Realm, Function);
}
public ExecutionContext UpdatePrivateEnvironment(PrivateEnvironmentRecord? privateEnvironment)
{
return new ExecutionContext(ScriptOrModule, LexicalEnvironment, VariableEnvironment, privateEnvironment, Realm, Function);
}

/// <summary>
/// https://tc39.es/ecma262/#sec-getthisenvironment
/// </summary>
internal EnvironmentRecord GetThisEnvironment()
/// <summary>
/// https://tc39.es/ecma262/#sec-getthisenvironment
/// </summary>
internal EnvironmentRecord GetThisEnvironment()
{
// The loop will always terminate because the list of environments always
// ends with the global environment which has a this binding.
var lex = LexicalEnvironment;
while (true)
{
// The loop will always terminate because the list of environments always
// ends with the global environment which has a this binding.
var lex = LexicalEnvironment;
while (true)
if (lex != null)
{
if (lex != null)
if (lex.HasThisBinding())
{
if (lex.HasThisBinding())
{
return lex;
return lex;

}

lex = lex._outerEnv;
}

lex = lex._outerEnv;
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions Jint/Runtime/Interpreter/EvaluationContext.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using Esprima.Ast;

namespace Jint.Runtime.Interpreter;
Expand All @@ -24,11 +25,23 @@ public EvaluationContext(Engine engine, in Completion? resumedCompletion = null)
public SyntaxElement LastSyntaxElement = null!;
public readonly bool OperatorOverloadingAllowed;

// completion record information
public string? Target;
public CompletionType Completion;

public void RunBeforeExecuteStatementChecks(Statement statement)
{
if (_shouldRunBeforeExecuteStatementChecks)
{
Engine.RunBeforeExecuteStatementChecks(statement);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PrepareFor(Node node)
{
LastSyntaxElement = node;
Target = null;
Completion = CompletionType.Normal;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ private ExpressionResult SetValue(EvaluationContext context)
}

environmentRecord.SetMutableBinding(left.Identifier, rval, strict);
return ExpressionResult.Normal(rval, completion._source);
return ExpressionResult.Normal(rval);
}

return null;
Expand Down
24 changes: 11 additions & 13 deletions Jint/Runtime/Interpreter/Expressions/JintExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,25 @@ namespace Jint.Runtime.Interpreter.Expressions
[StructLayout(LayoutKind.Auto)]
internal readonly struct ExpressionResult
{
internal readonly SyntaxElement _source;

public readonly ExpressionCompletionType Type;
public readonly object Value;

public ExpressionResult(ExpressionCompletionType type, object value, SyntaxElement source)
public ExpressionResult(ExpressionCompletionType type, object value)
{
Type = type;
Value = value;
_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._source);
return new ExpressionResult((ExpressionCompletionType) result.Type, result.Value);
}

public static ExpressionResult? Normal(JsValue value, SyntaxElement source)
public static ExpressionResult? Normal(JsValue value)
{
return new ExpressionResult(ExpressionCompletionType.Normal, value, source);
return new ExpressionResult(ExpressionCompletionType.Normal, value);
}
}

Expand Down Expand Up @@ -73,17 +70,18 @@ public virtual Completion GetValue(EvaluationContext context)
var result = Evaluate(context);
if (result.Type != ExpressionCompletionType.Reference)
{
return new Completion((CompletionType) result.Type, (JsValue) result.Value, result._source);
return new Completion((CompletionType) result.Type, (JsValue) result.Value, context.LastSyntaxElement);
}

var jsValue = context.Engine.GetValue((Reference) result.Value, true);
return new Completion(CompletionType.Normal, jsValue, null, _expression);
return new Completion(CompletionType.Normal, jsValue, context.LastSyntaxElement);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ExpressionResult Evaluate(EvaluationContext context)
{
context.LastSyntaxElement = _expression;
context.PrepareFor(_expression);

if (!_initialized)
{
Initialize(context);
Expand Down Expand Up @@ -112,12 +110,12 @@ protected virtual void Initialize(EvaluationContext context)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected ExpressionResult NormalCompletion(JsValue value)
{
return new ExpressionResult(ExpressionCompletionType.Normal, value, _expression);
return new ExpressionResult(ExpressionCompletionType.Normal, value);
}

protected ExpressionResult NormalCompletion(Reference value)
{
return new ExpressionResult(ExpressionCompletionType.Reference, value, _expression);
return new ExpressionResult(ExpressionCompletionType.Reference, value);
}

/// <summary>
Expand All @@ -130,7 +128,7 @@ protected ExpressionResult NormalCompletion(Reference value)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected ExpressionResult ThrowCompletion(JsValue value)
{
return new ExpressionResult(ExpressionCompletionType.Throw, value, _expression);
return new ExpressionResult(ExpressionCompletionType.Throw, value);
}

/// <summary>
Expand Down

0 comments on commit b3154ca

Please sign in to comment.