diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 5a7a8edc2..937fb3063 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -3884,6 +3884,8 @@ jerry_object_get_property_names (const jerry_value_t obj_val, /**< object */ ecma_object_t *obj_iter_p = obj_p; ecma_collection_t *result_p = ecma_new_collection (); + ecma_ref_object (obj_iter_p); + while (true) { /* Step 1. Get Object.[[OwnKeys]] */ @@ -3892,6 +3894,7 @@ jerry_object_get_property_names (const jerry_value_t obj_val, /**< object */ #if ENABLED (JERRY_BUILTIN_PROXY) if (prop_names_p == NULL) { + ecma_deref_object (obj_iter_p); return jerry_throw (ECMA_VALUE_ERROR); } #endif /* ENABLED (JERRY_BUILTIN_PROXY) */ @@ -3942,6 +3945,7 @@ jerry_object_get_property_names (const jerry_value_t obj_val, /**< object */ { ecma_collection_free (prop_names_p); ecma_collection_free (result_p); + ecma_deref_object (obj_iter_p); return jerry_throw (ECMA_VALUE_ERROR); } #endif /* ENABLED (JERRY_BUILTIN_PROXY) */ @@ -4008,38 +4012,32 @@ jerry_object_get_property_names (const jerry_value_t obj_val, /**< object */ ecma_collection_free (prop_names_p); /* Step 4: Traverse prototype chain */ - jmem_cpointer_t parent_cp = JMEM_CP_NULL; - if (filter & JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN) - { -#if ENABLED (JERRY_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (obj_iter_p)) - { - ecma_value_t parent = ecma_proxy_object_get_prototype_of (obj_iter_p); - - if (ECMA_IS_VALUE_ERROR (parent)) - { - ecma_collection_free (result_p); - return jerry_throw (ECMA_VALUE_ERROR); - } - - parent_cp = ecma_proxy_object_prototype_to_cp (parent); - } - else -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - { - parent_cp = ecma_op_ordinary_object_get_prototype_of (obj_iter_p); - } - } - - if (parent_cp == JMEM_CP_NULL) + if ((filter & JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN) != JERRY_PROPERTY_FILTER_TRAVERSE_PROTOTYPE_CHAIN) { break; } - obj_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, parent_cp); + ecma_object_t *proto_p = ecma_op_object_get_prototype_of (obj_iter_p); + + if (proto_p == NULL) + { + break; + } + + ecma_deref_object (obj_iter_p); + + if (JERRY_UNLIKELY (proto_p == ECMA_OBJECT_POINTER_ERROR)) + { + ecma_collection_free (result_p); + return jerry_throw (ECMA_VALUE_ERROR); + } + + obj_iter_p = proto_p; } + ecma_deref_object (obj_iter_p); + return ecma_op_new_array_object_from_collection (result_p, false); } /* jerry_object_get_property_names */ 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 0c18a7095..8c6c52b5c 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c @@ -324,11 +324,10 @@ ecma_builtin_object_prototype_lookup_getter_setter (ecma_value_t this_arg, /**< return ECMA_VALUE_ERROR; } - jmem_cpointer_t obj_cp; - ECMA_SET_NON_NULL_POINTER (obj_cp, obj_p); - ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; + ecma_ref_object (obj_p); + /* 3. */ while (true) { @@ -339,6 +338,7 @@ ecma_builtin_object_prototype_lookup_getter_setter (ecma_value_t this_arg, /**< if (ECMA_IS_VALUE_ERROR (get_desc)) { ret_value = get_desc; + ecma_deref_object (obj_p); break; } @@ -360,35 +360,26 @@ ecma_builtin_object_prototype_lookup_getter_setter (ecma_value_t this_arg, /**< } ecma_free_property_descriptor (&desc); + ecma_deref_object (obj_p); break; } /* 3.c */ -#if ENABLED (JERRY_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (obj_p)) - { - ecma_value_t parent = ecma_proxy_object_get_prototype_of (obj_p); + ecma_object_t *proto_p = ecma_op_object_get_prototype_of (obj_p); + ecma_deref_object (obj_p); - if (ECMA_IS_VALUE_ERROR (parent)) - { - ret_value = parent; - break; - } - - obj_cp = ecma_proxy_object_prototype_to_cp (parent); - } - else -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - { - obj_cp = ecma_op_ordinary_object_get_prototype_of (obj_p); - } - - if (obj_cp == JMEM_CP_NULL) + if (proto_p == NULL) { break; } + else if (JERRY_UNLIKELY (proto_p == ECMA_OBJECT_POINTER_ERROR)) + { + ret_value = ECMA_VALUE_ERROR; + break; + } - obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_cp); + /* Advance up on prototype chain. */ + obj_p = proto_p; } ecma_free_value (to_obj); diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index ebb985761..2de9022da 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -900,44 +900,34 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * ecma_value_t result = ECMA_VALUE_FALSE; #endif /* ENABLED (JERRY_BUILTIN_PROXY) */ + ecma_ref_object (v_obj_p); + while (true) { - jmem_cpointer_t v_obj_cp; -#if ENABLED (JERRY_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (v_obj_p)) - { - ecma_value_t parent = ecma_proxy_object_get_prototype_of (v_obj_p); + ecma_object_t *current_proto_p = ecma_op_object_get_prototype_of (v_obj_p); + ecma_deref_object (v_obj_p); - if (ECMA_IS_VALUE_ERROR (parent)) - { - break; - } - - v_obj_cp = ecma_proxy_object_prototype_to_cp (parent); - } - else - { -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - v_obj_cp = ecma_op_ordinary_object_get_prototype_of (v_obj_p); -#if ENABLED (JERRY_BUILTIN_PROXY) - } -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - - if (v_obj_cp == JMEM_CP_NULL) + if (current_proto_p == NULL) { #if ENABLED (JERRY_BUILTIN_PROXY) result = ECMA_VALUE_FALSE; #endif /* ENABLED (JERRY_BUILTIN_PROXY) */ break; } - - v_obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, v_obj_cp); - - if (v_obj_p == prototype_obj_p) + else if (current_proto_p == ECMA_OBJECT_POINTER_ERROR) { + break; + } + + if (current_proto_p == prototype_obj_p) + { + ecma_deref_object (current_proto_p); result = ECMA_VALUE_TRUE; break; } + + /* Advance up on prototype chain. */ + v_obj_p = current_proto_p; } ecma_deref_object (prototype_obj_p); @@ -957,38 +947,13 @@ ecma_op_function_has_instance (ecma_object_t *func_obj_p, /**< Function object * ecma_value_t ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p) /**< function object */ { - ecma_object_t *super_ctor_p; + ecma_object_t *super_ctor_p = ecma_op_object_get_prototype_of (func_obj_p); -#if ENABLED (JERRY_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (func_obj_p)) + if (JERRY_UNLIKELY (super_ctor_p == ECMA_OBJECT_POINTER_ERROR)) { - ecma_value_t super_ctor = ecma_proxy_object_get_prototype_of (func_obj_p); - - if (ECMA_IS_VALUE_ERROR (super_ctor)) - { - return super_ctor; - } - - super_ctor_p = ecma_is_value_null (super_ctor) ? NULL : ecma_get_object_from_value (super_ctor); + return ECMA_VALUE_ERROR; } - else - { -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (func_obj_p); - if (proto_cp == JMEM_CP_NULL) - { - super_ctor_p = NULL; - } - else - { - super_ctor_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); - ecma_ref_object (super_ctor_p); - } -#if ENABLED (JERRY_BUILTIN_PROXY) - } -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - - if (super_ctor_p == NULL || !ecma_object_is_constructor (super_ctor_p)) + else if (super_ctor_p == NULL || !ecma_object_is_constructor (super_ctor_p)) { if (super_ctor_p != NULL) { diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 4b5fee114..310aff3b5 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -1989,6 +1989,55 @@ ecma_op_object_has_instance (ecma_object_t *obj_p, /**< the object */ return ecma_raise_type_error (ECMA_ERR_MSG ("Expected a function object.")); } /* ecma_op_object_has_instance */ +/** + * General [[GetPrototypeOf]] abstract operation + * + * Note: returned valid object must be freed. + * + * @return ecma_object_t * - prototype of the input object. + * ECMA_OBJECT_POINTER_ERROR - error reported during Proxy resolve. + * NULL - the input object does not have a prototype. + */ +ecma_object_t * +ecma_op_object_get_prototype_of (ecma_object_t *obj_p) /**< input object */ +{ + JERRY_ASSERT (obj_p != NULL); + +#if ENABLED (JERRY_BUILTIN_PROXY) + if (ECMA_OBJECT_IS_PROXY (obj_p)) + { + ecma_value_t proto = ecma_proxy_object_get_prototype_of (obj_p); + + if (ECMA_IS_VALUE_ERROR (proto)) + { + return ECMA_OBJECT_POINTER_ERROR; + } + if (ecma_is_value_null (proto)) + { + return NULL; + } + + JERRY_ASSERT (ecma_is_value_object (proto)); + + return ecma_get_object_from_value (proto); + } + else +#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ + { + jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (obj_p); + + if (proto_cp == JMEM_CP_NULL) + { + return NULL; + } + + ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp); + ecma_ref_object (proto_p); + + return proto_p; + } +} /* ecma_op_object_get_prototype_of */ + /** * Object's isPrototypeOf operation * @@ -2003,40 +2052,31 @@ ecma_value_t ecma_op_object_is_prototype_of (ecma_object_t *base_p, /**< base object */ ecma_object_t *target_p) /**< target object */ { + ecma_ref_object (target_p); + do { - jmem_cpointer_t target_cp; -#if ENABLED (JERRY_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (target_p)) - { - ecma_value_t target_proto = ecma_proxy_object_get_prototype_of (target_p); + ecma_object_t *proto_p = ecma_op_object_get_prototype_of (target_p); + ecma_deref_object (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_BUILTIN_PROXY) */ - target_cp = ecma_op_ordinary_object_get_prototype_of (target_p); -#if ENABLED (JERRY_BUILTIN_PROXY) - } -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - - if (target_cp == JMEM_CP_NULL) + if (proto_p == NULL) { return ECMA_VALUE_FALSE; } - - target_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, target_cp); - - if (target_p == base_p) + else if (proto_p == ECMA_OBJECT_POINTER_ERROR) { + return ECMA_VALUE_ERROR; + } + else if (proto_p == base_p) + { + ecma_deref_object (proto_p); return ECMA_VALUE_TRUE; } - } while (true); + + /* Advance up on prototype chain. */ + target_p = proto_p; + } + while (true); } /* ecma_op_object_is_prototype_of */ /** @@ -2489,8 +2529,7 @@ ecma_op_object_enumerate (ecma_object_t *obj_p) /**< object */ ecma_collection_t *visited_names_p = ecma_new_collection (); ecma_collection_t *return_names_p = ecma_new_collection (); - jmem_cpointer_t obj_cp; - ECMA_SET_NON_NULL_POINTER (obj_cp, obj_p); + ecma_ref_object (obj_p); while (true) { @@ -2501,6 +2540,7 @@ ecma_op_object_enumerate (ecma_object_t *obj_p) /**< object */ { ecma_collection_free (return_names_p); ecma_collection_free (visited_names_p); + ecma_deref_object (obj_p); return keys; } #endif /* ENABLED (JERRY_ESNEXT) */ @@ -2525,6 +2565,7 @@ ecma_op_object_enumerate (ecma_object_t *obj_p) /**< object */ ecma_collection_free (keys); ecma_collection_free (return_names_p); ecma_collection_free (visited_names_p); + ecma_deref_object (obj_p); return NULL; } @@ -2554,32 +2595,23 @@ ecma_op_object_enumerate (ecma_object_t *obj_p) /**< object */ ecma_collection_free (keys); -#if ENABLED (JERRY_BUILTIN_PROXY) - if (ECMA_OBJECT_IS_PROXY (obj_p)) - { - ecma_value_t parent = ecma_proxy_object_get_prototype_of (obj_p); + /* Query the prototype. */ + ecma_object_t *proto_p = ecma_op_object_get_prototype_of (obj_p); + ecma_deref_object (obj_p); - if (ECMA_IS_VALUE_ERROR (parent)) - { - ecma_collection_free (return_names_p); - ecma_collection_free (visited_names_p); - return NULL; - } - - obj_cp = ecma_proxy_object_prototype_to_cp (parent); - } - else -#endif /* ENABLED (JERRY_BUILTIN_PROXY) */ - { - obj_cp = ecma_op_ordinary_object_get_prototype_of (obj_p); - } - - if (obj_cp == JMEM_CP_NULL) + if (proto_p == NULL) { break; } + else if (JERRY_UNLIKELY (proto_p == ECMA_OBJECT_POINTER_ERROR)) + { + ecma_collection_free (return_names_p); + ecma_collection_free (visited_names_p); + return NULL; + } - obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, obj_cp); + /* Advance up on prototype chain. */ + obj_p = proto_p; } ecma_collection_free (visited_names_p); diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index b5693def6..bd96d8539 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -62,6 +62,8 @@ ecma_value_t ecma_op_object_define_own_property (ecma_object_t *obj_p, ecma_stri 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); +ecma_object_t *ecma_op_object_get_prototype_of (ecma_object_t *obj_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_enumerable_property_names (ecma_object_t *obj_p, ecma_enumerable_property_names_options_t option); diff --git a/jerry-core/ecma/operations/ecma-proxy-object.c b/jerry-core/ecma/operations/ecma-proxy-object.c index a9010b0dc..c5d299c6a 100644 --- a/jerry-core/ecma/operations/ecma-proxy-object.c +++ b/jerry-core/ecma/operations/ecma-proxy-object.c @@ -228,31 +228,6 @@ ecma_proxy_object_find (ecma_object_t *obj_p, /**< proxy object */ 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 */ - /** * Helper method for validate the proxy object * diff --git a/jerry-core/ecma/operations/ecma-proxy-object.h b/jerry-core/ecma/operations/ecma-proxy-object.h index 97d33e01a..0ad66a7c6 100644 --- a/jerry-core/ecma/operations/ecma-proxy-object.h +++ b/jerry-core/ecma/operations/ecma-proxy-object.h @@ -41,9 +41,6 @@ ecma_proxy_revoke_cb (const ecma_value_t function_obj, const ecma_value_t args_p[], const uint32_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); diff --git a/tests/jerry/es.next/regression-test-issue-4445.js b/tests/jerry/es.next/regression-test-issue-4445.js new file mode 100644 index 000000000..60fba2157 --- /dev/null +++ b/tests/jerry/es.next/regression-test-issue-4445.js @@ -0,0 +1,60 @@ +// 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. + +// Keeping test as it is due to the fact this was triggered via a gc related issue + +var a= ["", "\0", "\t", "\n", "\v", "\f", "\r", " ", "\u00a0", "\u2028", "\u2029", "\ufeff"] +Array.prototype[4] = 10; + +function Test() +{ + a.sort(function() { + var A = function() { }; + A.prototype.x = 42; + var o = new Proxy({ + "3": { + writable:false, + value:20 + } + }, /*handler*/ { + getPrototypeOf: function (val, size, ch) { + var result = new String(val); + if (ch == null) { + ch = " "; + } + while (result.length < size) { + result = ch + result; + } + return result; + } + } + ); + + o.x = 43; + var result = ""; + for (var p in o) { + result += o[p]; + } + return a | 0; + }); + + throw new EvalError("error"); +} + +try { + Test(); + assert(false); +} catch (ex) { + assert (ex instanceof EvalError); +}