diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index 0189ce5fb..0d230bdc7 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -94,8 +94,9 @@ These option bits allow specializing Proxies with non-standard behaviour. These flags are recommended only for those trusted Proxies, whose handlers produce correct results. -- JERRY_PROXY_SKIP_GET_CHECKS - skip [[Get]] result checks -- JERRY_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS - skip [[GetOwnProperty]] result checks +- JERRY_PROXY_SKIP_RESULT_VALIDATION - skip result validation for [[GetPrototypeOf]], [[SetPrototypeOf]], [[IsExtensible]], + [[PreventExtensions]], [[GetOwnProperty]], [[DefineOwnProperty]], [[HasProperty]], + [[Get]], [[Set]], [[Delete]] and [[OwnPropertyKeys]] *New in version [[NEXT_RELEASE]]*. @@ -5760,7 +5761,7 @@ main (void) jerry_value_t target = jerry_create_object (); jerry_value_t handler = jerry_create_object (); - jerry_value_t proxy = jerry_create_special_proxy (target, handler, JERRY_PROXY_SKIP_GET_CHECKS); + jerry_value_t proxy = jerry_create_special_proxy (target, handler, JERRY_PROXY_SKIP_RESULT_VALIDATION); jerry_release_value (target); jerry_release_value (handler); diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 49152c1b0..4fb82d6b0 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -2242,10 +2242,8 @@ jerry_create_proxy (const jerry_value_t target, /**< target argument */ #if JERRY_BUILTIN_PROXY -JERRY_STATIC_ASSERT ((int) JERRY_PROXY_SKIP_GET_CHECKS == (int) ECMA_PROXY_SKIP_GET_CHECKS, - jerry_and_ecma_proxy_skip_get_checks_must_be_equal); -JERRY_STATIC_ASSERT ((int) JERRY_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS == (int) ECMA_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS, - jerry_and_ecma_proxy_skip_get_own_property_checks_must_be_equal); +JERRY_STATIC_ASSERT ((int) JERRY_PROXY_SKIP_RESULT_VALIDATION == (int) ECMA_PROXY_SKIP_RESULT_VALIDATION, + jerry_and_ecma_proxy_skip_result_validation_must_be_equal); #endif /* JERRY_BUILTIN_PROXY */ @@ -2271,9 +2269,7 @@ jerry_create_special_proxy (const jerry_value_t target, /**< target argument */ } #if JERRY_BUILTIN_PROXY - const uint32_t options_mask = (JERRY_PROXY_SKIP_GET_CHECKS - | JERRY_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS); - options &= options_mask; + options &= JERRY_PROXY_SKIP_RESULT_VALIDATION; ecma_object_t *proxy_p = ecma_proxy_create (target, handler, options); return jerry_return (proxy_p == NULL ? ECMA_VALUE_ERROR : ecma_make_object_value (proxy_p)); diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 97d904fcf..dfe047f5c 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -2189,10 +2189,13 @@ do \ */ typedef enum { - ECMA_PROXY_SKIP_GET_CHECKS = (1u << 0), /**< skip [[Get]] result checks */ - ECMA_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS = (1u << 1), /**< skip [[GetOwnProperty]] result checks */ - ECMA_PROXY_IS_CALLABLE = (1u << 2), /**< proxy is callable */ - ECMA_PROXY_IS_CONSTRUCTABLE = (1u << 3), /**< proxy is constructable */ + ECMA_PROXY_SKIP_RESULT_VALIDATION = (1u << 0), /**< skip result validation for [[GetPrototypeOf]], + * [[SetPrototypeOf]], [[IsExtensible]], + * [[PreventExtensions]], [[GetOwnProperty]], + * [[DefineOwnProperty]], [[HasProperty]], [[Get]], + * [[Set]], [[Delete]] and [[OwnPropertyKeys]] */ + ECMA_PROXY_IS_CALLABLE = (1u << 1), /**< proxy is callable */ + ECMA_PROXY_IS_CONSTRUCTABLE = (1u << 2), /**< proxy is constructable */ } ecma_proxy_flag_types_t; /** diff --git a/jerry-core/ecma/operations/ecma-proxy-object.c b/jerry-core/ecma/operations/ecma-proxy-object.c index 4703d9abf..a1dd1a41b 100644 --- a/jerry-core/ecma/operations/ecma-proxy-object.c +++ b/jerry-core/ecma/operations/ecma-proxy-object.c @@ -308,6 +308,11 @@ ecma_proxy_object_get_prototype_of (ecma_object_t *obj_p) /**< proxy object */ return ecma_raise_type_error (ECMA_ERR_MSG ("Trap returned neither object nor null")); } + if (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION) + { + return handler_proto; + } + /* 11. */ ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); @@ -417,6 +422,11 @@ ecma_proxy_object_set_prototype_of (ecma_object_t *obj_p, /**< proxy object */ ecma_free_value (trap_result); + if (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION) + { + return ecma_make_boolean_value (boolean_trap_result); + } + /* 11. */ ecma_value_t extensible_target = ecma_builtin_object_object_is_extensible (target_obj_p); @@ -512,6 +522,11 @@ ecma_proxy_object_is_extensible (ecma_object_t *obj_p) /**< proxy object */ ecma_free_value (trap_result); + if (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION) + { + return ecma_make_boolean_value (boolean_trap_result); + } + bool target_result; /* 10. */ @@ -606,7 +621,8 @@ ecma_proxy_object_prevent_extensions (ecma_object_t *obj_p) /**< proxy object */ ecma_free_value (trap_result); /* 10. */ - if (boolean_trap_result) + if (boolean_trap_result + && !(obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION)) { ecma_value_t target_is_ext = ecma_builtin_object_object_is_extensible (target_obj_p); @@ -688,7 +704,7 @@ ecma_proxy_object_get_own_property_descriptor (ecma_object_t *obj_p, /**< proxy return ecma_raise_type_error (ECMA_ERR_MSG ("Trap is neither an object nor undefined")); } - if (obj_p->u2.prototype_cp & ECMA_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS) + if (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION) { if (ecma_is_value_undefined (trap_result)) { @@ -899,6 +915,11 @@ ecma_proxy_object_define_own_property (ecma_object_t *obj_p, /**< proxy object * return ECMA_VALUE_FALSE; } + if (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION) + { + return ECMA_VALUE_TRUE; + } + /* 13. */ ecma_property_descriptor_t target_desc; @@ -1045,7 +1066,8 @@ ecma_proxy_object_has (ecma_object_t *obj_p, /**< proxy object */ ecma_free_value (trap_result); /* 11. */ - if (!boolean_trap_result) + if (!boolean_trap_result + && !(obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION)) { ecma_property_descriptor_t target_desc; @@ -1138,7 +1160,7 @@ ecma_proxy_object_get (ecma_object_t *obj_p, /**< proxy object */ /* 10. */ if (ECMA_IS_VALUE_ERROR (trap_result) - || (obj_p->u2.prototype_cp & ECMA_PROXY_SKIP_GET_CHECKS)) + || (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION)) { return trap_result; } @@ -1263,6 +1285,11 @@ ecma_proxy_object_set (ecma_object_t *obj_p, /**< proxy object */ return ECMA_VALUE_FALSE; } + if (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION) + { + return ECMA_VALUE_TRUE; + } + /* 12. */ ecma_property_descriptor_t target_desc; @@ -1372,6 +1399,11 @@ ecma_proxy_object_delete_property (ecma_object_t *obj_p, /**< proxy object */ return ECMA_VALUE_FALSE; } + if (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION) + { + return ECMA_VALUE_TRUE; + } + /* 12. */ ecma_property_descriptor_t target_desc; @@ -1580,7 +1612,8 @@ ecma_proxy_object_own_property_keys (ecma_object_t *obj_p) /**< proxy object */ ecma_free_value (trap_result_array); - if (trap_result == NULL) + if (trap_result == NULL + || (obj_p->u2.prototype_cp & JERRY_PROXY_SKIP_RESULT_VALIDATION)) { return trap_result; } diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 58fddcbe5..792711206 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -525,8 +525,11 @@ typedef enum */ typedef enum { - JERRY_PROXY_SKIP_GET_CHECKS = (1u << 0), /**< skip [[Get]] result checks */ - JERRY_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS = (1u << 1), /**< skip [[GetOwnProperty]] result checks */ + JERRY_PROXY_SKIP_RESULT_VALIDATION = (1u << 0), /**< skip result validation for [[GetPrototypeOf]], + * [[SetPrototypeOf]], [[IsExtensible]], + * [[PreventExtensions]], [[GetOwnProperty]], + * [[DefineOwnProperty]], [[HasProperty]], [[Get]], + * [[Set]], [[Delete]] and [[OwnPropertyKeys]] */ } jerry_proxy_object_options_t; /** diff --git a/tests/unit-core/test-special-proxy.c b/tests/unit-core/test-special-proxy.c index bc2a33110..6ef7f29e8 100644 --- a/tests/unit-core/test-special-proxy.c +++ b/tests/unit-core/test-special-proxy.c @@ -29,10 +29,7 @@ create_special_proxy_handler (const jerry_call_info_t *call_info_p, /**< call in return jerry_create_undefined (); } - const uint32_t options = (JERRY_PROXY_SKIP_GET_CHECKS - | JERRY_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS); - - return jerry_create_special_proxy (args_p[0], args_p[1], options); + return jerry_create_special_proxy (args_p[0], args_p[1], JERRY_PROXY_SKIP_RESULT_VALIDATION); } /* create_special_proxy_handler */ static void @@ -78,15 +75,34 @@ main (void) " throw 'Assertion failed!'\n" "}"); - /* This test fails unless JERRY_PROXY_SKIP_GET_CHECKS is set. */ - run_eval ("var o = {}\n" - "Object.defineProperty(o, 'prop', { value:4 })\n" - "var proxy = create_special_proxy(o, {\n" - " get(target, key) { return 5 }\n" - "})\n" - "assert(proxy.prop === 5)"); + /* These tests fail unless JERRY_PROXY_SKIP_RESULT_VALIDATION is set. */ + + run_eval ("var o = {}\n" + "Object.preventExtensions(o)\n" + "var proxy = create_special_proxy(o, {\n" + " getPrototypeOf(target) { return Array.prototype }\n" + "})\n" + "assert(Object.getPrototypeOf(proxy) === Array.prototype)"); + + run_eval ("var o = {}\n" + "Object.preventExtensions(o)\n" + "var proxy = create_special_proxy(o, {\n" + " setPrototypeOf(target, proto) { return true }\n" + "})\n" + "Object.setPrototypeOf(proxy, Array.prototype)"); + + run_eval ("var o = {}\n" + "var proxy = create_special_proxy(o, {\n" + " isExtensible(target) { return false }\n" + "})\n" + "assert(Object.isExtensible(proxy) === false)"); + + run_eval ("var o = {}\n" + "var proxy = create_special_proxy(o, {\n" + " preventExtensions(target) { return true }\n" + "})\n" + "Object.preventExtensions(proxy)"); - /* This test fails unless JERRY_PROXY_SKIP_GET_OWN_PROPERTY_CHECKS is set. */ run_eval ("var o = {}\n" "Object.defineProperty(o, 'prop', { value:4, enumerable:true })\n" "var proxy = create_special_proxy(o, {\n" @@ -100,6 +116,48 @@ main (void) "assert(desc.enumerable === false)\n" "assert(desc.writable === true)\n"); + run_eval ("var o = {}\n" + "Object.defineProperty(o, 'prop', { get() {} })\n" + "var proxy = create_special_proxy(o, {\n" + " defineProperty(target, key, descriptor) { return true }\n" + "})\n" + "Object.defineProperty(proxy, 'prop', { value:5 })"); + + run_eval ("var o = {}\n" + "Object.defineProperty(o, 'prop', { value:4 })\n" + "var proxy = create_special_proxy(o, {\n" + " has(target, key) { return false }\n" + "})\n" + "assert(!Reflect.has(proxy, 'prop'))"); + + run_eval ("var o = {}\n" + "Object.defineProperty(o, 'prop', { value:4 })\n" + "var proxy = create_special_proxy(o, {\n" + " get(target, key) { return 5 }\n" + "})\n" + "assert(proxy.prop === 5)"); + + run_eval ("var o = {}\n" + "Object.defineProperty(o, 'prop', { value:4 })\n" + "var proxy = create_special_proxy(o, {\n" + " set(target, key, value) { return true }\n" + "})\n" + "proxy.prop = 8"); + + run_eval ("var o = {}\n" + "Object.defineProperty(o, 'prop', { value:4 })\n" + "var proxy = create_special_proxy(o, {\n" + " deleteProperty(target, key) { return true }\n" + "})\n" + "assert(delete proxy.prop)"); + + run_eval ("var o = {}\n" + "Object.defineProperty(o, 'prop', { value:4 })\n" + "var proxy = create_special_proxy(o, {\n" + " ownKeys(target) { return [] }\n" + "})\n" + "Object.keys(proxy)"); + jerry_cleanup (); return 0; } /* main */