Reorganize ecma_gc_free_object (#3323)

This change cleans up object deallocation, and reorganizes the code so
that we are able to do object type specific operations before the
properties are freed.

Previously this would require extra conditions that would slow things
down regardless of object type. With this change however, object type
conditions are checked only once for each possible type.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
This commit is contained in:
Dániel Bátyai
2019-11-15 18:19:52 +01:00
committed by Robert Fancsik
parent 8d24c70513
commit 359643b5b2
+129 -120
View File
@@ -640,33 +640,15 @@ ecma_free_fast_access_array (ecma_object_t *object_p) /**< fast access mode arra
jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t)); jmem_heap_free_block (values_p, aligned_length * sizeof (ecma_value_t));
} }
JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0);
JERRY_CONTEXT (ecma_gc_objects_number)--;
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
} /* ecma_free_fast_access_array */ } /* ecma_free_fast_access_array */
/** /**
* Free specified object. * Free properties of an object
*/ */
static void static void
ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ ecma_gc_free_properties (ecma_object_t *object_p) /**< object */
{ {
JERRY_ASSERT (object_p != NULL
&& !ecma_gc_is_object_visited (object_p)
&& ((object_p->type_flags_refs & ECMA_OBJECT_REF_MASK) == ECMA_OBJECT_NON_VISITED));
bool obj_is_not_lex_env = !ecma_is_lexical_environment (object_p);
if (obj_is_not_lex_env
|| ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
if (obj_is_not_lex_env && ecma_op_object_is_fast_array (object_p))
{
ecma_free_fast_access_array (object_p);
return;
}
jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp; jmem_cpointer_t prop_iter_cp = object_p->u1.property_list_cp;
#if ENABLED (JERRY_PROPRETY_HASHMAP) #if ENABLED (JERRY_PROPRETY_HASHMAP)
@@ -715,18 +697,37 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
ecma_dealloc_property_pair (prop_pair_p); ecma_dealloc_property_pair (prop_pair_p);
} }
} } /* ecma_gc_free_properties */
/**
* Free specified object.
*/
static void
ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
{
JERRY_ASSERT (object_p != NULL
&& !ecma_gc_is_object_visited (object_p)
&& ((object_p->type_flags_refs & ECMA_OBJECT_REF_MASK) == ECMA_OBJECT_NON_VISITED));
JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0); JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_number) > 0);
JERRY_CONTEXT (ecma_gc_objects_number)--; JERRY_CONTEXT (ecma_gc_objects_number)--;
if (obj_is_not_lex_env) if (ecma_is_lexical_environment (object_p))
{ {
if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_gc_free_properties (object_p);
}
ecma_dealloc_object (object_p);
return;
}
ecma_object_type_t object_type = ecma_get_object_type (object_p); ecma_object_type_t object_type = ecma_get_object_type (object_p);
size_t ext_object_size = sizeof (ecma_extended_object_t); size_t ext_object_size = sizeof (ecma_extended_object_t);
if (ecma_get_object_is_builtin (object_p)) if (JERRY_UNLIKELY (ecma_get_object_is_builtin (object_p)))
{ {
uint8_t length_and_bitset_size; uint8_t length_and_bitset_size;
@@ -735,16 +736,41 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
{ {
ext_object_size = sizeof (ecma_extended_built_in_object_t); ext_object_size = sizeof (ecma_extended_built_in_object_t);
length_and_bitset_size = ((ecma_extended_built_in_object_t *) object_p)->built_in.length_and_bitset_size; length_and_bitset_size = ((ecma_extended_built_in_object_t *) object_p)->built_in.length_and_bitset_size;
ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT);
} }
else else
{ {
length_and_bitset_size = ((ecma_extended_object_t *) object_p)->u.built_in.length_and_bitset_size; length_and_bitset_size = ((ecma_extended_object_t *) object_p)->u.built_in.length_and_bitset_size;
}
ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT); ext_object_size += (2 * sizeof (uint32_t)) * (length_and_bitset_size >> ECMA_BUILT_IN_BITSET_SHIFT);
ecma_gc_free_properties (object_p);
ecma_dealloc_extended_object (object_p, ext_object_size);
return;
}
} }
if (object_type == ECMA_OBJECT_TYPE_CLASS) switch (object_type)
{
case ECMA_OBJECT_TYPE_GENERAL:
{
ecma_gc_free_properties (object_p);
ecma_dealloc_object (object_p);
return;
}
case ECMA_OBJECT_TYPE_ARRAY:
{
if (ecma_op_array_is_fast_array ((ecma_extended_object_t *) object_p))
{
ecma_free_fast_access_array (object_p);
return;
}
break;
}
case ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION:
{
break;
}
case ECMA_OBJECT_TYPE_CLASS:
{ {
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
@@ -784,11 +810,10 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
case LIT_MAGIC_STRING_ARRAY_BUFFER_UL: case LIT_MAGIC_STRING_ARRAY_BUFFER_UL:
{ {
ecma_length_t arraybuffer_length = ext_object_p->u.class_prop.u.length; ecma_length_t arraybuffer_length = ext_object_p->u.class_prop.u.length;
size_t size;
if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p))
{ {
size = sizeof (ecma_arraybuffer_external_info); ext_object_size = sizeof (ecma_arraybuffer_external_info);
/* Call external free callback if any. */ /* Call external free callback if any. */
ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p;
@@ -801,11 +826,10 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
} }
else else
{ {
size = sizeof (ecma_extended_object_t) + arraybuffer_length; ext_object_size += arraybuffer_length;
} }
ecma_dealloc_extended_object (object_p, size); break;
return;
} }
#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
#if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE)
@@ -814,29 +838,27 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value); ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value);
ecma_collection_free_if_not_object (((ecma_promise_object_t *) object_p)->fulfill_reactions); ecma_collection_free_if_not_object (((ecma_promise_object_t *) object_p)->fulfill_reactions);
ecma_collection_free_if_not_object (((ecma_promise_object_t *) object_p)->reject_reactions); ecma_collection_free_if_not_object (((ecma_promise_object_t *) object_p)->reject_reactions);
ecma_dealloc_extended_object (object_p, sizeof (ecma_promise_object_t)); ext_object_size = sizeof (ecma_promise_object_t);
return; break;
} }
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */
#if ENABLED (JERRY_ES2015_BUILTIN_SET) #if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET)
case LIT_MAGIC_STRING_SET_UL:
{
ecma_dealloc_extended_object (object_p, sizeof (ecma_map_object_t));
return;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
#if ENABLED (JERRY_ES2015_BUILTIN_MAP) #if ENABLED (JERRY_ES2015_BUILTIN_MAP)
case LIT_MAGIC_STRING_MAP_UL: case LIT_MAGIC_STRING_MAP_UL:
{
ecma_dealloc_extended_object (object_p, sizeof (ecma_map_object_t));
return;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */
#if ENABLED (JERRY_ES2015_BUILTIN_SET)
case LIT_MAGIC_STRING_SET_UL:
#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */
{
ext_object_size = sizeof (ecma_map_object_t);
break;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) || ENABLED (JERRY_ES2015_BUILTIN_SET) */
#if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) #if ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW)
case LIT_MAGIC_STRING_DATAVIEW_UL: case LIT_MAGIC_STRING_DATAVIEW_UL:
{ {
ecma_dealloc_extended_object (object_p, sizeof (ecma_dataview_object_t)); ext_object_size = sizeof (ecma_dataview_object_t);
return; break;
} }
#endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_DATAVIEW) */
default: default:
@@ -850,19 +872,9 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
} }
} }
ecma_dealloc_extended_object (object_p, ext_object_size); break;
return;
} }
case ECMA_OBJECT_TYPE_FUNCTION:
if (ecma_get_object_is_builtin (object_p)
|| object_type == ECMA_OBJECT_TYPE_ARRAY
|| object_type == ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION)
{
ecma_dealloc_extended_object (object_p, ext_object_size);
return;
}
if (object_type == ECMA_OBJECT_TYPE_FUNCTION)
{ {
/* Function with byte-code (not a built-in function). */ /* Function with byte-code (not a built-in function). */
ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p;
@@ -872,22 +884,19 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
{ {
ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
ext_func_p->u.function.bytecode_cp)); ext_func_p->u.function.bytecode_cp));
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
} }
else else
{ {
ecma_dealloc_extended_object (object_p, sizeof (ecma_static_function_t)); ext_object_size = sizeof (ecma_static_function_t);
} }
#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */ #else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */
ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
ext_func_p->u.function.bytecode_cp)); ext_func_p->u.function.bytecode_cp));
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
return; break;
} }
#if ENABLED (JERRY_ES2015) #if ENABLED (JERRY_ES2015)
if (object_type == ECMA_OBJECT_TYPE_ARROW_FUNCTION) case ECMA_OBJECT_TYPE_ARROW_FUNCTION:
{ {
ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p;
@@ -898,69 +907,27 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
{ {
ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t,
arrow_func_p->bytecode_cp)); arrow_func_p->bytecode_cp));
ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); ext_object_size = sizeof (ecma_arrow_function_t);
} }
else else
{ {
ecma_dealloc_extended_object (object_p, sizeof (ecma_static_arrow_function_t)); ext_object_size = sizeof (ecma_static_arrow_function_t);
} }
#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */ #else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */
ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t,
arrow_func_p->bytecode_cp)); arrow_func_p->bytecode_cp));
ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); ext_object_size = sizeof (ecma_arrow_function_t);
#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */ #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
return; break;
} }
#endif /* ENABLED (JERRY_ES2015) */ #endif /* ENABLED (JERRY_ES2015) */
case ECMA_OBJECT_TYPE_PSEUDO_ARRAY:
if (object_type == ECMA_OBJECT_TYPE_PSEUDO_ARRAY)
{ {
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
switch (ext_object_p->u.pseudo_array.type) switch (ext_object_p->u.pseudo_array.type)
{ {
#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) case ECMA_PSEUDO_ARRAY_ARGUMENTS:
case ECMA_PSEUDO_ARRAY_TYPEDARRAY:
{
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
return;
}
case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
{
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_typedarray_object_t));
return;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR)
case ECMA_PSEUDO_ARRAY_ITERATOR:
case ECMA_PSEUDO_SET_ITERATOR:
case ECMA_PSEUDO_MAP_ITERATOR:
{
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
return;
}
case ECMA_PSEUDO_STRING_ITERATOR:
{
ecma_value_t iterated_value = ext_object_p->u.pseudo_array.u2.iterated_value;
if (!ecma_is_value_empty (iterated_value))
{
ecma_deref_ecma_string (ecma_get_string_from_value (iterated_value));
}
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
return;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */
#if ENABLED (JERRY_ES2015)
case ECMA_PSEUDO_SPREAD_OBJECT:
{
ecma_value_t spread_value = ext_object_p->u.pseudo_array.u2.spread_value;
ecma_free_value_if_not_object (spread_value);
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t));
return;
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{ {
JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS); JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ARGUMENTS);
@@ -977,13 +944,51 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
} }
size_t formal_params_size = formal_params_number * sizeof (ecma_value_t); size_t formal_params_size = formal_params_number * sizeof (ecma_value_t);
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t) + formal_params_size); ext_object_size += formal_params_size;
return; break;
} }
#if ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY)
case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
{
ext_object_size = sizeof (ecma_extended_typedarray_object_t);
break;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) */
#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR)
case ECMA_PSEUDO_STRING_ITERATOR:
{
ecma_value_t iterated_value = ext_object_p->u.pseudo_array.u2.iterated_value;
if (!ecma_is_value_empty (iterated_value))
{
ecma_deref_ecma_string (ecma_get_string_from_value (iterated_value));
}
break;
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */
#if ENABLED (JERRY_ES2015)
case ECMA_PSEUDO_SPREAD_OBJECT:
{
ecma_value_t spread_value = ext_object_p->u.pseudo_array.u2.spread_value;
ecma_free_value_if_not_object (spread_value);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
JERRY_ASSERT (ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_TYPEDARRAY
|| ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_ARRAY_ITERATOR
|| ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_SET_ITERATOR
|| ext_object_p->u.pseudo_array.type == ECMA_PSEUDO_MAP_ITERATOR);
break;
} }
} }
if (object_type == ECMA_OBJECT_TYPE_BOUND_FUNCTION) break;
}
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
{ {
ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p; ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) object_p;
@@ -992,8 +997,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
if (!ecma_is_value_integer_number (args_len_or_this)) if (!ecma_is_value_integer_number (args_len_or_this))
{ {
ecma_free_value_if_not_object (args_len_or_this); ecma_free_value_if_not_object (args_len_or_this);
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); break;
return;
} }
ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this); ecma_integer_value_t args_length = ecma_get_integer_from_value (args_len_or_this);
@@ -1005,12 +1009,17 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
} }
size_t args_size = ((size_t) args_length) * sizeof (ecma_value_t); size_t args_size = ((size_t) args_length) * sizeof (ecma_value_t);
ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t) + args_size); ext_object_size += args_size;
return; break;
}
default:
{
JERRY_UNREACHABLE ();
} }
} }
ecma_dealloc_object (object_p); ecma_gc_free_properties (object_p);
ecma_dealloc_extended_object (object_p, ext_object_size);
} /* ecma_gc_free_object */ } /* ecma_gc_free_object */
/** /**