Use array based storage in container objects (#3600)

Currently, collections use object based solutions for storing elements and
iterating on them. If an element is deleted and re-inserted, the storage
position is the same as before so the iteration order is wrong.
This patch replaces the object based storage with an array based solution
that helps to store and iterate elements as expected.

JerryScript-DCO-1.0-Signed-off-by: Roland Takacs rtakacs@inf.u-szeged.hu
This commit is contained in:
Roland Takacs
2020-03-17 19:30:55 +01:00
committed by GitHub
parent 1cfda262bd
commit 51a9575fd0
10 changed files with 726 additions and 437 deletions
+1 -3
View File
@@ -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;
}
}
+113 -107
View File
@@ -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) */
+45 -3
View File
@@ -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;
/**
@@ -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 */
+456 -260
View File
@@ -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 */
@@ -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);
-1
View File
@@ -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;
+62 -2
View File
@@ -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++;
}
+46
View File
@@ -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++]);
}
+1 -1
View File
@@ -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();