/* Perform a full gc cycle */ MRB_API void mrb_full_gc(mrb_state *mrb) { mrb_gc *gc = &mrb->gc; if (gc->disabled || gc->iterating) return; GC_INVOKE_TIME_REPORT("mrb_full_gc()"); GC_TIME_START; if (is_generational(gc)) { /* clear all the old objects back to young */ clear_all_old(mrb, gc); gc->full = TRUE; } else if (gc->state != MRB_GC_STATE_ROOT) { /* finish half baked GC cycle */ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); } incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); gc->threshold = (gc->live_after_mark/100) * gc->interval_ratio; if (is_generational(gc)) { gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; gc->full = FALSE; } GC_TIME_STOP_AND_REPORT; }
/* Perform a full gc cycle */ void mrb_full_gc(mrb_state *mrb) { if (mrb->gc_disabled) return; GC_INVOKE_TIME_REPORT("mrb_full_gc()"); GC_TIME_START; if (is_generational(mrb)) { /* clear all the old objects back to young */ clear_all_old(mrb); mrb->gc_full = TRUE; } else if (mrb->gc_state != GC_STATE_NONE) { /* finish half baked GC cycle */ incremental_gc_until(mrb, GC_STATE_NONE); } incremental_gc_until(mrb, GC_STATE_NONE); mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio; if (is_generational(mrb)) { mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; mrb->gc_full = FALSE; } GC_TIME_STOP_AND_REPORT; }
void mrb_garbage_collect(mrb_state *mrb) { size_t max_limit = ~0; if (mrb->gc_disabled) return; GC_INVOKE_TIME_REPORT("mrb_garbage_collect()"); GC_TIME_START; if (mrb->gc_state == GC_STATE_SWEEP) { /* finish sweep phase */ while (mrb->gc_state != GC_STATE_NONE) { incremental_gc(mrb, max_limit); } } /* clean all black object as old */ if (is_generational(mrb)) { clear_all_old(mrb); mrb->gc_full = TRUE; } do { incremental_gc(mrb, max_limit); } while (mrb->gc_state != GC_STATE_NONE); mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio; if (is_generational(mrb)) { mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; mrb->gc_full = FALSE; } GC_TIME_STOP_AND_REPORT; }
static void change_gen_gc_mode(mrb_state *mrb, mrb_int enable) { if (is_generational(mrb) && !enable) { clear_all_old(mrb); mrb_assert(mrb->gc_state == GC_STATE_NONE); mrb->gc_full = FALSE; } else if (!is_generational(mrb) && enable) { incremental_gc_until(mrb, GC_STATE_NONE); mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; mrb->gc_full = FALSE; } mrb->is_generational_gc_mode = enable; }
static void change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable) { if (is_generational(gc) && !enable) { clear_all_old(mrb, gc); mrb_assert(gc->state == MRB_GC_STATE_ROOT); gc->full = FALSE; } else if (!is_generational(gc) && enable) { incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; gc->full = FALSE; } gc->generational = enable; }
void mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value) { if (!is_black(obj)) return; if (!is_white(value)) return; mrb_assert(!is_dead(mrb, value) && !is_dead(mrb, obj)); mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_NONE); if (is_generational(mrb) || mrb->gc_state == GC_STATE_MARK) { add_gray_list(mrb, value); } else { mrb_assert(mrb->gc_state == GC_STATE_SWEEP); paint_partial_white(mrb, obj); /* for never write barriers */ } }
static void change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable) { if (gc->disabled || gc->iterating) { mrb_raise(mrb, E_RUNTIME_ERROR, "generational mode changed when GC disabled"); return; } if (is_generational(gc) && !enable) { clear_all_old(mrb, gc); mrb_assert(gc->state == MRB_GC_STATE_ROOT); gc->full = FALSE; } else if (!is_generational(gc) && enable) { incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); gc->majorgc_old_threshold = gc->live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; gc->full = FALSE; } gc->generational = enable; }
MRB_API void mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value) { mrb_gc *gc = &mrb->gc; if (!is_black(obj)) return; if (!is_white(value)) return; mrb_assert(gc->state == MRB_GC_STATE_MARK || (!is_dead(gc, value) && !is_dead(gc, obj))); mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT); if (is_generational(gc) || gc->state == MRB_GC_STATE_MARK) { add_gray_list(mrb, gc, value); } else { mrb_assert(gc->state == MRB_GC_STATE_SWEEP); paint_partial_white(gc, obj); /* for never write barriers */ } }
void mrb_write_barrier(mrb_state *mrb, struct RBasic *obj) { if (!is_black(obj)) return; mrb_assert(!is_dead(mrb, obj)); mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_NONE); paint_gray(obj); obj->gcnext = mrb->atomic_gray_list; mrb->atomic_gray_list = obj; }
MRB_API void mrb_write_barrier(mrb_state *mrb, struct RBasic *obj) { mrb_gc *gc = &mrb->gc; if (!is_black(obj)) return; mrb_assert(!is_dead(gc, obj)); mrb_assert(is_generational(gc) || gc->state != MRB_GC_STATE_ROOT); paint_gray(obj); obj->gcnext = gc->atomic_gray_list; gc->atomic_gray_list = obj; }
static void clear_all_old(mrb_state *mrb) { size_t origin_mode = mrb->is_generational_gc_mode; gc_assert(is_generational(mrb)); if (is_major_gc(mrb)) { advance_phase(mrb, GC_STATE_NONE); } mrb->is_generational_gc_mode = FALSE; prepare_incremental_sweep(mrb); advance_phase(mrb, GC_STATE_NONE); mrb->variable_gray_list = mrb->gray_list = NULL; mrb->is_generational_gc_mode = origin_mode; }
static void clear_all_old(mrb_state *mrb) { mrb_bool origin_mode = mrb->is_generational_gc_mode; mrb_assert(is_generational(mrb)); if (is_major_gc(mrb)) { /* finish the half baked GC */ incremental_gc_until(mrb, GC_STATE_NONE); } /* Sweep the dead objects, then reset all the live objects * (including all the old objects, of course) to white. */ mrb->is_generational_gc_mode = FALSE; prepare_incremental_sweep(mrb); incremental_gc_until(mrb, GC_STATE_NONE); mrb->is_generational_gc_mode = origin_mode; /* The gray objects has already been painted as white */ mrb->atomic_gray_list = mrb->gray_list = NULL; }
static void clear_all_old(mrb_state *mrb, mrb_gc *gc) { mrb_bool origin_mode = gc->generational; mrb_assert(is_generational(gc)); if (is_major_gc(gc)) { /* finish the half baked GC */ incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); } /* Sweep the dead objects, then reset all the live objects * (including all the old objects, of course) to white. */ gc->generational = FALSE; prepare_incremental_sweep(mrb, gc); incremental_gc_until(mrb, gc, MRB_GC_STATE_ROOT); gc->generational = origin_mode; /* The gray objects have already been painted as white */ gc->atomic_gray_list = gc->gray_list = NULL; }
static size_t incremental_sweep_phase(mrb_state *mrb, size_t limit) { struct heap_page *page = mrb->sweeps; size_t tried_sweep = 0; while (page && (tried_sweep < limit)) { RVALUE *p = page->objects; RVALUE *e = p + MRB_HEAP_PAGE_SIZE; size_t freed = 0; mrb_bool dead_slot = TRUE; int full = (page->freelist == NULL); if (is_minor_gc(mrb) && page->old) { /* skip a slot which doesn't contain any young object */ p = e; dead_slot = FALSE; } while (p<e) { if (is_dead(mrb, &p->as.basic)) { if (p->as.basic.tt != MRB_TT_FREE) { obj_free(mrb, &p->as.basic); p->as.free.next = page->freelist; page->freelist = (struct RBasic*)p; freed++; } } else { if (!is_generational(mrb)) paint_partial_white(mrb, &p->as.basic); /* next gc target */ dead_slot = 0; } p++; } /* free dead slot */ if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) { struct heap_page *next = page->next; unlink_heap_page(mrb, page); unlink_free_heap_page(mrb, page); mrb_free(mrb, page); page = next; } else { if (full && freed > 0) { link_free_heap_page(mrb, page); } if (page->freelist == NULL && is_minor_gc(mrb)) page->old = TRUE; else page->old = FALSE; page = page->next; } tried_sweep += MRB_HEAP_PAGE_SIZE; mrb->live -= freed; mrb->gc_live_after_mark -= freed; } mrb->sweeps = page; return tried_sweep; }