FunctionInstance.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. using System.Collections.Generic;
  2. using System.Runtime.CompilerServices;
  3. using Jint.Native.Object;
  4. using Jint.Runtime;
  5. using Jint.Runtime.Descriptors;
  6. using Jint.Runtime.Environments;
  7. using Jint.Runtime.Interpreter;
  8. namespace Jint.Native.Function
  9. {
  10. public abstract class FunctionInstance : ObjectInstance, ICallable
  11. {
  12. internal enum FunctionThisMode
  13. {
  14. Lexical,
  15. Strict,
  16. Global
  17. }
  18. protected internal PropertyDescriptor _prototypeDescriptor;
  19. protected PropertyDescriptor _length;
  20. private JsValue _name;
  21. private PropertyDescriptor _nameDescriptor;
  22. protected internal LexicalEnvironment _environment;
  23. internal readonly JintFunctionDefinition _functionDefinition;
  24. internal readonly FunctionThisMode _thisMode;
  25. internal FunctionInstance(
  26. Engine engine,
  27. JintFunctionDefinition function,
  28. LexicalEnvironment scope,
  29. FunctionThisMode thisMode)
  30. : this(engine, !string.IsNullOrWhiteSpace(function.Name) ? new JsString(function.Name) : null, thisMode)
  31. {
  32. _functionDefinition = function;
  33. _environment = scope;
  34. }
  35. internal FunctionInstance(
  36. Engine engine,
  37. JsString name,
  38. FunctionThisMode thisMode = FunctionThisMode.Global,
  39. ObjectClass objectClass = ObjectClass.Function)
  40. : base(engine, objectClass)
  41. {
  42. _name = name;
  43. _thisMode = thisMode;
  44. }
  45. /// <summary>
  46. /// Executed when a function object is used as a function
  47. /// </summary>
  48. /// <param name="thisObject"></param>
  49. /// <param name="arguments"></param>
  50. /// <returns></returns>
  51. public abstract JsValue Call(JsValue thisObject, JsValue[] arguments);
  52. public bool Strict => _thisMode == FunctionThisMode.Strict;
  53. public virtual bool HasInstance(JsValue v)
  54. {
  55. if (!(v is ObjectInstance o))
  56. {
  57. return false;
  58. }
  59. var p = Get(CommonProperties.Prototype, this);
  60. if (!(p is ObjectInstance prototype))
  61. {
  62. ExceptionHelper.ThrowTypeError(_engine, $"Function has non-object prototype '{TypeConverter.ToString(p)}' in instanceof check");
  63. }
  64. while (true)
  65. {
  66. o = o.Prototype;
  67. if (o is null)
  68. {
  69. return false;
  70. }
  71. if (SameValue(p, o))
  72. {
  73. return true;
  74. }
  75. }
  76. }
  77. /// <summary>
  78. /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.4
  79. /// </summary>
  80. public override JsValue Get(JsValue property, JsValue receiver)
  81. {
  82. var v = base.Get(property, receiver);
  83. if (property == CommonProperties.Caller
  84. && v.As<FunctionInstance>()?._thisMode == FunctionThisMode.Strict)
  85. {
  86. ExceptionHelper.ThrowTypeError(_engine);
  87. }
  88. return v;
  89. }
  90. public override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> GetOwnProperties()
  91. {
  92. if (_prototypeDescriptor != null)
  93. {
  94. yield return new KeyValuePair<JsValue, PropertyDescriptor>(CommonProperties.Prototype, _prototypeDescriptor);
  95. }
  96. if (_length != null)
  97. {
  98. yield return new KeyValuePair<JsValue, PropertyDescriptor>(CommonProperties.Length, _length);
  99. }
  100. if (!(_name is null))
  101. {
  102. yield return new KeyValuePair<JsValue, PropertyDescriptor>(CommonProperties.Name, GetOwnProperty(CommonProperties.Name));
  103. }
  104. foreach (var entry in base.GetOwnProperties())
  105. {
  106. yield return entry;
  107. }
  108. }
  109. public override List<JsValue> GetOwnPropertyKeys(Types types)
  110. {
  111. var keys = new List<JsValue>();
  112. if (_prototypeDescriptor != null)
  113. {
  114. keys.Add(CommonProperties.Prototype);
  115. }
  116. if (_length != null)
  117. {
  118. keys.Add(CommonProperties.Length);
  119. }
  120. if (!(_name is null))
  121. {
  122. keys.Add(CommonProperties.Name);
  123. }
  124. keys.AddRange(base.GetOwnPropertyKeys(types));
  125. return keys;
  126. }
  127. public override PropertyDescriptor GetOwnProperty(JsValue property)
  128. {
  129. if (property == CommonProperties.Prototype)
  130. {
  131. return _prototypeDescriptor ?? PropertyDescriptor.Undefined;
  132. }
  133. if (property == CommonProperties.Length)
  134. {
  135. return _length ?? PropertyDescriptor.Undefined;
  136. }
  137. if (property == CommonProperties.Name)
  138. {
  139. return !(_name is null)
  140. ? _nameDescriptor ??= new PropertyDescriptor(_name, PropertyFlag.Configurable)
  141. : PropertyDescriptor.Undefined;
  142. }
  143. return base.GetOwnProperty(property);
  144. }
  145. protected internal override void SetOwnProperty(JsValue property, PropertyDescriptor desc)
  146. {
  147. if (property == CommonProperties.Prototype)
  148. {
  149. _prototypeDescriptor = desc;
  150. }
  151. else if (property == CommonProperties.Length)
  152. {
  153. _length = desc;
  154. }
  155. else if (property == CommonProperties.Name)
  156. {
  157. _name = desc._value;
  158. _nameDescriptor = desc;
  159. }
  160. else
  161. {
  162. base.SetOwnProperty(property, desc);
  163. }
  164. }
  165. public override bool HasOwnProperty(JsValue property)
  166. {
  167. if (property == CommonProperties.Prototype)
  168. {
  169. return _prototypeDescriptor != null;
  170. }
  171. if (property == CommonProperties.Length)
  172. {
  173. return _length != null;
  174. }
  175. if (property == CommonProperties.Name)
  176. {
  177. return !(_name is null);
  178. }
  179. return base.HasOwnProperty(property);
  180. }
  181. public override void RemoveOwnProperty(JsValue property)
  182. {
  183. if (property == CommonProperties.Prototype)
  184. {
  185. _prototypeDescriptor = null;
  186. }
  187. if (property == CommonProperties.Length)
  188. {
  189. _length = null;
  190. }
  191. if (property == CommonProperties.Name)
  192. {
  193. _name = null;
  194. _nameDescriptor = null;
  195. }
  196. base.RemoveOwnProperty(property);
  197. }
  198. internal void SetFunctionName(JsValue name, bool throwIfExists = false)
  199. {
  200. if (_name is null)
  201. {
  202. JsString value;
  203. if (name is JsSymbol symbol)
  204. {
  205. value = new JsString(symbol._value.IsUndefined()
  206. ? ""
  207. : "[" + symbol._value + "]");
  208. }
  209. else
  210. {
  211. value = name as JsString ?? new JsString(name.ToString());
  212. }
  213. _name = value;
  214. }
  215. else if (throwIfExists)
  216. {
  217. ExceptionHelper.ThrowError(_engine, "cannot set name");
  218. }
  219. }
  220. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  221. internal ObjectInstance OrdinaryCreateFromConstructor(JsValue constructor, ObjectInstance intrinsicDefaultProto)
  222. {
  223. var proto = GetPrototypeFromConstructor(constructor, intrinsicDefaultProto);
  224. var obj = new ObjectInstance(_engine)
  225. {
  226. _prototype = proto
  227. };
  228. return obj;
  229. }
  230. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  231. private static ObjectInstance GetPrototypeFromConstructor(JsValue constructor, ObjectInstance intrinsicDefaultProto)
  232. {
  233. var proto = constructor.Get(CommonProperties.Prototype, constructor) as ObjectInstance;
  234. // If Type(proto) is not Object, then
  235. // Let realm be ? GetFunctionRealm(constructor).
  236. // Set proto to realm's intrinsic object named intrinsicDefaultProto.
  237. return proto ?? intrinsicDefaultProto;
  238. }
  239. }
  240. }