Engine.cs 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  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.References;
  36. namespace Jint
  37. {
  38. public class Engine
  39. {
  40. private static readonly ParserOptions DefaultParserOptions = new("<anonymous>")
  41. {
  42. AdaptRegexp = true,
  43. Tolerant = true,
  44. Loc = 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, "", engine) }
  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. return Execute(script, true);
  297. }
  298. internal Engine Execute(Script script, bool resetState)
  299. {
  300. if (resetState)
  301. {
  302. ResetConstraints();
  303. ResetLastStatement();
  304. ResetCallStack();
  305. }
  306. using (new StrictModeScope(_isStrict || script.Strict))
  307. {
  308. GlobalDeclarationInstantiation(
  309. script,
  310. GlobalEnvironment);
  311. var list = new JintStatementList(this, null, script.Body);
  312. var result = list.Execute();
  313. if (result.Type == CompletionType.Throw)
  314. {
  315. var ex = new JavaScriptException(result.GetValueOrDefault()).SetCallstack(this, result.Location);
  316. throw ex;
  317. }
  318. _completionValue = result.GetValueOrDefault();
  319. }
  320. return this;
  321. }
  322. private void ResetLastStatement()
  323. {
  324. _lastSyntaxNode = null;
  325. }
  326. /// <summary>
  327. /// Gets the last evaluated statement completion value
  328. /// </summary>
  329. public JsValue GetCompletionValue()
  330. {
  331. return _completionValue;
  332. }
  333. internal void RunBeforeExecuteStatementChecks(Statement statement)
  334. {
  335. // Avoid allocating the enumerator because we run this loop very often.
  336. for (var i = 0; i < _constraints.Count; i++)
  337. {
  338. _constraints[i].Check();
  339. }
  340. if (_isDebugMode)
  341. {
  342. DebugHandler.OnStep(statement);
  343. }
  344. }
  345. /// <summary>
  346. /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.7.1
  347. /// </summary>
  348. public JsValue GetValue(object value)
  349. {
  350. return GetValue(value, false);
  351. }
  352. internal JsValue GetValue(object value, bool returnReferenceToPool)
  353. {
  354. if (value is JsValue jsValue)
  355. {
  356. return jsValue;
  357. }
  358. if (!(value is Reference reference))
  359. {
  360. return ((Completion) value).Value;
  361. }
  362. return GetValue(reference, returnReferenceToPool);
  363. }
  364. internal JsValue GetValue(Reference reference, bool returnReferenceToPool)
  365. {
  366. var baseValue = reference.GetBase();
  367. if (baseValue._type == InternalTypes.Undefined)
  368. {
  369. if (_referenceResolver.TryUnresolvableReference(this, reference, out JsValue val))
  370. {
  371. return val;
  372. }
  373. ExceptionHelper.ThrowReferenceError(this, reference);
  374. }
  375. if ((baseValue._type & InternalTypes.ObjectEnvironmentRecord) == 0
  376. && _referenceResolver.TryPropertyReference(this, reference, ref baseValue))
  377. {
  378. return baseValue;
  379. }
  380. if (reference.IsPropertyReference())
  381. {
  382. var property = reference.GetReferencedName();
  383. if (returnReferenceToPool)
  384. {
  385. _referencePool.Return(reference);
  386. }
  387. if (baseValue.IsObject())
  388. {
  389. var o = TypeConverter.ToObject(this, baseValue);
  390. var v = o.Get(property);
  391. return v;
  392. }
  393. else
  394. {
  395. // check if we are accessing a string, boxing operation can be costly to do index access
  396. // we have good chance to have fast path with integer or string indexer
  397. ObjectInstance o = null;
  398. if ((property._type & (InternalTypes.String | InternalTypes.Integer)) != 0
  399. && baseValue is JsString s
  400. && TryHandleStringValue(property, s, ref o, out var jsValue))
  401. {
  402. return jsValue;
  403. }
  404. if (o is null)
  405. {
  406. o = TypeConverter.ToObject(this, baseValue);
  407. }
  408. var desc = o.GetProperty(property);
  409. if (desc == PropertyDescriptor.Undefined)
  410. {
  411. return JsValue.Undefined;
  412. }
  413. if (desc.IsDataDescriptor())
  414. {
  415. return desc.Value;
  416. }
  417. var getter = desc.Get;
  418. if (getter.IsUndefined())
  419. {
  420. return Undefined.Instance;
  421. }
  422. var callable = (ICallable) getter.AsObject();
  423. return callable.Call(baseValue, Arguments.Empty);
  424. }
  425. }
  426. if (!(baseValue is EnvironmentRecord record))
  427. {
  428. return ExceptionHelper.ThrowArgumentException<JsValue>();
  429. }
  430. var bindingValue = record.GetBindingValue(reference.GetReferencedName().ToString(), reference.IsStrictReference());
  431. if (returnReferenceToPool)
  432. {
  433. _referencePool.Return(reference);
  434. }
  435. return bindingValue;
  436. }
  437. private bool TryHandleStringValue(JsValue property, JsString s, ref ObjectInstance o, out JsValue jsValue)
  438. {
  439. if (property == CommonProperties.Length)
  440. {
  441. jsValue = JsNumber.Create((uint) s.Length);
  442. return true;
  443. }
  444. if (property is JsNumber number && number.IsInteger())
  445. {
  446. var index = number.AsInteger();
  447. var str = s._value;
  448. if (index < 0 || index >= str.Length)
  449. {
  450. jsValue = JsValue.Undefined;
  451. return true;
  452. }
  453. jsValue = JsString.Create(str[index]);
  454. return true;
  455. }
  456. if (property is JsString propertyString
  457. && propertyString._value.Length > 0
  458. && char.IsLower(propertyString._value[0]))
  459. {
  460. // trying to find property that's always in prototype
  461. o = String.PrototypeObject;
  462. }
  463. jsValue = JsValue.Undefined;
  464. return false;
  465. }
  466. /// <summary>
  467. /// https://tc39.es/ecma262/#sec-putvalue
  468. /// </summary>
  469. internal void PutValue(Reference reference, JsValue value)
  470. {
  471. var baseValue = reference.GetBase();
  472. if (reference.IsUnresolvableReference())
  473. {
  474. if (reference.IsStrictReference())
  475. {
  476. ExceptionHelper.ThrowReferenceError(this, reference);
  477. }
  478. Global.Set(reference.GetReferencedName(), value, throwOnError: false);
  479. }
  480. else if (reference.IsPropertyReference())
  481. {
  482. if (reference.HasPrimitiveBase())
  483. {
  484. baseValue = TypeConverter.ToObject(this, baseValue);
  485. }
  486. var succeeded = baseValue.Set(reference.GetReferencedName(), value, reference.GetThisValue());
  487. if (!succeeded && reference.IsStrictReference())
  488. {
  489. ExceptionHelper.ThrowTypeError(this);
  490. }
  491. }
  492. else
  493. {
  494. ((EnvironmentRecord) baseValue).SetMutableBinding(TypeConverter.ToString(reference.GetReferencedName()), value, reference.IsStrictReference());
  495. }
  496. }
  497. /// <summary>
  498. /// http://www.ecma-international.org/ecma-262/6.0/#sec-initializereferencedbinding
  499. /// </summary>
  500. public void InitializeReferenceBinding(Reference reference, JsValue value)
  501. {
  502. var baseValue = (EnvironmentRecord) reference.GetBase();
  503. baseValue.InitializeBinding(TypeConverter.ToString(reference.GetReferencedName()), value);
  504. }
  505. /// <summary>
  506. /// Invoke the current value as function.
  507. /// </summary>
  508. /// <param name="propertyName">The name of the function to call.</param>
  509. /// <param name="arguments">The arguments of the function call.</param>
  510. /// <returns>The value returned by the function call.</returns>
  511. public JsValue Invoke(string propertyName, params object[] arguments)
  512. {
  513. return Invoke(propertyName, null, arguments);
  514. }
  515. /// <summary>
  516. /// Invoke the current value as function.
  517. /// </summary>
  518. /// <param name="propertyName">The name of the function to call.</param>
  519. /// <param name="thisObj">The this value inside the function call.</param>
  520. /// <param name="arguments">The arguments of the function call.</param>
  521. /// <returns>The value returned by the function call.</returns>
  522. public JsValue Invoke(string propertyName, object thisObj, object[] arguments)
  523. {
  524. var value = GetValue(propertyName);
  525. return Invoke(value, thisObj, arguments);
  526. }
  527. /// <summary>
  528. /// Invoke the current value as function.
  529. /// </summary>
  530. /// <param name="value">The function to call.</param>
  531. /// <param name="arguments">The arguments of the function call.</param>
  532. /// <returns>The value returned by the function call.</returns>
  533. public JsValue Invoke(JsValue value, params object[] arguments)
  534. {
  535. return Invoke(value, null, arguments);
  536. }
  537. /// <summary>
  538. /// Invoke the current value as function.
  539. /// </summary>
  540. /// <param name="value">The function to call.</param>
  541. /// <param name="thisObj">The this value inside the function call.</param>
  542. /// <param name="arguments">The arguments of the function call.</param>
  543. /// <returns>The value returned by the function call.</returns>
  544. public JsValue Invoke(JsValue value, object thisObj, object[] arguments)
  545. {
  546. var callable = value as ICallable ?? ExceptionHelper.ThrowTypeError<ICallable>(this, "Can only invoke functions");
  547. var items = _jsValueArrayPool.RentArray(arguments.Length);
  548. for (int i = 0; i < arguments.Length; ++i)
  549. {
  550. items[i] = JsValue.FromObject(this, arguments[i]);
  551. }
  552. var result = callable.Call(JsValue.FromObject(this, thisObj), items);
  553. _jsValueArrayPool.ReturnArray(items);
  554. return result;
  555. }
  556. /// <summary>
  557. /// Gets a named value from the Global scope.
  558. /// </summary>
  559. /// <param name="propertyName">The name of the property to return.</param>
  560. public JsValue GetValue(string propertyName)
  561. {
  562. return GetValue(Global, new JsString(propertyName));
  563. }
  564. /// <summary>
  565. /// Gets the last evaluated <see cref="Node"/>.
  566. /// </summary>
  567. internal Node GetLastSyntaxNode()
  568. {
  569. return _lastSyntaxNode;
  570. }
  571. /// <summary>
  572. /// Gets a named value from the specified scope.
  573. /// </summary>
  574. /// <param name="scope">The scope to get the property from.</param>
  575. /// <param name="property">The name of the property to return.</param>
  576. public JsValue GetValue(JsValue scope, JsValue property)
  577. {
  578. var reference = _referencePool.Rent(scope, property, _isStrict);
  579. var jsValue = GetValue(reference, false);
  580. _referencePool.Return(reference);
  581. return jsValue;
  582. }
  583. /// <summary>
  584. /// https://tc39.es/ecma262/#sec-resolvebinding
  585. /// </summary>
  586. internal Reference ResolveBinding(string name, LexicalEnvironment env = null)
  587. {
  588. env ??= ExecutionContext.LexicalEnvironment;
  589. return GetIdentifierReference(env, name, StrictModeScope.IsStrictModeCode);
  590. }
  591. private Reference GetIdentifierReference(LexicalEnvironment lex, string name, bool strict)
  592. {
  593. if (lex is null)
  594. {
  595. return new Reference(JsValue.Undefined, name, strict);
  596. }
  597. var envRec = lex._record;
  598. if (envRec.HasBinding(name))
  599. {
  600. return new Reference(envRec, name, strict);
  601. }
  602. return GetIdentifierReference(lex._outer, name, strict);
  603. }
  604. /// <summary>
  605. /// https://tc39.es/ecma262/#sec-getthisenvironment
  606. /// </summary>
  607. internal EnvironmentRecord GetThisEnvironment()
  608. {
  609. // The loop will always terminate because the list of environments always
  610. // ends with the global environment which has a this binding.
  611. var lex = ExecutionContext.LexicalEnvironment;
  612. while (true)
  613. {
  614. var envRec = lex._record;
  615. var exists = envRec.HasThisBinding();
  616. if (exists)
  617. {
  618. return envRec;
  619. }
  620. var outer = lex._outer;
  621. lex = outer;
  622. }
  623. }
  624. /// <summary>
  625. /// https://tc39.es/ecma262/#sec-resolvethisbinding
  626. /// </summary>
  627. internal JsValue ResolveThisBinding()
  628. {
  629. var envRec = GetThisEnvironment();
  630. return envRec.GetThisBinding();
  631. }
  632. /// <summary>
  633. /// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
  634. /// </summary>
  635. private void GlobalDeclarationInstantiation(
  636. Script script,
  637. LexicalEnvironment env)
  638. {
  639. var envRec = (GlobalEnvironmentRecord) env._record;
  640. var hoistingScope = HoistingScope.GetProgramLevelDeclarations(script);
  641. var functionDeclarations = hoistingScope._functionDeclarations;
  642. var varDeclarations = hoistingScope._variablesDeclarations;
  643. var lexDeclarations = hoistingScope._lexicalDeclarations;
  644. var functionToInitialize = new LinkedList<FunctionDeclaration>();
  645. var declaredFunctionNames = new HashSet<string>();
  646. var declaredVarNames = new List<string>();
  647. if (functionDeclarations != null)
  648. {
  649. for (var i = functionDeclarations.Count - 1; i >= 0; i--)
  650. {
  651. var d = functionDeclarations[i];
  652. var fn = d.Id.Name;
  653. if (!declaredFunctionNames.Contains(fn))
  654. {
  655. var fnDefinable = envRec.CanDeclareGlobalFunction(fn);
  656. if (!fnDefinable)
  657. {
  658. ExceptionHelper.ThrowTypeError(this);
  659. }
  660. declaredFunctionNames.Add(fn);
  661. functionToInitialize.AddFirst(d);
  662. }
  663. }
  664. }
  665. var boundNames = new List<string>();
  666. if (varDeclarations != null)
  667. {
  668. for (var i = 0; i < varDeclarations.Count; i++)
  669. {
  670. var d = varDeclarations[i];
  671. boundNames.Clear();
  672. d.GetBoundNames(boundNames);
  673. for (var j = 0; j < boundNames.Count; j++)
  674. {
  675. var vn = boundNames[j];
  676. if (!declaredFunctionNames.Contains(vn))
  677. {
  678. var vnDefinable = envRec.CanDeclareGlobalVar(vn);
  679. if (!vnDefinable)
  680. {
  681. ExceptionHelper.ThrowTypeError(this);
  682. }
  683. declaredVarNames.Add(vn);
  684. }
  685. }
  686. }
  687. }
  688. if (lexDeclarations != null)
  689. {
  690. for (var i = 0; i < lexDeclarations.Count; i++)
  691. {
  692. var d = lexDeclarations[i];
  693. boundNames.Clear();
  694. d.GetBoundNames(boundNames);
  695. for (var j = 0; j < boundNames.Count; j++)
  696. {
  697. var dn = boundNames[j];
  698. if (envRec.HasVarDeclaration(dn)
  699. || envRec.HasLexicalDeclaration(dn)
  700. || envRec.HasRestrictedGlobalProperty(dn))
  701. {
  702. ExceptionHelper.ThrowSyntaxError(this, $"Identifier '{dn}' has already been declared");
  703. }
  704. if (d.Kind == VariableDeclarationKind.Const)
  705. {
  706. envRec.CreateImmutableBinding(dn, strict: true);
  707. }
  708. else
  709. {
  710. envRec.CreateMutableBinding(dn, canBeDeleted: false);
  711. }
  712. }
  713. }
  714. }
  715. foreach (var f in functionToInitialize)
  716. {
  717. var fn = f.Id.Name;
  718. var fo = Function.CreateFunctionObject(f, env);
  719. envRec.CreateGlobalFunctionBinding(fn, fo, canBeDeleted: false);
  720. }
  721. for (var i = 0; i < declaredVarNames.Count; i++)
  722. {
  723. var vn = declaredVarNames[i];
  724. envRec.CreateGlobalVarBinding(vn, canBeDeleted: false);
  725. }
  726. }
  727. /// <summary>
  728. /// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
  729. /// </summary>
  730. internal ArgumentsInstance FunctionDeclarationInstantiation(
  731. FunctionInstance functionInstance,
  732. JsValue[] argumentsList,
  733. LexicalEnvironment env)
  734. {
  735. var func = functionInstance._functionDefinition;
  736. var envRec = (FunctionEnvironmentRecord) env._record;
  737. var strict = StrictModeScope.IsStrictModeCode;
  738. var configuration = func.Initialize(this, functionInstance);
  739. var parameterNames = configuration.ParameterNames;
  740. var hasDuplicates = configuration.HasDuplicates;
  741. var simpleParameterList = configuration.IsSimpleParameterList;
  742. var hasParameterExpressions = configuration.HasParameterExpressions;
  743. var canInitializeParametersOnDeclaration = simpleParameterList && !configuration.HasDuplicates;
  744. envRec.InitializeParameters(parameterNames, hasDuplicates, canInitializeParametersOnDeclaration ? argumentsList : null);
  745. ArgumentsInstance ao = null;
  746. if (configuration.ArgumentsObjectNeeded)
  747. {
  748. if (strict || !simpleParameterList)
  749. {
  750. ao = CreateUnmappedArgumentsObject(argumentsList);
  751. }
  752. else
  753. {
  754. // NOTE: mapped argument object is only provided for non-strict functions that don't have a rest parameter,
  755. // any parameter default value initializers, or any destructured parameters.
  756. ao = CreateMappedArgumentsObject(functionInstance, parameterNames, argumentsList, envRec, configuration.HasRestParameter);
  757. }
  758. if (strict)
  759. {
  760. envRec.CreateImmutableBindingAndInitialize(KnownKeys.Arguments, strict: false, ao);
  761. }
  762. else
  763. {
  764. envRec.CreateMutableBindingAndInitialize(KnownKeys.Arguments, canBeDeleted: false, ao);
  765. }
  766. }
  767. if (!canInitializeParametersOnDeclaration)
  768. {
  769. // slower set
  770. envRec.AddFunctionParameters(func.Function, argumentsList);
  771. }
  772. // Let iteratorRecord be CreateListIteratorRecord(argumentsList).
  773. // If hasDuplicates is true, then
  774. // Perform ? IteratorBindingInitialization for formals with iteratorRecord and undefined as arguments.
  775. // Else,
  776. // Perform ? IteratorBindingInitialization for formals with iteratorRecord and env as arguments.
  777. LexicalEnvironment varEnv;
  778. DeclarativeEnvironmentRecord varEnvRec;
  779. if (!hasParameterExpressions)
  780. {
  781. // NOTE: Only a single lexical environment is needed for the parameters and top-level vars.
  782. for (var i = 0; i < configuration.VarsToInitialize.Count; i++)
  783. {
  784. var pair = configuration.VarsToInitialize[i];
  785. envRec.CreateMutableBindingAndInitialize(pair.Name, canBeDeleted: false, JsValue.Undefined);
  786. }
  787. varEnv = env;
  788. varEnvRec = envRec;
  789. }
  790. else
  791. {
  792. // NOTE: A separate Environment Record is needed to ensure that closures created by expressions
  793. // in the formal parameter list do not have visibility of declarations in the function body.
  794. varEnv = LexicalEnvironment.NewDeclarativeEnvironment(this, env);
  795. varEnvRec = (DeclarativeEnvironmentRecord) varEnv._record;
  796. UpdateVariableEnvironment(varEnv);
  797. for (var i = 0; i < configuration.VarsToInitialize.Count; i++)
  798. {
  799. var pair = configuration.VarsToInitialize[i];
  800. var initialValue = pair.InitialValue ?? envRec.GetBindingValue(pair.Name, strict: false);
  801. varEnvRec.CreateMutableBindingAndInitialize(pair.Name, canBeDeleted: false, initialValue);
  802. }
  803. }
  804. // NOTE: Annex B.3.3.1 adds additional steps at this point.
  805. // A https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
  806. LexicalEnvironment lexEnv;
  807. if (!strict)
  808. {
  809. lexEnv = LexicalEnvironment.NewDeclarativeEnvironment(this, varEnv);
  810. // NOTE: Non-strict functions use a separate lexical Environment Record for top-level lexical declarations
  811. // so that a direct eval can determine whether any var scoped declarations introduced by the eval code conflict
  812. // with pre-existing top-level lexically scoped declarations. This is not needed for strict functions
  813. // because a strict direct eval always places all declarations into a new Environment Record.
  814. }
  815. else
  816. {
  817. lexEnv = varEnv;
  818. }
  819. var lexEnvRec = lexEnv._record;
  820. UpdateLexicalEnvironment(lexEnv);
  821. if (configuration.LexicalDeclarations.Length > 0)
  822. {
  823. InitializeLexicalDeclarations(configuration.LexicalDeclarations, lexEnvRec);
  824. }
  825. if (configuration.FunctionsToInitialize != null)
  826. {
  827. InitializeFunctions(configuration.FunctionsToInitialize, lexEnv, varEnvRec);
  828. }
  829. return ao;
  830. }
  831. private void InitializeFunctions(
  832. LinkedList<FunctionDeclaration> functionsToInitialize,
  833. LexicalEnvironment lexEnv,
  834. DeclarativeEnvironmentRecord varEnvRec)
  835. {
  836. foreach (var f in functionsToInitialize)
  837. {
  838. var fn = f.Id.Name;
  839. var fo = Function.CreateFunctionObject(f, lexEnv);
  840. varEnvRec.SetMutableBinding(fn, fo, strict: false);
  841. }
  842. }
  843. private static void InitializeLexicalDeclarations(
  844. JintFunctionDefinition.State.LexicalVariableDeclaration[] lexicalDeclarations,
  845. EnvironmentRecord lexEnvRec)
  846. {
  847. foreach (var d in lexicalDeclarations)
  848. {
  849. for (var j = 0; j < d.BoundNames.Count; j++)
  850. {
  851. var dn = d.BoundNames[j];
  852. if (d.Kind == VariableDeclarationKind.Const)
  853. {
  854. lexEnvRec.CreateImmutableBinding(dn, strict: true);
  855. }
  856. else
  857. {
  858. lexEnvRec.CreateMutableBinding(dn, canBeDeleted: false);
  859. }
  860. }
  861. }
  862. }
  863. private ArgumentsInstance CreateMappedArgumentsObject(
  864. FunctionInstance func,
  865. Key[] formals,
  866. JsValue[] argumentsList,
  867. DeclarativeEnvironmentRecord envRec,
  868. bool hasRestParameter)
  869. {
  870. return _argumentsInstancePool.Rent(func, formals, argumentsList, envRec, hasRestParameter);
  871. }
  872. private ArgumentsInstance CreateUnmappedArgumentsObject(JsValue[] argumentsList)
  873. {
  874. return _argumentsInstancePool.Rent(argumentsList);
  875. }
  876. /// <summary>
  877. /// https://tc39.es/ecma262/#sec-evaldeclarationinstantiation
  878. /// </summary>
  879. internal void EvalDeclarationInstantiation(
  880. Script script,
  881. LexicalEnvironment varEnv,
  882. LexicalEnvironment lexEnv,
  883. bool strict)
  884. {
  885. var hoistingScope = HoistingScope.GetProgramLevelDeclarations(script);
  886. var lexEnvRec = (DeclarativeEnvironmentRecord) lexEnv._record;
  887. var varEnvRec = varEnv._record;
  888. if (!strict && hoistingScope._variablesDeclarations != null)
  889. {
  890. if (varEnvRec is GlobalEnvironmentRecord globalEnvironmentRecord)
  891. {
  892. ref readonly var nodes = ref hoistingScope._variablesDeclarations;
  893. for (var i = 0; i < nodes.Count; i++)
  894. {
  895. var variablesDeclaration = nodes[i];
  896. var identifier = (Identifier) variablesDeclaration.Declarations[0].Id;
  897. if (globalEnvironmentRecord.HasLexicalDeclaration(identifier.Name))
  898. {
  899. ExceptionHelper.ThrowSyntaxError(this, "Identifier '" + identifier.Name + "' has already been declared");
  900. }
  901. }
  902. }
  903. var thisLex = lexEnv;
  904. while (thisLex != varEnv)
  905. {
  906. var thisEnvRec = thisLex._record;
  907. if (!(thisEnvRec is ObjectEnvironmentRecord))
  908. {
  909. ref readonly var nodes = ref hoistingScope._variablesDeclarations;
  910. for (var i = 0; i < nodes.Count; i++)
  911. {
  912. var variablesDeclaration = nodes[i];
  913. var identifier = (Identifier) variablesDeclaration.Declarations[0].Id;
  914. if (thisEnvRec.HasBinding(identifier.Name))
  915. {
  916. ExceptionHelper.ThrowSyntaxError(this);
  917. }
  918. }
  919. }
  920. thisLex = thisLex._outer;
  921. }
  922. }
  923. var functionDeclarations = hoistingScope._functionDeclarations;
  924. var functionsToInitialize = new LinkedList<FunctionDeclaration>();
  925. var declaredFunctionNames = new HashSet<string>();
  926. if (functionDeclarations != null)
  927. {
  928. for (var i = functionDeclarations.Count - 1; i >= 0; i--)
  929. {
  930. var d = functionDeclarations[i];
  931. var fn = d.Id.Name;
  932. if (!declaredFunctionNames.Contains(fn))
  933. {
  934. if (varEnvRec is GlobalEnvironmentRecord ger)
  935. {
  936. var fnDefinable = ger.CanDeclareGlobalFunction(fn);
  937. if (!fnDefinable)
  938. {
  939. ExceptionHelper.ThrowTypeError(this);
  940. }
  941. }
  942. declaredFunctionNames.Add(fn);
  943. functionsToInitialize.AddFirst(d);
  944. }
  945. }
  946. }
  947. var boundNames = new List<string>();
  948. var declaredVarNames = new List<string>();
  949. var variableDeclarations = hoistingScope._variablesDeclarations;
  950. var variableDeclarationsCount = variableDeclarations?.Count;
  951. for (var i = 0; i < variableDeclarationsCount; i++)
  952. {
  953. var variableDeclaration = variableDeclarations[i];
  954. boundNames.Clear();
  955. variableDeclaration.GetBoundNames(boundNames);
  956. for (var j = 0; j < boundNames.Count; j++)
  957. {
  958. var vn = boundNames[j];
  959. if (!declaredFunctionNames.Contains(vn))
  960. {
  961. if (varEnvRec is GlobalEnvironmentRecord ger)
  962. {
  963. var vnDefinable = ger.CanDeclareGlobalFunction(vn);
  964. if (!vnDefinable)
  965. {
  966. ExceptionHelper.ThrowTypeError(this);
  967. }
  968. }
  969. declaredVarNames.Add(vn);
  970. }
  971. }
  972. }
  973. var lexicalDeclarations = hoistingScope._lexicalDeclarations;
  974. var lexicalDeclarationsCount = lexicalDeclarations?.Count;
  975. for (var i = 0; i < lexicalDeclarationsCount; i++)
  976. {
  977. boundNames.Clear();
  978. var d = lexicalDeclarations[i];
  979. d.GetBoundNames(boundNames);
  980. for (var j = 0; j < boundNames.Count; j++)
  981. {
  982. var dn = boundNames[j];
  983. if (d.Kind == VariableDeclarationKind.Const)
  984. {
  985. lexEnvRec.CreateImmutableBinding(dn, strict: true);
  986. }
  987. else
  988. {
  989. lexEnvRec.CreateMutableBinding(dn, canBeDeleted: false);
  990. }
  991. }
  992. }
  993. foreach (var f in functionsToInitialize)
  994. {
  995. var fn = f.Id.Name;
  996. var fo = Function.CreateFunctionObject(f, lexEnv);
  997. if (varEnvRec is GlobalEnvironmentRecord ger)
  998. {
  999. ger.CreateGlobalFunctionBinding(fn, fo, canBeDeleted: true);
  1000. }
  1001. else
  1002. {
  1003. var bindingExists = varEnvRec.HasBinding(fn);
  1004. if (!bindingExists)
  1005. {
  1006. varEnvRec.CreateMutableBinding(fn, canBeDeleted: true);
  1007. varEnvRec.InitializeBinding(fn, fo);
  1008. }
  1009. else
  1010. {
  1011. varEnvRec.SetMutableBinding(fn, fo, strict: false);
  1012. }
  1013. }
  1014. }
  1015. foreach (var vn in declaredVarNames)
  1016. {
  1017. if (varEnvRec is GlobalEnvironmentRecord ger)
  1018. {
  1019. ger.CreateGlobalVarBinding(vn, true);
  1020. }
  1021. else
  1022. {
  1023. var bindingExists = varEnvRec.HasBinding(vn);
  1024. if (!bindingExists)
  1025. {
  1026. varEnvRec.CreateMutableBinding(vn, canBeDeleted: true);
  1027. varEnvRec.InitializeBinding(vn, JsValue.Undefined);
  1028. }
  1029. }
  1030. }
  1031. }
  1032. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1033. internal void UpdateLexicalEnvironment(LexicalEnvironment newEnv)
  1034. {
  1035. _executionContexts.ReplaceTopLexicalEnvironment(newEnv);
  1036. }
  1037. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1038. internal void UpdateVariableEnvironment(LexicalEnvironment newEnv)
  1039. {
  1040. _executionContexts.ReplaceTopVariableEnvironment(newEnv);
  1041. }
  1042. internal JsValue Call(ICallable callable, JsValue thisObject, JsValue[] arguments, Location? location)
  1043. {
  1044. if (callable is FunctionInstance functionInstance)
  1045. {
  1046. return Call(functionInstance, thisObject, arguments, location);
  1047. }
  1048. return callable.Call(thisObject, arguments);
  1049. }
  1050. internal JsValue Call(
  1051. FunctionInstance functionInstance,
  1052. JsValue thisObject,
  1053. JsValue[] arguments,
  1054. Location? location)
  1055. {
  1056. location ??= ((Node) functionInstance._functionDefinition?.Function)?.Location;
  1057. var callStackElement = new CallStackElement(functionInstance, location);
  1058. var recursionDepth = CallStack.Push(callStackElement);
  1059. if (recursionDepth > Options.MaxRecursionDepth)
  1060. {
  1061. // pop the current element as it was never reached
  1062. CallStack.Pop();
  1063. ExceptionHelper.ThrowRecursionDepthOverflowException(CallStack, callStackElement.ToString());
  1064. }
  1065. if (_isDebugMode)
  1066. {
  1067. DebugHandler.AddToDebugCallStack(functionInstance);
  1068. }
  1069. var result = functionInstance.Call(thisObject, arguments);
  1070. if (_isDebugMode)
  1071. {
  1072. DebugHandler.PopDebugCallStack();
  1073. }
  1074. CallStack.Pop();
  1075. return result;
  1076. }
  1077. }
  1078. }