Engine.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.CompilerServices;
  4. using Esprima;
  5. using Esprima.Ast;
  6. using Jint.Native;
  7. using Jint.Native.Array;
  8. using Jint.Native.Boolean;
  9. using Jint.Native.Date;
  10. using Jint.Native.Error;
  11. using Jint.Native.Function;
  12. using Jint.Native.Global;
  13. using Jint.Native.Json;
  14. using Jint.Native.Math;
  15. using Jint.Native.Number;
  16. using Jint.Native.Object;
  17. using Jint.Native.RegExp;
  18. using Jint.Native.String;
  19. using Jint.Native.Symbol;
  20. using Jint.Pooling;
  21. using Jint.Runtime;
  22. using Jint.Runtime.CallStack;
  23. using Jint.Runtime.Debugger;
  24. using Jint.Runtime.Descriptors;
  25. using Jint.Runtime.Environments;
  26. using Jint.Runtime.Interop;
  27. using Jint.Runtime.References;
  28. namespace Jint
  29. {
  30. public sealed class Engine
  31. {
  32. private static readonly ParserOptions DefaultParserOptions = new ParserOptions
  33. {
  34. AdaptRegexp = true,
  35. Tolerant = false,
  36. Loc = true
  37. };
  38. private readonly ExpressionInterpreter _expressions;
  39. private readonly StatementInterpreter _statements;
  40. private readonly ExecutionContextStack _executionContexts;
  41. private JsValue _completionValue = JsValue.Undefined;
  42. private int _statementsCount;
  43. private long _initialMemoryUsage;
  44. private long _timeoutTicks;
  45. private INode _lastSyntaxNode;
  46. // cached access
  47. private readonly bool _isDebugMode;
  48. private readonly bool _isStrict;
  49. private readonly int _maxStatements;
  50. private readonly long _memoryLimit;
  51. private readonly bool _runBeforeStatementChecks;
  52. private readonly IReferenceResolver _referenceResolver;
  53. internal readonly ReferencePool _referencePool;
  54. internal readonly ArgumentsInstancePool _argumentsInstancePool;
  55. internal readonly JsValueArrayPool _jsValueArrayPool;
  56. public ITypeConverter ClrTypeConverter;
  57. // cache of types used when resolving CLR type names
  58. internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
  59. internal static Dictionary<Type, Func<Engine, object, JsValue>> TypeMappers = new Dictionary<Type, Func<Engine, object, JsValue>>
  60. {
  61. { typeof(bool), (Engine engine, object v) => (bool) v ? JsBoolean.True : JsBoolean.False },
  62. { typeof(byte), (Engine engine, object v) => JsNumber.Create((byte)v) },
  63. { typeof(char), (Engine engine, object v) => JsString.Create((char)v) },
  64. { typeof(DateTime), (Engine engine, object v) => engine.Date.Construct((DateTime)v) },
  65. { typeof(DateTimeOffset), (Engine engine, object v) => engine.Date.Construct((DateTimeOffset)v) },
  66. { typeof(decimal), (Engine engine, object v) => (JsValue) (double)(decimal)v },
  67. { typeof(double), (Engine engine, object v) => (JsValue)(double)v },
  68. { typeof(Int16), (Engine engine, object v) => JsNumber.Create((Int16)v) },
  69. { typeof(Int32), (Engine engine, object v) => JsNumber.Create((Int32)v) },
  70. { typeof(Int64), (Engine engine, object v) => (JsValue)(Int64)v },
  71. { typeof(SByte), (Engine engine, object v) => JsNumber.Create((SByte)v) },
  72. { typeof(Single), (Engine engine, object v) => (JsValue)(Single)v },
  73. { typeof(string), (Engine engine, object v) => (JsValue) (string)v },
  74. { typeof(UInt16), (Engine engine, object v) => JsNumber.Create((UInt16)v) },
  75. { typeof(UInt32), (Engine engine, object v) => JsNumber.Create((UInt32)v) },
  76. { typeof(UInt64), (Engine engine, object v) => JsNumber.Create((UInt64)v) },
  77. { typeof(System.Text.RegularExpressions.Regex), (Engine engine, object v) => engine.RegExp.Construct((System.Text.RegularExpressions.Regex)v, "") }
  78. };
  79. internal readonly Dictionary<(Type, string), Func<Engine, object, PropertyDescriptor>> ClrPropertyDescriptorFactories =
  80. new Dictionary<(Type, string), Func<Engine, object, PropertyDescriptor>>();
  81. internal JintCallStack CallStack = new JintCallStack();
  82. static Engine()
  83. {
  84. var methodInfo = typeof(GC).GetMethod("GetAllocatedBytesForCurrentThread");
  85. if (methodInfo != null)
  86. {
  87. GetAllocatedBytesForCurrentThread = (Func<long>)Delegate.CreateDelegate(typeof(Func<long>), null, methodInfo);
  88. }
  89. }
  90. public Engine() : this(null)
  91. {
  92. }
  93. public Engine(Action<Options> options)
  94. {
  95. _executionContexts = new ExecutionContextStack();
  96. Global = GlobalObject.CreateGlobalObject(this);
  97. Object = ObjectConstructor.CreateObjectConstructor(this);
  98. Function = FunctionConstructor.CreateFunctionConstructor(this);
  99. Symbol = SymbolConstructor.CreateSymbolConstructor(this);
  100. Array = ArrayConstructor.CreateArrayConstructor(this);
  101. String = StringConstructor.CreateStringConstructor(this);
  102. RegExp = RegExpConstructor.CreateRegExpConstructor(this);
  103. Number = NumberConstructor.CreateNumberConstructor(this);
  104. Boolean = BooleanConstructor.CreateBooleanConstructor(this);
  105. Date = DateConstructor.CreateDateConstructor(this);
  106. Math = MathInstance.CreateMathObject(this);
  107. Json = JsonInstance.CreateJsonObject(this);
  108. Error = ErrorConstructor.CreateErrorConstructor(this, "Error");
  109. EvalError = ErrorConstructor.CreateErrorConstructor(this, "EvalError");
  110. RangeError = ErrorConstructor.CreateErrorConstructor(this, "RangeError");
  111. ReferenceError = ErrorConstructor.CreateErrorConstructor(this, "ReferenceError");
  112. SyntaxError = ErrorConstructor.CreateErrorConstructor(this, "SyntaxError");
  113. TypeError = ErrorConstructor.CreateErrorConstructor(this, "TypeError");
  114. UriError = ErrorConstructor.CreateErrorConstructor(this, "URIError");
  115. GlobalSymbolRegistry = new GlobalSymbolRegistry();
  116. // Because the properties might need some of the built-in object
  117. // their configuration is delayed to a later step
  118. Global.Configure();
  119. Object.Configure();
  120. Object.PrototypeObject.Configure();
  121. Symbol.Configure();
  122. Symbol.PrototypeObject.Configure();
  123. Function.Configure();
  124. Function.PrototypeObject.Configure();
  125. Array.Configure();
  126. Array.PrototypeObject.Configure();
  127. String.Configure();
  128. String.PrototypeObject.Configure();
  129. RegExp.Configure();
  130. RegExp.PrototypeObject.Configure();
  131. Number.Configure();
  132. Number.PrototypeObject.Configure();
  133. Boolean.Configure();
  134. Boolean.PrototypeObject.Configure();
  135. Date.Configure();
  136. Date.PrototypeObject.Configure();
  137. Math.Configure();
  138. Json.Configure();
  139. Error.Configure();
  140. Error.PrototypeObject.Configure();
  141. // create the global environment http://www.ecma-international.org/ecma-262/5.1/#sec-10.2.3
  142. GlobalEnvironment = LexicalEnvironment.NewObjectEnvironment(this, Global, null, false);
  143. // create the global execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.1.1
  144. EnterExecutionContext(GlobalEnvironment, GlobalEnvironment, Global);
  145. Options = new Options();
  146. options?.Invoke(Options);
  147. // gather some options as fields for faster checks
  148. _isDebugMode = Options.IsDebugMode;
  149. _isStrict = Options.IsStrict;
  150. _maxStatements = Options._MaxStatements;
  151. _referenceResolver = Options.ReferenceResolver;
  152. _memoryLimit = Options._MemoryLimit;
  153. _runBeforeStatementChecks = (_maxStatements > 0 &&_maxStatements < int.MaxValue)
  154. || Options._TimeoutInterval.Ticks > 0
  155. || _memoryLimit > 0
  156. || _isDebugMode;
  157. _referencePool = new ReferencePool();
  158. _argumentsInstancePool = new ArgumentsInstancePool(this);
  159. _jsValueArrayPool = new JsValueArrayPool();
  160. Eval = new EvalFunctionInstance(this, System.Array.Empty<string>(), LexicalEnvironment.NewDeclarativeEnvironment(this, ExecutionContext.LexicalEnvironment), StrictModeScope.IsStrictModeCode);
  161. Global.FastAddProperty("eval", Eval, true, false, true);
  162. _statements = new StatementInterpreter(this);
  163. _expressions = new ExpressionInterpreter(this);
  164. if (Options._IsClrAllowed)
  165. {
  166. Global.FastAddProperty("System", new NamespaceReference(this, "System"), false, false, false);
  167. Global.FastAddProperty("importNamespace", new ClrFunctionInstance(this, (thisObj, arguments) =>
  168. {
  169. return new NamespaceReference(this, TypeConverter.ToString(arguments.At(0)));
  170. }), false, false, false);
  171. }
  172. ClrTypeConverter = new DefaultTypeConverter(this);
  173. BreakPoints = new List<BreakPoint>();
  174. DebugHandler = new DebugHandler(this);
  175. }
  176. public LexicalEnvironment GlobalEnvironment { get; }
  177. public GlobalObject Global { get; }
  178. public ObjectConstructor Object { get; }
  179. public FunctionConstructor Function { get; }
  180. public ArrayConstructor Array { get; }
  181. public StringConstructor String { get; }
  182. public RegExpConstructor RegExp { get; }
  183. public BooleanConstructor Boolean { get; }
  184. public NumberConstructor Number { get; }
  185. public DateConstructor Date { get; }
  186. public MathInstance Math { get; }
  187. public JsonInstance Json { get; }
  188. public SymbolConstructor Symbol { get; }
  189. public EvalFunctionInstance Eval { get; }
  190. public ErrorConstructor Error { get; }
  191. public ErrorConstructor EvalError { get; }
  192. public ErrorConstructor SyntaxError { get; }
  193. public ErrorConstructor TypeError { get; }
  194. public ErrorConstructor RangeError { get; }
  195. public ErrorConstructor ReferenceError { get; }
  196. public ErrorConstructor UriError { get; }
  197. public ref readonly ExecutionContext ExecutionContext
  198. {
  199. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  200. get { return ref _executionContexts.Peek(); }
  201. }
  202. public GlobalSymbolRegistry GlobalSymbolRegistry { get; }
  203. internal Options Options { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; }
  204. #region Debugger
  205. public delegate StepMode DebugStepDelegate(object sender, DebugInformation e);
  206. public delegate StepMode BreakDelegate(object sender, DebugInformation e);
  207. public event DebugStepDelegate Step;
  208. public event BreakDelegate Break;
  209. internal DebugHandler DebugHandler { get; private set; }
  210. public List<BreakPoint> BreakPoints { get; private set; }
  211. internal StepMode? InvokeStepEvent(DebugInformation info)
  212. {
  213. return Step?.Invoke(this, info);
  214. }
  215. internal StepMode? InvokeBreakEvent(DebugInformation info)
  216. {
  217. return Break?.Invoke(this, info);
  218. }
  219. #endregion
  220. private static readonly Func<long> GetAllocatedBytesForCurrentThread;
  221. public void EnterExecutionContext(
  222. LexicalEnvironment lexicalEnvironment,
  223. LexicalEnvironment variableEnvironment,
  224. JsValue thisBinding)
  225. {
  226. var context = new ExecutionContext(
  227. lexicalEnvironment,
  228. variableEnvironment,
  229. thisBinding);
  230. _executionContexts.Push(context);
  231. }
  232. public Engine SetValue(string name, Delegate value)
  233. {
  234. Global.FastAddProperty(name, new DelegateWrapper(this, value), true, false, true);
  235. return this;
  236. }
  237. public Engine SetValue(string name, string value)
  238. {
  239. return SetValue(name, (JsValue) value);
  240. }
  241. public Engine SetValue(string name, double value)
  242. {
  243. return SetValue(name, JsNumber.Create(value));
  244. }
  245. public Engine SetValue(string name, int value)
  246. {
  247. return SetValue(name, JsNumber.Create(value));
  248. }
  249. public Engine SetValue(string name, bool value)
  250. {
  251. return SetValue(name, value ? JsBoolean.True : JsBoolean.False);
  252. }
  253. public Engine SetValue(string name, JsValue value)
  254. {
  255. Global.Put(name, value, false);
  256. return this;
  257. }
  258. public Engine SetValue(string name, object obj)
  259. {
  260. return SetValue(name, JsValue.FromObject(this, obj));
  261. }
  262. public void LeaveExecutionContext()
  263. {
  264. _executionContexts.Pop();
  265. }
  266. /// <summary>
  267. /// Initializes the statements count
  268. /// </summary>
  269. public void ResetStatementsCount()
  270. {
  271. _statementsCount = 0;
  272. }
  273. public void ResetMemoryUsage()
  274. {
  275. if (GetAllocatedBytesForCurrentThread != null)
  276. {
  277. _initialMemoryUsage = GetAllocatedBytesForCurrentThread();
  278. }
  279. }
  280. public void ResetTimeoutTicks()
  281. {
  282. var timeoutIntervalTicks = Options._TimeoutInterval.Ticks;
  283. _timeoutTicks = timeoutIntervalTicks > 0 ? DateTime.UtcNow.Ticks + timeoutIntervalTicks : 0;
  284. }
  285. /// <summary>
  286. /// Initializes list of references of called functions
  287. /// </summary>
  288. public void ResetCallStack()
  289. {
  290. CallStack.Clear();
  291. }
  292. public Engine Execute(string source)
  293. {
  294. return Execute(source, DefaultParserOptions);
  295. }
  296. public Engine Execute(string source, ParserOptions parserOptions)
  297. {
  298. var parser = new JavaScriptParser(source, parserOptions);
  299. return Execute(parser.ParseProgram());
  300. }
  301. public Engine Execute(Program program)
  302. {
  303. ResetStatementsCount();
  304. if (_memoryLimit > 0)
  305. {
  306. ResetMemoryUsage();
  307. }
  308. ResetTimeoutTicks();
  309. ResetLastStatement();
  310. ResetCallStack();
  311. using (new StrictModeScope(_isStrict || program.Strict))
  312. {
  313. DeclarationBindingInstantiation(DeclarationBindingType.GlobalCode, program.HoistingScope.FunctionDeclarations, program.HoistingScope.VariableDeclarations, null, null);
  314. var result = _statements.ExecuteProgram(program);
  315. if (result.Type == CompletionType.Throw)
  316. {
  317. var ex = new JavaScriptException(result.GetValueOrDefault()).SetCallstack(this, result.Location);
  318. throw ex;
  319. }
  320. _completionValue = result.GetValueOrDefault();
  321. }
  322. return this;
  323. }
  324. private void ResetLastStatement()
  325. {
  326. _lastSyntaxNode = null;
  327. }
  328. /// <summary>
  329. /// Gets the last evaluated statement completion value
  330. /// </summary>
  331. public JsValue GetCompletionValue()
  332. {
  333. return _completionValue;
  334. }
  335. public Completion ExecuteStatement(Statement statement)
  336. {
  337. _lastSyntaxNode = statement;
  338. if (_runBeforeStatementChecks)
  339. {
  340. BeforeExecuteStatement(statement);
  341. }
  342. switch (statement.Type)
  343. {
  344. case Nodes.BlockStatement:
  345. return _statements.ExecuteStatementList(((BlockStatement) statement).Body);
  346. case Nodes.ReturnStatement:
  347. var jsValue = ((ReturnStatement) statement).Argument == null
  348. ? Undefined.Instance
  349. : GetValue(EvaluateExpression(((ReturnStatement) statement).Argument), true);
  350. return new Completion(CompletionType.Return, jsValue, null);
  351. case Nodes.VariableDeclaration:
  352. return _statements.ExecuteVariableDeclaration((VariableDeclaration) statement);
  353. case Nodes.BreakStatement:
  354. return _statements.ExecuteBreakStatement((BreakStatement) statement);
  355. case Nodes.ContinueStatement:
  356. return _statements.ExecuteContinueStatement((ContinueStatement) statement);
  357. case Nodes.DoWhileStatement:
  358. return _statements.ExecuteDoWhileStatement((DoWhileStatement) statement);
  359. case Nodes.EmptyStatement:
  360. return new Completion(CompletionType.Normal, null, null);
  361. case Nodes.ExpressionStatement:
  362. return new Completion(
  363. CompletionType.Normal,
  364. GetValue(EvaluateExpression(((ExpressionStatement) statement).Expression), true),
  365. null);
  366. case Nodes.ForStatement:
  367. return _statements.ExecuteForStatement((ForStatement) statement);
  368. case Nodes.ForInStatement:
  369. return _statements.ExecuteForInStatement((ForInStatement) statement);
  370. case Nodes.IfStatement:
  371. return _statements.ExecuteIfStatement((IfStatement) statement);
  372. case Nodes.LabeledStatement:
  373. return _statements.ExecuteLabeledStatement((LabeledStatement) statement);
  374. case Nodes.SwitchStatement:
  375. return _statements.ExecuteSwitchStatement((SwitchStatement) statement);
  376. case Nodes.FunctionDeclaration:
  377. return new Completion(CompletionType.Normal, null, null);
  378. case Nodes.ThrowStatement:
  379. return _statements.ExecuteThrowStatement((ThrowStatement) statement);
  380. case Nodes.TryStatement:
  381. return _statements.ExecuteTryStatement((TryStatement) statement);
  382. case Nodes.WhileStatement:
  383. return _statements.ExecuteWhileStatement((WhileStatement) statement);
  384. case Nodes.WithStatement:
  385. return _statements.ExecuteWithStatement((WithStatement) statement);
  386. case Nodes.DebuggerStatement:
  387. return _statements.ExecuteDebuggerStatement((DebuggerStatement) statement);
  388. case Nodes.Program:
  389. return _statements.ExecuteProgram((Program) statement);
  390. default:
  391. ExceptionHelper.ThrowArgumentOutOfRangeException();
  392. return new Completion(CompletionType.Normal, null, null);
  393. }
  394. }
  395. private void BeforeExecuteStatement(Statement statement)
  396. {
  397. if (_maxStatements > 0 && _statementsCount++ > _maxStatements)
  398. {
  399. ExceptionHelper.ThrowStatementsCountOverflowException();
  400. }
  401. if (_timeoutTicks > 0 && _timeoutTicks < DateTime.UtcNow.Ticks)
  402. {
  403. ExceptionHelper.ThrowTimeoutException();
  404. }
  405. if (_memoryLimit > 0)
  406. {
  407. if (GetAllocatedBytesForCurrentThread != null)
  408. {
  409. var memoryUsage = GetAllocatedBytesForCurrentThread() - _initialMemoryUsage;
  410. if (memoryUsage > _memoryLimit)
  411. {
  412. ExceptionHelper.ThrowMemoryLimitExceededException($"Script has allocated {memoryUsage} but is limited to {_memoryLimit}");
  413. }
  414. }
  415. else
  416. {
  417. ExceptionHelper.ThrowPlatformNotSupportedException("The current platform doesn't support MemoryLimit.");
  418. }
  419. }
  420. if (_isDebugMode)
  421. {
  422. DebugHandler.OnStep(statement);
  423. }
  424. }
  425. public object EvaluateExpression(INode expression)
  426. {
  427. _lastSyntaxNode = expression;
  428. switch (expression.Type)
  429. {
  430. case Nodes.AssignmentExpression:
  431. return _expressions.EvaluateAssignmentExpression((AssignmentExpression) expression);
  432. case Nodes.ArrayExpression:
  433. return _expressions.EvaluateArrayExpression((ArrayExpression) expression);
  434. case Nodes.BinaryExpression:
  435. return _expressions.EvaluateBinaryExpression((BinaryExpression) expression);
  436. case Nodes.CallExpression:
  437. return _expressions.EvaluateCallExpression((CallExpression) expression);
  438. case Nodes.ConditionalExpression:
  439. return _expressions.EvaluateConditionalExpression((ConditionalExpression) expression);
  440. case Nodes.FunctionExpression:
  441. return _expressions.EvaluateFunctionExpression((IFunction) expression);
  442. case Nodes.Identifier:
  443. return _expressions.EvaluateIdentifier((Identifier) expression);
  444. case Nodes.Literal:
  445. return _expressions.EvaluateLiteral((Literal) expression);
  446. case Nodes.LogicalExpression:
  447. return _expressions.EvaluateLogicalExpression((BinaryExpression) expression);
  448. case Nodes.MemberExpression:
  449. return _expressions.EvaluateMemberExpression((MemberExpression) expression);
  450. case Nodes.NewExpression:
  451. return _expressions.EvaluateNewExpression((NewExpression) expression);
  452. case Nodes.ObjectExpression:
  453. return _expressions.EvaluateObjectExpression((ObjectExpression) expression);
  454. case Nodes.SequenceExpression:
  455. return _expressions.EvaluateSequenceExpression((SequenceExpression) expression);
  456. case Nodes.ThisExpression:
  457. return _expressions.EvaluateThisExpression((ThisExpression) expression);
  458. case Nodes.UpdateExpression:
  459. return _expressions.EvaluateUpdateExpression((UpdateExpression) expression);
  460. case Nodes.UnaryExpression:
  461. return _expressions.EvaluateUnaryExpression((UnaryExpression) expression);
  462. default:
  463. ExceptionHelper.ThrowArgumentOutOfRangeException();
  464. return null;
  465. }
  466. }
  467. /// <summary>
  468. /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.7.1
  469. /// </summary>
  470. public JsValue GetValue(object value)
  471. {
  472. return GetValue(value, false);
  473. }
  474. internal JsValue GetValue(object value, bool returnReferenceToPool)
  475. {
  476. if (value is JsValue jsValue)
  477. {
  478. return jsValue;
  479. }
  480. if (!(value is Reference reference))
  481. {
  482. return ((Completion) value).Value;
  483. }
  484. if (reference._baseValue._type == Types.Undefined)
  485. {
  486. if (_referenceResolver != null &&
  487. _referenceResolver.TryUnresolvableReference(this, reference, out JsValue val))
  488. {
  489. return val;
  490. }
  491. ExceptionHelper.ThrowReferenceError(this, reference.GetReferencedName() + " is not defined");
  492. }
  493. var baseValue = reference._baseValue;
  494. if (reference.IsPropertyReference())
  495. {
  496. if (_referenceResolver != null &&
  497. _referenceResolver.TryPropertyReference(this, reference, ref baseValue))
  498. {
  499. return baseValue;
  500. }
  501. var referencedName = reference._name;
  502. if (returnReferenceToPool)
  503. {
  504. _referencePool.Return(reference);
  505. }
  506. if (!(reference._baseValue._type != Types.Object && reference._baseValue._type != Types.None))
  507. {
  508. var o = TypeConverter.ToObject(this, baseValue);
  509. var v = o.Get(referencedName);
  510. return v;
  511. }
  512. else
  513. {
  514. var o = TypeConverter.ToObject(this, baseValue);
  515. var desc = o.GetProperty(referencedName);
  516. if (desc == PropertyDescriptor.Undefined)
  517. {
  518. return JsValue.Undefined;
  519. }
  520. if (desc.IsDataDescriptor())
  521. {
  522. return desc.Value;
  523. }
  524. var getter = desc.Get;
  525. if (getter.IsUndefined())
  526. {
  527. return Undefined.Instance;
  528. }
  529. var callable = (ICallable)getter.AsObject();
  530. return callable.Call(baseValue, Arguments.Empty);
  531. }
  532. }
  533. var record = (EnvironmentRecord) baseValue;
  534. if (ReferenceEquals(record, null))
  535. {
  536. ExceptionHelper.ThrowArgumentException();
  537. }
  538. var bindingValue = record.GetBindingValue(reference._name, reference._strict);
  539. if (returnReferenceToPool)
  540. {
  541. _referencePool.Return(reference);
  542. }
  543. return bindingValue;
  544. }
  545. /// <summary>
  546. /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.7.2
  547. /// </summary>
  548. /// <param name="reference"></param>
  549. /// <param name="value"></param>
  550. public void PutValue(Reference reference, JsValue value)
  551. {
  552. if (reference._baseValue._type == Types.Undefined)
  553. {
  554. if (reference._strict)
  555. {
  556. ExceptionHelper.ThrowReferenceError(this);
  557. }
  558. Global.Put(reference._name, value, false);
  559. }
  560. else if (reference.IsPropertyReference())
  561. {
  562. var baseValue = reference._baseValue;
  563. if (reference._baseValue._type == Types.Object || reference._baseValue._type == Types.None)
  564. {
  565. ((ObjectInstance) baseValue).Put(reference._name, value, reference._strict);
  566. }
  567. else
  568. {
  569. PutPrimitiveBase(baseValue, reference._name, value, reference._strict);
  570. }
  571. }
  572. else
  573. {
  574. var baseValue = reference._baseValue;
  575. ((EnvironmentRecord) baseValue).SetMutableBinding(reference._name, value, reference._strict);
  576. }
  577. }
  578. /// <summary>
  579. /// Used by PutValue when the reference has a primitive base value
  580. /// </summary>
  581. public void PutPrimitiveBase(JsValue b, string name, JsValue value, bool throwOnError)
  582. {
  583. var o = TypeConverter.ToObject(this, b);
  584. if (!o.CanPut(name))
  585. {
  586. if (throwOnError)
  587. {
  588. ExceptionHelper.ThrowTypeError(this);
  589. }
  590. return;
  591. }
  592. var ownDesc = o.GetOwnProperty(name);
  593. if (ownDesc.IsDataDescriptor())
  594. {
  595. if (throwOnError)
  596. {
  597. ExceptionHelper.ThrowTypeError(this);
  598. }
  599. return;
  600. }
  601. var desc = o.GetProperty(name);
  602. if (desc.IsAccessorDescriptor())
  603. {
  604. var setter = (ICallable)desc.Set.AsObject();
  605. setter.Call(b, new[] { value });
  606. }
  607. else
  608. {
  609. if (throwOnError)
  610. {
  611. ExceptionHelper.ThrowTypeError(this);
  612. }
  613. }
  614. }
  615. /// <summary>
  616. /// Invoke the current value as function.
  617. /// </summary>
  618. /// <param name="propertyName">The name of the function to call.</param>
  619. /// <param name="arguments">The arguments of the function call.</param>
  620. /// <returns>The value returned by the function call.</returns>
  621. public JsValue Invoke(string propertyName, params object[] arguments)
  622. {
  623. return Invoke(propertyName, null, arguments);
  624. }
  625. /// <summary>
  626. /// Invoke the current value as function.
  627. /// </summary>
  628. /// <param name="propertyName">The name of the function to call.</param>
  629. /// <param name="thisObj">The this value inside the function call.</param>
  630. /// <param name="arguments">The arguments of the function call.</param>
  631. /// <returns>The value returned by the function call.</returns>
  632. public JsValue Invoke(string propertyName, object thisObj, object[] arguments)
  633. {
  634. var value = GetValue(propertyName);
  635. return Invoke(value, thisObj, arguments);
  636. }
  637. /// <summary>
  638. /// Invoke the current value as function.
  639. /// </summary>
  640. /// <param name="value">The function to call.</param>
  641. /// <param name="arguments">The arguments of the function call.</param>
  642. /// <returns>The value returned by the function call.</returns>
  643. public JsValue Invoke(JsValue value, params object[] arguments)
  644. {
  645. return Invoke(value, null, arguments);
  646. }
  647. /// <summary>
  648. /// Invoke the current value as function.
  649. /// </summary>
  650. /// <param name="value">The function to call.</param>
  651. /// <param name="thisObj">The this value inside the function call.</param>
  652. /// <param name="arguments">The arguments of the function call.</param>
  653. /// <returns>The value returned by the function call.</returns>
  654. public JsValue Invoke(JsValue value, object thisObj, object[] arguments)
  655. {
  656. var callable = value as ICallable ?? ExceptionHelper.ThrowArgumentException<ICallable>("Can only invoke functions");
  657. var items = _jsValueArrayPool.RentArray(arguments.Length);
  658. for (int i = 0; i < arguments.Length; ++i)
  659. {
  660. items[i] = JsValue.FromObject(this, arguments[i]);
  661. }
  662. var result = callable.Call(JsValue.FromObject(this, thisObj), items);
  663. _jsValueArrayPool.ReturnArray(items);
  664. return result;
  665. }
  666. /// <summary>
  667. /// Gets a named value from the Global scope.
  668. /// </summary>
  669. /// <param name="propertyName">The name of the property to return.</param>
  670. public JsValue GetValue(string propertyName)
  671. {
  672. return GetValue(Global, propertyName);
  673. }
  674. /// <summary>
  675. /// Gets the last evaluated <see cref="INode"/>.
  676. /// </summary>
  677. public INode GetLastSyntaxNode()
  678. {
  679. return _lastSyntaxNode;
  680. }
  681. /// <summary>
  682. /// Gets a named value from the specified scope.
  683. /// </summary>
  684. /// <param name="scope">The scope to get the property from.</param>
  685. /// <param name="propertyName">The name of the property to return.</param>
  686. public JsValue GetValue(JsValue scope, string propertyName)
  687. {
  688. AssertNotNullOrEmpty(nameof(propertyName), propertyName);
  689. var reference = _referencePool.Rent(scope, propertyName, _isStrict);
  690. var jsValue = GetValue(reference, false);
  691. _referencePool.Return(reference);
  692. return jsValue;
  693. }
  694. // http://www.ecma-international.org/ecma-262/5.1/#sec-10.5
  695. internal bool DeclarationBindingInstantiation(
  696. DeclarationBindingType declarationBindingType,
  697. List<FunctionDeclaration> functionDeclarations,
  698. List<VariableDeclaration> variableDeclarations,
  699. FunctionInstance functionInstance,
  700. JsValue[] arguments)
  701. {
  702. var env = ExecutionContext.VariableEnvironment._record;
  703. bool configurableBindings = declarationBindingType == DeclarationBindingType.EvalCode;
  704. var strict = StrictModeScope.IsStrictModeCode;
  705. var der = env as DeclarativeEnvironmentRecord;
  706. bool canReleaseArgumentsInstance = false;
  707. if (declarationBindingType == DeclarationBindingType.FunctionCode)
  708. {
  709. var argsObj = _argumentsInstancePool.Rent(functionInstance, functionInstance._formalParameters, arguments, env, strict);
  710. canReleaseArgumentsInstance = true;
  711. if (!ReferenceEquals(der, null))
  712. {
  713. der.AddFunctionParameters(functionInstance, arguments, argsObj);
  714. }
  715. else
  716. {
  717. // slow path
  718. var parameters = functionInstance._formalParameters;
  719. for (var i = 0; i < parameters.Length; i++)
  720. {
  721. var argName = parameters[i];
  722. var v = i + 1 > arguments.Length ? Undefined.Instance : arguments[i];
  723. var argAlreadyDeclared = env.HasBinding(argName);
  724. if (!argAlreadyDeclared)
  725. {
  726. env.CreateMutableBinding(argName, v);
  727. }
  728. env.SetMutableBinding(argName, v, strict);
  729. }
  730. env.CreateMutableBinding("arguments", argsObj);
  731. }
  732. }
  733. if (functionDeclarations.Count > 0)
  734. {
  735. AddFunctionDeclarations(functionDeclarations, env, configurableBindings, strict);
  736. }
  737. if (variableDeclarations.Count == 0)
  738. {
  739. return canReleaseArgumentsInstance;
  740. }
  741. // process all variable declarations in the current parser scope
  742. if (!ReferenceEquals(der, null))
  743. {
  744. der.AddVariableDeclarations(variableDeclarations);
  745. }
  746. else
  747. {
  748. // slow path
  749. var variableDeclarationsCount = variableDeclarations.Count;
  750. for (var i = 0; i < variableDeclarationsCount; i++)
  751. {
  752. var variableDeclaration = variableDeclarations[i];
  753. var declarationsCount = variableDeclaration.Declarations.Count;
  754. for (var j = 0; j < declarationsCount; j++)
  755. {
  756. var d = variableDeclaration.Declarations[j];
  757. var dn = ((Identifier) d.Id).Name;
  758. var varAlreadyDeclared = env.HasBinding(dn);
  759. if (!varAlreadyDeclared)
  760. {
  761. env.CreateMutableBinding(dn, Undefined.Instance);
  762. }
  763. }
  764. }
  765. }
  766. return canReleaseArgumentsInstance;
  767. }
  768. private void AddFunctionDeclarations(List<FunctionDeclaration> functionDeclarations, EnvironmentRecord env, bool configurableBindings, bool strict)
  769. {
  770. var functionDeclarationsCount = functionDeclarations.Count;
  771. for (var i = 0; i < functionDeclarationsCount; i++)
  772. {
  773. var f = functionDeclarations[i];
  774. var fn = f.Id.Name;
  775. var fo = Function.CreateFunctionObject(f);
  776. var funcAlreadyDeclared = env.HasBinding(fn);
  777. if (!funcAlreadyDeclared)
  778. {
  779. env.CreateMutableBinding(fn, configurableBindings);
  780. }
  781. else
  782. {
  783. if (ReferenceEquals(env, GlobalEnvironment._record))
  784. {
  785. var go = Global;
  786. var existingProp = go.GetProperty(fn);
  787. if (existingProp.Configurable)
  788. {
  789. var flags = PropertyFlag.Writable | PropertyFlag.Enumerable;
  790. if (configurableBindings)
  791. {
  792. flags |= PropertyFlag.Configurable;
  793. }
  794. var descriptor = new PropertyDescriptor(Undefined.Instance, flags);
  795. go.DefineOwnProperty(fn, descriptor, true);
  796. }
  797. else
  798. {
  799. if (existingProp.IsAccessorDescriptor() || !existingProp.Enumerable)
  800. {
  801. ExceptionHelper.ThrowTypeError(this);
  802. }
  803. }
  804. }
  805. }
  806. env.SetMutableBinding(fn, fo, strict);
  807. }
  808. }
  809. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  810. internal void UpdateLexicalEnvironment(LexicalEnvironment newEnv)
  811. {
  812. _executionContexts.ReplaceTopLexicalEnvironment(newEnv);
  813. }
  814. private static void AssertNotNullOrEmpty(string propertyname, string propertyValue)
  815. {
  816. if (string.IsNullOrEmpty(propertyValue))
  817. {
  818. ExceptionHelper.ThrowArgumentException(propertyname);
  819. }
  820. }
  821. }
  822. }