From 1712ad5dc461c656a3b9097e6d2cb0165ebe6579 Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Wed, 3 Feb 2021 16:17:50 +0100 Subject: [PATCH] Ensure that fast array objects are always extensible (#4557) This patch helps to eliminate some extra checks from Array.prototype methods JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- .../ecma-builtin-array-prototype.c | 23 ++++--------------- jerry-core/ecma/operations/ecma-objects.c | 17 +++++++++----- .../es.next/regression-test-issue-3534.js | 9 ++------ 3 files changed, 17 insertions(+), 32 deletions(-) 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 eaa51e2d7..22e3b7087 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -390,12 +390,6 @@ ecma_builtin_array_prototype_object_pop (ecma_object_t *obj_p, /**< object */ if (ecma_op_object_is_fast_array (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")); - } - ecma_delete_fast_array_properties (obj_p, (uint32_t) len); return get_value; @@ -441,11 +435,6 @@ ecma_builtin_array_prototype_object_push (const ecma_value_t *argument_list_p, / { if (ecma_op_object_is_fast_array (obj_p)) { - if (!ecma_op_ordinary_object_is_extensible (obj_p)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type")); - } - if ((ecma_number_t) (length + arguments_number) > UINT32_MAX) { return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid Array length")); @@ -540,8 +529,7 @@ ecma_builtin_array_prototype_object_reverse (ecma_value_t this_arg, /**< this ar ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; if (ext_obj_p->u.array.length_prop_and_hole_count < ECMA_FAST_ARRAY_HOLE_ONE - && len != 0 - && ecma_op_ordinary_object_is_extensible (obj_p)) + && len != 0) { ecma_value_t *buffer_p = ECMA_GET_NON_NULL_POINTER (ecma_value_t, obj_p->u1.property_list_cp); @@ -726,8 +714,7 @@ ecma_builtin_array_prototype_object_shift (ecma_object_t *obj_p, /**< object */ ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; if (ext_obj_p->u.array.length_prop_and_hole_count < ECMA_FAST_ARRAY_HOLE_ONE - && len != 0 - && ecma_op_ordinary_object_is_extensible (obj_p)) + && len != 0) { 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]; @@ -1514,8 +1501,7 @@ ecma_builtin_array_prototype_object_unshift (const ecma_value_t args[], /**< arg ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; if (ext_obj_p->u.array.length_prop_and_hole_count < ECMA_FAST_ARRAY_HOLE_ONE - && len != 0 - && ecma_op_ordinary_object_is_extensible (obj_p)) + && len != 0) { if (args_number > UINT32_MAX - len) { @@ -2302,8 +2288,7 @@ ecma_builtin_array_prototype_fill (ecma_value_t value, /**< value */ { ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; - if (ext_obj_p->u.array.length_prop_and_hole_count < ECMA_FAST_ARRAY_HOLE_ONE - && ecma_op_ordinary_object_is_extensible (obj_p)) + if (ext_obj_p->u.array.length_prop_and_hole_count < ECMA_FAST_ARRAY_HOLE_ONE) { if (JERRY_UNLIKELY (obj_p->u1.property_list_cp == JMEM_CP_NULL)) { diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index a678f0f2d..d9c46c978 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -1276,11 +1276,6 @@ 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_op_ordinary_object_is_extensible (object_p))) - { - return ecma_reject (is_throw); - } - uint32_t index = ecma_string_get_array_index (property_name_p); if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX)) @@ -3233,7 +3228,11 @@ 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; + bool is_extensible = (object_p->type_flags_refs & ECMA_OBJECT_FLAG_EXTENSIBLE) != 0; + + JERRY_ASSERT (!ecma_op_object_is_fast_array (object_p) || is_extensible); + + return is_extensible; } /* ecma_op_ordinary_object_is_extensible */ /** @@ -3243,6 +3242,12 @@ void JERRY_ATTR_NOINLINE ecma_op_ordinary_object_prevent_extensions (ecma_object_t *object_p) /**< object */ { JERRY_ASSERT (!ECMA_OBJECT_IS_PROXY (object_p)); + + if (JERRY_UNLIKELY (ecma_op_object_is_fast_array (object_p))) + { + ecma_fast_array_convert_to_normal (object_p); + } + object_p->type_flags_refs &= (ecma_object_descriptor_t) ~ECMA_OBJECT_FLAG_EXTENSIBLE; } /* ecma_op_ordinary_object_prevent_extensions */ diff --git a/tests/jerry/es.next/regression-test-issue-3534.js b/tests/jerry/es.next/regression-test-issue-3534.js index 3eb168193..d0d2a97be 100644 --- a/tests/jerry/es.next/regression-test-issue-3534.js +++ b/tests/jerry/es.next/regression-test-issue-3534.js @@ -12,12 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -var array = [$, Infinity] +var array = [5.1, Infinity] Reflect.preventExtensions(array); -try { - var $ = array.pop() - assert(false); -} catch (e) { - assert(e instanceof TypeError); -} +assert(array.pop() == Infinity);