1 /* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecma-alloc.h"
17 #include "ecma-array-object.h"
18 #include "ecma-builtins.h"
19 #include "ecma-builtin-object.h"
20 #include "ecma-exceptions.h"
21 #include "ecma-function-object.h"
22 #include "ecma-gc.h"
23 #include "ecma-globals.h"
24 #include "ecma-helpers.h"
25 #include "ecma-objects.h"
26 #include "ecma-objects-general.h"
27 #include "ecma-proxy-object.h"
28 #include "jcontext.h"
29
30 /** \addtogroup ecma ECMA
31 * @{
32 *
33 * \addtogroup ecmaproxyobject ECMA Proxy object related routines
34 * @{
35 */
36
37 #if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
38 /**
39 * Check whether the argument satifies the requrements of [[ProxyTarget]] or [[ProxyHandler]]
40 *
41 * See also:
42 * ES2015 9.5.15.1-2
43 * ES2015 9.5.15.3-4
44 *
45 * @return true - if the arguments can be a valid [[ProxyTarget]] or [[ProxyHandler]]
46 * false - otherwise
47 */
48 static bool
ecma_proxy_validate(ecma_value_t argument)49 ecma_proxy_validate (ecma_value_t argument) /**< argument to validate */
50 {
51 if (ecma_is_value_object (argument))
52 {
53 ecma_object_t *obj_p = ecma_get_object_from_value (argument);
54
55 return (!ECMA_OBJECT_IS_PROXY (obj_p)
56 || !ecma_is_value_null (((ecma_proxy_object_t *) obj_p)->handler));
57 }
58
59 return false;
60 } /* ecma_proxy_validate */
61
62 /**
63 * ProxyCreate operation for create a new proxy object
64 *
65 * See also:
66 * ES2015 9.5.15
67 *
68 * @return created Proxy object as an ecma-value - if success
69 * raised error - otherwise
70 */
71 ecma_object_t *
ecma_proxy_create(ecma_value_t target,ecma_value_t handler)72 ecma_proxy_create (ecma_value_t target, /**< proxy target */
73 ecma_value_t handler) /**< proxy handler */
74 {
75 /* 1 - 4. */
76 if (!ecma_proxy_validate (target) || !ecma_proxy_validate (handler))
77 {
78 ecma_raise_type_error (ECMA_ERR_MSG ("Cannot create proxy with a non-object target or handler"));
79 return NULL;
80 }
81
82 /* 5 - 6. */
83 ecma_object_t *obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE),
84 sizeof (ecma_proxy_object_t),
85 ECMA_OBJECT_TYPE_PROXY);
86
87 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
88
89 /* 8. */
90 proxy_obj_p->target = target;
91 /* 9. */
92 proxy_obj_p->handler = handler;
93
94 /* 10. */
95 return obj_p;
96 } /* ecma_proxy_create */
97
98 /**
99 * Definition of Proxy Revocation Function
100 *
101 * See also:
102 * ES2015 26.2.2.1.1
103 *
104 * @return ECMA_VALUE_UNDEFINED
105 */
106 ecma_value_t
ecma_proxy_revoke_cb(const ecma_value_t function_obj,const ecma_value_t this_val,const ecma_value_t args_p[],const ecma_length_t args_count)107 ecma_proxy_revoke_cb (const ecma_value_t function_obj, /**< the function itself */
108 const ecma_value_t this_val, /**< this_arg of the function */
109 const ecma_value_t args_p[], /**< argument list */
110 const ecma_length_t args_count) /**< argument number */
111 {
112 JERRY_UNUSED_3 (this_val, args_p, args_count);
113
114 ecma_object_t *func_obj_p = ecma_get_object_from_value (function_obj);
115
116 /* 1. */
117 ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) func_obj_p;
118
119 /* 2. */
120 if (ecma_is_value_null (rev_proxy_p->proxy))
121 {
122 return ECMA_VALUE_UNDEFINED;
123 }
124
125 /* 4. */
126 ecma_proxy_object_t *proxy_p = (ecma_proxy_object_t *) ecma_get_object_from_value (rev_proxy_p->proxy);
127 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY ((ecma_object_t *) proxy_p));
128
129 /* 3. */
130 rev_proxy_p->proxy = ECMA_VALUE_NULL;
131
132 /* 5. */
133 proxy_p->target = ECMA_VALUE_NULL;
134
135 /* 6. */
136 proxy_p->handler = ECMA_VALUE_NULL;
137
138 /* 7. */
139 return ECMA_VALUE_UNDEFINED;
140 } /* ecma_proxy_revoke_cb */
141
142 /**
143 * Proxy.revocable operation for create a new revocable proxy object
144 *
145 * See also:
146 * ES2015 26.2.2.1
147 *
148 * @return NULL - if the operation fails
149 * pointer to the newly created revocable proxy object - otherwise
150 */
151 ecma_object_t *
ecma_proxy_create_revocable(ecma_value_t target,ecma_value_t handler)152 ecma_proxy_create_revocable (ecma_value_t target, /**< target argument */
153 ecma_value_t handler) /**< handler argument */
154 {
155 /* 1. */
156 ecma_object_t *proxy_p = ecma_proxy_create (target, handler);
157
158 /* 2. */
159 if (proxy_p == NULL)
160 {
161 return proxy_p;
162 }
163
164 ecma_value_t proxy_value = ecma_make_object_value (proxy_p);
165
166 /* 3. */
167 ecma_object_t *func_obj_p;
168 func_obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE),
169 sizeof (ecma_revocable_proxy_object_t),
170 ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION);
171
172 ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) func_obj_p;
173 rev_proxy_p->header.u.external_handler_cb = ecma_proxy_revoke_cb;
174 /* 4. */
175 rev_proxy_p->proxy = proxy_value;
176
177 ecma_property_value_t *prop_value_p;
178 ecma_value_t revoker = ecma_make_object_value (func_obj_p);
179
180 /* 5. */
181 ecma_object_t *obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE),
182 0,
183 ECMA_OBJECT_TYPE_GENERAL);
184
185 /* 6. */
186 prop_value_p = ecma_create_named_data_property (obj_p,
187 ecma_get_magic_string (LIT_MAGIC_STRING_PROXY),
188 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
189 NULL);
190 prop_value_p->value = proxy_value;
191
192 /* 7. */
193 prop_value_p = ecma_create_named_data_property (obj_p,
194 ecma_get_magic_string (LIT_MAGIC_STRING_REVOKE),
195 ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
196 NULL);
197 prop_value_p->value = revoker;
198
199 ecma_deref_object (proxy_p);
200 ecma_deref_object (func_obj_p);
201
202 /* 8. */
203 return obj_p;
204 } /* ecma_proxy_create_revocable */
205
206 /**
207 * Internal find property operation for Proxy object
208 *
209 * Note: Returned value must be freed with ecma_free_value.
210 *
211 * @return ECMA_VALUE_ERROR - if the operation fails
212 * ECMA_VALUE_NOT_FOUND - if the property is not found
213 * value of the property - otherwise
214 */
215 ecma_value_t
ecma_proxy_object_find(ecma_object_t * obj_p,ecma_string_t * prop_name_p)216 ecma_proxy_object_find (ecma_object_t *obj_p, /**< proxy object */
217 ecma_string_t *prop_name_p) /**< property name */
218 {
219 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
220
221 ecma_value_t has_result = ecma_proxy_object_has (obj_p, prop_name_p);
222
223 if (ECMA_IS_VALUE_ERROR (has_result))
224 {
225 return has_result;
226 }
227
228 if (ecma_is_value_false (has_result))
229 {
230 return ECMA_VALUE_NOT_FOUND;
231 }
232
233 return ecma_proxy_object_get (obj_p, prop_name_p, ecma_make_object_value (obj_p));
234 } /* ecma_proxy_object_find */
235
236 /**
237 * Convert the result of the ecma_proxy_object_get_prototype_of to compressed pointer
238 *
239 * Note: if `proto` is non-null, the reference from the object is released
240 *
241 * @return compressed pointer to the `proto` value
242 */
243 jmem_cpointer_t
ecma_proxy_object_prototype_to_cp(ecma_value_t proto)244 ecma_proxy_object_prototype_to_cp (ecma_value_t proto) /**< ECMA_VALUE_NULL or object */
245 {
246 JERRY_ASSERT (ecma_is_value_null (proto) || ecma_is_value_object (proto));
247
248 if (ecma_is_value_null (proto))
249 {
250 return JMEM_CP_NULL;
251 }
252
253 jmem_cpointer_t proto_cp;
254 ecma_object_t *proto_obj_p = ecma_get_object_from_value (proto);
255 ECMA_SET_POINTER (proto_cp, proto_obj_p);
256 ecma_deref_object (proto_obj_p);
257
258 return proto_cp;
259 } /* ecma_proxy_object_prototype_to_cp */
260
261 /**
262 * Helper method for validate the proxy object
263 *
264 * @return proxy trap - if the validation is successful
265 * ECMA_VALUE_ERROR - otherwise
266 */
267 static ecma_value_t
ecma_validate_proxy_object(ecma_value_t handler,lit_magic_string_id_t magic_id)268 ecma_validate_proxy_object (ecma_value_t handler, /**< proxy handler */
269 lit_magic_string_id_t magic_id) /**< routine magic id */
270 {
271 if (ecma_is_value_null (handler))
272 {
273 return ecma_raise_type_error (ECMA_ERR_MSG ("Handler can not be null"));
274 }
275
276 JERRY_ASSERT (ecma_is_value_object (handler));
277
278 return ecma_op_get_method_by_magic_id (handler, magic_id);
279 } /* ecma_validate_proxy_object */
280
281 /* Interal operations */
282
283 /**
284 * The Proxy object [[GetPrototypeOf]] internal routine
285 *
286 * See also:
287 * ECMAScript v6, 9.5.1
288 *
289 * @return ECMA_VALUE_ERROR - if the operation fails
290 * ECMA_VALUE_NULL or valid object (prototype) otherwise
291 */
292 ecma_value_t
ecma_proxy_object_get_prototype_of(ecma_object_t * obj_p)293 ecma_proxy_object_get_prototype_of (ecma_object_t *obj_p) /**< proxy object */
294 {
295 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
296
297 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
298
299 /* 1. */
300 ecma_value_t handler = proxy_obj_p->handler;
301
302 /* 2-5. */
303 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_GET_PROTOTYPE_OF_UL);
304
305 /* 6. */
306 if (ECMA_IS_VALUE_ERROR (trap))
307 {
308 return trap;
309 }
310
311 ecma_value_t target = proxy_obj_p->target;
312 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
313
314 /* 7. */
315 if (ecma_is_value_undefined (trap))
316 {
317 return ecma_builtin_object_object_get_prototype_of (target_obj_p);
318 }
319
320 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
321
322 /* 8. */
323 ecma_value_t handler_proto = ecma_op_function_call (func_obj_p, handler, &target, 1);
324
325 ecma_deref_object (func_obj_p);
326
327 /* 9. */
328 if (ECMA_IS_VALUE_ERROR (handler_proto))
329 {
330 return handler_proto;
331 }
332
333 /* 10. */
334 if (!ecma_is_value_object (handler_proto) && !ecma_is_value_null (handler_proto))
335 {
336 ecma_free_value (handler_proto);
337
338 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned neither object nor null."));
339 }
340
341 /* 11. */
342 ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p);
343
344 /* 12. */
345 if (ECMA_IS_VALUE_ERROR (extensible_target))
346 {
347 ecma_free_value (handler_proto);
348
349 return extensible_target;
350 }
351
352 /* 13. */
353 if (ecma_is_value_true (extensible_target))
354 {
355 return handler_proto;
356 }
357
358 /* 14. */
359 ecma_value_t target_proto = ecma_builtin_object_object_get_prototype_of (target_obj_p);
360
361 /* 15. */
362 if (ECMA_IS_VALUE_ERROR (target_proto))
363 {
364 return target_proto;
365 }
366
367 ecma_value_t ret_value = handler_proto;
368
369 /* 16. */
370 if (handler_proto != target_proto)
371 {
372 ecma_free_value (handler_proto);
373
374 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Proxy target is non-extensible, but the trap did not "
375 "return its actual prototype."));
376 }
377
378 ecma_free_value (target_proto);
379
380 /* 17. */
381 return ret_value;
382 } /* ecma_proxy_object_get_prototype_of */
383
384 /**
385 * The Proxy object [[SetPrototypeOf]] internal routine
386 *
387 * See also:
388 * ECMAScript v6, 9.5.2
389 *
390 * Note: Returned value is always a simple value so freeing it is unnecessary.
391 *
392 * @return ECMA_VALUE_ERROR - if the operation fails
393 * ECMA_VALUE_{TRUE/FALSE} - depends on whether the new prototype can be set for the given object
394 */
395 ecma_value_t
ecma_proxy_object_set_prototype_of(ecma_object_t * obj_p,ecma_value_t proto)396 ecma_proxy_object_set_prototype_of (ecma_object_t *obj_p, /**< proxy object */
397 ecma_value_t proto) /**< new prototype object */
398 {
399 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
400
401 /* 1. */
402 JERRY_ASSERT (ecma_is_value_object (proto) || ecma_is_value_null (proto));
403
404 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
405
406 /* 2. */
407 ecma_value_t handler = proxy_obj_p->handler;
408
409 /* 3-6. */
410 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_SET_PROTOTYPE_OF_UL);
411
412 /* 7.*/
413 if (ECMA_IS_VALUE_ERROR (trap))
414 {
415 return trap;
416 }
417
418 ecma_value_t target = proxy_obj_p->target;
419 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
420
421 /* 8. */
422 if (ecma_is_value_undefined (trap))
423 {
424 if (ECMA_OBJECT_IS_PROXY (target_obj_p))
425 {
426 return ecma_proxy_object_set_prototype_of (target_obj_p, proto);
427 }
428
429 return ecma_op_ordinary_object_set_prototype_of (target_obj_p, proto);
430 }
431
432 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
433 ecma_value_t args[] = { target, proto };
434
435 /* 9. */
436 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 2);
437
438 ecma_deref_object (func_obj_p);
439
440 /* 10. */
441 if (ECMA_IS_VALUE_ERROR (trap_result))
442 {
443 return trap_result;
444 }
445
446 bool boolean_trap_result = ecma_op_to_boolean (trap_result);
447
448 ecma_free_value (trap_result);
449
450 /* 11. */
451 ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p);
452
453 /* 12. */
454 if (ECMA_IS_VALUE_ERROR (extensible_target))
455 {
456 return extensible_target;
457 }
458
459 /* 13. */
460 if (ecma_is_value_true (extensible_target))
461 {
462 return ecma_make_boolean_value (boolean_trap_result);
463 }
464
465 /* 14. */
466 ecma_value_t target_proto = ecma_builtin_object_object_get_prototype_of (target_obj_p);
467
468 /* 15. */
469 if (ECMA_IS_VALUE_ERROR (target_proto))
470 {
471 return target_proto;
472 }
473
474 ecma_value_t ret_value = ecma_make_boolean_value (boolean_trap_result);
475
476 /* 16. */
477 if (boolean_trap_result && (target_proto != proto))
478 {
479 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Target object is non-extensible and trap "
480 "returned different prototype."));
481 }
482
483 ecma_free_value (target_proto);
484
485 /* 17. */
486 return ret_value;
487 } /* ecma_proxy_object_set_prototype_of */
488
489 /**
490 * The Proxy object [[isExtensible]] internal routine
491 *
492 * See also:
493 * ECMAScript v6, 9.5.3
494 *
495 * Note: Returned value is always a simple value so freeing it is unnecessary.
496 *
497 * @return ECMA_VALUE_ERROR - if the operation fails
498 * ECMA_VALUE_{TRUE/FALSE} - depends on whether the object is extensible
499 */
500 ecma_value_t
ecma_proxy_object_is_extensible(ecma_object_t * obj_p)501 ecma_proxy_object_is_extensible (ecma_object_t *obj_p) /**< proxy object */
502 {
503 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
504
505 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
506
507 /* 1. */
508 ecma_value_t handler = proxy_obj_p->handler;
509
510 /* 2-5. */
511 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_IS_EXTENSIBLE);
512
513 /* 6. */
514 if (ECMA_IS_VALUE_ERROR (trap))
515 {
516 return trap;
517 }
518
519 ecma_value_t target = proxy_obj_p->target;
520 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
521
522 /* 7. */
523 if (ecma_is_value_undefined (trap))
524 {
525 return ecma_builtin_object_object_is_extensible (target_obj_p);
526 }
527
528 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
529
530 /* 8. */
531 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, &target, 1);
532
533 ecma_deref_object (func_obj_p);
534
535 /* 9. */
536 if (ECMA_IS_VALUE_ERROR (trap_result))
537 {
538 return trap_result;
539 }
540
541 bool boolean_trap_result = ecma_op_to_boolean (trap_result);
542
543 ecma_free_value (trap_result);
544
545 bool target_result;
546
547 /* 10. */
548 if (ECMA_OBJECT_IS_PROXY (target_obj_p))
549 {
550 ecma_value_t proxy_is_ext = ecma_proxy_object_is_extensible (target_obj_p);
551
552 if (ECMA_IS_VALUE_ERROR (proxy_is_ext))
553 {
554 return proxy_is_ext;
555 }
556
557 target_result = ecma_is_value_true (proxy_is_ext);
558 }
559 else
560 {
561 target_result = ecma_op_ordinary_object_is_extensible (target_obj_p);
562 }
563
564 /* 12. */
565 if (boolean_trap_result != target_result)
566 {
567 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap result does not reflect extensibility of proxy target"));
568 }
569
570 return ecma_make_boolean_value (boolean_trap_result);
571 } /* ecma_proxy_object_is_extensible */
572
573 /**
574 * The Proxy object [[PreventExtensions]] internal routine
575 *
576 * See also:
577 * ECMAScript v6, 9.5.4
578 *
579 * Note: Returned value is always a simple value so freeing it is unnecessary.
580 *
581 * @return ECMA_VALUE_ERROR - if the operation fails
582 * ECMA_VALUE_{TRUE/FALSE} - depends on whether the object can be set as inextensible
583 */
584 ecma_value_t
ecma_proxy_object_prevent_extensions(ecma_object_t * obj_p)585 ecma_proxy_object_prevent_extensions (ecma_object_t *obj_p) /**< proxy object */
586 {
587 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
588
589 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
590
591 /* 1. */
592 ecma_value_t handler = proxy_obj_p->handler;
593
594 /* 2-5. */
595 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_PREVENT_EXTENSIONS_UL);
596
597 /* 6. */
598 if (ECMA_IS_VALUE_ERROR (trap))
599 {
600 return trap;
601 }
602
603 ecma_value_t target = proxy_obj_p->target;
604 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
605
606 /* 7. */
607 if (ecma_is_value_undefined (trap))
608 {
609 ecma_value_t ret_value = ecma_builtin_object_object_prevent_extensions (target_obj_p);
610
611 if (ECMA_IS_VALUE_ERROR (ret_value))
612 {
613 return ret_value;
614 }
615
616 ecma_deref_object (target_obj_p);
617
618 return ECMA_VALUE_TRUE;
619 }
620
621 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
622
623 /* 8. */
624 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, &target, 1);
625
626 ecma_deref_object (func_obj_p);
627
628 /* 9. */
629 if (ECMA_IS_VALUE_ERROR (trap_result))
630 {
631 return trap_result;
632 }
633
634 bool boolean_trap_result = ecma_op_to_boolean (trap_result);
635
636 ecma_free_value (trap_result);
637
638 /* 10. */
639 if (boolean_trap_result)
640 {
641 ecma_value_t target_is_ext = ecma_builtin_object_object_is_extensible (target_obj_p);
642
643 if (ECMA_IS_VALUE_ERROR (target_is_ext))
644 {
645 return target_is_ext;
646 }
647
648 if (ecma_is_value_true (target_is_ext))
649 {
650 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap result does not reflect inextensibility of proxy target"));
651 }
652 }
653
654 /* 11. */
655 return ecma_make_boolean_value (boolean_trap_result);
656 } /* ecma_proxy_object_prevent_extensions */
657
658 /**
659 * The Proxy object [[GetOwnProperty]] internal routine
660 *
661 * See also:
662 * ECMAScript v6, 9.5.5
663 *
664 * Note: - Returned value is always a simple value so freeing it is unnecessary.
665 * - If the operation does not fail, freeing the filled property descriptor is the caller's responsibility
666 *
667 * @return ECMA_VALUE_ERROR - if the operation fails
668 * ECMA_VALUE_{TRUE_FALSE} - depends on whether object has property with the given name
669 */
670 ecma_value_t
ecma_proxy_object_get_own_property_descriptor(ecma_object_t * obj_p,ecma_string_t * prop_name_p,ecma_property_descriptor_t * prop_desc_p)671 ecma_proxy_object_get_own_property_descriptor (ecma_object_t *obj_p, /**< proxy object */
672 ecma_string_t *prop_name_p, /**< property name */
673 ecma_property_descriptor_t *prop_desc_p) /**< [out] property
674 * descriptor */
675 {
676 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
677
678 /* 2. */
679 ecma_value_t handler = proxy_obj_p->handler;
680
681 /* 3-6. */
682 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL);
683
684 ecma_value_t target = proxy_obj_p->target;
685
686 /* 7. */
687 if (ECMA_IS_VALUE_ERROR (trap))
688 {
689 return trap;
690 }
691
692 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
693
694 /* 8. */
695 if (ecma_is_value_undefined (trap))
696 {
697 return ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, prop_desc_p);
698 }
699
700 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
701 ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p);
702 ecma_value_t args[] = { target, prop_value };
703
704 /* 9. */
705 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 2);
706 ecma_deref_object (func_obj_p);
707
708 /* 10. */
709 if (ECMA_IS_VALUE_ERROR (trap_result))
710 {
711 return trap_result;
712 }
713
714 /* 11. */
715 if (!ecma_is_value_object (trap_result) && !ecma_is_value_undefined (trap_result))
716 {
717 ecma_free_value (trap_result);
718 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap is not object nor undefined."));
719 }
720
721 /* 12. */
722 ecma_property_descriptor_t target_desc;
723 ecma_value_t target_status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc);
724
725 /* 13. */
726 if (ECMA_IS_VALUE_ERROR (target_status))
727 {
728 ecma_free_value (trap_result);
729 return target_status;
730 }
731
732 /* 14. */
733 if (ecma_is_value_undefined (trap_result))
734 {
735 /* .a */
736 if (ecma_is_value_false (target_status))
737 {
738 return ECMA_VALUE_FALSE;
739 }
740 /* .b */
741 if (!(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE))
742 {
743 ecma_free_property_descriptor (&target_desc);
744 return ecma_raise_type_error (ECMA_ERR_MSG ("Given property is a non-configurable"
745 " data property on the proxy target"));
746 }
747
748 /* .c */
749 ecma_free_property_descriptor (&target_desc);
750 ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p);
751
752 /* .d */
753 if (ECMA_IS_VALUE_ERROR (extensible_target))
754 {
755 return extensible_target;
756 }
757
758 /* .e */
759 JERRY_ASSERT (ecma_is_value_boolean (extensible_target));
760
761 /* .f */
762 if (ecma_is_value_false (extensible_target))
763 {
764 return ecma_raise_type_error (ECMA_ERR_MSG ("Target not extensible."));
765 }
766
767 /* .g */
768 return ECMA_VALUE_FALSE;
769 }
770
771 /* 15. */
772 ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p);
773
774 /* 16. */
775 if (ECMA_IS_VALUE_ERROR (extensible_target))
776 {
777 if (ecma_is_value_true (target_status))
778 {
779 ecma_free_property_descriptor (&target_desc);
780 }
781 ecma_free_value (trap_result);
782 return extensible_target;
783 }
784
785 /* 17, 19 */
786 ecma_value_t result_val = ecma_op_to_property_descriptor (trap_result, prop_desc_p);
787
788 ecma_op_to_complete_property_descriptor (prop_desc_p);
789 ecma_free_value (trap_result);
790
791 /* 18. */
792 if (ECMA_IS_VALUE_ERROR (result_val))
793 {
794 if (ecma_is_value_true (target_status))
795 {
796 ecma_free_property_descriptor (&target_desc);
797 }
798 return result_val;
799 }
800
801 /* 20. */
802 bool is_extensible = ecma_is_value_true (extensible_target);
803
804 bool is_valid = ecma_op_is_compatible_property_descriptor (prop_desc_p,
805 (ecma_is_value_true (target_status) ? &target_desc : NULL),
806 is_extensible);
807
808 bool target_has_desc = ecma_is_value_true (target_status);
809 bool target_is_configurable = false;
810
811 if (target_has_desc)
812 {
813 target_is_configurable = ((target_desc.flags & ECMA_PROP_IS_CONFIGURABLE) != 0);
814 ecma_free_property_descriptor (&target_desc);
815 }
816
817 /* 21. */
818 if (!is_valid)
819 {
820 ecma_free_property_descriptor (prop_desc_p);
821 return ecma_raise_type_error (ECMA_ERR_MSG ("The two descriptors are not compatible."));
822 }
823
824 /* 22. */
825 else if (!(prop_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE))
826 {
827 if (!target_has_desc || target_is_configurable)
828 {
829 ecma_free_property_descriptor (prop_desc_p);
830 return ecma_raise_type_error (ECMA_ERR_MSG ("Not compatible."));
831 }
832 }
833 return ECMA_VALUE_TRUE;
834 } /* ecma_proxy_object_get_own_property_descriptor */
835
836 /**
837 * The Proxy object [[DefineOwnProperty]] internal routine
838 *
839 * See also:
840 * ECMAScript v6, 9.5.6
841 *
842 * Note: Returned value is always a simple value so freeing it is unnecessary.
843 *
844 * @return ECMA_VALUE_ERROR - if the operation fails
845 * ECMA_VALUE_{TRUE_FALSE} - depends on whether the property can be defined for the given object
846 */
847 ecma_value_t
ecma_proxy_object_define_own_property(ecma_object_t * obj_p,ecma_string_t * prop_name_p,const ecma_property_descriptor_t * prop_desc_p)848 ecma_proxy_object_define_own_property (ecma_object_t *obj_p, /**< proxy object */
849 ecma_string_t *prop_name_p, /**< property name */
850 const ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */
851 {
852 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
853
854 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
855
856 /* 2. */
857 ecma_value_t handler = proxy_obj_p->handler;
858
859 /* 3-6. */
860 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_DEFINE_PROPERTY_UL);
861
862 /* 7. */
863 if (ECMA_IS_VALUE_ERROR (trap))
864 {
865 return trap;
866 }
867
868 ecma_value_t target = proxy_obj_p->target;
869 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
870
871 /* 8. */
872 if (ecma_is_value_undefined (trap))
873 {
874 return ecma_op_object_define_own_property (target_obj_p, prop_name_p, prop_desc_p);
875 }
876
877 /* 9. */
878 ecma_object_t *desc_obj = ecma_op_from_property_descriptor (prop_desc_p);
879
880 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
881 ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p);
882 ecma_value_t desc_obj_value = ecma_make_object_value (desc_obj);
883 ecma_value_t args[] = {target, prop_value, desc_obj_value};
884
885 /* 10. */
886 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 3);
887
888 ecma_deref_object (func_obj_p);
889 ecma_deref_object (desc_obj);
890
891 /* 11. */
892 if (ECMA_IS_VALUE_ERROR (trap_result))
893 {
894 return trap_result;
895 }
896
897 bool boolean_trap_result = ecma_op_to_boolean (trap_result);
898
899 ecma_free_value (trap_result);
900
901 /* 12. */
902 if (!boolean_trap_result)
903 {
904 return ECMA_VALUE_FALSE;
905 }
906
907 /* 13. */
908 ecma_property_descriptor_t target_desc;
909
910 ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc);
911
912 /* 14. */
913 if (ECMA_IS_VALUE_ERROR (status))
914 {
915 return status;
916 }
917
918 bool target_prop_found = ecma_is_value_true (status);
919
920 /* 15. */
921 ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p);
922
923 bool is_target_ext = ecma_is_value_true (extensible_target);
924
925 /* 16. */
926 if (ECMA_IS_VALUE_ERROR (extensible_target))
927 {
928 if (target_prop_found)
929 {
930 ecma_free_property_descriptor (&target_desc);
931 }
932
933 return extensible_target;
934 }
935
936 /* 17. */
937 bool setting_config_false = ((prop_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE_DEFINED)
938 && !(prop_desc_p->flags & ECMA_PROP_IS_CONFIGURABLE));
939
940 /* 19. */
941 if (!target_prop_found)
942 {
943 if (!is_target_ext)
944 {
945 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for adding property "
946 "to the non-extensible target"));
947 }
948
949 if (setting_config_false)
950 {
951 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for defining non-configurable property "
952 "which is non-existent in the target"));
953 }
954 }
955 /* 20. */
956 else
957 {
958 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
959
960 if (!ecma_op_is_compatible_property_descriptor (prop_desc_p, &target_desc, is_target_ext))
961 {
962 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for adding property that is "
963 "incompatible with the existing property in the target"));
964 }
965 else if (setting_config_false && (target_desc.flags & ECMA_PROP_IS_CONFIGURABLE))
966 {
967 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for defining non-configurable property "
968 "which is configurable in the target"));
969 }
970
971 ecma_free_property_descriptor (&target_desc);
972
973 if (ECMA_IS_VALUE_ERROR (ret_value))
974 {
975 return ret_value;
976 }
977 }
978
979 return ECMA_VALUE_TRUE;
980 } /* ecma_proxy_object_define_own_property */
981
982 /**
983 * The Proxy object [[HasProperty]] internal routine
984 *
985 * See also:
986 * ECMAScript v6, 9.5.7
987 *
988 * Note: Returned value is always a simple value so freeing it is unnecessary.
989 *
990 * @return ECMA_VALUE_ERROR - if the operation fails
991 * ECMA_VALUE_{TRUE_FALSE} - depends on whether the property is found
992 */
993 ecma_value_t
ecma_proxy_object_has(ecma_object_t * obj_p,ecma_string_t * prop_name_p)994 ecma_proxy_object_has (ecma_object_t *obj_p, /**< proxy object */
995 ecma_string_t *prop_name_p) /**< property name */
996 {
997 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
998 ECMA_CHECK_STACK_USAGE ();
999
1000 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
1001
1002 /* 2. */
1003 ecma_value_t handler = proxy_obj_p->handler;
1004
1005 /* 3-6. */
1006 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_HAS);
1007
1008 /* 7. */
1009 if (ECMA_IS_VALUE_ERROR (trap))
1010 {
1011 return trap;
1012 }
1013
1014 ecma_value_t target = proxy_obj_p->target;
1015 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
1016
1017 /* 8. */
1018 if (ecma_is_value_undefined (trap))
1019 {
1020 return ecma_op_object_has_property (target_obj_p, prop_name_p);
1021 }
1022
1023 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
1024 ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p);
1025 ecma_value_t args[] = {target, prop_value};
1026
1027 /* 9. */
1028 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 2);
1029
1030 ecma_deref_object (func_obj_p);
1031
1032 /* 10. */
1033 if (ECMA_IS_VALUE_ERROR (trap_result))
1034 {
1035 return trap_result;
1036 }
1037
1038 bool boolean_trap_result = ecma_op_to_boolean (trap_result);
1039
1040 ecma_free_value (trap_result);
1041
1042 /* 11. */
1043 if (!boolean_trap_result)
1044 {
1045 ecma_property_descriptor_t target_desc;
1046
1047 ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc);
1048
1049 if (ECMA_IS_VALUE_ERROR (status))
1050 {
1051 return status;
1052 }
1053
1054 if (ecma_is_value_true (status))
1055 {
1056 bool prop_is_configurable = target_desc.flags & ECMA_PROP_IS_CONFIGURABLE;
1057
1058 ecma_free_property_descriptor (&target_desc);
1059
1060 if (!prop_is_configurable)
1061 {
1062 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned falsish for property which exists "
1063 "in the proxy target as non-configurable"));
1064 }
1065
1066 ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p);
1067
1068 if (ECMA_IS_VALUE_ERROR (extensible_target))
1069 {
1070 return extensible_target;
1071 }
1072
1073 if (ecma_is_value_false (extensible_target))
1074 {
1075 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned falsish for property but "
1076 "the proxy target is not extensible"));
1077 }
1078 }
1079 }
1080
1081 /* 12. */
1082 return ecma_make_boolean_value (boolean_trap_result);
1083 } /* ecma_proxy_object_has */
1084
1085 /**
1086 * The Proxy object [[Get]] internal routine
1087 *
1088 * See also:
1089 * ECMAScript v6, 9.5.8
1090 *
1091 * Note: Returned value is always a simple value so freeing it is unnecessary.
1092 *
1093 * @return ECMA_VALUE_ERROR - if the operation fails
1094 * value of the given nameddata property or the result of the getter function call - otherwise
1095 */
1096 ecma_value_t
ecma_proxy_object_get(ecma_object_t * obj_p,ecma_string_t * prop_name_p,ecma_value_t receiver)1097 ecma_proxy_object_get (ecma_object_t *obj_p, /**< proxy object */
1098 ecma_string_t *prop_name_p, /**< property name */
1099 ecma_value_t receiver) /**< receiver to invoke getter function */
1100 {
1101 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
1102 ECMA_CHECK_STACK_USAGE ();
1103
1104 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
1105
1106 /* 2. */
1107 ecma_value_t handler = proxy_obj_p->handler;
1108
1109 /* 3-6. */
1110 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_GET);
1111
1112 /* 7. */
1113 if (ECMA_IS_VALUE_ERROR (trap))
1114 {
1115 return trap;
1116 }
1117
1118 ecma_value_t target = proxy_obj_p->target;
1119 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
1120
1121 /* 8. */
1122 if (ecma_is_value_undefined (trap))
1123 {
1124 return ecma_op_object_get_with_receiver (target_obj_p, prop_name_p, receiver);
1125 }
1126
1127 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
1128 ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p);
1129 ecma_value_t args[] = { target, prop_value, receiver };
1130
1131 /* 9. */
1132 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 3);
1133
1134 ecma_deref_object (func_obj_p);
1135
1136 /* 10. */
1137 if (ECMA_IS_VALUE_ERROR (trap_result))
1138 {
1139 return trap_result;
1140 }
1141
1142 /* 11. */
1143 ecma_property_descriptor_t target_desc;
1144
1145 ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc);
1146
1147 /* 12. */
1148 if (ECMA_IS_VALUE_ERROR (status))
1149 {
1150 return status;
1151 }
1152
1153 /* 13. */
1154 if (ecma_is_value_true (status))
1155 {
1156 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1157
1158 if ((target_desc.flags & ECMA_PROP_IS_VALUE_DEFINED)
1159 && !(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE)
1160 && !(target_desc.flags & ECMA_PROP_IS_WRITABLE)
1161 && !ecma_op_same_value (trap_result, target_desc.value))
1162 {
1163 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("given property is a read-only and non-configurable"
1164 " data property on the proxy target"));
1165 }
1166 else if (!(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE)
1167 && (target_desc.flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED))
1168 && target_desc.get_p == NULL
1169 && !ecma_is_value_undefined (trap_result))
1170 {
1171 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("given property is a non-configurable property and"
1172 " does not have a getter function"));
1173 }
1174
1175 ecma_free_property_descriptor (&target_desc);
1176
1177 if (ECMA_IS_VALUE_ERROR (ret_value))
1178 {
1179 ecma_free_value (trap_result);
1180
1181 return ret_value;
1182 }
1183 }
1184
1185 /* 14. */
1186 return trap_result;
1187 } /* ecma_proxy_object_get */
1188
1189 /**
1190 * The Proxy object [[Set]] internal routine
1191 *
1192 * See also:
1193 * ECMAScript v6, 9.5.9
1194 *
1195 * Note: Returned value is always a simple value so freeing it is unnecessary.
1196 *
1197 * @return ECMA_VALUE_ERROR - if the operation fails
1198 * ECMA_VALUE_{TRUE/FALSE} - depends on whether the propety can be set to the given object
1199 */
1200 ecma_value_t
ecma_proxy_object_set(ecma_object_t * obj_p,ecma_string_t * prop_name_p,ecma_value_t value,ecma_value_t receiver)1201 ecma_proxy_object_set (ecma_object_t *obj_p, /**< proxy object */
1202 ecma_string_t *prop_name_p, /**< property name */
1203 ecma_value_t value, /**< value to set */
1204 ecma_value_t receiver) /**< receiver to invoke setter function */
1205 {
1206 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
1207 ECMA_CHECK_STACK_USAGE ();
1208
1209 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
1210
1211 /* 2. */
1212 ecma_value_t handler = proxy_obj_p->handler;
1213
1214 /* 3-6. */
1215 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_SET);
1216
1217 /* 7. */
1218 if (ECMA_IS_VALUE_ERROR (trap))
1219 {
1220 return trap;
1221 }
1222
1223 ecma_value_t target = proxy_obj_p->target;
1224 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
1225
1226 /* 8. */
1227 if (ecma_is_value_undefined (trap))
1228 {
1229 return ecma_op_object_put_with_receiver (target_obj_p, prop_name_p, value, receiver, false);
1230 }
1231
1232 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
1233 ecma_value_t prop_name_value = ecma_make_prop_name_value (prop_name_p);
1234 ecma_value_t args[] = { target, prop_name_value, value, receiver };
1235
1236 /* 9. */
1237 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 4);
1238
1239 ecma_deref_object (func_obj_p);
1240
1241 /* 10. */
1242 if (ECMA_IS_VALUE_ERROR (trap_result))
1243 {
1244 return trap_result;
1245 }
1246
1247 bool boolean_trap_result = ecma_op_to_boolean (trap_result);
1248
1249 ecma_free_value (trap_result);
1250
1251 /* 11. */
1252 if (!boolean_trap_result)
1253 {
1254 return ECMA_VALUE_FALSE;
1255 }
1256
1257 /* 12. */
1258 ecma_property_descriptor_t target_desc;
1259
1260 ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc);
1261
1262 /* 13. */
1263 if (ECMA_IS_VALUE_ERROR (status))
1264 {
1265 return status;
1266 }
1267
1268 /* 14. */
1269 if (ecma_is_value_true (status))
1270 {
1271 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1272
1273 if ((target_desc.flags & ECMA_PROP_IS_VALUE_DEFINED)
1274 && !(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE)
1275 && !(target_desc.flags & ECMA_PROP_IS_WRITABLE)
1276 && !ecma_op_same_value (value, target_desc.value))
1277 {
1278 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("The property exists in the proxy target as a"
1279 " non-configurable and non-writable data property"
1280 " with a different value."));
1281 }
1282 else if (!(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE)
1283 && (target_desc.flags & (ECMA_PROP_IS_GET_DEFINED | ECMA_PROP_IS_SET_DEFINED))
1284 && target_desc.set_p == NULL)
1285 {
1286 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("The property exists in the proxy target as a"
1287 " non-configurable accessor property whitout a setter."));
1288 }
1289
1290 ecma_free_property_descriptor (&target_desc);
1291
1292 if (ECMA_IS_VALUE_ERROR (ret_value))
1293 {
1294 return ret_value;
1295 }
1296 }
1297
1298 /* 15. */
1299 return ECMA_VALUE_TRUE;
1300 } /* ecma_proxy_object_set */
1301
1302 /**
1303 * The Proxy object [[Delete]] internal routine
1304 *
1305 * See also:
1306 * ECMAScript v6, 9.5.10
1307 *
1308 * Note: Returned value is always a simple value so freeing it is unnecessary.
1309 *
1310 * @return ECMA_VALUE_ERROR - if the operation fails
1311 * ECMA_VALUE_{TRUE/FALSE} - depends on whether the propety can be deleted
1312 */
1313 ecma_value_t
ecma_proxy_object_delete_property(ecma_object_t * obj_p,ecma_string_t * prop_name_p)1314 ecma_proxy_object_delete_property (ecma_object_t *obj_p, /**< proxy object */
1315 ecma_string_t *prop_name_p) /**< property name */
1316 {
1317 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
1318
1319 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
1320
1321 /* 2. */
1322 ecma_value_t handler = proxy_obj_p->handler;
1323
1324 /* 3-6.*/
1325 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_DELETE_PROPERTY_UL);
1326
1327 /* 7. */
1328 if (ECMA_IS_VALUE_ERROR (trap))
1329 {
1330 return trap;
1331 }
1332
1333 ecma_value_t target = proxy_obj_p->target;
1334 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
1335
1336 /* 8. */
1337 if (ecma_is_value_undefined (trap))
1338 {
1339 return ecma_op_object_delete (target_obj_p, prop_name_p, false);
1340 }
1341
1342 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
1343 ecma_value_t prop_name_value = ecma_make_prop_name_value (prop_name_p);
1344 ecma_value_t args[] = { target, prop_name_value };
1345
1346 /* 9. */
1347 ecma_value_t trap_result = ecma_op_function_call (func_obj_p, handler, args, 2);
1348
1349 ecma_deref_object (func_obj_p);
1350
1351 /* 10. */
1352 if (ECMA_IS_VALUE_ERROR (trap_result))
1353 {
1354 return trap_result;
1355 }
1356
1357 bool boolean_trap_result = ecma_op_to_boolean (trap_result);
1358
1359 ecma_free_value (trap_result);
1360
1361 /* 11. */
1362 if (!boolean_trap_result)
1363 {
1364 return ECMA_VALUE_FALSE;
1365 }
1366
1367 /* 12. */
1368 ecma_property_descriptor_t target_desc;
1369
1370 ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p, prop_name_p, &target_desc);
1371
1372 /* 13. */
1373 if (ECMA_IS_VALUE_ERROR (status))
1374 {
1375 return status;
1376 }
1377
1378 /* 14. */
1379 if (ecma_is_value_false (status))
1380 {
1381 return ECMA_VALUE_TRUE;
1382 }
1383
1384 ecma_value_t ret_value = ECMA_VALUE_TRUE;
1385
1386 /* 15. */
1387 if (!(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE))
1388 {
1389 ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned truish for property which is "
1390 "non-configurable in the proxy target."));
1391 }
1392
1393 ecma_free_property_descriptor (&target_desc);
1394
1395 /* 16. */
1396 return ret_value;
1397 } /* ecma_proxy_object_delete_property */
1398
1399 /**
1400 * The Proxy object [[Enumerate]] internal routine
1401 *
1402 * See also:
1403 * ECMAScript v6, 9.5.11
1404 *
1405 * Note: Returned value must be freed with ecma_free_value.
1406 *
1407 * @return ECMA_VALUE_ERROR - if the operation fails
1408 * ecma-object - otherwise
1409 */
1410 ecma_value_t
ecma_proxy_object_enumerate(ecma_object_t * obj_p)1411 ecma_proxy_object_enumerate (ecma_object_t *obj_p) /**< proxy object */
1412 {
1413 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
1414 JERRY_UNUSED (obj_p);
1415 return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Enumerate]]"));
1416 } /* ecma_proxy_object_enumerate */
1417
1418 /**
1419 * Helper method for the Proxy object [[OwnPropertyKeys]] operation
1420 *
1421 * See also:
1422 * ECMAScript v6, 9.5.12 steps 21. 23.
1423 *
1424 * @return ECMA_VALUE_ERROR - if a target key is not in the unchecked_result_keys collection
1425 * ECMA_VALUE_EMPTY - otherwise
1426 */
1427 static ecma_value_t
ecma_proxy_object_own_property_keys_helper(ecma_collection_t * target_collection,ecma_collection_t * unchecked_result_keys,uint32_t * counter)1428 ecma_proxy_object_own_property_keys_helper (ecma_collection_t *target_collection, /**< target keys */
1429 ecma_collection_t *unchecked_result_keys, /**< unchecked keys */
1430 uint32_t *counter) /**< unchecked property counter */
1431 {
1432 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
1433
1434 for (uint32_t i = 0; i < target_collection->item_count; i++)
1435 {
1436 ecma_string_t *current_prop_name = ecma_get_prop_name_from_value (target_collection->buffer_p[i]);
1437
1438 ret_value = ECMA_VALUE_ERROR;
1439
1440 for (uint32_t j = 0; j < unchecked_result_keys->item_count; j++)
1441 {
1442 if (ecma_is_value_empty (unchecked_result_keys->buffer_p[j]))
1443 {
1444 continue;
1445 }
1446
1447 ecma_string_t *unchecked_prop_name = ecma_get_prop_name_from_value (unchecked_result_keys->buffer_p[j]);
1448
1449 if (ecma_compare_ecma_strings (current_prop_name, unchecked_prop_name))
1450 {
1451 ecma_deref_ecma_string (unchecked_prop_name);
1452 ret_value = ECMA_VALUE_EMPTY;
1453 unchecked_result_keys->buffer_p[j] = ECMA_VALUE_EMPTY;
1454 (*counter)++;
1455 }
1456 }
1457
1458 if (ECMA_IS_VALUE_ERROR (ret_value))
1459 {
1460 break;
1461 }
1462 }
1463
1464 return ret_value;
1465 } /* ecma_proxy_object_own_property_keys_helper */
1466
1467 /**
1468 * Helper method for checking the invariants in the Proxy object [[OwnPropertyKeys]] operation
1469 *
1470 * See also:
1471 * ECMAScript v6, 9.5.12 steps 20-25.
1472 *
1473 * @return true - if none of the invariants got violated
1474 * false - otherwise
1475 */
1476 static bool
ecma_proxy_check_invariants_for_own_prop_keys(ecma_collection_t * trap_result,ecma_collection_t * target_non_configurable_keys,ecma_collection_t * target_configurable_keys,ecma_value_t extensible_target)1477 ecma_proxy_check_invariants_for_own_prop_keys (ecma_collection_t *trap_result,
1478 ecma_collection_t *target_non_configurable_keys,
1479 ecma_collection_t *target_configurable_keys,
1480 ecma_value_t extensible_target)
1481 {
1482 /* 20. */
1483 ecma_collection_t *unchecked_result_keys = ecma_new_collection ();
1484
1485 ecma_collection_append (unchecked_result_keys, trap_result->buffer_p, trap_result->item_count);
1486
1487 for (uint32_t i = 0; i < unchecked_result_keys->item_count; i++)
1488 {
1489 ecma_string_t *unchecked_prop_name = ecma_get_prop_name_from_value (unchecked_result_keys->buffer_p[i]);
1490 ecma_ref_ecma_string (unchecked_prop_name);
1491 }
1492
1493 bool check_ok = false;
1494 uint32_t unchecked_prop_name_counter = 0;
1495
1496 /* 21. */
1497 if (ECMA_IS_VALUE_ERROR (ecma_proxy_object_own_property_keys_helper (target_non_configurable_keys,
1498 unchecked_result_keys,
1499 &unchecked_prop_name_counter)))
1500 {
1501 ecma_raise_type_error (ECMA_ERR_MSG ("Trap result did not include all non-configurable keys."));
1502 }
1503 /* 22. */
1504 else if (ecma_is_value_true (extensible_target))
1505 {
1506 check_ok = true;
1507 }
1508 /* 23. */
1509 else if (ECMA_IS_VALUE_ERROR (ecma_proxy_object_own_property_keys_helper (target_configurable_keys,
1510 unchecked_result_keys,
1511 &unchecked_prop_name_counter)))
1512 {
1513 ecma_raise_type_error (ECMA_ERR_MSG ("Trap result did not include all configurable keys."));
1514 }
1515 /* 24. */
1516 else if (unchecked_result_keys->item_count != unchecked_prop_name_counter)
1517 {
1518 ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned extra keys but proxy target is non-extensible"));
1519 }
1520 /* 25. */
1521 else
1522 {
1523 check_ok = true;
1524 }
1525
1526 ecma_collection_free (unchecked_result_keys);
1527
1528 return check_ok;
1529 } /* ecma_proxy_check_invariants_for_own_prop_keys */
1530
1531 /**
1532 * The Proxy object [[OwnPropertyKeys]] internal routine
1533 *
1534 * See also:
1535 * ECMAScript v6, 9.5.12
1536 *
1537 * Note: If the returned collection is not NULL, it must be freed with
1538 * ecma_collection_free if it is no longer needed
1539 *
1540 * @return NULL - if the operation fails
1541 * pointer to a newly allocated list of property names - otherwise
1542 */
1543 ecma_collection_t *
ecma_proxy_object_own_property_keys(ecma_object_t * obj_p)1544 ecma_proxy_object_own_property_keys (ecma_object_t *obj_p) /**< proxy object */
1545 {
1546 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
1547
1548 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
1549
1550 /* 1. */
1551 ecma_value_t handler = proxy_obj_p->handler;
1552
1553 /* 2-5. */
1554 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_OWN_KEYS_UL);
1555
1556 /* 6. */
1557 if (ECMA_IS_VALUE_ERROR (trap))
1558 {
1559 return NULL;
1560 }
1561
1562 ecma_value_t target = proxy_obj_p->target;
1563 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
1564
1565 /* 7. */
1566 if (ecma_is_value_undefined (trap))
1567 {
1568 return ecma_op_object_get_property_names (target_obj_p, ECMA_LIST_SYMBOLS);
1569 }
1570
1571 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
1572
1573 /* 8. */
1574 ecma_value_t trap_result_array = ecma_op_function_call (func_obj_p, handler, &target, 1);
1575
1576 ecma_deref_object (func_obj_p);
1577
1578 if (ECMA_IS_VALUE_ERROR (trap_result_array))
1579 {
1580 return NULL;
1581 }
1582
1583 /* 9. */
1584 ecma_collection_t *trap_result = ecma_op_create_list_from_array_like (trap_result_array, true);
1585
1586 ecma_free_value (trap_result_array);
1587
1588 /* 10. */
1589 if (trap_result == NULL)
1590 {
1591 return trap_result;
1592 }
1593
1594 /* 11. */
1595 ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p);
1596
1597 /* 12. */
1598 if (ECMA_IS_VALUE_ERROR (extensible_target))
1599 {
1600 ecma_collection_free (trap_result);
1601 return NULL;
1602 }
1603
1604 /* 13. */
1605 ecma_collection_t *target_keys = ecma_op_object_get_property_names (target_obj_p, ECMA_LIST_SYMBOLS);
1606
1607 /* 14. */
1608 if (target_keys == NULL)
1609 {
1610 ecma_collection_free (trap_result);
1611 return target_keys;
1612 }
1613
1614 /* 16. */
1615 ecma_collection_t *target_configurable_keys = ecma_new_collection ();
1616
1617 /* 17. */
1618 ecma_collection_t *target_non_configurable_keys = ecma_new_collection ();
1619
1620 ecma_collection_t *ret_value = NULL;
1621
1622 /* 18. */
1623 for (uint32_t i = 0; i < target_keys->item_count; i++)
1624 {
1625 ecma_property_descriptor_t target_desc;
1626
1627 ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (target_keys->buffer_p[i]);
1628
1629 ecma_value_t status = ecma_op_object_get_own_property_descriptor (target_obj_p,
1630 prop_name_p,
1631 &target_desc);
1632
1633 if (ECMA_IS_VALUE_ERROR (status))
1634 {
1635 ecma_collection_free (trap_result);
1636 goto free_target_collections;
1637 }
1638
1639 ecma_value_t prop_value = ecma_make_prop_name_value (prop_name_p);
1640
1641 if (ecma_is_value_true (status)
1642 && !(target_desc.flags & ECMA_PROP_IS_CONFIGURABLE))
1643 {
1644 ecma_collection_push_back (target_non_configurable_keys, prop_value);
1645 }
1646 else
1647 {
1648 ecma_collection_push_back (target_configurable_keys, prop_value);
1649 }
1650
1651 if (ecma_is_value_true (status))
1652 {
1653 ecma_free_property_descriptor (&target_desc);
1654 }
1655 }
1656
1657 /* 19. */
1658 if (ecma_is_value_true (extensible_target) && target_non_configurable_keys->item_count == 0)
1659 {
1660 ret_value = trap_result;
1661 }
1662 /* 20-25. */
1663 else if (ecma_proxy_check_invariants_for_own_prop_keys (trap_result,
1664 target_non_configurable_keys,
1665 target_configurable_keys,
1666 extensible_target))
1667 {
1668 ret_value = trap_result;
1669 }
1670 else
1671 {
1672 JERRY_ASSERT (ret_value == NULL);
1673 ecma_collection_free (trap_result);
1674 }
1675
1676 free_target_collections:
1677 ecma_collection_destroy (target_keys);
1678 ecma_collection_free (target_configurable_keys);
1679 ecma_collection_free (target_non_configurable_keys);
1680
1681 return ret_value;
1682 } /* ecma_proxy_object_own_property_keys */
1683
1684 /**
1685 * The Proxy object [[Call]] internal routine
1686 *
1687 * See also:
1688 * ECMAScript v6, 9.5.13
1689 *
1690 * Note: Returned value must be freed with ecma_free_value.
1691 *
1692 * @return ECMA_VALUE_ERROR - if the operation fails
1693 * result of the function call - otherwise
1694 */
1695 ecma_value_t
ecma_proxy_object_call(ecma_object_t * obj_p,ecma_value_t this_argument,const ecma_value_t * args_p,ecma_length_t argc)1696 ecma_proxy_object_call (ecma_object_t *obj_p, /**< proxy object */
1697 ecma_value_t this_argument, /**< this argument to invoke the function */
1698 const ecma_value_t *args_p, /**< argument list */
1699 ecma_length_t argc) /**< number of arguments */
1700 {
1701 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
1702
1703 ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
1704
1705 /* 1. */
1706 ecma_value_t handler = proxy_obj_p->handler;
1707
1708 /* 2-5.*/
1709 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_APPLY);
1710
1711 /* 6. */
1712 if (ECMA_IS_VALUE_ERROR (trap))
1713 {
1714 return trap;
1715 }
1716
1717 ecma_value_t target = proxy_obj_p->target;
1718
1719 /* 7. */
1720 if (ecma_is_value_undefined (trap))
1721 {
1722 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
1723 return ecma_op_function_call (target_obj_p, this_argument, args_p, argc);
1724 }
1725
1726 /* 8. */
1727 ecma_value_t args_array = ecma_op_create_array_object (args_p, argc, false);
1728 ecma_value_t value_array[] = {target, this_argument, args_array};
1729 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
1730 /* 9. */
1731 ecma_value_t ret_value = ecma_op_function_call (func_obj_p, handler, value_array, 3);
1732 ecma_deref_object (func_obj_p);
1733 ecma_deref_object (ecma_get_object_from_value (args_array));
1734
1735 return ret_value;
1736 } /* ecma_proxy_object_call */
1737
1738 /**
1739 * The Proxy object [[Construct]] internal routine
1740 *
1741 * See also:
1742 * ECMAScript v6, 9.5.14
1743 *
1744 * Note: Returned value must be freed with ecma_free_value.
1745 *
1746 * @return ECMA_VALUE_ERROR - if the operation fails
1747 * result of the construct call - otherwise
1748 */
1749 ecma_value_t
ecma_proxy_object_construct(ecma_object_t * obj_p,ecma_object_t * new_target_p,const ecma_value_t * args_p,ecma_length_t argc)1750 ecma_proxy_object_construct (ecma_object_t *obj_p, /**< proxy object */
1751 ecma_object_t *new_target_p, /**< new target */
1752 const ecma_value_t *args_p, /**< argument list */
1753 ecma_length_t argc) /**< number of arguments */
1754 {
1755 JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
1756
1757 ecma_proxy_object_t * proxy_obj_p = (ecma_proxy_object_t *) obj_p;
1758
1759 /* 1. */
1760 ecma_value_t handler = proxy_obj_p->handler;
1761
1762 /* 2-5. */
1763 ecma_value_t trap = ecma_validate_proxy_object (handler, LIT_MAGIC_STRING_CONSTRUCT);
1764
1765 /* 6. */
1766 if (ECMA_IS_VALUE_ERROR (trap))
1767 {
1768 return trap;
1769 }
1770
1771 ecma_value_t target = proxy_obj_p->target;
1772 ecma_object_t *target_obj_p = ecma_get_object_from_value (target);
1773
1774 /* 7. */
1775 if (ecma_is_value_undefined (trap))
1776 {
1777 JERRY_ASSERT (ecma_object_is_constructor (target_obj_p));
1778
1779 return ecma_op_function_construct (target_obj_p, new_target_p, args_p, argc);
1780 }
1781
1782 /* 8. */
1783 ecma_value_t arg_array = ecma_op_create_array_object (args_p, argc, false);
1784
1785 ecma_object_t *func_obj_p = ecma_get_object_from_value (trap);
1786 ecma_value_t new_target_value = ecma_make_object_value (new_target_p);
1787 ecma_value_t function_call_args[] = {target, arg_array, new_target_value};
1788
1789 /* 9. */
1790 ecma_value_t new_obj = ecma_op_function_call (func_obj_p, handler, function_call_args, 3);
1791
1792 ecma_free_value (arg_array);
1793 ecma_deref_object (func_obj_p);
1794
1795 /* 10 .*/
1796 if (ECMA_IS_VALUE_ERROR (new_obj))
1797 {
1798 return new_obj;
1799 }
1800
1801 /* 11. */
1802 if (!ecma_is_value_object (new_obj))
1803 {
1804 ecma_free_value (new_obj);
1805
1806 return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned non-object"));
1807 }
1808
1809 /* 12. */
1810 return new_obj;
1811 } /* ecma_proxy_object_construct */
1812
1813 #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
1814
1815 /**
1816 * @}
1817 * @}
1818 */
1819