diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 7b58433b5..bfb78287e 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -2981,9 +2981,7 @@ bool jerry_object_is_valid_foreach (ecma_object_t *object_p) /**< object to test switch (ext_object_p->u.class_prop.class_id) { /* An object's internal property object should not be iterable by foreach. */ - case LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT: - /* Containers are internal data, do not iterate on them. */ - case LIT_INTERNAL_MAGIC_STRING_CONTAINER: return false; + case LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT: return false; } } diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 7cdda2e0c..354424fbd 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -295,73 +295,106 @@ ecma_gc_mark_promise_object (ecma_extended_object_t *ext_object_p) /**< extended #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ -#if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) - +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) /** - * Mark objects referenced by Map/Set built-in. + * Mark objects referenced by Map built-in. */ static void -ecma_gc_mark_container_object (ecma_object_t *object_p) /**< object */ +ecma_gc_mark_map_object (ecma_object_t *object_p) /**< object */ { + JERRY_ASSERT (object_p != NULL); + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; - ecma_object_t *internal_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - map_object_p->u.class_prop.u.value); - ecma_extended_object_t *internal_ext_p = (ecma_extended_object_t *) internal_obj_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); - ecma_gc_set_object_visited (internal_obj_p); - - jmem_cpointer_t prop_iter_cp = internal_obj_p->u1.property_list_cp; - -#if ENABLED (JERRY_PROPRETY_HASHMAP) - if (prop_iter_cp != JMEM_CP_NULL) + for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_PAIR_SIZE) { - ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, - prop_iter_cp); - if (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) + ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); + + if (ecma_is_value_empty (entry_p->key)) { - prop_iter_cp = prop_iter_p->next_property_cp; - } - } -#endif /* ENABLED (JERRY_PROPRETY_HASHMAP) */ - - while (prop_iter_cp != JMEM_CP_NULL) - { - ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); - JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); - - ecma_gc_mark_properties ((ecma_property_pair_t *) prop_iter_p); - - if ((internal_ext_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) == 0) - { - ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - - for (uint32_t i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) - { - ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); - - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) - { - jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; - ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); - - if (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_CONTAINER_MAP_KEY) - { - ecma_value_t key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; - - if (ecma_is_value_object (key_arg)) - { - ecma_gc_set_object_visited (ecma_get_object_from_value (key_arg)); - } - } - } - } + continue; } - prop_iter_cp = prop_iter_p->next_property_cp; - } -} /* ecma_gc_mark_container_object */ + if (ecma_is_value_object (entry_p->key)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->key)); + } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ + if (ecma_is_value_object (entry_p->value)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->value)); + } + } +} /* ecma_gc_mark_map_object */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) +/** + * Mark objects referenced by WeakMap built-in. + */ +static void +ecma_gc_mark_weakmap_object (ecma_object_t *object_p) /**< object */ +{ + JERRY_ASSERT (object_p != NULL); + + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + + for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_PAIR_SIZE) + { + ecma_container_pair_t *entry_p = (ecma_container_pair_t *) (start_p + i); + + if (ecma_is_value_empty (entry_p->key)) + { + continue; + } + + if (ecma_is_value_object (entry_p->value)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (entry_p->value)); + } + } +} /* ecma_gc_mark_weakmap_object */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_SET) +/** + * Mark objects referenced by Set built-in. + */ +static void +ecma_gc_mark_set_object (ecma_object_t *object_p) /**< object */ +{ + JERRY_ASSERT (object_p != NULL); + + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + + for (uint32_t i = 0; i < entry_count; i+= ECMA_CONTAINER_VALUE_SIZE) + { + ecma_value_t *entry_p = start_p + i; + + if (ecma_is_value_empty (*entry_p)) + { + continue; + } + + if (ecma_is_value_object (*entry_p)) + { + ecma_gc_set_object_visited (ecma_get_object_from_value (*entry_p)); + } + } +} /* ecma_gc_mark_set_object */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ #if ENABLED (JERRY_ES2015) @@ -534,22 +567,33 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ #if ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) - case LIT_MAGIC_STRING_MAP_UL: -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case LIT_MAGIC_STRING_WEAKSET_UL: + { + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ #if ENABLED (JERRY_ES2015_BUILTIN_SET) case LIT_MAGIC_STRING_SET_UL: + { + ecma_gc_mark_set_object (object_p); + break; + } #endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) case LIT_MAGIC_STRING_WEAKMAP_UL: -#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ -#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) - case LIT_MAGIC_STRING_WEAKSET_UL: -#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ { - ecma_gc_mark_container_object (object_p); + ecma_gc_mark_weakmap_object (object_p); break; } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) + case LIT_MAGIC_STRING_MAP_UL: + { + ecma_gc_mark_map_object (object_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ #if ENABLED (JERRY_ES2015) case LIT_MAGIC_STRING_GENERATOR_UL: @@ -1125,50 +1169,12 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ case LIT_MAGIC_STRING_WEAKSET_UL: #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ { - break; - } - case LIT_INTERNAL_MAGIC_STRING_CONTAINER: - { -#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) - ecma_extended_object_t *container_p = (ecma_extended_object_t *) object_p; + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + ecma_op_container_free_entries (object_p); + ecma_collection_destroy (container_p); - if (container_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) - { - jmem_cpointer_t prop_iter_cp = container_p->object.u1.property_list_cp; - while (prop_iter_cp != JMEM_CP_NULL) - { - ecma_property_header_t *prop_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_property_header_t, prop_iter_cp); - JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); - - /* Both cannot be deleted. */ - JERRY_ASSERT (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED - || prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED); - - ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - - for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) - { - ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i); - - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) - { - jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; - ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); - - if (JERRY_LIKELY (ECMA_STRING_GET_CONTAINER (prop_name_p) == ECMA_STRING_CONTAINER_MAP_KEY)) - { - ecma_value_t key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; - ecma_object_t *key_object_p = ecma_get_object_from_value (key_arg); - - ecma_op_container_unref_weak (key_object_p, ecma_make_object_value (object_p)); - } - } - } - - prop_iter_cp = prop_iter_p->next_property_cp; - } - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ break; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 8317f2258..cabb67672 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -989,6 +989,50 @@ typedef enum ECMA_CONTAINER_FLAGS_EMPTY = (0), /** empty flags */ ECMA_CONTAINER_FLAGS_WEAK = (1 << 0) /** container object is weak */ } ecma_container_flags_t; + +/** + * Description of map collection. + */ +typedef struct +{ + ecma_value_t key; /**< key value */ + ecma_value_t value; /**< value of the key */ +} ecma_container_pair_t; + +/** + * Size of a single element (in ecma_value_t unit). + */ +#define ECMA_CONTAINER_VALUE_SIZE 1 + +/** + * Size of a key - value pair (in ecma_value_t unit). + */ +#define ECMA_CONTAINER_PAIR_SIZE 2 + +/** + * Size of the internal buffer. + */ +#define ECMA_CONTAINER_GET_SIZE(container_p) \ + (container_p->buffer_p[0]) + +/** + * Remove the size field of the internal buffer. + */ +#define ECMA_CONTAINER_SET_SIZE(container_p, size) \ + (container_p->buffer_p[0] = (ecma_value_t) (size)) + +/** + * Number of entries of the internal buffer. + */ +#define ECMA_CONTAINER_ENTRY_COUNT(collection_p) \ + (collection_p->item_count - 1) + +/** + * Pointer to the first entry of the internal buffer. + */ +#define ECMA_CONTAINER_START(collection_p) \ + (collection_p->buffer_p + 1) + #endif /* ENABLED (JERRY_ES2015_BUILTIN_CONTAINER) */ typedef enum @@ -1429,9 +1473,7 @@ typedef enum ECMA_STRING_CONTAINER_SYMBOL, /**< the ecma-string is a symbol */ - ECMA_STRING_CONTAINER_MAP_KEY, /**< the ecma-string is a map key string */ - - ECMA_STRING_CONTAINER__MAX = ECMA_STRING_CONTAINER_MAP_KEY /**< maximum value */ + ECMA_STRING_CONTAINER__MAX = ECMA_STRING_CONTAINER_SYMBOL /**< maximum value */ } ecma_string_container_t; /** diff --git a/jerry-core/ecma/base/ecma-helpers-string.c b/jerry-core/ecma/base/ecma-helpers-string.c index edc769689..3cd53da91 100644 --- a/jerry-core/ecma/base/ecma-helpers-string.c +++ b/jerry-core/ecma/base/ecma-helpers-string.c @@ -240,41 +240,6 @@ ecma_prop_name_is_symbol (ecma_string_t *string_p) /**< ecma-string */ } /* ecma_prop_name_is_symbol */ #endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) -/** - * Allocate new ecma-string and fill it with reference to the map key descriptor - * - * @return pointer to ecma-string descriptor - */ -ecma_string_t * -ecma_new_map_key_string (ecma_value_t value) /**< non prop-name ecma-value */ -{ - JERRY_ASSERT (!ecma_is_value_prop_name (value)); - - ecma_extended_string_t *string_p = ecma_alloc_extended_string (); - string_p->header.refs_and_container = ECMA_STRING_REF_ONE | ECMA_STRING_CONTAINER_MAP_KEY; - string_p->u.value = ecma_copy_value_if_not_object (value); - string_p->header.u.hash = (lit_string_hash_t) (ecma_is_value_simple (value) ? value : 0); - - return (ecma_string_t *) string_p; -} /* ecma_new_map_key_string */ - -/** - * Check whether an ecma-string contains a map key string - * - * @return true - if the ecma-string contains a map key string - * false - otherwise - */ -bool -ecma_prop_name_is_map_key (ecma_string_t *string_p) /**< ecma-string */ -{ - JERRY_ASSERT (string_p != NULL); - - return (!ECMA_IS_DIRECT_STRING (string_p) - && ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAP_KEY); -} /* ecma_prop_name_is_map_key */ -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ - /** * Allocate new UTF8 ecma-string and fill it with characters from the given utf8 buffer * @@ -889,15 +854,6 @@ ecma_destroy_ecma_string (ecma_string_t *string_p) /**< ecma-string */ return; } #endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) - case ECMA_STRING_CONTAINER_MAP_KEY: - { - ecma_extended_string_t *key_p = (ecma_extended_string_t *) string_p; - ecma_free_value_if_not_object (key_p->u.value); - ecma_dealloc_extended_string (key_p); - return; - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */ default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC @@ -1786,14 +1742,6 @@ ecma_compare_ecma_strings (const ecma_string_t *string1_p, /**< ecma-string */ } #endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) - if (string1_container == ECMA_STRING_CONTAINER_MAP_KEY) - { - return ecma_op_same_value_zero (((ecma_extended_string_t *) string1_p)->u.value, - ((ecma_extended_string_t *) string2_p)->u.value); - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ - return ecma_compare_ecma_strings_longpath (string1_p, string2_p); } /* ecma_compare_ecma_strings */ @@ -1840,14 +1788,6 @@ ecma_compare_ecma_non_direct_strings (const ecma_string_t *string1_p, /**< ecma- } #endif /* ENABLED (JERRY_ES2015) */ -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) - if (string1_container == ECMA_STRING_CONTAINER_MAP_KEY) - { - return ecma_op_same_value_zero (((ecma_extended_string_t *) string1_p)->u.value, - ((ecma_extended_string_t *) string2_p)->u.value); - } -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ - return ecma_compare_ecma_strings_longpath (string1_p, string2_p); } /* ecma_compare_ecma_non_direct_strings */ diff --git a/jerry-core/ecma/operations/ecma-container-object.c b/jerry-core/ecma/operations/ecma-container-object.c index 339ec3f2c..ac5332e21 100644 --- a/jerry-core/ecma/operations/ecma-container-object.c +++ b/jerry-core/ecma/operations/ecma-container-object.c @@ -35,6 +35,325 @@ * @{ */ +/** + * Create a new internal buffer. + * + * Note: + * The first element of the collection tracks the size of the buffer. + * ECMA_VALUE_EMPTY values are not calculated into the size. + * + * @return pointer to the internal buffer + */ +static inline ecma_collection_t * +ecma_op_create_internal_buffer (void) +{ + ecma_collection_t *collection_p = ecma_new_collection (); + ecma_collection_push_back (collection_p, (ecma_value_t) 0); + + return collection_p; +} /* ecma_op_create_internal_buffer */ + +/** + * Append values to the internal buffer. + */ +static void +ecma_op_internal_buffer_append (ecma_collection_t *container_p, /**< internal container pointer */ + ecma_value_t key_arg, /**< key argument */ + ecma_value_t value_arg, /**< value argument */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (container_p != NULL); + + ecma_collection_push_back (container_p, ecma_copy_value_if_not_object (key_arg)); + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + ecma_collection_push_back (container_p, ecma_copy_value_if_not_object (value_arg)); + } + + ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) + 1); +} /* ecma_op_internal_buffer_append */ + +/** + * Update the value of a given entry. + */ +static inline void +ecma_op_internal_buffer_update (ecma_value_t *entry_p, /**< entry pointer */ + ecma_value_t value_arg, /**< value argument */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (entry_p != NULL); + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + ecma_free_value_if_not_object (((ecma_container_pair_t *) entry_p)->value); + + ((ecma_container_pair_t *) entry_p)->value = ecma_copy_value_if_not_object (value_arg); + } +} /* ecma_op_internal_buffer_update */ + +/** + * Delete element from the internal buffer. + */ +static void +ecma_op_internal_buffer_delete (ecma_collection_t *container_p, /**< internal container pointer */ + ecma_container_pair_t *entry_p, /**< entry pointer */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (container_p != NULL); + JERRY_ASSERT (entry_p != NULL); + + ecma_free_value_if_not_object (entry_p->key); + entry_p->key = ECMA_VALUE_EMPTY; + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + ecma_free_value_if_not_object (entry_p->value); + entry_p->value = ECMA_VALUE_EMPTY; + } + + ECMA_CONTAINER_SET_SIZE (container_p, ECMA_CONTAINER_GET_SIZE (container_p) - 1); +} /* ecma_op_internal_buffer_delete */ + +/** + * Find an entry in the collection. + * + * @return pointer to the appropriate entry. + */ +static ecma_value_t * +ecma_op_internal_buffer_find (ecma_collection_t *container_p, /**< internal container pointer */ + ecma_value_t key_arg, /**< key argument */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (container_p != NULL); + + uint8_t entry_size = ecma_op_container_entry_size (lit_id); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += entry_size) + { + ecma_value_t *entry_p = start_p + i; + + if (ecma_op_same_value_zero (*entry_p, key_arg)) + { + return entry_p; + } + } + + return NULL; +} /* ecma_op_internal_buffer_find */ + +/** + * Get the value that belongs to the key. + * + * Note: in case of Set containers, the values are the same as the keys. + * + * @return ecma value + */ +static ecma_value_t +ecma_op_container_get_value (ecma_value_t *entry_p, /**< entry (key) pointer */ + lit_magic_string_id_t lit_id) /**< class id */ +{ + JERRY_ASSERT (entry_p != NULL); + + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + return ((ecma_container_pair_t *) entry_p)->value; + } + + return *entry_p; +} /* ecma_op_container_get_value */ + +/** + * Get the size (in ecma_value_t) of the stored entries. + * + * @return size of the entries. + */ +uint8_t +ecma_op_container_entry_size (lit_magic_string_id_t lit_id) /**< class id */ +{ + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_MAP_UL) + { + return ECMA_CONTAINER_PAIR_SIZE; + } + + return ECMA_CONTAINER_VALUE_SIZE; +} /* ecma_op_container_entry_size */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) +/** + * Release the entries in the WeakSet container. + */ +static void +ecma_op_container_free_weakset_entries (ecma_object_t *object_p, /**< object pointer */ + ecma_collection_t *container_p) /** internal buffer pointer */ +{ + JERRY_ASSERT (object_p != NULL); + JERRY_ASSERT (container_p != NULL); + + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE) + { + ecma_value_t *entry_p = start_p + i; + + if (ecma_is_value_empty (*entry_p)) + { + continue; + } + + ecma_op_container_unref_weak (ecma_get_object_from_value (*entry_p), ecma_make_object_value (object_p)); + ecma_op_container_remove_weak_entry (object_p, *entry_p); + + *entry_p = ECMA_VALUE_EMPTY; + } +} /* ecma_op_container_free_weakset_entries */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) +/** + * Release the entries in the WeakMap container. + */ +static void +ecma_op_container_free_weakmap_entries (ecma_object_t *object_p, /**< object pointer */ + ecma_collection_t *container_p) /**< internal buffer pointer */ +{ + JERRY_ASSERT (object_p != NULL); + JERRY_ASSERT (container_p != NULL); + + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE) + { + ecma_container_pair_t *entry_p = (ecma_container_pair_t *)(start_p + i); + + if (ecma_is_value_empty (entry_p->key)) + { + continue; + } + + ecma_op_container_unref_weak (ecma_get_object_from_value (entry_p->key), ecma_make_object_value (object_p)); + ecma_op_container_remove_weak_entry (object_p, entry_p->key); + + ecma_free_value_if_not_object (entry_p->value); + + entry_p->key = ECMA_VALUE_EMPTY; + entry_p->value = ECMA_VALUE_EMPTY; + } +} /* ecma_op_container_free_weakmap_entries */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_SET) +/** + * Release the entries in the Set container. + */ +static void +ecma_op_container_free_set_entries (ecma_collection_t *container_p) +{ + JERRY_ASSERT (container_p != NULL); + + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_VALUE_SIZE) + { + ecma_value_t *entry_p = start_p + i; + + if (ecma_is_value_empty (*entry_p)) + { + continue; + } + + ecma_free_value_if_not_object (*entry_p); + *entry_p = ECMA_VALUE_EMPTY; + } +} /* ecma_op_container_free_set_entries */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) +/** + * Release the entries in the Map container. + */ +static void +ecma_op_container_free_map_entries (ecma_collection_t *container_p) +{ + JERRY_ASSERT (container_p != NULL); + + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); + + for (uint32_t i = 0; i < entry_count; i += ECMA_CONTAINER_PAIR_SIZE) + { + ecma_container_pair_t *entry_p = (ecma_container_pair_t *)(start_p + i); + + if (ecma_is_value_empty (entry_p->key)) + { + continue; + } + + ecma_free_value_if_not_object (entry_p->key); + ecma_free_value_if_not_object (entry_p->value); + + entry_p->key = ECMA_VALUE_EMPTY; + entry_p->value = ECMA_VALUE_EMPTY; + } +} /* ecma_op_container_free_map_entries */ +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ + +/** + * Release the internal buffer and the stored entries. + */ +void +ecma_op_container_free_entries (ecma_object_t *object_p) /**< collection object pointer */ +{ + JERRY_ASSERT (object_p != NULL); + + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + + switch (map_object_p->u.class_prop.class_id) + { +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) + case LIT_MAGIC_STRING_WEAKSET_UL: + { + ecma_op_container_free_weakset_entries (object_p, container_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) + case LIT_MAGIC_STRING_WEAKMAP_UL: + { + ecma_op_container_free_weakmap_entries (object_p, container_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + case LIT_MAGIC_STRING_SET_UL: + { + ecma_op_container_free_set_entries (container_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) + case LIT_MAGIC_STRING_MAP_UL: + { + ecma_op_container_free_map_entries (container_p); + break; + } +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ + default: + { + break; + } + } + + ECMA_CONTAINER_SET_SIZE (container_p, 0); +} /* ecma_op_container_free_entries */ + /** * Handle calling [[Construct]] of built-in Map/Set like objects * @@ -52,29 +371,22 @@ ecma_op_container_create (const ecma_value_t *arguments_list_p, /**< arguments l || lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL); - ecma_object_t *internal_object_p = ecma_create_object (NULL, - sizeof (ecma_extended_object_t), - ECMA_OBJECT_TYPE_CLASS); - - ecma_extended_object_t *container_p = (ecma_extended_object_t *) internal_object_p; - container_p->u.class_prop.class_id = LIT_INTERNAL_MAGIC_STRING_CONTAINER; - container_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY; - container_p->u.class_prop.u.length = 0; - - if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) - { - container_p->u.class_prop.extra_info |= ECMA_CONTAINER_FLAGS_WEAK; - } + ecma_collection_t *container_p = ecma_op_create_internal_buffer (); ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (proto_id), sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS); ecma_extended_object_t *map_obj_p = (ecma_extended_object_t *) object_p; + map_obj_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY; map_obj_p->u.class_prop.class_id = (uint16_t) lit_id; - ECMA_SET_INTERNAL_VALUE_POINTER (map_obj_p->u.class_prop.u.value, container_p); - ecma_deref_object (internal_object_p); + if (lit_id == LIT_MAGIC_STRING_WEAKMAP_UL || lit_id == LIT_MAGIC_STRING_WEAKSET_UL) + { + map_obj_p->u.class_prop.extra_info |= ECMA_CONTAINER_FLAGS_WEAK; + } + + ECMA_SET_INTERNAL_VALUE_POINTER (map_obj_p->u.class_prop.u.value, container_p); ecma_value_t set_value = ecma_make_object_value (object_p); ecma_value_t result = set_value; @@ -261,37 +573,6 @@ ecma_op_container_get_object (ecma_value_t this_arg, /**< this argument */ return NULL; } /* ecma_op_container_get_object */ -/** - * Creates a property key for the internal object from the given argument - * - * Note: - * This operation does not increase the reference counter of strings and symbols - * - * @return property key - */ -static ecma_string_t * -ecma_op_container_to_key (ecma_value_t key_arg) /**< key argument */ -{ - if (ecma_is_value_prop_name (key_arg)) - { - ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key_arg); - ecma_ref_ecma_string (prop_name_p); - return prop_name_p; - } - - if (ecma_is_value_integer_number (key_arg)) - { - ecma_integer_value_t integer = ecma_get_integer_from_value (key_arg); - - if (JERRY_LIKELY (integer > 0 && integer <= ECMA_DIRECT_STRING_MAX_IMM)) - { - return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_ECMA_INTEGER, (uintptr_t) integer); - } - } - - return ecma_new_map_key_string (key_arg); -} /* ecma_op_container_to_key */ - /** * Returns with the size of the Map/Set object. * @@ -308,9 +589,10 @@ ecma_op_container_size (ecma_value_t this_arg, /**< this argument */ return ECMA_VALUE_ERROR; } - ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, - map_object_p->u.class_prop.u.value); - return ecma_make_uint32_value (container_p->u.class_prop.u.length); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + + return ecma_make_uint32_value (ECMA_CONTAINER_GET_SIZE (container_p)); } /* ecma_op_container_size */ /** @@ -338,26 +620,22 @@ ecma_op_container_get (ecma_value_t this_arg, /**< this argument */ } #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) */ - ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, - map_object_p->u.class_prop.u.value); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); - if (container_p->u.class_prop.u.length == 0) + if (ECMA_CONTAINER_GET_SIZE (container_p) == 0) { return ECMA_VALUE_UNDEFINED; } - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); - ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); - - ecma_deref_ecma_string (prop_name_p); - - if (property_p == NULL || ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) + if (entry_p == NULL) { return ECMA_VALUE_UNDEFINED; } - return ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); + return ecma_copy_value (((ecma_container_pair_t *) entry_p)->value); } /* ecma_op_container_get */ /** @@ -378,30 +656,25 @@ ecma_op_container_has (ecma_value_t this_arg, /**< this argument */ return ECMA_VALUE_ERROR; } - ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, - map_object_p->u.class_prop.u.value); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) - if ((container_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0 + if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0 && !ecma_is_value_object (key_arg)) { return ECMA_VALUE_FALSE; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ - if (container_p->u.class_prop.u.length == 0) + if (ECMA_CONTAINER_GET_SIZE (container_p) == 0) { return ECMA_VALUE_FALSE; } - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); - ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); - - ecma_deref_ecma_string (prop_name_p); - - return ecma_make_boolean_value (property_p != NULL - && !ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)); + return ecma_make_boolean_value (entry_p != NULL); } /* ecma_op_container_has */ /** @@ -467,52 +740,36 @@ ecma_op_container_set (ecma_value_t this_arg, /**< this argument */ return ECMA_VALUE_ERROR; } - ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, - map_object_p->u.class_prop.u.value); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) - if ((container_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0 + if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0 && !ecma_is_value_object (key_arg)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Key must be an object")); } #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); - ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); - - if (property_p == NULL) + if (entry_p == NULL) { - ecma_property_value_t *value_p = ecma_create_named_data_property ((ecma_object_t *) container_p, - prop_name_p, - ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, - NULL); - value_p->value = ecma_copy_value_if_not_object (value_arg); - container_p->u.class_prop.u.length++; + ecma_op_internal_buffer_append (container_p, key_arg, value_arg, lit_id); #if ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) - if ((container_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0) + if ((map_object_p->u.class_prop.extra_info & ECMA_CONTAINER_FLAGS_WEAK) != 0) { ecma_object_t *key_p = ecma_get_object_from_value (key_arg); - ecma_op_container_set_weak (key_p, container_p); + ecma_op_container_set_weak (key_p, map_object_p); } #endif /* ENABLED (JERRY_ES2015_BUILTIN_WEAKMAP) || ENABLED (JERRY_ES2015_BUILTIN_WEAKSET) */ - } else { - if (ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) - { - container_p->u.class_prop.u.length++; - } - - ecma_named_data_property_assign_value ((ecma_object_t *) container_p, - ECMA_PROPERTY_VALUE_PTR (property_p), - value_arg); + ecma_op_internal_buffer_update (entry_p, value_arg, lit_id); } - ecma_deref_ecma_string (prop_name_p); ecma_ref_object ((ecma_object_t *) map_object_p); return this_arg; } /* ecma_op_container_set */ @@ -544,59 +801,28 @@ ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ JERRY_ASSERT (ecma_is_value_object (predicate)); ecma_object_t *func_object_p = ecma_get_object_from_value (predicate); - - ecma_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - map_object_p->u.class_prop.u.value); - - ecma_collection_t *props_p = ecma_op_object_get_property_names (container_p, ECMA_LIST_NO_OPTS); - - ecma_value_t *buffer_p = props_p->buffer_p; - ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; - ecma_ref_object (container_p); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); - for (uint32_t i = 0; i < props_p->item_count; i++) + uint8_t entry_size = ecma_op_container_entry_size (lit_id); + + for (uint32_t i = 0; i < ECMA_CONTAINER_ENTRY_COUNT (container_p); i += entry_size) { - ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (buffer_p[i]); - ecma_property_t *property_p = ecma_find_named_property (container_p, prop_name_p); - JERRY_ASSERT (property_p != NULL); + ecma_value_t *entry_p = ECMA_CONTAINER_START (container_p) + i; - if (ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) + if (ecma_is_value_empty (*entry_p)) { continue; } - ecma_value_t value = ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); - ecma_value_t key_arg; - - if (lit_id == LIT_MAGIC_STRING_SET_UL) - { - key_arg = value; - } - else if (ecma_prop_name_is_map_key (prop_name_p)) - { - key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; - } - else - { - if (ECMA_IS_DIRECT_STRING (prop_name_p) - && ECMA_GET_DIRECT_STRING_TYPE (prop_name_p) == ECMA_DIRECT_STRING_ECMA_INTEGER) - { - key_arg = ecma_make_uint32_value ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (prop_name_p)); - } - else - { - key_arg = buffer_p[i]; - } - } - - ecma_value_t call_args[] = { value, key_arg, this_arg }; + ecma_value_t key_arg = *entry_p; + ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id); + ecma_value_t call_args[] = { value_arg, key_arg, this_arg }; ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 3); - ecma_free_value (value); - if (ECMA_IS_VALUE_ERROR (call_value)) { ret_value = call_value; @@ -606,9 +832,6 @@ ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ ecma_free_value (call_value); } - ecma_deref_object (container_p); - ecma_collection_free (props_p); - return ret_value; } /* ecma_op_container_foreach */ @@ -629,18 +852,7 @@ ecma_op_container_clear (ecma_value_t this_arg, /**< this argument */ return ECMA_VALUE_ERROR; } - ecma_object_t *internal_object_p = ecma_create_object (NULL, - sizeof (ecma_extended_object_t), - ECMA_OBJECT_TYPE_CLASS); - - ecma_extended_object_t *container_p = (ecma_extended_object_t *) internal_object_p; - container_p->u.class_prop.class_id = LIT_INTERNAL_MAGIC_STRING_CONTAINER; - container_p->u.class_prop.extra_info = ECMA_CONTAINER_FLAGS_EMPTY; - container_p->u.class_prop.u.length = 0; - - ECMA_SET_INTERNAL_VALUE_POINTER (map_object_p->u.class_prop.u.value, internal_object_p); - - ecma_deref_object (internal_object_p); + ecma_op_container_free_entries ((ecma_object_t *) map_object_p); return ECMA_VALUE_UNDEFINED; } /* ecma_op_container_clear */ @@ -663,25 +875,17 @@ ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */ return ECMA_VALUE_ERROR; } - ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, - map_object_p->u.class_prop.u.value); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); - ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); - - ecma_deref_ecma_string (prop_name_p); - - if (property_p == NULL || ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) + if (entry_p == NULL) { return ECMA_VALUE_FALSE; } - ecma_named_data_property_assign_value ((ecma_object_t *) container_p, - ECMA_PROPERTY_VALUE_PTR (property_p), - ECMA_VALUE_EMPTY); - container_p->u.class_prop.u.length--; - + ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id); return ECMA_VALUE_TRUE; } /* ecma_op_container_delete */ @@ -708,28 +912,21 @@ ecma_op_container_delete_weak (ecma_value_t this_arg, /**< this argument */ return ECMA_VALUE_FALSE; } - ecma_extended_object_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_extended_object_t, - map_object_p->u.class_prop.u.value); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, lit_id); - ecma_property_t *property_p = ecma_find_named_property ((ecma_object_t *) container_p, prop_name_p); - - ecma_deref_ecma_string (prop_name_p); - - if (property_p == NULL) + if (entry_p == NULL) { return ECMA_VALUE_FALSE; } - ecma_delete_property ((ecma_object_t *) container_p, ECMA_PROPERTY_VALUE_PTR (property_p)); + ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, lit_id); - ecma_object_t *internal_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - map_object_p->u.class_prop.u.value); ecma_object_t *key_object_p = ecma_get_object_from_value (key_arg); - ecma_op_container_unref_weak (key_object_p, ecma_make_object_value (internal_obj_p)); + ecma_op_container_unref_weak (key_object_p, ecma_make_object_value ((ecma_object_t *) map_object_p)); - container_p->u.class_prop.u.length--; return ECMA_VALUE_TRUE; } /* ecma_op_container_delete_weak */ @@ -764,18 +961,19 @@ ecma_op_container_unref_weak (ecma_object_t *object_p, /**< this argument */ * Helper function to remove a key/value pair from a weak container object */ void -ecma_op_container_remove_weak_entry (ecma_object_t *container_p, /**< internal container object */ +ecma_op_container_remove_weak_entry (ecma_object_t *object_p, /**< internal container object */ ecma_value_t key_arg) /**< key */ { - ecma_string_t *prop_name_p = ecma_new_map_key_string (key_arg); + ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) object_p; - ecma_property_t *property_p = ecma_find_named_property (container_p, prop_name_p); - JERRY_ASSERT (property_p != NULL); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); - ecma_deref_ecma_string (prop_name_p); + ecma_value_t *entry_p = ecma_op_internal_buffer_find (container_p, key_arg, map_object_p->u.class_prop.class_id); - ecma_delete_property (container_p, ECMA_PROPERTY_VALUE_PTR (property_p)); - ((ecma_extended_object_t *) container_p)->u.class_prop.u.length--; + JERRY_ASSERT (entry_p != NULL); + + ecma_op_internal_buffer_delete (container_p, (ecma_container_pair_t *) entry_p, map_object_p->u.class_prop.class_id); } /* ecma_op_container_remove_weak_entry */ #if ENABLED (JERRY_ES2015) @@ -814,6 +1012,60 @@ ecma_op_container_create_iterator (ecma_value_t this_arg, /**< this argument */ type); } /* ecma_op_container_create_iterator */ +/** + * Get the index of the iterator object. + * + * @return index of the iterator. + */ +static uint32_t +ecma_op_iterator_get_index (ecma_object_t *iter_obj_p) /**< iterator object pointer */ +{ + uint32_t index = ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index; + + if (JERRY_UNLIKELY (index == ECMA_ITERATOR_INDEX_LIMIT)) + { + ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX); + ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p); + ecma_property_value_t *value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + + return (uint32_t) (ecma_get_number_from_value (value_p->value)); + } + + return index; +} /* ecma_op_iterator_get_index */ + +/** + * Set the index of the iterator object. + */ +static void +ecma_op_iterator_set_index (ecma_object_t *iter_obj_p, /**< iterator object pointer */ + uint32_t index) /* iterator index to set */ +{ + if (JERRY_UNLIKELY (index >= ECMA_ITERATOR_INDEX_LIMIT)) + { + /* After the ECMA_ITERATOR_INDEX_LIMIT limit is reached the [[%Iterator%NextIndex]] + property is stored as an internal property */ + ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX); + ecma_property_t *property_p = ecma_find_named_property (iter_obj_p, prop_name_p); + ecma_property_value_t *value_p; + + if (property_p == NULL) + { + value_p = ecma_create_named_data_property (iter_obj_p, prop_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p); + value_p->value = ecma_make_uint32_value (index); + } + else + { + value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + value_p->value = ecma_make_uint32_value (index); + } + } + else + { + ((ecma_extended_object_t *) iter_obj_p)->u.pseudo_array.u1.iterator_index = (uint16_t) index; + } +} /* ecma_op_iterator_set_index */ + /** * The %{Set, Map}IteratorPrototype% object's 'next' routine * @@ -853,97 +1105,44 @@ ecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */ } ecma_extended_object_t *map_object_p = (ecma_extended_object_t *) (ecma_get_object_from_value (iterated_value)); + lit_magic_string_id_t lit_id = map_object_p->u.class_prop.class_id; - ecma_object_t *internal_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, - map_object_p->u.class_prop.u.value); - ecma_collection_t *props_p = ecma_op_object_get_property_names (internal_obj_p, ECMA_LIST_NO_OPTS); + ecma_collection_t *container_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, + map_object_p->u.class_prop.u.value); + uint32_t entry_count = ECMA_CONTAINER_ENTRY_COUNT (container_p); + uint32_t index = ecma_op_iterator_get_index (obj_p); - uint32_t length = props_p->item_count; - uint32_t index = ext_obj_p->u.pseudo_array.u1.iterator_index; - - if (JERRY_UNLIKELY (index == ECMA_ITERATOR_INDEX_LIMIT)) - { - /* After the ECMA_ITERATOR_INDEX_LIMIT limit is reached the [[%Iterator%NextIndex]] - property is stored as an internal property */ - ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ITERATOR_NEXT_INDEX); - - ecma_property_t *property_p = ecma_find_named_property (obj_p, prop_name_p); - ecma_property_value_t *value_p; - - if (property_p == NULL) - { - value_p = ecma_create_named_data_property (obj_p, prop_name_p, ECMA_PROPERTY_FLAG_WRITABLE, &property_p); - value_p->value = ecma_make_uint32_value (index); - } - else - { - value_p = ECMA_PROPERTY_VALUE_PTR (property_p); - index = (uint32_t) (ecma_get_number_from_value (value_p->value) + 1); - value_p->value = ecma_make_uint32_value (index); - } - } - else - { - ext_obj_p->u.pseudo_array.u1.iterator_index++; - } - - if (index >= length) + if (index == entry_count) { ext_obj_p->u.pseudo_array.u2.iterated_value = ECMA_VALUE_EMPTY; - ecma_collection_free (props_p); + return ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); } + uint8_t entry_size = ecma_op_container_entry_size (lit_id); uint8_t iterator_kind = ext_obj_p->u.pseudo_array.extra_info; - - ecma_value_t *buffer_p = props_p->buffer_p; - + ecma_value_t *start_p = ECMA_CONTAINER_START (container_p); ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; - for (uint32_t i = 0; i < props_p->item_count; i++) + for (uint32_t i = index; i < entry_count; i += entry_size) { - if (index > 0) - { - index--; - continue; - } + ecma_value_t *entry_p = start_p + i; - ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (buffer_p[i]); - ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); - JERRY_ASSERT (property_p != NULL); - - if (ecma_is_value_empty (ECMA_PROPERTY_VALUE_PTR (property_p)->value)) + if (ecma_is_value_empty (*entry_p)) { - if (i == props_p->item_count - 1) + if (i == (entry_count - entry_size)) { ret_value = ecma_create_iter_result_object (ECMA_VALUE_UNDEFINED, ECMA_VALUE_TRUE); + break; } + continue; } - ecma_value_t value = ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); - ecma_value_t key_arg; + ecma_op_iterator_set_index (obj_p, i + entry_size); - if (iterator_type == ECMA_PSEUDO_SET_ITERATOR) - { - key_arg = value; - } - else if (ecma_prop_name_is_map_key (prop_name_p)) - { - key_arg = ((ecma_extended_string_t *) prop_name_p)->u.value; - } - else - { - if (ECMA_IS_DIRECT_STRING (prop_name_p) - && ECMA_GET_DIRECT_STRING_TYPE (prop_name_p) == ECMA_DIRECT_STRING_ECMA_INTEGER) - { - key_arg = ecma_make_uint32_value ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (prop_name_p)); - } - else - { - key_arg = buffer_p[i]; - } - } + ecma_value_t key_arg = *entry_p; + ecma_value_t value_arg = ecma_op_container_get_value (entry_p, lit_id); if (iterator_kind == ECMA_ITERATOR_KEYS) { @@ -951,25 +1150,22 @@ ecma_op_container_iterator_next (ecma_value_t this_val, /**< this argument */ } else if (iterator_kind == ECMA_ITERATOR_VALUES) { - ret_value = ecma_create_iter_result_object (value, ECMA_VALUE_FALSE); + ret_value = ecma_create_iter_result_object (value_arg, ECMA_VALUE_FALSE); } else { JERRY_ASSERT (iterator_kind == ECMA_ITERATOR_KEYS_VALUES); ecma_value_t entry_array_value; - entry_array_value = ecma_create_array_from_iter_element (value, key_arg); + entry_array_value = ecma_create_array_from_iter_element (value_arg, key_arg); ret_value = ecma_create_iter_result_object (entry_array_value, ECMA_VALUE_FALSE); ecma_free_value (entry_array_value); } - ecma_free_value (value); break; } - ecma_collection_free (props_p); - return ret_value; } /* ecma_op_container_iterator_next */ diff --git a/jerry-core/ecma/operations/ecma-container-object.h b/jerry-core/ecma/operations/ecma-container-object.h index 9c82f5042..ec30bb120 100644 --- a/jerry-core/ecma/operations/ecma-container-object.h +++ b/jerry-core/ecma/operations/ecma-container-object.h @@ -28,6 +28,7 @@ * @{ */ +uint8_t ecma_op_container_entry_size (lit_magic_string_id_t lit_id); ecma_value_t ecma_op_container_create (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len, lit_magic_string_id_t lit_id, ecma_builtin_id_t proto_id); ecma_value_t ecma_op_container_size (ecma_value_t this_arg, lit_magic_string_id_t lit_id); @@ -42,6 +43,7 @@ ecma_value_t ecma_op_container_delete (ecma_value_t this_arg, ecma_value_t key_a ecma_value_t ecma_op_container_delete_weak (ecma_value_t this_arg, ecma_value_t key_arg, lit_magic_string_id_t lit_id); void ecma_op_container_unref_weak (ecma_object_t *object_p, ecma_value_t ref_holder); void ecma_op_container_remove_weak_entry (ecma_object_t *container_p, ecma_value_t key_arg); +void ecma_op_container_free_entries (ecma_object_t *object_p); ecma_value_t ecma_op_container_create_iterator (ecma_value_t this_arg, uint8_t type, lit_magic_string_id_t lit_id, ecma_builtin_id_t proto_id, ecma_pseudo_array_type_t iterator_type); ecma_value_t ecma_op_container_iterator_next (ecma_value_t this_val, ecma_pseudo_array_type_t iterator_type); diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index 745171831..6ca3f91ed 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -72,7 +72,6 @@ typedef enum LIT_FIRST_INTERNAL_MAGIC_STRING = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of internal * magic strings */ LIT_INTERNAL_MAGIC_STRING_WEAK_REFS, /**< Weak references to the current object */ - LIT_INTERNAL_MAGIC_STRING_CONTAINER, /**< Literal ID for internal container objects */ LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT, /**< Internal object ID for internal properties */ LIT_MAGIC_STRING__COUNT /**< number of magic strings */ } lit_magic_string_id_t; diff --git a/tests/jerry/es2015/map-iterators.js b/tests/jerry/es2015/map-iterators.js index fc327f098..d65e34e9e 100644 --- a/tests/jerry/es2015/map-iterators.js +++ b/tests/jerry/es2015/map-iterators.js @@ -32,13 +32,15 @@ methods.forEach(function (method) { } }); -var m = new Map([{0: '0', 1: 0}, +var testArray = [{0: '0', 1: 0}, {0: '1', 1: 1}, {0: '2', 1: 2}, {0: '3', 1: 3}, {0: '4', 1: 4}, {0: '5', 1: 5}, - {0: '6', 1: 6}]); + {0: '6', 1: 6}]; + +var m = new Map(testArray); methods.forEach(function(method) { assert(m[method]().toString() === '[object Map Iterator]'); @@ -122,3 +124,61 @@ for (var i = 0; i < elementCount; i++) { } assert(m.size === 0); + +m = new Map(testArray); +var loopCount = 0; +var expected = [{0: '0', 1: 0}, + {0: '2', 1: 2}, + {0: '4', 1: 4}, + {0: '6', 1: 6}, + {0: '1', 1: 1}, + {0: '3', 1: 3}, + {0: '5', 1: 5}] + +m.forEach(function(value, key) { + if (loopCount === 0) { + for (i = 0; i < testArray.length; i++) { + if (i % 2) { + m.delete(testArray[i][0]); + m.set(testArray[i][0], testArray[i][1]); + } + } + } + + assert (key === expected[loopCount][0]); + assert (value === expected[loopCount][1]); + + loopCount++; +}); + +assert(loopCount === expected.length); + +loopCount = 0; +expected = [{0: '0', 1: 0}, + {0: '1', 1: 1}]; + +for (var [key, value] of m) { + if (loopCount === 0) { + m.clear(); + m.set('1', 1); + } + + assert(key === expected[loopCount][0]); + assert(value === expected[loopCount][1]); + + loopCount++; +} + +m = new Map(testArray); +loopCount = 0; + +for (var [key, value] of m) { + if (loopCount === 0) { + m.delete('' + testArray.length - 1); + } + + assert(key === '' + loopCount); + assert(value === loopCount); + + loopCount++; +} diff --git a/tests/jerry/es2015/set-iterators.js b/tests/jerry/es2015/set-iterators.js index 136688173..31423a359 100644 --- a/tests/jerry/es2015/set-iterators.js +++ b/tests/jerry/es2015/set-iterators.js @@ -106,3 +106,49 @@ for (var i = 0; i < elementCount; i++) { } assert(s.size === 0); + +s = new Set ([0, 1]); +var expected = [0, 1, 2, 4, 5, 6, 3]; +var loopCount = 0; + +s.forEach(function(element) { + if (loopCount === 0) { + for (var i = 0; i < expected.length ; i++) { + s.add(i); + } + s.delete(3); + s.add(3); + } + assert(element === expected[loopCount++]); +}); + +assert(loopCount === expected.length); + +s = new Set([0, 1, 2, 3, 4, 5, 6]); +expected = [0, 1]; +loopCount = 0; + +for (var value of s) { + if (loopCount === 0) { + s.clear(); + s.add(1); + } + + assert(value === expected[loopCount++]); +} + +s = new Set([0]) +expected = [0, 1]; +loopCount = 0; + +for (var value of s) { + if (loopCount === 0) { + s.add(2); + s.delete(2); + s.add(3); + s.delete(3); + s.add(1); + } + + assert(value === expected[loopCount++]); +} diff --git a/tests/jerry/es2015/weakmap.js b/tests/jerry/es2015/weakmap.js index 2eb702c95..d842872ef 100644 --- a/tests/jerry/es2015/weakmap.js +++ b/tests/jerry/es2015/weakmap.js @@ -115,7 +115,7 @@ m1.set(k1, "str"); m1.set(k1, "4"); m1.set(k1, null); m1.set(k1, 42); -print (m1.has (k1)); +assert (m1.has (k1)); k1 = {}; gc();