diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 9451baf24..925bb5ee8 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -70,6 +70,7 @@ Possible compile time enabled feature types: - JERRY_FEATURE_LOGGING - logging - JERRY_FEATURE_SYMBOL - symbol support - JERRY_FEATURE_DATAVIEW - DataView support + - JERRY_FEATURE_PROXY - Proxy support *New in version 2.0*. @@ -1865,6 +1866,55 @@ jerry_value_is_promise (const jerry_value_t value) - [jerry_create_promise](#jerry_create_promise) +## jerry_value_is_proxy + +**Summary** + +Returns whether the given `jerry_value_t` is a proxy value. + +*Notes*: +- This API depends on a build option (`JERRY_ES2015_BUILTIN_PROXY`) and can be checked + in runtime with the `JERRY_FEATURE_PROXY` feature enum value, + see: [jerry_is_feature_enabled](#jerry_is_feature_enabled). +- The ES2015-subset profile enables this by default. + + +**Prototype** + +```c +bool +jerry_value_is_proxy (const jerry_value_t value) +``` + +- `value` - api value +- return value + - true, if the given `jerry_value_t` is a proxy object + - false, otherwise + +**Example** + +*New in version [next_version]*. + +```c +{ + jerry_value_t value; + ... // create or acquire value + + if (jerry_value_is_proxy (value)) + { + ... + } + + jerry_release_value (value); +} +``` + +**See also** + +- [jerry_release_value](#jerry_release_value) +- [jerry_create_proxy](#jerry_create_proxy) + + ## jerry_value_is_string **Summary** @@ -4212,6 +4262,65 @@ jerry_create_promise (void) - [jerry_release_value](#jerry_release_value) +## jerry_create_proxy + +**Summary** + +Create a new Proxy object with the given target and handler. + +*Note*: + - This API depends on the ES2015-subset profile. + - Returned value must be freed with [jerry_release_value](#jerry_release_value) + when it is no longer needed. + +**Prototype** + +```c +jerry_value_t +jerry_create_proxy (const jerry_value_t target, + const jerry_value_t handler) +``` + +- `target` - proxy target +- `handler` - proxy handler +- return thrown error - if the Proxy construction fails + value of the newly created proxy object - otherwise + +**Example** + +*New in version [next_version]*. + +[doctest]: # () + +```c +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + jerry_value_t target = jerry_create_object (); + jerry_value_t handler = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + + jerry_release_value (target); + jerry_release_value (handler); + + // usage of the proxy + + jerry_release_value (proxy); + + jerry_cleanup (); +} +``` + +**See also** + +- [jerry_value_is_proxy](#jerry_value_is_proxy) +- [jerry_release_value](#jerry_release_value) + + ## jerry_create_string **Summary** @@ -4746,9 +4855,9 @@ jerry_has_property (const jerry_value_t obj_val, - `obj_val` - object value - `prop_name_val` - property name -- return value - JavaScript boolean value that evaluates to - - true, if the property exists - - false, otherwise +- return value - JavaScript value that evaluates to + - raised error - if the operation fail + - true/false API value - depend on whether the property exists *Changed in version 2.0*: The return value type is now a JavaScript value and not a primitive boolean value. @@ -4805,9 +4914,9 @@ jerry_has_own_property (const jerry_value_t obj_val, - `obj_val` - object value - `prop_name_val` - property name -- return value - JavaScript boolean value that evaluates to - - true, if the property exists - - false, otherwise +- return value - JavaScript value that evaluates to + - raised error - if the operation fails + - true/false API value - depend on whether the property exists *Changed in version 2.0*: The return value type is now a JavaScript value and not a primitive boolean value. diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 9cafcdf1b..9214c0181 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -35,6 +35,7 @@ #include "ecma-objects-general.h" #include "ecma-regexp-object.h" #include "ecma-promise-object.h" +#include "ecma-proxy-object.h" #include "ecma-symbol-object.h" #include "ecma-typedarray-object.h" #include "opcodes.h" @@ -803,6 +804,25 @@ jerry_value_is_promise (const jerry_value_t value) /**< api value */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ } /* jerry_value_is_promise */ +/** + * Check if the specified value is a proxy object. + * + * @return true - if the specified value is a proxy object, + * false - otherwise + */ +bool +jerry_value_is_proxy (const jerry_value_t value) /**< api value */ +{ + jerry_assert_api_available (); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + return (ecma_is_value_object (value) + && ECMA_OBJECT_IS_PROXY (ecma_get_object_from_value (value))); +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + JERRY_UNUSED (value); + return false; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ +} /* jerry_value_is_proxy */ + /** * Check if the specified value is string. * @@ -966,6 +986,9 @@ jerry_is_feature_enabled (const jerry_feature_t feature) /**< feature to check * #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) || feature == JERRY_FEATURE_DATAVIEW #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + || feature == JERRY_FEATURE_PROXY +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ #if ENABLED (JERRY_BUILTIN_DATE) || feature == JERRY_FEATURE_DATE #endif /* ENABLED (JERRY_BUILTIN_DATE) */ @@ -1585,6 +1608,34 @@ jerry_create_promise (void) #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ } /* jerry_create_promise */ +/** + * Create a new Proxy object with the given target and handler + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return value of the created Proxy object + */ +jerry_value_t +jerry_create_proxy (const jerry_value_t target, /**< target argument */ + const jerry_value_t handler) /**< handler argument */ +{ + jerry_assert_api_available (); + + if (ecma_is_value_error_reference (target) + || ecma_is_value_error_reference (handler)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); + } + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + ecma_object_t *proxy_p = ecma_proxy_create (target, handler); + return jerry_return (proxy_p == NULL ? ECMA_VALUE_ERROR : ecma_make_object_value (proxy_p)); +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Proxy is not supported."))); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ +} /* jerry_create_proxy */ + /** * Create string from a valid UTF-8 string * @@ -1986,8 +2037,8 @@ jerry_substring_to_utf8_char_buffer (const jerry_value_t value, /**< input strin /** * Checks whether the object or it's prototype objects have the given property. * - * @return true - if the property exists - * false - otherwise + * @return raised error - if the operation fail + * true/false API value - depend on whether the property exists */ jerry_value_t jerry_has_property (const jerry_value_t obj_val, /**< object value */ @@ -2001,17 +2052,15 @@ jerry_has_property (const jerry_value_t obj_val, /**< object value */ return ECMA_VALUE_FALSE; } - bool has_property = ecma_op_object_has_property (ecma_get_object_from_value (obj_val), - ecma_get_prop_name_from_value (prop_name_val)); - - return ecma_make_boolean_value (has_property); + return ecma_op_object_has_property (ecma_get_object_from_value (obj_val), + ecma_get_prop_name_from_value (prop_name_val)); } /* jerry_has_property */ /** * Checks whether the object has the given property. * - * @return true - if the property exists - * false - otherwise + * @return ECMA_VALUE_ERROR - if the operation raises error + * ECMA_VALUE_{TRUE, FALSE} - based on whether the property exists */ jerry_value_t jerry_has_own_property (const jerry_value_t obj_val, /**< object value */ @@ -2025,10 +2074,26 @@ jerry_has_own_property (const jerry_value_t obj_val, /**< object value */ return ECMA_VALUE_FALSE; } - bool has_property = ecma_op_object_has_own_property (ecma_get_object_from_value (obj_val), - ecma_get_prop_name_from_value (prop_name_val)); + ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); + ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (prop_name_val); - return ecma_make_boolean_value (has_property); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_property_descriptor_t prop_desc; + + ecma_value_t status = ecma_proxy_object_get_own_property_descriptor (obj_p, prop_name_p, &prop_desc); + + if (ecma_is_value_true (status)) + { + ecma_free_property_descriptor (&prop_desc); + } + + return jerry_return (status); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ecma_make_boolean_value (ecma_op_ordinary_object_has_own_property (obj_p, prop_name_p)); } /* jerry_has_own_property */ /** @@ -2092,6 +2157,15 @@ jerry_delete_property (const jerry_value_t obj_val, /**< object value */ ecma_value_t ret_value = ecma_op_object_delete (ecma_get_object_from_value (obj_val), ecma_get_prop_name_from_value (prop_name_val), false); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + // TODO: Due to Proxies the return value must be changed to jerry_value_t on next release + jcontext_release_exception (); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return ecma_is_value_true (ret_value); } /* jerry_delete_property */ @@ -2118,6 +2192,14 @@ jerry_delete_property_by_index (const jerry_value_t obj_val, /**< object value * false); ecma_deref_ecma_string (str_idx_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + // TODO: Due to Proxies the return value must be changed to jerry_value_t on next release + jcontext_release_exception (); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return ecma_is_value_true (ret_value); } /* jerry_delete_property_by_index */ @@ -2560,9 +2642,19 @@ jerry_get_own_property_descriptor (const jerry_value_t obj_val, /**< object val ecma_property_descriptor_t prop_desc; - if (!ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (obj_val), - ecma_get_prop_name_from_value (prop_name_val), - &prop_desc)) + ecma_value_t status = ecma_op_object_get_own_property_descriptor (ecma_get_object_from_value (obj_val), + ecma_get_prop_name_from_value (prop_name_val), + &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + // TODO: Due to Proxies the return value must be changed to jerry_value_t on next release + jcontext_release_exception (); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (!ecma_is_value_true (status)) { return false; } @@ -2803,6 +2895,13 @@ jerry_get_prototype (const jerry_value_t obj_val) /**< object value */ ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return jerry_return (ecma_proxy_object_get_prototype_of (obj_p)); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (obj_p->u2.prototype_cp == JMEM_CP_NULL) { return ECMA_VALUE_NULL; @@ -2834,16 +2933,14 @@ jerry_set_prototype (const jerry_value_t obj_val, /**< object value */ } ecma_object_t *obj_p = ecma_get_object_from_value (obj_val); - if (ecma_is_value_null (proto_obj_val)) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) { - obj_p->u2.prototype_cp = JMEM_CP_NULL; - } - else - { - ECMA_SET_NON_NULL_POINTER (obj_p->u2.prototype_cp, ecma_get_object_from_value (proto_obj_val)); + return jerry_return (ecma_proxy_object_set_prototype_of (obj_p, proto_obj_val)); } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ - return ECMA_VALUE_TRUE; + return ecma_op_ordinary_object_set_prototype_of (obj_p, proto_obj_val); } /* jerry_set_prototype */ /** @@ -3073,6 +3170,16 @@ jerry_foreach_object_property (const jerry_value_t obj_val, /**< object value */ ecma_object_t *object_p = ecma_get_object_from_value (obj_val); ecma_collection_t *names_p = ecma_op_object_get_property_names (object_p, ECMA_LIST_ENUMERABLE_PROTOTYPE); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (names_p == NULL) + { + // TODO: Due to Proxies the return value must be changed to jerry_value_t on next release + jcontext_release_exception (); + return false; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t *buffer_p = names_p->buffer_p; ecma_value_t property_value = ECMA_VALUE_EMPTY; diff --git a/jerry-core/config.h b/jerry-core/config.h index 9d0a66383..0e5e8b97a 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -103,6 +103,10 @@ # define JERRY_ES2015_BUILTIN_PROMISE JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_PROMISE) */ +#ifndef JERRY_ES2015_BUILTIN_PROXY +# define JERRY_ES2015_BUILTIN_PROXY JERRY_ES2015 +#endif /* !defined (JERRY_ES2015_BUILTIN_PROXY) */ + #ifndef JERRY_ES2015_BUILTIN_REFLECT # define JERRY_ES2015_BUILTIN_REFLECT JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_REFLECT) */ @@ -543,6 +547,10 @@ || ((JERRY_ES2015_BUILTIN_PROMISE != 0) && (JERRY_ES2015_BUILTIN_PROMISE != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_PROMISE macro." #endif +#if !defined (JERRY_ES2015_BUILTIN_PROXY) \ +|| ((JERRY_ES2015_BUILTIN_PROXY != 0) && (JERRY_ES2015_BUILTIN_PROXY != 1)) +# error "Invalid value for JERRY_ES2015_BUILTIN_PROXY macro." +#endif #if !defined (JERRY_ES2015_BUILTIN_TYPEDARRAY) \ || ((JERRY_ES2015_BUILTIN_TYPEDARRAY != 0) && (JERRY_ES2015_BUILTIN_TYPEDARRAY != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_TYPEDARRAY macro." diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index d58bc4ed6..5d1d3fcb2 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -24,7 +24,9 @@ #include "ecma-globals.h" #include "ecma-gc.h" #include "ecma-helpers.h" +#include "ecma-objects.h" #include "ecma-property-hashmap.h" +#include "ecma-proxy-object.h" #include "jcontext.h" #include "jrt.h" #include "jrt-libc-includes.h" @@ -450,6 +452,29 @@ ecma_gc_mark_executable_object (ecma_object_t *object_p) /**< object */ #endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/** + * Mark the objects referenced by a proxy object + */ +static void +ecma_gc_mark_proxy_object (ecma_object_t *object_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (object_p)); + + ecma_proxy_object_t *proxy_p = (ecma_proxy_object_t *) object_p; + + if (!ecma_is_value_null (proxy_p->target)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (proxy_p->target)); + } + + if (!ecma_is_value_null (proxy_p->handler)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (proxy_p->handler)); + } +} /* ecma_gc_mark_proxy_object */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + /** * Mark objects as visited starting from specified object as root */ @@ -609,6 +634,13 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } break; } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + case ECMA_OBJECT_TYPE_PROXY: + { + ecma_gc_mark_proxy_object (object_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ case ECMA_OBJECT_TYPE_BOUND_FUNCTION: { ecma_gc_mark_bound_function_object (object_p); @@ -643,6 +675,23 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } break; } +#if ENABLED (JERRY_ES2015) + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: + { + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + + if (ext_func_p->u.external_handler_cb == ecma_proxy_revoke_cb) + { + ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) object_p; + + if (!ecma_is_value_null (rev_proxy_p->proxy)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (rev_proxy_p->proxy)); + } + } + break; + } +#endif /* ENABLED (JERRY_ES2015) */ default: { break; @@ -975,6 +1024,14 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: { +#if ENABLED (JERRY_ES2015) + ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + + if (ext_func_p->u.external_handler_cb == ecma_proxy_revoke_cb) + { + ext_object_size = sizeof (ecma_revocable_proxy_object_t); + } +#endif /* ENABLED (JERRY_ES2015) */ break; } case ECMA_OBJECT_TYPE_CLASS: @@ -1138,6 +1195,13 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ break; } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + case ECMA_OBJECT_TYPE_PROXY: + { + ext_object_size = sizeof (ecma_proxy_object_t); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ case ECMA_OBJECT_TYPE_FUNCTION: { /* Function with byte-code (not a built-in function). */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 8339a8aeb..581856563 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -614,6 +614,7 @@ typedef enum ECMA_PROPERTY_GET_NO_OPTIONS = 0, /**< no option flags for ecma_op_object_get_property */ ECMA_PROPERTY_GET_VALUE = 1u << 0, /**< fill virtual_value field for virtual properties */ ECMA_PROPERTY_GET_EXT_REFERENCE = 1u << 1, /**< get extended reference to the property */ + ECMA_PROPERTY_GET_HAS_OWN_PROP = 1u << 2, /**< internal [[HasOwnProperty]] method */ } ecma_property_get_option_bits_t; /** @@ -625,8 +626,9 @@ typedef enum ECMA_OBJECT_TYPE_CLASS = 1, /**< Objects with class property */ ECMA_OBJECT_TYPE_ARRAY = 2, /**< Array object (15.4) */ ECMA_OBJECT_TYPE_PSEUDO_ARRAY = 3, /**< Array-like object, such as Arguments object (10.6) */ + ECMA_OBJECT_TYPE_PROXY = 4, /**< Proxy object ECMAScript v6 26.2 */ /* Note: these 4 types must be in this order. See IsCallable operation. */ - ECMA_OBJECT_TYPE_FUNCTION = 4, /**< Function objects (15.3), created through 13.2 routine */ + ECMA_OBJECT_TYPE_FUNCTION = 5, /**< Function objects (15.3), created through 13.2 routine */ ECMA_OBJECT_TYPE_BOUND_FUNCTION = 6, /**< Function objects (15.3), created through 15.3.4.5 routine */ ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION = 7, /**< External (host) function object */ /* Types between 13-15 cannot have a built-in flag. See ecma_lexical_environment_type_t. */ @@ -837,6 +839,7 @@ typedef struct { ecma_value_t value; /**< value of the object (e.g. boolean, number, string, etc.) */ uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */ + ecma_value_t target; /**< [[ProxyTarget]] internal property */ } u; } class_prop; @@ -1835,6 +1838,32 @@ do \ #define ECMA_CHECK_STACK_USAGE() #endif /* (JERRY_STACK_LIMIT != 0) */ +/** + * Invalid object pointer which represents abrupt completion + */ +#define ECMA_OBJECT_POINTER_ERROR ((ecma_object_t *) 0x01) + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/** + * Description of Proxy objects. + */ +typedef struct +{ + ecma_object_t header; /**< header part */ + ecma_value_t target; /**< [[ProxyTarget]] internal slot */ + ecma_value_t handler; /**< [[ProxyHandler]] internal slot */ +} ecma_proxy_object_t; + +/** + * Description of Proxy objects. + */ +typedef struct +{ + ecma_extended_object_t header; /**< header part */ + ecma_value_t proxy; /**< [[RevocableProxy]] internal slot */ +} ecma_revocable_proxy_object_t; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + /** * @} * @} diff --git a/jerry-core/ecma/base/ecma-helpers-external-pointers.c b/jerry-core/ecma/base/ecma-helpers-external-pointers.c index 12d41641f..b79bf1f00 100644 --- a/jerry-core/ecma/base/ecma-helpers-external-pointers.c +++ b/jerry-core/ecma/base/ecma-helpers-external-pointers.c @@ -17,6 +17,7 @@ #include "ecma-array-object.h" #include "ecma-globals.h" #include "ecma-objects.h" +#include "ecma-objects-general.h" #include "ecma-helpers.h" /** \addtogroup ecma ECMA @@ -193,7 +194,8 @@ ecma_delete_native_pointer_property (ecma_object_t *obj_p, /**< object to delete if (native_pointer_p->next_p == NULL) { /* Only one native pointer property exists, so the property can be deleted as well. */ - ecma_op_object_delete (obj_p, name_p, false); + ecma_op_general_object_delete (obj_p, name_p, false); + jmem_heap_free_block (native_pointer_p, sizeof (ecma_native_pointer_t)); return true; } diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 50efdccb9..7b26d6f41 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -179,40 +179,17 @@ ecma_is_lexical_environment (const ecma_object_t *object_p) /**< object or lexic return full_type >= (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV | ECMA_LEXICAL_ENVIRONMENT_TYPE_START); } /* ecma_is_lexical_environment */ -/** - * Get value of [[Extensible]] object's internal property. - * - * @return true - if object is extensible - * false - otherwise - */ -inline bool JERRY_ATTR_PURE -ecma_get_object_extensible (const ecma_object_t *object_p) /**< object */ -{ - JERRY_ASSERT (object_p != NULL); - JERRY_ASSERT (!ecma_is_lexical_environment (object_p)); - - return (object_p->type_flags_refs & ECMA_OBJECT_FLAG_EXTENSIBLE) != 0; -} /* ecma_get_object_extensible */ - /** * Set value of [[Extensible]] object's internal property. */ inline void -ecma_set_object_extensible (ecma_object_t *object_p, /**< object */ - bool is_extensible) /**< value of [[Extensible]] */ +ecma_op_ordinary_object_set_extensible (ecma_object_t *object_p) /**< object */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (!ecma_is_lexical_environment (object_p)); - if (is_extensible) - { - object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_FLAG_EXTENSIBLE); - } - else - { - object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ~ECMA_OBJECT_FLAG_EXTENSIBLE); - } -} /* ecma_set_object_extensible */ + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_FLAG_EXTENSIBLE); +} /* ecma_op_ordinary_object_set_extensible */ /** * Get object's internal implementation-defined type. diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 5dd8c9498..7bd36d14c 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -159,6 +159,17 @@ typedef enum #define ECMA_ASSERT_VALUE_IS_SYMBOL(value) (false) #endif /* ENABLED (JERRY_ES2015) */ +/** + * Check whether the given object has [[ProxyHandler]] and [[ProxyTarger]] internal slots + * + * @param obj_p ecma-object + */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +#define ECMA_OBJECT_IS_PROXY(obj_p) (JERRY_UNLIKELY (ecma_get_object_type ((obj_p)) == ECMA_OBJECT_TYPE_PROXY)) +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ +#define ECMA_OBJECT_IS_PROXY(obj_p) (false) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + /* ecma-helpers-value.c */ ecma_type_t JERRY_ATTR_CONST ecma_get_value_type_field (ecma_value_t value); bool JERRY_ATTR_CONST ecma_is_value_direct (ecma_value_t value); @@ -367,8 +378,7 @@ ecma_object_t *ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environmen ecma_object_t *ecma_create_object_lex_env (ecma_object_t *outer_lexical_environment_p, ecma_object_t *binding_obj_p, ecma_lexical_environment_type_t type); bool JERRY_ATTR_PURE ecma_is_lexical_environment (const ecma_object_t *object_p); -bool JERRY_ATTR_PURE ecma_get_object_extensible (const ecma_object_t *object_p); -void ecma_set_object_extensible (ecma_object_t *object_p, bool is_extensible); +void ecma_op_ordinary_object_set_extensible (ecma_object_t *object_p); ecma_object_type_t JERRY_ATTR_PURE ecma_get_object_type (const ecma_object_t *object_p); bool JERRY_ATTR_PURE ecma_get_object_is_builtin (const ecma_object_t *object_p); void ecma_set_object_is_builtin (ecma_object_t *object_p); diff --git a/jerry-core/ecma/base/ecma-module.c b/jerry-core/ecma/base/ecma-module.c index 0967a19ce..424f8c8ae 100644 --- a/jerry-core/ecma/base/ecma-module.c +++ b/jerry-core/ecma/base/ecma-module.c @@ -688,7 +688,21 @@ ecma_module_connect_imports (void) lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); } - if (binding_p != NULL || ecma_op_has_binding (lex_env_p, import_names_p->local_name_p)) + if (binding_p != NULL) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Imported binding shadows local variable.")); + } + + ecma_value_t status = ecma_op_has_binding (lex_env_p, import_names_p->local_name_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (status)) { return ecma_raise_syntax_error (ECMA_ERR_MSG ("Imported binding shadows local variable.")); } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index 4fc03e1bb..416804ccc 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -426,7 +426,7 @@ ecma_builtin_array_prototype_object_pop (ecma_object_t *obj_p, /**< array object if (ecma_op_object_is_fast_array (obj_p)) { - if (!ecma_get_object_extensible (obj_p)) + if (!ecma_op_ordinary_object_is_extensible (obj_p)) { ecma_free_value (get_value); return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type.")); @@ -479,7 +479,7 @@ ecma_builtin_array_prototype_object_push (const ecma_value_t *argument_list_p, / if (ecma_op_object_is_fast_array (obj_p)) { - if (!ecma_get_object_extensible (obj_p)) + if (!ecma_op_ordinary_object_is_extensible (obj_p)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type.")); } @@ -554,7 +554,7 @@ ecma_builtin_array_prototype_object_reverse (ecma_value_t this_arg, /**< this ar if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE && len != 0 - && ecma_get_object_extensible (obj_p)) + && ecma_op_ordinary_object_is_extensible (obj_p)) { ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); @@ -592,13 +592,30 @@ ecma_builtin_array_prototype_object_reverse (ecma_value_t this_arg, /**< this ar if (ECMA_IS_VALUE_ERROR (upper_value)) { - upper_value = ECMA_VALUE_EMPTY; goto clean_up; } /* 6.f and 6.g */ - bool lower_exist = ecma_op_object_has_property (obj_p, lower_str_p); - bool upper_exist = ecma_op_object_has_property (obj_p, upper_str_p); + ecma_value_t has_lower = ecma_op_object_has_property (obj_p, lower_str_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_lower)) + { + goto clean_up; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + ecma_value_t has_upper = ecma_op_object_has_property (obj_p, upper_str_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_upper)) + { + goto clean_up; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + bool lower_exist = ecma_is_value_true (has_lower); + bool upper_exist = ecma_is_value_true (has_upper); /* 6.h */ if (lower_exist && upper_exist) @@ -699,7 +716,7 @@ ecma_builtin_array_prototype_object_shift (ecma_object_t *obj_p, /**< array obje if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE && len != 0 - && ecma_get_object_extensible (obj_p)) + && ecma_op_ordinary_object_is_extensible (obj_p)) { ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); ecma_value_t ret_value = buffer_p[0]; @@ -1069,6 +1086,13 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum ecma_collection_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ARRAY_INDICES); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (array_index_props_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + uint32_t defined_prop_count = 0; ecma_value_t *buffer_p = array_index_props_p->buffer_p; @@ -1482,7 +1506,7 @@ ecma_builtin_array_prototype_object_unshift (const ecma_value_t args[], /**< arg if (ext_obj_p->u.array.u.hole_count < ECMA_FAST_ARRAY_HOLE_ONE && len != 0 - && ecma_get_object_extensible (obj_p)) + && ecma_op_ordinary_object_is_extensible (obj_p)) { if ((ecma_number_t) (len + args_number) > UINT32_MAX) { @@ -2236,12 +2260,8 @@ ecma_builtin_array_prototype_fill (ecma_value_t value, /**< value */ /* 11. */ while (k < final) { - /* 11.a */ - ecma_string_t *pk = ecma_new_ecma_string_from_number (k); - - /* 11.b */ - ecma_value_t put_val = ecma_op_object_put (obj_p, pk, value, true); - ecma_deref_ecma_string (pk); + /* 11.a - 11.b */ + ecma_value_t put_val = ecma_op_object_put_by_number_index (obj_p, k, value, true); /* 11. c */ if (ECMA_IS_VALUE_ERROR (put_val)) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c index cfe3bcecf..f97efefb6 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c @@ -23,6 +23,7 @@ #include "ecma-helpers.h" #include "ecma-function-object.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "ecma-try-catch-macro.h" #include "jrt.h" #include "ecma-builtin-function-prototype.h" @@ -210,11 +211,37 @@ ecma_builtin_function_prototype_object_bind (ecma_object_t *this_arg_obj_p , /** /* 4. 11. 18. */ ecma_object_t *prototype_obj_p; -#if ENABLED (JERRY_ES2015) - prototype_obj_p = ECMA_GET_POINTER (ecma_object_t, this_arg_obj_p->u2.prototype_cp); -#else /* !ENABLED (JERRY_ES2015) */ +#if !ENABLED (JERRY_ES2015) prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); -#endif /* ENABLED (JERRY_ES2015) */ +#else /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (this_arg_obj_p)) + { + ecma_value_t proto = ecma_proxy_object_get_prototype_of (this_arg_obj_p); + + if (ECMA_IS_VALUE_ERROR (proto)) + { + return proto; + } + prototype_obj_p = ecma_is_value_null (proto) ? NULL : ecma_get_object_from_value (proto); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (this_arg_obj_p); + if (proto_cp != JMEM_CP_NULL) + { + prototype_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + ecma_ref_object (prototype_obj_p); + } + else + { + prototype_obj_p = NULL; + } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ +#endif /* !ENABLED (JERRY_ES2015) */ ecma_object_t *function_p; ecma_extended_object_t *ext_function_p; @@ -267,6 +294,13 @@ ecma_builtin_function_prototype_object_bind (ecma_object_t *this_arg_obj_p , /** ext_function_p->u.bound_function.args_len_or_this = args_len_or_this; } +#if ENABLED (JERRY_ES2015) + if (prototype_obj_p != NULL) + { + ecma_deref_object (prototype_obj_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + /* * [[Class]] property is not stored explicitly for objects of ECMA_OBJECT_TYPE_FUNCTION type. * diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h index aa2e3efe8..ab7a566f4 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h @@ -246,6 +246,13 @@ OBJECT_VALUE (LIT_MAGIC_STRING_DATAVIEW_UL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/* ECMA-262 v6, 26.2.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROXY_UL, + ECMA_BUILTIN_ID_PROXY, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + /* Routine properties: * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c index 9db4a6dc0..fabad3040 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c @@ -280,26 +280,23 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ { JERRY_ASSERT (obj_p != NULL); - ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false); - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array)); - ecma_object_t *new_array_p = ecma_get_object_from_value (new_array); - ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, opts); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (props_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (props_p->item_count == 0) { ecma_collection_destroy (props_p); - return new_array; + return ecma_op_create_array_object (NULL, 0, false); } - JERRY_ASSERT (ecma_op_object_is_fast_array (new_array_p)); - - ecma_value_t *buffer_p = props_p->buffer_p; - ecma_value_t *values_p = ecma_fast_array_extend (new_array_p, props_p->item_count); - - memcpy (values_p, buffer_p, props_p->item_count * sizeof (ecma_value_t)); - - ecma_collection_free_objects (props_p); + ecma_value_t new_array = ecma_op_create_array_object (props_p->buffer_p, props_p->item_count, false); + ecma_collection_free (props_p); return new_array; } /* ecma_builtin_helper_object_get_properties */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c index cea9da231..adc624be1 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-json.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-json.c @@ -904,6 +904,13 @@ ecma_builtin_json_serialize_object (ecma_json_stringify_context_t *context_p, /* else { property_keys_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ENUMERABLE); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (property_keys_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ } /* 8. */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c index 7a32f6099..b03fcd30b 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c @@ -23,6 +23,7 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "ecma-string-object.h" #include "ecma-try-catch-macro.h" #include "jrt.h" @@ -143,7 +144,23 @@ static ecma_value_t ecma_builtin_object_prototype_object_has_own_property (ecma_object_t *obj_p, /**< this argument */ ecma_string_t *prop_name_p) /**< first argument */ { - return ecma_make_boolean_value (ecma_op_object_has_own_property (obj_p, prop_name_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_property_descriptor_t prop_desc; + + ecma_value_t status = ecma_proxy_object_get_own_property_descriptor (obj_p, prop_name_p, &prop_desc); + + if (ecma_is_value_true (status)) + { + ecma_free_property_descriptor (&prop_desc); + } + + return status; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ecma_make_boolean_value (ecma_op_ordinary_object_has_own_property (obj_p, prop_name_p)); } /* ecma_builtin_object_prototype_object_has_own_property */ /** @@ -169,7 +186,7 @@ ecma_builtin_object_prototype_object_is_prototype_of (ecma_object_t *obj_p, /**< ecma_object_t *v_obj_p = ecma_get_object_from_value (v_obj_value); - ecma_value_t ret_value = ecma_make_boolean_value (ecma_op_object_is_prototype_of (obj_p, v_obj_p)); + ecma_value_t ret_value = ecma_op_object_is_prototype_of (obj_p, v_obj_p); ecma_deref_object (v_obj_p); @@ -189,19 +206,19 @@ static ecma_value_t ecma_builtin_object_prototype_object_property_is_enumerable (ecma_object_t *obj_p, /**< this argument */ ecma_string_t *prop_name_p) /**< first argument */ { - /* 3. */ - ecma_property_t property = ecma_op_object_get_own_property (obj_p, - prop_name_p, - NULL, - ECMA_PROPERTY_GET_NO_OPTIONS); + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, prop_name_p, &prop_desc); - /* 4. */ - if (property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP) + if (!ecma_is_value_true (status)) { - return ecma_make_boolean_value (ecma_is_property_enumerable (property)); + return status; } - return ECMA_VALUE_FALSE; + bool is_enumerable = (prop_desc.flags & ECMA_PROP_IS_ENUMERABLE); + + ecma_free_property_descriptor (&prop_desc); + + return ecma_make_boolean_value (is_enumerable); } /* ecma_builtin_object_prototype_object_property_is_enumerable */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c index be59d07b2..977fc58cf 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c @@ -22,6 +22,7 @@ #include "ecma-globals.h" #include "ecma-helpers.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "ecma-objects-general.h" #include "jrt.h" #include "ecma-builtin-object.h" @@ -136,11 +137,18 @@ ecma_builtin_object_dispatch_construct (const ecma_value_t *arguments_list_p, /* ecma_value_t ecma_builtin_object_object_get_prototype_of (ecma_object_t *obj_p) /**< routine's argument */ { - jmem_cpointer_t prototype_cp = obj_p->u2.prototype_cp; - - if (prototype_cp != JMEM_CP_NULL) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) { - ecma_object_t *prototype_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, prototype_cp); + return ecma_proxy_object_get_prototype_of (obj_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (obj_p); + + if (proto_cp != JMEM_CP_NULL) + { + ecma_object_t *prototype_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); ecma_ref_object (prototype_p); return ecma_make_object_value (prototype_p); } @@ -149,77 +157,6 @@ ecma_builtin_object_object_get_prototype_of (ecma_object_t *obj_p) /**< routine' } /* ecma_builtin_object_object_get_prototype_of */ #if ENABLED (JERRY_ES2015) - -/** - * [[SetPrototypeOf]] - * - * See also: - * ES2015 9.1.2 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_set_prototype_of (ecma_value_t o_value, /**< O */ - ecma_value_t v_value) /**< V */ -{ - /* 1. */ - JERRY_ASSERT (ecma_is_value_object (o_value)); - JERRY_ASSERT (ecma_is_value_object (v_value) || ecma_is_value_null (v_value)); - - ecma_object_t *o_p = ecma_get_object_from_value (o_value); - - jmem_cpointer_t v_cp; - - if (ecma_is_value_null (v_value)) - { - v_cp = JMEM_CP_NULL; - } - else - { - ECMA_SET_NON_NULL_POINTER (v_cp, ecma_get_object_from_value (v_value)); - } - - /* 3., 4. */ - if (v_cp == o_p->u2.prototype_cp) - { - ecma_ref_object (o_p); - return ecma_make_object_value (o_p); - } - - /* 2., 5. */ - if (!ecma_get_object_extensible (o_p)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("cannot set prototype.")); - } - - /* 6., 7., 8. */ - jmem_cpointer_t p_cp = v_cp; - while (p_cp != JMEM_CP_NULL) - { - ecma_object_t *p_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, p_cp); - - /* b. */ - if (p_p == o_p) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("cannot set prototype.")); - } - - /* c.i. TODO: es2015-subset profile does not support having a different - * [[GetPrototypeOf]] internal method */ - - /* c.ii. */ - p_cp = p_p->u2.prototype_cp; - } - - /* 9. */ - o_p->u2.prototype_cp = v_cp; - - /* 10. */ - ecma_ref_object (o_p); - return ecma_make_object_value (o_p); -} /* ecma_set_prototype_of */ - /** * The Object object's 'setPrototypeOf' routine * @@ -251,11 +188,37 @@ ecma_builtin_object_object_set_prototype_of (ecma_value_t arg1, /**< routine's f return ecma_copy_value (arg1); } - /* 6. TODO: es2015-subset profile does not support having a different - * [[SetPrototypeOf]] internal method */ + ecma_object_t *obj_p = ecma_get_object_from_value (arg1); + ecma_value_t status; - /* 5-8. */ - return ecma_set_prototype_of (arg1, arg2); + /* 5. */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + status = ecma_proxy_object_set_prototype_of (obj_p, arg2); + + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + status = ecma_op_ordinary_object_set_prototype_of (obj_p, arg2); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot set [[Prototype]].")); + } + + JERRY_ASSERT (ecma_is_value_true (status)); + ecma_ref_object (obj_p); + + return arg1; } /* ecma_builtin_object_object_set_prototype_of */ #endif /* ENABLED (JERRY_ES2015) */ @@ -294,6 +257,150 @@ ecma_builtin_object_object_get_own_property_symbols (ecma_object_t *obj_p) /**< #endif /* ENABLED (JERRY_ES2015) */ +/** + * SetIntegrityLevel operation + * + * See also: + * ECMA-262 v6, 7.3.14 + * + * @return ECMA_VALUE_ERROR - if the operation raised an error + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the integrity level has been set sucessfully + */ +static ecma_value_t +ecma_builtin_object_set_integrity_level (ecma_object_t *obj_p, /**< object */ + bool is_seal) /**< true - set "sealed" + * false - set "frozen" */ +{ + /* 3. */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_value_t status = ecma_proxy_object_prevent_extensions (obj_p); + + if (!ecma_is_value_true (status)) + { + return status; + } + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_op_ordinary_object_prevent_extensions (obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + /* 6. */ + ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_CONVERT_FAST_ARRAYS); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (props_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + ecma_value_t *buffer_p = props_p->buffer_p; + + if (is_seal) + { + /* 8.a */ + for (uint32_t i = 0; i < props_p->item_count; i++) + { + ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]); + + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (status)) + { + continue; + } + + prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_CONFIGURABLE; + prop_desc.flags |= ECMA_PROP_IS_THROW; + + /* 8.a.i */ + ecma_value_t define_own_prop_ret = ecma_op_object_define_own_property (obj_p, + property_name_p, + &prop_desc); + + ecma_free_property_descriptor (&prop_desc); + + /* 8.a.ii */ + if (ECMA_IS_VALUE_ERROR (define_own_prop_ret)) + { + ecma_collection_free (props_p); + return define_own_prop_ret; + } + + ecma_free_value (define_own_prop_ret); + } + } + else + { + /* 9.a */ + for (uint32_t i = 0; i < props_p->item_count; i++) + { + ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]); + + /* 9.1 */ + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (status)) + { + continue; + } + + /* 9.2 */ + if ((prop_desc.flags & (ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE)) + == (ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE)) + { + prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_WRITABLE; + } + + prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_CONFIGURABLE; + prop_desc.flags |= ECMA_PROP_IS_THROW; + + /* 9.3 */ + ecma_value_t define_own_prop_ret = ecma_op_object_define_own_property (obj_p, + property_name_p, + &prop_desc); + + ecma_free_property_descriptor (&prop_desc); + + /* 9.4 */ + if (ECMA_IS_VALUE_ERROR (define_own_prop_ret)) + { + ecma_collection_free (props_p); + return define_own_prop_ret; + } + + ecma_free_value (define_own_prop_ret); + } + + } + + ecma_collection_free (props_p); + + return ECMA_VALUE_TRUE; +} /* ecma_builtin_object_set_integrity_level */ + /** * The Object object's 'seal' routine * @@ -306,46 +413,19 @@ ecma_builtin_object_object_get_own_property_symbols (ecma_object_t *obj_p) /**< static ecma_value_t ecma_builtin_object_object_seal (ecma_object_t *obj_p) /**< routine's argument */ { - ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_CONVERT_FAST_ARRAYS); + ecma_value_t status = ecma_builtin_object_set_integrity_level (obj_p, true); - ecma_value_t *buffer_p = props_p->buffer_p; - - for (uint32_t i = 0; i < props_p->item_count; i++) + if (ECMA_IS_VALUE_ERROR (status)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]); - - /* 2.a */ - ecma_property_descriptor_t prop_desc; - - if (!ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc)) - { - continue; - } - - /* 2.b */ - prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_CONFIGURABLE; - prop_desc.flags |= ECMA_PROP_IS_THROW; - - /* 2.c */ - ecma_value_t define_own_prop_ret = ecma_op_object_define_own_property (obj_p, - property_name_p, - &prop_desc); - - ecma_free_property_descriptor (&prop_desc); - - if (ECMA_IS_VALUE_ERROR (define_own_prop_ret)) - { - ecma_collection_free (props_p); - return define_own_prop_ret; - } - - ecma_free_value (define_own_prop_ret); + return status; } - ecma_collection_free (props_p); - - /* 3. */ - ecma_set_object_extensible (obj_p, false); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Object cannot be sealed.")); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ /* 4. */ ecma_ref_object (obj_p); @@ -364,53 +444,19 @@ ecma_builtin_object_object_seal (ecma_object_t *obj_p) /**< routine's argument * static ecma_value_t ecma_builtin_object_object_freeze (ecma_object_t *obj_p) /**< routine's argument */ { - ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_CONVERT_FAST_ARRAYS); + ecma_value_t status = ecma_builtin_object_set_integrity_level (obj_p, false); - ecma_value_t *buffer_p = props_p->buffer_p; - - for (uint32_t i = 0; i < props_p->item_count; i++) + if (ECMA_IS_VALUE_ERROR (status)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]); - - /* 2.a */ - ecma_property_descriptor_t prop_desc; - - if (!ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc)) - { - continue; - } - - /* 2.b */ - if ((prop_desc.flags & (ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE)) - == (ECMA_PROP_IS_WRITABLE_DEFINED | ECMA_PROP_IS_WRITABLE)) - { - prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_WRITABLE; - } - - /* 2.c */ - prop_desc.flags &= (uint16_t) ~ECMA_PROP_IS_CONFIGURABLE; - prop_desc.flags |= ECMA_PROP_IS_THROW; - - /* 2.d */ - ecma_value_t define_own_prop_ret = ecma_op_object_define_own_property (obj_p, - property_name_p, - &prop_desc); - - ecma_free_property_descriptor (&prop_desc); - - if (ECMA_IS_VALUE_ERROR (define_own_prop_ret)) - { - ecma_collection_free (props_p); - return define_own_prop_ret; - } - - ecma_free_value (define_own_prop_ret); + return status; } - ecma_collection_free (props_p); - - /* 3. */ - ecma_set_object_extensible (obj_p, false); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Object cannot be frozen.")); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ /* 4. */ ecma_ref_object (obj_p); @@ -429,7 +475,30 @@ ecma_builtin_object_object_freeze (ecma_object_t *obj_p) /**< routine's argument ecma_value_t ecma_builtin_object_object_prevent_extensions (ecma_object_t *obj_p) /**< routine's argument */ { - ecma_set_object_extensible (obj_p, false); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_value_t status = ecma_proxy_object_prevent_extensions (obj_p); + + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + if (ecma_is_value_false (status)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Cannot set [[Extensible]] property of the object.")); + } + + JERRY_ASSERT (ecma_is_value_true (status)); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_op_ordinary_object_prevent_extensions (obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_ref_object (obj_p); return ecma_make_object_value (obj_p); @@ -446,13 +515,34 @@ ecma_builtin_object_object_prevent_extensions (ecma_object_t *obj_p) /**< routin * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine's argument */ - int mode) /**< routine mode */ +ecma_builtin_object_test_integrity_level (ecma_object_t *obj_p, /**< routine's argument */ + int mode) /**< routine mode */ { JERRY_ASSERT (mode == ECMA_OBJECT_ROUTINE_IS_FROZEN || mode == ECMA_OBJECT_ROUTINE_IS_SEALED); /* 3. */ - if (ecma_get_object_extensible (obj_p)) + bool is_extensible; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_value_t status = ecma_proxy_object_is_extensible (obj_p); + + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } + + is_extensible = ecma_is_value_true (status); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + is_extensible = ecma_op_ordinary_object_is_extensible (obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (is_extensible) { return ECMA_VALUE_FALSE; } @@ -463,6 +553,13 @@ ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine' /* 2. */ ecma_collection_t *props_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_NO_OPTS); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (props_p == NULL) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t *buffer_p = props_p->buffer_p; for (uint32_t i = 0; i < props_p->item_count; i++) @@ -470,22 +567,32 @@ ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine' ecma_string_t *property_name_p = ecma_get_string_from_value (buffer_p[i]); /* 2.a */ - ecma_property_t property = ecma_op_object_get_own_property (obj_p, - property_name_p, - NULL, - ECMA_PROPERTY_GET_NO_OPTIONS); + ecma_property_descriptor_t prop_desc; + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, property_name_p, &prop_desc); - /* 2.b for isFrozen */ - if (mode == ECMA_OBJECT_ROUTINE_IS_FROZEN - && ECMA_PROPERTY_GET_TYPE (property) != ECMA_PROPERTY_TYPE_NAMEDACCESSOR - && ecma_is_property_writable (property)) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) { - ret_value = ECMA_VALUE_FALSE; + ret_value = status; break; } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (ecma_is_value_false (status)) + { + continue; + } + + bool is_writable_data = ((prop_desc.flags & (ECMA_PROP_IS_VALUE_DEFINED | ECMA_PROP_IS_WRITABLE)) + == (ECMA_PROP_IS_VALUE_DEFINED | ECMA_PROP_IS_WRITABLE)); + bool is_configurable = (prop_desc.flags & ECMA_PROP_IS_CONFIGURABLE); + + ecma_free_property_descriptor (&prop_desc); + + /* 2.b for isFrozen */ /* 2.b for isSealed, 2.c for isFrozen */ - if (ecma_is_property_configurable (property)) + if ((mode == ECMA_OBJECT_ROUTINE_IS_FROZEN && is_writable_data) + || is_configurable) { ret_value = ECMA_VALUE_FALSE; break; @@ -495,7 +602,7 @@ ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine' ecma_collection_free (props_p); return ret_value; -} /* ecma_builtin_object_frozen_or_sealed_helper */ +} /* ecma_builtin_object_test_integrity_level */ /** * The Object object's 'isExtensible' routine @@ -509,7 +616,14 @@ ecma_builtin_object_frozen_or_sealed_helper (ecma_object_t *obj_p, /**< routine' ecma_value_t ecma_builtin_object_object_is_extensible (ecma_object_t *obj_p) /**< routine's argument */ { - return ecma_make_boolean_value (ecma_get_object_extensible (obj_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_proxy_object_is_extensible (obj_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ecma_make_boolean_value (ecma_op_ordinary_object_is_extensible (obj_p)); } /* ecma_builtin_object_object_is_extensible */ /** @@ -543,7 +657,16 @@ ecma_builtin_object_object_get_own_property_descriptor (ecma_object_t *obj_p, /* /* 3. */ ecma_property_descriptor_t prop_desc; - if (ecma_op_object_get_own_property_descriptor (obj_p, name_str_p, &prop_desc)) + ecma_value_t status = ecma_op_object_get_own_property_descriptor (obj_p, name_str_p, &prop_desc); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (status)) + { + return status; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (status)) { /* 4. */ ecma_object_t *desc_obj_p = ecma_op_from_property_descriptor (&prop_desc); @@ -583,6 +706,14 @@ ecma_builtin_object_object_define_properties (ecma_object_t *obj_p, /**< routine | ECMA_LIST_ENUMERABLE); ecma_value_t ret_value = ECMA_VALUE_ERROR; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (prop_names_p == NULL) + { + ecma_deref_object (props_p); + return ret_value; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t *buffer_p = prop_names_p->buffer_p; /* 4. */ @@ -783,6 +914,13 @@ ecma_builtin_object_object_assign (ecma_object_t *target_p, /**< target object * ecma_collection_t *props_p = ecma_op_object_get_property_names (from_obj_p, ECMA_LIST_CONVERT_FAST_ARRAYS | ECMA_LIST_ENUMERABLE | ECMA_LIST_SYMBOLS); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (props_p == NULL) + { + ecma_deref_object (from_obj_p); + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_value_t *buffer_p = props_p->buffer_p; @@ -792,8 +930,17 @@ ecma_builtin_object_object_assign (ecma_object_t *target_p, /**< target object * /* 5.c.i-ii */ ecma_property_descriptor_t prop_desc; + ecma_value_t desc_status = ecma_op_object_get_own_property_descriptor (from_obj_p, property_name_p, &prop_desc); - if (!ecma_op_object_get_own_property_descriptor (from_obj_p, property_name_p, &prop_desc)) +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (desc_status)) + { + ret_value = desc_status; + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (desc_status)) { continue; } @@ -1056,8 +1203,7 @@ ecma_builtin_object_dispatch_routine (uint16_t builtin_routine_id, /**< built-in case ECMA_OBJECT_ROUTINE_IS_SEALED: case ECMA_OBJECT_ROUTINE_IS_FROZEN: { - return ecma_builtin_object_frozen_or_sealed_helper (obj_p, - builtin_routine_id); + return ecma_builtin_object_test_integrity_level (obj_p, builtin_routine_id); } case ECMA_OBJECT_ROUTINE_IS_EXTENSIBLE: { diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.c b/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.c new file mode 100644 index 000000000..73875eab0 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.c @@ -0,0 +1,120 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-proxy-object.h" +#include "jrt.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-proxy.inc.h" +#define BUILTIN_UNDERSCORED_ID proxy +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup proxy ECMA Proxy object built-in + * @{ + */ + +/** + * The Proxy object's 'revocable' routine + * + * See also: + * ES2015 26.2.2.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_proxy_object_revocable (ecma_value_t this_arg, /**< 'this' argument */ + ecma_value_t target, /**< target argument */ + ecma_value_t handler) /**< handler argument */ +{ + JERRY_UNUSED (this_arg); + + ecma_object_t *rev_proxy_p = ecma_proxy_create_revocable (target, handler); + + if (JERRY_UNLIKELY (rev_proxy_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + return ecma_make_object_value (rev_proxy_p); +} /* ecma_builtin_proxy_object_revocable */ + +/** + * Handle calling [[Call]] of built-in Proxy object + * + * See also: + * ES2015 26.2.2 + * + * @return raised error + */ +ecma_value_t +ecma_builtin_proxy_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + /* 1. */ + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor Proxy requires 'new'")); +} /* ecma_builtin_proxy_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in proxy object + * + * See also: + * ES2015 26.2.2 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * new proxy object - otherwise + */ +ecma_value_t +ecma_builtin_proxy_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + /* 2. */ + ecma_object_t *proxy_p = ecma_proxy_create (arguments_list_len > 0 ? arguments_list_p[0] : ECMA_VALUE_UNDEFINED, + arguments_list_len > 1 ? arguments_list_p[1] : ECMA_VALUE_UNDEFINED); + + if (JERRY_UNLIKELY (proxy_p == NULL)) + { + return ECMA_VALUE_ERROR; + } + + return ecma_make_object_value (proxy_p); +} /* ecma_builtin_proxy_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.inc.h new file mode 100644 index 000000000..cfe4be575 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-proxy.inc.h @@ -0,0 +1,38 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Proxy object built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 2, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ + +ROUTINE (LIT_MAGIC_STRING_REVOCABLE, ecma_builtin_proxy_object_revocable, 2, 2) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c index 8de9fb1c9..4734da96d 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-reflect.c @@ -124,7 +124,7 @@ ecma_builtin_reflect_dispatch_routine (uint16_t builtin_routine_id, /**< built-i case ECMA_REFLECT_OBJECT_HAS: { - ret_value = ecma_make_boolean_value (ecma_op_object_has_property (target_p, name_str_p)); + ret_value = ecma_op_object_has_property (target_p, name_str_p); break; } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.c b/jerry-core/ecma/builtin-objects/ecma-builtins.c index 891e0fe70..427da99e7 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -384,7 +384,14 @@ ecma_instantiate_builtin (ecma_builtin_id_t obj_builtin_id) /**< built-in id */ ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, ext_object_size, obj_type); - ecma_set_object_extensible (obj_p, (obj_builtin_id != ECMA_BUILTIN_ID_TYPE_ERROR_THROWER)); + if (JERRY_UNLIKELY (obj_builtin_id == ECMA_BUILTIN_ID_TYPE_ERROR_THROWER)) + { + ecma_op_ordinary_object_prevent_extensions (obj_p); + } + else + { + ecma_op_ordinary_object_set_extensible (obj_p); + } /* * [[Class]] property of built-in object is not stored explicitly. @@ -986,7 +993,7 @@ ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in uint32_t bit_for_index = (uint32_t) 1u << index; - if (!(*bitset_p & bit_for_index) || ecma_op_object_has_own_property (object_p, name_p)) + if (!(*bitset_p & bit_for_index) || ecma_op_ordinary_object_has_own_property (object_p, name_p)) { ecma_value_t name = ecma_make_magic_string_value ((lit_magic_string_id_t) curr_property_p->magic_string_id); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h index a50ad4673..0d86ff556 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -507,6 +507,15 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_WEAKSET, #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/* The Proxy routine (ECMA-262 v6, 26.2.1) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_PROXY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + proxy) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + #if ENABLED (JERRY_ES2015) /* Intrinsic hidden builtin object */ diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index f52e47989..ba9ea55fe 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -24,6 +24,7 @@ #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-objects-arguments.h" +#include "ecma-proxy-object.h" #include "ecma-try-catch-macro.h" #include "jcontext.h" @@ -75,6 +76,13 @@ ecma_op_object_is_callable (ecma_object_t *obj_p) /**< ecma object */ { JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_op_is_callable (((ecma_proxy_object_t *) obj_p)->target); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return ecma_get_object_type (obj_p) >= ECMA_OBJECT_TYPE_FUNCTION; } /* ecma_op_object_is_callable */ @@ -104,6 +112,13 @@ ecma_object_is_constructor (ecma_object_t *obj_p) /**< ecma object */ { JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_is_constructor (((ecma_proxy_object_t *) obj_p)->target); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_object_type_t type = ecma_get_object_type (obj_p); if (type == ECMA_OBJECT_TYPE_FUNCTION) @@ -523,7 +538,27 @@ ecma_op_implicit_class_constructor_has_instance (ecma_object_t *func_obj_p, /**< while (true) { - jmem_cpointer_t v_obj_cp = v_obj_p->u2.prototype_cp; + jmem_cpointer_t v_obj_cp; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (v_obj_p)) + { + ecma_value_t parent = ecma_proxy_object_get_prototype_of (v_obj_p); + + if (ECMA_IS_VALUE_ERROR (parent)) + { + ecma_deref_object (prototype_obj_p); + return parent; + } + + v_obj_cp = ecma_proxy_object_prototype_to_cp (parent); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + v_obj_cp = ecma_op_ordinary_object_get_prototype_of (v_obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ if (v_obj_cp == JMEM_CP_NULL) { @@ -611,14 +646,40 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * ecma_object_t *prototype_obj_p = ecma_get_object_from_value (prototype_obj_value); JERRY_ASSERT (prototype_obj_p != NULL); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + ecma_value_t result = ECMA_VALUE_ERROR; +#else /* !ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_value_t result = ECMA_VALUE_FALSE; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ while (true) { - jmem_cpointer_t v_obj_cp = v_obj_p->u2.prototype_cp; + jmem_cpointer_t v_obj_cp; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (v_obj_p)) + { + ecma_value_t parent = ecma_proxy_object_get_prototype_of (v_obj_p); + + if (ECMA_IS_VALUE_ERROR (parent)) + { + break; + } + + v_obj_cp = ecma_proxy_object_prototype_to_cp (parent); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + v_obj_cp = ecma_op_ordinary_object_get_prototype_of (v_obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ if (v_obj_cp == JMEM_CP_NULL) { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + result = ECMA_VALUE_FALSE; +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ break; } @@ -1119,7 +1180,17 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ { JERRY_ASSERT (func_obj_p != NULL && !ecma_is_lexical_environment (func_obj_p)); - JERRY_ASSERT (ecma_op_is_callable (ecma_make_object_value (func_obj_p))); + JERRY_ASSERT (ecma_op_object_is_callable (func_obj_p)); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (func_obj_p)) + { + return ecma_proxy_object_call (func_obj_p, + this_arg_value, + arguments_list_p, + arguments_list_len); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION || ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION @@ -1275,6 +1346,16 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */ JERRY_ASSERT (ecma_is_value_object (this_arg_value) || this_arg_value == ECMA_VALUE_UNDEFINED); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (func_obj_p)) + { + return ecma_proxy_object_construct (func_obj_p, + arguments_list_p, + arguments_list_len, + ecma_make_object_value (func_obj_p)); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_object_t *target_func_obj_p = NULL; while (JERRY_UNLIKELY (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION)) diff --git a/jerry-core/ecma/operations/ecma-get-put-value.c b/jerry-core/ecma/operations/ecma-get-put-value.c index eba5a0672..9c716ec9d 100644 --- a/jerry-core/ecma/operations/ecma-get-put-value.c +++ b/jerry-core/ecma/operations/ecma-get-put-value.c @@ -90,6 +90,11 @@ ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme ecma_value_t result = ecma_op_object_find (binding_obj_p, name_p); + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + if (ecma_is_value_found (result)) { *ref_base_lex_env_p = lex_env_p; @@ -272,7 +277,16 @@ ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - if (ecma_op_object_has_property (binding_obj_p, name_p)) + ecma_value_t has_property = ecma_op_object_has_property (binding_obj_p, name_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_property)) + { + return has_property; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (has_property)) { ecma_value_t completion = ecma_op_object_put (binding_obj_p, name_p, diff --git a/jerry-core/ecma/operations/ecma-lex-env.c b/jerry-core/ecma/operations/ecma-lex-env.c index 3b244e6f4..4bd0308f6 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.c +++ b/jerry-core/ecma/operations/ecma-lex-env.c @@ -124,7 +124,7 @@ ecma_get_global_scope (void) * * @return true / false */ -bool +ecma_value_t ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_string_t *name_p) /**< argument N */ { @@ -137,16 +137,14 @@ ecma_op_has_binding (ecma_object_t *lex_env_p, /**< lexical environment */ { ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); - return (property_p != NULL); + return ecma_make_boolean_value (property_p != NULL); } - else - { - JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - return ecma_op_object_has_property (binding_obj_p, name_p); - } + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + + return ecma_op_object_has_property (binding_obj_p, name_p); } /* ecma_op_has_binding */ /** @@ -186,7 +184,7 @@ ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, /**< lexical environme ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - if (!ecma_get_object_extensible (binding_obj_p)) + if (!ecma_op_ordinary_object_is_extensible (binding_obj_p)) { return ECMA_VALUE_EMPTY; } @@ -299,6 +297,11 @@ ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */ ecma_value_t result = ecma_op_object_find (binding_obj_p, name_p); + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + if (!ecma_is_value_found (result)) { if (is_strict) @@ -321,8 +324,8 @@ ecma_op_get_binding_value (ecma_object_t *lex_env_p, /**< lexical environment */ * See also: ECMA-262 v5, 10.2.1 * * @return ecma value - * Return value is simple and so need not be freed. - * However, ecma_free_value may be called for it, but it is a no-op. + * Return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the binding can be deleted */ ecma_value_t ecma_op_delete_binding (ecma_object_t *lex_env_p, /**< lexical environment */ diff --git a/jerry-core/ecma/operations/ecma-lex-env.h b/jerry-core/ecma/operations/ecma-lex-env.h index c43c3b147..e7860f5b1 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.h +++ b/jerry-core/ecma/operations/ecma-lex-env.h @@ -55,7 +55,7 @@ ecma_value_t ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, ecma_stri bool is_strict, ecma_value_t value); /* ECMA-262 v5, Table 17. Abstract methods of Environment Records */ -bool ecma_op_has_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p); +ecma_value_t ecma_op_has_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p); ecma_value_t ecma_op_create_mutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, bool is_deletable); ecma_value_t ecma_op_set_mutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value, bool is_strict); diff --git a/jerry-core/ecma/operations/ecma-objects-general.c b/jerry-core/ecma/operations/ecma-objects-general.c index 90506466f..48f5da45f 100644 --- a/jerry-core/ecma/operations/ecma-objects-general.c +++ b/jerry-core/ecma/operations/ecma-objects-general.c @@ -22,6 +22,7 @@ #include "ecma-helpers.h" #include "ecma-objects.h" #include "ecma-objects-general.h" +#include "ecma-proxy-object.h" #include "ecma-try-catch-macro.h" /** \addtogroup ecma ECMA @@ -362,6 +363,13 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob const ecma_property_descriptor_t *property_desc_p) /**< property * descriptor */ { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_define_own_property (object_p, property_name_p, property_desc_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p)); @@ -403,7 +411,7 @@ ecma_op_general_object_define_own_property (ecma_object_t *object_p, /**< the ob if (current_prop == ECMA_PROPERTY_TYPE_NOT_FOUND || current_prop == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP) { /* 3. */ - if (!ecma_get_object_extensible (object_p)) + if (!ecma_op_ordinary_object_is_extensible (object_p)) { /* 2. */ return ecma_reject (property_desc_p->flags & ECMA_PROP_IS_THROW); diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 19111b8d5..42ae0e4a8 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -26,6 +26,7 @@ #include "ecma-objects-arguments.h" #include "ecma-objects-general.h" #include "ecma-objects.h" +#include "ecma-proxy-object.h" #include "jcontext.h" #if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) @@ -75,8 +76,13 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ { JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ JERRY_ASSERT (property_name_p != NULL); - JERRY_ASSERT (options == ECMA_PROPERTY_GET_NO_OPTIONS || property_ref_p != NULL); + JERRY_ASSERT (options == ECMA_PROPERTY_GET_NO_OPTIONS + || options == ECMA_PROPERTY_GET_HAS_OWN_PROP + || property_ref_p != NULL); ecma_object_type_t type = ecma_get_object_type (object_p); @@ -287,7 +293,7 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ } } else if (type == ECMA_OBJECT_TYPE_PSEUDO_ARRAY - && property_ref_p != NULL) + && (options & ECMA_PROPERTY_GET_HAS_OWN_PROP)) { ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; @@ -378,39 +384,43 @@ ecma_op_object_get_property (ecma_object_t *object_p, /**< the object */ } /* ecma_op_object_get_property */ /** - * Checks whether an object (excluding prototypes) has a named property + * Generic [[HasProperty]] operation * - * @return true - if property is found - * false - otherwise - */ -inline bool JERRY_ATTR_ALWAYS_INLINE -ecma_op_object_has_own_property (ecma_object_t *object_p, /**< the object */ - ecma_string_t *property_name_p) /**< property name */ -{ - ecma_property_ref_t property_ref; - ecma_property_t property = ecma_op_object_get_own_property (object_p, - property_name_p, - &property_ref, - ECMA_PROPERTY_GET_NO_OPTIONS); - - return property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP; -} /* ecma_op_object_has_own_property */ - -/** - * Checks whether an object (including prototypes) has a named property + * See also: + * ECMAScript v6, 9.1.7.1 * - * @return true - if property is found - * false - otherwise + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE_FALSE} - whether the property is found */ -inline bool JERRY_ATTR_ALWAYS_INLINE +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE ecma_op_object_has_property (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p) /**< property name */ { - ecma_property_t property = ecma_op_object_get_property (object_p, - property_name_p, - NULL, - ECMA_PROPERTY_GET_NO_OPTIONS); - return property != ECMA_PROPERTY_TYPE_NOT_FOUND; + while (true) + { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_has (object_p, property_name_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + /* 2 - 3. */ + if (ecma_op_ordinary_object_has_own_property (object_p, property_name_p)) + { + return ECMA_VALUE_TRUE; + } + + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p); + + /* 7. */ + if (proto_cp == JMEM_CP_NULL) + { + return ECMA_VALUE_FALSE; + } + + object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + } } /* ecma_op_object_has_property */ /** @@ -430,6 +440,7 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); JERRY_ASSERT (property_name_p != NULL); + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); ecma_object_type_t type = ecma_get_object_type (object_p); @@ -705,6 +716,13 @@ ecma_op_object_find (ecma_object_t *object_p, /**< the object */ while (true) { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_find (object_p, property_name_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t value = ecma_op_object_find_own (base_value, object_p, property_name_p); if (ecma_is_value_found (value)) @@ -770,30 +788,11 @@ ecma_op_object_get_own_data_prop (ecma_object_t *object_p, /**< the object */ * @return ecma value * Returned value must be freed with ecma_free_value */ -ecma_value_t +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE ecma_op_object_get (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p) /**< property name */ { - ecma_value_t base_value = ecma_make_object_value (object_p); - - while (true) - { - ecma_value_t value = ecma_op_object_find_own (base_value, object_p, property_name_p); - - if (ecma_is_value_found (value)) - { - return value; - } - - if (object_p->u2.prototype_cp == JMEM_CP_NULL) - { - break; - } - - object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp); - } - - return ECMA_VALUE_UNDEFINED; + return ecma_op_object_get_with_receiver (object_p, property_name_p, ecma_make_object_value (object_p)); } /* ecma_op_object_get */ /** @@ -817,6 +816,13 @@ ecma_op_object_get_with_receiver (ecma_object_t *object_p, /**< the object */ { while (true) { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_get (object_p, property_name_p, receiver); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t value = ecma_op_object_find_own (receiver, object_p, property_name_p); if (ecma_is_value_found (value)) @@ -824,12 +830,14 @@ ecma_op_object_get_with_receiver (ecma_object_t *object_p, /**< the object */ return value; } - if (object_p->u2.prototype_cp == JMEM_CP_NULL) + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p); + + if (proto_cp == JMEM_CP_NULL) { break; } - object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp); + object_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); } return ECMA_VALUE_UNDEFINED; @@ -1149,6 +1157,13 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */ && !ecma_is_lexical_environment (object_p)); JERRY_ASSERT (property_name_p != NULL); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_set (object_p, property_name_p, value, receiver); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_object_type_t type = ecma_get_object_type (object_p); switch (type) @@ -1169,7 +1184,7 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */ if (JERRY_LIKELY (ecma_op_array_is_fast_array (ext_object_p))) { - if (JERRY_UNLIKELY (!ecma_get_object_extensible (object_p))) + if (JERRY_UNLIKELY (!ecma_op_ordinary_object_is_extensible (object_p))) { return ecma_reject (is_throw); } @@ -1354,10 +1369,12 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */ { bool create_new_property = true; - if (object_p->u2.prototype_cp != JMEM_CP_NULL) + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (object_p); + + if (proto_cp != JMEM_CP_NULL) { ecma_property_ref_t property_ref = { NULL }; - ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, object_p->u2.prototype_cp); + ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); ecma_property_t inherited_property = ecma_op_object_get_property (proto_p, property_name_p, @@ -1379,7 +1396,7 @@ ecma_op_object_put_with_receiver (ecma_object_t *object_p, /**< the object */ } if (create_new_property - && ecma_get_object_extensible (object_p)) + && ecma_op_ordinary_object_is_extensible (object_p)) { const ecma_object_type_t obj_type = ecma_get_object_type (object_p); @@ -1526,6 +1543,13 @@ ecma_op_object_delete (ecma_object_t *obj_p, /**< the object */ } } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_proxy_object_delete_property (obj_p, property_name_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + JERRY_ASSERT_OBJECT_TYPE_IS_VALID (ecma_get_object_type (obj_p)); return ecma_op_general_object_delete (obj_p, @@ -1591,6 +1615,13 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ const ecma_object_type_t type = ecma_get_object_type (obj_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_proxy_object_define_own_property (obj_p, property_name_p, property_desc_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + switch (type) { case ECMA_OBJECT_TYPE_GENERAL: @@ -1691,11 +1722,18 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ * @return true - if property found * false - otherwise */ -bool +ecma_value_t ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the object */ ecma_string_t *property_name_p, /**< property name */ ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */ { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + return ecma_proxy_object_get_own_property_descriptor (object_p, property_name_p, prop_desc_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_property_ref_t property_ref; ecma_property_t property = ecma_op_object_get_own_property (object_p, @@ -1705,7 +1743,7 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob if (property == ECMA_PROPERTY_TYPE_NOT_FOUND || property == ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP) { - return false; + return ECMA_VALUE_FALSE; } *prop_desc_p = ecma_make_empty_property_descriptor (); @@ -1760,7 +1798,7 @@ ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, /**< the ob } } - return true; + return ECMA_VALUE_TRUE; } /* ecma_op_object_get_own_property_descriptor */ /** @@ -1795,27 +1833,46 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ * See also: * ECMA-262 v5, 15.2.4.6; 3 * - * @return true - if the target object is prototype of the base object - * false - if the target object is not prototype of the base object + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_TRUE - if the target object is prototype of the base object + * ECMA_VALUE_FALSE - if the target object is not prototype of the base object */ -bool +ecma_value_t ecma_op_object_is_prototype_of (ecma_object_t *base_p, /**< base object */ ecma_object_t *target_p) /**< target object */ { do { - jmem_cpointer_t target_cp = target_p->u2.prototype_cp; + jmem_cpointer_t target_cp; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (target_p)) + { + ecma_value_t target_proto = ecma_proxy_object_get_prototype_of (target_p); + + if (ECMA_IS_VALUE_ERROR (target_proto)) + { + return target_proto; + } + target_cp = ecma_proxy_object_prototype_to_cp (target_proto); + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + target_cp = ecma_op_ordinary_object_get_prototype_of (target_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ if (target_cp == JMEM_CP_NULL) { - return false; + return ECMA_VALUE_FALSE; } target_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, target_cp); if (target_p == base_p) { - return true; + return ECMA_VALUE_TRUE; } } while (true); } /* ecma_op_object_is_prototype_of */ @@ -1832,7 +1889,8 @@ ecma_op_object_is_prototype_of (ecma_object_t *base_p, /**< base object */ * property list, and the list is not reordered (in other words, properties are stored in order that is reversed * to the properties' addition order). * - * @return collection of strings - property names + * @return NULL - if the Proxy.[[OwnPropertyKeys]] operation raises error + * collection of property names - otherwise */ ecma_collection_t * ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ @@ -1841,6 +1899,13 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + return ecma_proxy_object_own_property_keys (obj_p); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (ecma_op_object_is_fast_array (obj_p)) { return ecma_fast_array_get_property_names (obj_p, opts); @@ -2480,7 +2545,7 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ } default: { - JERRY_ASSERT (type == ECMA_OBJECT_TYPE_GENERAL); + JERRY_ASSERT (type == ECMA_OBJECT_TYPE_GENERAL || type == ECMA_OBJECT_TYPE_PROXY); if (ecma_get_object_is_builtin (obj_p)) { @@ -2524,6 +2589,12 @@ ecma_object_get_class_name (ecma_object_t *obj_p) /**< object */ { return LIT_MAGIC_STRING_ERROR_UL; } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + case ECMA_BUILTIN_ID_PROXY: + { + return LIT_MAGIC_STRING_FUNCTION_UL; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ default: { JERRY_ASSERT (ecma_object_check_class_name_is_object (obj_p)); @@ -2766,6 +2837,142 @@ ecma_op_invoke (ecma_value_t object, /**< Object value */ return call_result; } /* ecma_op_invoke */ +/** + * Ordinary object [[GetPrototypeOf]] operation + * + * See also: + * ECMAScript v6, 9.1.1 + * + * @return the value of the [[Prototype]] internal slot of the given object. + */ +inline jmem_cpointer_t JERRY_ATTR_ALWAYS_INLINE +ecma_op_ordinary_object_get_prototype_of (ecma_object_t *obj_p) /**< object */ +{ + JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (obj_p)); + + return obj_p->u2.prototype_cp; +} /* ecma_op_ordinary_object_get_prototype_of */ + +/** + * Ordinary object [[SetPrototypeOf]] operation + * + * See also: + * ECMAScript v6, 9.1.2 + * + * @return ECMA_VALUE_FALSE - if the operation fails + * ECMA_VALUE_TRUE - otherwise + */ +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE +ecma_op_ordinary_object_set_prototype_of (ecma_object_t *obj_p, /**< base object */ + ecma_value_t proto) /**< prototype object */ +{ + JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (obj_p)); + + /* 1. */ + JERRY_ASSERT (ecma_is_value_object (proto) || ecma_is_value_null (proto)); + + /* 3. */ + ecma_object_t *current_proto_p = ECMA_GET_POINTER (ecma_object_t, ecma_op_ordinary_object_get_prototype_of (obj_p)); + ecma_object_t *new_proto_p = ecma_is_value_null (proto) ? NULL : ecma_get_object_from_value (proto); + + /* 4. */ + if (new_proto_p == current_proto_p) + { + return ECMA_VALUE_TRUE; + } + + /* 2 - 5. */ + if (!ecma_op_ordinary_object_is_extensible (obj_p)) + { + return ECMA_VALUE_FALSE; + } + + /* 6. */ + ecma_object_t *iter_p = new_proto_p; + + /* 7 - 8. */ + while (true) + { + /* 8.a */ + if (iter_p == NULL) + { + break; + } + + /* 8.b */ + if (obj_p == iter_p) + { + return ECMA_VALUE_FALSE; + } + + /* 8.c.i */ +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (iter_p)) + { + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + /* 8.c.ii */ + iter_p = ECMA_GET_POINTER (ecma_object_t, ecma_op_ordinary_object_get_prototype_of (iter_p)); + } + + /* 9. */ + ECMA_SET_POINTER (obj_p->u2.prototype_cp, new_proto_p); + + /* 10. */ + return ECMA_VALUE_TRUE; +} /* ecma_op_ordinary_object_set_prototype_of */ + +/** + * [[IsExtensible]] operation for Ordinary object. + * + * See also: + * ECMAScript v6, 9.1.2 + * + * @return true - if object is extensible + * false - otherwise + */ +inline bool JERRY_ATTR_PURE +ecma_op_ordinary_object_is_extensible (ecma_object_t *object_p) /**< object */ +{ + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); + + return (object_p->type_flags_refs & ECMA_OBJECT_FLAG_EXTENSIBLE) != 0; +} /* ecma_op_ordinary_object_is_extensible */ + +/** + * Set value of [[Extensible]] object's internal property. + */ +void JERRY_ATTR_NOINLINE +ecma_op_ordinary_object_prevent_extensions (ecma_object_t *object_p) /**< object */ +{ + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); + object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ~ECMA_OBJECT_FLAG_EXTENSIBLE); +} /* ecma_op_ordinary_object_prevent_extensions */ + +/** + * Checks whether an object (excluding prototypes) has a named property + * + * @return true - if property is found + * false - otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +ecma_op_ordinary_object_has_own_property (ecma_object_t *object_p, /**< the object */ + ecma_string_t *property_name_p) /**< property name */ +{ + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); + + ecma_property_t property = ecma_op_object_get_own_property (object_p, + property_name_p, + NULL, + ECMA_PROPERTY_GET_HAS_OWN_PROP); + + return property != ECMA_PROPERTY_TYPE_NOT_FOUND && property != ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP; +} /* ecma_op_ordinary_object_has_own_property */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index 9986d4ca8..26a8df369 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -29,8 +29,8 @@ ecma_property_t ecma_op_object_get_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_property_ref_t *property_ref_p, uint32_t options); -bool ecma_op_object_has_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p); -bool ecma_op_object_has_property (ecma_object_t *object_p, ecma_string_t *property_name_p); +bool ecma_op_ordinary_object_has_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p); +ecma_value_t ecma_op_object_has_property (ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_find_own (ecma_value_t base_value, ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_find (ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_find_by_uint32_index (ecma_object_t *object_p, uint32_t index); @@ -52,6 +52,8 @@ ecma_value_t ecma_op_object_put_with_receiver (ecma_object_t *object_p, ecma_str ecma_value_t value, ecma_value_t receiver, bool is_throw); ecma_value_t ecma_op_object_put (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_value_t value, bool is_throw); +ecma_value_t ecma_op_object_put_with_receiver (ecma_object_t *object_p, ecma_string_t *property_name_p, + ecma_value_t value, ecma_value_t receiver, bool is_throw); ecma_value_t ecma_op_object_put_by_uint32_index (ecma_object_t *object_p, uint32_t index, ecma_value_t value, bool is_throw); ecma_value_t ecma_op_object_put_by_number_index (ecma_object_t *object_p, ecma_number_t index, @@ -62,10 +64,10 @@ ecma_value_t ecma_op_object_delete_by_number_index (ecma_object_t *obj_p, ecma_n ecma_value_t ecma_op_object_default_value (ecma_object_t *obj_p, ecma_preferred_type_hint_t hint); ecma_value_t ecma_op_object_define_own_property (ecma_object_t *obj_p, ecma_string_t *property_name_p, const ecma_property_descriptor_t *property_desc_p); -bool ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, ecma_string_t *property_name_p, - ecma_property_descriptor_t *prop_desc_p); +ecma_value_t ecma_op_object_get_own_property_descriptor (ecma_object_t *object_p, ecma_string_t *property_name_p, + ecma_property_descriptor_t *prop_desc_p); ecma_value_t ecma_op_object_has_instance (ecma_object_t *obj_p, ecma_value_t value); -bool ecma_op_object_is_prototype_of (ecma_object_t *base_p, ecma_object_t *target_p); +ecma_value_t ecma_op_object_is_prototype_of (ecma_object_t *base_p, ecma_object_t *target_p); ecma_collection_t * ecma_op_object_get_property_names (ecma_object_t *obj_p, uint32_t opts); lit_magic_string_id_t ecma_object_get_class_name (ecma_object_t *obj_p); @@ -81,6 +83,11 @@ ecma_value_t ecma_op_invoke (ecma_value_t object, ecma_string_t *property_name_p ecma_value_t ecma_op_invoke_by_magic_id (ecma_value_t object, lit_magic_string_id_t magic_string_id, ecma_value_t *args_p, ecma_length_t args_len); +jmem_cpointer_t ecma_op_ordinary_object_get_prototype_of (ecma_object_t *obj_p); +ecma_value_t ecma_op_ordinary_object_set_prototype_of (ecma_object_t *base_p, ecma_value_t proto); +bool JERRY_ATTR_PURE ecma_op_ordinary_object_is_extensible (ecma_object_t *object_p); +void ecma_op_ordinary_object_prevent_extensions (ecma_object_t *object_p); + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-proxy-object.c b/jerry-core/ecma/operations/ecma-proxy-object.c new file mode 100644 index 000000000..f1741657b --- /dev/null +++ b/jerry-core/ecma/operations/ecma-proxy-object.c @@ -0,0 +1,552 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecma-alloc.h" +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-function-object.h" +#include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-objects.h" +#include "ecma-objects-general.h" +#include "ecma-proxy-object.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmaproxyobject ECMA Proxy object related routines + * @{ + */ + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +/** + * Check whether the argument satifies the requrements of [[ProxyTarget]] or [[ProxyHandler]] + * + * See also: + * ES2015 9.5.15.1-2 + * ES2015 9.5.15.3-4 + * + * @return true - if the arguments can be a valid [[ProxyTarget]] or [[ProxyHandler]] + * false - otherwise + */ +static bool +ecma_proxy_validate (ecma_value_t argument) /**< argument to validate */ +{ + if (ecma_is_value_object (argument)) + { + ecma_object_t *obj_p = ecma_get_object_from_value (argument); + + return (!ECMA_OBJECT_IS_PROXY (obj_p) + || !ecma_is_value_null (((ecma_proxy_object_t *) obj_p)->handler)); + } + + return false; +} /* ecma_proxy_validate */ + +/** + * ProxyCreate operation for create a new proxy object + * + * See also: + * ES2015 9.5.15 + * + * @return created Proxy object as an ecma-value - if success + * raised error - otherwise + */ +ecma_object_t * +ecma_proxy_create (ecma_value_t target, /**< proxy target */ + ecma_value_t handler) /**< proxy handler */ +{ + /* 1 - 4. */ + if (!ecma_proxy_validate (target) || !ecma_proxy_validate (handler)) + { + ecma_raise_type_error (ECMA_ERR_MSG ("Cannot create proxy with a non-object target or handler")); + return NULL; + } + + /* 5 - 6. */ + ecma_object_t *obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), + sizeof (ecma_proxy_object_t), + ECMA_OBJECT_TYPE_PROXY); + + ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p; + + /* 8. */ + proxy_obj_p->target = target; + /* 9. */ + proxy_obj_p->handler = handler; + + /* 10. */ + return obj_p; +} /* ecma_proxy_create */ + +/** + * Definition of Proxy Revocation Function + * + * See also: + * ES2015 26.2.2.1.1 + * + * @return ECMA_VALUE_UNDEFINED + */ +ecma_value_t +ecma_proxy_revoke_cb (const ecma_value_t function_obj, /**< the function itself */ + const ecma_value_t this_val, /**< this_arg of the function */ + const ecma_value_t args_p[], /**< argument list */ + const ecma_length_t args_count) /**< argument number */ +{ + JERRY_UNUSED_3 (this_val, args_p, args_count); + + ecma_object_t *func_obj_p = ecma_get_object_from_value (function_obj); + + /* 1. */ + ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) func_obj_p; + + /* 2. */ + if (ecma_is_value_null (rev_proxy_p->proxy)) + { + return ECMA_VALUE_UNDEFINED; + } + + /* 4. */ + ecma_proxy_object_t *proxy_p = (ecma_proxy_object_t *) ecma_get_object_from_value (rev_proxy_p->proxy); + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY ((ecma_object_t *) proxy_p)); + + /* 3. */ + rev_proxy_p->proxy = ECMA_VALUE_NULL; + + /* 5. */ + proxy_p->target = ECMA_VALUE_NULL; + + /* 6. */ + proxy_p->handler = ECMA_VALUE_NULL; + + /* 7. */ + return ECMA_VALUE_UNDEFINED; +} /* ecma_proxy_revoke_cb */ + +/** + * Proxy.revocable operation for create a new revocable proxy object + * + * See also: + * ES2015 26.2.2.1 + * + * @return NULL - if the operation fails + * pointer to the newly created revocable proxy object - otherwise + */ +ecma_object_t * +ecma_proxy_create_revocable (ecma_value_t target, /**< target argument */ + ecma_value_t handler) /**< handler argument */ +{ + /* 1. */ + ecma_object_t *proxy_p = ecma_proxy_create (target, handler); + + /* 2. */ + if (proxy_p == NULL) + { + return proxy_p; + } + + ecma_value_t proxy_value = ecma_make_object_value (proxy_p); + + /* 3. */ + ecma_object_t *func_obj_p; + func_obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE), + sizeof (ecma_revocable_proxy_object_t), + ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION); + + ecma_revocable_proxy_object_t *rev_proxy_p = (ecma_revocable_proxy_object_t *) func_obj_p; + rev_proxy_p->header.u.external_handler_cb = ecma_proxy_revoke_cb; + /* 4. */ + rev_proxy_p->proxy = proxy_value; + + ecma_property_value_t *prop_value_p; + ecma_value_t revoker = ecma_make_object_value (func_obj_p); + + /* 5. */ + ecma_object_t *obj_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), + 0, + ECMA_OBJECT_TYPE_GENERAL); + + /* 6. */ + prop_value_p = ecma_create_named_data_property (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_PROXY), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + prop_value_p->value = proxy_value; + + /* 7. */ + prop_value_p = ecma_create_named_data_property (obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_REVOKE), + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + prop_value_p->value = revoker; + + ecma_deref_object (proxy_p); + ecma_deref_object (func_obj_p); + + /* 8. */ + return obj_p; +} /* ecma_proxy_create_revocable */ + +/** + * Internal find property operation for Proxy object + * + * Note: Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_NOT_FOUND - if the property is not found + * value of the property - otherwise + */ +ecma_value_t +ecma_proxy_object_find (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p) /**< property name */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + + ecma_value_t has_result = ecma_proxy_object_has (obj_p, prop_name_p); + + if (ECMA_IS_VALUE_ERROR (has_result)) + { + return has_result; + } + + if (ecma_is_value_false (has_result)) + { + return ECMA_VALUE_NOT_FOUND; + } + + return ecma_proxy_object_get (obj_p, prop_name_p, ecma_make_object_value (obj_p)); +} /* ecma_proxy_object_find */ + +/** + * Convert the result of the ecma_proxy_object_get_prototype_of to compressed pointer + * + * Note: if `proto` is non-null, the reference from the object is released + * + * @return compressed pointer to the `proto` value + */ +jmem_cpointer_t +ecma_proxy_object_prototype_to_cp (ecma_value_t proto) /**< ECMA_VALUE_NULL or object */ +{ + JERRY_ASSERT (ecma_is_value_null (proto) || ecma_is_value_object (proto)); + + if (ecma_is_value_null (proto)) + { + return JMEM_CP_NULL; + } + + jmem_cpointer_t proto_cp; + ecma_object_t *proto_obj_p = ecma_get_object_from_value (proto); + ECMA_SET_POINTER (proto_cp, proto_obj_p); + ecma_deref_object (proto_obj_p); + + return proto_cp; +} /* ecma_proxy_object_prototype_to_cp */ + +/* Interal operations */ + +/** + * The Proxy object [[GetPrototypeOf]] internal routine + * + * See also: + * ECMAScript v6, 9.5.1 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_NULL or valid object (prototype) otherwise + */ +ecma_value_t +ecma_proxy_object_get_prototype_of (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED (obj_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[GetPrototypeOf]]")); +} /* ecma_proxy_object_get_prototype_of */ + +/** + * The Proxy object [[SetPrototypeOf]] internal routine + * + * See also: + * ECMAScript v6, 9.5.2 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the new prototype can be set for the given object + */ +ecma_value_t +ecma_proxy_object_set_prototype_of (ecma_object_t *obj_p, /**< proxy object */ + ecma_value_t proto) /**< new prototype object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_ASSERT (ecma_is_value_object (proto) || ecma_is_value_null (proto)); + JERRY_UNUSED_2 (obj_p, proto); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[SetPrototypeOf]]")); +} /* ecma_proxy_object_set_prototype_of */ + +/** + * The Proxy object [[isExtensible]] internal routine + * + * See also: + * ECMAScript v6, 9.5.3 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the object is extensible + */ +ecma_value_t +ecma_proxy_object_is_extensible (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED (obj_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[IsExtensible]]")); +} /* ecma_proxy_object_is_extensible */ + +/** + * The Proxy object [[PreventExtensions]] internal routine + * + * See also: + * ECMAScript v6, 9.5.4 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the object can be set as inextensible + */ +ecma_value_t +ecma_proxy_object_prevent_extensions (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED (obj_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[PreventExtensions]]")); +} /* ecma_proxy_object_prevent_extensions */ + +/** + * The Proxy object [[GetOwnProperty]] internal routine + * + * See also: + * ECMAScript v6, 9.5.5 + * + * Note: - Returned value is always a simple value so freeing it is unnecessary. + * - If the operation does not fail, freeing the filled property descriptor is the caller's responsibility + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE_FALSE} - depends on whether object has property with the given name + */ +ecma_value_t +ecma_proxy_object_get_own_property_descriptor (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p, /**< property name */ + ecma_property_descriptor_t *prop_desc_p) /**< [out] property + * descriptor */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED_3 (obj_p, prop_name_p, prop_desc_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[GetOwnProperty]]")); +} /* ecma_proxy_object_get_own_property_descriptor */ + +/** + * The Proxy object [[DefineOwnProperty]] internal routine + * + * See also: + * ECMAScript v6, 9.5.6 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE_FALSE} - depends on whether the property can be defined for the given object + */ +ecma_value_t +ecma_proxy_object_define_own_property (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p, /**< property name */ + const ecma_property_descriptor_t *prop_desc_p) /**< property descriptor */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED_3 (obj_p, prop_name_p, prop_desc_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[DefineOwnProperty]]")); +} /* ecma_proxy_object_define_own_property */ + +/** + * The Proxy object [[HasProperty]] internal routine + * + * See also: + * ECMAScript v6, 9.5.7 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE_FALSE} - depends on whether the property is found + */ +ecma_value_t +ecma_proxy_object_has (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p) /**< property name */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED_2 (obj_p, prop_name_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[HasProperty]]")); +} /* ecma_proxy_object_has */ + +/** + * The Proxy object [[Get]] internal routine + * + * See also: + * ECMAScript v6, 9.5.8 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * value of the given nameddata property or the result of the getter function call - otherwise + */ +ecma_value_t +ecma_proxy_object_get (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p, /**< property name */ + ecma_value_t receiver) /**< receiver to invoke getter function */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED_3 (obj_p, prop_name_p, receiver); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Get]]")); +} /* ecma_proxy_object_get */ + +/** + * The Proxy object [[Set]] internal routine + * + * See also: + * ECMAScript v6, 9.5.9 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the propety can be set to the given object + */ +ecma_value_t +ecma_proxy_object_set (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p, /**< property name */ + ecma_value_t value, /**< value to set */ + ecma_value_t receiver) /**< receiver to invoke setter function */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED_4 (obj_p, prop_name_p, value, receiver); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Set]]")); +} /* ecma_proxy_object_set */ + +/** + * The Proxy object [[Delete]] internal routine + * + * See also: + * ECMAScript v6, 9.5.10 + * + * Note: Returned value is always a simple value so freeing it is unnecessary. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_{TRUE/FALSE} - depends on whether the propety can be deleted + */ +ecma_value_t +ecma_proxy_object_delete_property (ecma_object_t *obj_p, /**< proxy object */ + ecma_string_t *prop_name_p) /**< property name */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED_2 (obj_p, prop_name_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Delete]]")); +} /* ecma_proxy_object_delete_property */ + +/** + * The Proxy object [[Enumerate]] internal routine + * + * See also: + * ECMAScript v6, 9.5.11 + * + * Note: Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ecma-object - otherwise + */ +ecma_value_t +ecma_proxy_object_enumerate (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED (obj_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Enumerate]]")); +} /* ecma_proxy_object_enumerate */ + +/** + * The Proxy object [[OwnPropertyKeys]] internal routine + * + * See also: + * ECMAScript v6, 9.5.12 + * + * Note: If the returned collection is not NULL, it must be freed with + * ecma_collection_free if it is no longer needed + * + * @return NULL - if the operation fails + * pointer to a newly allocated list of property names - otherwise + */ +ecma_collection_t * +ecma_proxy_object_own_property_keys (ecma_object_t *obj_p) /**< proxy object */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED (obj_p); + ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[OwnPropertyKeys]]")); + return NULL; +} /* ecma_proxy_object_own_property_keys */ + +/** + * The Proxy object [[Call]] internal routine + * + * See also: + * ECMAScript v6, 9.5.13 + * + * Note: Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * result of the function call - otherwise + */ +ecma_value_t +ecma_proxy_object_call (ecma_object_t *obj_p, /**< proxy object */ + ecma_value_t this_argument, /**< this argument to invoke the function */ + const ecma_value_t *args_p, /**< argument list */ + ecma_length_t argc) /**< number of arguments */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED_4 (obj_p, this_argument, args_p, argc); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Call]]")); +} /* ecma_proxy_object_call */ + +/** + * The Proxy object [[Construct]] internal routine + * + * See also: + * ECMAScript v6, 9.5.14 + * + * Note: Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_ERROR - if the operation fails + * result of the construct call - otherwise + */ +ecma_value_t +ecma_proxy_object_construct (ecma_object_t *obj_p, /**< proxy object */ + const ecma_value_t *args_p, /**< argument list */ + ecma_length_t argc, /**< number of arguments */ + ecma_value_t new_target) /**< this argument to invoke the function */ +{ + JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p)); + JERRY_UNUSED_4 (obj_p, args_p, argc, new_target); + return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Construct]]")); +} /* ecma_proxy_object_construct */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +/** + * @} + * @} + */ diff --git a/jerry-core/ecma/operations/ecma-proxy-object.h b/jerry-core/ecma/operations/ecma-proxy-object.h new file mode 100644 index 000000000..f8a6991f9 --- /dev/null +++ b/jerry-core/ecma/operations/ecma-proxy-object.h @@ -0,0 +1,120 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMA_PROXY_OBJECT_H +#define ECMA_PROXY_OBJECT_H + +#include "ecma-globals.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmaproxyobject ECMA Proxy object related routines + * @{ + */ + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + +ecma_object_t * +ecma_proxy_create (ecma_value_t target, + ecma_value_t handler); + +ecma_object_t * +ecma_proxy_create_revocable (ecma_value_t target, + ecma_value_t handler); + +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); + +jmem_cpointer_t +ecma_proxy_object_prototype_to_cp (ecma_value_t proto); + +ecma_value_t +ecma_proxy_object_find (ecma_object_t *obj_p, + ecma_string_t *prop_name_p); + +/* Interal operations */ + +ecma_value_t +ecma_proxy_object_get_prototype_of (ecma_object_t *obj_p); + +ecma_value_t +ecma_proxy_object_set_prototype_of (ecma_object_t *obj_p, + ecma_value_t proto); + +ecma_value_t +ecma_proxy_object_is_extensible (ecma_object_t *obj_p); + +ecma_value_t +ecma_proxy_object_prevent_extensions (ecma_object_t *obj_p); + +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); + +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); + +ecma_value_t +ecma_proxy_object_has (ecma_object_t *obj_p, + ecma_string_t *prop_name_p); + +ecma_value_t +ecma_proxy_object_get (ecma_object_t *obj_p, + ecma_string_t *prop_name_p, + ecma_value_t receiver); + +ecma_value_t +ecma_proxy_object_set (ecma_object_t *obj_p, + ecma_string_t *prop_name_p, + ecma_value_t name, + ecma_value_t receiver); + +ecma_value_t +ecma_proxy_object_delete_property (ecma_object_t *obj_p, + ecma_string_t *prop_name_p); + +ecma_value_t +ecma_proxy_object_enumerate (ecma_object_t *obj_p); + +ecma_collection_t * +ecma_proxy_object_own_property_keys (ecma_object_t *obj_p); + +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); + +ecma_value_t +ecma_proxy_object_construct (ecma_object_t *obj_p, + const ecma_value_t *args_p, + ecma_length_t argc, + ecma_value_t new_target); + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +/** + * @} + * @} + */ + +#endif /* !ECMA_PROXY_OBJECT_H */ diff --git a/jerry-core/ecma/operations/ecma-reference.c b/jerry-core/ecma/operations/ecma-reference.c index cba1d4c4e..191730f29 100644 --- a/jerry-core/ecma/operations/ecma-reference.c +++ b/jerry-core/ecma/operations/ecma-reference.c @@ -34,9 +34,9 @@ /** * Resolve syntactic reference. * - * @return if reference was resolved successfully, - * pointer to lexical environment - reference's base, - * else - NULL. + * @return ECMA_OBJECT_POINTER_ERROR - if the operation fails + * pointer to lexical environment - if the reference's base is resolved sucessfully, + * NULL - otherwise. */ ecma_object_t * ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical environment */ @@ -54,7 +54,16 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical } #endif /* ENABLED (JERRY_ES2015) */ - if (ecma_op_has_binding (lex_env_p, name_p)) + ecma_value_t has_binding = ecma_op_has_binding (lex_env_p, name_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_binding)) + { + return ECMA_OBJECT_POINTER_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (has_binding)) { return lex_env_p; } @@ -221,6 +230,11 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical ecma_value_t prop_value = ecma_op_object_find (binding_obj_p, name_p); + if (ECMA_IS_VALUE_ERROR (prop_value)) + { + return prop_value; + } + if (ecma_is_value_found (prop_value)) { #if ENABLED (JERRY_ES2015) diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 2223686ba..1cfbf386f 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -99,6 +99,7 @@ typedef enum JERRY_FEATURE_LOGGING, /**< logging */ JERRY_FEATURE_SYMBOL, /**< symbol support */ JERRY_FEATURE_DATAVIEW, /**< DataView support */ + JERRY_FEATURE_PROXY, /**< Proxy support */ JERRY_FEATURE__COUNT /**< number of features. NOTE: must be at the end of the list */ } jerry_feature_t; @@ -379,6 +380,7 @@ bool jerry_value_is_number (const jerry_value_t value); bool jerry_value_is_null (const jerry_value_t value); bool jerry_value_is_object (const jerry_value_t value); bool jerry_value_is_promise (const jerry_value_t value); +bool jerry_value_is_proxy (const jerry_value_t value); bool jerry_value_is_string (const jerry_value_t value); bool jerry_value_is_symbol (const jerry_value_t value); bool jerry_value_is_undefined (const jerry_value_t value); @@ -493,6 +495,7 @@ jerry_value_t jerry_create_number_nan (void); jerry_value_t jerry_create_null (void); jerry_value_t jerry_create_object (void); jerry_value_t jerry_create_promise (void); +jerry_value_t jerry_create_proxy (const jerry_value_t target, const jerry_value_t handler); jerry_value_t jerry_create_regexp (const jerry_char_t *pattern, uint16_t flags); jerry_value_t jerry_create_regexp_sz (const jerry_char_t *pattern, jerry_size_t pattern_size, uint16_t flags); jerry_value_t jerry_create_string_from_utf8 (const jerry_char_t *str_p); diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index ec5ca613e..cfc52f06c 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -195,6 +195,11 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ARRAY_UL, "Array") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ERROR_UL, "Error") #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LOG2E_U, "LOG2E") +#endif +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROXY_UL, "Proxy") +#endif +#if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SQRT2_U, "SQRT2") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_APPLY, "apply") @@ -232,6 +237,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MATCH, "match") || ENABLED (JERRY_BUILTIN_JSON) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PARSE, "parse") #endif +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROXY, "proxy") +#endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ROUND, "round") #endif @@ -327,6 +335,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REPEAT, "repeat") #if ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RETURN, "return") #endif +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REVOKE, "revoke") +#endif #if ENABLED (JERRY_BUILTIN_REGEXP) && ENABLED (JERRY_BUILTIN_STRING) \ || ENABLED (JERRY_ES2015) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEARCH, "search") @@ -560,6 +571,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LASTINDEX_UL, "lastIndex") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MULTILINE, "multiline") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PROTOTYPE, "prototype") +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_REVOCABLE, "revocable") +#endif #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UINT16_UL, "setUint16") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UINT32_UL, "setUint32") diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 2a3da322a..762a2adac 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -93,6 +93,7 @@ LIT_MAGIC_STRING_TRIM = "trim" LIT_MAGIC_STRING_TRUE = "true" LIT_MAGIC_STRING_ARRAY_UL = "Array" LIT_MAGIC_STRING_ERROR_UL = "Error" +LIT_MAGIC_STRING_PROXY_UL = "Proxy" LIT_MAGIC_STRING_LOG2E_U = "LOG2E" LIT_MAGIC_STRING_SQRT2_U = "SQRT2" LIT_MAGIC_STRING_APPLY = "apply" @@ -108,6 +109,7 @@ LIT_MAGIC_STRING_INPUT = "input" LIT_MAGIC_STRING_IS_NAN = "isNaN" LIT_MAGIC_STRING_MATCH = "match" LIT_MAGIC_STRING_PARSE = "parse" +LIT_MAGIC_STRING_PROXY = "proxy" LIT_MAGIC_STRING_ROUND = "round" LIT_MAGIC_STRING_SHIFT = "shift" LIT_MAGIC_STRING_SLICE = "slice" @@ -144,6 +146,7 @@ LIT_MAGIC_STRING_RANDOM = "random" LIT_MAGIC_STRING_REDUCE = "reduce" LIT_MAGIC_STRING_REJECT = "reject" LIT_MAGIC_STRING_REPEAT = "repeat" +LIT_MAGIC_STRING_REVOKE = "revoke" LIT_MAGIC_STRING_RETURN = "return" LIT_MAGIC_STRING_SEARCH = "search" LIT_MAGIC_STRING_SOURCE = "source" @@ -233,6 +236,7 @@ LIT_MAGIC_STRING_GET_UINT32_UL = "getUint32" LIT_MAGIC_STRING_LASTINDEX_UL = "lastIndex" LIT_MAGIC_STRING_MULTILINE = "multiline" LIT_MAGIC_STRING_PROTOTYPE = "prototype" +LIT_MAGIC_STRING_REVOCABLE = "revocable" LIT_MAGIC_STRING_STRINGIFY = "stringify" LIT_MAGIC_STRING_SET_UINT16_UL = "setUint16" LIT_MAGIC_STRING_SET_UINT32_UL = "setUint32" diff --git a/jerry-core/parser/js/js-parser-tagged-template-literal.c b/jerry-core/parser/js/js-parser-tagged-template-literal.c index 9088ae7f0..cb4dca972 100644 --- a/jerry-core/parser/js/js-parser-tagged-template-literal.c +++ b/jerry-core/parser/js/js-parser-tagged-template-literal.c @@ -19,6 +19,7 @@ #include "ecma-builtin-helpers.h" #include "ecma-gc.h" #include "ecma-helpers.h" +#include "ecma-objects.h" /* \addtogroup parser Parser * @{ @@ -126,7 +127,7 @@ parser_tagged_template_literal_freeze_array (ecma_object_t *obj_p) { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY); - ecma_set_object_extensible (obj_p, false); + ecma_op_ordinary_object_prevent_extensions (obj_p); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; uint8_t new_prop_value = (uint8_t) (ext_obj_p->u.array.u.length_prop & ~ECMA_PROPERTY_FLAG_WRITABLE); ext_obj_p->u.array.u.length_prop = new_prop_value; diff --git a/jerry-core/vm/opcodes-ecma-relational-equality.c b/jerry-core/vm/opcodes-ecma-relational-equality.c index a811e90f7..5fe14577d 100644 --- a/jerry-core/vm/opcodes-ecma-relational-equality.c +++ b/jerry-core/vm/opcodes-ecma-relational-equality.c @@ -167,8 +167,7 @@ opfunc_in (ecma_value_t left_value, /**< left value */ } ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value); - ecma_value_t result = ecma_make_boolean_value (ecma_op_object_has_property (right_value_obj_p, - property_name_p)); + ecma_value_t result = ecma_op_object_has_property (right_value_obj_p, property_name_p); ecma_deref_ecma_string (property_name_p); return result; } /* opfunc_in */ diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 1c60c8db4..529b0694c 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -44,13 +44,25 @@ * 'Variable declaration' opcode handler. * * See also: ECMA-262 v5, 10.5 - Declaration binding instantiation (block 8). + * + * @return ECMA_VALUE_ERROR - if no the operation fails + * ECMA_VALUE_EMPTY - otherwise */ -inline void JERRY_ATTR_ALWAYS_INLINE +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE vm_var_decl (ecma_object_t *lex_env_p, /**< target lexical environment */ ecma_string_t *var_name_str_p, /**< variable name */ bool is_configurable_bindings) /**< true if the binding can be deleted */ { - if (!ecma_op_has_binding (lex_env_p, var_name_str_p)) + ecma_value_t has_binding = ecma_op_has_binding (lex_env_p, var_name_str_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (has_binding)) + { + return has_binding; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_false (has_binding)) { ecma_value_t completion_value = ecma_op_create_mutable_binding (lex_env_p, var_name_str_p, @@ -65,12 +77,17 @@ vm_var_decl (ecma_object_t *lex_env_p, /**< target lexical environment */ var_name_str_p, vm_is_strict_mode ()))); } + + return ECMA_VALUE_EMPTY; } /* vm_var_decl */ /** * Set var binding to a function literal value. + * + * @return ECMA_VALUE_ERROR - if no the operation fails + * ECMA_VALUE_EMPTY - otherwise */ -inline void JERRY_ATTR_ALWAYS_INLINE +inline ecma_value_t JERRY_ATTR_ALWAYS_INLINE vm_set_var (ecma_object_t *lex_env_p, /**< target lexical environment */ ecma_string_t *var_name_str_p, /**< variable name */ bool is_strict, /**< true, if the engine is in strict mode */ @@ -83,12 +100,9 @@ vm_set_var (ecma_object_t *lex_env_p, /**< target lexical environment */ || ecma_is_value_empty (put_value_result) || ECMA_IS_VALUE_ERROR (put_value_result)); - if (ECMA_IS_VALUE_ERROR (put_value_result)) - { - jcontext_release_exception (); - } - ecma_free_value (lit_value); + + return put_value_result; } /* vm_set_var */ /** @@ -206,7 +220,7 @@ vm_op_delete_prop (ecma_value_t object, /**< base object */ JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); ecma_value_t delete_op_ret = ecma_op_object_delete (obj_p, name_string_p, is_strict); - JERRY_ASSERT (ecma_is_value_boolean (delete_op_ret) || (is_strict == true && ECMA_IS_VALUE_ERROR (delete_op_ret))); + JERRY_ASSERT (ecma_is_value_boolean (delete_op_ret) || ECMA_IS_VALUE_ERROR (delete_op_ret)); ecma_deref_object (obj_p); ecma_deref_ecma_string (name_string_p); @@ -229,6 +243,13 @@ vm_op_delete_var (ecma_value_t name_literal, /**< name literal */ ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (lex_env_p, var_name_str_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (JERRY_UNLIKELY (ref_base_lex_env_p == ECMA_OBJECT_POINTER_ERROR)) + { + return ECMA_VALUE_ERROR; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + if (ref_base_lex_env_p == NULL) { completion_value = ECMA_VALUE_TRUE; @@ -267,6 +288,9 @@ opfunc_for_in (ecma_value_t left_value, /**< left value */ /* ecma_op_to_object will only raise error on null/undefined values but those are handled above. */ JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (obj_expr_value)); ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (obj_p)); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ ecma_collection_t *prop_names_p = ecma_op_object_get_property_names (obj_p, ECMA_LIST_ENUMERABLE_PROTOTYPE); if (prop_names_p->item_count != 0) diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 6b384efbc..43c8fdd49 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -56,10 +56,10 @@ typedef enum */ #define OPFUNC_HAS_SPREAD_ELEMENT (1 << 8) -void +ecma_value_t vm_var_decl (ecma_object_t *lex_env_p, ecma_string_t *var_name_str_p, bool is_configurable_bindings); -void +ecma_value_t vm_set_var (ecma_object_t *lex_env_p, ecma_string_t *var_name_str_p, bool is_strict, ecma_value_t lit_value); ecma_value_t diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index fbffc5a1b..17310cb4e 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -185,7 +185,7 @@ vm_op_set_value (ecma_value_t object, /**< base object */ } object_p = ecma_get_object_from_value (to_object); - ecma_set_object_extensible (object_p, false); + ecma_op_ordinary_object_prevent_extensions (object_p); } else { @@ -1321,11 +1321,21 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } #endif /* ENABLED (JERRY_ES2015) && !JERRY_NDEBUG */ - vm_var_decl (lex_env_p, name_p, frame_ctx_p->is_eval_code); + result = vm_var_decl (lex_env_p, name_p, frame_ctx_p->is_eval_code); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } if (lit_value != ECMA_VALUE_UNDEFINED) { - vm_set_var (lex_env_p, name_p, is_strict, lit_value); + result = vm_set_var (lex_env_p, name_p, is_strict, lit_value); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } } continue; @@ -1423,7 +1433,22 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); } - if (binding_p != NULL || ecma_op_has_binding (lex_env_p, literal_name_p)) + if (binding_p != NULL) + { + result = ecma_raise_syntax_error (ECMA_ERR_MSG ("Local variable is redeclared.")); + goto error; + } + + result = ecma_op_has_binding (lex_env_p, literal_name_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + if (ecma_is_value_true (result)) { result = ecma_raise_syntax_error (ECMA_ERR_MSG ("Local variable is redeclared.")); goto error; @@ -1486,7 +1511,13 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } #endif /* ENABLED (JERRY_ES2015) && !JERRY_NDEBUG */ - vm_set_var (lex_env_p, name_p, is_strict, left_value); + result = vm_set_var (lex_env_p, name_p, is_strict, left_value); + + if (ECMA_IS_VALUE_ERROR (result)) + { + goto error; + } + continue; } case VM_OC_CLONE_CONTEXT: @@ -3421,6 +3452,20 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (VM_GET_REGISTERS (frame_ctx_p) + register_end + frame_ctx_p->context_depth == stack_top_p); +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ecma_is_value_object (value) + && ECMA_OBJECT_IS_PROXY (ecma_get_object_from_value (value))) + { + /* Note: - For proxy objects we should create a new object which implements the iterable protocol, + and iterates through the enumerated collection below. + - This inkoves that the VM context type should be adjusted and checked in all FOR-IN related + instruction. + - For other objects we should keep the current implementation due to performance reasons.*/ + result = ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy support in for-in.")); + goto error; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + ecma_value_t expr_obj_value = ECMA_VALUE_UNDEFINED; ecma_collection_t *prop_names_p = opfunc_for_in (value, &expr_obj_value); ecma_free_value (value); @@ -3478,12 +3523,17 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_value_t *buffer_p = collection_p->buffer_p; ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[-4]); uint32_t index = stack_top_p[-3]; +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ while (index < collection_p->item_count) { ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (buffer_p[index]); - if (JERRY_LIKELY (ecma_op_object_has_property (object_p, prop_name_p))) + result = ecma_op_object_has_property (object_p, prop_name_p); + + if (JERRY_LIKELY (ecma_is_value_true (result))) { byte_code_p = byte_code_start_p + branch_offset; break; @@ -4088,7 +4138,8 @@ error: /** * Initialize code block execution * - * @return ecma value + * @return ECMA_VALUE_ERROR - if the initialization fails + * ECMA_VALUE_EMPTY - otherwise */ static void JERRY_ATTR_NOINLINE vm_init_exec (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ diff --git a/tests/jerry/es2015/proxy_call.js b/tests/jerry/es2015/proxy_call.js new file mode 100644 index 000000000..74e2ab2c5 --- /dev/null +++ b/tests/jerry/es2015/proxy_call.js @@ -0,0 +1,40 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = function () {}; +var handler = { apply (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // opfunc_call + proxy(5) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + var revocable = Proxy.revokable(function() {}, {}); + proxy = new Proxy(revocable.proxy, {}) + revocable.revoke(); + proxy(5) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_construct.js b/tests/jerry/es2015/proxy_construct.js new file mode 100644 index 000000000..1df33e352 --- /dev/null +++ b/tests/jerry/es2015/proxy_construct.js @@ -0,0 +1,38 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = function () {}; +var handler = { construct (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // opfunc_call + new proxy(5) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 22.1.2.3.4.a + Array.of.call(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_create.js b/tests/jerry/es2015/proxy_create.js new file mode 100644 index 000000000..b6b3a3cbe --- /dev/null +++ b/tests/jerry/es2015/proxy_create.js @@ -0,0 +1,65 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {} +var handler = {}; +var proxy = new Proxy(target, handler); + +var revocable = Proxy.revocable(target, handler); +revocable.revoke(); +var rev_proxy = revocable.proxy; + +try { + Proxy(target, handler); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + proxy.a; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + new Proxy(undefined, undefined); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + new Proxy(rev_proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + new Proxy({}, rev_proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + new Proxy(rev_proxy, {}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_define_own_property.js b/tests/jerry/es2015/proxy_define_own_property.js new file mode 100644 index 000000000..d4d8157d9 --- /dev/null +++ b/tests/jerry/es2015/proxy_define_own_property.js @@ -0,0 +1,32 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = function () {}; +var handler = { defineProperty (target) { + throw 42; +}, construct () { + return {}; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 22.1.2.3.8.c + Array.of.call(proxy, 5) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_delete.js b/tests/jerry/es2015/proxy_delete.js new file mode 100644 index 000000000..04b765da1 --- /dev/null +++ b/tests/jerry/es2015/proxy_delete.js @@ -0,0 +1,46 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { deleteProperty (target) { + throw 42; +}, get (object, propName) { + if (propName == "length") { + return 5; + } +}}; + +var proxy = new Proxy(target, handler); + +var a = 5; + +try { + // ecma_op_delete_binding + with (proxy) { + delete a + } + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 22.1.3.16.6.e + Array.prototype.pop.call(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_get.js b/tests/jerry/es2015/proxy_get.js new file mode 100644 index 000000000..61dbf7ccb --- /dev/null +++ b/tests/jerry/es2015/proxy_get.js @@ -0,0 +1,46 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { get (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // vm_op_get_value + proxy.a + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // ecma_op_get_value_object_base + proxy[2]; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // @@toPrimitive symbol + proxy + "foo"; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_get_own_property_descriptor.js b/tests/jerry/es2015/proxy_get_own_property_descriptor.js new file mode 100644 index 000000000..e0adc87fc --- /dev/null +++ b/tests/jerry/es2015/proxy_get_own_property_descriptor.js @@ -0,0 +1,80 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { getOwnPropertyDescriptor (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 19.1.3.2.5 + Object.prototype.hasOwnProperty.call(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.3.4 + Object.prototype.propertyIsEnumerable.call(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.2.1.5.b.iii + Object.assign({}, proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.2.6.5 + Object.getOwnPropertyDescriptor(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +/* TODO: enable these test when Proxy.[[isExtensible]] has been implemted +try { + // 19.1.2.5.2.9.a.i + Object.freeze(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.2.12.2.7 + Object.isFrozen(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.2.13.2.7 + Object.isSealed(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} +*/ diff --git a/tests/jerry/es2015/proxy_get_prototoype_of.js b/tests/jerry/es2015/proxy_get_prototoype_of.js new file mode 100644 index 000000000..f01339fbc --- /dev/null +++ b/tests/jerry/es2015/proxy_get_prototoype_of.js @@ -0,0 +1,70 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { getPrototypeOf (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 19.1.2.9.2 + Object.getPrototypeOf(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.3.3 + Object.prototype.isPrototypeOf(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +(function () { + class e extends Array {}; + function f () {}; + function g () {}; + + Object.setPrototypeOf(g, proxy); + + // 7.3.19.7.b + try { + g instanceof f; + assert(false); + } catch (e) { + assert(e instanceof TypeError); + } + + // ecma_op_implicit_class_constructor_has_instance [[GetPrototypeOf]] + try { + g instanceof e; + assert(false); + } catch (e) { + assert(e instanceof TypeError); + } +})(); + +try { + // 9.4.1.3.3 + Function.prototype.bind.call(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_has.js b/tests/jerry/es2015/proxy_has.js new file mode 100644 index 000000000..af23c8e43 --- /dev/null +++ b/tests/jerry/es2015/proxy_has.js @@ -0,0 +1,52 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { has (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 12.9.3 + "foo" in proxy; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 8.1.1.2.1 + with (proxy) { + p; + assert(false); + } + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // ecma_op_put_value_lex_env_base/[[HasProperty]] + with (proxy) { + function a (){} + assert(false); + } + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_is_extensible.js b/tests/jerry/es2015/proxy_is_extensible.js new file mode 100644 index 000000000..cf83cf4ee --- /dev/null +++ b/tests/jerry/es2015/proxy_is_extensible.js @@ -0,0 +1,46 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { isExtensible (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 7.3.15 + Object.isFrozen(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 7.3.15 + Object.isSealed(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 7.2.5 + Object.isExtensible(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_own_keys.js b/tests/jerry/es2015/proxy_own_keys.js new file mode 100644 index 000000000..e7e051067 --- /dev/null +++ b/tests/jerry/es2015/proxy_own_keys.js @@ -0,0 +1,54 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { ownKeys (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // Array.prototype.sort + Array.prototype.sort.call(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.2.14.4 + Object.keys(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.2.7.1 + Object.getOwnPropertyNames(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 19.1.2.8.1 + Object.getOwnPropertySymbols(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_prevent_extensions.js b/tests/jerry/es2015/proxy_prevent_extensions.js new file mode 100644 index 000000000..6750f4e45 --- /dev/null +++ b/tests/jerry/es2015/proxy_prevent_extensions.js @@ -0,0 +1,39 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { preventExtensions (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 7.3.14 + Object.freeze(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 7.3.14 + Object.seal(proxy) + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + diff --git a/tests/jerry/es2015/proxy_revocable.js b/tests/jerry/es2015/proxy_revocable.js new file mode 100644 index 000000000..46e21769a --- /dev/null +++ b/tests/jerry/es2015/proxy_revocable.js @@ -0,0 +1,69 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = function () {}; +var handler = { get (name) { + return 5; +}}; + +var revocable = Proxy.revocable(target, handler); + +var proxy = revocable.proxy; + +try { + proxy.a; // FIXME: this should return 5 when proxy.[[Get]] has been implemted + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +revocable.revoke(); + +try { + proxy.a; + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Proxy.revocable(); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Proxy.revocable(proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Proxy.revocable({}, proxy); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + Proxy.revocable(proxy, {}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + diff --git a/tests/jerry/es2015/proxy_set.js b/tests/jerry/es2015/proxy_set.js new file mode 100644 index 000000000..b9763ac69 --- /dev/null +++ b/tests/jerry/es2015/proxy_set.js @@ -0,0 +1,38 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { set (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // vm_op_set_value + proxy.a = 5 + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + // 22.1.3.6.11.b + Array.prototype.fill.call(proxy, 'foo', 0, 5); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/es2015/proxy_set_prototoype_of.js b/tests/jerry/es2015/proxy_set_prototoype_of.js new file mode 100644 index 000000000..c39ef79cf --- /dev/null +++ b/tests/jerry/es2015/proxy_set_prototoype_of.js @@ -0,0 +1,30 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Update these tests when the internal routine has been implemented + +var target = {}; +var handler = { setPrototypeOf (target) { + throw 42; +}}; + +var proxy = new Proxy(target, handler); + +try { + // 19.1.2.18 + Object.setPrototypeOf(proxy, {}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/jerry/regression-test-issue-1387.js b/tests/jerry/fail/regression-test-issue-1387.js similarity index 100% rename from tests/jerry/regression-test-issue-1387.js rename to tests/jerry/fail/regression-test-issue-1387.js diff --git a/tests/unit-core/test-api-property.c b/tests/unit-core/test-api-property.c index c1f5de1f0..a755258f5 100644 --- a/tests/unit-core/test-api-property.c +++ b/tests/unit-core/test-api-property.c @@ -64,10 +64,25 @@ main (void) TEST_ASSERT (jerry_value_is_undefined (prop_desc.getter)); TEST_ASSERT (prop_desc.is_set_defined == false); TEST_ASSERT (jerry_value_is_undefined (prop_desc.setter)); - jerry_release_value (prop_name); + jerry_release_value (global_obj_val); jerry_free_property_descriptor_fields (&prop_desc); - jerry_release_value (global_obj_val); + if (jerry_is_feature_enabled (JERRY_FEATURE_PROXY)) + { + /* Note: update this test when the internal method is implemented */ + jerry_value_t target = jerry_create_object (); + jerry_value_t handler = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + + jerry_release_value (target); + jerry_release_value (handler); + is_ok = jerry_get_own_property_descriptor (proxy, prop_name, &prop_desc); + TEST_ASSERT (!is_ok); + jerry_release_value (proxy); + } + + jerry_release_value (prop_name); + jerry_cleanup (); return 0; diff --git a/tests/unit-core/test-api.c b/tests/unit-core/test-api.c index d19e8a280..4414381df 100644 --- a/tests/unit-core/test-api.c +++ b/tests/unit-core/test-api.c @@ -695,6 +695,23 @@ main (void) jerry_release_value (proto_val); jerry_release_value (obj_val); + if (jerry_is_feature_enabled (JERRY_FEATURE_PROXY)) + { + /* Note: update this test when the internal method is implemented */ + jerry_value_t target = jerry_create_object (); + jerry_value_t handler = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + + jerry_release_value (target); + jerry_release_value (handler); + proto_val = jerry_get_prototype (proxy); + TEST_ASSERT (jerry_value_is_error (proto_val)); + error = jerry_get_value_from_error (proto_val, true); + TEST_ASSERT (jerry_get_error_type (error) == JERRY_ERROR_TYPE); + jerry_release_value (error); + jerry_release_value (proxy); + } + /* Test: jerry_set_prototype */ obj_val = jerry_create_object (); res = jerry_set_prototype (obj_val, jerry_create_null ()); @@ -714,6 +731,25 @@ main (void) jerry_release_value (proto_val); jerry_release_value (obj_val); + if (jerry_is_feature_enabled (JERRY_FEATURE_PROXY)) + { + /* Note: update this test when the internal method is implemented */ + jerry_value_t target = jerry_create_object (); + jerry_value_t handler = jerry_create_object (); + jerry_value_t proxy = jerry_create_proxy (target, handler); + + jerry_release_value (target); + jerry_release_value (handler); + new_proto = jerry_create_object (); + res = jerry_set_prototype (proxy, new_proto); + jerry_release_value (new_proto); + TEST_ASSERT (jerry_value_is_error (res)); + error = jerry_get_value_from_error (res, true); + TEST_ASSERT (jerry_get_error_type (error) == JERRY_ERROR_TYPE); + jerry_release_value (error); + jerry_release_value (proxy); + } + /* Test: eval */ const jerry_char_t eval_code_src1[] = "(function () { return 123; })"; val_t = jerry_eval (eval_code_src1, sizeof (eval_code_src1) - 1, JERRY_PARSE_STRICT_MODE);