From 09c5d98e25882b81e10b5b576ce48cba22990254 Mon Sep 17 00:00:00 2001 From: Szilagyi Adam Date: Wed, 16 Oct 2019 16:41:01 +0200 Subject: [PATCH] Optimize array push/pop for fast-array cases (#3187) Performance results: ARM: 1m19s -> 0m57s Intel: 0m7,5s -> 0m5s Binary size increase: 168 bytes JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu --- .../ecma-builtin-array-prototype.c | 42 +++++++++++++++++++ .../ecma/operations/ecma-array-object.c | 22 +++++----- .../ecma/operations/ecma-array-object.h | 5 ++- jerry-core/ecma/operations/ecma-objects.c | 8 +++- jerry-core/vm/vm-utils.c | 4 +- 5 files changed, 64 insertions(+), 17 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 000bdc7c7..85c50caee 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -439,6 +439,19 @@ ecma_builtin_array_prototype_object_pop (ecma_object_t *obj_p, /**< array object return get_value; } + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY + && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + { + if (!ecma_get_object_extensible (obj_p)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument type.")); + } + + ecma_delete_fast_array_properties (obj_p, len); + + return get_value; + } + /* 5.c */ ecma_value_t del_value = ecma_op_object_delete (obj_p, index_str_p, true); @@ -481,6 +494,35 @@ ecma_builtin_array_prototype_object_push (const ecma_value_t *argument_list_p, / { ecma_number_t n = (ecma_number_t) length; + if (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_ARRAY + && ((ecma_extended_object_t *) obj_p)->u.array.is_fast_mode) + { + if (!ecma_get_object_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")); + } + + if (arguments_number == 0) + { + return ecma_make_uint32_value (length); + } + + uint32_t new_length = length + arguments_number; + ecma_value_t *buffer_p = ecma_fast_array_extend (obj_p, new_length) + length; + + for (uint32_t index = 0; index < arguments_number; index++) + { + buffer_p[index] = ecma_copy_value_if_not_object (argument_list_p[index]); + } + + return ecma_make_uint32_value (new_length); + } + /* 5. */ for (uint32_t index = 0; index < arguments_number; index++, n++) { diff --git a/jerry-core/ecma/operations/ecma-array-object.c b/jerry-core/ecma/operations/ecma-array-object.c index 03a7b2e38..cc6b57cf5 100644 --- a/jerry-core/ecma/operations/ecma-array-object.c +++ b/jerry-core/ecma/operations/ecma-array-object.c @@ -212,21 +212,13 @@ ecma_fast_array_convert_to_normal (ecma_object_t *object_p) /**< fast access mod */ bool ecma_fast_array_set_property (ecma_object_t *object_p, /**< fast access mode array object */ - ecma_string_t *property_name_p, /**< property name */ + uint32_t index, /**< property name index */ ecma_value_t value) /**< value to be set */ { JERRY_ASSERT (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARRAY); ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - - uint32_t index = ecma_string_get_array_index (property_name_p); JERRY_ASSERT (ext_obj_p->u.array.is_fast_mode); - if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX)) - { - ecma_fast_array_convert_to_normal (object_p); - return false; - } - ecma_value_t *values_p; if (JERRY_LIKELY (index < ext_obj_p->u.array.length)) @@ -327,7 +319,7 @@ ecma_fast_array_extend (ecma_object_t *object_p, /**< fast access mode array obj ext_obj_p->u.array.length = new_length; - ECMA_SET_POINTER (object_p->u1.property_list_cp, new_values_p); + ECMA_SET_NON_NULL_POINTER (object_p->u1.property_list_cp, new_values_p); ecma_deref_object (object_p); return new_values_p; @@ -391,7 +383,7 @@ ecma_array_object_delete_property (ecma_object_t *object_p, /**< object */ * * @return the updated value of new_length */ -static uint32_t +uint32_t ecma_delete_fast_array_properties (ecma_object_t *object_p, /**< fast access mode array */ uint32_t new_length) /**< new length of the fast access mode array */ { @@ -1039,7 +1031,13 @@ ecma_op_array_object_define_own_property (ecma_object_t *object_p, /**< the arra { if ((property_desc_p->flags & ECMA_FAST_ARRAY_DATA_PROP_FLAGS) == ECMA_FAST_ARRAY_DATA_PROP_FLAGS) { - if (ecma_fast_array_set_property (object_p, property_name_p, property_desc_p->value)) + uint32_t index = ecma_string_get_array_index (property_name_p); + + if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX)) + { + ecma_fast_array_convert_to_normal (object_p); + } + else if (ecma_fast_array_set_property (object_p, index, property_desc_p->value)) { return ECMA_VALUE_TRUE; } diff --git a/jerry-core/ecma/operations/ecma-array-object.h b/jerry-core/ecma/operations/ecma-array-object.h index b5de122f9..8a89e5e2b 100644 --- a/jerry-core/ecma/operations/ecma-array-object.h +++ b/jerry-core/ecma/operations/ecma-array-object.h @@ -56,12 +56,15 @@ ecma_value_t * ecma_fast_array_extend (ecma_object_t *object_p, uint32_t new_lengt); bool -ecma_fast_array_set_property (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_value_t value); +ecma_fast_array_set_property (ecma_object_t *object_p, uint32_t index, ecma_value_t value); void ecma_array_object_delete_property (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_property_value_t *prop_value_p); +uint32_t +ecma_delete_fast_array_properties (ecma_object_t *object_p, uint32_t new_length); + ecma_collection_t * ecma_fast_array_get_property_names (ecma_object_t *object_p, uint32_t opts); diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 67137ebc2..69e190483 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -1024,7 +1024,13 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ return ecma_reject (is_throw); } - if (ecma_fast_array_set_property (object_p, property_name_p, value)) + uint32_t index = ecma_string_get_array_index (property_name_p); + + if (JERRY_UNLIKELY (index == ECMA_STRING_NOT_ARRAY_INDEX)) + { + ecma_fast_array_convert_to_normal (object_p); + } + else if (ecma_fast_array_set_property (object_p, index, value)) { return ECMA_VALUE_TRUE; } diff --git a/jerry-core/vm/vm-utils.c b/jerry-core/vm/vm-utils.c index 4327e002e..8cf64224d 100644 --- a/jerry-core/vm/vm-utils.c +++ b/jerry-core/vm/vm-utils.c @@ -98,10 +98,8 @@ vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimite str_p = ecma_concat_ecma_strings (str_p, line_str_p); ecma_deref_ecma_string (line_str_p); - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); - ecma_fast_array_set_property (array_p, index_str_p, ecma_make_string_value (str_p)); + ecma_fast_array_set_property (array_p, index, ecma_make_string_value (str_p)); ecma_deref_ecma_string (str_p); - ecma_deref_ecma_string (index_str_p); context_p = context_p->prev_context_p; index++;