Engine.cs 36 KB

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