From 9ad9d574fefd27e0ae3104436989e88608da1711 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Wed, 13 May 2020 14:27:31 +0200 Subject: [PATCH] Add proxy support for HasBinding operation for Object Environment records (#3731) JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- .../ecma/operations/ecma-get-put-value.c | 32 +---- jerry-core/ecma/operations/ecma-reference.c | 130 +++++++++++++----- jerry-core/ecma/operations/ecma-reference.h | 2 +- tests/jerry/es2015/symbol-unscopables.js | 21 +++ 4 files changed, 116 insertions(+), 69 deletions(-) diff --git a/jerry-core/ecma/operations/ecma-get-put-value.c b/jerry-core/ecma/operations/ecma-get-put-value.c index 64d252c54..fc47534b8 100644 --- a/jerry-core/ecma/operations/ecma-get-put-value.c +++ b/jerry-core/ecma/operations/ecma-get-put-value.c @@ -86,41 +86,13 @@ ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme { JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND); - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - - ecma_value_t result = ecma_op_object_find (binding_obj_p, name_p); - - if (ECMA_IS_VALUE_ERROR (result)) - { - return result; - } + ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p); if (ecma_is_value_found (result)) { + /* Note: the result may contains ECMA_VALUE_ERROR */ *ref_base_lex_env_p = lex_env_p; - -#if ENABLED (JERRY_ES2015) - ecma_value_t blocked = ecma_op_is_prop_unscopable (lex_env_p, name_p); - - if (ECMA_IS_VALUE_ERROR (blocked)) - { - ecma_free_value (result); - return blocked; - } - - if (ecma_is_value_true (blocked)) - { - *ref_base_lex_env_p = NULL; - ecma_free_value (result); - } - else - { - return result; - } -#else /* !ENABLED (JERRY_ES2015) */ return result; -#endif /* ENABLED (JERRY_ES2015) */ - } break; diff --git a/jerry-core/ecma/operations/ecma-reference.c b/jerry-core/ecma/operations/ecma-reference.c index 8851166f2..518d21676 100644 --- a/jerry-core/ecma/operations/ecma-reference.c +++ b/jerry-core/ecma/operations/ecma-reference.c @@ -140,17 +140,10 @@ ecma_op_resolve_super_base (ecma_object_t *lex_env_p) /**< starting lexical envi * ECMA_VALUE_FALSE - if a the property is not unscopable * ECMA_VALUE_ERROR - otherwise */ -ecma_value_t -ecma_op_is_prop_unscopable (ecma_object_t *lex_env_p, /**< lexical environment */ +static ecma_value_t +ecma_op_is_prop_unscopable (ecma_object_t *binding_obj_p, /**< binding object */ ecma_string_t *prop_name_p) /**< property's name */ { - if (lex_env_p == ecma_get_global_scope ()) - { - return ECMA_VALUE_FALSE; - } - - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - ecma_value_t unscopables = ecma_op_object_get_by_symbol_id (binding_obj_p, LIT_GLOBAL_SYMBOL_UNSCOPABLES); if (ECMA_IS_VALUE_ERROR (unscopables)) @@ -182,6 +175,91 @@ ecma_op_is_prop_unscopable (ecma_object_t *lex_env_p, /**< lexical environment * } /* ecma_op_is_prop_unscopable */ #endif /* ENABLED (JERRY_ES2015) */ +/** + * Helper method for HasBindig operation + * + * See also: + * ECMA-262 v6, 8.1.1.2.1 steps 7-9; + * + * @return ECMA_VALUE_TRUE - if the property is unscopable + * ECMA_VALUE_FALSE - if a the property is not unscopable + * ECMA_VALUE_ERROR - otherwise + */ + +/** + * Resolve value corresponding to the given object environment reference. + * + * Note: the steps are already include the HasBindig operation steps + * + * See also: + * ECMA-262 v6, 8.1.1.2.1 + * + * @return ECMA_VALUE_ERROR - if the operation fails + * ECMA_VALUE_NOT_FOUND - if the binding not exists or blocked via @@unscopables + * result of the binding - otherwise + */ +ecma_value_t +ecma_op_object_bound_environment_resolve_reference_value (ecma_object_t *lex_env_p, /**< lexical environment */ + ecma_string_t *name_p) /**< variable name */ +{ + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); + ecma_value_t found_binding; + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (binding_obj_p)) + { + found_binding = ecma_proxy_object_has (binding_obj_p, name_p); + + if (!ecma_is_value_true (found_binding)) + { + return ECMA_IS_VALUE_ERROR (found_binding) ? found_binding : ECMA_VALUE_NOT_FOUND; + } + } + else + { +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + found_binding = ecma_op_object_find (binding_obj_p, name_p); + + if (ECMA_IS_VALUE_ERROR (found_binding) || !ecma_is_value_found (found_binding)) + { + return found_binding; + } + +#if ENABLED (JERRY_ES2015) + if (JERRY_LIKELY (lex_env_p == ecma_get_global_scope ())) +#endif /* ENABLED (JERRY_ES2015) */ + { + return found_binding; + } +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + +#if ENABLED (JERRY_ES2015) + ecma_value_t blocked = ecma_op_is_prop_unscopable (binding_obj_p, name_p); + + if (ecma_is_value_false (blocked)) + { +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (binding_obj_p)) + { + return ecma_proxy_object_get (binding_obj_p, name_p, ecma_make_object_value (binding_obj_p)); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + return found_binding; + } + +#if ENABLED (JERRY_ES2015_BUILTIN_PROXY) + if (!ECMA_OBJECT_IS_PROXY (binding_obj_p)) + { + ecma_free_value (found_binding); + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */ + + return ECMA_IS_VALUE_ERROR (blocked) ? blocked : ECMA_VALUE_NOT_FOUND; +#endif /* ENABLED (JERRY_ES2015) */ +} /* ecma_op_object_bound_environment_resolve_reference_value */ + /** * Resolve value corresponding to reference. * @@ -218,8 +296,6 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical } else if (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND) { - ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); - #if ENABLED (JERRY_ES2015) bool lcache_lookup_allowed = (lex_env_p == ecma_get_global_environment ()); #else /* !ENABLED (JERRY_ES2015)*/ @@ -229,6 +305,7 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical if (lcache_lookup_allowed) { #if ENABLED (JERRY_LCACHE) + ecma_object_t *binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p); ecma_property_t *property_p = ecma_lcache_lookup (binding_obj_p, name_p); if (property_p != NULL) @@ -257,35 +334,12 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical #endif /* ENABLED (JERRY_LCACHE) */ } - ecma_value_t prop_value = ecma_op_object_find (binding_obj_p, name_p); + ecma_value_t result = ecma_op_object_bound_environment_resolve_reference_value (lex_env_p, name_p); - if (ECMA_IS_VALUE_ERROR (prop_value)) + if (ecma_is_value_found (result)) { - return prop_value; - } - - if (ecma_is_value_found (prop_value)) - { -#if ENABLED (JERRY_ES2015) - ecma_value_t blocked = ecma_op_is_prop_unscopable (lex_env_p, name_p); - - if (ECMA_IS_VALUE_ERROR (blocked)) - { - ecma_free_value (prop_value); - return blocked; - } - - if (ecma_is_value_true (blocked)) - { - ecma_free_value (prop_value); - } - else - { - return prop_value; - } -#else /* !ENABLED (JERRY_ES2015) */ - return prop_value; -#endif /* ENABLED (JERRY_ES2015) */ + /* Note: the result may contains ECMA_VALUE_ERROR */ + return result; } } else diff --git a/jerry-core/ecma/operations/ecma-reference.h b/jerry-core/ecma/operations/ecma-reference.h index 4ee2d0923..958379766 100644 --- a/jerry-core/ecma/operations/ecma-reference.h +++ b/jerry-core/ecma/operations/ecma-reference.h @@ -28,9 +28,9 @@ ecma_object_t *ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, ecma_string_t *name_p); ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, ecma_string_t *name_p); +ecma_value_t ecma_op_object_bound_environment_resolve_reference_value (ecma_object_t *lex_env_p, ecma_string_t *name_p); #if ENABLED (JERRY_ES2015) ecma_value_t ecma_op_resolve_super_base (ecma_object_t *lex_env_p); -ecma_value_t ecma_op_is_prop_unscopable (ecma_object_t *lex_env_p, ecma_string_t *prop_name_p); #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/tests/jerry/es2015/symbol-unscopables.js b/tests/jerry/es2015/symbol-unscopables.js index e1f74eadd..109c06e04 100644 --- a/tests/jerry/es2015/symbol-unscopables.js +++ b/tests/jerry/es2015/symbol-unscopables.js @@ -104,3 +104,24 @@ with (a) { assert(foo === 1); assert(typeof bar === "undefined"); } + +let track = []; +let proxy = new Proxy({ a : 4, [Symbol.unscopables] : [] }, { + has (t, p) { + track.push(p); + return Reflect.has(...arguments); + }, + get (t, p, r) { + track.push(p); + return Reflect.get(...arguments); + } +}); + +with (proxy){ + a; +} + +assert(track.length == 3); +assert(track[0] === 'a'); +assert(track[1] === Symbol.unscopables); +assert(track[2] === 'a');