Engine.cs 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315
  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.Argument;
  8. using Jint.Native.Array;
  9. using Jint.Native.Boolean;
  10. using Jint.Native.Date;
  11. using Jint.Native.Error;
  12. using Jint.Native.Function;
  13. using Jint.Native.Global;
  14. using Jint.Native.Iterator;
  15. using Jint.Native.Json;
  16. using Jint.Native.Map;
  17. using Jint.Native.Math;
  18. using Jint.Native.Number;
  19. using Jint.Native.Object;
  20. using Jint.Native.Proxy;
  21. using Jint.Native.Reflect;
  22. using Jint.Native.RegExp;
  23. using Jint.Native.Set;
  24. using Jint.Native.String;
  25. using Jint.Native.Symbol;
  26. using Jint.Pooling;
  27. using Jint.Runtime;
  28. using Jint.Runtime.CallStack;
  29. using Jint.Runtime.Debugger;
  30. using Jint.Runtime.Descriptors;
  31. using Jint.Runtime.Environments;
  32. using Jint.Runtime.Interop;
  33. using Jint.Runtime.Interop.Reflection;
  34. using Jint.Runtime.Interpreter;
  35. using Jint.Runtime.Interpreter.Expressions;
  36. using Jint.Runtime.References;
  37. namespace Jint
  38. {
  39. public class Engine
  40. {
  41. private static readonly ParserOptions DefaultParserOptions = new("<anonymous>")
  42. {
  43. AdaptRegexp = true,
  44. Tolerant = true
  45. };
  46. private static readonly JsString _errorFunctionName = new JsString("Error");
  47. private static readonly JsString _evalErrorFunctionName = new JsString("EvalError");
  48. private static readonly JsString _rangeErrorFunctionName = new JsString("RangeError");
  49. private static readonly JsString _referenceErrorFunctionName = new JsString("ReferenceError");
  50. private static readonly JsString _syntaxErrorFunctionName = new JsString("SyntaxError");
  51. private static readonly JsString _typeErrorFunctionName = new JsString("TypeError");
  52. private static readonly JsString _uriErrorFunctionName = new JsString("URIError");
  53. private readonly ExecutionContextStack _executionContexts;
  54. private JsValue _completionValue = JsValue.Undefined;
  55. internal Node _lastSyntaxNode;
  56. // lazy properties
  57. private ErrorConstructor _error;
  58. private ErrorConstructor _evalError;
  59. private ErrorConstructor _rangeError;
  60. private ErrorConstructor _referenceError;
  61. private ErrorConstructor _syntaxError;
  62. private ErrorConstructor _typeError;
  63. private ErrorConstructor _uriError;
  64. private DebugHandler _debugHandler;
  65. private List<BreakPoint> _breakPoints;
  66. // cached access
  67. private readonly List<IConstraint> _constraints;
  68. private readonly bool _isDebugMode;
  69. internal readonly bool _isStrict;
  70. internal readonly IReferenceResolver _referenceResolver;
  71. internal readonly ReferencePool _referencePool;
  72. internal readonly ArgumentsInstancePool _argumentsInstancePool;
  73. internal readonly JsValueArrayPool _jsValueArrayPool;
  74. public ITypeConverter ClrTypeConverter { get; internal set; }
  75. // cache of types used when resolving CLR type names
  76. internal readonly Dictionary<string, Type> TypeCache = new();
  77. internal static Dictionary<Type, Func<Engine, object, JsValue>> TypeMappers = new()
  78. {
  79. { typeof(bool), (engine, v) => (bool) v ? JsBoolean.True : JsBoolean.False },
  80. { typeof(byte), (engine, v) => JsNumber.Create((byte)v) },
  81. { typeof(char), (engine, v) => JsString.Create((char)v) },
  82. { typeof(DateTime), (engine, v) => engine.Date.Construct((DateTime)v) },
  83. { typeof(DateTimeOffset), (engine, v) => engine.Date.Construct((DateTimeOffset)v) },
  84. { typeof(decimal), (engine, v) => (JsValue) (double)(decimal)v },
  85. { typeof(double), (engine, v) => (JsValue)(double)v },
  86. { typeof(Int16), (engine, v) => JsNumber.Create((Int16)v) },
  87. { typeof(Int32), (engine, v) => JsNumber.Create((Int32)v) },
  88. { typeof(Int64), (engine, v) => (JsValue)(Int64)v },
  89. { typeof(SByte), (engine, v) => JsNumber.Create((SByte)v) },
  90. { typeof(Single), (engine, v) => (JsValue)(Single)v },
  91. { typeof(string), (engine, v) => JsString.Create((string) v) },
  92. { typeof(UInt16), (engine, v) => JsNumber.Create((UInt16)v) },
  93. { typeof(UInt32), (engine, v) => JsNumber.Create((UInt32)v) },
  94. { typeof(UInt64), (engine, v) => JsNumber.Create((UInt64)v) },
  95. { typeof(System.Text.RegularExpressions.Regex), (engine, v) => engine.RegExp.Construct((System.Text.RegularExpressions.Regex)v, "") }
  96. };
  97. // shared frozen version
  98. internal readonly PropertyDescriptor _callerCalleeArgumentsThrowerConfigurable;
  99. internal readonly PropertyDescriptor _callerCalleeArgumentsThrowerNonConfigurable;
  100. internal static Dictionary<ClrPropertyDescriptorFactoriesKey, ReflectionAccessor> ReflectionAccessors = new();
  101. internal readonly JintCallStack CallStack;
  102. /// <summary>
  103. /// Constructs a new engine instance.
  104. /// </summary>
  105. public Engine() : this((Action<Options>) null)
  106. {
  107. }
  108. /// <summary>
  109. /// Constructs a new engine instance and allows customizing options.
  110. /// </summary>
  111. public Engine(Action<Options> options)
  112. : this((engine, opts) => options?.Invoke(opts))
  113. {
  114. }
  115. /// <summary>
  116. /// Constructs a new engine with a custom <see cref="Options"/> instance.
  117. /// </summary>
  118. public Engine(Options options) : this((e, o) => e.Options = options)
  119. {
  120. }
  121. /// <summary>
  122. /// Constructs a new engine instance and allows customizing options.
  123. /// </summary>
  124. /// <remarks>The provided engine instance in callback is not guaranteed to be fully configured</remarks>
  125. public Engine(Action<Engine, Options> options)
  126. {
  127. _executionContexts = new ExecutionContextStack(2);
  128. Global = GlobalObject.CreateGlobalObject(this);
  129. Object = ObjectConstructor.CreateObjectConstructor(this);
  130. Function = FunctionConstructor.CreateFunctionConstructor(this);
  131. _callerCalleeArgumentsThrowerConfigurable = new GetSetPropertyDescriptor.ThrowerPropertyDescriptor(this, PropertyFlag.Configurable | PropertyFlag.CustomJsValue, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them");
  132. _callerCalleeArgumentsThrowerNonConfigurable = new GetSetPropertyDescriptor.ThrowerPropertyDescriptor(this, PropertyFlag.CustomJsValue, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them");
  133. Symbol = SymbolConstructor.CreateSymbolConstructor(this);
  134. Array = ArrayConstructor.CreateArrayConstructor(this);
  135. Map = MapConstructor.CreateMapConstructor(this);
  136. Set = SetConstructor.CreateSetConstructor(this);
  137. Iterator = IteratorConstructor.CreateIteratorConstructor(this);
  138. String = StringConstructor.CreateStringConstructor(this);
  139. RegExp = RegExpConstructor.CreateRegExpConstructor(this);
  140. Number = NumberConstructor.CreateNumberConstructor(this);
  141. Boolean = BooleanConstructor.CreateBooleanConstructor(this);
  142. Date = DateConstructor.CreateDateConstructor(this);
  143. Math = MathInstance.CreateMathObject(this);
  144. Json = JsonInstance.CreateJsonObject(this);
  145. Proxy = ProxyConstructor.CreateProxyConstructor(this);
  146. Reflect = ReflectInstance.CreateReflectObject(this);
  147. GlobalSymbolRegistry = new GlobalSymbolRegistry();
  148. // Because the properties might need some of the built-in object
  149. // their configuration is delayed to a later step
  150. // trigger initialization
  151. Global.EnsureInitialized();
  152. // this is implementation dependent, and only to pass some unit tests
  153. Global._prototype = Object.PrototypeObject;
  154. Object._prototype = Function.PrototypeObject;
  155. // create the global environment http://www.ecma-international.org/ecma-262/5.1/#sec-10.2.3
  156. GlobalEnvironment = LexicalEnvironment.NewGlobalEnvironment(this, Global);
  157. // create the global execution context http://www.ecma-international.org/ecma-262/5.1/#sec-10.4.1.1
  158. EnterExecutionContext(GlobalEnvironment, GlobalEnvironment);
  159. Eval = new EvalFunctionInstance(this);
  160. Global.SetProperty(CommonProperties.Eval, new PropertyDescriptor(Eval, PropertyFlag.Configurable | PropertyFlag.Writable));
  161. Options = new Options();
  162. options?.Invoke(this, Options);
  163. // gather some options as fields for faster checks
  164. _isDebugMode = Options.IsDebugMode;
  165. _isStrict = Options.IsStrict;
  166. _constraints = Options._Constraints;
  167. _referenceResolver = Options.ReferenceResolver;
  168. CallStack = new JintCallStack(Options.MaxRecursionDepth >= 0);
  169. _referencePool = new ReferencePool();
  170. _argumentsInstancePool = new ArgumentsInstancePool(this);
  171. _jsValueArrayPool = new JsValueArrayPool();
  172. Options.Apply(this);
  173. }
  174. internal LexicalEnvironment GlobalEnvironment { get; }
  175. public GlobalObject Global { get; }
  176. public ObjectConstructor Object { get; }
  177. public FunctionConstructor Function { get; }
  178. public ArrayConstructor Array { get; }
  179. public MapConstructor Map { get; }
  180. public SetConstructor Set { get; }
  181. public IteratorConstructor Iterator { get; }
  182. public StringConstructor String { get; }
  183. public RegExpConstructor RegExp { get; }
  184. public BooleanConstructor Boolean { get; }
  185. public NumberConstructor Number { get; }
  186. public DateConstructor Date { get; }
  187. public MathInstance Math { get; }
  188. public JsonInstance Json { get; }
  189. public ProxyConstructor Proxy { get; }
  190. public ReflectInstance Reflect { get; }
  191. public SymbolConstructor Symbol { get; }
  192. public EvalFunctionInstance Eval { get; }
  193. public ErrorConstructor Error => _error ??= ErrorConstructor.CreateErrorConstructor(this, _errorFunctionName);
  194. public ErrorConstructor EvalError => _evalError ??= ErrorConstructor.CreateErrorConstructor(this, _evalErrorFunctionName);
  195. public ErrorConstructor SyntaxError => _syntaxError ??= ErrorConstructor.CreateErrorConstructor(this, _syntaxErrorFunctionName);
  196. public ErrorConstructor TypeError => _typeError ??= ErrorConstructor.CreateErrorConstructor(this, _typeErrorFunctionName);
  197. public ErrorConstructor RangeError => _rangeError ??= ErrorConstructor.CreateErrorConstructor(this, _rangeErrorFunctionName);
  198. public ErrorConstructor ReferenceError => _referenceError ??= ErrorConstructor.CreateErrorConstructor(this, _referenceErrorFunctionName);
  199. public ErrorConstructor UriError => _uriError ??= ErrorConstructor.CreateErrorConstructor(this, _uriErrorFunctionName);
  200. public ref readonly ExecutionContext ExecutionContext
  201. {
  202. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  203. get => ref _executionContexts.Peek();
  204. }
  205. public GlobalSymbolRegistry GlobalSymbolRegistry { get; }
  206. internal long CurrentMemoryUsage { get; private set; }
  207. internal Options Options { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; private set; }
  208. #region Debugger
  209. public delegate StepMode DebugStepDelegate(object sender, DebugInformation e);
  210. public delegate StepMode BreakDelegate(object sender, DebugInformation e);
  211. public event DebugStepDelegate Step;
  212. public event BreakDelegate Break;
  213. internal DebugHandler DebugHandler => _debugHandler ??= new DebugHandler(this);
  214. public List<BreakPoint> BreakPoints => _breakPoints ??= new List<BreakPoint>();
  215. internal StepMode? InvokeStepEvent(DebugInformation info)
  216. {
  217. return Step?.Invoke(this, info);
  218. }
  219. internal StepMode? InvokeBreakEvent(DebugInformation info)
  220. {
  221. return Break?.Invoke(this, info);
  222. }
  223. #endregion
  224. public ExecutionContext EnterExecutionContext(
  225. LexicalEnvironment lexicalEnvironment,
  226. LexicalEnvironment variableEnvironment)
  227. {
  228. var context = new ExecutionContext(
  229. lexicalEnvironment,
  230. variableEnvironment);
  231. _executionContexts.Push(context);
  232. return context;
  233. }
  234. public Engine SetValue(JsValue name, Delegate value)
  235. {
  236. Global.FastAddProperty(name, new DelegateWrapper(this, value), true, false, true);
  237. return this;
  238. }
  239. public Engine SetValue(JsValue name, string value)
  240. {
  241. return SetValue(name, new JsString(value));
  242. }
  243. public Engine SetValue(JsValue name, double value)
  244. {
  245. return SetValue(name, JsNumber.Create(value));
  246. }
  247. public Engine SetValue(JsValue name, int value)
  248. {
  249. return SetValue(name, JsNumber.Create(value));
  250. }
  251. public Engine SetValue(JsValue name, bool value)
  252. {
  253. return SetValue(name, value ? JsBoolean.True : JsBoolean.False);
  254. }
  255. public Engine SetValue(JsValue name, JsValue value)
  256. {
  257. Global.Set(name, value, Global);
  258. return this;
  259. }
  260. public Engine SetValue(JsValue name, object obj)
  261. {
  262. return SetValue(name, JsValue.FromObject(this, obj));
  263. }
  264. public void LeaveExecutionContext()
  265. {
  266. _executionContexts.Pop();
  267. }
  268. /// <summary>
  269. /// Initializes the statements count
  270. /// </summary>
  271. public void ResetConstraints()
  272. {
  273. for (var i = 0; i < _constraints.Count; i++)
  274. {
  275. _constraints[i].Reset();
  276. }
  277. }
  278. /// <summary>
  279. /// Initializes list of references of called functions
  280. /// </summary>
  281. public void ResetCallStack()
  282. {
  283. CallStack.Clear();
  284. }
  285. public Engine Execute(string source)
  286. {
  287. return Execute(source, DefaultParserOptions);
  288. }
  289. public Engine Execute(string source, ParserOptions parserOptions)
  290. {
  291. var parser = new JavaScriptParser(source, parserOptions);
  292. return Execute(parser.ParseScript());
  293. }
  294. public Engine Execute(Script script)
  295. {
  296. ResetConstraints();
  297. ResetLastStatement();
  298. using (new StrictModeScope(_isStrict || script.Strict))
  299. {
  300. GlobalDeclarationInstantiation(
  301. script,
  302. GlobalEnvironment);
  303. var list = new JintStatementList(this, null, script.Body);
  304. Completion result;
  305. try
  306. {
  307. result = list.Execute();
  308. }
  309. catch
  310. {
  311. // unhandled exception
  312. ResetCallStack();
  313. throw;
  314. }
  315. if (result.Type == CompletionType.Throw)
  316. {
  317. var ex = new JavaScriptException(result.GetValueOrDefault()).SetCallstack(this, result.Location);
  318. ResetCallStack();
  319. throw ex;
  320. }
  321. _completionValue = result.GetValueOrDefault();
  322. }
  323. return this;
  324. }
  325. private void ResetLastStatement()
  326. {
  327. _lastSyntaxNode = null;
  328. }
  329. /// <summary>
  330. /// Gets the last evaluated statement completion value
  331. /// </summary>
  332. public JsValue GetCompletionValue()
  333. {
  334. return _completionValue;
  335. }
  336. internal void RunBeforeExecuteStatementChecks(Statement statement)
  337. {
  338. // Avoid allocating the enumerator because we run this loop very often.
  339. for (var i = 0; i < _constraints.Count; i++)
  340. {
  341. _constraints[i].Check();
  342. }
  343. if (_isDebugMode)
  344. {
  345. DebugHandler.OnStep(statement);
  346. }
  347. }
  348. /// <summary>
  349. /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.7.1
  350. /// </summary>
  351. public JsValue GetValue(object value)
  352. {
  353. return GetValue(value, false);
  354. }
  355. internal JsValue GetValue(object value, bool returnReferenceToPool)
  356. {
  357. if (value is JsValue jsValue)
  358. {
  359. return jsValue;
  360. }
  361. if (!(value is Reference reference))
  362. {
  363. return ((Completion) value).Value;
  364. }
  365. return GetValue(reference, returnReferenceToPool);
  366. }
  367. internal JsValue GetValue(Reference reference, bool returnReferenceToPool)
  368. {
  369. var baseValue = reference.GetBase();
  370. if (baseValue._type == InternalTypes.Undefined)
  371. {
  372. if (_referenceResolver.TryUnresolvableReference(this, reference, out JsValue val))
  373. {
  374. return val;
  375. }
  376. ExceptionHelper.ThrowReferenceError(this, reference);
  377. }
  378. if ((baseValue._type & InternalTypes.ObjectEnvironmentRecord) == 0
  379. && _referenceResolver.TryPropertyReference(this, reference, ref baseValue))
  380. {
  381. return baseValue;
  382. }
  383. if (reference.IsPropertyReference())
  384. {
  385. var property = reference.GetReferencedName();
  386. if (returnReferenceToPool)
  387. {
  388. _referencePool.Return(reference);
  389. }
  390. if (baseValue.IsObject())
  391. {
  392. var o = TypeConverter.ToObject(this, baseValue);
  393. var v = o.Get(property, reference.GetThisValue());
  394. return v;
  395. }
  396. else
  397. {
  398. // check if we are accessing a string, boxing operation can be costly to do index access
  399. // we have good chance to have fast path with integer or string indexer
  400. ObjectInstance o = null;
  401. if ((property._type & (InternalTypes.String | InternalTypes.Integer)) != 0
  402. && baseValue is JsString s
  403. && TryHandleStringValue(property, s, ref o, out var jsValue))
  404. {
  405. return jsValue;
  406. }
  407. if (o is null)
  408. {
  409. o = TypeConverter.ToObject(this, baseValue);
  410. }
  411. var desc = o.GetProperty(property);
  412. if (desc == PropertyDescriptor.Undefined)
  413. {
  414. return JsValue.Undefined;
  415. }
  416. if (desc.IsDataDescriptor())
  417. {
  418. return desc.Value;
  419. }
  420. var getter = desc.Get;
  421. if (getter.IsUndefined())
  422. {
  423. return Undefined.Instance;
  424. }
  425. var callable = (ICallable) getter.AsObject();
  426. return callable.Call(baseValue, Arguments.Empty);
  427. }
  428. }
  429. if (!(baseValue is EnvironmentRecord record))
  430. {
  431. return ExceptionHelper.ThrowArgumentException<JsValue>();
  432. }
  433. var bindingValue = record.GetBindingValue(reference.GetReferencedName().ToString(), reference.IsStrictReference());
  434. if (returnReferenceToPool)
  435. {
  436. _referencePool.Return(reference);
  437. }
  438. return bindingValue;
  439. }
  440. private bool TryHandleStringValue(JsValue property, JsString s, ref ObjectInstance o, out JsValue jsValue)
  441. {
  442. if (property == CommonProperties.Length)
  443. {
  444. jsValue = JsNumber.Create((uint) s.Length);
  445. return true;
  446. }
  447. if (property is JsNumber number && number.IsInteger())
  448. {
  449. var index = number.AsInteger();
  450. var str = s._value;
  451. if (index < 0 || index >= str.Length)
  452. {
  453. jsValue = JsValue.Undefined;
  454. return true;
  455. }
  456. jsValue = JsString.Create(str[index]);
  457. return true;
  458. }
  459. if (property is JsString propertyString
  460. && propertyString._value.Length > 0
  461. && char.IsLower(propertyString._value[0]))
  462. {
  463. // trying to find property that's always in prototype
  464. o = String.PrototypeObject;
  465. }
  466. jsValue = JsValue.Undefined;
  467. return false;
  468. }
  469. /// <summary>
  470. /// https://tc39.es/ecma262/#sec-putvalue
  471. /// </summary>
  472. internal void PutValue(Reference reference, JsValue value)
  473. {
  474. var baseValue = reference.GetBase();
  475. if (reference.IsUnresolvableReference())
  476. {
  477. if (reference.IsStrictReference())
  478. {
  479. ExceptionHelper.ThrowReferenceError(this, reference);
  480. }
  481. Global.Set(reference.GetReferencedName(), value, throwOnError: false);
  482. }
  483. else if (reference.IsPropertyReference())
  484. {
  485. if (reference.HasPrimitiveBase())
  486. {
  487. baseValue = TypeConverter.ToObject(this, baseValue);
  488. }
  489. var succeeded = baseValue.Set(reference.GetReferencedName(), value, reference.GetThisValue());
  490. if (!succeeded && reference.IsStrictReference())
  491. {
  492. ExceptionHelper.ThrowTypeError(this);
  493. }
  494. }
  495. else
  496. {
  497. ((EnvironmentRecord) baseValue).SetMutableBinding(TypeConverter.ToString(reference.GetReferencedName()), value, reference.IsStrictReference());
  498. }
  499. }
  500. /// <summary>
  501. /// http://www.ecma-international.org/ecma-262/6.0/#sec-initializereferencedbinding
  502. /// </summary>
  503. public void InitializeReferenceBinding(Reference reference, JsValue value)
  504. {
  505. var baseValue = (EnvironmentRecord) reference.GetBase();
  506. baseValue.InitializeBinding(TypeConverter.ToString(reference.GetReferencedName()), value);
  507. }
  508. /// <summary>
  509. /// Invoke the current value as function.
  510. /// </summary>
  511. /// <param name="propertyName">The name of the function to call.</param>
  512. /// <param name="arguments">The arguments of the function call.</param>
  513. /// <returns>The value returned by the function call.</returns>
  514. public JsValue Invoke(string propertyName, params object[] arguments)
  515. {
  516. return Invoke(propertyName, null, arguments);
  517. }
  518. /// <summary>
  519. /// Invoke the current value as function.
  520. /// </summary>
  521. /// <param name="propertyName">The name of the function to call.</param>
  522. /// <param name="thisObj">The this value inside the function call.</param>
  523. /// <param name="arguments">The arguments of the function call.</param>
  524. /// <returns>The value returned by the function call.</returns>
  525. public JsValue Invoke(string propertyName, object thisObj, object[] arguments)
  526. {
  527. var value = GetValue(propertyName);
  528. return Invoke(value, thisObj, arguments);
  529. }
  530. /// <summary>
  531. /// Invoke the current value as function.
  532. /// </summary>
  533. /// <param name="value">The function to call.</param>
  534. /// <param name="arguments">The arguments of the function call.</param>
  535. /// <returns>The value returned by the function call.</returns>
  536. public JsValue Invoke(JsValue value, params object[] arguments)
  537. {
  538. return Invoke(value, null, arguments);
  539. }
  540. /// <summary>
  541. /// Invoke the current value as function.
  542. /// </summary>
  543. /// <param name="value">The function to call.</param>
  544. /// <param name="thisObj">The this value inside the function call.</param>
  545. /// <param name="arguments">The arguments of the function call.</param>
  546. /// <returns>The value returned by the function call.</returns>
  547. public JsValue Invoke(JsValue value, object thisObj, object[] arguments)
  548. {
  549. var callable = value as ICallable ?? ExceptionHelper.ThrowTypeError<ICallable>(this, "Can only invoke functions");
  550. var items = _jsValueArrayPool.RentArray(arguments.Length);
  551. for (int i = 0; i < arguments.Length; ++i)
  552. {
  553. items[i] = JsValue.FromObject(this, arguments[i]);
  554. }
  555. var result = callable.Call(JsValue.FromObject(this, thisObj), items);
  556. _jsValueArrayPool.ReturnArray(items);
  557. return result;
  558. }
  559. /// <summary>
  560. /// Gets a named value from the Global scope.
  561. /// </summary>
  562. /// <param name="propertyName">The name of the property to return.</param>
  563. public JsValue GetValue(string propertyName)
  564. {
  565. return GetValue(Global, new JsString(propertyName));
  566. }
  567. /// <summary>
  568. /// Gets the last evaluated <see cref="Node"/>.
  569. /// </summary>
  570. internal Node GetLastSyntaxNode()
  571. {
  572. return _lastSyntaxNode;
  573. }
  574. /// <summary>
  575. /// Gets a named value from the specified scope.
  576. /// </summary>
  577. /// <param name="scope">The scope to get the property from.</param>
  578. /// <param name="property">The name of the property to return.</param>
  579. public JsValue GetValue(JsValue scope, JsValue property)
  580. {
  581. var reference = _referencePool.Rent(scope, property, _isStrict, thisValue: null);
  582. var jsValue = GetValue(reference, false);
  583. _referencePool.Return(reference);
  584. return jsValue;
  585. }
  586. /// <summary>
  587. /// https://tc39.es/ecma262/#sec-resolvebinding
  588. /// </summary>
  589. internal Reference ResolveBinding(string name, LexicalEnvironment env = null)
  590. {
  591. env ??= ExecutionContext.LexicalEnvironment;
  592. return GetIdentifierReference(env, name, StrictModeScope.IsStrictModeCode);
  593. }
  594. private Reference GetIdentifierReference(LexicalEnvironment env, string name, bool strict)
  595. {
  596. if (env is null)
  597. {
  598. return new Reference(JsValue.Undefined, name, strict);
  599. }
  600. var envRec = env._record;
  601. if (envRec.HasBinding(name))
  602. {
  603. return new Reference(envRec, name, strict);
  604. }
  605. return GetIdentifierReference(env._outer, name, strict);
  606. }
  607. /// <summary>
  608. /// https://tc39.es/ecma262/#sec-getnewtarget
  609. /// </summary>
  610. internal JsValue GetNewTarget(EnvironmentRecord thisEnvironment = null)
  611. {
  612. // we can take as argument if caller site has already determined the value, otherwise resolve
  613. thisEnvironment ??= GetThisEnvironment();
  614. return thisEnvironment.NewTarget;
  615. }
  616. /// <summary>
  617. /// https://tc39.es/ecma262/#sec-getthisenvironment
  618. /// </summary>
  619. internal EnvironmentRecord GetThisEnvironment()
  620. {
  621. // The loop will always terminate because the list of environments always
  622. // ends with the global environment which has a this binding.
  623. var lex = ExecutionContext.LexicalEnvironment;
  624. while (true)
  625. {
  626. var envRec = lex._record;
  627. var exists = envRec.HasThisBinding();
  628. if (exists)
  629. {
  630. return envRec;
  631. }
  632. var outer = lex._outer;
  633. lex = outer;
  634. }
  635. }
  636. /// <summary>
  637. /// https://tc39.es/ecma262/#sec-resolvethisbinding
  638. /// </summary>
  639. internal JsValue ResolveThisBinding()
  640. {
  641. var envRec = GetThisEnvironment();
  642. return envRec.GetThisBinding();
  643. }
  644. /// <summary>
  645. /// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
  646. /// </summary>
  647. private void GlobalDeclarationInstantiation(
  648. Script script,
  649. LexicalEnvironment env)
  650. {
  651. var envRec = (GlobalEnvironmentRecord) env._record;
  652. var hoistingScope = HoistingScope.GetProgramLevelDeclarations(script);
  653. var functionDeclarations = hoistingScope._functionDeclarations;
  654. var varDeclarations = hoistingScope._variablesDeclarations;
  655. var lexDeclarations = hoistingScope._lexicalDeclarations;
  656. var functionToInitialize = new LinkedList<FunctionDeclaration>();
  657. var declaredFunctionNames = new HashSet<string>();
  658. var declaredVarNames = new List<string>();
  659. if (functionDeclarations != null)
  660. {
  661. for (var i = functionDeclarations.Count - 1; i >= 0; i--)
  662. {
  663. var d = functionDeclarations[i];
  664. var fn = d.Id.Name;
  665. if (!declaredFunctionNames.Contains(fn))
  666. {
  667. var fnDefinable = envRec.CanDeclareGlobalFunction(fn);
  668. if (!fnDefinable)
  669. {
  670. ExceptionHelper.ThrowTypeError(this);
  671. }
  672. declaredFunctionNames.Add(fn);
  673. functionToInitialize.AddFirst(d);
  674. }
  675. }
  676. }
  677. var boundNames = new List<string>();
  678. if (varDeclarations != null)
  679. {
  680. for (var i = 0; i < varDeclarations.Count; i++)
  681. {
  682. var d = varDeclarations[i];
  683. boundNames.Clear();
  684. d.GetBoundNames(boundNames);
  685. for (var j = 0; j < boundNames.Count; j++)
  686. {
  687. var vn = boundNames[j];
  688. if (envRec.HasLexicalDeclaration(vn))
  689. {
  690. ExceptionHelper.ThrowSyntaxError(this, $"Identifier '{vn}' has already been declared");
  691. }
  692. if (!declaredFunctionNames.Contains(vn))
  693. {
  694. var vnDefinable = envRec.CanDeclareGlobalVar(vn);
  695. if (!vnDefinable)
  696. {
  697. ExceptionHelper.ThrowTypeError(this);
  698. }
  699. declaredVarNames.Add(vn);
  700. }
  701. }
  702. }
  703. }
  704. if (lexDeclarations != null)
  705. {
  706. for (var i = 0; i < lexDeclarations.Count; i++)
  707. {
  708. var d = lexDeclarations[i];
  709. boundNames.Clear();
  710. d.GetBoundNames(boundNames);
  711. for (var j = 0; j < boundNames.Count; j++)
  712. {
  713. var dn = boundNames[j];
  714. if (envRec.HasVarDeclaration(dn)
  715. || envRec.HasLexicalDeclaration(dn)
  716. || envRec.HasRestrictedGlobalProperty(dn))
  717. {
  718. ExceptionHelper.ThrowSyntaxError(this, $"Identifier '{dn}' has already been declared");
  719. }
  720. if (d.Kind == VariableDeclarationKind.Const)
  721. {
  722. envRec.CreateImmutableBinding(dn, strict: true);
  723. }
  724. else
  725. {
  726. envRec.CreateMutableBinding(dn, canBeDeleted: false);
  727. }
  728. }
  729. }
  730. }
  731. foreach (var f in functionToInitialize)
  732. {
  733. var fn = f.Id!.Name;
  734. if (envRec.HasLexicalDeclaration(fn))
  735. {
  736. ExceptionHelper.ThrowSyntaxError(this, $"Identifier '{fn}' has already been declared");
  737. }
  738. var fo = Function.CreateFunctionObject(f, env);
  739. envRec.CreateGlobalFunctionBinding(fn, fo, canBeDeleted: false);
  740. }
  741. for (var i = 0; i < declaredVarNames.Count; i++)
  742. {
  743. var vn = declaredVarNames[i];
  744. envRec.CreateGlobalVarBinding(vn, canBeDeleted: false);
  745. }
  746. }
  747. /// <summary>
  748. /// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
  749. /// </summary>
  750. internal ArgumentsInstance FunctionDeclarationInstantiation(
  751. FunctionInstance functionInstance,
  752. JsValue[] argumentsList,
  753. LexicalEnvironment env)
  754. {
  755. var func = functionInstance._functionDefinition;
  756. var envRec = (FunctionEnvironmentRecord) env._record;
  757. var strict = StrictModeScope.IsStrictModeCode;
  758. var configuration = func.Initialize(this, functionInstance);
  759. var parameterNames = configuration.ParameterNames;
  760. var hasDuplicates = configuration.HasDuplicates;
  761. var simpleParameterList = configuration.IsSimpleParameterList;
  762. var hasParameterExpressions = configuration.HasParameterExpressions;
  763. var canInitializeParametersOnDeclaration = simpleParameterList && !configuration.HasDuplicates;
  764. envRec.InitializeParameters(parameterNames, hasDuplicates, canInitializeParametersOnDeclaration ? argumentsList : null);
  765. ArgumentsInstance ao = null;
  766. if (configuration.ArgumentsObjectNeeded)
  767. {
  768. if (strict || !simpleParameterList)
  769. {
  770. ao = CreateUnmappedArgumentsObject(argumentsList);
  771. }
  772. else
  773. {
  774. // NOTE: mapped argument object is only provided for non-strict functions that don't have a rest parameter,
  775. // any parameter default value initializers, or any destructured parameters.
  776. ao = CreateMappedArgumentsObject(functionInstance, parameterNames, argumentsList, envRec, configuration.HasRestParameter);
  777. }
  778. if (strict)
  779. {
  780. envRec.CreateImmutableBindingAndInitialize(KnownKeys.Arguments, strict: false, ao);
  781. }
  782. else
  783. {
  784. envRec.CreateMutableBindingAndInitialize(KnownKeys.Arguments, canBeDeleted: false, ao);
  785. }
  786. }
  787. if (!canInitializeParametersOnDeclaration)
  788. {
  789. // slower set
  790. envRec.AddFunctionParameters(func.Function, argumentsList);
  791. }
  792. // Let iteratorRecord be CreateListIteratorRecord(argumentsList).
  793. // If hasDuplicates is true, then
  794. // Perform ? IteratorBindingInitialization for formals with iteratorRecord and undefined as arguments.
  795. // Else,
  796. // Perform ? IteratorBindingInitialization for formals with iteratorRecord and env as arguments.
  797. LexicalEnvironment varEnv;
  798. DeclarativeEnvironmentRecord varEnvRec;
  799. if (!hasParameterExpressions)
  800. {
  801. // NOTE: Only a single lexical environment is needed for the parameters and top-level vars.
  802. for (var i = 0; i < configuration.VarsToInitialize.Count; i++)
  803. {
  804. var pair = configuration.VarsToInitialize[i];
  805. envRec.CreateMutableBindingAndInitialize(pair.Name, canBeDeleted: false, JsValue.Undefined);
  806. }
  807. varEnv = env;
  808. varEnvRec = envRec;
  809. }
  810. else
  811. {
  812. // NOTE: A separate Environment Record is needed to ensure that closures created by expressions
  813. // in the formal parameter list do not have visibility of declarations in the function body.
  814. varEnv = LexicalEnvironment.NewDeclarativeEnvironment(this, env);
  815. varEnvRec = (DeclarativeEnvironmentRecord) varEnv._record;
  816. UpdateVariableEnvironment(varEnv);
  817. for (var i = 0; i < configuration.VarsToInitialize.Count; i++)
  818. {
  819. var pair = configuration.VarsToInitialize[i];
  820. var initialValue = pair.InitialValue ?? envRec.GetBindingValue(pair.Name, strict: false);
  821. varEnvRec.CreateMutableBindingAndInitialize(pair.Name, canBeDeleted: false, initialValue);
  822. }
  823. }
  824. // NOTE: Annex B.3.3.1 adds additional steps at this point.
  825. // A https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
  826. LexicalEnvironment lexEnv;
  827. if (!strict)
  828. {
  829. lexEnv = LexicalEnvironment.NewDeclarativeEnvironment(this, varEnv);
  830. // NOTE: Non-strict functions use a separate lexical Environment Record for top-level lexical declarations
  831. // so that a direct eval can determine whether any var scoped declarations introduced by the eval code conflict
  832. // with pre-existing top-level lexically scoped declarations. This is not needed for strict functions
  833. // because a strict direct eval always places all declarations into a new Environment Record.
  834. }
  835. else
  836. {
  837. lexEnv = varEnv;
  838. }
  839. var lexEnvRec = lexEnv._record;
  840. UpdateLexicalEnvironment(lexEnv);
  841. if (configuration.LexicalDeclarations.Length > 0)
  842. {
  843. InitializeLexicalDeclarations(configuration.LexicalDeclarations, lexEnvRec);
  844. }
  845. if (configuration.FunctionsToInitialize != null)
  846. {
  847. InitializeFunctions(configuration.FunctionsToInitialize, lexEnv, varEnvRec);
  848. }
  849. return ao;
  850. }
  851. private void InitializeFunctions(
  852. LinkedList<FunctionDeclaration> functionsToInitialize,
  853. LexicalEnvironment lexEnv,
  854. DeclarativeEnvironmentRecord varEnvRec)
  855. {
  856. foreach (var f in functionsToInitialize)
  857. {
  858. var fn = f.Id.Name;
  859. var fo = Function.CreateFunctionObject(f, lexEnv);
  860. varEnvRec.SetMutableBinding(fn, fo, strict: false);
  861. }
  862. }
  863. private static void InitializeLexicalDeclarations(
  864. JintFunctionDefinition.State.LexicalVariableDeclaration[] lexicalDeclarations,
  865. EnvironmentRecord lexEnvRec)
  866. {
  867. foreach (var d in lexicalDeclarations)
  868. {
  869. for (var j = 0; j < d.BoundNames.Count; j++)
  870. {
  871. var dn = d.BoundNames[j];
  872. if (d.Kind == VariableDeclarationKind.Const)
  873. {
  874. lexEnvRec.CreateImmutableBinding(dn, strict: true);
  875. }
  876. else
  877. {
  878. lexEnvRec.CreateMutableBinding(dn, canBeDeleted: false);
  879. }
  880. }
  881. }
  882. }
  883. private ArgumentsInstance CreateMappedArgumentsObject(
  884. FunctionInstance func,
  885. Key[] formals,
  886. JsValue[] argumentsList,
  887. DeclarativeEnvironmentRecord envRec,
  888. bool hasRestParameter)
  889. {
  890. return _argumentsInstancePool.Rent(func, formals, argumentsList, envRec, hasRestParameter);
  891. }
  892. private ArgumentsInstance CreateUnmappedArgumentsObject(JsValue[] argumentsList)
  893. {
  894. return _argumentsInstancePool.Rent(argumentsList);
  895. }
  896. /// <summary>
  897. /// https://tc39.es/ecma262/#sec-evaldeclarationinstantiation
  898. /// </summary>
  899. internal void EvalDeclarationInstantiation(
  900. Script script,
  901. LexicalEnvironment varEnv,
  902. LexicalEnvironment lexEnv,
  903. bool strict)
  904. {
  905. var hoistingScope = HoistingScope.GetProgramLevelDeclarations(script);
  906. var lexEnvRec = (DeclarativeEnvironmentRecord) lexEnv._record;
  907. var varEnvRec = varEnv._record;
  908. if (!strict && hoistingScope._variablesDeclarations != null)
  909. {
  910. if (varEnvRec is GlobalEnvironmentRecord globalEnvironmentRecord)
  911. {
  912. ref readonly var nodes = ref hoistingScope._variablesDeclarations;
  913. for (var i = 0; i < nodes.Count; i++)
  914. {
  915. var variablesDeclaration = nodes[i];
  916. var identifier = (Identifier) variablesDeclaration.Declarations[0].Id;
  917. if (globalEnvironmentRecord.HasLexicalDeclaration(identifier.Name))
  918. {
  919. ExceptionHelper.ThrowSyntaxError(this, "Identifier '" + identifier.Name + "' has already been declared");
  920. }
  921. }
  922. }
  923. var thisLex = lexEnv;
  924. while (thisLex != varEnv)
  925. {
  926. var thisEnvRec = thisLex._record;
  927. if (!(thisEnvRec is ObjectEnvironmentRecord))
  928. {
  929. ref readonly var nodes = ref hoistingScope._variablesDeclarations;
  930. for (var i = 0; i < nodes.Count; i++)
  931. {
  932. var variablesDeclaration = nodes[i];
  933. var identifier = (Identifier) variablesDeclaration.Declarations[0].Id;
  934. if (thisEnvRec.HasBinding(identifier.Name))
  935. {
  936. ExceptionHelper.ThrowSyntaxError(this);
  937. }
  938. }
  939. }
  940. thisLex = thisLex._outer;
  941. }
  942. }
  943. var functionDeclarations = hoistingScope._functionDeclarations;
  944. var functionsToInitialize = new LinkedList<FunctionDeclaration>();
  945. var declaredFunctionNames = new HashSet<string>();
  946. if (functionDeclarations != null)
  947. {
  948. for (var i = functionDeclarations.Count - 1; i >= 0; i--)
  949. {
  950. var d = functionDeclarations[i];
  951. var fn = d.Id.Name;
  952. if (!declaredFunctionNames.Contains(fn))
  953. {
  954. if (varEnvRec is GlobalEnvironmentRecord ger)
  955. {
  956. var fnDefinable = ger.CanDeclareGlobalFunction(fn);
  957. if (!fnDefinable)
  958. {
  959. ExceptionHelper.ThrowTypeError(this);
  960. }
  961. }
  962. declaredFunctionNames.Add(fn);
  963. functionsToInitialize.AddFirst(d);
  964. }
  965. }
  966. }
  967. var boundNames = new List<string>();
  968. var declaredVarNames = new List<string>();
  969. var variableDeclarations = hoistingScope._variablesDeclarations;
  970. var variableDeclarationsCount = variableDeclarations?.Count;
  971. for (var i = 0; i < variableDeclarationsCount; i++)
  972. {
  973. var variableDeclaration = variableDeclarations[i];
  974. boundNames.Clear();
  975. variableDeclaration.GetBoundNames(boundNames);
  976. for (var j = 0; j < boundNames.Count; j++)
  977. {
  978. var vn = boundNames[j];
  979. if (!declaredFunctionNames.Contains(vn))
  980. {
  981. if (varEnvRec is GlobalEnvironmentRecord ger)
  982. {
  983. var vnDefinable = ger.CanDeclareGlobalFunction(vn);
  984. if (!vnDefinable)
  985. {
  986. ExceptionHelper.ThrowTypeError(this);
  987. }
  988. }
  989. declaredVarNames.Add(vn);
  990. }
  991. }
  992. }
  993. var lexicalDeclarations = hoistingScope._lexicalDeclarations;
  994. var lexicalDeclarationsCount = lexicalDeclarations?.Count;
  995. for (var i = 0; i < lexicalDeclarationsCount; i++)
  996. {
  997. boundNames.Clear();
  998. var d = lexicalDeclarations[i];
  999. d.GetBoundNames(boundNames);
  1000. for (var j = 0; j < boundNames.Count; j++)
  1001. {
  1002. var dn = boundNames[j];
  1003. if (d.Kind == VariableDeclarationKind.Const)
  1004. {
  1005. lexEnvRec.CreateImmutableBinding(dn, strict: true);
  1006. }
  1007. else
  1008. {
  1009. lexEnvRec.CreateMutableBinding(dn, canBeDeleted: false);
  1010. }
  1011. }
  1012. }
  1013. foreach (var f in functionsToInitialize)
  1014. {
  1015. var fn = f.Id.Name;
  1016. var fo = Function.CreateFunctionObject(f, lexEnv);
  1017. if (varEnvRec is GlobalEnvironmentRecord ger)
  1018. {
  1019. ger.CreateGlobalFunctionBinding(fn, fo, canBeDeleted: true);
  1020. }
  1021. else
  1022. {
  1023. var bindingExists = varEnvRec.HasBinding(fn);
  1024. if (!bindingExists)
  1025. {
  1026. varEnvRec.CreateMutableBinding(fn, canBeDeleted: true);
  1027. varEnvRec.InitializeBinding(fn, fo);
  1028. }
  1029. else
  1030. {
  1031. varEnvRec.SetMutableBinding(fn, fo, strict: false);
  1032. }
  1033. }
  1034. }
  1035. foreach (var vn in declaredVarNames)
  1036. {
  1037. if (varEnvRec is GlobalEnvironmentRecord ger)
  1038. {
  1039. ger.CreateGlobalVarBinding(vn, true);
  1040. }
  1041. else
  1042. {
  1043. var bindingExists = varEnvRec.HasBinding(vn);
  1044. if (!bindingExists)
  1045. {
  1046. varEnvRec.CreateMutableBinding(vn, canBeDeleted: true);
  1047. varEnvRec.InitializeBinding(vn, JsValue.Undefined);
  1048. }
  1049. }
  1050. }
  1051. }
  1052. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1053. internal void UpdateLexicalEnvironment(LexicalEnvironment newEnv)
  1054. {
  1055. _executionContexts.ReplaceTopLexicalEnvironment(newEnv);
  1056. }
  1057. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1058. internal void UpdateVariableEnvironment(LexicalEnvironment newEnv)
  1059. {
  1060. _executionContexts.ReplaceTopVariableEnvironment(newEnv);
  1061. }
  1062. internal JsValue Call(ICallable callable, JsValue thisObject, JsValue[] arguments, JintExpression expression)
  1063. {
  1064. if (callable is FunctionInstance functionInstance)
  1065. {
  1066. return Call(functionInstance, thisObject, arguments, expression);
  1067. }
  1068. return callable.Call(thisObject, arguments);
  1069. }
  1070. internal JsValue Construct(IConstructor constructor, JsValue[] arguments, JsValue newTarget, JintExpression expression)
  1071. {
  1072. if (constructor is FunctionInstance functionInstance)
  1073. {
  1074. return Construct(functionInstance, arguments, newTarget, expression);
  1075. }
  1076. return constructor.Construct(arguments, newTarget);
  1077. }
  1078. internal JsValue Call(
  1079. FunctionInstance functionInstance,
  1080. JsValue thisObject,
  1081. JsValue[] arguments,
  1082. JintExpression expression)
  1083. {
  1084. var callStackElement = new CallStackElement(functionInstance, expression);
  1085. var recursionDepth = CallStack.Push(callStackElement);
  1086. if (recursionDepth > Options.MaxRecursionDepth)
  1087. {
  1088. // pop the current element as it was never reached
  1089. CallStack.Pop();
  1090. ExceptionHelper.ThrowRecursionDepthOverflowException(CallStack, callStackElement.ToString());
  1091. }
  1092. if (_isDebugMode)
  1093. {
  1094. DebugHandler.AddToDebugCallStack(functionInstance);
  1095. }
  1096. var result = functionInstance.Call(thisObject, arguments);
  1097. if (_isDebugMode)
  1098. {
  1099. DebugHandler.PopDebugCallStack();
  1100. }
  1101. CallStack.Pop();
  1102. return result;
  1103. }
  1104. internal JsValue Construct(
  1105. FunctionInstance functionInstance,
  1106. JsValue[] arguments,
  1107. JsValue newTarget,
  1108. JintExpression expression)
  1109. {
  1110. var callStackElement = new CallStackElement(functionInstance, expression);
  1111. var recursionDepth = CallStack.Push(callStackElement);
  1112. if (recursionDepth > Options.MaxRecursionDepth)
  1113. {
  1114. // pop the current element as it was never reached
  1115. CallStack.Pop();
  1116. ExceptionHelper.ThrowRecursionDepthOverflowException(CallStack, callStackElement.ToString());
  1117. }
  1118. if (_isDebugMode)
  1119. {
  1120. DebugHandler.AddToDebugCallStack(functionInstance);
  1121. }
  1122. var result = ((IConstructor) functionInstance).Construct(arguments, newTarget);
  1123. if (_isDebugMode)
  1124. {
  1125. DebugHandler.PopDebugCallStack();
  1126. }
  1127. CallStack.Pop();
  1128. return result;
  1129. }
  1130. }
  1131. }