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