/** * Free specified object */ void ecma_gc_sweep (ecma_object_t *object_p) /**< object to free */ { JERRY_ASSERT (object_p != NULL && !ecma_gc_is_object_visited (object_p) && ecma_gc_get_object_refs (object_p) == 0); if (!ecma_is_lexical_environment (object_p)) { /* if the object provides free callback, invoke it with handle stored in the object */ ecma_external_pointer_t freecb_p; ecma_external_pointer_t native_p; bool is_retrieved = ecma_get_external_pointer_value (object_p, ECMA_INTERNAL_PROPERTY_FREE_CALLBACK, &freecb_p); if (is_retrieved) { is_retrieved = ecma_get_external_pointer_value (object_p, ECMA_INTERNAL_PROPERTY_NATIVE_HANDLE, &native_p); JERRY_ASSERT (is_retrieved); jerry_dispatch_object_free_callback (freecb_p, native_p); } } if (!ecma_is_lexical_environment (object_p) || ecma_get_lex_env_type (object_p) != ECMA_LEXICAL_ENVIRONMENT_OBJECTBOUND) { for (ecma_property_t *property = ecma_get_property_list (object_p), *next_property_p; property != NULL; property = next_property_p) { next_property_p = ECMA_GET_POINTER (ecma_property_t, property->next_property_p); ecma_free_property (object_p, property); } } JERRY_ASSERT (ecma_gc_objects_number > 0); ecma_gc_objects_number--; ecma_dealloc_object (object_p); } /* ecma_gc_sweep */
/** * 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 */
/** * Increase reference counter of an object */ void ecma_ref_object (ecma_object_t *object_p) /**< object */ { ecma_gc_set_object_refs (object_p, ecma_gc_get_object_refs (object_p) + 1); } /* ecma_ref_object */
/** * Decrease reference counter of an object */ void ecma_deref_object (ecma_object_t *object_p) /**< object */ { JERRY_ASSERT (ecma_gc_get_object_refs (object_p) > 0); ecma_gc_set_object_refs (object_p, ecma_gc_get_object_refs (object_p) - 1); } /* ecma_deref_object */
/** * 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 */