121 #include <sys/time.h>
123 static double program_invoke_time = 0;
124 static double gc_time = 0;
125 static double gc_total_time = 0;
128 gettimeofday_time(
void)
131 gettimeofday(&tv, NULL);
132 return tv.tv_sec + tv.tv_usec * 1e-6;
135 #define GC_INVOKE_TIME_REPORT(with) do {\
136 fprintf(stderr, "%s\n", with);\
137 fprintf(stderr, "gc_invoke: %19.3f\n", gettimeofday_time() - program_invoke_time);\
138 fprintf(stderr, "is_generational: %d\n", is_generational(mrb));\
139 fprintf(stderr, "is_major_gc: %d\n", is_major_gc(mrb));\
142 #define GC_TIME_START do {\
143 gc_time = gettimeofday_time();\
146 #define GC_TIME_STOP_AND_REPORT do {\
147 gc_time = gettimeofday_time() - gc_time;\
148 gc_total_time += gc_time;\
149 fprintf(stderr, "gc_state: %d\n", mrb->gc_state);\
150 fprintf(stderr, "live: %zu\n", mrb->live);\
151 fprintf(stderr, "majorgc_old_threshold: %zu\n", mrb->majorgc_old_threshold);\
152 fprintf(stderr, "gc_threshold: %zu\n", mrb->gc_threshold);\
153 fprintf(stderr, "gc_time: %30.20f\n", gc_time);\
154 fprintf(stderr, "gc_total_time: %30.20f\n\n", gc_total_time);\
157 #define GC_INVOKE_TIME_REPORT(s)
158 #define GC_TIME_START
159 #define GC_TIME_STOP_AND_REPORT
168 #define GC_STEP_SIZE 1024
176 p2 = (mrb->
allocf)(mrb, p, len, mrb->
ud);
177 if (!p2 && len > 0 && mrb->
heaps) {
179 p2 = (mrb->
allocf)(mrb, p, len, mrb->
ud);
225 if (nelem > 0 && len > 0 &&
226 nelem <= SIZE_MAX / len) {
248 #ifndef MRB_HEAP_PAGE_SIZE
249 #define MRB_HEAP_PAGE_SIZE 1024
278 if (mrb->
heaps == page)
312 struct RBasic *prev = NULL;
321 link_heap_page(mrb, page);
322 link_free_heap_page(mrb, page);
325 #define DEFAULT_GC_INTERVAL_RATIO 200
326 #define DEFAULT_GC_STEP_RATIO 200
327 #define DEFAULT_MAJOR_GC_INC_RATIO 200
328 #define is_generational(mrb) ((mrb)->is_generational_gc_mode)
329 #define is_major_gc(mrb) (is_generational(mrb) && (mrb)->gc_full)
330 #define is_minor_gc(mrb) (is_generational(mrb) && !(mrb)->gc_full)
340 #ifndef MRB_GC_TURN_OFF_GENERATIONAL
346 program_invoke_time = gettimeofday_time();
412 *(
RVALUE *)p = RVALUE_zero;
441 for (i=0; i<e; i++) {
454 mark_context_stack(mrb, c);
458 for (i=0; i<e; i++) {
462 for (ci = c->
cibase; ci <= c->ci; ci++) {
518 for (i=0; i<len; i++) {
529 mark_context(mrb, c);
538 for (i=0,e=a->
len; i<e; i++) {
571 if (obj == 0)
return;
574 add_gray_list(mrb, obj);
580 DEBUG(printf(
"obj_free(%p,tt=%d)\n",obj,obj->tt));
590 #ifdef MRB_WORD_BOXING
684 mark_context(mrb, mrb->
root_c);
686 mark_context(mrb, mrb->
c);
693 for (i=0; i<len; i++) {
696 for (j=0; j<irep->
plen; j++) {
708 gc_mark_children(mrb, obj);
733 children += (int)obj->flags;
743 i = c->stack - c->stbase;
744 if (c->ci) i += c->ci->nregs;
745 if (c->stbase + i > c->stend) i = c->stend - c->stbase;
749 children += (c->ci) ? c->ci->eidx : 0;
753 for (i=0, ci = c->cibase; ci <= c->ci; i++, ci++)
796 incremental_marking_phase(
mrb_state *mrb,
size_t limit)
798 size_t tried_marks = 0;
800 while (mrb->
gray_list && tried_marks < limit) {
801 tried_marks += gc_gray_mark(mrb, mrb->
gray_list);
810 mark_context_stack(mrb, mrb->
root_c);
811 gc_mark_gray_list(mrb);
815 gc_mark_gray_list(mrb);
820 prepare_incremental_sweep(
mrb_state *mrb)
828 incremental_sweep_phase(
mrb_state *mrb,
size_t limit)
831 size_t tried_sweep = 0;
833 while (page && (tried_sweep < limit)) {
838 int full = (page->
freelist == NULL);
863 if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) {
866 unlink_heap_page(mrb, page);
867 unlink_free_heap_page(mrb, page);
872 if (full && freed > 0) {
873 link_free_heap_page(mrb, page);
890 incremental_gc(
mrb_state *mrb,
size_t limit)
894 root_scan_phase(mrb);
900 return incremental_marking_phase(mrb, limit);
903 final_marking_phase(mrb);
904 prepare_incremental_sweep(mrb);
908 size_t tried_sweep = 0;
909 tried_sweep = incremental_sweep_phase(mrb, limit);
910 if (tried_sweep == 0)
925 incremental_gc(mrb, ~0);
926 }
while (mrb->
gc_state != to_state);
932 size_t limit = 0, result = 0;
934 while (result < limit) {
935 result += incremental_gc(mrb, limit);
957 prepare_incremental_sweep(mrb);
977 incremental_gc_step(mrb);
1064 add_gray_list(mrb, value);
1105 return mrb_nil_value();
1128 return mrb_bool_value(old);
1150 return mrb_bool_value(old);
1183 return mrb_nil_value();
1216 return mrb_nil_value();
1264 change_gen_gc_mode(mrb, enable);
1266 return mrb_bool_value(enable);
1274 while (page != NULL) {
1279 for (;p < pend; p++) {
1280 (*callback)(mrb, &p->
as.
basic, data);
1319 test_mrb_field_write_barrier(
void)
1322 struct RBasic *obj, *value;
1324 puts(
"test_mrb_field_write_barrier");
1332 puts(
" in GC_STATE_MARK");
1339 puts(
" in GC_STATE_SWEEP");
1348 puts(
" fail with black");
1357 puts(
" fail with gray");
1367 puts(
"test_mrb_field_write_barrier_value");
1383 test_mrb_write_barrier(
void)
1388 puts(
"test_mrb_write_barrier");
1392 puts(
" in GC_STATE_MARK");
1400 puts(
" fail with gray");
1410 test_add_gray_list(
void)
1413 struct RBasic *obj1, *obj2;
1415 puts(
"test_add_gray_list");
1416 change_gen_gc_mode(mrb,
FALSE);
1419 add_gray_list(mrb, obj1);
1424 add_gray_list(mrb, obj2);
1433 test_gc_gray_mark(
void)
1438 size_t gray_num = 0;
1440 puts(
"test_gc_gray_mark");
1442 puts(
" in MRB_TT_CLASS");
1445 gray_num = gc_gray_mark(mrb, obj);
1449 puts(
" in MRB_TT_ARRAY");
1464 test_incremental_gc(
void)
1467 size_t max = ~0, live = 0, total = 0, freed = 0;
1471 puts(
"test_incremental_gc");
1472 change_gen_gc_mode(mrb,
FALSE);
1474 puts(
" in mrb_full_gc");
1478 puts(
" in GC_STATE_NONE");
1479 incremental_gc(mrb, max);
1481 puts(
" in GC_STATE_MARK");
1485 puts(
" in GC_STATE_SWEEP");
1505 incremental_gc(mrb, max);
1508 incremental_gc(mrb, max);
1520 puts(
"test_incremental_gc(gen)");
1522 change_gen_gc_mode(mrb,
TRUE);
1546 test_incremental_sweep_phase(
void)
1550 puts(
"test_incremental_sweep_phase");
1557 incremental_sweep_phase(mrb, MRB_HEAP_PAGE_SIZE*3);
1568 test_mrb_field_write_barrier();
1569 test_mrb_write_barrier();
1570 test_add_gray_list();
1571 test_gc_gray_mark();
1572 test_incremental_gc();
1573 test_incremental_sweep_phase();
1574 return mrb_nil_value();