From da47c671e71bfa3a6da42b7b012579e220b2f080 Mon Sep 17 00:00:00 2001 From: Ruben Ayrapetyan Date: Fri, 30 Oct 2015 22:19:33 +0300 Subject: [PATCH] List of lazy instantiated properties' names in ecma_op_object_get_property_names. JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com --- ...a-builtin-internal-routines-template.inc.h | 120 +++++++++ .../builtin-objects/ecma-builtins-internal.h | 5 + .../ecma/builtin-objects/ecma-builtins.cpp | 77 ++++++ .../ecma/builtin-objects/ecma-builtins.h | 5 + .../ecma/operations/ecma-function-object.cpp | 38 +++ .../ecma/operations/ecma-function-object.h | 6 + jerry-core/ecma/operations/ecma-objects.cpp | 234 ++++++++++++------ .../ecma/operations/ecma-string-object.cpp | 51 +++- .../ecma/operations/ecma-string-object.h | 7 + 9 files changed, 464 insertions(+), 79 deletions(-) diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h index e4d6ac733..33f61c540 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-internal-routines-template.inc.h @@ -21,6 +21,8 @@ # error "Please, define BUILTIN_INC_HEADER_NAME" #endif /* !BUILTIN_INC_HEADER_NAME */ +#include "ecma-objects.h" + #define PASTE__(x, y) x ## y #define PASTE_(x, y) PASTE__ (x, y) #define PASTE(x, y) PASTE_ (x, y) @@ -29,6 +31,8 @@ PASTE (PASTE (ecma_builtin_, builtin_underscored_id), _sort_property_names) #define TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME(builtin_underscored_id) \ PASTE (PASTE (ecma_builtin_, builtin_underscored_id), _try_to_instantiate_property) +#define LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME(builtin_underscored_id) \ + PASTE (PASTE (ecma_builtin_, builtin_underscored_id), _list_lazy_property_names) #define DISPATCH_ROUTINE_ROUTINE_NAME(builtin_underscored_id) \ PASTE (PASTE (ecma_builtin_, builtin_underscored_id), _dispatch_routine) @@ -268,6 +272,122 @@ TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (ecma_object_t return prop_p; } /* TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME */ +/** + * List names of the built-in object's lazy instantiated properties + * + * See also: + * TRY_TO_INSTANTIATE_PROPERTY_ROUTINE_NAME + * + * @return string values collection + */ +void +LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME (BUILTIN_UNDERSCORED_ID) (ecma_object_t *object_p, /**< a built-in object */ + /** true - list enumerable properties + * into main collection, + * and non-enumerable to + * collection of 'skipped + * non-enumerable' + * properties, + * false - list all properties into + * main collection. + */ + bool separate_enumerable, + /** 'main' collection */ + ecma_collection_header_t *main_collection_p, + /** skipped 'non-enumerable' collection */ + ecma_collection_header_t *non_enum_collection_p) +{ + ecma_collection_header_t *for_enumerable_p = main_collection_p; + (void) for_enumerable_p; + + ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + +#define OBJECT_ID(builtin_id) const ecma_builtin_id_t builtin_object_id = builtin_id; +#include BUILTIN_INC_HEADER_NAME + + JERRY_ASSERT (ecma_builtin_is (object_p, builtin_object_id)); + + const ecma_length_t properties_number = (ecma_length_t) (sizeof (ecma_builtin_property_names) / + sizeof (ecma_builtin_property_names[0])); + + for (ecma_length_t i = 0; + i < properties_number; + i++) + { + lit_magic_string_id_t name = ecma_builtin_property_names[i]; + + int32_t index; + index = ecma_builtin_bin_search_for_magic_string_id_in_array (ecma_builtin_property_names, + properties_number, + name); + + uint32_t bit; + ecma_internal_property_id_t mask_prop_id; + + if (index >= 32) + { + mask_prop_id = ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63; + bit = (uint32_t) 1u << (index - 32); + } + else + { + mask_prop_id = ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31; + bit = (uint32_t) 1u << index; + } + + ecma_property_t *mask_prop_p = ecma_find_internal_property (object_p, mask_prop_id); + bool is_instantiated = false; + if (mask_prop_p == NULL) + { + is_instantiated = true; + } + else + { + uint32_t bit_mask = mask_prop_p->u.internal_property.value; + + if (bit_mask & bit) + { + is_instantiated = true; + } + else + { + is_instantiated = false; + } + } + + bool is_existing; + + ecma_string_t *name_p = ecma_get_magic_string (name); + + if (!is_instantiated) + { + /* will be instantiated upon first request */ + is_existing = true; + } + else + { + if (ecma_op_object_get_own_property (object_p, name_p) == NULL) + { + is_existing = false; + } + else + { + is_existing = true; + } + } + + if (is_existing) + { + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_string_value (name_p), + true); + } + + ecma_deref_ecma_string (name_p); + } +} /* LIST_LAZY_PROPERTY_NAMES_ROUTINE_NAME */ + + /** * Dispatcher of the built-in's routines * diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h b/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h index 65e5f615c..98ab2e446 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h @@ -85,6 +85,11 @@ extern ecma_property_t * \ ecma_builtin_ ## lowercase_name ## _try_to_instantiate_property (ecma_object_t *, \ ecma_string_t *); \ extern void \ +ecma_builtin_ ## lowercase_name ## _list_lazy_property_names (ecma_object_t *, \ + bool, \ + ecma_collection_header_t *, \ + ecma_collection_header_t *); \ +extern void \ ecma_builtin_ ## lowercase_name ## _sort_property_names (void); #include "ecma-builtins.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.cpp b/jerry-core/ecma/builtin-objects/ecma-builtins.cpp index 244e76dab..b4dcf3c68 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.cpp +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.cpp @@ -378,6 +378,83 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * } } /* ecma_builtin_try_to_instantiate_property */ +/** + * List names of a built-in object's lazy instantiated properties + * + * See also: + * ecma_builtin_try_to_instantiate_property + */ +void +ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in object */ + bool separate_enumerable, /**< true - list enumerable properties into + * main collection, and non-enumerable + * to collection of 'skipped non-enumerable' + * properties, + * false - list all properties into main collection. + */ + ecma_collection_header_t *main_collection_p, /**< 'main' collection */ + ecma_collection_header_t *non_enum_collection_p) /**< skipped 'non-enumerable' + * collection */ +{ + const ecma_object_type_t type = ecma_get_object_type (object_p); + + if (type == ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION) + { + ecma_collection_header_t *for_enumerable_p = main_collection_p; + (void) for_enumerable_p; + + ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + + /* 'length' property is non-enumerable (ECMA-262 v5, 15) */ + ecma_string_t *name_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); + } + else + { + ecma_property_t *built_in_id_prop_p = ecma_get_internal_property (object_p, + ECMA_INTERNAL_PROPERTY_BUILT_IN_ID); + ecma_builtin_id_t builtin_id = (ecma_builtin_id_t) built_in_id_prop_p->u.internal_property.value; + + JERRY_ASSERT (ecma_builtin_is (object_p, builtin_id)); + + switch (builtin_id) + { +#define BUILTIN(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + is_static, \ + lowercase_name) \ + case builtin_id: \ + { \ + ecma_builtin_ ## lowercase_name ## _list_lazy_property_names (object_p, \ + separate_enumerable, \ + main_collection_p, \ + non_enum_collection_p); \ + return; \ + } +#include "ecma-builtins.inc.h" + + case ECMA_BUILTIN_ID__COUNT: + { + JERRY_UNREACHABLE (); + } + + default: + { +#ifdef CONFIG_ECMA_COMPACT_PROFILE + JERRY_UNREACHABLE (); +#else /* CONFIG_ECMA_COMPACT_PROFILE */ + JERRY_UNIMPLEMENTED ("The built-in is not implemented."); +#endif /* !CONFIG_ECMA_COMPACT_PROFILE */ + } + } + + JERRY_UNREACHABLE (); + } +} /* ecma_builtin_list_and_lazy_property_names */ + /** * Construct a Function object for specified built-in routine * diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.h b/jerry-core/ecma/builtin-objects/ecma-builtins.h index a18c3d04b..989f7a518 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.h @@ -44,6 +44,11 @@ extern ecma_completion_value_t ecma_builtin_dispatch_construct (ecma_object_t *, ecma_collection_header_t *); extern ecma_property_t * ecma_builtin_try_to_instantiate_property (ecma_object_t *, ecma_string_t *); +extern void +ecma_builtin_list_lazy_property_names (ecma_object_t *, + bool, + ecma_collection_header_t *, + ecma_collection_header_t *); extern bool ecma_builtin_is (ecma_object_t *, ecma_builtin_id_t); extern ecma_object_t * diff --git a/jerry-core/ecma/operations/ecma-function-object.cpp b/jerry-core/ecma/operations/ecma-function-object.cpp index 0639ede9b..582f92b68 100644 --- a/jerry-core/ecma/operations/ecma-function-object.cpp +++ b/jerry-core/ecma/operations/ecma-function-object.cpp @@ -312,6 +312,44 @@ ecma_op_create_function_object (ecma_collection_header_t *formal_params_collecti return f; } /* ecma_op_create_function_object */ +/** + * List names of a Function object's lazy instantiated properties, + * adding them to corresponding string collections + * + * See also: + * ecma_op_function_try_lazy_instantiate_property + */ +void +ecma_op_function_list_lazy_property_names (bool separate_enumerable, /**< true - list enumerable properties into + * main collection and non-enumerable + * to collection of 'skipped + * non-enumerable' properties, + * false - list all properties into main + * collection. + */ + ecma_collection_header_t *main_collection_p, /**< 'main' collection */ + ecma_collection_header_t *non_enum_collection_p) /**< skipped + * 'non-enumerable' + * collection */ +{ + ecma_collection_header_t *for_enumerable_p = main_collection_p; + (void) for_enumerable_p; + + ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; + + ecma_string_t *name_p; + + /* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */ + name_p = ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); + + /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ + name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); + ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); + ecma_deref_ecma_string (name_p); +} /* ecma_op_function_list_lazy_property_names */ + /** * Lazy instantation of non-builtin ecma function object's properties * diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 7337fa73b..fd5ff302a 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -32,6 +32,12 @@ extern bool ecma_is_constructor (ecma_value_t); extern ecma_object_t * ecma_op_create_function_object (ecma_collection_header_t *, ecma_object_t *, bool, bool, const bytecode_data_header_t *, vm_instr_counter_t); + +extern void +ecma_op_function_list_lazy_property_names (bool, + ecma_collection_header_t *, + ecma_collection_header_t *); + extern ecma_object_t * ecma_op_create_external_function_object (ecma_external_pointer_t); diff --git a/jerry-core/ecma/operations/ecma-objects.cpp b/jerry-core/ecma/operations/ecma-objects.cpp index 2c5c159b4..2cdc0759a 100644 --- a/jerry-core/ecma/operations/ecma-objects.cpp +++ b/jerry-core/ecma/operations/ecma-objects.cpp @@ -540,9 +540,15 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ bool is_with_prototype_chain) /**< true - list properties from prototype chain, * false - list only own properties */ { + JERRY_ASSERT (obj_p != NULL + && !ecma_is_lexical_environment (obj_p)); + ecma_collection_header_t *ret_p = ecma_new_strings_collection (NULL, 0); ecma_collection_header_t *skipped_non_enumerable_p = ecma_new_strings_collection (NULL, 0); + const ecma_object_type_t type = ecma_get_object_type (obj_p); + ecma_assert_object_type_is_valid (type); + const size_t bitmap_row_size = sizeof (uint32_t) * JERRY_BITSINBYTE; uint32_t names_hashes_bitmap[(1u << LIT_STRING_HASH_BITS) / bitmap_row_size]; @@ -555,64 +561,68 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ { ecma_length_t string_named_properties_count = 0; ecma_length_t array_index_named_properties_count = 0; - ecma_length_t skipped_non_enumerable_properties_count = 0; - /* First pass: counting properties */ - for (ecma_property_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p); - prop_iter_p != NULL; - prop_iter_p = ECMA_GET_POINTER (ecma_property_t, prop_iter_p->next_property_p)) + ecma_collection_header_t *prop_names_p = ecma_new_strings_collection (NULL, 0); + + if (ecma_get_object_is_builtin (obj_p)) { - if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA - || prop_iter_p->type == ECMA_PROPERTY_NAMEDACCESSOR) + ecma_builtin_list_lazy_property_names (obj_p, + is_enumerable_only, + prop_names_p, + skipped_non_enumerable_p); + } + else + { + switch (type) { - ecma_string_t *name_p; - - if (prop_iter_p->type == ECMA_PROPERTY_NAMEDDATA) + case ECMA_OBJECT_TYPE_FUNCTION: { - name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_iter_p->u.named_data_property.name_p); - } - else - { - JERRY_ASSERT (prop_iter_p->type == ECMA_PROPERTY_NAMEDACCESSOR); - - name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_iter_p->u.named_accessor_property.name_p); + ecma_op_function_list_lazy_property_names (is_enumerable_only, + prop_names_p, + skipped_non_enumerable_p); + break; } - if (!(is_enumerable_only && !ecma_is_property_enumerable (prop_iter_p))) + case ECMA_OBJECT_TYPE_STRING: { - uint32_t index; - - if (ecma_string_get_array_index (name_p, &index)) - { - /* name_p is a valid array index */ - array_index_named_properties_count++; - } - else if (!is_array_indices_only) - { - string_named_properties_count++; - } + ecma_op_string_list_lazy_property_names (obj_p, + is_enumerable_only, + prop_names_p, + skipped_non_enumerable_p); + break; } - else + + case ECMA_OBJECT_TYPE_ARRAY: + case ECMA_OBJECT_TYPE_GENERAL: + case ECMA_OBJECT_TYPE_ARGUMENTS: + case ECMA_OBJECT_TYPE_BOUND_FUNCTION: + case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION: + case ECMA_OBJECT_TYPE_BUILT_IN_FUNCTION: { - JERRY_ASSERT (is_enumerable_only && !ecma_is_property_enumerable (prop_iter_p)); - - skipped_non_enumerable_properties_count++; + break; } } - else - { - JERRY_ASSERT (prop_iter_p->type == ECMA_PROPERTY_INTERNAL); - } } - /* Second pass: collecting properties names into arrays */ - MEM_DEFINE_LOCAL_ARRAY (names_p, - array_index_named_properties_count + string_named_properties_count, - ecma_string_t *); - MEM_DEFINE_LOCAL_ARRAY (array_index_names_p, array_index_named_properties_count, uint32_t); + ecma_collection_iterator_t iter; + ecma_collection_iterator_init (&iter, prop_names_p); - uint32_t name_pos = array_index_named_properties_count + string_named_properties_count; - uint32_t array_index_name_pos = 0; + uint32_t own_names_hashes_bitmap[(1u << LIT_STRING_HASH_BITS) / bitmap_row_size]; + memset (own_names_hashes_bitmap, 0, sizeof (own_names_hashes_bitmap)); + + while (ecma_collection_iterator_next (&iter)) + { + ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + + lit_string_hash_t hash = name_p->hash; + uint32_t bitmap_row = hash / bitmap_row_size; + uint32_t bitmap_column = hash % bitmap_row_size; + + if ((own_names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) == 0) + { + own_names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column); + } + } for (ecma_property_t *prop_iter_p = ecma_get_property_list (prototype_chain_iter_p); prop_iter_p != NULL; @@ -636,50 +646,35 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (!(is_enumerable_only && !ecma_is_property_enumerable (prop_iter_p))) { - uint32_t index; + lit_string_hash_t hash = name_p->hash; + uint32_t bitmap_row = hash / bitmap_row_size; + uint32_t bitmap_column = hash % bitmap_row_size; - if (ecma_string_get_array_index (name_p, &index)) + bool is_add = true; + + if ((own_names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) != 0) { - JERRY_ASSERT (array_index_name_pos < array_index_named_properties_count); + ecma_collection_iterator_init (&iter, prop_names_p); - uint32_t insertion_pos = 0; - while (insertion_pos < array_index_name_pos - && index < array_index_names_p[insertion_pos]) + while (ecma_collection_iterator_next (&iter)) { - insertion_pos++; - } + ecma_string_t *name2_p = ecma_get_string_from_value (*iter.current_value_p); - if (insertion_pos == array_index_name_pos) - { - array_index_names_p[array_index_name_pos++] = index; - } - 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; - - while (move_pos != insertion_pos) + if (ecma_compare_ecma_strings (name_p, name2_p)) { - array_index_names_p[move_pos] = array_index_names_p[move_pos - 1u]; - - move_pos--; + is_add = false; + break; } - - array_index_names_p[insertion_pos] = index; } } - else if (!is_array_indices_only) - { - /* - * Filling from end to begin, as list of object's properties is sorted - * in order that is reverse to properties creation order - */ - JERRY_ASSERT (name_pos > 0 - && name_pos <= array_index_named_properties_count + string_named_properties_count); - names_p[--name_pos] = ecma_copy_or_ref_ecma_string (name_p); + if (is_add) + { + own_names_hashes_bitmap[bitmap_row] |= (1u << bitmap_column); + + ecma_append_to_values_collection (prop_names_p, + ecma_make_string_value (name_p), + true); } } else @@ -706,6 +701,85 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ } } + ecma_collection_iterator_init (&iter, prop_names_p); + while (ecma_collection_iterator_next (&iter)) + { + ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + + uint32_t index; + + if (ecma_string_get_array_index (name_p, &index)) + { + /* name_p is a valid array index */ + array_index_named_properties_count++; + } + else if (!is_array_indices_only) + { + string_named_properties_count++; + } + } + + /* Second pass: collecting properties names into arrays */ + MEM_DEFINE_LOCAL_ARRAY (names_p, + array_index_named_properties_count + string_named_properties_count, + ecma_string_t *); + MEM_DEFINE_LOCAL_ARRAY (array_index_names_p, array_index_named_properties_count, uint32_t); + + uint32_t name_pos = array_index_named_properties_count + string_named_properties_count; + uint32_t array_index_name_pos = 0; + + ecma_collection_iterator_init (&iter, prop_names_p); + while (ecma_collection_iterator_next (&iter)) + { + ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + + uint32_t index; + + if (ecma_string_get_array_index (name_p, &index)) + { + JERRY_ASSERT (array_index_name_pos < array_index_named_properties_count); + + uint32_t insertion_pos = 0; + while (insertion_pos < array_index_name_pos + && index < array_index_names_p[insertion_pos]) + { + insertion_pos++; + } + + if (insertion_pos == array_index_name_pos) + { + array_index_names_p[array_index_name_pos++] = index; + } + 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; + + while (move_pos != insertion_pos) + { + array_index_names_p[move_pos] = array_index_names_p[move_pos - 1u]; + + move_pos--; + } + + array_index_names_p[insertion_pos] = index; + } + } + else if (!is_array_indices_only) + { + /* + * Filling from end to begin, as list of object's properties is sorted + * in order that is reverse to properties creation order + */ + + JERRY_ASSERT (name_pos > 0 + && name_pos <= array_index_named_properties_count + string_named_properties_count); + names_p[--name_pos] = ecma_copy_or_ref_ecma_string (name_p); + } + } + for (uint32_t i = 0; i < array_index_named_properties_count; i++) { JERRY_ASSERT (name_pos > 0 @@ -717,6 +791,10 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ MEM_FINALIZE_LOCAL_ARRAY (array_index_names_p); + ecma_free_values_collection (prop_names_p, true); + + /* Third pass: + * embedding own property names of current object of prototype chain to aggregate property names collection */ for (uint32_t i = 0; i < array_index_named_properties_count + string_named_properties_count; i++) diff --git a/jerry-core/ecma/operations/ecma-string-object.cpp b/jerry-core/ecma/operations/ecma-string-object.cpp index ae9d8906f..970111ecf 100644 --- a/jerry-core/ecma/operations/ecma-string-object.cpp +++ b/jerry-core/ecma/operations/ecma-string-object.cpp @@ -120,7 +120,7 @@ ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of * Returned value must be freed with ecma_free_completion_value */ ecma_property_t* -ecma_op_string_object_get_own_property (ecma_object_t *obj_p, /**< the string object */ +ecma_op_string_object_get_own_property (ecma_object_t *obj_p, /**< a String object */ ecma_string_t *property_name_p) /**< property name */ { JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_STRING); @@ -202,6 +202,55 @@ ecma_op_string_object_get_own_property (ecma_object_t *obj_p, /**< the string ob return new_prop_p; } /* ecma_op_string_object_get_own_property */ +/** + * List names of a String object's lazy instantiated properties + * + * See also: + * ecma_op_string_object_get_own_property + * + * @return string values collection + */ +void +ecma_op_string_list_lazy_property_names (ecma_object_t *obj_p, /**< a String object */ + bool separate_enumerable, /**< true - list enumerable properties + * into main collection, + * and non-enumerable to collection of + * 'skipped non-enumerable' properties, + * false - list all properties into main + * collection. + */ + ecma_collection_header_t *main_collection_p, /**< 'main' + * collection */ + ecma_collection_header_t *non_enum_collection_p) /**< skipped + * 'non-enumerable' + * collection + */ +{ + JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_STRING); + + ecma_collection_header_t *for_enumerable_p = main_collection_p; + + ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? main_collection_p : non_enum_collection_p; + (void) for_non_enumerable_p; + + ecma_property_t* prim_value_prop_p = ecma_get_internal_property (obj_p, + ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE); + ecma_string_t *prim_value_str_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, + prim_value_prop_p->u.internal_property.value); + + ecma_length_t length = ecma_string_get_length (prim_value_str_p); + + for (ecma_length_t i = 0; i < length; i++) + { + ecma_string_t *name_p = ecma_new_ecma_string_from_uint32 (i); + + /* the properties are enumerable (ECMA-262 v5, 15.5.5.2.9) */ + ecma_append_to_values_collection (for_enumerable_p, ecma_make_string_value (name_p), true); + + ecma_deref_ecma_string (name_p); + } +} /* ecma_op_string_list_lazy_property_names */ + /** * @} * @} diff --git a/jerry-core/ecma/operations/ecma-string-object.h b/jerry-core/ecma/operations/ecma-string-object.h index e0674a208..3c2cc389a 100644 --- a/jerry-core/ecma/operations/ecma-string-object.h +++ b/jerry-core/ecma/operations/ecma-string-object.h @@ -31,6 +31,13 @@ ecma_op_create_string_object (const ecma_value_t *, ecma_length_t); extern ecma_property_t * ecma_op_string_object_get_own_property (ecma_object_t *, ecma_string_t *); +extern void +ecma_op_string_list_lazy_property_names (ecma_object_t *, + bool, + ecma_collection_header_t *, + ecma_collection_header_t *); + + /** * @} * @}