From a2c6663d43321f17a1ff10f04a59526a52629ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20B=C3=A1tyai?= Date: Tue, 14 Jul 2015 13:25:11 +0200 Subject: [PATCH] Array.prototype.sort() now handles defined properties only. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com --- jerry-core/ecma/base/ecma-helpers-string.cpp | 33 +++++++ jerry-core/ecma/base/ecma-helpers.h | 1 + .../ecma-builtin-array-prototype.cpp | 93 +++++++++++++++---- .../ecma/operations/ecma-array-object.cpp | 23 +---- 4 files changed, 112 insertions(+), 38 deletions(-) diff --git a/jerry-core/ecma/base/ecma-helpers-string.cpp b/jerry-core/ecma/base/ecma-helpers-string.cpp index 4e05d2ddd..8ae12e963 100644 --- a/jerry-core/ecma/base/ecma-helpers-string.cpp +++ b/jerry-core/ecma/base/ecma-helpers-string.cpp @@ -992,6 +992,39 @@ ecma_string_to_number (const ecma_string_t *str_p) /**< ecma-string */ JERRY_UNREACHABLE (); } /* ecma_string_to_number */ +/** + * Check if string is array index. + * + * @return true - if string is valid array index + * false - otherwise + */ +bool +ecma_string_get_array_index (const ecma_string_t *str_p, /**< ecma-string */ + uint32_t *out_index_p) /**< out: index */ +{ + bool is_array_index = true; + if (str_p->container == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + { + *out_index_p = str_p->u.uint32_number; + } + else + { + ecma_number_t num = ecma_string_to_number (str_p); + *out_index_p = ecma_number_to_uint32 (num); + + ecma_string_t *to_uint32_to_string_p = ecma_new_ecma_string_from_uint32 (*out_index_p); + + is_array_index = ecma_compare_ecma_strings (str_p, + to_uint32_to_string_p); + + ecma_deref_ecma_string (to_uint32_to_string_p); + } + + is_array_index = is_array_index && (*out_index_p != ECMA_MAX_VALUE_OF_VALID_ARRAY_INDEX); + + return is_array_index; +} /* ecma_string_is_array_index */ + /** * Convert ecma-string's contents to a utf-8 string and put it to the buffer. * diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index cc83c05c1..78107d7d6 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -125,6 +125,7 @@ extern ecma_string_t* ecma_copy_or_ref_ecma_string (ecma_string_t *string_desc_p extern void ecma_deref_ecma_string (ecma_string_t *string_p); extern void ecma_check_that_ecma_string_need_not_be_freed (const ecma_string_t *string_p); extern ecma_number_t ecma_string_to_number (const ecma_string_t *str_p); +extern bool ecma_string_get_array_index (const ecma_string_t *str_p, uint32_t *index); extern ssize_t ecma_string_to_utf8_string (const ecma_string_t *string_desc_p, lit_utf8_byte_t *buffer_p, ssize_t buffer_size); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp index 10302c060..12112bf59 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp @@ -1449,36 +1449,75 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum uint32_t len = ecma_number_to_uint32 (len_number); uint32_t defined_prop_count = 0; - /* Count number of defined properties. */ + /* Count number of array index properties. */ for (ecma_property_t *property_p = ecma_get_property_list (obj_p); property_p != NULL; property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) { - defined_prop_count++; + ecma_string_t *property_name_p; + + if (property_p->type == ECMA_PROPERTY_NAMEDDATA) + { + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + property_p->u.named_data_property.name_p); + } + else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR) + { + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + property_p->u.named_accessor_property.name_p); + } + else + { + continue; + } + + uint32_t index; + if (ecma_string_get_array_index (property_name_p, &index) && index < len) + { + defined_prop_count++; + } } MEM_DEFINE_LOCAL_ARRAY (values_buffer, defined_prop_count, ecma_value_t); uint32_t copied_num = 0; /* Copy unsorted array into a native c array. */ - for (uint32_t index = 0; index < len && ecma_is_completion_value_empty (ret_value); index++) + for (ecma_property_t *property_p = ecma_get_property_list (obj_p); + property_p != NULL && ecma_is_completion_value_empty (ret_value); + property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) { - ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); - if (ecma_op_object_get_property (obj_p, index_string_p) != NULL) + ecma_string_t *property_name_p; + + if (property_p->type == ECMA_PROPERTY_NAMEDDATA) { - ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, index_string_p), ret_value); + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + property_p->u.named_data_property.name_p); + } + else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR) + { + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + property_p->u.named_accessor_property.name_p); + } + else + { + continue; + } + + uint32_t index; + if (ecma_string_get_array_index (property_name_p, &index) && index < len) + { + ECMA_TRY_CATCH (index_value, ecma_op_object_get (obj_p, property_name_p), ret_value); values_buffer[copied_num++] = ecma_copy_value (index_value, true); ECMA_FINALIZE (index_value); } - ecma_deref_ecma_string (index_string_p); } - JERRY_ASSERT (copied_num <= defined_prop_count); + JERRY_ASSERT (copied_num == defined_prop_count || !ecma_is_completion_value_empty (ret_value)); /* Sorting. */ - if (len > 1 && ecma_is_completion_value_empty (ret_value)) + if (copied_num > 1 && ecma_is_completion_value_empty (ret_value)) { ECMA_TRY_CATCH (sort_value, ecma_builtin_array_prototype_object_array_heap_sort_helper (values_buffer, @@ -1489,8 +1528,7 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum } /* Put sorted values to the front of the array. */ - uint32_t index; - for (index = 0; index < copied_num && ecma_is_completion_value_empty (ret_value); index++) + for (uint32_t index = 0; index < copied_num && ecma_is_completion_value_empty (ret_value); index++) { ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ECMA_TRY_CATCH (put_value, @@ -1501,12 +1539,35 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum } /* Undefined properties should be in the back of the array. */ - for (;index < len && ecma_is_completion_value_empty (ret_value); index++) + ecma_property_t *next_prop; + for (ecma_property_t *property_p = ecma_get_property_list (obj_p); + property_p != NULL && ecma_is_completion_value_empty (ret_value); + property_p = next_prop) { - ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); - ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, index_string_p, true), ret_value); - ECMA_FINALIZE (del_value); - ecma_deref_ecma_string (index_string_p); + ecma_string_t *property_name_p; + next_prop = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p); + + if (property_p->type == ECMA_PROPERTY_NAMEDDATA) + { + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + property_p->u.named_data_property.name_p); + } + else if (property_p->type == ECMA_PROPERTY_NAMEDACCESSOR) + { + property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + property_p->u.named_accessor_property.name_p); + } + else + { + continue; + } + + uint32_t index; + if (ecma_string_get_array_index (property_name_p, &index) && index < len && index >= copied_num) + { + ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, property_name_p, true), ret_value); + ECMA_FINALIZE (del_value); + } } /* Free values that were copied to the local array. */ diff --git a/jerry-core/ecma/operations/ecma-array-object.cpp b/jerry-core/ecma/operations/ecma-array-object.cpp index 5e6e00e93..49a074f68 100644 --- a/jerry-core/ecma/operations/ecma-array-object.cpp +++ b/jerry-core/ecma/operations/ecma-array-object.cpp @@ -386,29 +386,8 @@ ecma_op_array_object_define_own_property (ecma_object_t *obj_p, /**< the array o { // 4.a. uint32_t index; - bool is_index; - if (property_name_p->container == ECMA_STRING_CONTAINER_UINT32_IN_DESC) - { - index = property_name_p->u.uint32_number; - is_index = true; - } - else - { - ecma_number_t number = ecma_string_to_number (property_name_p); - index = ecma_number_to_uint32 (number); - - ecma_string_t *to_uint32_to_string_p = ecma_new_ecma_string_from_uint32 (index); - - is_index = ecma_compare_ecma_strings (property_name_p, - to_uint32_to_string_p); - - ecma_deref_ecma_string (to_uint32_to_string_p); - } - - is_index = is_index && (index != ECMA_MAX_VALUE_OF_VALID_ARRAY_INDEX); - - if (!is_index) + if (!ecma_string_get_array_index (property_name_p, &index)) { // 5. return ecma_op_general_object_define_own_property (obj_p,