diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/gc.c | 94 | ||||
| -rw-r--r-- | src/kernel.c | 11 |
2 files changed, 58 insertions, 47 deletions
@@ -42,18 +42,18 @@ There're two white color types in a flip-flop fassion: White-A and White-B, which respectively represent the Current White color (the newly allocated - objects in the current round of GC) and the Sweep Target White color (the + objects in the current GC cycle) and the Sweep Target White color (the dead objects to be swept). - A and B will be switched just at the beginning of the next round of GC. At + A and B will be switched just at the beginning of the next GC cycle. At that time, all the dead objects have been swept, while the newly created - objects in the current round of GC which finally remains White are now + objects in the current GC cycle which finally remains White are now regarded as dead objects. Instead of traversing all the White-A objects and paint them as White-B, just switch the meaning of White-A and White-B would be much cheaper. - As a result, the objects we sweep in the current round of GC are always - left from the previous round of GC. This allows us to sweep objects + As a result, the objects we sweep in the current GC cycle are always + left from the previous GC cycle. This allows us to sweep objects incrementally, without the disturbance of the newly created objects. == Execution Timing @@ -86,7 +86,7 @@ phase, then only sweep the newly created objects, and leave the Old objects live. - * Major GC - same as a full round of regular GC. + * Major GC - same as a full regular GC cycle. For details, see the comments for each function. @@ -175,7 +175,7 @@ mrb_realloc_simple(mrb_state *mrb, void *p, size_t len) p2 = (mrb->allocf)(mrb, p, len, mrb->ud); if (!p2 && len > 0 && mrb->heaps) { - mrb_garbage_collect(mrb); + mrb_full_gc(mrb); p2 = (mrb->allocf)(mrb, p, len, mrb->ud); } @@ -390,7 +390,7 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } }; #ifdef MRB_GC_STRESS - mrb_garbage_collect(mrb); + mrb_full_gc(mrb); #endif if (mrb->gc_threshold < mrb->live) { mrb_incremental_gc(mrb); @@ -664,7 +664,7 @@ root_scan_phase(mrb_state *mrb) if (!is_minor_gc(mrb)) { mrb->gray_list = NULL; - mrb->variable_gray_list = NULL; + mrb->atomic_gray_list = NULL; } mrb_gc_mark_gv(mrb); @@ -774,6 +774,20 @@ gc_gray_mark(mrb_state *mrb, struct RBasic *obj) return children; } + +static void +gc_mark_gray_list(mrb_state *mrb, struct RBasic **gray_list) { + struct RBasic *obj; + + while ((obj = *gray_list)) { + if (is_gray(obj)) { + gc_mark_children(mrb, obj); + } + *gray_list = obj->gcnext; + } +} + + static size_t incremental_marking_phase(mrb_state *mrb, size_t limit) { @@ -790,21 +804,9 @@ static void final_marking_phase(mrb_state *mrb) { mark_context_stack(mrb, mrb->root_c); - while (mrb->gray_list) { - if (is_gray(mrb->gray_list)) - gc_mark_children(mrb, mrb->gray_list); - else - mrb->gray_list = mrb->gray_list->gcnext; - } + gc_mark_gray_list(mrb, &mrb->gray_list); + gc_mark_gray_list(mrb, &mrb->atomic_gray_list); gc_assert(mrb->gray_list == NULL); - mrb->gray_list = mrb->variable_gray_list; - mrb->variable_gray_list = NULL; - while (mrb->gray_list) { - if (is_gray(mrb->gray_list)) - gc_mark_children(mrb, mrb->gray_list); - else - mrb->gray_list = mrb->gray_list->gcnext; - } gc_assert(mrb->gray_list == NULL); } @@ -919,6 +921,20 @@ incremental_gc_until(mrb_state *mrb, enum gc_state to_state) } static void +incremental_gc_step(mrb_state *mrb) +{ + size_t limit = 0, result = 0; + limit = (GC_STEP_SIZE/100) * mrb->gc_step_ratio; + while (result < limit) { + result += incremental_gc(mrb, limit); + if (mrb->gc_state == GC_STATE_NONE) + break; + } + + mrb->gc_threshold = mrb->live + GC_STEP_SIZE; +} + +static void clear_all_old(mrb_state *mrb) { size_t origin_mode = mrb->is_generational_gc_mode; @@ -931,7 +947,7 @@ clear_all_old(mrb_state *mrb) mrb->is_generational_gc_mode = FALSE; prepare_incremental_sweep(mrb); incremental_gc_until(mrb, GC_STATE_NONE); - mrb->variable_gray_list = mrb->gray_list = NULL; + mrb->atomic_gray_list = mrb->gray_list = NULL; mrb->is_generational_gc_mode = origin_mode; } @@ -947,13 +963,7 @@ mrb_incremental_gc(mrb_state *mrb) incremental_gc_until(mrb, GC_STATE_NONE); } else { - size_t limit = 0, result = 0; - limit = (GC_STEP_SIZE/100) * mrb->gc_step_ratio; - while (result < limit) { - result += incremental_gc(mrb, limit); - if (mrb->gc_state == GC_STATE_NONE) - break; - } + incremental_gc_step(mrb); } if (mrb->gc_state == GC_STATE_NONE) { @@ -962,6 +972,7 @@ mrb_incremental_gc(mrb_state *mrb) if (mrb->gc_threshold < GC_STEP_SIZE) { mrb->gc_threshold = GC_STEP_SIZE; } + if (is_major_gc(mrb)) { mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO; mrb->gc_full = FALSE; @@ -973,19 +984,16 @@ mrb_incremental_gc(mrb_state *mrb) } } } - else { - mrb->gc_threshold = mrb->live + GC_STEP_SIZE; - } - GC_TIME_STOP_AND_REPORT; } +/* Perform a full gc cycle */ void -mrb_garbage_collect(mrb_state *mrb) +mrb_full_gc(mrb_state *mrb) { if (mrb->gc_disabled) return; - GC_INVOKE_TIME_REPORT("mrb_garbage_collect()"); + GC_INVOKE_TIME_REPORT("mrb_full_gc()"); GC_TIME_START; if (mrb->gc_state == GC_STATE_SWEEP) { @@ -1062,8 +1070,8 @@ mrb_write_barrier(mrb_state *mrb, struct RBasic *obj) gc_assert(!is_dead(mrb, obj)); gc_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_NONE); paint_gray(obj); - obj->gcnext = mrb->variable_gray_list; - mrb->variable_gray_list = obj; + obj->gcnext = mrb->atomic_gray_list; + mrb->atomic_gray_list = obj; } /* @@ -1077,7 +1085,7 @@ mrb_write_barrier(mrb_state *mrb, struct RBasic *obj) static mrb_value gc_start(mrb_state *mrb, mrb_value obj) { - mrb_garbage_collect(mrb); + mrb_full_gc(mrb); return mrb_nil_value(); } @@ -1370,7 +1378,7 @@ test_mrb_write_barrier(void) mrb_write_barrier(mrb, obj); gc_assert(is_gray(obj)); - gc_assert(mrb->variable_gray_list == obj); + gc_assert(mrb->atomic_gray_list == obj); puts(" fail with gray"); @@ -1447,8 +1455,8 @@ test_incremental_gc(void) puts("test_incremental_gc"); change_gen_gc_mode(mrb, FALSE); - puts(" in mrb_garbage_collect"); - mrb_garbage_collect(mrb); + puts(" in mrb_full_gc"); + mrb_full_gc(mrb); gc_assert(mrb->gc_state == GC_STATE_NONE); puts(" in GC_STATE_NONE"); diff --git a/src/kernel.c b/src/kernel.c index 4914b7285..eb123b51e 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -4,6 +4,8 @@ ** See Copyright Notice in mruby.h */ +#include <assert.h> + #include "mruby.h" #include "mruby/array.h" #include "mruby/class.h" @@ -549,7 +551,7 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self) } static void -valid_iv_name(mrb_state *mrb, mrb_sym iv_name_id, const char* s, size_t len) +valid_iv_name(mrb_state *mrb, mrb_sym iv_name_id, const char* s, size_t len) { if (len < 2 || !(s[0] == '@' && s[1] != '@')) { mrb_name_error(mrb, iv_name_id, "`%S' is not allowed as an instance variable name", mrb_sym2str(mrb, iv_name_id)); @@ -575,7 +577,8 @@ get_valid_iv_sym(mrb_state *mrb, mrb_value iv_name) iv_name_id = mrb_intern_cstr(mrb, RSTRING_PTR(iv_name)); valid_iv_name(mrb, iv_name_id, RSTRING_PTR(iv_name), RSTRING_LEN(iv_name)); } - else if(mrb_symbol_p(iv_name)) { + else { + assert(mrb_symbol_p(iv_name)); iv_name_id = mrb_symbol(iv_name); check_iv_name(mrb, iv_name_id); } @@ -640,7 +643,7 @@ mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) { mrb_sym iv_name_id; mrb_value iv_name; - + mrb_get_args(mrb, "o", &iv_name); iv_name_id = get_valid_iv_sym(mrb, iv_name); @@ -674,7 +677,7 @@ mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) mrb_value iv_name, val; mrb_get_args(mrb, "oo", &iv_name, &val); - + iv_name_id = get_valid_iv_sym(mrb, iv_name); mrb_iv_set(mrb, self, iv_name_id, val); return val; |
