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:
+113
-107
@@ -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) */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user