Free the GC mark bit to increase the number of object types. (#2032)

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2017-09-29 16:15:13 +02:00
committed by GitHub
parent 6d53931055
commit 29ea702fa4
4 changed files with 115 additions and 126 deletions
+100 -81
View File
@@ -47,20 +47,12 @@
* @{
*/
/**
* Current state of an object's visited flag that
* indicates whether the object is in visited state:
*
* visited_field | visited_flip_flag | real_value
* false | false | false
* false | true | true
* true | false | true
* true | true | false
/*
* The garbage collector uses the reference counter
* of object: it increases the counter by one when
* the object is marked at the first time.
*/
static void ecma_gc_mark (ecma_object_t *object_p);
static void ecma_gc_sweep (ecma_object_t *object_p);
/**
* Get next object in list of objects with same generation.
*/
@@ -92,27 +84,19 @@ ecma_gc_is_object_visited (ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p != NULL);
bool flag_value = (object_p->type_flags_refs & ECMA_OBJECT_FLAG_GC_VISITED) != 0;
return flag_value != JERRY_CONTEXT (ecma_gc_visited_flip_flag);
return (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE);
} /* ecma_gc_is_object_visited */
/**
* Set visited flag of the object.
*/
static inline void
ecma_gc_set_object_visited (ecma_object_t *object_p, /**< object */
bool is_visited) /**< flag value */
ecma_gc_set_object_visited (ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p != NULL);
if (is_visited != JERRY_CONTEXT (ecma_gc_visited_flip_flag))
/* Set reference counter to one if it is zero. */
if (object_p->type_flags_refs < ECMA_OBJECT_REF_ONE)
{
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_FLAG_GC_VISITED);
}
else
{
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs & ~ECMA_OBJECT_FLAG_GC_VISITED);
object_p->type_flags_refs |= ECMA_OBJECT_REF_ONE;
}
} /* ecma_gc_set_object_visited */
@@ -130,11 +114,8 @@ ecma_init_gc_info (ecma_object_t *object_p) /**< object */
JERRY_ASSERT (object_p->type_flags_refs < ECMA_OBJECT_REF_ONE);
object_p->type_flags_refs = (uint16_t) (object_p->type_flags_refs | ECMA_OBJECT_REF_ONE);
ecma_gc_set_object_next (object_p, JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY]);
JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY] = object_p;
/* Should be set to false at the beginning of garbage collection */
ecma_gc_set_object_visited (object_p, false);
ecma_gc_set_object_next (object_p, JERRY_CONTEXT (ecma_gc_objects_p));
JERRY_CONTEXT (ecma_gc_objects_p) = object_p;
} /* ecma_init_gc_info */
/**
@@ -156,7 +137,7 @@ ecma_ref_object (ecma_object_t *object_p) /**< object */
/**
* Decrease reference counter of an object
*/
void
inline void __attr_always_inline___
ecma_deref_object (ecma_object_t *object_p) /**< object */
{
JERRY_ASSERT (object_p->type_flags_refs >= ECMA_OBJECT_REF_ONE);
@@ -188,7 +169,7 @@ ecma_gc_mark_property (ecma_property_pair_t *property_pair_p, /**< property pair
{
ecma_object_t *value_obj_p = ecma_get_object_from_value (value);
ecma_gc_set_object_visited (value_obj_p, true);
ecma_gc_set_object_visited (value_obj_p);
}
break;
}
@@ -200,12 +181,12 @@ ecma_gc_mark_property (ecma_property_pair_t *property_pair_p, /**< property pair
if (getter_obj_p != NULL)
{
ecma_gc_set_object_visited (getter_obj_p, true);
ecma_gc_set_object_visited (getter_obj_p);
}
if (setter_obj_p != NULL)
{
ecma_gc_set_object_visited (setter_obj_p, true);
ecma_gc_set_object_visited (setter_obj_p);
}
break;
}
@@ -226,7 +207,7 @@ ecma_gc_mark_property (ecma_property_pair_t *property_pair_p, /**< property pair
/**
* Mark objects as visited starting from specified object as root
*/
void
static void
ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
{
JERRY_ASSERT (object_p != NULL);
@@ -239,13 +220,13 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
ecma_object_t *lex_env_p = ecma_get_lex_env_outer_reference (object_p);
if (lex_env_p != NULL)
{
ecma_gc_set_object_visited (lex_env_p, true);
ecma_gc_set_object_visited (lex_env_p);
}
if (ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p);
ecma_gc_set_object_visited (binding_object_p, true);
ecma_gc_set_object_visited (binding_object_p);
traverse_properties = false;
}
@@ -255,7 +236,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
ecma_object_t *proto_p = ecma_get_object_prototype (object_p);
if (proto_p != NULL)
{
ecma_gc_set_object_visited (proto_p, true);
ecma_gc_set_object_visited (proto_p);
}
switch (ecma_get_object_type (object_p))
@@ -272,7 +253,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
if (ecma_is_value_object (result))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (result), true);
ecma_gc_set_object_visited (ecma_get_object_from_value (result));
}
/* Mark all reactions. */
@@ -281,14 +262,14 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
while (ecma_collection_iterator_next (&iter))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p), true);
ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p));
}
ecma_collection_iterator_init (&iter, ((ecma_promise_object_t *) ext_object_p)->reject_reactions);
while (ecma_collection_iterator_next (&iter))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p), true);
ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p));
}
}
@@ -306,14 +287,14 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_object_p->u.pseudo_array.u2.lex_env_cp);
ecma_gc_set_object_visited (lex_env_p, true);
ecma_gc_set_object_visited (lex_env_p);
break;
}
#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
case ECMA_PSEUDO_ARRAY_TYPEDARRAY:
case ECMA_PSEUDO_ARRAY_TYPEDARRAY_WITH_INFO:
{
ecma_gc_set_object_visited (ecma_typedarray_get_arraybuffer (object_p), true);
ecma_gc_set_object_visited (ecma_typedarray_get_arraybuffer (object_p));
break;
}
#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */
@@ -334,7 +315,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
target_func_obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_function_p->u.bound_function.target_function);
ecma_gc_set_object_visited (target_func_obj_p, true);
ecma_gc_set_object_visited (target_func_obj_p);
ecma_value_t args_len_or_this = ext_function_p->u.bound_function.args_len_or_this;
@@ -342,7 +323,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
{
if (ecma_is_value_object (args_len_or_this))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this), true);
ecma_gc_set_object_visited (ecma_get_object_from_value (args_len_or_this));
}
break;
}
@@ -356,7 +337,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
{
if (ecma_is_value_object (args_p[i]))
{
ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i]), true);
ecma_gc_set_object_visited (ecma_get_object_from_value (args_p[i]));
}
}
break;
@@ -370,7 +351,7 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
ecma_object_t *scope_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t,
ext_func_p->u.function.scope_cp);
ecma_gc_set_object_visited (scope_p, true);
ecma_gc_set_object_visited (scope_p);
}
break;
}
@@ -441,8 +422,8 @@ ecma_gc_free_native_pointer (ecma_property_t *property_p, /**< property */
/**
* Free specified object.
*/
void
ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */
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)
@@ -695,7 +676,7 @@ ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */
}
ecma_dealloc_object (object_p);
} /* ecma_gc_sweep */
} /* ecma_gc_free_object */
/**
* Run garbage collection
@@ -705,51 +686,85 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */
{
JERRY_CONTEXT (ecma_gc_new_objects) = 0;
JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] == NULL);
ecma_object_t *white_gray_objects_p = JERRY_CONTEXT (ecma_gc_objects_p);
ecma_object_t *black_objects_p = NULL;
/* if some object is referenced from stack or globals (i.e. it is root), mark it */
for (ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY];
obj_iter_p != NULL;
obj_iter_p = ecma_gc_get_object_next (obj_iter_p))
ecma_object_t *obj_iter_p = white_gray_objects_p;
ecma_object_t *obj_prev_p = NULL;
/* Move root objects (i.e. they have global or stack references) to the black list. */
while (obj_iter_p != NULL)
{
JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p));
ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p);
if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE)
JERRY_ASSERT (obj_prev_p == NULL
|| ecma_gc_get_object_next (obj_prev_p) == obj_iter_p);
if (ecma_gc_is_object_visited (obj_iter_p))
{
ecma_gc_set_object_visited (obj_iter_p, true);
/* Moving the object to list of marked objects. */
if (likely (obj_prev_p != NULL))
{
obj_prev_p->gc_next_cp = obj_iter_p->gc_next_cp;
}
else
{
white_gray_objects_p = obj_next_p;
}
ecma_gc_set_object_next (obj_iter_p, black_objects_p);
black_objects_p = obj_iter_p;
}
else
{
obj_prev_p = obj_iter_p;
}
obj_iter_p = obj_next_p;
}
bool marked_anything_during_current_iteration = false;
/* Mark root objects. */
obj_iter_p = black_objects_p;
while (obj_iter_p != NULL)
{
ecma_gc_mark (obj_iter_p);
obj_iter_p = ecma_gc_get_object_next (obj_iter_p);
}
ecma_object_t *first_root_object_p = black_objects_p;
/* Mark non-root objects. */
bool marked_anything_during_current_iteration;
do
{
marked_anything_during_current_iteration = false;
ecma_object_t *obj_prev_p = NULL;
ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY];
obj_prev_p = NULL;
obj_iter_p = white_gray_objects_p;
while (obj_iter_p != NULL)
{
ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p);
JERRY_ASSERT (obj_prev_p == NULL
|| ecma_gc_get_object_next (obj_prev_p) == obj_iter_p);
if (ecma_gc_is_object_visited (obj_iter_p))
{
/* Moving the object to list of marked objects */
ecma_gc_set_object_next (obj_iter_p, JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK]);
JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] = obj_iter_p;
if (likely (obj_prev_p != NULL))
{
JERRY_ASSERT (ecma_gc_get_object_next (obj_prev_p) == obj_iter_p);
ecma_gc_set_object_next (obj_prev_p, obj_next_p);
obj_prev_p->gc_next_cp = obj_iter_p->gc_next_cp;
}
else
{
JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY] = obj_next_p;
white_gray_objects_p = obj_next_p;
}
ecma_gc_set_object_next (obj_iter_p, black_objects_p);
black_objects_p = obj_iter_p;
ecma_gc_mark (obj_iter_p);
marked_anything_during_current_iteration = true;
}
@@ -763,8 +778,8 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */
}
while (marked_anything_during_current_iteration);
/* Sweeping objects that are currently unmarked */
ecma_object_t *obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY];
/* Sweep objects that are currently unmarked. */
obj_iter_p = white_gray_objects_p;
while (obj_iter_p != NULL)
{
@@ -772,19 +787,28 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */
JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p));
ecma_gc_sweep (obj_iter_p);
ecma_gc_free_object (obj_iter_p);
obj_iter_p = obj_next_p;
}
/* Reset the reference counter of non-root black objects. */
obj_iter_p = black_objects_p;
while (obj_iter_p != first_root_object_p)
{
/* The reference counter must be 1. */
ecma_deref_object (obj_iter_p);
JERRY_ASSERT (obj_iter_p->type_flags_refs < ECMA_OBJECT_REF_ONE);
obj_iter_p = ecma_gc_get_object_next (obj_iter_p);
}
if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH)
{
/* Remove the property hashmap of BLACK objects */
obj_iter_p = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK];
obj_iter_p = black_objects_p;
while (obj_iter_p != NULL)
{
JERRY_ASSERT (ecma_gc_is_object_visited (obj_iter_p));
if (!ecma_is_lexical_environment (obj_iter_p)
|| ecma_get_lex_env_type (obj_iter_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE)
{
@@ -800,12 +824,7 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */
}
}
/* Unmarking all objects */
ecma_object_t *black_objects = JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK];
JERRY_CONTEXT (ecma_gc_objects_lists)[ECMA_GC_COLOR_WHITE_GRAY] = black_objects;
JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_BLACK] = NULL;
JERRY_CONTEXT (ecma_gc_visited_flip_flag) = !JERRY_CONTEXT (ecma_gc_visited_flip_flag);
JERRY_CONTEXT (ecma_gc_objects_p) = black_objects_p;
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
/* Free RegExp bytecodes stored in cache */
+12 -34
View File
@@ -583,6 +583,8 @@ typedef enum
ECMA_OBJECT_TYPE_BOUND_FUNCTION = 5, /**< Function objects (15.3), created through 15.3.4.5 routine */
ECMA_OBJECT_TYPE_PSEUDO_ARRAY = 6, /**< Array-like object, such as Arguments object (10.6) */
/* Types between 13-15 cannot have a built-in flag. See ecma_lexical_environment_type_t. */
ECMA_OBJECT_TYPE__MAX = ECMA_OBJECT_TYPE_PSEUDO_ARRAY /**< maximum value */
} ecma_object_type_t;
@@ -603,14 +605,11 @@ typedef enum
*/
typedef enum
{
/* ECMA_OBJECT_TYPE_GENERAL (0) with built-in flag. */
/* ECMA_OBJECT_TYPE_CLASS (1) with built-in flag. */
/* ECMA_OBJECT_TYPE_FUNCTION (2) with built-in flag. */
/* ECMA_OBJECT_TYPE_EXTERNAL_FUNCTION (3) with built-in flag. */
/* ECMA_OBJECT_TYPE_ARRAY (4) with built-in flag. */
ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE = 5, /**< declarative lexical environment */
ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND = 6, /**< object-bound lexical environment */
ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND = 7, /**< object-bound lexical environment
/* Types between 0 - 12 are ecma_object_type_t which can have a built-in flag. */
ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE = 13, /**< declarative lexical environment */
ECMA_LEXICAL_ENVIRONMENT_OBJECT_BOUND = 14, /**< object-bound lexical environment */
ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND = 15, /**< object-bound lexical environment
* with provideThis flag */
ECMA_LEXICAL_ENVIRONMENT_TYPE_START = ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE, /**< first lexical
@@ -621,19 +620,14 @@ typedef enum
/**
* Ecma object type mask for getting the object type.
*/
#define ECMA_OBJECT_TYPE_MASK 0x07u
#define ECMA_OBJECT_TYPE_MASK 0x0fu
/**
* Ecma object is built-in or lexical environment.
* Ecma object is built-in or lexical environment. When this flag is set, the object is a
* - built-in, if object type is less than ECMA_LEXICAL_ENVIRONMENT_TYPES_START
* - lexical environment, if object type is greater or equal than ECMA_LEXICAL_ENVIRONMENT_TYPES_START
*/
#define ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV 0x08
/**
* This object is visited by the garbage collector.
*/
#define ECMA_OBJECT_FLAG_GC_VISITED 0x10
#define ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV 0x10
/**
* Extensible object.
@@ -656,10 +650,9 @@ typedef enum
*/
typedef struct
{
/** type : 3 bit : ecma_object_type_t or ecma_lexical_environment_type_t
/** type : 4 bit : ecma_object_type_t or ecma_lexical_environment_type_t
depending on ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV
flags : 3 bit : ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV,
ECMA_OBJECT_FLAG_GC_VISITED,
flags : 2 bit : ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV,
ECMA_OBJECT_FLAG_EXTENSIBLE
refs : 10 bit (max 1023) */
uint16_t type_flags_refs;
@@ -1143,21 +1136,6 @@ typedef struct
* If regexp, the other flags must be RE_FLAG... */
} ecma_compiled_code_t;
/**
* An object's GC color
*
* Tri-color marking:
* WHITE_GRAY, unvisited -> WHITE: not referenced by a live object or the reference not found yet
* WHITE_GRAY, visited -> GRAY: referenced by some live object
* BLACK -> BLACK: all referenced objects are gray or black
*/
typedef enum
{
ECMA_GC_COLOR_WHITE_GRAY, /**< white or gray */
ECMA_GC_COLOR_BLACK, /**< black */
ECMA_GC_COLOR__COUNT /**< number of colors */
} ecma_gc_color_t;
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
/**
+2 -8
View File
@@ -60,17 +60,11 @@ JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK >= ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX
JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK + 1 == ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV,
ecma_built_in_flag_must_follow_the_object_type);
/**
* The ecma gc visited flag must follow the built in flag.
*/
JERRY_STATIC_ASSERT (ECMA_OBJECT_FLAG_GC_VISITED == (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV << 1),
ecma_gc_visited_flag_must_follow_the_built_in_flag);
/**
* The ecma extensible flag must follow the gc visited flag.
*/
JERRY_STATIC_ASSERT (ECMA_OBJECT_FLAG_EXTENSIBLE == (ECMA_OBJECT_FLAG_GC_VISITED << 1),
ecma_extensible_flag_must_follow_the_gc_visited_flag);
JERRY_STATIC_ASSERT (ECMA_OBJECT_FLAG_EXTENSIBLE == (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV << 1),
ecma_extensible_flag_must_follow_the_built_in_flag);
/**
* The ecma object ref one must follow the extensible flag.
+1 -3
View File
@@ -62,8 +62,7 @@ typedef struct
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
const re_compiled_code_t *re_cache[RE_CACHE_SIZE]; /**< regex cache */
#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
ecma_object_t *ecma_gc_objects_lists[ECMA_GC_COLOR__COUNT]; /**< List of marked (visited during
* current GC session) and umarked objects */
ecma_object_t *ecma_gc_objects_p; /**< List of currently alive objects. */
jmem_heap_free_t *jmem_heap_list_skip_p; /**< This is used to speed up deallocation. */
jmem_pools_chunk_t *jmem_free_8_byte_chunk_p; /**< list of free eight byte pool chunks */
#ifdef JERRY_CPOINTER_32_BIT
@@ -84,7 +83,6 @@ typedef struct
* causes call of "try give memory back" callbacks */
uint32_t lit_magic_string_ex_count; /**< external magic strings count */
uint32_t jerry_init_flags; /**< run-time configuration flags */
uint8_t ecma_gc_visited_flip_flag; /**< current state of an object's visited flag */
uint8_t is_direct_eval_form_call; /**< direct call from eval */
uint8_t jerry_api_available; /**< API availability flag */