/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { 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); } 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); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } } if (traverse_properties) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (prop_iter_p->types[0].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 0); } if (prop_iter_p->types[1].type_and_flags != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 1); } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } } } /* ecma_gc_mark */
/** * Initialize GC information for the object */ void ecma_init_gc_info (ecma_object_t *object_p) /**< object */ { ecma_gc_set_object_refs (object_p, 1); ecma_gc_set_object_next (object_p, ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY]); 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_init_gc_info */
/** * Initialize GC information for the object */ void ecma_init_gc_info (ecma_object_t *object_p) /**< object */ { ecma_gc_objects_number++; ecma_gc_new_objects_since_last_gc++; JERRY_ASSERT (ecma_gc_new_objects_since_last_gc <= ecma_gc_objects_number); ecma_gc_set_object_refs (object_p, 1); ecma_gc_set_object_next (object_p, ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY]); 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_init_gc_info */
/** * Initialize GC information for the object */ inline void ecma_init_gc_info (ecma_object_t *object_p) /**< object */ { JERRY_CONTEXT (ecma_gc_objects_number)++; JERRY_CONTEXT (ecma_gc_new_objects)++; JERRY_ASSERT (JERRY_CONTEXT (ecma_gc_new_objects) <= JERRY_CONTEXT (ecma_gc_objects_number)); 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_init_gc_info */
/** * Run garbage collecting */ void ecma_gc_run (void) { ecma_gc_new_objects_since_last_gc = 0; JERRY_ASSERT (ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK] == NULL); /* if some object is referenced from stack or globals (i.e. it is root), mark it */ for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY]; obj_iter_p != NULL; obj_iter_p = ecma_gc_get_object_next (obj_iter_p)) { JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); if (ecma_gc_get_object_refs (obj_iter_p) > 0) { ecma_gc_set_object_visited (obj_iter_p, true); } } /* if some object is referenced from a register variable (i.e. it is root), * start recursive marking traverse from the object */ for (vm_stack_frame_t *frame_iter_p = vm_stack_get_top_frame (); frame_iter_p != NULL; frame_iter_p = frame_iter_p->prev_frame_p) { for (int32_t reg_index = 0; reg_index < frame_iter_p->regs_number; reg_index++) { ecma_value_t reg_value = vm_stack_frame_get_reg_value (frame_iter_p, reg_index); if (ecma_is_value_object (reg_value)) { ecma_object_t *obj_p = ecma_get_object_from_value (reg_value); ecma_gc_set_object_visited (obj_p, true); } } } bool marked_anything_during_current_iteration = false; do { marked_anything_during_current_iteration = false; for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY], *obj_prev_p = NULL, *obj_next_p; obj_iter_p != NULL; obj_iter_p = obj_next_p) { obj_next_p = ecma_gc_get_object_next (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, ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK]); 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); } else { ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY] = obj_next_p; } ecma_gc_mark (obj_iter_p); marked_anything_during_current_iteration = true; } else { obj_prev_p = obj_iter_p; } } } while (marked_anything_during_current_iteration); /* Sweeping objects that are currently unmarked */ for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY], *obj_next_p; obj_iter_p != NULL; obj_iter_p = obj_next_p) { obj_next_p = ecma_gc_get_object_next (obj_iter_p); JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); ecma_gc_sweep (obj_iter_p); } /* Unmarking all objects */ ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY] = ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK]; ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK] = NULL; ecma_gc_visited_flip_flag = !ecma_gc_visited_flip_flag; } /* ecma_gc_run */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { 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); } if (ecma_get_lex_env_type (object_p) == ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND) { ecma_object_t *binding_object_p = ecma_get_lex_env_binding_object (object_p); ecma_gc_set_object_visited (binding_object_p, true); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } } if (traverse_properties) { for (ecma_property_t *property_p = ecma_get_property_list (object_p), *next_property_p; property_p != NULL; property_p = next_property_p) { next_property_p = ECMA_GET_POINTER (ecma_property_t, property_p->next_property_p); switch ((ecma_property_type_t) property_p->type) { case ECMA_PROPERTY_NAMEDDATA: { ecma_value_t value = ecma_get_named_data_property_value (property_p); if (ecma_is_value_object (value)) { ecma_object_t *value_obj_p = ecma_get_object_from_value (value); ecma_gc_set_object_visited (value_obj_p, true); } break; } case ECMA_PROPERTY_NAMEDACCESSOR: { ecma_object_t *getter_obj_p = ecma_get_named_accessor_property_getter (property_p); ecma_object_t *setter_obj_p = ecma_get_named_accessor_property_setter (property_p); if (getter_obj_p != NULL) { ecma_gc_set_object_visited (getter_obj_p, true); } if (setter_obj_p != NULL) { ecma_gc_set_object_visited (setter_obj_p, true); } break; } case ECMA_PROPERTY_INTERNAL: { ecma_internal_property_id_t property_id = (ecma_internal_property_id_t) property_p->u.internal_property.type; uint32_t property_value = property_p->u.internal_property.value; switch (property_id) { case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */ case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* a collection of ecma-values */ { JERRY_UNIMPLEMENTED ("Indexed array storage is not implemented yet."); } case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t (see above in the routine) */ case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t (see above in the routine) */ case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type, * but number of the real internal property types */ { JERRY_UNREACHABLE (); } case ECMA_INTERNAL_PROPERTY_FORMAL_PARAMETERS: /* a collection of strings */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* compressed pointer to a ecma_number_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */ case ECMA_INTERNAL_PROPERTY_CODE_FLAGS_AND_OFFSET: /* an integer */ case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an object's native free callback */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */ case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: { break; } case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */ { ecma_object_t *obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, property_value); ecma_gc_set_object_visited (obj_p, true); break; } } break; } } } } } /* ecma_gc_mark */
/** * Run garbage collection */ void 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); /* 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)) { JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) { ecma_gc_set_object_visited (obj_iter_p, true); } } bool marked_anything_during_current_iteration = false; 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]; while (obj_iter_p != NULL) { ecma_object_t *obj_next_p = ecma_gc_get_object_next (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); } else { JERRY_CONTEXT (ecma_gc_objects_lists) [ECMA_GC_COLOR_WHITE_GRAY] = obj_next_p; } ecma_gc_mark (obj_iter_p); marked_anything_during_current_iteration = true; } else { obj_prev_p = obj_iter_p; } obj_iter_p = obj_next_p; } } 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]; while (obj_iter_p != NULL) { ecma_object_t *obj_next_p = ecma_gc_get_object_next (obj_iter_p); JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); ecma_gc_sweep (obj_iter_p); obj_iter_p = obj_next_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]; 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) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (obj_iter_p); if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP) { ecma_property_hashmap_free (obj_iter_p); } } obj_iter_p = ecma_gc_get_object_next (obj_iter_p); } } /* 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); #ifndef CONFIG_DISABLE_REGEXP_BUILTIN /* Free RegExp bytecodes stored in cache */ re_cache_gc_run (); #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ } /* ecma_gc_run */
/** * Mark objects as visited starting from specified object as root */ void ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { JERRY_ASSERT (object_p != NULL); JERRY_ASSERT (ecma_gc_is_object_visited (object_p)); bool traverse_properties = true; if (ecma_is_lexical_environment (object_p)) { 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); } 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); traverse_properties = false; } } else { ecma_object_t *proto_p = ecma_get_object_prototype (object_p); if (proto_p != NULL) { ecma_gc_set_object_visited (proto_p, true); } if (!ecma_get_object_is_builtin (object_p) && ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_FUNCTION) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; 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); } } if (traverse_properties) { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); if (prop_iter_p != NULL && ECMA_PROPERTY_GET_TYPE (prop_iter_p->types[0]) == ECMA_PROPERTY_TYPE_HASHMAP) { prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } while (prop_iter_p != NULL) { JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); if (prop_iter_p->types[0] != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 0); } if (prop_iter_p->types[1] != ECMA_PROPERTY_TYPE_DELETED) { ecma_gc_mark_property (prop_iter_p->types + 1); } prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); } } } /* ecma_gc_mark */
/** * Mark referenced object from property */ static void ecma_gc_mark_property (ecma_property_t *property_p) /**< property */ { switch (ECMA_PROPERTY_GET_TYPE (*property_p)) { case ECMA_PROPERTY_TYPE_NAMEDDATA: { ecma_value_t value = ECMA_PROPERTY_VALUE_PTR (property_p)->value; if (ecma_is_value_object (value)) { ecma_object_t *value_obj_p = ecma_get_object_from_value (value); ecma_gc_set_object_visited (value_obj_p, true); } break; } case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: { ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); ecma_object_t *getter_obj_p = ecma_get_named_accessor_property_getter (prop_value_p); ecma_object_t *setter_obj_p = ecma_get_named_accessor_property_setter (prop_value_p); if (getter_obj_p != NULL) { ecma_gc_set_object_visited (getter_obj_p, true); } if (setter_obj_p != NULL) { ecma_gc_set_object_visited (setter_obj_p, true); } break; } case ECMA_PROPERTY_TYPE_INTERNAL: { uint32_t property_value = ECMA_PROPERTY_VALUE_PTR (property_p)->value; switch (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (property_p)) { case ECMA_INTERNAL_PROPERTY_ECMA_VALUE: /* an ecma_value_t except object */ case ECMA_INTERNAL_PROPERTY_DATE_FLOAT: /* pointer to a ecma_number_t */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: /* pointer to a regexp bytecode array */ case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an object's native free callback */ case ECMA_INTERNAL_PROPERTY_INSTANTIATED_MASK_32_63: /* an integer (bit-mask) */ { break; } case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: /* an ecma value */ { if (ecma_is_value_object (property_value)) { ecma_object_t *obj_p = ecma_get_object_from_value (property_value); ecma_gc_set_object_visited (obj_p, true); } break; } case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: /* a collection of ecma values */ { ecma_collection_header_t *bound_arg_list_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_header_t, property_value); ecma_collection_iterator_t bound_args_iterator; ecma_collection_iterator_init (&bound_args_iterator, bound_arg_list_p); for (ecma_length_t i = 0; i < bound_arg_list_p->unit_number; i++) { bool is_moved = ecma_collection_iterator_next (&bound_args_iterator); JERRY_ASSERT (is_moved); if (ecma_is_value_object (*bound_args_iterator.current_value_p)) { ecma_object_t *obj_p = ecma_get_object_from_value (*bound_args_iterator.current_value_p); ecma_gc_set_object_visited (obj_p, true); } } break; } case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: /* an object */ case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */ { ecma_object_t *obj_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, property_value); ecma_gc_set_object_visited (obj_p, true); break; } case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type, * but number of the real internal property types */ { JERRY_UNREACHABLE (); break; } } break; } default: { JERRY_UNREACHABLE (); break; } } } /* ecma_gc_mark_property */
/** * Run garbage collecting */ void ecma_gc_run (void) { ecma_gc_new_objects_since_last_gc = 0; JERRY_ASSERT (ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK] == NULL); /* if some object is referenced from stack or globals (i.e. it is root), mark it */ for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY]; obj_iter_p != NULL; obj_iter_p = ecma_gc_get_object_next (obj_iter_p)) { JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); if (ecma_gc_get_object_refs (obj_iter_p) > 0) { ecma_gc_set_object_visited (obj_iter_p, true); } } bool marked_anything_during_current_iteration = false; do { marked_anything_during_current_iteration = false; for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY], *obj_prev_p = NULL, *obj_next_p; obj_iter_p != NULL; obj_iter_p = obj_next_p) { obj_next_p = ecma_gc_get_object_next (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, ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK]); 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); } else { ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY] = obj_next_p; } ecma_gc_mark (obj_iter_p); marked_anything_during_current_iteration = true; } else { obj_prev_p = obj_iter_p; } } } while (marked_anything_during_current_iteration); /* Sweeping objects that are currently unmarked */ for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY], *obj_next_p; obj_iter_p != NULL; obj_iter_p = obj_next_p) { obj_next_p = ecma_gc_get_object_next (obj_iter_p); JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); ecma_gc_sweep (obj_iter_p); } /* Unmarking all objects */ ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY] = ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK]; ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK] = NULL; ecma_gc_visited_flip_flag = !ecma_gc_visited_flip_flag; } /* ecma_gc_run */
/** * Run garbage collecting */ void ecma_gc_run (void) { ecma_gc_new_objects_since_last_gc = 0; JERRY_ASSERT (ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK] == NULL); /* if some object is referenced from stack or globals (i.e. it is root), mark it */ for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY]; obj_iter_p != NULL; obj_iter_p = ecma_gc_get_object_next (obj_iter_p)) { JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); if (obj_iter_p->type_flags_refs >= ECMA_OBJECT_REF_ONE) { ecma_gc_set_object_visited (obj_iter_p, true); } } bool marked_anything_during_current_iteration = false; do { marked_anything_during_current_iteration = false; for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY], *obj_prev_p = NULL, *obj_next_p; obj_iter_p != NULL; obj_iter_p = obj_next_p) { obj_next_p = ecma_gc_get_object_next (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, ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK]); 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); } else { ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY] = obj_next_p; } ecma_gc_mark (obj_iter_p); marked_anything_during_current_iteration = true; } else { obj_prev_p = obj_iter_p; } } } while (marked_anything_during_current_iteration); /* Sweeping objects that are currently unmarked */ for (ecma_object_t *obj_iter_p = ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY], *obj_next_p; obj_iter_p != NULL; obj_iter_p = obj_next_p) { obj_next_p = ecma_gc_get_object_next (obj_iter_p); JERRY_ASSERT (!ecma_gc_is_object_visited (obj_iter_p)); ecma_gc_sweep (obj_iter_p); } /* Unmarking all objects */ ecma_gc_objects_lists[ECMA_GC_COLOR_WHITE_GRAY] = ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK]; ecma_gc_objects_lists[ECMA_GC_COLOR_BLACK] = NULL; ecma_gc_visited_flip_flag = !ecma_gc_visited_flip_flag; #ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN /* Free RegExp bytecodes stored in cache */ re_cache_gc_run (); #endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */ } /* ecma_gc_run */
/** * Mark referenced object from property */ static void ecma_gc_mark_property (ecma_property_t *property_p) /**< property */ { switch (ECMA_PROPERTY_GET_TYPE (property_p)) { case ECMA_PROPERTY_TYPE_NAMEDDATA: { ecma_value_t value = ecma_get_named_data_property_value (property_p); if (ecma_is_value_object (value)) { ecma_object_t *value_obj_p = ecma_get_object_from_value (value); ecma_gc_set_object_visited (value_obj_p, true); } break; } case ECMA_PROPERTY_TYPE_NAMEDACCESSOR: { ecma_object_t *getter_obj_p = ecma_get_named_accessor_property_getter (property_p); ecma_object_t *setter_obj_p = ecma_get_named_accessor_property_setter (property_p); if (getter_obj_p != NULL) { ecma_gc_set_object_visited (getter_obj_p, true); } if (setter_obj_p != NULL) { ecma_gc_set_object_visited (setter_obj_p, true); } break; } case ECMA_PROPERTY_TYPE_INTERNAL: { uint32_t property_value = ECMA_PROPERTY_VALUE_PTR (property_p)->value; switch (ECMA_PROPERTY_GET_INTERNAL_PROPERTY_TYPE (property_p)) { case ECMA_INTERNAL_PROPERTY_NUMBER_INDEXED_ARRAY_VALUES: /* a collection of ecma values */ case ECMA_INTERNAL_PROPERTY_STRING_INDEXED_ARRAY_VALUES: /* a collection of ecma values */ { JERRY_UNIMPLEMENTED ("Indexed array storage is not implemented yet."); } case ECMA_INTERNAL_PROPERTY_PROTOTYPE: /* the property's value is located in ecma_object_t * (see above in the routine) */ case ECMA_INTERNAL_PROPERTY_EXTENSIBLE: /* the property's value is located in ecma_object_t * (see above in the routine) */ case ECMA_INTERNAL_PROPERTY__COUNT: /* not a real internal property type, * but number of the real internal property types */ { JERRY_UNREACHABLE (); } case ECMA_INTERNAL_PROPERTY_PRIMITIVE_STRING_VALUE: /* compressed pointer to a ecma_string_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_NUMBER_VALUE: /* compressed pointer to a ecma_number_t */ case ECMA_INTERNAL_PROPERTY_PRIMITIVE_BOOLEAN_VALUE: /* a simple boolean value */ case ECMA_INTERNAL_PROPERTY_CLASS: /* an enum */ case ECMA_INTERNAL_PROPERTY_CODE_BYTECODE: /* compressed pointer to a bytecode array */ case ECMA_INTERNAL_PROPERTY_NATIVE_CODE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE: /* an external pointer */ case ECMA_INTERNAL_PROPERTY_FREE_CALLBACK: /* an object's native free callback */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_BUILT_IN_ROUTINE_DESC: /* an integer */ case ECMA_INTERNAL_PROPERTY_EXTENSION_ID: /* an integer */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_0_31: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_NON_INSTANTIATED_BUILT_IN_MASK_32_63: /* an integer (bit-mask) */ case ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE: { break; } case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_THIS: /* an ecma value */ { if (ecma_is_value_object (property_value)) { ecma_object_t *obj_p = ecma_get_object_from_value (property_value); ecma_gc_set_object_visited (obj_p, true); } break; } case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_BOUND_ARGS: /* a collection of ecma values */ { ecma_collection_header_t *bound_arg_list_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_header_t, property_value); ecma_collection_iterator_t bound_args_iterator; ecma_collection_iterator_init (&bound_args_iterator, bound_arg_list_p); for (ecma_length_t i = 0; i < bound_arg_list_p->unit_number; i++) { bool is_moved = ecma_collection_iterator_next (&bound_args_iterator); JERRY_ASSERT (is_moved); if (ecma_is_value_object (*bound_args_iterator.current_value_p)) { ecma_object_t *obj_p = ecma_get_object_from_value (*bound_args_iterator.current_value_p); ecma_gc_set_object_visited (obj_p, true); } } break; } case ECMA_INTERNAL_PROPERTY_BOUND_FUNCTION_TARGET_FUNCTION: /* an object */ case ECMA_INTERNAL_PROPERTY_SCOPE: /* a lexical environment */ case ECMA_INTERNAL_PROPERTY_PARAMETERS_MAP: /* an object */ { ecma_object_t *obj_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, property_value); ecma_gc_set_object_visited (obj_p, true); break; } } break; } default: { JERRY_UNREACHABLE (); break; } } } /* ecma_gc_mark_property */