FunctionInstance.cs 8.4 KB

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