• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

mrubyを超漢字で動作させる


Commit MetaInfo

Révision3ab2f9371e60039936356afaee9f509d782259fd (tree)
l'heure2015-10-20 05:29:43
Auteurfurunkel <julian@linu...>
Commiterfurunkel

Message de Log

Clean up GC code

Change Summary

Modification

--- a/include/mruby.h
+++ b/include/mruby.h
@@ -35,6 +35,7 @@
3535 #include "mrbconf.h"
3636 #include "mruby/common.h"
3737 #include "mruby/value.h"
38+#include "mruby/gc.h"
3839 #include "mruby/version.h"
3940
4041 /**
@@ -114,16 +115,11 @@ struct mrb_context {
114115 struct RFiber *fib;
115116 };
116117
117-enum gc_state {
118- GC_STATE_ROOT = 0,
119- GC_STATE_MARK,
120- GC_STATE_SWEEP
121-};
122-
123118 struct mrb_jmpbuf;
124119
125120 typedef void (*mrb_atexit_func)(struct mrb_state*);
126121
122+
127123 typedef struct mrb_state {
128124 struct mrb_jmpbuf *jmp;
129125
@@ -153,32 +149,8 @@ typedef struct mrb_state {
153149 struct RClass *symbol_class;
154150 struct RClass *kernel_module;
155151
156- struct heap_page *heaps; /* heaps for GC */
157- struct heap_page *sweeps;
158- struct heap_page *free_heaps;
159- size_t live; /* count of live objects */
160-#ifdef MRB_GC_FIXED_ARENA
161- struct RBasic *arena[MRB_GC_ARENA_SIZE]; /* GC protection array */
162-#else
163- struct RBasic **arena; /* GC protection array */
164- int arena_capa;
165-#endif
166- int arena_idx;
167-
168- enum gc_state gc_state; /* state of gc */
169- int current_white_part; /* make white object by white_part */
170- struct RBasic *gray_list; /* list of gray objects to be traversed incrementally */
171- struct RBasic *atomic_gray_list; /* list of objects to be traversed atomically */
172- size_t gc_live_after_mark;
173- size_t gc_threshold;
174- int gc_interval_ratio;
175- int gc_step_ratio;
176- mrb_bool gc_disabled:1;
177- mrb_bool gc_full:1;
178- mrb_bool is_generational_gc_mode:1;
179- mrb_bool out_of_memory:1;
180- size_t majorgc_old_threshold;
181152 struct alloca_header *mems;
153+ mrb_gc gc;
182154
183155 mrb_sym symidx;
184156 struct kh_n2s *name2sym; /* symbol hash */
--- a/include/mruby/gc.h
+++ b/include/mruby/gc.h
@@ -14,9 +14,68 @@
1414 */
1515 MRB_BEGIN_DECL
1616
17-typedef void (mrb_each_object_callback)(mrb_state *mrb, struct RBasic *obj, void *data);
18-void mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data);
19-MRB_API void mrb_free_context(mrb_state *mrb, struct mrb_context *c);
17+
18+struct mrb_state;
19+
20+typedef void (mrb_each_object_callback)(struct mrb_state *mrb, struct RBasic *obj, void *data);
21+void mrb_objspace_each_objects(struct mrb_state *mrb, mrb_each_object_callback *callback, void *data);
22+MRB_API void mrb_free_context(struct mrb_state *mrb, struct mrb_context *c);
23+
24+
25+/* white: 011, black: 100, gray: 000 */
26+#define MRB_GC_GRAY 0
27+#define MRB_GC_WHITE_A 1
28+#define MRB_GC_WHITE_B (1 << 1)
29+#define MRB_GC_BLACK (1 << 2)
30+#define MRB_GC_WHITES (MRB_GC_WHITE_A | MRB_GC_WHITE_B)
31+#define MRB_GC_COLOR_MASK 7
32+
33+typedef enum {
34+ GC_STATE_ROOT = 0,
35+ GC_STATE_MARK,
36+ GC_STATE_SWEEP
37+} mrb_gc_state;
38+
39+typedef struct mrb_heap_page {
40+ struct RBasic *freelist;
41+ struct mrb_heap_page *prev;
42+ struct mrb_heap_page *next;
43+ struct mrb_heap_page *free_next;
44+ struct mrb_heap_page *free_prev;
45+ mrb_bool old:1;
46+ void *objects[];
47+} mrb_heap_page;
48+
49+typedef struct mrb_gc {
50+ mrb_heap_page *heaps; /* heaps for GC */
51+ mrb_heap_page *sweeps;
52+ mrb_heap_page *free_heaps;
53+ size_t live; /* count of live objects */
54+#ifdef MRB_GC_FIXED_ARENA
55+ struct RBasic *arena[MRB_GC_ARENA_SIZE]; /* GC protection array */
56+#else
57+ struct RBasic **arena; /* GC protection array */
58+ int arena_capa;
59+#endif
60+ int arena_idx;
61+
62+ mrb_gc_state gc_state; /* state of gc */
63+ int current_white_part; /* make white object by white_part */
64+ struct RBasic *gray_list; /* list of gray objects to be traversed incrementally */
65+ struct RBasic *atomic_gray_list; /* list of objects to be traversed atomically */
66+ size_t gc_live_after_mark;
67+ size_t gc_threshold;
68+ int gc_interval_ratio;
69+ int gc_step_ratio;
70+ mrb_bool disabled :1;
71+ mrb_bool full :1;
72+ mrb_bool generational :1;
73+ mrb_bool out_of_memory :1;
74+ size_t majorgc_old_threshold;
75+} mrb_gc;
76+
77+MRB_API mrb_bool
78+mrb_object_dead_p(struct mrb_state *mrb, struct RObject *object);
2079
2180 MRB_END_DECL
2281
--- a/include/mruby/object.h
+++ b/include/mruby/object.h
@@ -16,24 +16,6 @@
1616
1717 #define MRB_FLAG_TEST(obj, flag) ((obj)->flags & flag)
1818
19-/* white: 011, black: 100, gray: 000 */
20-#define MRB_GC_GRAY 0
21-#define MRB_GC_WHITE_A 1
22-#define MRB_GC_WHITE_B (1 << 1)
23-#define MRB_GC_BLACK (1 << 2)
24-#define MRB_GC_WHITES (MRB_GC_WHITE_A | MRB_GC_WHITE_B)
25-#define MRB_GC_COLOR_MASK 7
26-
27-#define paint_gray(o) ((o)->color = MRB_GC_GRAY)
28-#define paint_black(o) ((o)->color = MRB_GC_BLACK)
29-#define paint_white(o) ((o)->color = MRB_GC_WHITES)
30-#define paint_partial_white(s, o) ((o)->color = (s)->current_white_part)
31-#define is_gray(o) ((o)->color == MRB_GC_GRAY)
32-#define is_white(o) ((o)->color & MRB_GC_WHITES)
33-#define is_black(o) ((o)->color & MRB_GC_BLACK)
34-#define is_dead(s, o) (((o)->color & other_white_part(s) & MRB_GC_WHITES) || (o)->tt == MRB_TT_FREE)
35-#define flip_white_part(s) ((s)->current_white_part = other_white_part(s))
36-#define other_white_part(s) ((s)->current_white_part ^ MRB_GC_WHITES)
3719
3820 struct RBasic {
3921 MRB_OBJECT_HEADER;
--- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c
+++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c
@@ -17,7 +17,7 @@ os_count_object_type(mrb_state *mrb, struct RBasic *obj, void *data)
1717
1818 obj_count->total++;
1919
20- if (is_dead(mrb, obj)) {
20+ if (mrb_object_dead_p(mrb, obj)) {
2121 obj_count->freed++;
2222 }
2323 else {
@@ -115,7 +115,7 @@ os_each_object_cb(mrb_state *mrb, struct RBasic *obj, void *ud)
115115 struct os_each_object_data *d = (struct os_each_object_data*)ud;
116116
117117 /* filter dead objects */
118- if (is_dead(mrb, obj)) {
118+ if (mrb_object_dead_p(mrb, obj)) {
119119 return;
120120 }
121121
--- a/src/error.c
+++ b/src/error.c
@@ -206,7 +206,7 @@ MRB_API mrb_noreturn void
206206 mrb_exc_raise(mrb_state *mrb, mrb_value exc)
207207 {
208208 mrb->exc = mrb_obj_ptr(exc);
209- if (!mrb->out_of_memory) {
209+ if (!mrb->gc.out_of_memory) {
210210 exc_debug_info(mrb, mrb->exc);
211211 }
212212 if (!mrb->jmp) {
--- a/src/gc.c
+++ b/src/gc.c
@@ -101,6 +101,40 @@ typedef struct {
101101 union {
102102 struct free_obj free;
103103 struct RBasic basic;
104+ struct RClass klass;
105+ struct RProc proc;
106+ struct RException exc;
107+ } as;
108+} infreq_value;
109+
110+typedef struct {
111+ union {
112+ struct free_obj free;
113+ struct RBasic basic;
114+ struct RObject object;
115+#ifdef MRB_WORD_BOXING
116+ struct RFloat floatv;
117+ struct RCptr cptr;
118+#endif
119+ } as;
120+} small_value;
121+
122+typedef struct {
123+ union {
124+ struct free_obj free;
125+ struct RBasic basic;
126+ struct RString string;
127+ struct RArray array;
128+ struct RHash hash;
129+ struct RRange range;
130+ struct RData data;
131+ } as;
132+} large_value;
133+
134+typedef struct {
135+ union {
136+ struct free_obj free;
137+ struct RBasic basic;
104138 struct RObject object;
105139 struct RClass klass;
106140 struct RString string;
@@ -136,7 +170,7 @@ gettimeofday_time(void)
136170 #define GC_INVOKE_TIME_REPORT(with) do {\
137171 fprintf(stderr, "%s\n", with);\
138172 fprintf(stderr, "gc_invoke: %19.3f\n", gettimeofday_time() - program_invoke_time);\
139- fprintf(stderr, "is_generational: %d\n", is_generational(mrb));\
173+ fprintf(stderr, "is_generational: %d\n", is_generational(gc));\
140174 fprintf(stderr, "is_major_gc: %d\n", is_major_gc(mrb));\
141175 } while(0)
142176
@@ -147,10 +181,10 @@ gettimeofday_time(void)
147181 #define GC_TIME_STOP_AND_REPORT do {\
148182 gc_time = gettimeofday_time() - gc_time;\
149183 gc_total_time += gc_time;\
150- fprintf(stderr, "gc_state: %d\n", mrb->gc_state);\
151- fprintf(stderr, "live: %zu\n", mrb->live);\
152- fprintf(stderr, "majorgc_old_threshold: %zu\n", mrb->majorgc_old_threshold);\
153- fprintf(stderr, "gc_threshold: %zu\n", mrb->gc_threshold);\
184+ fprintf(stderr, "gc_state: %d\n", gc->gc_state);\
185+ fprintf(stderr, "live: %zu\n", gc->live);\
186+ fprintf(stderr, "majorgc_old_threshold: %zu\n", gc->majorgc_old_threshold);\
187+ fprintf(stderr, "gc_threshold: %zu\n", gc->gc_threshold);\
154188 fprintf(stderr, "gc_time: %30.20f\n", gc_time);\
155189 fprintf(stderr, "gc_total_time: %30.20f\n\n", gc_total_time);\
156190 } while(0)
@@ -166,8 +200,24 @@ gettimeofday_time(void)
166200 #define DEBUG(x)
167201 #endif
168202
203+#ifndef MRB_HEAP_PAGE_SIZE
204+#define MRB_HEAP_PAGE_SIZE 1024
205+#endif
206+
169207 #define GC_STEP_SIZE 1024
170208
209+#define paint_gray(o) ((o)->color = MRB_GC_GRAY)
210+#define paint_black(o) ((o)->color = MRB_GC_BLACK)
211+#define paint_white(o) ((o)->color = MRB_GC_WHITES)
212+#define paint_partial_white(s, o) ((o)->color = (s)->current_white_part)
213+#define is_gray(o) ((o)->color == MRB_GC_GRAY)
214+#define is_white(o) ((o)->color & MRB_GC_WHITES)
215+#define is_black(o) ((o)->color & MRB_GC_BLACK)
216+#define flip_white_part(s) ((s)->current_white_part = other_white_part(s))
217+#define other_white_part(s) ((s)->current_white_part ^ MRB_GC_WHITES)
218+#define is_dead(s, o) (((o)->color & other_white_part(s) & MRB_GC_WHITES) || (o)->tt == MRB_TT_FREE)
219+
220+#define objects(p) ((RVALUE *)p->objects)
171221
172222 MRB_API void*
173223 mrb_realloc_simple(mrb_state *mrb, void *p, size_t len)
@@ -175,7 +225,7 @@ mrb_realloc_simple(mrb_state *mrb, void *p, size_t len)
175225 void *p2;
176226
177227 p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
178- if (!p2 && len > 0 && mrb->heaps) {
228+ if (!p2 && len > 0 && mrb->gc.heaps) {
179229 mrb_full_gc(mrb);
180230 p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
181231 }
@@ -183,7 +233,6 @@ mrb_realloc_simple(mrb_state *mrb, void *p, size_t len)
183233 return p2;
184234 }
185235
186-
187236 MRB_API void*
188237 mrb_realloc(mrb_state *mrb, void *p, size_t len)
189238 {
@@ -191,16 +240,16 @@ mrb_realloc(mrb_state *mrb, void *p, size_t len)
191240
192241 p2 = mrb_realloc_simple(mrb, p, len);
193242 if (!p2 && len) {
194- if (mrb->out_of_memory) {
243+ if (mrb->gc.out_of_memory) {
195244 /* mrb_panic(mrb); */
196245 }
197246 else {
198- mrb->out_of_memory = TRUE;
247+ mrb->gc.out_of_memory = TRUE;
199248 mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
200249 }
201250 }
202251 else {
203- mrb->out_of_memory = FALSE;
252+ mrb->gc.out_of_memory = FALSE;
204253 }
205254
206255 return p2;
@@ -244,101 +293,98 @@ mrb_free(mrb_state *mrb, void *p)
244293 (mrb->allocf)(mrb, p, 0, mrb->allocf_ud);
245294 }
246295
247-#ifndef MRB_HEAP_PAGE_SIZE
248-#define MRB_HEAP_PAGE_SIZE 1024
249-#endif
250-
251-struct heap_page {
252- struct RBasic *freelist;
253- struct heap_page *prev;
254- struct heap_page *next;
255- struct heap_page *free_next;
256- struct heap_page *free_prev;
257- mrb_bool old:1;
258- RVALUE objects[MRB_HEAP_PAGE_SIZE];
259-};
296+MRB_API mrb_bool
297+mrb_object_dead_p(mrb_state *mrb, struct RObject *object) {
298+ return is_dead(&mrb->gc, object);
299+}
260300
261301 static void
262-link_heap_page(mrb_state *mrb, struct heap_page *page)
302+link_heap_page(mrb_gc *gc, mrb_heap_page *page)
263303 {
264- page->next = mrb->heaps;
265- if (mrb->heaps)
266- mrb->heaps->prev = page;
267- mrb->heaps = page;
304+ page->next = gc->heaps;
305+ if (gc->heaps)
306+ gc->heaps->prev = page;
307+ gc->heaps = page;
268308 }
269309
270310 static void
271-unlink_heap_page(mrb_state *mrb, struct heap_page *page)
311+unlink_heap_page(mrb_gc *gc, mrb_heap_page *page)
272312 {
273313 if (page->prev)
274314 page->prev->next = page->next;
275315 if (page->next)
276316 page->next->prev = page->prev;
277- if (mrb->heaps == page)
278- mrb->heaps = page->next;
317+ if (gc->heaps == page)
318+ gc->heaps = page->next;
279319 page->prev = NULL;
280320 page->next = NULL;
281321 }
282322
283323 static void
284-link_free_heap_page(mrb_state *mrb, struct heap_page *page)
324+link_free_heap_page(mrb_gc *gc, mrb_heap_page *page)
285325 {
286- page->free_next = mrb->free_heaps;
287- if (mrb->free_heaps) {
288- mrb->free_heaps->free_prev = page;
326+ page->free_next = gc->free_heaps;
327+ if (gc->free_heaps) {
328+ gc->free_heaps->free_prev = page;
289329 }
290- mrb->free_heaps = page;
330+ gc->free_heaps = page;
291331 }
292332
293333 static void
294-unlink_free_heap_page(mrb_state *mrb, struct heap_page *page)
334+unlink_free_heap_page(mrb_gc *gc, mrb_heap_page *page)
295335 {
296336 if (page->free_prev)
297337 page->free_prev->free_next = page->free_next;
298338 if (page->free_next)
299339 page->free_next->free_prev = page->free_prev;
300- if (mrb->free_heaps == page)
301- mrb->free_heaps = page->free_next;
340+ if (gc->free_heaps == page)
341+ gc->free_heaps = page->free_next;
302342 page->free_prev = NULL;
303343 page->free_next = NULL;
304344 }
305345
306346 static void
307-add_heap(mrb_state *mrb)
347+add_heap(mrb_state *mrb, mrb_gc *gc)
308348 {
309- struct heap_page *page = (struct heap_page *)mrb_calloc(mrb, 1, sizeof(struct heap_page));
349+ mrb_heap_page *page = (mrb_heap_page *)mrb_calloc(mrb, 1, sizeof(mrb_heap_page) + MRB_HEAP_PAGE_SIZE * sizeof(RVALUE));
310350 RVALUE *p, *e;
311351 struct RBasic *prev = NULL;
312352
313- for (p = page->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
353+ for (p = objects(page), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
314354 p->as.free.tt = MRB_TT_FREE;
315355 p->as.free.next = prev;
316356 prev = &p->as.basic;
317357 }
318358 page->freelist = prev;
319359
320- link_heap_page(mrb, page);
321- link_free_heap_page(mrb, page);
360+ link_heap_page(gc, page);
361+ link_free_heap_page(gc, page);
322362 }
323363
324364 #define DEFAULT_GC_INTERVAL_RATIO 200
325365 #define DEFAULT_GC_STEP_RATIO 200
326366 #define DEFAULT_MAJOR_GC_INC_RATIO 200
327-#define is_generational(mrb) ((mrb)->is_generational_gc_mode)
328-#define is_major_gc(mrb) (is_generational(mrb) && (mrb)->gc_full)
329-#define is_minor_gc(mrb) (is_generational(mrb) && !(mrb)->gc_full)
367+#define is_generational(gc) ((gc)->generational)
368+#define is_major_gc(gc) (is_generational(gc) && (gc)->full)
369+#define is_minor_gc(gc) (is_generational(gc) && !(gc)->full)
330370
331371 void
332-mrb_init_heap(mrb_state *mrb)
372+mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
333373 {
334- mrb->heaps = NULL;
335- mrb->free_heaps = NULL;
336- add_heap(mrb);
337- mrb->gc_interval_ratio = DEFAULT_GC_INTERVAL_RATIO;
338- mrb->gc_step_ratio = DEFAULT_GC_STEP_RATIO;
374+#ifndef MRB_GC_FIXED_ARENA
375+ gc->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE);
376+ gc->arena_capa = MRB_GC_ARENA_SIZE;
377+#endif
378+
379+ gc->current_white_part = MRB_GC_WHITE_A;
380+ gc->heaps = NULL;
381+ gc->free_heaps = NULL;
382+ add_heap(mrb, gc);
383+ gc->gc_interval_ratio = DEFAULT_GC_INTERVAL_RATIO;
384+ gc->gc_step_ratio = DEFAULT_GC_STEP_RATIO;
339385 #ifndef MRB_GC_TURN_OFF_GENERATIONAL
340- mrb->is_generational_gc_mode = TRUE;
341- mrb->gc_full = TRUE;
386+ gc->generational = TRUE;
387+ gc->full = TRUE;
342388 #endif
343389
344390 #ifdef GC_PROFILE
@@ -349,16 +395,16 @@ mrb_init_heap(mrb_state *mrb)
349395 static void obj_free(mrb_state *mrb, struct RBasic *obj);
350396
351397 void
352-mrb_free_heap(mrb_state *mrb)
398+free_heap(mrb_state *mrb, mrb_gc *gc)
353399 {
354- struct heap_page *page = mrb->heaps;
355- struct heap_page *tmp;
400+ mrb_heap_page *page = gc->heaps;
401+ mrb_heap_page *tmp;
356402 RVALUE *p, *e;
357403
358404 while (page) {
359405 tmp = page;
360406 page = page->next;
361- for (p = tmp->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
407+ for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
362408 if (p->as.free.tt != MRB_TT_FREE)
363409 obj_free(mrb, &p->as.basic);
364410 }
@@ -366,23 +412,32 @@ mrb_free_heap(mrb_state *mrb)
366412 }
367413 }
368414
415+void
416+mrb_gc_destroy(mrb_state *mrb, mrb_gc *gc)
417+{
418+ free_heap(mrb, gc);
419+#ifndef MRB_GC_FIXED_ARENA
420+ mrb_free(mrb, gc->arena);
421+#endif
422+}
423+
369424 static void
370-gc_protect(mrb_state *mrb, struct RBasic *p)
425+gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p)
371426 {
372427 #ifdef MRB_GC_FIXED_ARENA
373- if (mrb->arena_idx >= MRB_GC_ARENA_SIZE) {
428+ if (gc->arena_idx >= MRB_GC_ARENA_SIZE) {
374429 /* arena overflow error */
375- mrb->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
376- mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error");
430+ gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
431+ mrb_raise(gc, E_RUNTIME_ERROR, "arena overflow error");
377432 }
378433 #else
379- if (mrb->arena_idx >= mrb->arena_capa) {
434+ if (gc->arena_idx >= gc->arena_capa) {
380435 /* extend arena */
381- mrb->arena_capa = (int)(mrb->arena_capa * 1.5);
382- mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*mrb->arena_capa);
436+ gc->arena_capa = (int)(gc->arena_capa * 1.5);
437+ gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*gc->arena_capa);
383438 }
384439 #endif
385- mrb->arena[mrb->arena_idx++] = p;
440+ gc->arena[gc->arena_idx++] = p;
386441 }
387442
388443 /* mrb_gc_protect() leaves the object in the arena */
@@ -390,7 +445,7 @@ MRB_API void
390445 mrb_gc_protect(mrb_state *mrb, mrb_value obj)
391446 {
392447 if (mrb_immediate_p(obj)) return;
393- gc_protect(mrb, mrb_basic_ptr(obj));
448+ gc_protect(mrb, &mrb->gc, mrb_basic_ptr(obj));
394449 }
395450
396451 #define GC_ROOT_NAME "_gc_root_"
@@ -445,34 +500,35 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
445500 {
446501 struct RBasic *p;
447502 static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } };
503+ mrb_gc *gc = &mrb->gc;
448504
449505 #ifdef MRB_GC_STRESS
450506 mrb_full_gc(mrb);
451507 #endif
452- if (mrb->gc_threshold < mrb->live) {
508+ if (gc->gc_threshold < gc->live) {
453509 mrb_incremental_gc(mrb);
454510 }
455- if (mrb->free_heaps == NULL) {
456- add_heap(mrb);
511+ if (gc->free_heaps == NULL) {
512+ add_heap(mrb, gc);
457513 }
458514
459- p = mrb->free_heaps->freelist;
460- mrb->free_heaps->freelist = ((struct free_obj*)p)->next;
461- if (mrb->free_heaps->freelist == NULL) {
462- unlink_free_heap_page(mrb, mrb->free_heaps);
515+ p = gc->free_heaps->freelist;
516+ gc->free_heaps->freelist = ((struct free_obj*)p)->next;
517+ if (gc->free_heaps->freelist == NULL) {
518+ unlink_free_heap_page(gc, gc->free_heaps);
463519 }
464520
465- mrb->live++;
466- gc_protect(mrb, p);
521+ gc->live++;
522+ gc_protect(mrb, gc, p);
467523 *(RVALUE *)p = RVALUE_zero;
468524 p->tt = ttype;
469525 p->c = cls;
470- paint_partial_white(mrb, p);
526+ paint_partial_white(gc, p);
471527 return p;
472528 }
473529
474530 static inline void
475-add_gray_list(mrb_state *mrb, struct RBasic *obj)
531+add_gray_list(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
476532 {
477533 #ifdef MRB_GC_STRESS
478534 if (obj->tt > MRB_TT_MAXDEFINE) {
@@ -480,8 +536,8 @@ add_gray_list(mrb_state *mrb, struct RBasic *obj)
480536 }
481537 #endif
482538 paint_gray(obj);
483- obj->gcnext = mrb->gray_list;
484- mrb->gray_list = obj;
539+ obj->gcnext = gc->gray_list;
540+ gc->gray_list = obj;
485541 }
486542
487543 static void
@@ -538,11 +594,11 @@ mark_context(mrb_state *mrb, struct mrb_context *c)
538594 }
539595
540596 static void
541-gc_mark_children(mrb_state *mrb, struct RBasic *obj)
597+gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
542598 {
543599 mrb_assert(is_gray(obj));
544600 paint_black(obj);
545- mrb->gray_list = obj->gcnext;
601+ gc->gray_list = obj->gcnext;
546602 mrb_gc_mark(mrb, (struct RBasic*)obj->c);
547603 switch (obj->tt) {
548604 case MRB_TT_ICLASS:
@@ -644,7 +700,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
644700 if (obj == 0) return;
645701 if (!is_white(obj)) return;
646702 mrb_assert((obj)->tt != MRB_TT_FREE);
647- add_gray_list(mrb, obj);
703+ add_gray_list(mrb, &mrb->gc, obj);
648704 }
649705
650706 static void
@@ -748,19 +804,19 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
748804 }
749805
750806 static void
751-root_scan_phase(mrb_state *mrb)
807+root_scan_phase(mrb_state *mrb, mrb_gc *gc)
752808 {
753809 size_t i, e;
754810
755- if (!is_minor_gc(mrb)) {
756- mrb->gray_list = NULL;
757- mrb->atomic_gray_list = NULL;
811+ if (!is_minor_gc(gc)) {
812+ gc->gray_list = NULL;
813+ gc->atomic_gray_list = NULL;
758814 }
759815
760816 mrb_gc_mark_gv(mrb);
761817 /* mark arena */
762- for (i=0,e=mrb->arena_idx; i<e; i++) {
763- mrb_gc_mark(mrb, mrb->arena[i]);
818+ for (i=0,e=gc->arena_idx; i<e; i++) {
819+ mrb_gc_mark(mrb, gc->arena[i]);
764820 }
765821 /* mark class hierarchy */
766822 mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class);
@@ -781,11 +837,11 @@ root_scan_phase(mrb_state *mrb)
781837 }
782838
783839 static size_t
784-gc_gray_mark(mrb_state *mrb, struct RBasic *obj)
840+gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
785841 {
786842 size_t children = 0;
787843
788- gc_mark_children(mrb, obj);
844+ gc_mark_children(mrb, gc, obj);
789845
790846 switch (obj->tt) {
791847 case MRB_TT_ICLASS:
@@ -864,68 +920,68 @@ gc_gray_mark(mrb_state *mrb, struct RBasic *obj)
864920
865921
866922 static void
867-gc_mark_gray_list(mrb_state *mrb) {
868- while (mrb->gray_list) {
869- if (is_gray(mrb->gray_list))
870- gc_mark_children(mrb, mrb->gray_list);
923+gc_mark_gray_list(mrb_state *mrb, mrb_gc *gc) {
924+ while (gc->gray_list) {
925+ if (is_gray(gc->gray_list))
926+ gc_mark_children(mrb, gc, gc->gray_list);
871927 else
872- mrb->gray_list = mrb->gray_list->gcnext;
928+ gc->gray_list = gc->gray_list->gcnext;
873929 }
874930 }
875931
876932
877933 static size_t
878-incremental_marking_phase(mrb_state *mrb, size_t limit)
934+incremental_marking_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
879935 {
880936 size_t tried_marks = 0;
881937
882- while (mrb->gray_list && tried_marks < limit) {
883- tried_marks += gc_gray_mark(mrb, mrb->gray_list);
938+ while (gc->gray_list && tried_marks < limit) {
939+ tried_marks += gc_gray_mark(mrb, gc, gc->gray_list);
884940 }
885941
886942 return tried_marks;
887943 }
888944
889945 static void
890-final_marking_phase(mrb_state *mrb)
946+final_marking_phase(mrb_state *mrb, mrb_gc *gc)
891947 {
892948 mark_context_stack(mrb, mrb->root_c);
893- gc_mark_gray_list(mrb);
894- mrb_assert(mrb->gray_list == NULL);
895- mrb->gray_list = mrb->atomic_gray_list;
896- mrb->atomic_gray_list = NULL;
897- gc_mark_gray_list(mrb);
898- mrb_assert(mrb->gray_list == NULL);
949+ gc_mark_gray_list(mrb, gc);
950+ mrb_assert(gc->gray_list == NULL);
951+ gc->gray_list = gc->atomic_gray_list;
952+ gc->atomic_gray_list = NULL;
953+ gc_mark_gray_list(mrb, gc);
954+ mrb_assert(gc->gray_list == NULL);
899955 }
900956
901957 static void
902-prepare_incremental_sweep(mrb_state *mrb)
958+prepare_incremental_sweep(mrb_state *mrb, mrb_gc *gc)
903959 {
904- mrb->gc_state = GC_STATE_SWEEP;
905- mrb->sweeps = mrb->heaps;
906- mrb->gc_live_after_mark = mrb->live;
960+ gc->gc_state = GC_STATE_SWEEP;
961+ gc->sweeps = gc->heaps;
962+ gc->gc_live_after_mark = gc->live;
907963 }
908964
909965 static size_t
910-incremental_sweep_phase(mrb_state *mrb, size_t limit)
966+incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
911967 {
912- struct heap_page *page = mrb->sweeps;
968+ mrb_heap_page *page = gc->sweeps;
913969 size_t tried_sweep = 0;
914970
915971 while (page && (tried_sweep < limit)) {
916- RVALUE *p = page->objects;
972+ RVALUE *p = objects(page);
917973 RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
918974 size_t freed = 0;
919975 mrb_bool dead_slot = TRUE;
920976 mrb_bool full = (page->freelist == NULL);
921977
922- if (is_minor_gc(mrb) && page->old) {
978+ if (is_minor_gc(gc) && page->old) {
923979 /* skip a slot which doesn't contain any young object */
924980 p = e;
925981 dead_slot = FALSE;
926982 }
927983 while (p<e) {
928- if (is_dead(mrb, &p->as.basic)) {
984+ if (is_dead(gc, &p->as.basic)) {
929985 if (p->as.basic.tt != MRB_TT_FREE) {
930986 obj_free(mrb, &p->as.basic);
931987 p->as.free.next = page->freelist;
@@ -934,8 +990,8 @@ incremental_sweep_phase(mrb_state *mrb, size_t limit)
934990 }
935991 }
936992 else {
937- if (!is_generational(mrb))
938- paint_partial_white(mrb, &p->as.basic); /* next gc target */
993+ if (!is_generational(gc))
994+ paint_partial_white(gc, &p->as.basic); /* next gc target */
939995 dead_slot = 0;
940996 }
941997 p++;
@@ -943,54 +999,54 @@ incremental_sweep_phase(mrb_state *mrb, size_t limit)
943999
9441000 /* free dead slot */
9451001 if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) {
946- struct heap_page *next = page->next;
1002+ mrb_heap_page *next = page->next;
9471003
948- unlink_heap_page(mrb, page);
949- unlink_free_heap_page(mrb, page);
1004+ unlink_heap_page(gc, page);
1005+ unlink_free_heap_page(gc, page);
9501006 mrb_free(mrb, page);
9511007 page = next;
9521008 }
9531009 else {
9541010 if (full && freed > 0) {
955- link_free_heap_page(mrb, page);
1011+ link_free_heap_page(gc, page);
9561012 }
957- if (page->freelist == NULL && is_minor_gc(mrb))
1013+ if (page->freelist == NULL && is_minor_gc(gc))
9581014 page->old = TRUE;
9591015 else
9601016 page->old = FALSE;
9611017 page = page->next;
9621018 }
9631019 tried_sweep += MRB_HEAP_PAGE_SIZE;
964- mrb->live -= freed;
965- mrb->gc_live_after_mark -= freed;
1020+ gc->live -= freed;
1021+ gc->gc_live_after_mark -= freed;
9661022 }
967- mrb->sweeps = page;
1023+ gc->sweeps = page;
9681024 return tried_sweep;
9691025 }
9701026
9711027 static size_t
972-incremental_gc(mrb_state *mrb, size_t limit)
1028+incremental_gc(mrb_state *mrb, mrb_gc *gc, size_t limit)
9731029 {
974- switch (mrb->gc_state) {
1030+ switch (gc->gc_state) {
9751031 case GC_STATE_ROOT:
976- root_scan_phase(mrb);
977- mrb->gc_state = GC_STATE_MARK;
978- flip_white_part(mrb);
1032+ root_scan_phase(mrb, gc);
1033+ gc->gc_state = GC_STATE_MARK;
1034+ flip_white_part(gc);
9791035 return 0;
9801036 case GC_STATE_MARK:
981- if (mrb->gray_list) {
982- return incremental_marking_phase(mrb, limit);
1037+ if (gc->gray_list) {
1038+ return incremental_marking_phase(mrb, gc, limit);
9831039 }
9841040 else {
985- final_marking_phase(mrb);
986- prepare_incremental_sweep(mrb);
1041+ final_marking_phase(mrb, gc);
1042+ prepare_incremental_sweep(mrb, gc);
9871043 return 0;
9881044 }
9891045 case GC_STATE_SWEEP: {
9901046 size_t tried_sweep = 0;
991- tried_sweep = incremental_sweep_phase(mrb, limit);
1047+ tried_sweep = incremental_sweep_phase(mrb, gc, limit);
9921048 if (tried_sweep == 0)
993- mrb->gc_state = GC_STATE_ROOT;
1049+ gc->gc_state = GC_STATE_ROOT;
9941050 return tried_sweep;
9951051 }
9961052 default:
@@ -1001,79 +1057,81 @@ incremental_gc(mrb_state *mrb, size_t limit)
10011057 }
10021058
10031059 static void
1004-incremental_gc_until(mrb_state *mrb, enum gc_state to_state)
1060+incremental_gc_until(mrb_state *mrb, mrb_gc *gc, mrb_gc_state to_state)
10051061 {
10061062 do {
1007- incremental_gc(mrb, SIZE_MAX);
1008- } while (mrb->gc_state != to_state);
1063+ incremental_gc(mrb, gc, SIZE_MAX);
1064+ } while (gc->gc_state != to_state);
10091065 }
10101066
10111067 static void
1012-incremental_gc_step(mrb_state *mrb)
1068+incremental_gc_step(mrb_state *mrb, mrb_gc *gc)
10131069 {
10141070 size_t limit = 0, result = 0;
1015- limit = (GC_STEP_SIZE/100) * mrb->gc_step_ratio;
1071+ limit = (GC_STEP_SIZE/100) * gc->gc_step_ratio;
10161072 while (result < limit) {
1017- result += incremental_gc(mrb, limit);
1018- if (mrb->gc_state == GC_STATE_ROOT)
1073+ result += incremental_gc(mrb, gc, limit);
1074+ if (gc->gc_state == GC_STATE_ROOT)
10191075 break;
10201076 }
10211077
1022- mrb->gc_threshold = mrb->live + GC_STEP_SIZE;
1078+ gc->gc_threshold = gc->live + GC_STEP_SIZE;
10231079 }
10241080
10251081 static void
1026-clear_all_old(mrb_state *mrb)
1082+clear_all_old(mrb_state *mrb, mrb_gc *gc)
10271083 {
1028- mrb_bool origin_mode = mrb->is_generational_gc_mode;
1084+ mrb_bool origin_mode = gc->generational;
10291085
1030- mrb_assert(is_generational(mrb));
1031- if (is_major_gc(mrb)) {
1086+ mrb_assert(is_generational(gc));
1087+ if (is_major_gc(gc)) {
10321088 /* finish the half baked GC */
1033- incremental_gc_until(mrb, GC_STATE_ROOT);
1089+ incremental_gc_until(mrb, gc, GC_STATE_ROOT);
10341090 }
10351091
10361092 /* Sweep the dead objects, then reset all the live objects
10371093 * (including all the old objects, of course) to white. */
1038- mrb->is_generational_gc_mode = FALSE;
1039- prepare_incremental_sweep(mrb);
1040- incremental_gc_until(mrb, GC_STATE_ROOT);
1041- mrb->is_generational_gc_mode = origin_mode;
1094+ gc->generational = FALSE;
1095+ prepare_incremental_sweep(mrb, gc);
1096+ incremental_gc_until(mrb, gc, GC_STATE_ROOT);
1097+ gc->generational = origin_mode;
10421098
10431099 /* The gray objects have already been painted as white */
1044- mrb->atomic_gray_list = mrb->gray_list = NULL;
1100+ gc->atomic_gray_list = gc->gray_list = NULL;
10451101 }
10461102
10471103 MRB_API void
10481104 mrb_incremental_gc(mrb_state *mrb)
10491105 {
1050- if (mrb->gc_disabled) return;
1106+ mrb_gc *gc = &mrb->gc;
1107+
1108+ if (gc->disabled) return;
10511109
10521110 GC_INVOKE_TIME_REPORT("mrb_incremental_gc()");
10531111 GC_TIME_START;
10541112
1055- if (is_minor_gc(mrb)) {
1056- incremental_gc_until(mrb, GC_STATE_ROOT);
1113+ if (is_minor_gc(gc)) {
1114+ incremental_gc_until(mrb, gc, GC_STATE_ROOT);
10571115 }
10581116 else {
1059- incremental_gc_step(mrb);
1117+ incremental_gc_step(mrb, gc);
10601118 }
10611119
1062- if (mrb->gc_state == GC_STATE_ROOT) {
1063- mrb_assert(mrb->live >= mrb->gc_live_after_mark);
1064- mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
1065- if (mrb->gc_threshold < GC_STEP_SIZE) {
1066- mrb->gc_threshold = GC_STEP_SIZE;
1120+ if (gc->gc_state == GC_STATE_ROOT) {
1121+ mrb_assert(gc->live >= gc->gc_live_after_mark);
1122+ gc->gc_threshold = (gc->gc_live_after_mark/100) * gc->gc_interval_ratio;
1123+ if (gc->gc_threshold < GC_STEP_SIZE) {
1124+ gc->gc_threshold = GC_STEP_SIZE;
10671125 }
10681126
1069- if (is_major_gc(mrb)) {
1070- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
1071- mrb->gc_full = FALSE;
1127+ if (is_major_gc(gc)) {
1128+ gc->majorgc_old_threshold = gc->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
1129+ gc->full = FALSE;
10721130 }
1073- else if (is_minor_gc(mrb)) {
1074- if (mrb->live > mrb->majorgc_old_threshold) {
1075- clear_all_old(mrb);
1076- mrb->gc_full = TRUE;
1131+ else if (is_minor_gc(gc)) {
1132+ if (gc->live > gc->majorgc_old_threshold) {
1133+ clear_all_old(mrb, gc);
1134+ gc->full = TRUE;
10771135 }
10781136 }
10791137 }
@@ -1085,26 +1143,29 @@ mrb_incremental_gc(mrb_state *mrb)
10851143 MRB_API void
10861144 mrb_full_gc(mrb_state *mrb)
10871145 {
1088- if (mrb->gc_disabled) return;
1146+ mrb_gc *gc = &mrb->gc;
1147+
1148+ if (gc->disabled) return;
1149+
10891150 GC_INVOKE_TIME_REPORT("mrb_full_gc()");
10901151 GC_TIME_START;
10911152
1092- if (is_generational(mrb)) {
1153+ if (is_generational(gc)) {
10931154 /* clear all the old objects back to young */
1094- clear_all_old(mrb);
1095- mrb->gc_full = TRUE;
1155+ clear_all_old(mrb, gc);
1156+ gc->full = TRUE;
10961157 }
1097- else if (mrb->gc_state != GC_STATE_ROOT) {
1158+ else if (gc->gc_state != GC_STATE_ROOT) {
10981159 /* finish half baked GC cycle */
1099- incremental_gc_until(mrb, GC_STATE_ROOT);
1160+ incremental_gc_until(mrb, gc, GC_STATE_ROOT);
11001161 }
11011162
1102- incremental_gc_until(mrb, GC_STATE_ROOT);
1103- mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
1163+ incremental_gc_until(mrb, gc, GC_STATE_ROOT);
1164+ gc->gc_threshold = (gc->gc_live_after_mark/100) * gc->gc_interval_ratio;
11041165
1105- if (is_generational(mrb)) {
1106- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
1107- mrb->gc_full = FALSE;
1166+ if (is_generational(gc)) {
1167+ gc->majorgc_old_threshold = gc->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
1168+ gc->full = FALSE;
11081169 }
11091170
11101171 GC_TIME_STOP_AND_REPORT;
@@ -1119,27 +1180,29 @@ mrb_garbage_collect(mrb_state *mrb)
11191180 MRB_API int
11201181 mrb_gc_arena_save(mrb_state *mrb)
11211182 {
1122- return mrb->arena_idx;
1183+ return mrb->gc.arena_idx;
11231184 }
11241185
11251186 MRB_API void
11261187 mrb_gc_arena_restore(mrb_state *mrb, int idx)
11271188 {
1189+ mrb_gc *gc = &mrb->gc;
1190+
11281191 #ifndef MRB_GC_FIXED_ARENA
1129- int capa = mrb->arena_capa;
1192+ int capa = gc->arena_capa;
11301193
11311194 if (idx < capa / 2) {
11321195 capa = (int)(capa * 0.66);
11331196 if (capa < MRB_GC_ARENA_SIZE) {
11341197 capa = MRB_GC_ARENA_SIZE;
11351198 }
1136- if (capa != mrb->arena_capa) {
1137- mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*capa);
1138- mrb->arena_capa = capa;
1199+ if (capa != gc->arena_capa) {
1200+ gc->arena = (struct RBasic**)mrb_realloc(mrb, gc->arena, sizeof(struct RBasic*)*capa);
1201+ gc->arena_capa = capa;
11391202 }
11401203 }
11411204 #endif
1142- mrb->arena_idx = idx;
1205+ gc->arena_idx = idx;
11431206 }
11441207
11451208 /*
@@ -1150,18 +1213,20 @@ mrb_gc_arena_restore(mrb_state *mrb, int idx)
11501213 MRB_API void
11511214 mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value)
11521215 {
1216+ mrb_gc *gc = &mrb->gc;
1217+
11531218 if (!is_black(obj)) return;
11541219 if (!is_white(value)) return;
11551220
1156- mrb_assert(!is_dead(mrb, value) && !is_dead(mrb, obj));
1157- mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_ROOT);
1221+ mrb_assert(!is_dead(gc, value) && !is_dead(gc, obj));
1222+ mrb_assert(is_generational(gc) || mrb->gc.gc_state != GC_STATE_ROOT);
11581223
1159- if (is_generational(mrb) || mrb->gc_state == GC_STATE_MARK) {
1160- add_gray_list(mrb, value);
1224+ if (is_generational(gc) || mrb->gc.gc_state == GC_STATE_MARK) {
1225+ add_gray_list(mrb, gc, value);
11611226 }
11621227 else {
1163- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
1164- paint_partial_white(mrb, obj); /* for never write barriers */
1228+ mrb_assert(mrb->gc.gc_state == GC_STATE_SWEEP);
1229+ paint_partial_white(gc, obj); /* for never write barriers */
11651230 }
11661231 }
11671232
@@ -1177,13 +1242,15 @@ mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value
11771242 MRB_API void
11781243 mrb_write_barrier(mrb_state *mrb, struct RBasic *obj)
11791244 {
1245+ mrb_gc *gc = &mrb->gc;
1246+
11801247 if (!is_black(obj)) return;
11811248
1182- mrb_assert(!is_dead(mrb, obj));
1183- mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_ROOT);
1249+ mrb_assert(!is_dead(gc, obj));
1250+ mrb_assert(is_generational(gc) || gc->gc_state != GC_STATE_ROOT);
11841251 paint_gray(obj);
1185- obj->gcnext = mrb->atomic_gray_list;
1186- mrb->atomic_gray_list = obj;
1252+ obj->gcnext = gc->atomic_gray_list;
1253+ gc->atomic_gray_list = obj;
11871254 }
11881255
11891256 /*
@@ -1217,9 +1284,9 @@ gc_start(mrb_state *mrb, mrb_value obj)
12171284 static mrb_value
12181285 gc_enable(mrb_state *mrb, mrb_value obj)
12191286 {
1220- mrb_bool old = mrb->gc_disabled;
1287+ mrb_bool old = mrb->gc.disabled;
12211288
1222- mrb->gc_disabled = FALSE;
1289+ mrb->gc.disabled = FALSE;
12231290
12241291 return mrb_bool_value(old);
12251292 }
@@ -1239,9 +1306,9 @@ gc_enable(mrb_state *mrb, mrb_value obj)
12391306 static mrb_value
12401307 gc_disable(mrb_state *mrb, mrb_value obj)
12411308 {
1242- mrb_bool old = mrb->gc_disabled;
1309+ mrb_bool old = mrb->gc.disabled;
12431310
1244- mrb->gc_disabled = TRUE;
1311+ mrb->gc.disabled = TRUE;
12451312
12461313 return mrb_bool_value(old);
12471314 }
@@ -1257,7 +1324,7 @@ gc_disable(mrb_state *mrb, mrb_value obj)
12571324 static mrb_value
12581325 gc_interval_ratio_get(mrb_state *mrb, mrb_value obj)
12591326 {
1260- return mrb_fixnum_value(mrb->gc_interval_ratio);
1327+ return mrb_fixnum_value(mrb->gc.gc_interval_ratio);
12611328 }
12621329
12631330 /*
@@ -1275,7 +1342,7 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
12751342 mrb_int ratio;
12761343
12771344 mrb_get_args(mrb, "i", &ratio);
1278- mrb->gc_interval_ratio = ratio;
1345+ mrb->gc.gc_interval_ratio = ratio;
12791346 return mrb_nil_value();
12801347 }
12811348
@@ -1290,7 +1357,7 @@ gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
12901357 static mrb_value
12911358 gc_step_ratio_get(mrb_state *mrb, mrb_value obj)
12921359 {
1293- return mrb_fixnum_value(mrb->gc_step_ratio);
1360+ return mrb_fixnum_value(mrb->gc.gc_step_ratio);
12941361 }
12951362
12961363 /*
@@ -1308,24 +1375,24 @@ gc_step_ratio_set(mrb_state *mrb, mrb_value obj)
13081375 mrb_int ratio;
13091376
13101377 mrb_get_args(mrb, "i", &ratio);
1311- mrb->gc_step_ratio = ratio;
1378+ mrb->gc.gc_step_ratio = ratio;
13121379 return mrb_nil_value();
13131380 }
13141381
13151382 static void
1316-change_gen_gc_mode(mrb_state *mrb, mrb_bool enable)
1383+change_gen_gc_mode(mrb_state *mrb, mrb_gc *gc, mrb_bool enable)
13171384 {
1318- if (is_generational(mrb) && !enable) {
1319- clear_all_old(mrb);
1320- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
1321- mrb->gc_full = FALSE;
1385+ if (is_generational(gc) && !enable) {
1386+ clear_all_old(mrb, gc);
1387+ mrb_assert(gc->gc_state == GC_STATE_ROOT);
1388+ gc->full = FALSE;
13221389 }
1323- else if (!is_generational(mrb) && enable) {
1324- incremental_gc_until(mrb, GC_STATE_ROOT);
1325- mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
1326- mrb->gc_full = FALSE;
1390+ else if (!is_generational(gc) && enable) {
1391+ incremental_gc_until(mrb, gc, GC_STATE_ROOT);
1392+ gc->majorgc_old_threshold = gc->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
1393+ gc->full = FALSE;
13271394 }
1328- mrb->is_generational_gc_mode = enable;
1395+ gc->generational = enable;
13291396 }
13301397
13311398 /*
@@ -1339,7 +1406,7 @@ change_gen_gc_mode(mrb_state *mrb, mrb_bool enable)
13391406 static mrb_value
13401407 gc_generational_mode_get(mrb_state *mrb, mrb_value self)
13411408 {
1342- return mrb_bool_value(mrb->is_generational_gc_mode);
1409+ return mrb_bool_value(mrb->gc.generational);
13431410 }
13441411
13451412 /*
@@ -1356,21 +1423,22 @@ gc_generational_mode_set(mrb_state *mrb, mrb_value self)
13561423 mrb_bool enable;
13571424
13581425 mrb_get_args(mrb, "b", &enable);
1359- if (mrb->is_generational_gc_mode != enable)
1360- change_gen_gc_mode(mrb, enable);
1426+ if (mrb->gc.generational != enable)
1427+ change_gen_gc_mode(mrb, &mrb->gc, enable);
13611428
13621429 return mrb_bool_value(enable);
13631430 }
13641431
1365-void
1366-mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
1432+
1433+static void
1434+gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void *data)
13671435 {
1368- struct heap_page* page = mrb->heaps;
1436+ mrb_heap_page* page = gc->heaps;
13691437
13701438 while (page != NULL) {
13711439 RVALUE *p, *pend;
13721440
1373- p = page->objects;
1441+ p = objects(page);
13741442 pend = p + MRB_HEAP_PAGE_SIZE;
13751443 for (;p < pend; p++) {
13761444 (*callback)(mrb, &p->as.basic, data);
@@ -1380,6 +1448,12 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo
13801448 }
13811449 }
13821450
1451+void
1452+mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
1453+{
1454+ return gc_each_objects(mrb, &mrb->gc, callback, data);
1455+}
1456+
13831457 #ifdef GC_TEST
13841458 #ifdef GC_DEBUG
13851459 static mrb_value gc_test(mrb_state *, mrb_value);
@@ -1416,9 +1490,10 @@ test_mrb_field_write_barrier(void)
14161490 {
14171491 mrb_state *mrb = mrb_open();
14181492 struct RBasic *obj, *value;
1493+ mrb_gc *gc = &mrb->gc;
14191494
14201495 puts("test_mrb_field_write_barrier");
1421- mrb->is_generational_gc_mode = FALSE;
1496+ gc->generational = FALSE;
14221497 obj = mrb_basic_ptr(mrb_ary_new(mrb));
14231498 value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value"));
14241499 paint_black(obj);
@@ -1426,7 +1501,7 @@ test_mrb_field_write_barrier(void)
14261501
14271502
14281503 puts(" in GC_STATE_MARK");
1429- mrb->gc_state = GC_STATE_MARK;
1504+ gc->gc_state = GC_STATE_MARK;
14301505 mrb_field_write_barrier(mrb, obj, value);
14311506
14321507 mrb_assert(is_gray(value));
@@ -1434,24 +1509,24 @@ test_mrb_field_write_barrier(void)
14341509
14351510 puts(" in GC_STATE_SWEEP");
14361511 paint_partial_white(mrb, value);
1437- mrb->gc_state = GC_STATE_SWEEP;
1512+ gc->gc_state = GC_STATE_SWEEP;
14381513 mrb_field_write_barrier(mrb, obj, value);
14391514
1440- mrb_assert(obj->color & mrb->current_white_part);
1441- mrb_assert(value->color & mrb->current_white_part);
1515+ mrb_assert(obj->color & gc->current_white_part);
1516+ mrb_assert(value->color & gc->current_white_part);
14421517
14431518
14441519 puts(" fail with black");
1445- mrb->gc_state = GC_STATE_MARK;
1520+ gc->gc_state = GC_STATE_MARK;
14461521 paint_white(obj);
14471522 paint_partial_white(mrb, value);
14481523 mrb_field_write_barrier(mrb, obj, value);
14491524
1450- mrb_assert(obj->color & mrb->current_white_part);
1525+ mrb_assert(obj->color & gc->current_white_part);
14511526
14521527
14531528 puts(" fail with gray");
1454- mrb->gc_state = GC_STATE_MARK;
1529+ gc->gc_state = GC_STATE_MARK;
14551530 paint_black(obj);
14561531 paint_gray(value);
14571532 mrb_field_write_barrier(mrb, obj, value);
@@ -1466,7 +1541,7 @@ test_mrb_field_write_barrier(void)
14661541 paint_black(obj);
14671542 paint_partial_white(mrb, mrb_basic_ptr(value));
14681543
1469- mrb->gc_state = GC_STATE_MARK;
1544+ gc->gc_state = GC_STATE_MARK;
14701545 mrb_field_write_barrier_value(mrb, obj, value);
14711546
14721547 mrb_assert(is_gray(mrb_basic_ptr(value)));
@@ -1480,17 +1555,18 @@ test_mrb_write_barrier(void)
14801555 {
14811556 mrb_state *mrb = mrb_open();
14821557 struct RBasic *obj;
1558+ mrb_gc *gc = &mrb->gc;
14831559
14841560 puts("test_mrb_write_barrier");
14851561 obj = mrb_basic_ptr(mrb_ary_new(mrb));
14861562 paint_black(obj);
14871563
14881564 puts(" in GC_STATE_MARK");
1489- mrb->gc_state = GC_STATE_MARK;
1565+ gc->gc_state = GC_STATE_MARK;
14901566 mrb_write_barrier(mrb, obj);
14911567
14921568 mrb_assert(is_gray(obj));
1493- mrb_assert(mrb->atomic_gray_list == obj);
1569+ mrb_assert(gc->atomic_gray_list == obj);
14941570
14951571
14961572 puts(" fail with gray");
@@ -1507,19 +1583,20 @@ test_add_gray_list(void)
15071583 {
15081584 mrb_state *mrb = mrb_open();
15091585 struct RBasic *obj1, *obj2;
1586+ mrb_gc *gc = &mrb->gc;
15101587
15111588 puts("test_add_gray_list");
15121589 change_gen_gc_mode(mrb, FALSE);
1513- mrb_assert(mrb->gray_list == NULL);
1590+ mrb_assert(gc->gray_list == NULL);
15141591 obj1 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
15151592 add_gray_list(mrb, obj1);
1516- mrb_assert(mrb->gray_list == obj1);
1593+ mrb_assert(gc->gray_list == obj1);
15171594 mrb_assert(is_gray(obj1));
15181595
15191596 obj2 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
15201597 add_gray_list(mrb, obj2);
1521- mrb_assert(mrb->gray_list == obj2);
1522- mrb_assert(mrb->gray_list->gcnext == obj1);
1598+ mrb_assert(gc->gray_list == obj2);
1599+ mrb_assert(gc->gray_list->gcnext == obj1);
15231600 mrb_assert(is_gray(obj2));
15241601
15251602 mrb_close(mrb);
@@ -1532,6 +1609,7 @@ test_gc_gray_mark(void)
15321609 mrb_value obj_v, value_v;
15331610 struct RBasic *obj;
15341611 size_t gray_num = 0;
1612+ mrb_gc *gc = &mrb->gc;
15351613
15361614 puts("test_gc_gray_mark");
15371615
@@ -1562,7 +1640,8 @@ test_incremental_gc(void)
15621640 mrb_state *mrb = mrb_open();
15631641 size_t max = ~0, live = 0, total = 0, freed = 0;
15641642 RVALUE *free;
1565- struct heap_page *page;
1643+ mrb_heap_page *page;
1644+ mrb_gc *gc = &mrb->gc;
15661645
15671646 puts("test_incremental_gc");
15681647 change_gen_gc_mode(mrb, FALSE);
@@ -1570,18 +1649,18 @@ test_incremental_gc(void)
15701649 puts(" in mrb_full_gc");
15711650 mrb_full_gc(mrb);
15721651
1573- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
1652+ mrb_assert(gc->gc_state == GC_STATE_ROOT);
15741653 puts(" in GC_STATE_ROOT");
15751654 incremental_gc(mrb, max);
1576- mrb_assert(mrb->gc_state == GC_STATE_MARK);
1655+ mrb_assert(gc->gc_state == GC_STATE_MARK);
15771656 puts(" in GC_STATE_MARK");
15781657 incremental_gc_until(mrb, GC_STATE_SWEEP);
1579- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
1658+ mrb_assert(gc->gc_state == GC_STATE_SWEEP);
15801659
15811660 puts(" in GC_STATE_SWEEP");
1582- page = mrb->heaps;
1661+ page = gc->heaps;
15831662 while (page) {
1584- RVALUE *p = page->objects;
1663+ RVALUE *p = objects(page);
15851664 RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
15861665 while (p<e) {
15871666 if (is_black(&p->as.basic)) {
@@ -1596,44 +1675,44 @@ test_incremental_gc(void)
15961675 total += MRB_HEAP_PAGE_SIZE;
15971676 }
15981677
1599- mrb_assert(mrb->gray_list == NULL);
1678+ mrb_assert(gc->gray_list == NULL);
16001679
16011680 incremental_gc(mrb, max);
1602- mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
1681+ mrb_assert(gc->gc_state == GC_STATE_SWEEP);
16031682
16041683 incremental_gc(mrb, max);
1605- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
1684+ mrb_assert(gc->gc_state == GC_STATE_ROOT);
16061685
1607- free = (RVALUE*)mrb->heaps->freelist;
1686+ free = (RVALUE*)gc->heaps->freelist;
16081687 while (free) {
16091688 freed++;
16101689 free = (RVALUE*)free->as.free.next;
16111690 }
16121691
1613- mrb_assert(mrb->live == live);
1614- mrb_assert(mrb->live == total-freed);
1692+ mrb_assert(gc->live == live);
1693+ mrb_assert(gc->live == total-freed);
16151694
16161695 puts("test_incremental_gc(gen)");
16171696 incremental_gc_until(mrb, GC_STATE_SWEEP);
16181697 change_gen_gc_mode(mrb, TRUE);
16191698
1620- mrb_assert(mrb->gc_full == FALSE);
1621- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
1699+ mrb_assert(gc->full == FALSE);
1700+ mrb_assert(gc->gc_state == GC_STATE_ROOT);
16221701
16231702 puts(" in minor");
16241703 mrb_assert(is_minor_gc(mrb));
1625- mrb_assert(mrb->majorgc_old_threshold > 0);
1626- mrb->majorgc_old_threshold = 0;
1704+ mrb_assert(gc->majorgc_old_threshold > 0);
1705+ gc->majorgc_old_threshold = 0;
16271706 mrb_incremental_gc(mrb);
1628- mrb_assert(mrb->gc_full == TRUE);
1629- mrb_assert(mrb->gc_state == GC_STATE_ROOT);
1707+ mrb_assert(gc->full == TRUE);
1708+ mrb_assert(gc->gc_state == GC_STATE_ROOT);
16301709
16311710 puts(" in major");
16321711 mrb_assert(is_major_gc(mrb));
16331712 do {
16341713 mrb_incremental_gc(mrb);
1635- } while (mrb->gc_state != GC_STATE_ROOT);
1636- mrb_assert(mrb->gc_full == FALSE);
1714+ } while (gc->gc_state != GC_STATE_ROOT);
1715+ mrb_assert(gc->full == FALSE);
16371716
16381717 mrb_close(mrb);
16391718 }
@@ -1642,18 +1721,19 @@ void
16421721 test_incremental_sweep_phase(void)
16431722 {
16441723 mrb_state *mrb = mrb_open();
1724+ mrb_gc *gc = &mrb->gc;
16451725
16461726 puts("test_incremental_sweep_phase");
16471727
16481728 add_heap(mrb);
1649- mrb->sweeps = mrb->heaps;
1729+ gc->sweeps = gc->heaps;
16501730
1651- mrb_assert(mrb->heaps->next->next == NULL);
1652- mrb_assert(mrb->free_heaps->next->next == NULL);
1731+ mrb_assert(gc->heaps->next->next == NULL);
1732+ mrb_assert(gc->free_heaps->next->next == NULL);
16531733 incremental_sweep_phase(mrb, MRB_HEAP_PAGE_SIZE*3);
16541734
1655- mrb_assert(mrb->heaps->next == NULL);
1656- mrb_assert(mrb->heaps == mrb->free_heaps);
1735+ mrb_assert(gc->heaps->next == NULL);
1736+ mrb_assert(gc->heaps == gc->free_heaps);
16571737
16581738 mrb_close(mrb);
16591739 }
--- a/src/state.c
+++ b/src/state.c
@@ -12,10 +12,12 @@
1212 #include "mruby/debug.h"
1313 #include "mruby/string.h"
1414
15-void mrb_init_heap(mrb_state*);
1615 void mrb_init_core(mrb_state*);
1716 void mrb_init_mrbgems(mrb_state*);
1817
18+void mrb_gc_init(mrb_state*, mrb_gc *gc);
19+void mrb_gc_destroy(mrb_state*, mrb_gc *gc);
20+
1921 static mrb_value
2022 inspect_main(mrb_state *mrb, mrb_value mod)
2123 {
@@ -35,15 +37,9 @@ mrb_open_core(mrb_allocf f, void *ud)
3537 *mrb = mrb_state_zero;
3638 mrb->allocf_ud = ud;
3739 mrb->allocf = f;
38- mrb->current_white_part = MRB_GC_WHITE_A;
3940 mrb->atexit_stack_len = 0;
4041
41-#ifndef MRB_GC_FIXED_ARENA
42- mrb->arena = (struct RBasic**)mrb_malloc(mrb, sizeof(struct RBasic*)*MRB_GC_ARENA_SIZE);
43- mrb->arena_capa = MRB_GC_ARENA_SIZE;
44-#endif
45-
46- mrb_init_heap(mrb);
42+ mrb_gc_init(mrb, &mrb->gc);
4743 mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
4844 *mrb->c = mrb_context_zero;
4945 mrb->root_c = mrb->c;
@@ -122,7 +118,6 @@ mrb_open_allocf(mrb_allocf f, void *ud)
122118 }
123119
124120 void mrb_free_symtbl(mrb_state *mrb);
125-void mrb_free_heap(mrb_state *mrb);
126121
127122 void
128123 mrb_irep_incref(mrb_state *mrb, mrb_irep *irep)
@@ -249,11 +244,8 @@ mrb_close(mrb_state *mrb)
249244 mrb_gc_free_gv(mrb);
250245 mrb_free_context(mrb, mrb->root_c);
251246 mrb_free_symtbl(mrb);
252- mrb_free_heap(mrb);
253247 mrb_alloca_free(mrb);
254-#ifndef MRB_GC_FIXED_ARENA
255- mrb_free(mrb, mrb->arena);
256-#endif
248+ mrb_gc_destroy(mrb, &mrb->gc);
257249 mrb_free(mrb, mrb);
258250 }
259251
--- a/src/vm.c
+++ b/src/vm.c
@@ -52,7 +52,7 @@ The value below allows about 60000 recursive calls in the simplest case. */
5252 # define DEBUG(x)
5353 #endif
5454
55-#define ARENA_RESTORE(mrb,ai) (mrb)->arena_idx = (ai)
55+#define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai)
5656
5757 static inline void
5858 stack_clear(mrb_value *from, size_t count)