ReflectInstance.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #pragma warning disable CA1859 // Use concrete types when possible for improved performance -- most of prototype methods return JsValue
  2. using Jint.Collections;
  3. using Jint.Native.Function;
  4. using Jint.Native.Object;
  5. using Jint.Native.Symbol;
  6. using Jint.Runtime;
  7. using Jint.Runtime.Descriptors;
  8. using Jint.Runtime.Interop;
  9. namespace Jint.Native.Reflect
  10. {
  11. /// <summary>
  12. /// https://www.ecma-international.org/ecma-262/6.0/index.html#sec-reflect-object
  13. /// </summary>
  14. internal sealed class ReflectInstance : ObjectInstance
  15. {
  16. private readonly Realm _realm;
  17. internal ReflectInstance(
  18. Engine engine,
  19. Realm realm,
  20. ObjectPrototype objectPrototype) : base(engine)
  21. {
  22. _realm = realm;
  23. _prototype = objectPrototype;
  24. }
  25. protected override void Initialize()
  26. {
  27. var properties = new PropertyDictionary(14, checkExistingKeys: false)
  28. {
  29. ["apply"] = new PropertyDescriptor(new ClrFunction(Engine, "apply", Apply, 3, PropertyFlag.Configurable), true, false, true),
  30. ["construct"] = new PropertyDescriptor(new ClrFunction(Engine, "construct", Construct, 2, PropertyFlag.Configurable), true, false, true),
  31. ["defineProperty"] = new PropertyDescriptor(new ClrFunction(Engine, "defineProperty", DefineProperty, 3, PropertyFlag.Configurable), true, false, true),
  32. ["deleteProperty"] = new PropertyDescriptor(new ClrFunction(Engine, "deleteProperty", DeleteProperty, 2, PropertyFlag.Configurable), true, false, true),
  33. ["get"] = new PropertyDescriptor(new ClrFunction(Engine, "get", Get, 2, PropertyFlag.Configurable), true, false, true),
  34. ["getOwnPropertyDescriptor"] = new PropertyDescriptor(new ClrFunction(Engine, "getOwnPropertyDescriptor", GetOwnPropertyDescriptor, 2, PropertyFlag.Configurable), true, false, true),
  35. ["getPrototypeOf"] = new PropertyDescriptor(new ClrFunction(Engine, "getPrototypeOf", GetPrototypeOf, 1, PropertyFlag.Configurable), true, false, true),
  36. ["has"] = new PropertyDescriptor(new ClrFunction(Engine, "has", Has, 2, PropertyFlag.Configurable), true, false, true),
  37. ["isExtensible"] = new PropertyDescriptor(new ClrFunction(Engine, "isExtensible", IsExtensible, 1, PropertyFlag.Configurable), true, false, true),
  38. ["ownKeys"] = new PropertyDescriptor(new ClrFunction(Engine, "ownKeys", OwnKeys, 1, PropertyFlag.Configurable), true, false, true),
  39. ["preventExtensions"] = new PropertyDescriptor(new ClrFunction(Engine, "preventExtensions", PreventExtensions, 1, PropertyFlag.Configurable), true, false, true),
  40. ["set"] = new PropertyDescriptor(new ClrFunction(Engine, "set", Set, 3, PropertyFlag.Configurable), true, false, true),
  41. ["setPrototypeOf"] = new PropertyDescriptor(new ClrFunction(Engine, "setPrototypeOf", SetPrototypeOf, 2, PropertyFlag.Configurable), true, false, true),
  42. };
  43. SetProperties(properties);
  44. var symbols = new SymbolDictionary(1)
  45. {
  46. [GlobalSymbolRegistry.ToStringTag] = new PropertyDescriptor("Reflect", false, false, true)
  47. };
  48. SetSymbols(symbols);
  49. }
  50. private JsValue Apply(JsValue thisObject, JsValue[] arguments)
  51. {
  52. var target = arguments.At(0);
  53. var thisArgument = arguments.At(1);
  54. var argumentsList = arguments.At(2);
  55. if (!target.IsCallable)
  56. {
  57. ExceptionHelper.ThrowTypeError(_realm);
  58. }
  59. var args = FunctionPrototype.CreateListFromArrayLike(_realm, argumentsList);
  60. // 3. Perform PrepareForTailCall().
  61. return ((ICallable) target).Call(thisArgument, args);
  62. }
  63. /// <summary>
  64. /// https://tc39.es/ecma262/#sec-reflect.construct
  65. /// </summary>
  66. private JsValue Construct(JsValue thisObject, JsValue[] arguments)
  67. {
  68. var target = AssertConstructor(_engine, arguments.At(0));
  69. var newTargetArgument = arguments.At(2, arguments[0]);
  70. AssertConstructor(_engine, newTargetArgument);
  71. var args = FunctionPrototype.CreateListFromArrayLike(_realm, arguments.At(1));
  72. return target.Construct(args, newTargetArgument);
  73. }
  74. /// <summary>
  75. /// https://tc39.es/ecma262/#sec-reflect.defineproperty
  76. /// </summary>
  77. private JsValue DefineProperty(JsValue thisObject, JsValue[] arguments)
  78. {
  79. var target = arguments.At(0) as ObjectInstance;
  80. if (target is null)
  81. {
  82. ExceptionHelper.ThrowTypeError(_realm, "Reflect.defineProperty called on non-object");
  83. }
  84. var propertyKey = arguments.At(1);
  85. var attributes = arguments.At(2);
  86. var key = TypeConverter.ToPropertyKey(propertyKey);
  87. var desc = PropertyDescriptor.ToPropertyDescriptor(_realm, attributes);
  88. return target.DefineOwnProperty(key, desc);
  89. }
  90. private JsValue DeleteProperty(JsValue thisObject, JsValue[] arguments)
  91. {
  92. var o = arguments.At(0) as ObjectInstance;
  93. if (o is null)
  94. {
  95. ExceptionHelper.ThrowTypeError(_realm, "Reflect.deleteProperty called on non-object");
  96. }
  97. var property = TypeConverter.ToPropertyKey(arguments.At(1));
  98. return o.Delete(property) ? JsBoolean.True : JsBoolean.False;
  99. }
  100. private JsValue Has(JsValue thisObject, JsValue[] arguments)
  101. {
  102. var o = arguments.At(0) as ObjectInstance;
  103. if (o is null)
  104. {
  105. ExceptionHelper.ThrowTypeError(_realm, "Reflect.has called on non-object");
  106. }
  107. var property = TypeConverter.ToPropertyKey(arguments.At(1));
  108. return o.HasProperty(property) ? JsBoolean.True : JsBoolean.False;
  109. }
  110. private JsValue Set(JsValue thisObject, JsValue[] arguments)
  111. {
  112. var target = arguments.At(0);
  113. var property = TypeConverter.ToPropertyKey(arguments.At(1));
  114. var value = arguments.At(2);
  115. var receiver = arguments.At(3, target);
  116. var o = target as ObjectInstance;
  117. if (o is null)
  118. {
  119. ExceptionHelper.ThrowTypeError(_realm, "Reflect.set called on non-object");
  120. }
  121. return o.Set(property, value, receiver);
  122. }
  123. private JsValue Get(JsValue thisObject, JsValue[] arguments)
  124. {
  125. var target = arguments.At(0);
  126. var o = target as ObjectInstance;
  127. if (o is null)
  128. {
  129. ExceptionHelper.ThrowTypeError(_realm, "Reflect.get called on non-object");
  130. }
  131. var receiver = arguments.At(2, target);
  132. var property = TypeConverter.ToPropertyKey(arguments.At(1));
  133. return o.Get(property, receiver);
  134. }
  135. private JsValue GetOwnPropertyDescriptor(JsValue thisObject, JsValue[] arguments)
  136. {
  137. if (!arguments.At(0).IsObject())
  138. {
  139. ExceptionHelper.ThrowTypeError(_realm, "Reflect.getOwnPropertyDescriptor called on non-object");
  140. }
  141. return _realm.Intrinsics.Object.GetOwnPropertyDescriptor(Undefined, arguments);
  142. }
  143. private JsValue OwnKeys(JsValue thisObject, JsValue[] arguments)
  144. {
  145. var o = arguments.At(0) as ObjectInstance;
  146. if (o is null)
  147. {
  148. ExceptionHelper.ThrowTypeError(_realm, "Reflect.get called on non-object");
  149. }
  150. var keys = o.GetOwnPropertyKeys();
  151. return _realm.Intrinsics.Array.CreateArrayFromList(keys);
  152. }
  153. private JsValue IsExtensible(JsValue thisObject, JsValue[] arguments)
  154. {
  155. var o = arguments.At(0) as ObjectInstance;
  156. if (o is null)
  157. {
  158. ExceptionHelper.ThrowTypeError(_realm, "Reflect.isExtensible called on non-object");
  159. }
  160. return o.Extensible;
  161. }
  162. private JsValue PreventExtensions(JsValue thisObject, JsValue[] arguments)
  163. {
  164. var o = arguments.At(0) as ObjectInstance;
  165. if (o is null)
  166. {
  167. ExceptionHelper.ThrowTypeError(_realm, "Reflect.preventExtensions called on non-object");
  168. }
  169. return o.PreventExtensions();
  170. }
  171. private JsValue GetPrototypeOf(JsValue thisObject, JsValue[] arguments)
  172. {
  173. var target = arguments.At(0);
  174. if (!target.IsObject())
  175. {
  176. ExceptionHelper.ThrowTypeError(_realm, "Reflect.getPrototypeOf called on non-object");
  177. }
  178. return _realm.Intrinsics.Object.GetPrototypeOf(Undefined, arguments);
  179. }
  180. private JsValue SetPrototypeOf(JsValue thisObject, JsValue[] arguments)
  181. {
  182. var target = arguments.At(0);
  183. var o = target as ObjectInstance;
  184. if (o is null)
  185. {
  186. ExceptionHelper.ThrowTypeError(_realm, "Reflect.setPrototypeOf called on non-object");
  187. }
  188. var prototype = arguments.At(1);
  189. if (!prototype.IsObject() && !prototype.IsNull())
  190. {
  191. ExceptionHelper.ThrowTypeError(_realm, $"Object prototype may only be an Object or null: {prototype}");
  192. }
  193. return o.SetPrototypeOf(prototype);
  194. }
  195. }
  196. }