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
+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 */