ProxyObject.cpp 36 KB

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