|
@@ -39,7 +39,7 @@ namespace Jint
|
|
|
|
|
|
private readonly ExpressionInterpreter _expressions;
|
|
|
private readonly StatementInterpreter _statements;
|
|
|
- private readonly Stack<ExecutionContext> _executionContexts;
|
|
|
+ private readonly ExecutionContextStack _executionContexts;
|
|
|
private JsValue _completionValue = JsValue.Undefined;
|
|
|
private int _statementsCount;
|
|
|
private long _timeoutTicks;
|
|
@@ -85,7 +85,7 @@ namespace Jint
|
|
|
|
|
|
public Engine(Action<Options> options)
|
|
|
{
|
|
|
- _executionContexts = new Stack<ExecutionContext>();
|
|
|
+ _executionContexts = new ExecutionContextStack();
|
|
|
|
|
|
Global = GlobalObject.CreateGlobalObject(this);
|
|
|
|
|
@@ -213,7 +213,11 @@ namespace Jint
|
|
|
public ErrorConstructor ReferenceError { get; }
|
|
|
public ErrorConstructor UriError { get; }
|
|
|
|
|
|
- public ExecutionContext ExecutionContext => _executionContexts.Peek();
|
|
|
+ public ref readonly ExecutionContext ExecutionContext
|
|
|
+ {
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
+ get { return ref _executionContexts.Peek(); }
|
|
|
+ }
|
|
|
|
|
|
public GlobalSymbolRegistry GlobalSymbolRegistry { get; }
|
|
|
|
|
@@ -247,17 +251,17 @@ namespace Jint
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
- public ExecutionContext EnterExecutionContext(LexicalEnvironment lexicalEnvironment, LexicalEnvironment variableEnvironment, JsValue thisBinding)
|
|
|
+ public void EnterExecutionContext(
|
|
|
+ LexicalEnvironment lexicalEnvironment,
|
|
|
+ LexicalEnvironment variableEnvironment,
|
|
|
+ JsValue thisBinding)
|
|
|
{
|
|
|
- var executionContext = new ExecutionContext
|
|
|
- {
|
|
|
- LexicalEnvironment = lexicalEnvironment,
|
|
|
- VariableEnvironment = variableEnvironment,
|
|
|
- ThisBinding = thisBinding
|
|
|
- };
|
|
|
- _executionContexts.Push(executionContext);
|
|
|
+ var context = new ExecutionContext(
|
|
|
+ lexicalEnvironment,
|
|
|
+ variableEnvironment,
|
|
|
+ thisBinding);
|
|
|
|
|
|
- return executionContext;
|
|
|
+ _executionContexts.Push(context);
|
|
|
}
|
|
|
|
|
|
public Engine SetValue(string name, Delegate value)
|
|
@@ -376,12 +380,12 @@ namespace Jint
|
|
|
{
|
|
|
if (_maxStatements > 0 && _statementsCount++ > _maxStatements)
|
|
|
{
|
|
|
- throw new StatementsCountOverflowException();
|
|
|
+ ThrowStatementsCountOverflowException();
|
|
|
}
|
|
|
|
|
|
if (_timeoutTicks > 0 && _timeoutTicks < DateTime.UtcNow.Ticks)
|
|
|
{
|
|
|
- throw new TimeoutException();
|
|
|
+ ThrowTimeoutException();
|
|
|
}
|
|
|
|
|
|
_lastSyntaxNode = statement;
|
|
@@ -433,7 +437,7 @@ namespace Jint
|
|
|
return _statements.ExecuteSwitchStatement((SwitchStatement) statement);
|
|
|
|
|
|
case Nodes.FunctionDeclaration:
|
|
|
- return Completion.Empty;
|
|
|
+ return new Completion(CompletionType.Normal, null, null);
|
|
|
|
|
|
case Nodes.ThrowStatement:
|
|
|
return _statements.ExecuteThrowStatement((ThrowStatement) statement);
|
|
@@ -454,7 +458,8 @@ namespace Jint
|
|
|
return _statements.ExecuteProgram((Program) statement);
|
|
|
|
|
|
default:
|
|
|
- throw new ArgumentOutOfRangeException();
|
|
|
+ ThrowArgumentOutOfRange();
|
|
|
+ return new Completion(CompletionType.Normal, null, null);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -513,30 +518,50 @@ namespace Jint
|
|
|
return _expressions.EvaluateUnaryExpression((UnaryExpression) expression);
|
|
|
|
|
|
default:
|
|
|
- throw new ArgumentOutOfRangeException();
|
|
|
+ ThrowArgumentOutOfRange();
|
|
|
+ return null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/// <summary>
|
|
|
/// http://www.ecma-international.org/ecma-262/5.1/#sec-8.7.1
|
|
|
/// </summary>
|
|
|
- /// <param name="value"></param>
|
|
|
- /// <returns></returns>
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
public JsValue GetValue(object value)
|
|
|
{
|
|
|
- return GetValue(value, false);
|
|
|
+ if (value is JsValue jsValue)
|
|
|
+ {
|
|
|
+ return jsValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ return GetValueFromReference(value, false);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
+ internal JsValue GetValue(in Completion completion)
|
|
|
+ {
|
|
|
+ var value = completion.Value;
|
|
|
+ if (value is JsValue jsValue)
|
|
|
+ {
|
|
|
+ return jsValue;
|
|
|
+ }
|
|
|
+ return GetValueFromReference(completion.Value, false);
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
internal JsValue GetValue(object value, bool returnReferenceToPool)
|
|
|
{
|
|
|
- var jsValue = value as JsValue;
|
|
|
- if (!ReferenceEquals(jsValue, null))
|
|
|
+ if (value is JsValue jsValue)
|
|
|
{
|
|
|
return jsValue;
|
|
|
}
|
|
|
|
|
|
+ return GetValueFromReference(value, returnReferenceToPool);
|
|
|
+ }
|
|
|
+
|
|
|
+ internal JsValue GetValueFromReference(object value, bool returnReferenceToPool)
|
|
|
+ {
|
|
|
var reference = value as Reference;
|
|
|
if (reference == null)
|
|
|
{
|
|
@@ -592,7 +617,7 @@ namespace Jint
|
|
|
}
|
|
|
|
|
|
var getter = desc.Get;
|
|
|
- if (ReferenceEquals(getter, Undefined.Instance))
|
|
|
+ if (getter.IsUndefined())
|
|
|
{
|
|
|
return Undefined.Instance;
|
|
|
}
|
|
@@ -629,7 +654,7 @@ namespace Jint
|
|
|
{
|
|
|
if (reference.IsStrict())
|
|
|
{
|
|
|
- throw new JavaScriptException(ReferenceError);
|
|
|
+ ThrowReferenceError();
|
|
|
}
|
|
|
|
|
|
Global.Put(reference.GetReferencedName(), value, false);
|
|
@@ -649,11 +674,10 @@ namespace Jint
|
|
|
else
|
|
|
{
|
|
|
var baseValue = reference.GetBase();
|
|
|
- var record = baseValue as EnvironmentRecord;
|
|
|
-
|
|
|
- if (ReferenceEquals(record, null))
|
|
|
+ if (!(baseValue is EnvironmentRecord record))
|
|
|
{
|
|
|
- throw new ArgumentNullException();
|
|
|
+ ThrowArgumentNullException();
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
record.SetMutableBinding(reference.GetReferencedName(), value, reference.IsStrict());
|
|
@@ -663,10 +687,6 @@ namespace Jint
|
|
|
/// <summary>
|
|
|
/// Used by PutValue when the reference has a primitive base value
|
|
|
/// </summary>
|
|
|
- /// <param name="b"></param>
|
|
|
- /// <param name="name"></param>
|
|
|
- /// <param name="value"></param>
|
|
|
- /// <param name="throwOnError"></param>
|
|
|
public void PutPrimitiveBase(JsValue b, string name, JsValue value, bool throwOnError)
|
|
|
{
|
|
|
var o = TypeConverter.ToObject(this, b);
|
|
@@ -674,9 +694,8 @@ namespace Jint
|
|
|
{
|
|
|
if (throwOnError)
|
|
|
{
|
|
|
- throw new JavaScriptException(TypeError);
|
|
|
+ ThrowTypeError();
|
|
|
}
|
|
|
-
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -686,9 +705,8 @@ namespace Jint
|
|
|
{
|
|
|
if (throwOnError)
|
|
|
{
|
|
|
- throw new JavaScriptException(TypeError);
|
|
|
+ ThrowTypeError();
|
|
|
}
|
|
|
-
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -703,7 +721,7 @@ namespace Jint
|
|
|
{
|
|
|
if (throwOnError)
|
|
|
{
|
|
|
- throw new JavaScriptException(TypeError);
|
|
|
+ ThrowTypeError();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -796,15 +814,11 @@ namespace Jint
|
|
|
/// <param name="propertyName">The name of the property to return.</param>
|
|
|
public JsValue GetValue(JsValue scope, string propertyName)
|
|
|
{
|
|
|
- if (string.IsNullOrEmpty(propertyName))
|
|
|
- {
|
|
|
- throw new ArgumentException("propertyName");
|
|
|
- }
|
|
|
+ AssertNotNullOrEmpty(nameof(propertyName), propertyName);
|
|
|
|
|
|
var reference = ReferencePool.Rent(scope, propertyName, _isStrict);
|
|
|
var jsValue = GetValue(reference);
|
|
|
ReferencePool.Return(reference);
|
|
|
-
|
|
|
return jsValue;
|
|
|
}
|
|
|
|
|
@@ -921,5 +935,49 @@ namespace Jint
|
|
|
|
|
|
return canReleaseArgumentsInstance;
|
|
|
}
|
|
|
+
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
+ internal void UpdateLexicalEnvironment(LexicalEnvironment newEnv)
|
|
|
+ {
|
|
|
+ _executionContexts.ReplaceTopLexicalEnvironment(newEnv);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void ThrowTimeoutException()
|
|
|
+ {
|
|
|
+ throw new TimeoutException();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void ThrowStatementsCountOverflowException()
|
|
|
+ {
|
|
|
+ throw new StatementsCountOverflowException();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void ThrowArgumentOutOfRange()
|
|
|
+ {
|
|
|
+ throw new ArgumentOutOfRangeException();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void ThrowArgumentNullException()
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ThrowReferenceError()
|
|
|
+ {
|
|
|
+ throw new JavaScriptException(ReferenceError);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void AssertNotNullOrEmpty(string propertyname, string propertyValue)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(propertyValue))
|
|
|
+ {
|
|
|
+ throw new ArgumentException(propertyname);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ThrowTypeError()
|
|
|
+ {
|
|
|
+ throw new JavaScriptException(TypeError);
|
|
|
+ }
|
|
|
}
|
|
|
}
|