ProxyObject.cpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. /*
  2. * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
  3. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibJS/Runtime/AbstractOperations.h>
  8. #include <LibJS/Runtime/Accessor.h>
  9. #include <LibJS/Runtime/Array.h>
  10. #include <LibJS/Runtime/Error.h>
  11. #include <LibJS/Runtime/GlobalObject.h>
  12. #include <LibJS/Runtime/PropertyDescriptor.h>
  13. #include <LibJS/Runtime/ProxyObject.h>
  14. namespace JS {
  15. ProxyObject* ProxyObject::create(GlobalObject& global_object, Object& target, Object& handler)
  16. {
  17. return global_object.heap().allocate<ProxyObject>(global_object, target, handler, *global_object.object_prototype());
  18. }
  19. ProxyObject::ProxyObject(Object& target, Object& handler, Object& prototype)
  20. : FunctionObject(prototype)
  21. , m_target(target)
  22. , m_handler(handler)
  23. {
  24. }
  25. ProxyObject::~ProxyObject()
  26. {
  27. }
  28. static Value property_name_to_value(VM& vm, PropertyName const& name)
  29. {
  30. VERIFY(name.is_valid());
  31. if (name.is_symbol())
  32. return name.as_symbol();
  33. if (name.is_string())
  34. return js_string(vm, name.as_string());
  35. VERIFY(name.is_number());
  36. return js_string(vm, String::number(name.as_number()));
  37. }
  38. // 10.5.1 [[GetPrototypeOf]] ( ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-getprototypeof
  39. Object* ProxyObject::internal_get_prototype_of() const
  40. {
  41. auto& vm = this->vm();
  42. auto& global_object = this->global_object();
  43. // 1. Let handler be O.[[ProxyHandler]].
  44. // 2. If handler is null, throw a TypeError exception.
  45. if (m_is_revoked) {
  46. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  47. return {};
  48. }
  49. // 3. Assert: Type(handler) is Object.
  50. // 4. Let target be O.[[ProxyTarget]].
  51. // 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
  52. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.getPrototypeOf));
  53. // 6. If trap is undefined, then
  54. if (!trap) {
  55. // a. Return ? target.[[GetPrototypeOf]]().
  56. return m_target.internal_get_prototype_of();
  57. }
  58. // 7. Let handlerProto be ? Call(trap, handler, « target »).
  59. auto handler_proto = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target));
  60. // 8. If Type(handlerProto) is neither Object nor Null, throw a TypeError exception.
  61. if (!handler_proto.is_object() && !handler_proto.is_null()) {
  62. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetPrototypeOfReturn);
  63. return {};
  64. }
  65. // 9. Let extensibleTarget be ? IsExtensible(target).
  66. auto extensible_target = m_target.is_extensible();
  67. if (vm.exception())
  68. return {};
  69. // 10. If extensibleTarget is true, return handlerProto.
  70. if (extensible_target)
  71. return handler_proto.is_null() ? nullptr : &handler_proto.as_object();
  72. // 11. Let targetProto be ? target.[[GetPrototypeOf]]().
  73. auto target_proto = m_target.internal_get_prototype_of();
  74. if (vm.exception())
  75. return {};
  76. // 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception.
  77. if (!same_value(handler_proto, target_proto)) {
  78. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetPrototypeOfNonExtensible);
  79. return {};
  80. }
  81. // 13. Return handlerProto.
  82. return handler_proto.is_null() ? nullptr : &handler_proto.as_object();
  83. }
  84. // 10.5.2 [[SetPrototypeOf]] ( V ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-setprototypeof-v
  85. bool ProxyObject::internal_set_prototype_of(Object* prototype)
  86. {
  87. auto& vm = this->vm();
  88. auto& global_object = this->global_object();
  89. // 1. Assert: Either Type(V) is Object or Type(V) is Null.
  90. // 2. Let handler be O.[[ProxyHandler]].
  91. // 3. If handler is null, throw a TypeError exception.
  92. if (m_is_revoked) {
  93. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  94. return {};
  95. }
  96. // 4. Assert: Type(handler) is Object.
  97. // 5. Let target be O.[[ProxyTarget]].
  98. // 6. Let trap be ? GetMethod(handler, "setPrototypeOf").
  99. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.setPrototypeOf));
  100. // 7. If trap is undefined, then
  101. if (!trap) {
  102. // a. Return ? target.[[SetPrototypeOf]](V).
  103. return m_target.internal_set_prototype_of(prototype);
  104. }
  105. // 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, V »)).
  106. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, prototype)).to_boolean();
  107. // 9. If booleanTrapResult is false, return false.
  108. if (!trap_result)
  109. return false;
  110. // 10. Let extensibleTarget be ? IsExtensible(target).
  111. auto extensible_target = m_target.is_extensible();
  112. if (vm.exception())
  113. return {};
  114. // 11. If extensibleTarget is true, return true.
  115. if (extensible_target)
  116. return true;
  117. // 12. Let targetProto be ? target.[[GetPrototypeOf]]().
  118. auto* target_proto = m_target.internal_get_prototype_of();
  119. if (vm.exception())
  120. return {};
  121. // 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
  122. if (!same_value(prototype, target_proto)) {
  123. vm.throw_exception<TypeError>(global_object, ErrorType::ProxySetPrototypeOfNonExtensible);
  124. return {};
  125. }
  126. // 14. Return true.
  127. return true;
  128. }
  129. // 10.5.3 [[IsExtensible]] ( ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible
  130. bool ProxyObject::internal_is_extensible() const
  131. {
  132. auto& vm = this->vm();
  133. auto& global_object = this->global_object();
  134. // 1. Let handler be O.[[ProxyHandler]].
  135. // 2. If handler is null, throw a TypeError exception.
  136. if (m_is_revoked) {
  137. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  138. return {};
  139. }
  140. // 3. Assert: Type(handler) is Object.
  141. // 4. Let target be O.[[ProxyTarget]].
  142. // 5. Let trap be ? GetMethod(handler, "isExtensible").
  143. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.isExtensible));
  144. // 6. If trap is undefined, then
  145. if (!trap) {
  146. // a. Return ? IsExtensible(target).
  147. return m_target.is_extensible();
  148. }
  149. // 7. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target »)).
  150. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target)).to_boolean();
  151. // 8. Let targetResult be ? IsExtensible(target).
  152. auto target_result = m_target.is_extensible();
  153. if (vm.exception())
  154. return {};
  155. // 9. If SameValue(booleanTrapResult, targetResult) is false, throw a TypeError exception.
  156. if (trap_result != target_result) {
  157. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyIsExtensibleReturn);
  158. return {};
  159. }
  160. // 10. Return booleanTrapResult.
  161. return trap_result;
  162. }
  163. // 10.5.4 [[PreventExtensions]] ( ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions
  164. bool ProxyObject::internal_prevent_extensions()
  165. {
  166. auto& vm = this->vm();
  167. auto& global_object = this->global_object();
  168. // 1. Let handler be O.[[ProxyHandler]].
  169. // 2. If handler is null, throw a TypeError exception.
  170. if (m_is_revoked) {
  171. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  172. return {};
  173. }
  174. // 3. Assert: Type(handler) is Object.
  175. // 4. Let target be O.[[ProxyTarget]].
  176. // 5. Let trap be ? GetMethod(handler, "preventExtensions").
  177. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.preventExtensions));
  178. // 6. If trap is undefined, then
  179. if (!trap) {
  180. // a. Return ? target.[[PreventExtensions]]().
  181. return m_target.internal_prevent_extensions();
  182. }
  183. // 7. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target »)).
  184. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target)).to_boolean();
  185. // 8. If booleanTrapResult is true, then
  186. if (trap_result) {
  187. // a. Let extensibleTarget be ? IsExtensible(target).
  188. auto extensible_target = m_target.is_extensible();
  189. if (vm.exception())
  190. return {};
  191. // b. If extensibleTarget is true, throw a TypeError exception.
  192. if (extensible_target) {
  193. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyPreventExtensionsReturn);
  194. return {};
  195. }
  196. }
  197. // 9. Return booleanTrapResult.
  198. return trap_result;
  199. }
  200. // 10.5.5 [[GetOwnProperty]] ( P ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-getownproperty-p
  201. Optional<PropertyDescriptor> ProxyObject::internal_get_own_property(const PropertyName& property_name) const
  202. {
  203. auto& vm = this->vm();
  204. auto& global_object = this->global_object();
  205. // 1. Assert: IsPropertyKey(P) is true.
  206. VERIFY(property_name.is_valid());
  207. // 2. Let handler be O.[[ProxyHandler]].
  208. // 3. If handler is null, throw a TypeError exception.
  209. if (m_is_revoked) {
  210. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  211. return {};
  212. }
  213. // 4. Assert: Type(handler) is Object.
  214. // 5. Let target be O.[[ProxyTarget]].
  215. // 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
  216. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.getOwnPropertyDescriptor));
  217. // 7. If trap is undefined, then
  218. if (!trap) {
  219. // a. Return ? target.[[GetOwnProperty]](P).
  220. return m_target.internal_get_own_property(property_name);
  221. }
  222. // 8. Let trapResultObj be ? Call(trap, handler, « target, P »).
  223. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, property_name_to_value(vm, property_name)));
  224. // 9. If Type(trapResultObj) is neither Object nor Undefined, throw a TypeError exception.
  225. if (!trap_result.is_object() && !trap_result.is_undefined()) {
  226. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetOwnDescriptorReturn);
  227. return {};
  228. }
  229. // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
  230. auto target_descriptor = m_target.internal_get_own_property(property_name);
  231. if (vm.exception())
  232. return {};
  233. // 11. If trapResultObj is undefined, then
  234. if (trap_result.is_undefined()) {
  235. // a. If targetDesc is undefined, return undefined.
  236. if (!target_descriptor.has_value())
  237. return {};
  238. // b. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
  239. if (!*target_descriptor->configurable) {
  240. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetOwnDescriptorNonConfigurable);
  241. return {};
  242. }
  243. // c. Let extensibleTarget be ? IsExtensible(target).
  244. auto extensible_target = m_target.is_extensible();
  245. if (vm.exception())
  246. return {};
  247. // d. If extensibleTarget is false, throw a TypeError exception.
  248. if (!extensible_target) {
  249. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetOwnDescriptorUndefinedReturn);
  250. return {};
  251. }
  252. // e. Return undefined.
  253. return {};
  254. }
  255. // 12. Let extensibleTarget be ? IsExtensible(target).
  256. auto extensible_target = m_target.is_extensible();
  257. if (vm.exception())
  258. return {};
  259. // 13. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
  260. auto result_desc = to_property_descriptor(global_object, trap_result);
  261. if (vm.exception())
  262. return {};
  263. // 14. Call CompletePropertyDescriptor(resultDesc).
  264. result_desc.complete();
  265. // 15. Let valid be IsCompatiblePropertyDescriptor(extensibleTarget, resultDesc, targetDesc).
  266. auto valid = is_compatible_property_descriptor(extensible_target, result_desc, target_descriptor);
  267. // 16. If valid is false, throw a TypeError exception.
  268. if (!valid) {
  269. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetOwnDescriptorInvalidDescriptor);
  270. return {};
  271. }
  272. // 17. If resultDesc.[[Configurable]] is false, then
  273. if (!*result_desc.configurable) {
  274. // a. If targetDesc is undefined or targetDesc.[[Configurable]] is true, then
  275. if (!target_descriptor.has_value() || *target_descriptor->configurable) {
  276. // i. Throw a TypeError exception.
  277. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetOwnDescriptorInvalidNonConfig);
  278. return {};
  279. }
  280. // b. If resultDesc has a [[Writable]] field and resultDesc.[[Writable]] is false, then
  281. if (result_desc.writable.has_value() && !*result_desc.writable) {
  282. // i. If targetDesc.[[Writable]] is true, throw a TypeError exception.
  283. if (*target_descriptor->writable) {
  284. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetOwnDescriptorNonConfigurableNonWritable);
  285. return {};
  286. }
  287. }
  288. }
  289. // 18. Return resultDesc.
  290. return result_desc;
  291. }
  292. // 10.5.6 [[DefineOwnProperty]] ( P, Desc ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-defineownproperty-p-desc
  293. bool ProxyObject::internal_define_own_property(PropertyName const& property_name, PropertyDescriptor const& property_descriptor)
  294. {
  295. auto& vm = this->vm();
  296. auto& global_object = this->global_object();
  297. // 1. Assert: IsPropertyKey(P) is true.
  298. VERIFY(property_name.is_valid());
  299. // 2. Let handler be O.[[ProxyHandler]].
  300. // 3. If handler is null, throw a TypeError exception.
  301. if (m_is_revoked) {
  302. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  303. return {};
  304. }
  305. // 4. Assert: Type(handler) is Object.
  306. // 5. Let target be O.[[ProxyTarget]].
  307. // 6. Let trap be ? GetMethod(handler, "defineProperty").
  308. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.defineProperty));
  309. // 7. If trap is undefined, then
  310. if (!trap) {
  311. // a. Return ? target.[[DefineOwnProperty]](P, Desc).
  312. return m_target.internal_define_own_property(property_name, property_descriptor);
  313. }
  314. // 8. Let descObj be FromPropertyDescriptor(Desc).
  315. auto descriptor_object = from_property_descriptor(global_object, property_descriptor);
  316. // 9. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P, descObj »)).
  317. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, property_name_to_value(vm, property_name), descriptor_object)).to_boolean();
  318. // 10. If booleanTrapResult is false, return false.
  319. if (!trap_result)
  320. return false;
  321. // 11. Let targetDesc be ? target.[[GetOwnProperty]](P).
  322. auto target_descriptor = m_target.internal_get_own_property(property_name);
  323. if (vm.exception())
  324. return {};
  325. // 12. Let extensibleTarget be ? IsExtensible(target).
  326. auto extensible_target = m_target.is_extensible();
  327. if (vm.exception())
  328. return {};
  329. // 14. Else, let settingConfigFalse be false.
  330. bool setting_config_false = false;
  331. // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] is false, then
  332. if (property_descriptor.configurable.has_value() && !*property_descriptor.configurable) {
  333. // a. Let settingConfigFalse be true.
  334. setting_config_false = true;
  335. }
  336. // 15. If targetDesc is undefined, then
  337. if (!target_descriptor.has_value()) {
  338. // a. If extensibleTarget is false, throw a TypeError exception.
  339. if (!extensible_target) {
  340. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyDefinePropNonExtensible);
  341. return {};
  342. }
  343. // b. If settingConfigFalse is true, throw a TypeError exception.
  344. if (setting_config_false) {
  345. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyDefinePropNonConfigurableNonExisting);
  346. return {};
  347. }
  348. }
  349. // 16. Else,
  350. else {
  351. // a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, targetDesc) is false, throw a TypeError exception.
  352. if (!is_compatible_property_descriptor(extensible_target, property_descriptor, target_descriptor)) {
  353. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyDefinePropIncompatibleDescriptor);
  354. return {};
  355. }
  356. // b. If settingConfigFalse is true and targetDesc.[[Configurable]] is true, throw a TypeError exception.
  357. if (setting_config_false && *target_descriptor->configurable) {
  358. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyDefinePropExistingConfigurable);
  359. return {};
  360. }
  361. // c. If IsDataDescriptor(targetDesc) is true, targetDesc.[[Configurable]] is false, and targetDesc.[[Writable]] is true, then
  362. if (target_descriptor->is_data_descriptor() && !*target_descriptor->configurable && *target_descriptor->writable) {
  363. // i. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, throw a TypeError exception.
  364. if (property_descriptor.writable.has_value() && !*property_descriptor.writable) {
  365. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyDefinePropNonWritable);
  366. return {};
  367. }
  368. }
  369. }
  370. // 17. Return true.
  371. return true;
  372. }
  373. // 10.5.7 [[HasProperty]] ( P ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-hasproperty-p
  374. bool ProxyObject::internal_has_property(PropertyName const& property_name) const
  375. {
  376. auto& vm = this->vm();
  377. auto& global_object = this->global_object();
  378. // 1. Assert: IsPropertyKey(P) is true.
  379. VERIFY(property_name.is_valid());
  380. // 2. Let handler be O.[[ProxyHandler]].
  381. // 3. If handler is null, throw a TypeError exception.
  382. if (m_is_revoked) {
  383. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  384. return {};
  385. }
  386. // 4. Assert: Type(handler) is Object.
  387. // 5. Let target be O.[[ProxyTarget]].
  388. // 6. Let trap be ? GetMethod(handler, "has").
  389. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.has));
  390. // 7. If trap is undefined, then
  391. if (!trap) {
  392. // a. Return ? target.[[HasProperty]](P).
  393. return m_target.internal_has_property(property_name);
  394. }
  395. // 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P »)).
  396. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, property_name_to_value(vm, property_name))).to_boolean();
  397. // 9. If booleanTrapResult is false, then
  398. if (!trap_result) {
  399. // a. Let targetDesc be ? target.[[GetOwnProperty]](P).
  400. auto target_descriptor = m_target.internal_get_own_property(property_name);
  401. if (vm.exception())
  402. return {};
  403. // b. If targetDesc is not undefined, then
  404. if (target_descriptor.has_value()) {
  405. // i. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
  406. if (!*target_descriptor->configurable) {
  407. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyHasExistingNonConfigurable);
  408. return {};
  409. }
  410. // ii. Let extensibleTarget be ? IsExtensible(target).
  411. auto extensible_target = m_target.is_extensible();
  412. if (vm.exception())
  413. return {};
  414. // iii. If extensibleTarget is false, throw a TypeError exception.
  415. if (!extensible_target) {
  416. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyHasExistingNonExtensible);
  417. return false;
  418. }
  419. }
  420. }
  421. // 10. Return booleanTrapResult.
  422. return trap_result;
  423. }
  424. // 10.5.8 [[Get]] ( P, Receiver ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
  425. Value ProxyObject::internal_get(PropertyName const& property_name, Value receiver) const
  426. {
  427. VERIFY(!receiver.is_empty());
  428. auto& vm = this->vm();
  429. auto& global_object = this->global_object();
  430. // 1. Assert: IsPropertyKey(P) is true.
  431. VERIFY(property_name.is_valid());
  432. // 2. Let handler be O.[[ProxyHandler]].
  433. // 3. If handler is null, throw a TypeError exception.
  434. if (m_is_revoked) {
  435. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  436. return {};
  437. }
  438. // 4. Assert: Type(handler) is Object.
  439. // 5. Let target be O.[[ProxyTarget]].
  440. // NOTE: We need to protect ourselves from a Proxy with the handler's prototype set to the
  441. // Proxy itself, which would by default bounce between these functions indefinitely and lead to
  442. // a stack overflow when the Proxy's (p) or Proxy handler's (h) Object::get() is called and the
  443. // handler doesn't have a `get` trap:
  444. //
  445. // 1. p -> ProxyObject::internal_get() <- you are here
  446. // 2. h -> Value::get_method()
  447. // 3. h -> Value::get()
  448. // 4. h -> Object::internal_get()
  449. // 5. h -> Object::internal_get_prototype_of() (result is p)
  450. // 6. goto 1
  451. //
  452. // In JS code: `h = {}; p = new Proxy({}, h); h.__proto__ = p; p.foo // or h.foo`
  453. if (vm.did_reach_stack_space_limit()) {
  454. vm.throw_exception<Error>(global_object, ErrorType::CallStackSizeExceeded);
  455. return {};
  456. }
  457. // 6. Let trap be ? GetMethod(handler, "get").
  458. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.get));
  459. // 7. If trap is undefined, then
  460. if (!trap) {
  461. // a. Return ? target.[[Get]](P, Receiver).
  462. return m_target.internal_get(property_name, receiver);
  463. }
  464. // 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
  465. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, property_name_to_value(vm, property_name), receiver));
  466. // 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
  467. auto target_descriptor = m_target.internal_get_own_property(property_name);
  468. if (vm.exception())
  469. return {};
  470. // 10. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then
  471. if (target_descriptor.has_value() && !*target_descriptor->configurable) {
  472. // a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then
  473. if (target_descriptor->is_data_descriptor() && !*target_descriptor->writable) {
  474. // i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception.
  475. if (!same_value(trap_result, *target_descriptor->value)) {
  476. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetImmutableDataProperty);
  477. return {};
  478. }
  479. }
  480. // b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Get]] is undefined, then
  481. if (target_descriptor->is_accessor_descriptor() && !*target_descriptor->get) {
  482. // i. If trapResult is not undefined, throw a TypeError exception.
  483. if (!trap_result.is_undefined()) {
  484. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyGetNonConfigurableAccessor);
  485. return {};
  486. }
  487. }
  488. }
  489. // 11. Return trapResult.
  490. return trap_result;
  491. }
  492. // 10.5.9 [[Set]] ( P, V, Receiver ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver
  493. bool ProxyObject::internal_set(PropertyName const& property_name, Value value, Value receiver)
  494. {
  495. VERIFY(!value.is_empty());
  496. VERIFY(!receiver.is_empty());
  497. auto& vm = this->vm();
  498. auto& global_object = this->global_object();
  499. // 1. Assert: IsPropertyKey(P) is true.
  500. VERIFY(property_name.is_valid());
  501. // 2. Let handler be O.[[ProxyHandler]].
  502. // 3. If handler is null, throw a TypeError exception.
  503. if (m_is_revoked) {
  504. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  505. return {};
  506. }
  507. // 4. Assert: Type(handler) is Object.
  508. // 5. Let target be O.[[ProxyTarget]].
  509. // 6. Let trap be ? GetMethod(handler, "set").
  510. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.set));
  511. // 7. If trap is undefined, then
  512. if (!trap) {
  513. // a. Return ? target.[[Set]](P, V, Receiver).
  514. return m_target.internal_set(property_name, value, receiver);
  515. }
  516. // 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P, V, Receiver »)).
  517. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, property_name_to_value(vm, property_name), value, receiver)).to_boolean();
  518. // 9. If booleanTrapResult is false, return false.
  519. if (!trap_result)
  520. return false;
  521. // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
  522. auto target_descriptor = m_target.internal_get_own_property(property_name);
  523. if (vm.exception())
  524. return {};
  525. // 11. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then
  526. if (target_descriptor.has_value() && !*target_descriptor->configurable) {
  527. // a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then
  528. if (target_descriptor->is_data_descriptor() && !*target_descriptor->writable) {
  529. // i. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception.
  530. if (!same_value(value, *target_descriptor->value)) {
  531. vm.throw_exception<TypeError>(global_object, ErrorType::ProxySetImmutableDataProperty);
  532. return {};
  533. }
  534. }
  535. // b. If IsAccessorDescriptor(targetDesc) is true, then
  536. if (target_descriptor->is_accessor_descriptor()) {
  537. // i. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
  538. if (!*target_descriptor->set) {
  539. vm.throw_exception<TypeError>(global_object, ErrorType::ProxySetNonConfigurableAccessor);
  540. return {};
  541. }
  542. }
  543. }
  544. // 12. Return true.
  545. return true;
  546. }
  547. // 10.5.10 [[Delete]] ( P ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-delete-p
  548. bool ProxyObject::internal_delete(PropertyName const& property_name)
  549. {
  550. auto& vm = this->vm();
  551. auto& global_object = this->global_object();
  552. // 1. Assert: IsPropertyKey(P) is true.
  553. VERIFY(property_name.is_valid());
  554. // 2. Let handler be O.[[ProxyHandler]].
  555. // 3. If handler is null, throw a TypeError exception.
  556. if (m_is_revoked) {
  557. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  558. return {};
  559. }
  560. // 4. Assert: Type(handler) is Object.
  561. // 5. Let target be O.[[ProxyTarget]].
  562. // 6. Let trap be ? GetMethod(handler, "deleteProperty").
  563. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.deleteProperty));
  564. // 7. If trap is undefined, then
  565. if (!trap) {
  566. // a. Return ? target.[[Delete]](P).
  567. return m_target.internal_delete(property_name);
  568. }
  569. // 8. Let booleanTrapResult be ! ToBoolean(? Call(trap, handler, « target, P »)).
  570. auto trap_result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, property_name_to_value(vm, property_name))).to_boolean();
  571. // 9. If booleanTrapResult is false, return false.
  572. if (!trap_result)
  573. return false;
  574. // 10. Let targetDesc be ? target.[[GetOwnProperty]](P).
  575. auto target_descriptor = m_target.internal_get_own_property(property_name);
  576. if (vm.exception())
  577. return {};
  578. // 11. If targetDesc is undefined, return true.
  579. if (!target_descriptor.has_value())
  580. return true;
  581. // 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
  582. if (!*target_descriptor->configurable) {
  583. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyDeleteNonConfigurable);
  584. return {};
  585. }
  586. // 13. Let extensibleTarget be ? IsExtensible(target).
  587. auto extensible_target = m_target.is_extensible();
  588. if (vm.exception())
  589. return {};
  590. // 14. If extensibleTarget is false, throw a TypeError exception.
  591. if (!extensible_target) {
  592. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyDeleteNonExtensible);
  593. return {};
  594. }
  595. // 15. Return true.
  596. return true;
  597. }
  598. // 10.5.11 [[OwnPropertyKeys]] ( ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
  599. MarkedValueList ProxyObject::internal_own_property_keys() const
  600. {
  601. auto& vm = this->vm();
  602. auto& global_object = this->global_object();
  603. // 1. Let handler be O.[[ProxyHandler]].
  604. // 2. If handler is null, throw a TypeError exception.
  605. if (m_is_revoked) {
  606. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  607. return MarkedValueList { heap() };
  608. }
  609. // 3. Assert: Type(handler) is Object.
  610. // 4. Let target be O.[[ProxyTarget]].
  611. // 5. Let trap be ? GetMethod(handler, "ownKeys").
  612. auto trap_or_error = Value(&m_handler).get_method(global_object, vm.names.ownKeys);
  613. if (trap_or_error.is_error())
  614. return MarkedValueList { heap() };
  615. auto trap = trap_or_error.release_value();
  616. // 6. If trap is undefined, then
  617. if (!trap) {
  618. // a. Return ? target.[[OwnPropertyKeys]]().
  619. return m_target.internal_own_property_keys();
  620. }
  621. // 7. Let trapResultArray be ? Call(trap, handler, « target »).
  622. auto trap_result_array_or_error = vm.call(*trap, &m_handler, &m_target);
  623. if (trap_result_array_or_error.is_error())
  624. return MarkedValueList { heap() };
  625. auto trap_result_array = trap_result_array_or_error.release_value();
  626. // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, « String, Symbol »).
  627. HashTable<StringOrSymbol> unique_keys;
  628. auto throw_completion_or_trap_result = create_list_from_array_like(global_object, trap_result_array, [&](auto value) -> ThrowCompletionOr<void> {
  629. auto& vm = global_object.vm();
  630. if (!value.is_string() && !value.is_symbol())
  631. return vm.throw_completion<TypeError>(global_object, ErrorType::ProxyOwnPropertyKeysNotStringOrSymbol);
  632. auto property_key = value.to_property_key(global_object);
  633. VERIFY(!vm.exception());
  634. unique_keys.set(property_key, AK::HashSetExistingEntryBehavior::Keep);
  635. return {};
  636. });
  637. // TODO: This becomes a lot nicer once this function returns a ThrowCompletionOr as well.
  638. if (throw_completion_or_trap_result.is_throw_completion())
  639. return MarkedValueList { heap() };
  640. auto trap_result = throw_completion_or_trap_result.release_value();
  641. // 9. If trapResult contains any duplicate entries, throw a TypeError exception.
  642. if (unique_keys.size() != trap_result.size()) {
  643. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyOwnPropertyKeysDuplicates);
  644. return MarkedValueList { heap() };
  645. }
  646. // 10. Let extensibleTarget be ? IsExtensible(target).
  647. auto extensible_target = m_target.is_extensible();
  648. if (vm.exception())
  649. return MarkedValueList { heap() };
  650. // 11. Let targetKeys be ? target.[[OwnPropertyKeys]]().
  651. auto target_keys = m_target.internal_own_property_keys();
  652. if (vm.exception())
  653. return MarkedValueList { heap() };
  654. // 12. Assert: targetKeys is a List whose elements are only String and Symbol values.
  655. // 13. Assert: targetKeys contains no duplicate entries.
  656. // 14. Let targetConfigurableKeys be a new empty List.
  657. auto target_configurable_keys = MarkedValueList { heap() };
  658. // 15. Let targetNonconfigurableKeys be a new empty List.
  659. auto target_nonconfigurable_keys = MarkedValueList { heap() };
  660. // 16. For each element key of targetKeys, do
  661. for (auto& key : target_keys) {
  662. // a. Let desc be ? target.[[GetOwnProperty]](key).
  663. auto descriptor = m_target.internal_get_own_property(PropertyName::from_value(global_object, key));
  664. // b. If desc is not undefined and desc.[[Configurable]] is false, then
  665. if (descriptor.has_value() && !*descriptor->configurable) {
  666. // i. Append key as an element of targetNonconfigurableKeys.
  667. target_nonconfigurable_keys.append(key);
  668. }
  669. // c. Else,
  670. else {
  671. // i. Append key as an element of targetConfigurableKeys.
  672. target_configurable_keys.append(key);
  673. }
  674. }
  675. // 17. If extensibleTarget is true and targetNonconfigurableKeys is empty, then
  676. if (extensible_target && target_nonconfigurable_keys.is_empty()) {
  677. // a. Return trapResult.
  678. return trap_result;
  679. }
  680. // 18. Let uncheckedResultKeys be a List whose elements are the elements of trapResult.
  681. auto unchecked_result_keys = MarkedValueList { heap() };
  682. unchecked_result_keys.extend(trap_result);
  683. // 19. For each element key of targetNonconfigurableKeys, do
  684. for (auto& key : target_nonconfigurable_keys) {
  685. // a. If key is not an element of uncheckedResultKeys, throw a TypeError exception.
  686. if (!unchecked_result_keys.contains_slow(key)) {
  687. vm.throw_exception<TypeError>(global_object, ErrorType::FixmeAddAnErrorString);
  688. return MarkedValueList { heap() };
  689. }
  690. // b. Remove key from uncheckedResultKeys.
  691. unchecked_result_keys.remove_first_matching([&](auto& value) {
  692. return same_value(value, key);
  693. });
  694. }
  695. // 20. If extensibleTarget is true, return trapResult.
  696. if (extensible_target)
  697. return trap_result;
  698. // 21. For each element key of targetConfigurableKeys, do
  699. for (auto& key : target_configurable_keys) {
  700. // a. If key is not an element of uncheckedResultKeys, throw a TypeError exception.
  701. if (!unchecked_result_keys.contains_slow(key)) {
  702. vm.throw_exception<TypeError>(global_object, ErrorType::FixmeAddAnErrorString);
  703. return MarkedValueList { heap() };
  704. }
  705. // b. Remove key from uncheckedResultKeys.
  706. unchecked_result_keys.remove_first_matching([&](auto& value) {
  707. return same_value(value, key);
  708. });
  709. }
  710. // 22. If uncheckedResultKeys is not empty, throw a TypeError exception.
  711. if (!unchecked_result_keys.is_empty()) {
  712. vm.throw_exception<TypeError>(global_object, ErrorType::FixmeAddAnErrorString);
  713. return MarkedValueList { heap() };
  714. }
  715. // 23. Return trapResult.
  716. return trap_result;
  717. }
  718. // 10.5.12 [[Call]] ( thisArgument, argumentsList ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-call-thisargument-argumentslist
  719. Value ProxyObject::call()
  720. {
  721. auto& vm = this->vm();
  722. auto& global_object = this->global_object();
  723. auto this_argument = vm.this_value(global_object);
  724. // A Proxy exotic object only has a [[Call]] internal method if the initial value of its [[ProxyTarget]] internal slot is an object that has a [[Call]] internal method.
  725. if (!is_function()) {
  726. vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, Value(this).to_string_without_side_effects());
  727. return {};
  728. }
  729. // 1. Let handler be O.[[ProxyHandler]].
  730. // 2. If handler is null, throw a TypeError exception.
  731. if (m_is_revoked) {
  732. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  733. return {};
  734. }
  735. // 3. Assert: Type(handler) is Object.
  736. // 4. Let target be O.[[ProxyTarget]].
  737. // 5. Let trap be ? GetMethod(handler, "apply").
  738. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.apply));
  739. // 6. If trap is undefined, then
  740. if (!trap) {
  741. // a. Return ? Call(target, thisArgument, argumentsList).
  742. return static_cast<FunctionObject&>(m_target).call();
  743. }
  744. // 7. Let argArray be ! CreateArrayFromList(argumentsList).
  745. auto arguments_array = Array::create(global_object, 0);
  746. vm.for_each_argument([&](auto& argument) {
  747. arguments_array->indexed_properties().append(argument);
  748. });
  749. // 8. Return ? Call(trap, handler, « target, thisArgument, argArray »).
  750. return TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, this_argument, arguments_array));
  751. }
  752. // 10.5.13 [[Construct]] ( argumentsList, newTarget ), https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-construct-argumentslist-newtarget
  753. Value ProxyObject::construct(FunctionObject& new_target)
  754. {
  755. auto& vm = this->vm();
  756. auto& global_object = this->global_object();
  757. // A Proxy exotic object only has a [[Construct]] internal method if the initial value of its [[ProxyTarget]] internal slot is an object that has a [[Construct]] internal method.
  758. if (!is_function()) {
  759. vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, Value(this).to_string_without_side_effects());
  760. return {};
  761. }
  762. // 1. Let handler be O.[[ProxyHandler]].
  763. // 2. If handler is null, throw a TypeError exception.
  764. if (m_is_revoked) {
  765. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  766. return {};
  767. }
  768. // 3. Assert: Type(handler) is Object.
  769. // 4. Let target be O.[[ProxyTarget]].
  770. // 5. Assert: IsConstructor(target) is true.
  771. // 6. Let trap be ? GetMethod(handler, "construct").
  772. auto trap = TRY_OR_DISCARD(Value(&m_handler).get_method(global_object, vm.names.construct));
  773. // 7. If trap is undefined, then
  774. if (!trap) {
  775. // a. Return ? Construct(target, argumentsList, newTarget).
  776. return static_cast<FunctionObject&>(m_target).construct(new_target);
  777. }
  778. // 8. Let argArray be ! CreateArrayFromList(argumentsList).
  779. auto arguments_array = Array::create(global_object, 0);
  780. vm.for_each_argument([&](auto& argument) {
  781. arguments_array->indexed_properties().append(argument);
  782. });
  783. // 9. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »).
  784. auto result = TRY_OR_DISCARD(vm.call(*trap, &m_handler, &m_target, arguments_array, &new_target));
  785. // 10. If Type(newObj) is not Object, throw a TypeError exception.
  786. if (!result.is_object()) {
  787. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyConstructBadReturnType);
  788. return {};
  789. }
  790. // 11. Return newObj.
  791. return result;
  792. }
  793. void ProxyObject::visit_edges(Cell::Visitor& visitor)
  794. {
  795. Base::visit_edges(visitor);
  796. visitor.visit(&m_target);
  797. visitor.visit(&m_handler);
  798. }
  799. const FlyString& ProxyObject::name() const
  800. {
  801. VERIFY(is_function());
  802. return static_cast<FunctionObject&>(m_target).name();
  803. }
  804. FunctionEnvironment* ProxyObject::create_environment(FunctionObject& function_being_invoked)
  805. {
  806. VERIFY(is_function());
  807. return static_cast<FunctionObject&>(m_target).create_environment(function_being_invoked);
  808. }
  809. }