From 09b4d2071812b3212be80cadd016e407c1fc699b Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 30 Oct 2015 15:25:58 +0300 Subject: [PATCH] Use ecma_op_object_get_property_names for property enumeration in built-ins implementation. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- .../ecma-builtin-array-prototype.cpp | 145 +++++----- .../builtin-objects/ecma-builtin-helpers.cpp | 43 +-- .../builtin-objects/ecma-builtin-json.cpp | 133 ++++----- .../builtin-objects/ecma-builtin-object.cpp | 255 +++++++----------- jerry-core/ecma/operations/ecma-objects.cpp | 3 +- tests/jerry/json-stringify.js | 16 +- 6 files changed, 232 insertions(+), 363 deletions(-) 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 0c8600d82..f376f1864 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.cpp @@ -1222,73 +1222,58 @@ 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 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)) - { - ecma_string_t *property_name_p; + ecma_collection_header_t *array_index_props_p = ecma_op_object_get_property_names (obj_p, true, false, false); - 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 defined_prop_count = 0; + uint32_t copied_num = 0; + + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, array_index_props_p); + + /* Count properties with name that is array index less than len */ + while (ecma_collection_iterator_next (&iter) + && ecma_is_completion_value_empty (ret_value)) + { + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); uint32_t index; - if (ecma_string_get_array_index (property_name_p, &index) && index < len) + bool is_index = ecma_string_get_array_index (property_name_p, &index); + JERRY_ASSERT (is_index); + + if (index < len) { defined_prop_count++; } } MEM_DEFINE_LOCAL_ARRAY (values_buffer, defined_prop_count, ecma_value_t); - uint32_t copied_num = 0; + + ecma_collection_iterator_init (&iter, array_index_props_p); /* Copy unsorted array into a native c array. */ - 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)) + while (ecma_collection_iterator_next (&iter) + && ecma_is_completion_value_empty (ret_value)) { - 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; - } + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); uint32_t index; - if (ecma_string_get_array_index (property_name_p, &index) && index < len) + bool is_index = ecma_string_get_array_index (property_name_p, &index); + JERRY_ASSERT (is_index); + + if (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); + break; } + + 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); } - JERRY_ASSERT (copied_num == defined_prop_count || !ecma_is_completion_value_empty (ret_value)); + JERRY_ASSERT (copied_num == defined_prop_count + || !ecma_is_completion_value_empty (ret_value)); /* Sorting. */ if (copied_num > 1 && ecma_is_completion_value_empty (ret_value)) @@ -1302,7 +1287,9 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum } /* Put sorted values to the front of the array. */ - for (uint32_t 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, @@ -1312,51 +1299,41 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum ecma_deref_ecma_string (index_string_p); } - /* Undefined properties should be in the back of the array. */ - 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 *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. */ for (uint32_t index = 0; index < copied_num; index++) { ecma_free_value (values_buffer[index], true); } + MEM_FINALIZE_LOCAL_ARRAY (values_buffer); + + /* Undefined properties should be in the back of the array. */ + + ecma_collection_iterator_init (&iter, array_index_props_p); + + while (ecma_collection_iterator_next (&iter) + && ecma_is_completion_value_empty (ret_value)) + { + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + + uint32_t index; + bool is_index = ecma_string_get_array_index (property_name_p, &index); + JERRY_ASSERT (is_index); + + if (index >= copied_num && index < len) + { + ECMA_TRY_CATCH (del_value, ecma_op_object_delete (obj_p, property_name_p, true), ret_value); + ECMA_FINALIZE (del_value); + } + } + + ecma_free_values_collection (array_index_props_p, true); + if (ecma_is_completion_value_empty (ret_value)) { ret_value = ecma_make_normal_completion_value (ecma_copy_value (this_arg, true)); } - MEM_FINALIZE_LOCAL_ARRAY (values_buffer); - ECMA_OP_TO_NUMBER_FINALIZE (len_number); ECMA_FINALIZE (len_value); ecma_deref_ecma_string (magic_string_length_p); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp index 175ef86b8..e7cad2280 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.cpp @@ -185,7 +185,7 @@ ecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, /** < t /** - * The Object.keys and Object.getOwnPropertyName routine's common part. + * The Object.keys and Object.getOwnPropertyNames routine's common part. * * See also: * ECMA-262 v5, 15.2.3.4 steps 2-5 @@ -206,39 +206,21 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /** < object */ uint32_t index = 0; - 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)) + ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, + false, + only_enumerable_properties, + false); + + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, props_p); + + while (ecma_collection_iterator_next (&iter)) { - 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; - } - - if (only_enumerable_properties && !ecma_is_property_enumerable (property_p)) - { - continue; - } - - JERRY_ASSERT (property_name_p != NULL); - ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_completion_value_t completion = ecma_builtin_helper_def_prop (new_array_p, index_string_p, - ecma_make_string_value (property_name_p), + *iter.current_value_p, true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ @@ -246,12 +228,13 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /** < object */ JERRY_ASSERT (ecma_is_completion_value_normal_true (completion)); - ecma_free_completion_value (completion); ecma_deref_ecma_string (index_string_p); index++; } + ecma_free_values_collection (props_p, true); + return new_array; } /* ecma_builtin_helper_object_get_properties */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-json.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-json.cpp index f0fa4645f..04dbb4d39 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-json.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-json.cpp @@ -625,91 +625,45 @@ ecma_builtin_json_walk (ecma_object_t *reviver_p, /**< reviver function */ { ecma_object_t *object_p = ecma_get_object_from_value (value_get); - uint32_t no_properties = 0; + ecma_collection_header_t *props_p = ecma_op_object_get_property_names (object_p, false, true, false); - /* - * The following algorithm works with arrays and objects as well. - */ - for (ecma_property_t *property_p = ecma_get_property_list (object_p); - property_p != NULL; - property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, props_p); + + while (ecma_collection_iterator_next (&iter) + && ecma_is_completion_value_empty (ret_value)) { + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + + ECMA_TRY_CATCH (value_walk, + ecma_builtin_json_walk (reviver_p, + object_p, + property_name_p), + ret_value); + /* - * All properties must be named data or internal properties, since we constructed them. + * We cannot optimize this function since any members + * can be changed (deleted) by the reviver function. */ - JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA - || property_p->type == ECMA_PROPERTY_INTERNAL); - - if (property_p->type == ECMA_PROPERTY_NAMEDDATA - && ecma_is_property_enumerable (property_p)) + if (ecma_is_value_undefined (value_walk)) { - no_properties++; + ecma_completion_value_t delete_val = ecma_op_general_object_delete (object_p, + property_name_p, + false); + JERRY_ASSERT (ecma_is_completion_value_normal_true (delete_val) + || ecma_is_completion_value_normal_false (delete_val)); } + else + { + ecma_builtin_json_define_value_property (object_p, + property_name_p, + value_walk); + } + + ECMA_FINALIZE (value_walk); } - if (no_properties > 0) - { - MEM_DEFINE_LOCAL_ARRAY (property_names_p, no_properties, ecma_string_t *); - - uint32_t property_index = no_properties; - for (ecma_property_t *property_p = ecma_get_property_list (object_p); - property_p != NULL; - property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) - { - if (property_p->type == ECMA_PROPERTY_NAMEDDATA - && ecma_is_property_enumerable (property_p)) - { - ecma_string_t *property_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, - property_p->u.named_data_property.name_p); - /* - * The property list must be in creation order. - */ - property_index--; - property_names_p[property_index] = ecma_copy_or_ref_ecma_string (property_name_p); - } - } - - JERRY_ASSERT (property_index == 0); - - for (property_index = 0; - property_index < no_properties && ecma_is_completion_value_empty (ret_value); - property_index++) - { - ECMA_TRY_CATCH (value_walk, - ecma_builtin_json_walk (reviver_p, - object_p, - property_names_p[property_index]), - ret_value); - - /* - * We cannot optimize this function since any members - * can be changed (deleted) by the reviver function. - */ - if (ecma_is_value_undefined (value_walk)) - { - ecma_completion_value_t delete_val = ecma_op_general_object_delete (object_p, - property_names_p[property_index], - false); - JERRY_ASSERT (ecma_is_completion_value_normal_true (delete_val) - || ecma_is_completion_value_normal_false (delete_val)); - } - else - { - ecma_builtin_json_define_value_property (object_p, - property_names_p[property_index], - value_walk); - } - - ECMA_FINALIZE (value_walk); - } - - for (uint32_t i = 0; i < no_properties; i++) - { - ecma_deref_ecma_string (property_names_p[i]); - } - - MEM_FINALIZE_LOCAL_ARRAY (property_names_p); - } + ecma_free_values_collection (props_p, true); } if (ecma_is_completion_value_empty (ret_value)) @@ -1492,20 +1446,25 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ { property_keys_p = ecma_new_values_collection (NULL, 0, true); - 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)) + ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, true, false); + + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, props_p); + + while (ecma_collection_iterator_next (&iter)) { - if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_enumerable (property_p)) + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); + + JERRY_ASSERT (ecma_is_property_enumerable (property_p)); + + if (property_p->type == ECMA_PROPERTY_NAMEDDATA) { - ecma_string_t *prop_key = ECMA_GET_NON_NULL_POINTER (ecma_string_t, - property_p->u.named_data_property.name_p); - - JERRY_ASSERT (prop_key != NULL); - - ecma_append_to_values_collection (property_keys_p, ecma_make_string_value (prop_key), true); + ecma_append_to_values_collection (property_keys_p, *iter.current_value_p, true); } } + + ecma_free_values_collection (props_p, true); } /* 7. */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp b/jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp index f3829ac05..2534fb8b7 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.cpp @@ -199,27 +199,16 @@ ecma_builtin_object_object_seal (ecma_value_t this_arg __attr_unused___, /**< 't // 2. ecma_object_t *obj_p = ecma_get_object_from_value (arg); - ecma_property_t *property_p; - for (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 *property_name_p; + ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); - 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; - } + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, props_p); + + while (ecma_collection_iterator_next (&iter) + && ecma_is_completion_value_empty (ret_value)) + { + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2.a ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (property_p); @@ -242,6 +231,8 @@ ecma_builtin_object_object_seal (ecma_value_t this_arg __attr_unused___, /**< 't ecma_free_property_descriptor (&prop_desc); } + ecma_free_values_collection (props_p, true); + if (ecma_is_completion_value_empty (ret_value)) { // 3. @@ -280,28 +271,17 @@ ecma_builtin_object_object_freeze (ecma_value_t this_arg __attr_unused___, /**< // 2. ecma_object_t *obj_p = ecma_get_object_from_value (arg); - ecma_property_t *property_p; - for (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 *property_name_p; + ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); - 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; - } + + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, props_p); + + while (ecma_collection_iterator_next (&iter) + && ecma_is_completion_value_empty (ret_value)) + { + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); // 2.a ecma_property_descriptor_t prop_desc = ecma_get_property_descriptor_from_property (property_p); @@ -330,6 +310,8 @@ ecma_builtin_object_object_freeze (ecma_value_t this_arg __attr_unused___, /**< ecma_free_property_descriptor (&prop_desc); } + ecma_free_values_collection (props_p, true); + if (ecma_is_completion_value_empty (ret_value)) { // 3. @@ -396,41 +378,45 @@ ecma_builtin_object_object_is_sealed (ecma_value_t this_arg __attr_unused___, /* else { ecma_object_t *obj_p = ecma_get_object_from_value (arg); - ecma_property_t *property_p; - // This will be the result if the other steps doesn't change it. - bool sealed = false; + bool is_sealed; // 3. - // The pseudo code contains multiple early return but this way we get the same - // result. - if (!ecma_get_object_extensible (obj_p)) + if (ecma_get_object_extensible (obj_p)) { - sealed = true; + is_sealed = false; } - - // 2. - for (property_p = ecma_get_property_list (obj_p); - property_p != NULL && sealed; - property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) + else { - if (property_p->type == ECMA_PROPERTY_INTERNAL) + /* the value can be updated in the loop below */ + is_sealed = true; + + // 2. + ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); + + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, props_p); + + while (ecma_collection_iterator_next (&iter)) { - continue; + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + + // 2.a + ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); + + // 2.b + if (ecma_is_property_configurable (property_p)) + { + is_sealed = false; + break; + } } - JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR); - - // 2.b - if (ecma_is_property_configurable (property_p)) - { - sealed = false; - break; - } + ecma_free_values_collection (props_p, true); } // 4. - ret_value = ecma_make_simple_completion_value (sealed + ret_value = ecma_make_simple_completion_value (is_sealed ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } @@ -461,48 +447,53 @@ ecma_builtin_object_object_is_frozen (ecma_value_t this_arg __attr_unused___, /* else { ecma_object_t *obj_p = ecma_get_object_from_value (arg); - ecma_property_t *property_p; - // This will be the result if the other steps doesn't change it. - bool frozen = false; + bool is_frozen; // 3. - // The pseudo code contains multiple early return but this way we get the same - // result. - if (!ecma_get_object_extensible (obj_p)) + if (ecma_get_object_extensible (obj_p)) { - frozen = true; + is_frozen = false; } - - // 2. - for (property_p = ecma_get_property_list (obj_p); - property_p != NULL && frozen; - property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) + else { - if (property_p->type == ECMA_PROPERTY_INTERNAL) + is_frozen = true; + + // 2. + ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); + + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, props_p); + + while (ecma_collection_iterator_next (&iter)) { - continue; + ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + + // 2.a + ecma_property_t *property_p = ecma_op_object_get_own_property (obj_p, property_name_p); + + JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR); + + // 2.b + if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p)) + { + is_frozen = false; + break; + } + + // 2.c + if (ecma_is_property_configurable (property_p)) + { + is_frozen = false; + break; + } } - JERRY_ASSERT (property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR); - - // 2.b - if (property_p->type == ECMA_PROPERTY_NAMEDDATA && ecma_is_property_writable (property_p)) - { - frozen = false; - break; - } - - // 2.c - if (ecma_is_property_configurable (property_p)) - { - frozen = false; - break; - } + ecma_free_values_collection (props_p, true); } // 4. - ret_value = ecma_make_simple_completion_value (frozen + ret_value = ecma_make_simple_completion_value (is_frozen ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE); } @@ -716,69 +707,30 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg __attr_unuse ret_value); ecma_object_t *props_p = ecma_get_object_from_value (props); - ecma_property_t *property_p; - - // First we need to know how many properties should be stored - uint32_t property_number = 0; - for (property_p = ecma_get_property_list (props_p); - property_p != NULL; - property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) - { - if ((property_p->type == ECMA_PROPERTY_NAMEDDATA || property_p->type == ECMA_PROPERTY_NAMEDACCESSOR) - && ecma_is_property_enumerable (property_p)) - { - property_number++; - } - } - // 3. - MEM_DEFINE_LOCAL_ARRAY (property_names_p, property_number, ecma_string_t*); + ecma_collection_header_t *prop_names_p = ecma_op_object_get_property_names (props_p, false, true, false); + uint32_t property_number = prop_names_p->unit_number; - uint32_t index = 0; - for (property_p = ecma_get_property_list (props_p); - property_p != NULL; - property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p)) - { - 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; - } - - if (ecma_is_property_enumerable (property_p)) - { - property_names_p[index++] = ecma_copy_or_ref_ecma_string (property_name_p); - } - } + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, prop_names_p); // 4. MEM_DEFINE_LOCAL_ARRAY (property_descriptors, property_number, ecma_property_descriptor_t); + uint32_t property_descriptor_number = 0; - for (index = 0; - index < property_number && ecma_is_completion_value_empty (ret_value); - index++) + while (ecma_collection_iterator_next (&iter) + && ecma_is_completion_value_empty (ret_value)) { // 5.a ECMA_TRY_CATCH (desc_obj, - ecma_op_object_get (props_p, property_names_p[index]), + ecma_op_object_get (props_p, ecma_get_string_from_value (*iter.current_value_p)), ret_value); // 5.b ECMA_TRY_CATCH (conv_result, ecma_op_to_property_descriptor (desc_obj, - &property_descriptors[index]), + &property_descriptors[property_descriptor_number]), ret_value); property_descriptor_number++; @@ -788,13 +740,17 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg __attr_unuse } // 6. - for (index = 0; + ecma_collection_iterator_init (&iter, prop_names_p); + for (uint32_t index = 0; index < property_number && ecma_is_completion_value_empty (ret_value); index++) { + bool is_next = ecma_collection_iterator_next (&iter); + JERRY_ASSERT (is_next); + ECMA_TRY_CATCH (define_own_prop_ret, ecma_op_object_define_own_property (obj_p, - property_names_p[index], + ecma_get_string_from_value (*iter.current_value_p), &property_descriptors[index], true), ret_value); @@ -803,7 +759,7 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg __attr_unuse } // Clean up - for (index = 0; + for (uint32_t index = 0; index < property_descriptor_number; index++) { @@ -812,14 +768,7 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg __attr_unuse MEM_FINALIZE_LOCAL_ARRAY (property_descriptors); - for (index = 0; - index < property_number; - index++) - { - ecma_deref_ecma_string (property_names_p[index]); - } - - MEM_FINALIZE_LOCAL_ARRAY (property_names_p); + ecma_free_values_collection (prop_names_p, true); // 7. if (ecma_is_completion_value_empty (ret_value)) diff --git a/jerry-core/ecma/operations/ecma-objects.cpp b/jerry-core/ecma/operations/ecma-objects.cpp index 570b5b78a..11e759f67 100644 --- a/jerry-core/ecma/operations/ecma-objects.cpp +++ b/jerry-core/ecma/operations/ecma-objects.cpp @@ -644,7 +644,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ uint32_t insertion_pos = 0; while (insertion_pos < array_index_name_pos - && index <= array_index_names_p[insertion_pos]) + && index < array_index_names_p[insertion_pos]) { insertion_pos++; } @@ -656,6 +656,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ else { JERRY_ASSERT (insertion_pos < array_index_name_pos); + JERRY_ASSERT (index < array_index_names_p[insertion_pos]); uint32_t move_pos = ++array_index_name_pos; diff --git a/tests/jerry/json-stringify.js b/tests/jerry/json-stringify.js index 59aac295e..d8e83c267 100644 --- a/tests/jerry/json-stringify.js +++ b/tests/jerry/json-stringify.js @@ -52,15 +52,15 @@ empty_object.a = undefined; assert (JSON.stringify (empty_object) == '{}'); p_object = { "a": 1, "b": true, "c": "foo", "d": null, "e": undefined }; -assert (JSON.stringify (p_object) == '{"d":null,"c":"foo","b":true,"a":1}'); +assert (JSON.stringify (p_object) == '{"a":1,"b":true,"c":"foo","d":null}'); o_object = { "a": new Number(1), "b": new Boolean(true), "c": new String("foo") }; -assert (JSON.stringify (o_object) == '{"c":"foo","b":true,"a":1}'); +assert (JSON.stringify (o_object) == '{"a":1,"b":true,"c":"foo"}'); child = { "a": 1, "b": new String("\nfoo"), "c": undefined }; parent = { "a": true, "b": child, "c": null}; -assert (JSON.stringify (parent) == '{"c":null,"b":{"b":"\\nfoo","a":1},"a":true}'); +assert (JSON.stringify (parent) == '{"a":true,"b":{"a":1,"b":"\\nfoo"},"c":null}'); recursive_object = {}; recursive_object.a = 2; @@ -105,13 +105,13 @@ try { } object = {"a": 1, "b": [1, true, {"a": "foo"}]}; -assert (JSON.stringify (object) == '{"b":[1,true,{"a":"foo"}],"a":1}'); +assert (JSON.stringify (object) == '{"a":1,"b":[1,true,{"a":"foo"}]}'); object = {"a": [1], "b": {}}; -assert (JSON.stringify(object) === '{"b":{},"a":[1]}'); +assert (JSON.stringify(object) === '{"a":[1],"b":{}}'); array = [1, {"a": 2, "b": true, c: [3]}]; -assert (JSON.stringify (array) == '[1,{"c":[3],"b":true,"a":2}]'); +assert (JSON.stringify (array) == '[1,{"a":2,"b":true,"c":[3]}]'); // Filtering / replacing to_json_object = {}; @@ -128,7 +128,7 @@ function replacer_function (key, value) } object = { "a": "JSON", "b": new String("JSON"), "c": 3 }; -assert (JSON.stringify (object, replacer_function) == '{"c":3,"b":"JSON","a":"FOO"}'); +assert (JSON.stringify (object, replacer_function) == '{"a":"FOO","b":"JSON","c":3}'); filter = ["a", "b"]; assert (JSON.stringify (object, filter) == '{"a":"JSON","b":"JSON"}'); @@ -198,7 +198,7 @@ assert (JSON.stringify (array, null, 100) == '[\n 2\n]'); assert (JSON.stringify (array, null, -5) == '[2]'); nested_object = {"a": 2, "b": {"c": 1, "d": true}}; -assert (JSON.stringify (nested_object, null, 2) == '{\n "b": {\n "d": true,\n "c": 1\n },\n "a": 2\n}'); +assert (JSON.stringify (nested_object, null, 2) == '{\n "a": 2,\n "b": {\n "c": 1,\n "d": true\n }\n}'); nested_array = [2, [1,true]]; assert (JSON.stringify (nested_array, null, 2) == '[\n 2,\n [\n 1,\n true\n ]\n]');