DeclarativeEnvironmentRecord.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. using System;
  2. using System.Collections.Generic;
  3. using Esprima.Ast;
  4. using Jint.Collections;
  5. using Jint.Native;
  6. using Jint.Native.Argument;
  7. using Jint.Native.Function;
  8. namespace Jint.Runtime.Environments
  9. {
  10. /// <summary>
  11. /// Represents a declarative environment record
  12. /// http://www.ecma-international.org/ecma-262/5.1/#sec-10.2.1.1
  13. /// </summary>
  14. public sealed class DeclarativeEnvironmentRecord : EnvironmentRecord
  15. {
  16. private StringDictionarySlim<Binding> _dictionary;
  17. private bool _set;
  18. private string _key;
  19. private Binding _value;
  20. private const string BindingNameArguments = "arguments";
  21. private Binding _argumentsBinding;
  22. public DeclarativeEnvironmentRecord(Engine engine) : base(engine)
  23. {
  24. }
  25. private void SetItem(string key, in Binding value)
  26. {
  27. if (_set && _key != key)
  28. {
  29. if (_dictionary == null)
  30. {
  31. _dictionary = new StringDictionarySlim<Binding>();
  32. }
  33. _dictionary[_key] = _value;
  34. }
  35. _set = true;
  36. _key = key;
  37. _value = value;
  38. if (_dictionary != null)
  39. {
  40. _dictionary[key] = value;
  41. }
  42. }
  43. private ref Binding GetExistingItem(string key)
  44. {
  45. if (_set && _key == key)
  46. {
  47. return ref _value;
  48. }
  49. if (key.Length == 9 && key == BindingNameArguments)
  50. {
  51. return ref _argumentsBinding;
  52. }
  53. return ref _dictionary[key];
  54. }
  55. private bool ContainsKey(string key)
  56. {
  57. if (key.Length == 9 && key == BindingNameArguments)
  58. {
  59. return !ReferenceEquals(_argumentsBinding.Value, null);
  60. }
  61. if (_set && key == _key)
  62. {
  63. return true;
  64. }
  65. return _dictionary?.ContainsKey(key) == true;
  66. }
  67. private void Remove(string key)
  68. {
  69. if (_set && key == _key)
  70. {
  71. _set = false;
  72. _key = null;
  73. _value = default;
  74. }
  75. if (key == BindingNameArguments)
  76. {
  77. _argumentsBinding.Value = null;
  78. }
  79. else
  80. {
  81. _dictionary?.Remove(key);
  82. }
  83. }
  84. private bool TryGetValue(string key, out Binding value)
  85. {
  86. value = default;
  87. if (_set && _key == key)
  88. {
  89. value = _value;
  90. return true;
  91. }
  92. return _dictionary != null && _dictionary.TryGetValue(key, out value);
  93. }
  94. public override bool HasBinding(string name)
  95. {
  96. return ContainsKey(name);
  97. }
  98. public override void CreateMutableBinding(string name, JsValue value, bool canBeDeleted = false)
  99. {
  100. SetItem(name, new Binding(value, canBeDeleted, mutable: true));
  101. }
  102. public override void SetMutableBinding(string name, JsValue value, bool strict)
  103. {
  104. ref var binding = ref GetExistingItem(name);
  105. if (binding.Mutable)
  106. {
  107. binding.Value = value;
  108. }
  109. else
  110. {
  111. if (strict)
  112. {
  113. ExceptionHelper.ThrowTypeError(_engine, "Can't update the value of an immutable binding.");
  114. }
  115. }
  116. }
  117. public override JsValue GetBindingValue(string name, bool strict)
  118. {
  119. ref var binding = ref GetExistingItem(name);
  120. if (!binding.Mutable && binding.Value._type == Types.Undefined)
  121. {
  122. if (strict)
  123. {
  124. ExceptionHelper.ThrowReferenceError(_engine, "Can't access an uninitialized immutable binding.");
  125. }
  126. return Undefined;
  127. }
  128. return binding.Value;
  129. }
  130. public override bool DeleteBinding(string name)
  131. {
  132. ref Binding binding = ref GetExistingItem(name);
  133. if (ReferenceEquals(binding.Value, null))
  134. {
  135. return true;
  136. }
  137. if (!binding.CanBeDeleted)
  138. {
  139. return false;
  140. }
  141. Remove(name);
  142. return true;
  143. }
  144. public override JsValue ImplicitThisValue()
  145. {
  146. return Undefined;
  147. }
  148. /// <inheritdoc />
  149. public override string[] GetAllBindingNames()
  150. {
  151. int size = _set ? 1 : 0;
  152. if (!ReferenceEquals(_argumentsBinding.Value, null))
  153. {
  154. size += 1;
  155. }
  156. if (_dictionary != null)
  157. {
  158. size += _dictionary.Count;
  159. }
  160. var keys = size > 0 ? new string[size] : ArrayExt.Empty<string>();
  161. int n = 0;
  162. if (_set)
  163. {
  164. keys[n++] = _key;
  165. }
  166. if (!ReferenceEquals(_argumentsBinding.Value, null))
  167. {
  168. keys[n++] = BindingNameArguments;
  169. }
  170. _dictionary?.Keys.CopyTo(keys, n);
  171. return keys;
  172. }
  173. internal void ReleaseArguments()
  174. {
  175. _engine._argumentsInstancePool.Return(_argumentsBinding.Value as ArgumentsInstance);
  176. _argumentsBinding = default;
  177. }
  178. /// <summary>
  179. /// Optimized version for function calls.
  180. /// </summary>
  181. internal void AddFunctionParameters(
  182. FunctionInstance functionInstance,
  183. JsValue[] arguments,
  184. ArgumentsInstance argumentsInstance)
  185. {
  186. var parameters = functionInstance._formalParameters;
  187. bool empty = _dictionary == null && !_set;
  188. if (empty && parameters.Length == 1 && parameters[0].Length != BindingNameArguments.Length)
  189. {
  190. var jsValue = arguments.Length == 0 ? Undefined : arguments[0];
  191. var binding = new Binding(jsValue, false, true);
  192. _set = true;
  193. _key = parameters[0];
  194. _value = binding;
  195. }
  196. else
  197. {
  198. AddMultipleParameters(arguments, parameters);
  199. }
  200. if (ReferenceEquals(_argumentsBinding.Value, null))
  201. {
  202. _argumentsBinding = new Binding(argumentsInstance, canBeDeleted: false, mutable: true);
  203. }
  204. }
  205. private void AddMultipleParameters(JsValue[] arguments, string[] parameters)
  206. {
  207. bool empty = _dictionary == null && !_set;
  208. for (var i = 0; i < parameters.Length; i++)
  209. {
  210. var argName = parameters[i];
  211. var jsValue = i + 1 > arguments.Length ? Undefined : arguments[i];
  212. if (empty || !TryGetValue(argName, out var existing))
  213. {
  214. var binding = new Binding(jsValue, false, true);
  215. if (argName.Length == 9 && argName == BindingNameArguments)
  216. {
  217. _argumentsBinding = binding;
  218. }
  219. else
  220. {
  221. SetItem(argName, binding);
  222. }
  223. }
  224. else
  225. {
  226. if (existing.Mutable)
  227. {
  228. ref var b = ref GetExistingItem(argName);
  229. b.Value = jsValue;
  230. }
  231. else
  232. {
  233. ExceptionHelper.ThrowTypeError(_engine, "Can't update the value of an immutable binding.");
  234. }
  235. }
  236. }
  237. }
  238. internal void AddVariableDeclarations(List<VariableDeclaration> variableDeclarations)
  239. {
  240. var variableDeclarationsCount = variableDeclarations.Count;
  241. for (var i = 0; i < variableDeclarationsCount; i++)
  242. {
  243. var variableDeclaration = variableDeclarations[i];
  244. var declarationsCount = variableDeclaration.Declarations.Count;
  245. for (var j = 0; j < declarationsCount; j++)
  246. {
  247. var d = variableDeclaration.Declarations[j];
  248. var dn = ((Identifier) d.Id).Name;
  249. if (!ContainsKey(dn))
  250. {
  251. var binding = new Binding(Undefined, canBeDeleted: false, mutable: true);
  252. SetItem(dn, binding);
  253. }
  254. }
  255. }
  256. }
  257. }
  258. }