|
@@ -28,24 +28,23 @@ using Jint.Runtime;
|
|
using Jint.Runtime.CallStack;
|
|
using Jint.Runtime.CallStack;
|
|
using Jint.Runtime.Debugger;
|
|
using Jint.Runtime.Debugger;
|
|
using Jint.Runtime.Descriptors;
|
|
using Jint.Runtime.Descriptors;
|
|
-using Jint.Runtime.Descriptors.Specialized;
|
|
|
|
using Jint.Runtime.Environments;
|
|
using Jint.Runtime.Environments;
|
|
using Jint.Runtime.Interop;
|
|
using Jint.Runtime.Interop;
|
|
|
|
+using Jint.Runtime.Interop.Reflection;
|
|
using Jint.Runtime.Interpreter;
|
|
using Jint.Runtime.Interpreter;
|
|
|
|
+using Jint.Runtime.Interpreter.Expressions;
|
|
using Jint.Runtime.References;
|
|
using Jint.Runtime.References;
|
|
|
|
|
|
namespace Jint
|
|
namespace Jint
|
|
{
|
|
{
|
|
public class Engine
|
|
public class Engine
|
|
{
|
|
{
|
|
- private static readonly ParserOptions DefaultParserOptions = new ParserOptions
|
|
|
|
|
|
+ private static readonly ParserOptions DefaultParserOptions = new("<anonymous>")
|
|
{
|
|
{
|
|
AdaptRegexp = true,
|
|
AdaptRegexp = true,
|
|
- Tolerant = true,
|
|
|
|
- Loc = true
|
|
|
|
|
|
+ Tolerant = true
|
|
};
|
|
};
|
|
|
|
|
|
-
|
|
|
|
private static readonly JsString _errorFunctionName = new JsString("Error");
|
|
private static readonly JsString _errorFunctionName = new JsString("Error");
|
|
private static readonly JsString _evalErrorFunctionName = new JsString("EvalError");
|
|
private static readonly JsString _evalErrorFunctionName = new JsString("EvalError");
|
|
private static readonly JsString _rangeErrorFunctionName = new JsString("RangeError");
|
|
private static readonly JsString _rangeErrorFunctionName = new JsString("RangeError");
|
|
@@ -81,9 +80,9 @@ namespace Jint
|
|
public ITypeConverter ClrTypeConverter { get; internal set; }
|
|
public ITypeConverter ClrTypeConverter { get; internal set; }
|
|
|
|
|
|
// cache of types used when resolving CLR type names
|
|
// cache of types used when resolving CLR type names
|
|
- internal readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
|
|
|
|
|
|
+ internal readonly Dictionary<string, Type> TypeCache = new();
|
|
|
|
|
|
- internal static Dictionary<Type, Func<Engine, object, JsValue>> TypeMappers = new Dictionary<Type, Func<Engine, object, JsValue>>
|
|
|
|
|
|
+ internal static Dictionary<Type, Func<Engine, object, JsValue>> TypeMappers = new()
|
|
{
|
|
{
|
|
{ typeof(bool), (engine, v) => (bool) v ? JsBoolean.True : JsBoolean.False },
|
|
{ typeof(bool), (engine, v) => (bool) v ? JsBoolean.True : JsBoolean.False },
|
|
{ typeof(byte), (engine, v) => JsNumber.Create((byte)v) },
|
|
{ typeof(byte), (engine, v) => JsNumber.Create((byte)v) },
|
|
@@ -101,17 +100,16 @@ namespace Jint
|
|
{ typeof(UInt16), (engine, v) => JsNumber.Create((UInt16)v) },
|
|
{ typeof(UInt16), (engine, v) => JsNumber.Create((UInt16)v) },
|
|
{ typeof(UInt32), (engine, v) => JsNumber.Create((UInt32)v) },
|
|
{ typeof(UInt32), (engine, v) => JsNumber.Create((UInt32)v) },
|
|
{ typeof(UInt64), (engine, v) => JsNumber.Create((UInt64)v) },
|
|
{ typeof(UInt64), (engine, v) => JsNumber.Create((UInt64)v) },
|
|
- { typeof(System.Text.RegularExpressions.Regex), (engine, v) => engine.RegExp.Construct((System.Text.RegularExpressions.Regex)v, "", engine) }
|
|
|
|
|
|
+ { typeof(System.Text.RegularExpressions.Regex), (engine, v) => engine.RegExp.Construct((System.Text.RegularExpressions.Regex)v, "") }
|
|
};
|
|
};
|
|
|
|
|
|
// shared frozen version
|
|
// shared frozen version
|
|
internal readonly PropertyDescriptor _callerCalleeArgumentsThrowerConfigurable;
|
|
internal readonly PropertyDescriptor _callerCalleeArgumentsThrowerConfigurable;
|
|
internal readonly PropertyDescriptor _callerCalleeArgumentsThrowerNonConfigurable;
|
|
internal readonly PropertyDescriptor _callerCalleeArgumentsThrowerNonConfigurable;
|
|
|
|
|
|
- internal readonly Dictionary<ClrPropertyDescriptorFactoriesKey, Func<Engine, object, PropertyDescriptor>> ClrPropertyDescriptorFactories =
|
|
|
|
- new Dictionary<ClrPropertyDescriptorFactoriesKey, Func<Engine, object, PropertyDescriptor>>();
|
|
|
|
|
|
+ internal static Dictionary<ClrPropertyDescriptorFactoriesKey, ReflectionAccessor> ReflectionAccessors = new();
|
|
|
|
|
|
- internal readonly JintCallStack CallStack = new JintCallStack();
|
|
|
|
|
|
+ internal readonly JintCallStack CallStack;
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
/// Constructs a new engine instance.
|
|
/// Constructs a new engine instance.
|
|
@@ -171,7 +169,7 @@ namespace Jint
|
|
// their configuration is delayed to a later step
|
|
// their configuration is delayed to a later step
|
|
|
|
|
|
// trigger initialization
|
|
// trigger initialization
|
|
- Global.GetProperty(JsString.Empty);
|
|
|
|
|
|
+ Global.EnsureInitialized();
|
|
|
|
|
|
// this is implementation dependent, and only to pass some unit tests
|
|
// this is implementation dependent, and only to pass some unit tests
|
|
Global._prototype = Object.PrototypeObject;
|
|
Global._prototype = Object.PrototypeObject;
|
|
@@ -195,23 +193,13 @@ namespace Jint
|
|
_isStrict = Options.IsStrict;
|
|
_isStrict = Options.IsStrict;
|
|
_constraints = Options._Constraints;
|
|
_constraints = Options._Constraints;
|
|
_referenceResolver = Options.ReferenceResolver;
|
|
_referenceResolver = Options.ReferenceResolver;
|
|
|
|
+ CallStack = new JintCallStack(Options.MaxRecursionDepth >= 0);
|
|
|
|
|
|
_referencePool = new ReferencePool();
|
|
_referencePool = new ReferencePool();
|
|
_argumentsInstancePool = new ArgumentsInstancePool(this);
|
|
_argumentsInstancePool = new ArgumentsInstancePool(this);
|
|
_jsValueArrayPool = new JsValueArrayPool();
|
|
_jsValueArrayPool = new JsValueArrayPool();
|
|
|
|
|
|
- if (Options._IsClrAllowed)
|
|
|
|
- {
|
|
|
|
- Global.SetProperty("System", new PropertyDescriptor(new NamespaceReference(this, "System"), PropertyFlag.AllForbidden));
|
|
|
|
- Global.SetProperty("importNamespace", new PropertyDescriptor(new ClrFunctionInstance(
|
|
|
|
- this,
|
|
|
|
- "importNamespace",
|
|
|
|
- (thisObj, arguments) => new NamespaceReference(this, TypeConverter.ToString(arguments.At(0)))), PropertyFlag.AllForbidden));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
Options.Apply(this);
|
|
Options.Apply(this);
|
|
-
|
|
|
|
- ClrTypeConverter ??= new DefaultTypeConverter(this);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
internal LexicalEnvironment GlobalEnvironment { get; }
|
|
internal LexicalEnvironment GlobalEnvironment { get; }
|
|
@@ -359,19 +347,27 @@ namespace Jint
|
|
return Execute(parser.ParseScript());
|
|
return Execute(parser.ParseScript());
|
|
}
|
|
}
|
|
|
|
|
|
- public Engine Execute(Script program)
|
|
|
|
|
|
+ public Engine Execute(Script script)
|
|
{
|
|
{
|
|
- ResetConstraints();
|
|
|
|
- ResetLastStatement();
|
|
|
|
- ResetCallStack();
|
|
|
|
|
|
+ return Execute(script, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ internal Engine Execute(Script script, bool resetState)
|
|
|
|
+ {
|
|
|
|
+ if (resetState)
|
|
|
|
+ {
|
|
|
|
+ ResetConstraints();
|
|
|
|
+ ResetLastStatement();
|
|
|
|
+ ResetCallStack();
|
|
|
|
+ }
|
|
|
|
|
|
- using (new StrictModeScope(_isStrict || program.Strict))
|
|
|
|
|
|
+ using (new StrictModeScope(_isStrict || script.Strict))
|
|
{
|
|
{
|
|
GlobalDeclarationInstantiation(
|
|
GlobalDeclarationInstantiation(
|
|
- program,
|
|
|
|
|
|
+ script,
|
|
GlobalEnvironment);
|
|
GlobalEnvironment);
|
|
|
|
|
|
- var list = new JintStatementList(this, null, program.Body);
|
|
|
|
|
|
+ var list = new JintStatementList(this, null, script.Body);
|
|
|
|
|
|
var result = list.Execute();
|
|
var result = list.Execute();
|
|
if (result.Type == CompletionType.Throw)
|
|
if (result.Type == CompletionType.Throw)
|
|
@@ -467,7 +463,7 @@ namespace Jint
|
|
if (baseValue.IsObject())
|
|
if (baseValue.IsObject())
|
|
{
|
|
{
|
|
var o = TypeConverter.ToObject(this, baseValue);
|
|
var o = TypeConverter.ToObject(this, baseValue);
|
|
- var v = o.Get(property);
|
|
|
|
|
|
+ var v = o.Get(property, reference.GetThisValue());
|
|
return v;
|
|
return v;
|
|
}
|
|
}
|
|
else
|
|
else
|
|
@@ -670,9 +666,9 @@ namespace Jint
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// Gets the last evaluated <see cref="INode"/>.
|
|
|
|
|
|
+ /// Gets the last evaluated <see cref="Node"/>.
|
|
/// </summary>
|
|
/// </summary>
|
|
- public Node GetLastSyntaxNode()
|
|
|
|
|
|
+ internal Node GetLastSyntaxNode()
|
|
{
|
|
{
|
|
return _lastSyntaxNode;
|
|
return _lastSyntaxNode;
|
|
}
|
|
}
|
|
@@ -684,7 +680,7 @@ namespace Jint
|
|
/// <param name="property">The name of the property to return.</param>
|
|
/// <param name="property">The name of the property to return.</param>
|
|
public JsValue GetValue(JsValue scope, JsValue property)
|
|
public JsValue GetValue(JsValue scope, JsValue property)
|
|
{
|
|
{
|
|
- var reference = _referencePool.Rent(scope, property, _isStrict);
|
|
|
|
|
|
+ var reference = _referencePool.Rent(scope, property, _isStrict, thisValue: null);
|
|
var jsValue = GetValue(reference, false);
|
|
var jsValue = GetValue(reference, false);
|
|
_referencePool.Return(reference);
|
|
_referencePool.Return(reference);
|
|
return jsValue;
|
|
return jsValue;
|
|
@@ -699,20 +695,20 @@ namespace Jint
|
|
return GetIdentifierReference(env, name, StrictModeScope.IsStrictModeCode);
|
|
return GetIdentifierReference(env, name, StrictModeScope.IsStrictModeCode);
|
|
}
|
|
}
|
|
|
|
|
|
- private Reference GetIdentifierReference(LexicalEnvironment lex, string name, in bool strict)
|
|
|
|
|
|
+ private Reference GetIdentifierReference(LexicalEnvironment env, string name, bool strict)
|
|
{
|
|
{
|
|
- if (lex is null)
|
|
|
|
|
|
+ if (env is null)
|
|
{
|
|
{
|
|
return new Reference(JsValue.Undefined, name, strict);
|
|
return new Reference(JsValue.Undefined, name, strict);
|
|
}
|
|
}
|
|
|
|
|
|
- var envRec = lex._record;
|
|
|
|
|
|
+ var envRec = env._record;
|
|
if (envRec.HasBinding(name))
|
|
if (envRec.HasBinding(name))
|
|
{
|
|
{
|
|
return new Reference(envRec, name, strict);
|
|
return new Reference(envRec, name, strict);
|
|
}
|
|
}
|
|
|
|
|
|
- return GetIdentifierReference(lex._outer, name, strict);
|
|
|
|
|
|
+ return GetIdentifierReference(env._outer, name, strict);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -795,6 +791,12 @@ namespace Jint
|
|
for (var j = 0; j < boundNames.Count; j++)
|
|
for (var j = 0; j < boundNames.Count; j++)
|
|
{
|
|
{
|
|
var vn = boundNames[j];
|
|
var vn = boundNames[j];
|
|
|
|
+
|
|
|
|
+ if (envRec.HasLexicalDeclaration(vn))
|
|
|
|
+ {
|
|
|
|
+ ExceptionHelper.ThrowSyntaxError(this, $"Identifier '{vn}' has already been declared");
|
|
|
|
+ }
|
|
|
|
+
|
|
if (!declaredFunctionNames.Contains(vn))
|
|
if (!declaredFunctionNames.Contains(vn))
|
|
{
|
|
{
|
|
var vnDefinable = envRec.CanDeclareGlobalVar(vn);
|
|
var vnDefinable = envRec.CanDeclareGlobalVar(vn);
|
|
@@ -840,7 +842,13 @@ namespace Jint
|
|
|
|
|
|
foreach (var f in functionToInitialize)
|
|
foreach (var f in functionToInitialize)
|
|
{
|
|
{
|
|
- var fn = f.Id.Name;
|
|
|
|
|
|
+ var fn = f.Id!.Name;
|
|
|
|
+
|
|
|
|
+ if (envRec.HasLexicalDeclaration(fn))
|
|
|
|
+ {
|
|
|
|
+ ExceptionHelper.ThrowSyntaxError(this, $"Identifier '{fn}' has already been declared");
|
|
|
|
+ }
|
|
|
|
+
|
|
var fo = Function.CreateFunctionObject(f, env);
|
|
var fo = Function.CreateFunctionObject(f, env);
|
|
envRec.CreateGlobalFunctionBinding(fn, fo, canBeDeleted: false);
|
|
envRec.CreateGlobalFunctionBinding(fn, fo, canBeDeleted: false);
|
|
}
|
|
}
|
|
@@ -1204,5 +1212,91 @@ namespace Jint
|
|
{
|
|
{
|
|
_executionContexts.ReplaceTopVariableEnvironment(newEnv);
|
|
_executionContexts.ReplaceTopVariableEnvironment(newEnv);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ internal JsValue Call(ICallable callable, JsValue thisObject, JsValue[] arguments, JintExpression expression)
|
|
|
|
+ {
|
|
|
|
+ if (callable is FunctionInstance functionInstance)
|
|
|
|
+ {
|
|
|
|
+ return Call(functionInstance, thisObject, arguments, expression);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return callable.Call(thisObject, arguments);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ internal JsValue Construct(IConstructor constructor, JsValue[] arguments, JsValue newTarget, JintExpression expression)
|
|
|
|
+ {
|
|
|
|
+ if (constructor is FunctionInstance functionInstance)
|
|
|
|
+ {
|
|
|
|
+ return Construct(functionInstance, arguments, newTarget, expression);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return constructor.Construct(arguments, newTarget);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ internal JsValue Call(
|
|
|
|
+ FunctionInstance functionInstance,
|
|
|
|
+ JsValue thisObject,
|
|
|
|
+ JsValue[] arguments,
|
|
|
|
+ JintExpression expression)
|
|
|
|
+ {
|
|
|
|
+ var callStackElement = new CallStackElement(functionInstance, expression);
|
|
|
|
+ var recursionDepth = CallStack.Push(callStackElement);
|
|
|
|
+
|
|
|
|
+ if (recursionDepth > Options.MaxRecursionDepth)
|
|
|
|
+ {
|
|
|
|
+ // pop the current element as it was never reached
|
|
|
|
+ CallStack.Pop();
|
|
|
|
+ ExceptionHelper.ThrowRecursionDepthOverflowException(CallStack, callStackElement.ToString());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (_isDebugMode)
|
|
|
|
+ {
|
|
|
|
+ DebugHandler.AddToDebugCallStack(functionInstance);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var result = functionInstance.Call(thisObject, arguments);
|
|
|
|
+
|
|
|
|
+ if (_isDebugMode)
|
|
|
|
+ {
|
|
|
|
+ DebugHandler.PopDebugCallStack();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ CallStack.Pop();
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ internal JsValue Construct(
|
|
|
|
+ FunctionInstance functionInstance,
|
|
|
|
+ JsValue[] arguments,
|
|
|
|
+ JsValue newTarget,
|
|
|
|
+ JintExpression expression)
|
|
|
|
+ {
|
|
|
|
+ var callStackElement = new CallStackElement(functionInstance, expression);
|
|
|
|
+ var recursionDepth = CallStack.Push(callStackElement);
|
|
|
|
+
|
|
|
|
+ if (recursionDepth > Options.MaxRecursionDepth)
|
|
|
|
+ {
|
|
|
|
+ // pop the current element as it was never reached
|
|
|
|
+ CallStack.Pop();
|
|
|
|
+ ExceptionHelper.ThrowRecursionDepthOverflowException(CallStack, callStackElement.ToString());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (_isDebugMode)
|
|
|
|
+ {
|
|
|
|
+ DebugHandler.AddToDebugCallStack(functionInstance);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var result = ((IConstructor) functionInstance).Construct(arguments, newTarget);
|
|
|
|
+
|
|
|
|
+ if (_isDebugMode)
|
|
|
|
+ {
|
|
|
|
+ DebugHandler.PopDebugCallStack();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ CallStack.Pop();
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|