Skip to content

Commit

Permalink
gracefully handle recursive engine invocations
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Feb 4, 2021
1 parent 7e44891 commit e2404d8
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Jint.Tests.Test262/Test262Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ protected void RunTestCode(string code, bool strict)
var parser = new JavaScriptParser(args.At(0).AsString(), options);
var script = parser.ParseScript(strict);
var value = engine.Execute(script, false).GetCompletionValue();
var value = engine.Execute(script).GetCompletionValue();
return value;
}), true, true, true));
Expand Down
13 changes: 13 additions & 0 deletions Jint.Tests/Runtime/EngineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2934,6 +2934,19 @@ public void ShouldReuseOptions()
Assert.Equal(1, Convert.ToInt32(engine2.GetValue("x").ToObject()));
}

[Fact]
public void RecursiveCallStack()
{
var engine = new Engine();
Func<string, object> evaluateCode = code => engine.Execute(code).GetCompletionValue();
var evaluateCodeValue = JsValue.FromObject(engine, evaluateCode);

engine.SetValue("evaluateCode", evaluateCodeValue);
var result = (int) engine.Execute(@"evaluateCode('678 + 711')").GetCompletionValue().AsNumber();

Assert.Equal(1389, result);
}

private class Wrapper
{
public Testificate Test { get; set; }
Expand Down
44 changes: 23 additions & 21 deletions Jint/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,16 +349,12 @@ public Engine Execute(string source, ParserOptions parserOptions)

public Engine Execute(Script script)
{
return Execute(script, true);
}

internal Engine Execute(Script script, bool resetState)
{
if (resetState)
// only if we are not in a recursive call, we can reset constraints and last statement
// we assume that call stack will be empty only when exited on top level of call chain
if (CallStack.Count == 0)
{
ResetConstraints();
ResetLastStatement();
ResetCallStack();
}

using (new StrictModeScope(_isStrict || script.Strict))
Expand Down Expand Up @@ -1254,16 +1250,19 @@ internal JsValue Construct(IConstructor constructor, JsValue[] arguments, JsValu
DebugHandler.AddToDebugCallStack(functionInstance);
}

var result = functionInstance.Call(thisObject, arguments);

if (_isDebugMode)
try
{
DebugHandler.PopDebugCallStack();
return functionInstance.Call(thisObject, arguments);
}
finally
{
if (_isDebugMode)
{
DebugHandler.PopDebugCallStack();
}

CallStack.Pop();

return result;
CallStack.Pop();
}
}

internal JsValue Construct(
Expand All @@ -1287,16 +1286,19 @@ internal JsValue Construct(IConstructor constructor, JsValue[] arguments, JsValu
DebugHandler.AddToDebugCallStack(functionInstance);
}

var result = ((IConstructor) functionInstance).Construct(arguments, newTarget);

if (_isDebugMode)
try
{
DebugHandler.PopDebugCallStack();
return ((IConstructor) functionInstance).Construct(arguments, newTarget);
}
finally
{
if (_isDebugMode)
{
DebugHandler.PopDebugCallStack();
}

CallStack.Pop();

return result;
CallStack.Pop();
}
}
}
}
2 changes: 2 additions & 0 deletions Jint/Runtime/CallStack/JintCallStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public CallStackElement Pop()
return item;
}

public int Count => _stack._size;

public void Clear()
{
_stack.Clear();
Expand Down

0 comments on commit e2404d8

Please sign in to comment.