mbed I/F binding for mruby

Dependents:   mruby_mbed_web mirb_mbed

mbed-mruby

How to use

Class

Committer:
mzta
Date:
Mon Apr 13 05:20:15 2015 +0000
Revision:
1:8ccd1d494a4b
Parent:
0:158c61bb030f
- code refactoring.; - add SPI, SPISlave, I2C class to mruby-mbed (Incomplete).

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mzta 0:158c61bb030f 1 /*
mzta 0:158c61bb030f 2 ** gc.c - garbage collector for mruby
mzta 0:158c61bb030f 3 **
mzta 0:158c61bb030f 4 ** See Copyright Notice in mruby.h
mzta 0:158c61bb030f 5 */
mzta 0:158c61bb030f 6
mzta 0:158c61bb030f 7 #include <string.h>
mzta 0:158c61bb030f 8 #include <stdlib.h>
mzta 0:158c61bb030f 9 #include "mruby.h"
mzta 0:158c61bb030f 10 #include "mruby/array.h"
mzta 0:158c61bb030f 11 #include "mruby/class.h"
mzta 0:158c61bb030f 12 #include "mruby/data.h"
mzta 0:158c61bb030f 13 #include "mruby/hash.h"
mzta 0:158c61bb030f 14 #include "mruby/proc.h"
mzta 0:158c61bb030f 15 #include "mruby/range.h"
mzta 0:158c61bb030f 16 #include "mruby/string.h"
mzta 0:158c61bb030f 17 #include "mruby/variable.h"
mzta 0:158c61bb030f 18 #include "mruby/gc.h"
mzta 0:158c61bb030f 19 #include "mruby/error.h"
mzta 0:158c61bb030f 20
mzta 0:158c61bb030f 21 /*
mzta 0:158c61bb030f 22 = Tri-color Incremental Garbage Collection
mzta 0:158c61bb030f 23
mzta 0:158c61bb030f 24 mruby's GC is Tri-color Incremental GC with Mark & Sweep.
mzta 0:158c61bb030f 25 Algorithm details are omitted.
mzta 0:158c61bb030f 26 Instead, the implementation part is described below.
mzta 0:158c61bb030f 27
mzta 0:158c61bb030f 28 == Object's Color
mzta 0:158c61bb030f 29
mzta 0:158c61bb030f 30 Each object can be painted in three colors:
mzta 0:158c61bb030f 31
mzta 0:158c61bb030f 32 * White - Unmarked.
mzta 0:158c61bb030f 33 * Gray - Marked, But the child objects are unmarked.
mzta 0:158c61bb030f 34 * Black - Marked, the child objects are also marked.
mzta 0:158c61bb030f 35
mzta 0:158c61bb030f 36 == Two White Types
mzta 0:158c61bb030f 37
mzta 0:158c61bb030f 38 There're two white color types in a flip-flop fashion: White-A and White-B,
mzta 0:158c61bb030f 39 which respectively represent the Current White color (the newly allocated
mzta 0:158c61bb030f 40 objects in the current GC cycle) and the Sweep Target White color (the
mzta 0:158c61bb030f 41 dead objects to be swept).
mzta 0:158c61bb030f 42
mzta 0:158c61bb030f 43 A and B will be switched just at the beginning of the next GC cycle. At
mzta 0:158c61bb030f 44 that time, all the dead objects have been swept, while the newly created
mzta 0:158c61bb030f 45 objects in the current GC cycle which finally remains White are now
mzta 0:158c61bb030f 46 regarded as dead objects. Instead of traversing all the White-A objects and
mzta 0:158c61bb030f 47 painting them as White-B, just switch the meaning of White-A and White-B as
mzta 0:158c61bb030f 48 this will be much cheaper.
mzta 0:158c61bb030f 49
mzta 0:158c61bb030f 50 As a result, the objects we sweep in the current GC cycle are always
mzta 0:158c61bb030f 51 left from the previous GC cycle. This allows us to sweep objects
mzta 0:158c61bb030f 52 incrementally, without the disturbance of the newly created objects.
mzta 0:158c61bb030f 53
mzta 0:158c61bb030f 54 == Execution Timing
mzta 0:158c61bb030f 55
mzta 0:158c61bb030f 56 GC Execution Time and Each step interval are decided by live objects count.
mzta 0:158c61bb030f 57 List of Adjustment API:
mzta 0:158c61bb030f 58
mzta 0:158c61bb030f 59 * gc_interval_ratio_set
mzta 0:158c61bb030f 60 * gc_step_ratio_set
mzta 0:158c61bb030f 61
mzta 0:158c61bb030f 62 For details, see the comments for each function.
mzta 0:158c61bb030f 63
mzta 0:158c61bb030f 64 == Write Barrier
mzta 0:158c61bb030f 65
mzta 0:158c61bb030f 66 mruby implementer and C extension library writer must insert a write
mzta 0:158c61bb030f 67 barrier when updating a reference from a field of an object.
mzta 0:158c61bb030f 68 When updating a reference from a field of object A to object B,
mzta 0:158c61bb030f 69 two different types of write barrier are available:
mzta 0:158c61bb030f 70
mzta 0:158c61bb030f 71 * mrb_field_write_barrier - target B object for a mark.
mzta 0:158c61bb030f 72 * mrb_write_barrier - target A object for a mark.
mzta 0:158c61bb030f 73
mzta 0:158c61bb030f 74 == Generational Mode
mzta 0:158c61bb030f 75
mzta 0:158c61bb030f 76 mruby's GC offers an Generational Mode while re-using the tri-color GC
mzta 0:158c61bb030f 77 infrastructure. It will treat the Black objects as Old objects after each
mzta 0:158c61bb030f 78 sweep phase, instead of painting them White. The key ideas are still the same
mzta 0:158c61bb030f 79 as traditional generational GC:
mzta 0:158c61bb030f 80
mzta 0:158c61bb030f 81 * Minor GC - just traverse the Young objects (Gray objects) in the mark
mzta 0:158c61bb030f 82 phase, then only sweep the newly created objects, and leave
mzta 0:158c61bb030f 83 the Old objects live.
mzta 0:158c61bb030f 84
mzta 0:158c61bb030f 85 * Major GC - same as a full regular GC cycle.
mzta 0:158c61bb030f 86
mzta 0:158c61bb030f 87 The difference from "traditional" generational GC is, that the major GC
mzta 0:158c61bb030f 88 in mruby is triggered incrementally in a tri-color manner.
mzta 0:158c61bb030f 89
mzta 0:158c61bb030f 90
mzta 0:158c61bb030f 91 For details, see the comments for each function.
mzta 0:158c61bb030f 92
mzta 0:158c61bb030f 93 */
mzta 0:158c61bb030f 94
mzta 0:158c61bb030f 95 struct free_obj {
mzta 0:158c61bb030f 96 MRB_OBJECT_HEADER;
mzta 0:158c61bb030f 97 struct RBasic *next;
mzta 0:158c61bb030f 98 };
mzta 0:158c61bb030f 99
mzta 0:158c61bb030f 100 typedef struct {
mzta 0:158c61bb030f 101 union {
mzta 0:158c61bb030f 102 struct free_obj free;
mzta 0:158c61bb030f 103 struct RBasic basic;
mzta 0:158c61bb030f 104 struct RObject object;
mzta 0:158c61bb030f 105 struct RClass klass;
mzta 0:158c61bb030f 106 struct RString string;
mzta 0:158c61bb030f 107 struct RArray array;
mzta 0:158c61bb030f 108 struct RHash hash;
mzta 0:158c61bb030f 109 struct RRange range;
mzta 0:158c61bb030f 110 struct RData data;
mzta 0:158c61bb030f 111 struct RProc proc;
mzta 0:158c61bb030f 112 struct RException exc;
mzta 0:158c61bb030f 113 #ifdef MRB_WORD_BOXING
mzta 0:158c61bb030f 114 struct RFloat floatv;
mzta 0:158c61bb030f 115 struct RCptr cptr;
mzta 0:158c61bb030f 116 #endif
mzta 0:158c61bb030f 117 } as;
mzta 0:158c61bb030f 118 } RVALUE;
mzta 0:158c61bb030f 119
mzta 0:158c61bb030f 120 #ifdef GC_PROFILE
mzta 0:158c61bb030f 121 #include <stdio.h>
mzta 0:158c61bb030f 122 #include <sys/time.h>
mzta 0:158c61bb030f 123
mzta 0:158c61bb030f 124 static double program_invoke_time = 0;
mzta 0:158c61bb030f 125 static double gc_time = 0;
mzta 0:158c61bb030f 126 static double gc_total_time = 0;
mzta 0:158c61bb030f 127
mzta 0:158c61bb030f 128 static double
mzta 0:158c61bb030f 129 gettimeofday_time(void)
mzta 0:158c61bb030f 130 {
mzta 0:158c61bb030f 131 struct timeval tv;
mzta 0:158c61bb030f 132 gettimeofday(&tv, NULL);
mzta 0:158c61bb030f 133 return tv.tv_sec + tv.tv_usec * 1e-6;
mzta 0:158c61bb030f 134 }
mzta 0:158c61bb030f 135
mzta 0:158c61bb030f 136 #define GC_INVOKE_TIME_REPORT(with) do {\
mzta 0:158c61bb030f 137 fprintf(stderr, "%s\n", with);\
mzta 0:158c61bb030f 138 fprintf(stderr, "gc_invoke: %19.3f\n", gettimeofday_time() - program_invoke_time);\
mzta 0:158c61bb030f 139 fprintf(stderr, "is_generational: %d\n", is_generational(mrb));\
mzta 0:158c61bb030f 140 fprintf(stderr, "is_major_gc: %d\n", is_major_gc(mrb));\
mzta 0:158c61bb030f 141 } while(0)
mzta 0:158c61bb030f 142
mzta 0:158c61bb030f 143 #define GC_TIME_START do {\
mzta 0:158c61bb030f 144 gc_time = gettimeofday_time();\
mzta 0:158c61bb030f 145 } while(0)
mzta 0:158c61bb030f 146
mzta 0:158c61bb030f 147 #define GC_TIME_STOP_AND_REPORT do {\
mzta 0:158c61bb030f 148 gc_time = gettimeofday_time() - gc_time;\
mzta 0:158c61bb030f 149 gc_total_time += gc_time;\
mzta 0:158c61bb030f 150 fprintf(stderr, "gc_state: %d\n", mrb->gc_state);\
mzta 0:158c61bb030f 151 fprintf(stderr, "live: %zu\n", mrb->live);\
mzta 0:158c61bb030f 152 fprintf(stderr, "majorgc_old_threshold: %zu\n", mrb->majorgc_old_threshold);\
mzta 0:158c61bb030f 153 fprintf(stderr, "gc_threshold: %zu\n", mrb->gc_threshold);\
mzta 0:158c61bb030f 154 fprintf(stderr, "gc_time: %30.20f\n", gc_time);\
mzta 0:158c61bb030f 155 fprintf(stderr, "gc_total_time: %30.20f\n\n", gc_total_time);\
mzta 0:158c61bb030f 156 } while(0)
mzta 0:158c61bb030f 157 #else
mzta 0:158c61bb030f 158 #define GC_INVOKE_TIME_REPORT(s)
mzta 0:158c61bb030f 159 #define GC_TIME_START
mzta 0:158c61bb030f 160 #define GC_TIME_STOP_AND_REPORT
mzta 0:158c61bb030f 161 #endif
mzta 0:158c61bb030f 162
mzta 0:158c61bb030f 163 #ifdef GC_DEBUG
mzta 0:158c61bb030f 164 #define DEBUG(x) (x)
mzta 0:158c61bb030f 165 #else
mzta 0:158c61bb030f 166 #define DEBUG(x)
mzta 0:158c61bb030f 167 #endif
mzta 0:158c61bb030f 168
mzta 0:158c61bb030f 169 #define GC_STEP_SIZE 1024
mzta 0:158c61bb030f 170
mzta 0:158c61bb030f 171
mzta 0:158c61bb030f 172 MRB_API void*
mzta 0:158c61bb030f 173 mrb_realloc_simple(mrb_state *mrb, void *p, size_t len)
mzta 0:158c61bb030f 174 {
mzta 0:158c61bb030f 175 void *p2;
mzta 0:158c61bb030f 176
mzta 0:158c61bb030f 177 p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
mzta 0:158c61bb030f 178 if (!p2 && len > 0 && mrb->heaps) {
mzta 0:158c61bb030f 179 mrb_full_gc(mrb);
mzta 0:158c61bb030f 180 p2 = (mrb->allocf)(mrb, p, len, mrb->allocf_ud);
mzta 0:158c61bb030f 181 }
mzta 0:158c61bb030f 182
mzta 0:158c61bb030f 183 return p2;
mzta 0:158c61bb030f 184 }
mzta 0:158c61bb030f 185
mzta 0:158c61bb030f 186
mzta 0:158c61bb030f 187 MRB_API void*
mzta 0:158c61bb030f 188 mrb_realloc(mrb_state *mrb, void *p, size_t len)
mzta 0:158c61bb030f 189 {
mzta 0:158c61bb030f 190 void *p2;
mzta 0:158c61bb030f 191
mzta 0:158c61bb030f 192 p2 = mrb_realloc_simple(mrb, p, len);
mzta 0:158c61bb030f 193 if (!p2 && len) {
mzta 0:158c61bb030f 194 if (mrb->out_of_memory) {
mzta 0:158c61bb030f 195 /* mrb_panic(mrb); */
mzta 0:158c61bb030f 196 }
mzta 0:158c61bb030f 197 else {
mzta 0:158c61bb030f 198 mrb->out_of_memory = TRUE;
mzta 0:158c61bb030f 199 mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
mzta 0:158c61bb030f 200 }
mzta 0:158c61bb030f 201 }
mzta 0:158c61bb030f 202 else {
mzta 0:158c61bb030f 203 mrb->out_of_memory = FALSE;
mzta 0:158c61bb030f 204 }
mzta 0:158c61bb030f 205
mzta 0:158c61bb030f 206 return p2;
mzta 0:158c61bb030f 207 }
mzta 0:158c61bb030f 208
mzta 0:158c61bb030f 209 MRB_API void*
mzta 0:158c61bb030f 210 mrb_malloc(mrb_state *mrb, size_t len)
mzta 0:158c61bb030f 211 {
mzta 0:158c61bb030f 212 return mrb_realloc(mrb, 0, len);
mzta 0:158c61bb030f 213 }
mzta 0:158c61bb030f 214
mzta 0:158c61bb030f 215 MRB_API void*
mzta 0:158c61bb030f 216 mrb_malloc_simple(mrb_state *mrb, size_t len)
mzta 0:158c61bb030f 217 {
mzta 0:158c61bb030f 218 return mrb_realloc_simple(mrb, 0, len);
mzta 0:158c61bb030f 219 }
mzta 0:158c61bb030f 220
mzta 0:158c61bb030f 221 MRB_API void*
mzta 0:158c61bb030f 222 mrb_calloc(mrb_state *mrb, size_t nelem, size_t len)
mzta 0:158c61bb030f 223 {
mzta 0:158c61bb030f 224 void *p;
mzta 0:158c61bb030f 225
mzta 0:158c61bb030f 226 if (nelem > 0 && len > 0 &&
mzta 0:158c61bb030f 227 nelem <= SIZE_MAX / len) {
mzta 0:158c61bb030f 228 size_t size;
mzta 0:158c61bb030f 229 size = nelem * len;
mzta 0:158c61bb030f 230 p = mrb_malloc(mrb, size);
mzta 0:158c61bb030f 231
mzta 0:158c61bb030f 232 memset(p, 0, size);
mzta 0:158c61bb030f 233 }
mzta 0:158c61bb030f 234 else {
mzta 0:158c61bb030f 235 p = NULL;
mzta 0:158c61bb030f 236 }
mzta 0:158c61bb030f 237
mzta 0:158c61bb030f 238 return p;
mzta 0:158c61bb030f 239 }
mzta 0:158c61bb030f 240
mzta 0:158c61bb030f 241 MRB_API void
mzta 0:158c61bb030f 242 mrb_free(mrb_state *mrb, void *p)
mzta 0:158c61bb030f 243 {
mzta 0:158c61bb030f 244 (mrb->allocf)(mrb, p, 0, mrb->allocf_ud);
mzta 0:158c61bb030f 245 }
mzta 0:158c61bb030f 246
mzta 0:158c61bb030f 247 #ifndef MRB_HEAP_PAGE_SIZE
mzta 0:158c61bb030f 248 #define MRB_HEAP_PAGE_SIZE 1024
mzta 0:158c61bb030f 249 #endif
mzta 0:158c61bb030f 250
mzta 0:158c61bb030f 251 struct heap_page {
mzta 0:158c61bb030f 252 struct RBasic *freelist;
mzta 0:158c61bb030f 253 struct heap_page *prev;
mzta 0:158c61bb030f 254 struct heap_page *next;
mzta 0:158c61bb030f 255 struct heap_page *free_next;
mzta 0:158c61bb030f 256 struct heap_page *free_prev;
mzta 0:158c61bb030f 257 mrb_bool old:1;
mzta 0:158c61bb030f 258 RVALUE objects[MRB_HEAP_PAGE_SIZE];
mzta 0:158c61bb030f 259 };
mzta 0:158c61bb030f 260
mzta 0:158c61bb030f 261 static void
mzta 0:158c61bb030f 262 link_heap_page(mrb_state *mrb, struct heap_page *page)
mzta 0:158c61bb030f 263 {
mzta 0:158c61bb030f 264 page->next = mrb->heaps;
mzta 0:158c61bb030f 265 if (mrb->heaps)
mzta 0:158c61bb030f 266 mrb->heaps->prev = page;
mzta 0:158c61bb030f 267 mrb->heaps = page;
mzta 0:158c61bb030f 268 }
mzta 0:158c61bb030f 269
mzta 0:158c61bb030f 270 static void
mzta 0:158c61bb030f 271 unlink_heap_page(mrb_state *mrb, struct heap_page *page)
mzta 0:158c61bb030f 272 {
mzta 0:158c61bb030f 273 if (page->prev)
mzta 0:158c61bb030f 274 page->prev->next = page->next;
mzta 0:158c61bb030f 275 if (page->next)
mzta 0:158c61bb030f 276 page->next->prev = page->prev;
mzta 0:158c61bb030f 277 if (mrb->heaps == page)
mzta 0:158c61bb030f 278 mrb->heaps = page->next;
mzta 0:158c61bb030f 279 page->prev = NULL;
mzta 0:158c61bb030f 280 page->next = NULL;
mzta 0:158c61bb030f 281 }
mzta 0:158c61bb030f 282
mzta 0:158c61bb030f 283 static void
mzta 0:158c61bb030f 284 link_free_heap_page(mrb_state *mrb, struct heap_page *page)
mzta 0:158c61bb030f 285 {
mzta 0:158c61bb030f 286 page->free_next = mrb->free_heaps;
mzta 0:158c61bb030f 287 if (mrb->free_heaps) {
mzta 0:158c61bb030f 288 mrb->free_heaps->free_prev = page;
mzta 0:158c61bb030f 289 }
mzta 0:158c61bb030f 290 mrb->free_heaps = page;
mzta 0:158c61bb030f 291 }
mzta 0:158c61bb030f 292
mzta 0:158c61bb030f 293 static void
mzta 0:158c61bb030f 294 unlink_free_heap_page(mrb_state *mrb, struct heap_page *page)
mzta 0:158c61bb030f 295 {
mzta 0:158c61bb030f 296 if (page->free_prev)
mzta 0:158c61bb030f 297 page->free_prev->free_next = page->free_next;
mzta 0:158c61bb030f 298 if (page->free_next)
mzta 0:158c61bb030f 299 page->free_next->free_prev = page->free_prev;
mzta 0:158c61bb030f 300 if (mrb->free_heaps == page)
mzta 0:158c61bb030f 301 mrb->free_heaps = page->free_next;
mzta 0:158c61bb030f 302 page->free_prev = NULL;
mzta 0:158c61bb030f 303 page->free_next = NULL;
mzta 0:158c61bb030f 304 }
mzta 0:158c61bb030f 305
mzta 0:158c61bb030f 306 static void
mzta 0:158c61bb030f 307 add_heap(mrb_state *mrb)
mzta 0:158c61bb030f 308 {
mzta 0:158c61bb030f 309 struct heap_page *page = (struct heap_page *)mrb_calloc(mrb, 1, sizeof(struct heap_page));
mzta 0:158c61bb030f 310 RVALUE *p, *e;
mzta 0:158c61bb030f 311 struct RBasic *prev = NULL;
mzta 0:158c61bb030f 312
mzta 0:158c61bb030f 313 for (p = page->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
mzta 0:158c61bb030f 314 p->as.free.tt = MRB_TT_FREE;
mzta 0:158c61bb030f 315 p->as.free.next = prev;
mzta 0:158c61bb030f 316 prev = &p->as.basic;
mzta 0:158c61bb030f 317 }
mzta 0:158c61bb030f 318 page->freelist = prev;
mzta 0:158c61bb030f 319
mzta 0:158c61bb030f 320 link_heap_page(mrb, page);
mzta 0:158c61bb030f 321 link_free_heap_page(mrb, page);
mzta 0:158c61bb030f 322 }
mzta 0:158c61bb030f 323
mzta 0:158c61bb030f 324 #define DEFAULT_GC_INTERVAL_RATIO 200
mzta 0:158c61bb030f 325 #define DEFAULT_GC_STEP_RATIO 200
mzta 0:158c61bb030f 326 #define DEFAULT_MAJOR_GC_INC_RATIO 200
mzta 0:158c61bb030f 327 #define is_generational(mrb) ((mrb)->is_generational_gc_mode)
mzta 0:158c61bb030f 328 #define is_major_gc(mrb) (is_generational(mrb) && (mrb)->gc_full)
mzta 0:158c61bb030f 329 #define is_minor_gc(mrb) (is_generational(mrb) && !(mrb)->gc_full)
mzta 0:158c61bb030f 330
mzta 0:158c61bb030f 331 void
mzta 0:158c61bb030f 332 mrb_init_heap(mrb_state *mrb)
mzta 0:158c61bb030f 333 {
mzta 0:158c61bb030f 334 mrb->heaps = NULL;
mzta 0:158c61bb030f 335 mrb->free_heaps = NULL;
mzta 0:158c61bb030f 336 add_heap(mrb);
mzta 0:158c61bb030f 337 mrb->gc_interval_ratio = DEFAULT_GC_INTERVAL_RATIO;
mzta 0:158c61bb030f 338 mrb->gc_step_ratio = DEFAULT_GC_STEP_RATIO;
mzta 0:158c61bb030f 339 #ifndef MRB_GC_TURN_OFF_GENERATIONAL
mzta 0:158c61bb030f 340 mrb->is_generational_gc_mode = TRUE;
mzta 0:158c61bb030f 341 mrb->gc_full = TRUE;
mzta 0:158c61bb030f 342 #endif
mzta 0:158c61bb030f 343
mzta 0:158c61bb030f 344 #ifdef GC_PROFILE
mzta 0:158c61bb030f 345 program_invoke_time = gettimeofday_time();
mzta 0:158c61bb030f 346 #endif
mzta 0:158c61bb030f 347 }
mzta 0:158c61bb030f 348
mzta 0:158c61bb030f 349 static void obj_free(mrb_state *mrb, struct RBasic *obj);
mzta 0:158c61bb030f 350
mzta 0:158c61bb030f 351 void
mzta 0:158c61bb030f 352 mrb_free_heap(mrb_state *mrb)
mzta 0:158c61bb030f 353 {
mzta 0:158c61bb030f 354 struct heap_page *page = mrb->heaps;
mzta 0:158c61bb030f 355 struct heap_page *tmp;
mzta 0:158c61bb030f 356 RVALUE *p, *e;
mzta 0:158c61bb030f 357
mzta 0:158c61bb030f 358 while (page) {
mzta 0:158c61bb030f 359 tmp = page;
mzta 0:158c61bb030f 360 page = page->next;
mzta 0:158c61bb030f 361 for (p = tmp->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
mzta 0:158c61bb030f 362 if (p->as.free.tt != MRB_TT_FREE)
mzta 0:158c61bb030f 363 obj_free(mrb, &p->as.basic);
mzta 0:158c61bb030f 364 }
mzta 0:158c61bb030f 365 mrb_free(mrb, tmp);
mzta 0:158c61bb030f 366 }
mzta 0:158c61bb030f 367 }
mzta 0:158c61bb030f 368
mzta 0:158c61bb030f 369 static void
mzta 0:158c61bb030f 370 gc_protect(mrb_state *mrb, struct RBasic *p)
mzta 0:158c61bb030f 371 {
mzta 0:158c61bb030f 372 #ifdef MRB_GC_FIXED_ARENA
mzta 0:158c61bb030f 373 if (mrb->arena_idx >= MRB_GC_ARENA_SIZE) {
mzta 0:158c61bb030f 374 /* arena overflow error */
mzta 0:158c61bb030f 375 mrb->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */
mzta 0:158c61bb030f 376 mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error");
mzta 0:158c61bb030f 377 }
mzta 0:158c61bb030f 378 #else
mzta 0:158c61bb030f 379 if (mrb->arena_idx >= mrb->arena_capa) {
mzta 0:158c61bb030f 380 /* extend arena */
mzta 0:158c61bb030f 381 mrb->arena_capa = (int)(mrb->arena_capa * 1.5);
mzta 0:158c61bb030f 382 mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*mrb->arena_capa);
mzta 0:158c61bb030f 383 }
mzta 0:158c61bb030f 384 #endif
mzta 0:158c61bb030f 385 mrb->arena[mrb->arena_idx++] = p;
mzta 0:158c61bb030f 386 }
mzta 0:158c61bb030f 387
mzta 0:158c61bb030f 388 MRB_API void
mzta 0:158c61bb030f 389 mrb_gc_protect(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 390 {
mzta 0:158c61bb030f 391 if (mrb_immediate_p(obj)) return;
mzta 0:158c61bb030f 392 gc_protect(mrb, mrb_basic_ptr(obj));
mzta 0:158c61bb030f 393 }
mzta 0:158c61bb030f 394
mzta 0:158c61bb030f 395 MRB_API struct RBasic*
mzta 0:158c61bb030f 396 mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
mzta 0:158c61bb030f 397 {
mzta 0:158c61bb030f 398 struct RBasic *p;
mzta 0:158c61bb030f 399 static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } };
mzta 0:158c61bb030f 400
mzta 0:158c61bb030f 401 #ifdef MRB_GC_STRESS
mzta 0:158c61bb030f 402 mrb_full_gc(mrb);
mzta 0:158c61bb030f 403 #endif
mzta 0:158c61bb030f 404 if (mrb->gc_threshold < mrb->live) {
mzta 0:158c61bb030f 405 mrb_incremental_gc(mrb);
mzta 0:158c61bb030f 406 }
mzta 0:158c61bb030f 407 if (mrb->free_heaps == NULL) {
mzta 0:158c61bb030f 408 add_heap(mrb);
mzta 0:158c61bb030f 409 }
mzta 0:158c61bb030f 410
mzta 0:158c61bb030f 411 p = mrb->free_heaps->freelist;
mzta 0:158c61bb030f 412 mrb->free_heaps->freelist = ((struct free_obj*)p)->next;
mzta 0:158c61bb030f 413 if (mrb->free_heaps->freelist == NULL) {
mzta 0:158c61bb030f 414 unlink_free_heap_page(mrb, mrb->free_heaps);
mzta 0:158c61bb030f 415 }
mzta 0:158c61bb030f 416
mzta 0:158c61bb030f 417 mrb->live++;
mzta 0:158c61bb030f 418 gc_protect(mrb, p);
mzta 0:158c61bb030f 419 *(RVALUE *)p = RVALUE_zero;
mzta 0:158c61bb030f 420 p->tt = ttype;
mzta 0:158c61bb030f 421 p->c = cls;
mzta 0:158c61bb030f 422 paint_partial_white(mrb, p);
mzta 0:158c61bb030f 423 return p;
mzta 0:158c61bb030f 424 }
mzta 0:158c61bb030f 425
mzta 0:158c61bb030f 426 static inline void
mzta 0:158c61bb030f 427 add_gray_list(mrb_state *mrb, struct RBasic *obj)
mzta 0:158c61bb030f 428 {
mzta 0:158c61bb030f 429 #ifdef MRB_GC_STRESS
mzta 0:158c61bb030f 430 if (obj->tt > MRB_TT_MAXDEFINE) {
mzta 0:158c61bb030f 431 abort();
mzta 0:158c61bb030f 432 }
mzta 0:158c61bb030f 433 #endif
mzta 0:158c61bb030f 434 paint_gray(obj);
mzta 0:158c61bb030f 435 obj->gcnext = mrb->gray_list;
mzta 0:158c61bb030f 436 mrb->gray_list = obj;
mzta 0:158c61bb030f 437 }
mzta 0:158c61bb030f 438
mzta 0:158c61bb030f 439 static void
mzta 0:158c61bb030f 440 mark_context_stack(mrb_state *mrb, struct mrb_context *c)
mzta 0:158c61bb030f 441 {
mzta 0:158c61bb030f 442 size_t i;
mzta 0:158c61bb030f 443 size_t e;
mzta 0:158c61bb030f 444
mzta 0:158c61bb030f 445 e = c->stack - c->stbase;
mzta 0:158c61bb030f 446 if (c->ci) e += c->ci->nregs;
mzta 0:158c61bb030f 447 if (c->stbase + e > c->stend) e = c->stend - c->stbase;
mzta 0:158c61bb030f 448 for (i=0; i<e; i++) {
mzta 0:158c61bb030f 449 mrb_value v = c->stbase[i];
mzta 0:158c61bb030f 450
mzta 0:158c61bb030f 451 if (!mrb_immediate_p(v)) {
mzta 0:158c61bb030f 452 if (mrb_basic_ptr(v)->tt == MRB_TT_FREE) {
mzta 0:158c61bb030f 453 c->stbase[i] = mrb_nil_value();
mzta 0:158c61bb030f 454 }
mzta 0:158c61bb030f 455 else {
mzta 0:158c61bb030f 456 mrb_gc_mark(mrb, mrb_basic_ptr(v));
mzta 0:158c61bb030f 457 }
mzta 0:158c61bb030f 458 }
mzta 0:158c61bb030f 459 }
mzta 0:158c61bb030f 460 }
mzta 0:158c61bb030f 461
mzta 0:158c61bb030f 462 static void
mzta 0:158c61bb030f 463 mark_context(mrb_state *mrb, struct mrb_context *c)
mzta 0:158c61bb030f 464 {
mzta 0:158c61bb030f 465 int i, e = 0;
mzta 0:158c61bb030f 466 mrb_callinfo *ci;
mzta 0:158c61bb030f 467
mzta 0:158c61bb030f 468 /* mark stack */
mzta 0:158c61bb030f 469 mark_context_stack(mrb, c);
mzta 0:158c61bb030f 470
mzta 0:158c61bb030f 471 /* mark VM stack */
mzta 0:158c61bb030f 472 if (c->cibase) {
mzta 0:158c61bb030f 473 for (ci = c->cibase; ci <= c->ci; ci++) {
mzta 0:158c61bb030f 474 if (ci->eidx > e) {
mzta 0:158c61bb030f 475 e = ci->eidx;
mzta 0:158c61bb030f 476 }
mzta 0:158c61bb030f 477 mrb_gc_mark(mrb, (struct RBasic*)ci->env);
mzta 0:158c61bb030f 478 mrb_gc_mark(mrb, (struct RBasic*)ci->proc);
mzta 0:158c61bb030f 479 mrb_gc_mark(mrb, (struct RBasic*)ci->target_class);
mzta 0:158c61bb030f 480 }
mzta 0:158c61bb030f 481 }
mzta 0:158c61bb030f 482 /* mark ensure stack */
mzta 0:158c61bb030f 483 for (i=0; i<e; i++) {
mzta 0:158c61bb030f 484 mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]);
mzta 0:158c61bb030f 485 }
mzta 0:158c61bb030f 486 /* mark fibers */
mzta 0:158c61bb030f 487 if (c->prev && c->prev->fib) {
mzta 0:158c61bb030f 488 mrb_gc_mark(mrb, (struct RBasic*)c->prev->fib);
mzta 0:158c61bb030f 489 }
mzta 0:158c61bb030f 490 }
mzta 0:158c61bb030f 491
mzta 0:158c61bb030f 492 static void
mzta 0:158c61bb030f 493 gc_mark_children(mrb_state *mrb, struct RBasic *obj)
mzta 0:158c61bb030f 494 {
mzta 0:158c61bb030f 495 mrb_assert(is_gray(obj));
mzta 0:158c61bb030f 496 paint_black(obj);
mzta 0:158c61bb030f 497 mrb->gray_list = obj->gcnext;
mzta 0:158c61bb030f 498 mrb_gc_mark(mrb, (struct RBasic*)obj->c);
mzta 0:158c61bb030f 499 switch (obj->tt) {
mzta 0:158c61bb030f 500 case MRB_TT_ICLASS:
mzta 0:158c61bb030f 501 mrb_gc_mark(mrb, (struct RBasic*)((struct RClass*)obj)->super);
mzta 0:158c61bb030f 502 break;
mzta 0:158c61bb030f 503
mzta 0:158c61bb030f 504 case MRB_TT_CLASS:
mzta 0:158c61bb030f 505 case MRB_TT_MODULE:
mzta 0:158c61bb030f 506 case MRB_TT_SCLASS:
mzta 0:158c61bb030f 507 {
mzta 0:158c61bb030f 508 struct RClass *c = (struct RClass*)obj;
mzta 0:158c61bb030f 509
mzta 0:158c61bb030f 510 mrb_gc_mark_mt(mrb, c);
mzta 0:158c61bb030f 511 mrb_gc_mark(mrb, (struct RBasic*)c->super);
mzta 0:158c61bb030f 512 }
mzta 0:158c61bb030f 513 /* fall through */
mzta 0:158c61bb030f 514
mzta 0:158c61bb030f 515 case MRB_TT_OBJECT:
mzta 0:158c61bb030f 516 case MRB_TT_DATA:
mzta 0:158c61bb030f 517 case MRB_TT_EXCEPTION:
mzta 0:158c61bb030f 518 mrb_gc_mark_iv(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 519 break;
mzta 0:158c61bb030f 520
mzta 0:158c61bb030f 521 case MRB_TT_PROC:
mzta 0:158c61bb030f 522 {
mzta 0:158c61bb030f 523 struct RProc *p = (struct RProc*)obj;
mzta 0:158c61bb030f 524
mzta 0:158c61bb030f 525 mrb_gc_mark(mrb, (struct RBasic*)p->env);
mzta 0:158c61bb030f 526 mrb_gc_mark(mrb, (struct RBasic*)p->target_class);
mzta 0:158c61bb030f 527 }
mzta 0:158c61bb030f 528 break;
mzta 0:158c61bb030f 529
mzta 0:158c61bb030f 530 case MRB_TT_ENV:
mzta 0:158c61bb030f 531 {
mzta 0:158c61bb030f 532 struct REnv *e = (struct REnv*)obj;
mzta 0:158c61bb030f 533
mzta 0:158c61bb030f 534 if (!MRB_ENV_STACK_SHARED_P(e)) {
mzta 0:158c61bb030f 535 mrb_int i, len;
mzta 0:158c61bb030f 536
mzta 0:158c61bb030f 537 len = MRB_ENV_STACK_LEN(e);
mzta 0:158c61bb030f 538 for (i=0; i<len; i++) {
mzta 0:158c61bb030f 539 mrb_gc_mark_value(mrb, e->stack[i]);
mzta 0:158c61bb030f 540 }
mzta 0:158c61bb030f 541 }
mzta 0:158c61bb030f 542 }
mzta 0:158c61bb030f 543 break;
mzta 0:158c61bb030f 544
mzta 0:158c61bb030f 545 case MRB_TT_FIBER:
mzta 0:158c61bb030f 546 {
mzta 0:158c61bb030f 547 struct mrb_context *c = ((struct RFiber*)obj)->cxt;
mzta 0:158c61bb030f 548
mzta 0:158c61bb030f 549 if (c) mark_context(mrb, c);
mzta 0:158c61bb030f 550 }
mzta 0:158c61bb030f 551 break;
mzta 0:158c61bb030f 552
mzta 0:158c61bb030f 553 case MRB_TT_ARRAY:
mzta 0:158c61bb030f 554 {
mzta 0:158c61bb030f 555 struct RArray *a = (struct RArray*)obj;
mzta 0:158c61bb030f 556 size_t i, e;
mzta 0:158c61bb030f 557
mzta 0:158c61bb030f 558 for (i=0,e=a->len; i<e; i++) {
mzta 0:158c61bb030f 559 mrb_gc_mark_value(mrb, a->ptr[i]);
mzta 0:158c61bb030f 560 }
mzta 0:158c61bb030f 561 }
mzta 0:158c61bb030f 562 break;
mzta 0:158c61bb030f 563
mzta 0:158c61bb030f 564 case MRB_TT_HASH:
mzta 0:158c61bb030f 565 mrb_gc_mark_iv(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 566 mrb_gc_mark_hash(mrb, (struct RHash*)obj);
mzta 0:158c61bb030f 567 break;
mzta 0:158c61bb030f 568
mzta 0:158c61bb030f 569 case MRB_TT_STRING:
mzta 0:158c61bb030f 570 break;
mzta 0:158c61bb030f 571
mzta 0:158c61bb030f 572 case MRB_TT_RANGE:
mzta 0:158c61bb030f 573 {
mzta 0:158c61bb030f 574 struct RRange *r = (struct RRange*)obj;
mzta 0:158c61bb030f 575
mzta 0:158c61bb030f 576 if (r->edges) {
mzta 0:158c61bb030f 577 mrb_gc_mark_value(mrb, r->edges->beg);
mzta 0:158c61bb030f 578 mrb_gc_mark_value(mrb, r->edges->end);
mzta 0:158c61bb030f 579 }
mzta 0:158c61bb030f 580 }
mzta 0:158c61bb030f 581 break;
mzta 0:158c61bb030f 582
mzta 0:158c61bb030f 583 default:
mzta 0:158c61bb030f 584 break;
mzta 0:158c61bb030f 585 }
mzta 0:158c61bb030f 586 }
mzta 0:158c61bb030f 587
mzta 0:158c61bb030f 588 MRB_API void
mzta 0:158c61bb030f 589 mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
mzta 0:158c61bb030f 590 {
mzta 0:158c61bb030f 591 if (obj == 0) return;
mzta 0:158c61bb030f 592 if (!is_white(obj)) return;
mzta 0:158c61bb030f 593 mrb_assert((obj)->tt != MRB_TT_FREE);
mzta 0:158c61bb030f 594 add_gray_list(mrb, obj);
mzta 0:158c61bb030f 595 }
mzta 0:158c61bb030f 596
mzta 0:158c61bb030f 597 static void
mzta 0:158c61bb030f 598 obj_free(mrb_state *mrb, struct RBasic *obj)
mzta 0:158c61bb030f 599 {
mzta 0:158c61bb030f 600 DEBUG(printf("obj_free(%p,tt=%d)\n",obj,obj->tt));
mzta 0:158c61bb030f 601 switch (obj->tt) {
mzta 0:158c61bb030f 602 /* immediate - no mark */
mzta 0:158c61bb030f 603 case MRB_TT_TRUE:
mzta 0:158c61bb030f 604 case MRB_TT_FIXNUM:
mzta 0:158c61bb030f 605 case MRB_TT_SYMBOL:
mzta 0:158c61bb030f 606 /* cannot happen */
mzta 0:158c61bb030f 607 return;
mzta 0:158c61bb030f 608
mzta 0:158c61bb030f 609 case MRB_TT_FLOAT:
mzta 0:158c61bb030f 610 #ifdef MRB_WORD_BOXING
mzta 0:158c61bb030f 611 break;
mzta 0:158c61bb030f 612 #else
mzta 0:158c61bb030f 613 return;
mzta 0:158c61bb030f 614 #endif
mzta 0:158c61bb030f 615
mzta 0:158c61bb030f 616 case MRB_TT_OBJECT:
mzta 0:158c61bb030f 617 case MRB_TT_EXCEPTION:
mzta 0:158c61bb030f 618 mrb_gc_free_iv(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 619 break;
mzta 0:158c61bb030f 620
mzta 0:158c61bb030f 621 case MRB_TT_CLASS:
mzta 0:158c61bb030f 622 case MRB_TT_MODULE:
mzta 0:158c61bb030f 623 case MRB_TT_SCLASS:
mzta 0:158c61bb030f 624 mrb_gc_free_mt(mrb, (struct RClass*)obj);
mzta 0:158c61bb030f 625 mrb_gc_free_iv(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 626 break;
mzta 0:158c61bb030f 627
mzta 0:158c61bb030f 628 case MRB_TT_ENV:
mzta 0:158c61bb030f 629 {
mzta 0:158c61bb030f 630 struct REnv *e = (struct REnv*)obj;
mzta 0:158c61bb030f 631
mzta 0:158c61bb030f 632 if (!MRB_ENV_STACK_SHARED_P(e)) {
mzta 0:158c61bb030f 633 mrb_free(mrb, e->stack);
mzta 0:158c61bb030f 634 e->stack = NULL;
mzta 0:158c61bb030f 635 }
mzta 0:158c61bb030f 636 }
mzta 0:158c61bb030f 637 break;
mzta 0:158c61bb030f 638
mzta 0:158c61bb030f 639 case MRB_TT_FIBER:
mzta 0:158c61bb030f 640 {
mzta 0:158c61bb030f 641 struct mrb_context *c = ((struct RFiber*)obj)->cxt;
mzta 0:158c61bb030f 642
mzta 0:158c61bb030f 643 if (c != mrb->root_c)
mzta 0:158c61bb030f 644 mrb_free_context(mrb, c);
mzta 0:158c61bb030f 645 }
mzta 0:158c61bb030f 646 break;
mzta 0:158c61bb030f 647
mzta 0:158c61bb030f 648 case MRB_TT_ARRAY:
mzta 0:158c61bb030f 649 if (ARY_SHARED_P(obj))
mzta 0:158c61bb030f 650 mrb_ary_decref(mrb, ((struct RArray*)obj)->aux.shared);
mzta 0:158c61bb030f 651 else
mzta 0:158c61bb030f 652 mrb_free(mrb, ((struct RArray*)obj)->ptr);
mzta 0:158c61bb030f 653 break;
mzta 0:158c61bb030f 654
mzta 0:158c61bb030f 655 case MRB_TT_HASH:
mzta 0:158c61bb030f 656 mrb_gc_free_iv(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 657 mrb_gc_free_hash(mrb, (struct RHash*)obj);
mzta 0:158c61bb030f 658 break;
mzta 0:158c61bb030f 659
mzta 0:158c61bb030f 660 case MRB_TT_STRING:
mzta 0:158c61bb030f 661 mrb_gc_free_str(mrb, (struct RString*)obj);
mzta 0:158c61bb030f 662 break;
mzta 0:158c61bb030f 663
mzta 0:158c61bb030f 664 case MRB_TT_PROC:
mzta 0:158c61bb030f 665 {
mzta 0:158c61bb030f 666 struct RProc *p = (struct RProc*)obj;
mzta 0:158c61bb030f 667
mzta 0:158c61bb030f 668 if (!MRB_PROC_CFUNC_P(p) && p->body.irep) {
mzta 0:158c61bb030f 669 mrb_irep_decref(mrb, p->body.irep);
mzta 0:158c61bb030f 670 }
mzta 0:158c61bb030f 671 }
mzta 0:158c61bb030f 672 break;
mzta 0:158c61bb030f 673
mzta 0:158c61bb030f 674 case MRB_TT_RANGE:
mzta 0:158c61bb030f 675 mrb_free(mrb, ((struct RRange*)obj)->edges);
mzta 0:158c61bb030f 676 break;
mzta 0:158c61bb030f 677
mzta 0:158c61bb030f 678 case MRB_TT_DATA:
mzta 0:158c61bb030f 679 {
mzta 0:158c61bb030f 680 struct RData *d = (struct RData*)obj;
mzta 0:158c61bb030f 681 if (d->type && d->type->dfree) {
mzta 0:158c61bb030f 682 d->type->dfree(mrb, d->data);
mzta 0:158c61bb030f 683 }
mzta 0:158c61bb030f 684 mrb_gc_free_iv(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 685 }
mzta 0:158c61bb030f 686 break;
mzta 0:158c61bb030f 687
mzta 0:158c61bb030f 688 default:
mzta 0:158c61bb030f 689 break;
mzta 0:158c61bb030f 690 }
mzta 0:158c61bb030f 691 obj->tt = MRB_TT_FREE;
mzta 0:158c61bb030f 692 }
mzta 0:158c61bb030f 693
mzta 0:158c61bb030f 694 static void
mzta 0:158c61bb030f 695 root_scan_phase(mrb_state *mrb)
mzta 0:158c61bb030f 696 {
mzta 0:158c61bb030f 697 size_t i, e;
mzta 0:158c61bb030f 698
mzta 0:158c61bb030f 699 if (!is_minor_gc(mrb)) {
mzta 0:158c61bb030f 700 mrb->gray_list = NULL;
mzta 0:158c61bb030f 701 mrb->atomic_gray_list = NULL;
mzta 0:158c61bb030f 702 }
mzta 0:158c61bb030f 703
mzta 0:158c61bb030f 704 mrb_gc_mark_gv(mrb);
mzta 0:158c61bb030f 705 /* mark arena */
mzta 0:158c61bb030f 706 for (i=0,e=mrb->arena_idx; i<e; i++) {
mzta 0:158c61bb030f 707 mrb_gc_mark(mrb, mrb->arena[i]);
mzta 0:158c61bb030f 708 }
mzta 0:158c61bb030f 709 /* mark class hierarchy */
mzta 0:158c61bb030f 710 mrb_gc_mark(mrb, (struct RBasic*)mrb->object_class);
mzta 0:158c61bb030f 711 /* mark top_self */
mzta 0:158c61bb030f 712 mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self);
mzta 0:158c61bb030f 713 /* mark exception */
mzta 0:158c61bb030f 714 mrb_gc_mark(mrb, (struct RBasic*)mrb->exc);
mzta 0:158c61bb030f 715 /* mark pre-allocated exception */
mzta 0:158c61bb030f 716 mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err);
mzta 0:158c61bb030f 717
mzta 0:158c61bb030f 718 mark_context(mrb, mrb->root_c);
mzta 0:158c61bb030f 719 if (mrb->root_c->fib) {
mzta 0:158c61bb030f 720 mrb_gc_mark(mrb, (struct RBasic*)mrb->root_c->fib);
mzta 0:158c61bb030f 721 }
mzta 0:158c61bb030f 722 if (mrb->root_c != mrb->c) {
mzta 0:158c61bb030f 723 mark_context(mrb, mrb->c);
mzta 0:158c61bb030f 724 }
mzta 0:158c61bb030f 725 }
mzta 0:158c61bb030f 726
mzta 0:158c61bb030f 727 static size_t
mzta 0:158c61bb030f 728 gc_gray_mark(mrb_state *mrb, struct RBasic *obj)
mzta 0:158c61bb030f 729 {
mzta 0:158c61bb030f 730 size_t children = 0;
mzta 0:158c61bb030f 731
mzta 0:158c61bb030f 732 gc_mark_children(mrb, obj);
mzta 0:158c61bb030f 733
mzta 0:158c61bb030f 734 switch (obj->tt) {
mzta 0:158c61bb030f 735 case MRB_TT_ICLASS:
mzta 0:158c61bb030f 736 children++;
mzta 0:158c61bb030f 737 break;
mzta 0:158c61bb030f 738
mzta 0:158c61bb030f 739 case MRB_TT_CLASS:
mzta 0:158c61bb030f 740 case MRB_TT_SCLASS:
mzta 0:158c61bb030f 741 case MRB_TT_MODULE:
mzta 0:158c61bb030f 742 {
mzta 0:158c61bb030f 743 struct RClass *c = (struct RClass*)obj;
mzta 0:158c61bb030f 744
mzta 0:158c61bb030f 745 children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 746 children += mrb_gc_mark_mt_size(mrb, c);
mzta 0:158c61bb030f 747 children++;
mzta 0:158c61bb030f 748 }
mzta 0:158c61bb030f 749 break;
mzta 0:158c61bb030f 750
mzta 0:158c61bb030f 751 case MRB_TT_OBJECT:
mzta 0:158c61bb030f 752 case MRB_TT_DATA:
mzta 0:158c61bb030f 753 case MRB_TT_EXCEPTION:
mzta 0:158c61bb030f 754 children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 755 break;
mzta 0:158c61bb030f 756
mzta 0:158c61bb030f 757 case MRB_TT_ENV:
mzta 0:158c61bb030f 758 children += (int)obj->flags;
mzta 0:158c61bb030f 759 break;
mzta 0:158c61bb030f 760
mzta 0:158c61bb030f 761 case MRB_TT_FIBER:
mzta 0:158c61bb030f 762 {
mzta 0:158c61bb030f 763 struct mrb_context *c = ((struct RFiber*)obj)->cxt;
mzta 0:158c61bb030f 764 size_t i;
mzta 0:158c61bb030f 765 mrb_callinfo *ci;
mzta 0:158c61bb030f 766
mzta 0:158c61bb030f 767 if (!c) break;
mzta 0:158c61bb030f 768 /* mark stack */
mzta 0:158c61bb030f 769 i = c->stack - c->stbase;
mzta 0:158c61bb030f 770 if (c->ci) i += c->ci->nregs;
mzta 0:158c61bb030f 771 if (c->stbase + i > c->stend) i = c->stend - c->stbase;
mzta 0:158c61bb030f 772 children += i;
mzta 0:158c61bb030f 773
mzta 0:158c61bb030f 774 /* mark ensure stack */
mzta 0:158c61bb030f 775 children += (c->ci) ? c->ci->eidx : 0;
mzta 0:158c61bb030f 776
mzta 0:158c61bb030f 777 /* mark closure */
mzta 0:158c61bb030f 778 if (c->cibase) {
mzta 0:158c61bb030f 779 for (i=0, ci = c->cibase; ci <= c->ci; i++, ci++)
mzta 0:158c61bb030f 780 ;
mzta 0:158c61bb030f 781 }
mzta 0:158c61bb030f 782 children += i;
mzta 0:158c61bb030f 783 }
mzta 0:158c61bb030f 784 break;
mzta 0:158c61bb030f 785
mzta 0:158c61bb030f 786 case MRB_TT_ARRAY:
mzta 0:158c61bb030f 787 {
mzta 0:158c61bb030f 788 struct RArray *a = (struct RArray*)obj;
mzta 0:158c61bb030f 789 children += a->len;
mzta 0:158c61bb030f 790 }
mzta 0:158c61bb030f 791 break;
mzta 0:158c61bb030f 792
mzta 0:158c61bb030f 793 case MRB_TT_HASH:
mzta 0:158c61bb030f 794 children += mrb_gc_mark_iv_size(mrb, (struct RObject*)obj);
mzta 0:158c61bb030f 795 children += mrb_gc_mark_hash_size(mrb, (struct RHash*)obj);
mzta 0:158c61bb030f 796 break;
mzta 0:158c61bb030f 797
mzta 0:158c61bb030f 798 case MRB_TT_PROC:
mzta 0:158c61bb030f 799 case MRB_TT_RANGE:
mzta 0:158c61bb030f 800 children+=2;
mzta 0:158c61bb030f 801 break;
mzta 0:158c61bb030f 802
mzta 0:158c61bb030f 803 default:
mzta 0:158c61bb030f 804 break;
mzta 0:158c61bb030f 805 }
mzta 0:158c61bb030f 806 return children;
mzta 0:158c61bb030f 807 }
mzta 0:158c61bb030f 808
mzta 0:158c61bb030f 809
mzta 0:158c61bb030f 810 static void
mzta 0:158c61bb030f 811 gc_mark_gray_list(mrb_state *mrb) {
mzta 0:158c61bb030f 812 while (mrb->gray_list) {
mzta 0:158c61bb030f 813 if (is_gray(mrb->gray_list))
mzta 0:158c61bb030f 814 gc_mark_children(mrb, mrb->gray_list);
mzta 0:158c61bb030f 815 else
mzta 0:158c61bb030f 816 mrb->gray_list = mrb->gray_list->gcnext;
mzta 0:158c61bb030f 817 }
mzta 0:158c61bb030f 818 }
mzta 0:158c61bb030f 819
mzta 0:158c61bb030f 820
mzta 0:158c61bb030f 821 static size_t
mzta 0:158c61bb030f 822 incremental_marking_phase(mrb_state *mrb, size_t limit)
mzta 0:158c61bb030f 823 {
mzta 0:158c61bb030f 824 size_t tried_marks = 0;
mzta 0:158c61bb030f 825
mzta 0:158c61bb030f 826 while (mrb->gray_list && tried_marks < limit) {
mzta 0:158c61bb030f 827 tried_marks += gc_gray_mark(mrb, mrb->gray_list);
mzta 0:158c61bb030f 828 }
mzta 0:158c61bb030f 829
mzta 0:158c61bb030f 830 return tried_marks;
mzta 0:158c61bb030f 831 }
mzta 0:158c61bb030f 832
mzta 0:158c61bb030f 833 static void
mzta 0:158c61bb030f 834 final_marking_phase(mrb_state *mrb)
mzta 0:158c61bb030f 835 {
mzta 0:158c61bb030f 836 mark_context_stack(mrb, mrb->root_c);
mzta 0:158c61bb030f 837 gc_mark_gray_list(mrb);
mzta 0:158c61bb030f 838 mrb_assert(mrb->gray_list == NULL);
mzta 0:158c61bb030f 839 mrb->gray_list = mrb->atomic_gray_list;
mzta 0:158c61bb030f 840 mrb->atomic_gray_list = NULL;
mzta 0:158c61bb030f 841 gc_mark_gray_list(mrb);
mzta 0:158c61bb030f 842 mrb_assert(mrb->gray_list == NULL);
mzta 0:158c61bb030f 843 }
mzta 0:158c61bb030f 844
mzta 0:158c61bb030f 845 static void
mzta 0:158c61bb030f 846 prepare_incremental_sweep(mrb_state *mrb)
mzta 0:158c61bb030f 847 {
mzta 0:158c61bb030f 848 mrb->gc_state = GC_STATE_SWEEP;
mzta 0:158c61bb030f 849 mrb->sweeps = mrb->heaps;
mzta 0:158c61bb030f 850 mrb->gc_live_after_mark = mrb->live;
mzta 0:158c61bb030f 851 }
mzta 0:158c61bb030f 852
mzta 0:158c61bb030f 853 static size_t
mzta 0:158c61bb030f 854 incremental_sweep_phase(mrb_state *mrb, size_t limit)
mzta 0:158c61bb030f 855 {
mzta 0:158c61bb030f 856 struct heap_page *page = mrb->sweeps;
mzta 0:158c61bb030f 857 size_t tried_sweep = 0;
mzta 0:158c61bb030f 858
mzta 0:158c61bb030f 859 while (page && (tried_sweep < limit)) {
mzta 0:158c61bb030f 860 RVALUE *p = page->objects;
mzta 0:158c61bb030f 861 RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
mzta 0:158c61bb030f 862 size_t freed = 0;
mzta 0:158c61bb030f 863 mrb_bool dead_slot = TRUE;
mzta 0:158c61bb030f 864 mrb_bool full = (page->freelist == NULL);
mzta 0:158c61bb030f 865
mzta 0:158c61bb030f 866 if (is_minor_gc(mrb) && page->old) {
mzta 0:158c61bb030f 867 /* skip a slot which doesn't contain any young object */
mzta 0:158c61bb030f 868 p = e;
mzta 0:158c61bb030f 869 dead_slot = FALSE;
mzta 0:158c61bb030f 870 }
mzta 0:158c61bb030f 871 while (p<e) {
mzta 0:158c61bb030f 872 if (is_dead(mrb, &p->as.basic)) {
mzta 0:158c61bb030f 873 if (p->as.basic.tt != MRB_TT_FREE) {
mzta 0:158c61bb030f 874 obj_free(mrb, &p->as.basic);
mzta 0:158c61bb030f 875 p->as.free.next = page->freelist;
mzta 0:158c61bb030f 876 page->freelist = (struct RBasic*)p;
mzta 0:158c61bb030f 877 freed++;
mzta 0:158c61bb030f 878 }
mzta 0:158c61bb030f 879 }
mzta 0:158c61bb030f 880 else {
mzta 0:158c61bb030f 881 if (!is_generational(mrb))
mzta 0:158c61bb030f 882 paint_partial_white(mrb, &p->as.basic); /* next gc target */
mzta 0:158c61bb030f 883 dead_slot = 0;
mzta 0:158c61bb030f 884 }
mzta 0:158c61bb030f 885 p++;
mzta 0:158c61bb030f 886 }
mzta 0:158c61bb030f 887
mzta 0:158c61bb030f 888 /* free dead slot */
mzta 0:158c61bb030f 889 if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) {
mzta 0:158c61bb030f 890 struct heap_page *next = page->next;
mzta 0:158c61bb030f 891
mzta 0:158c61bb030f 892 unlink_heap_page(mrb, page);
mzta 0:158c61bb030f 893 unlink_free_heap_page(mrb, page);
mzta 0:158c61bb030f 894 mrb_free(mrb, page);
mzta 0:158c61bb030f 895 page = next;
mzta 0:158c61bb030f 896 }
mzta 0:158c61bb030f 897 else {
mzta 0:158c61bb030f 898 if (full && freed > 0) {
mzta 0:158c61bb030f 899 link_free_heap_page(mrb, page);
mzta 0:158c61bb030f 900 }
mzta 0:158c61bb030f 901 if (page->freelist == NULL && is_minor_gc(mrb))
mzta 0:158c61bb030f 902 page->old = TRUE;
mzta 0:158c61bb030f 903 else
mzta 0:158c61bb030f 904 page->old = FALSE;
mzta 0:158c61bb030f 905 page = page->next;
mzta 0:158c61bb030f 906 }
mzta 0:158c61bb030f 907 tried_sweep += MRB_HEAP_PAGE_SIZE;
mzta 0:158c61bb030f 908 mrb->live -= freed;
mzta 0:158c61bb030f 909 mrb->gc_live_after_mark -= freed;
mzta 0:158c61bb030f 910 }
mzta 0:158c61bb030f 911 mrb->sweeps = page;
mzta 0:158c61bb030f 912 return tried_sweep;
mzta 0:158c61bb030f 913 }
mzta 0:158c61bb030f 914
mzta 0:158c61bb030f 915 static size_t
mzta 0:158c61bb030f 916 incremental_gc(mrb_state *mrb, size_t limit)
mzta 0:158c61bb030f 917 {
mzta 0:158c61bb030f 918 switch (mrb->gc_state) {
mzta 0:158c61bb030f 919 case GC_STATE_ROOT:
mzta 0:158c61bb030f 920 root_scan_phase(mrb);
mzta 0:158c61bb030f 921 mrb->gc_state = GC_STATE_MARK;
mzta 0:158c61bb030f 922 flip_white_part(mrb);
mzta 0:158c61bb030f 923 return 0;
mzta 0:158c61bb030f 924 case GC_STATE_MARK:
mzta 0:158c61bb030f 925 if (mrb->gray_list) {
mzta 0:158c61bb030f 926 return incremental_marking_phase(mrb, limit);
mzta 0:158c61bb030f 927 }
mzta 0:158c61bb030f 928 else {
mzta 0:158c61bb030f 929 final_marking_phase(mrb);
mzta 0:158c61bb030f 930 prepare_incremental_sweep(mrb);
mzta 0:158c61bb030f 931 return 0;
mzta 0:158c61bb030f 932 }
mzta 0:158c61bb030f 933 case GC_STATE_SWEEP: {
mzta 0:158c61bb030f 934 size_t tried_sweep = 0;
mzta 0:158c61bb030f 935 tried_sweep = incremental_sweep_phase(mrb, limit);
mzta 0:158c61bb030f 936 if (tried_sweep == 0)
mzta 0:158c61bb030f 937 mrb->gc_state = GC_STATE_ROOT;
mzta 0:158c61bb030f 938 return tried_sweep;
mzta 0:158c61bb030f 939 }
mzta 0:158c61bb030f 940 default:
mzta 0:158c61bb030f 941 /* unknown state */
mzta 0:158c61bb030f 942 mrb_assert(0);
mzta 0:158c61bb030f 943 return 0;
mzta 0:158c61bb030f 944 }
mzta 0:158c61bb030f 945 }
mzta 0:158c61bb030f 946
mzta 0:158c61bb030f 947 static void
mzta 0:158c61bb030f 948 incremental_gc_until(mrb_state *mrb, enum gc_state to_state)
mzta 0:158c61bb030f 949 {
mzta 0:158c61bb030f 950 do {
mzta 0:158c61bb030f 951 incremental_gc(mrb, SIZE_MAX);
mzta 0:158c61bb030f 952 } while (mrb->gc_state != to_state);
mzta 0:158c61bb030f 953 }
mzta 0:158c61bb030f 954
mzta 0:158c61bb030f 955 static void
mzta 0:158c61bb030f 956 incremental_gc_step(mrb_state *mrb)
mzta 0:158c61bb030f 957 {
mzta 0:158c61bb030f 958 size_t limit = 0, result = 0;
mzta 0:158c61bb030f 959 limit = (GC_STEP_SIZE/100) * mrb->gc_step_ratio;
mzta 0:158c61bb030f 960 while (result < limit) {
mzta 0:158c61bb030f 961 result += incremental_gc(mrb, limit);
mzta 0:158c61bb030f 962 if (mrb->gc_state == GC_STATE_ROOT)
mzta 0:158c61bb030f 963 break;
mzta 0:158c61bb030f 964 }
mzta 0:158c61bb030f 965
mzta 0:158c61bb030f 966 mrb->gc_threshold = mrb->live + GC_STEP_SIZE;
mzta 0:158c61bb030f 967 }
mzta 0:158c61bb030f 968
mzta 0:158c61bb030f 969 static void
mzta 0:158c61bb030f 970 clear_all_old(mrb_state *mrb)
mzta 0:158c61bb030f 971 {
mzta 0:158c61bb030f 972 mrb_bool origin_mode = mrb->is_generational_gc_mode;
mzta 0:158c61bb030f 973
mzta 0:158c61bb030f 974 mrb_assert(is_generational(mrb));
mzta 0:158c61bb030f 975 if (is_major_gc(mrb)) {
mzta 0:158c61bb030f 976 /* finish the half baked GC */
mzta 0:158c61bb030f 977 incremental_gc_until(mrb, GC_STATE_ROOT);
mzta 0:158c61bb030f 978 }
mzta 0:158c61bb030f 979
mzta 0:158c61bb030f 980 /* Sweep the dead objects, then reset all the live objects
mzta 0:158c61bb030f 981 * (including all the old objects, of course) to white. */
mzta 0:158c61bb030f 982 mrb->is_generational_gc_mode = FALSE;
mzta 0:158c61bb030f 983 prepare_incremental_sweep(mrb);
mzta 0:158c61bb030f 984 incremental_gc_until(mrb, GC_STATE_ROOT);
mzta 0:158c61bb030f 985 mrb->is_generational_gc_mode = origin_mode;
mzta 0:158c61bb030f 986
mzta 0:158c61bb030f 987 /* The gray objects have already been painted as white */
mzta 0:158c61bb030f 988 mrb->atomic_gray_list = mrb->gray_list = NULL;
mzta 0:158c61bb030f 989 }
mzta 0:158c61bb030f 990
mzta 0:158c61bb030f 991 MRB_API void
mzta 0:158c61bb030f 992 mrb_incremental_gc(mrb_state *mrb)
mzta 0:158c61bb030f 993 {
mzta 0:158c61bb030f 994 if (mrb->gc_disabled) return;
mzta 0:158c61bb030f 995
mzta 0:158c61bb030f 996 GC_INVOKE_TIME_REPORT("mrb_incremental_gc()");
mzta 0:158c61bb030f 997 GC_TIME_START;
mzta 0:158c61bb030f 998
mzta 0:158c61bb030f 999 if (is_minor_gc(mrb)) {
mzta 0:158c61bb030f 1000 incremental_gc_until(mrb, GC_STATE_ROOT);
mzta 0:158c61bb030f 1001 }
mzta 0:158c61bb030f 1002 else {
mzta 0:158c61bb030f 1003 incremental_gc_step(mrb);
mzta 0:158c61bb030f 1004 }
mzta 0:158c61bb030f 1005
mzta 0:158c61bb030f 1006 if (mrb->gc_state == GC_STATE_ROOT) {
mzta 0:158c61bb030f 1007 mrb_assert(mrb->live >= mrb->gc_live_after_mark);
mzta 0:158c61bb030f 1008 mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
mzta 0:158c61bb030f 1009 if (mrb->gc_threshold < GC_STEP_SIZE) {
mzta 0:158c61bb030f 1010 mrb->gc_threshold = GC_STEP_SIZE;
mzta 0:158c61bb030f 1011 }
mzta 0:158c61bb030f 1012
mzta 0:158c61bb030f 1013 if (is_major_gc(mrb)) {
mzta 0:158c61bb030f 1014 mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
mzta 0:158c61bb030f 1015 mrb->gc_full = FALSE;
mzta 0:158c61bb030f 1016 }
mzta 0:158c61bb030f 1017 else if (is_minor_gc(mrb)) {
mzta 0:158c61bb030f 1018 if (mrb->live > mrb->majorgc_old_threshold) {
mzta 0:158c61bb030f 1019 clear_all_old(mrb);
mzta 0:158c61bb030f 1020 mrb->gc_full = TRUE;
mzta 0:158c61bb030f 1021 }
mzta 0:158c61bb030f 1022 }
mzta 0:158c61bb030f 1023 }
mzta 0:158c61bb030f 1024
mzta 0:158c61bb030f 1025 GC_TIME_STOP_AND_REPORT;
mzta 0:158c61bb030f 1026 }
mzta 0:158c61bb030f 1027
mzta 0:158c61bb030f 1028 /* Perform a full gc cycle */
mzta 0:158c61bb030f 1029 MRB_API void
mzta 0:158c61bb030f 1030 mrb_full_gc(mrb_state *mrb)
mzta 0:158c61bb030f 1031 {
mzta 0:158c61bb030f 1032 if (mrb->gc_disabled) return;
mzta 0:158c61bb030f 1033 GC_INVOKE_TIME_REPORT("mrb_full_gc()");
mzta 0:158c61bb030f 1034 GC_TIME_START;
mzta 0:158c61bb030f 1035
mzta 0:158c61bb030f 1036 if (is_generational(mrb)) {
mzta 0:158c61bb030f 1037 /* clear all the old objects back to young */
mzta 0:158c61bb030f 1038 clear_all_old(mrb);
mzta 0:158c61bb030f 1039 mrb->gc_full = TRUE;
mzta 0:158c61bb030f 1040 }
mzta 0:158c61bb030f 1041 else if (mrb->gc_state != GC_STATE_ROOT) {
mzta 0:158c61bb030f 1042 /* finish half baked GC cycle */
mzta 0:158c61bb030f 1043 incremental_gc_until(mrb, GC_STATE_ROOT);
mzta 0:158c61bb030f 1044 }
mzta 0:158c61bb030f 1045
mzta 0:158c61bb030f 1046 incremental_gc_until(mrb, GC_STATE_ROOT);
mzta 0:158c61bb030f 1047 mrb->gc_threshold = (mrb->gc_live_after_mark/100) * mrb->gc_interval_ratio;
mzta 0:158c61bb030f 1048
mzta 0:158c61bb030f 1049 if (is_generational(mrb)) {
mzta 0:158c61bb030f 1050 mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
mzta 0:158c61bb030f 1051 mrb->gc_full = FALSE;
mzta 0:158c61bb030f 1052 }
mzta 0:158c61bb030f 1053
mzta 0:158c61bb030f 1054 GC_TIME_STOP_AND_REPORT;
mzta 0:158c61bb030f 1055 }
mzta 0:158c61bb030f 1056
mzta 0:158c61bb030f 1057 MRB_API void
mzta 0:158c61bb030f 1058 mrb_garbage_collect(mrb_state *mrb)
mzta 0:158c61bb030f 1059 {
mzta 0:158c61bb030f 1060 mrb_full_gc(mrb);
mzta 0:158c61bb030f 1061 }
mzta 0:158c61bb030f 1062
mzta 0:158c61bb030f 1063 MRB_API int
mzta 0:158c61bb030f 1064 mrb_gc_arena_save(mrb_state *mrb)
mzta 0:158c61bb030f 1065 {
mzta 0:158c61bb030f 1066 return mrb->arena_idx;
mzta 0:158c61bb030f 1067 }
mzta 0:158c61bb030f 1068
mzta 0:158c61bb030f 1069 MRB_API void
mzta 0:158c61bb030f 1070 mrb_gc_arena_restore(mrb_state *mrb, int idx)
mzta 0:158c61bb030f 1071 {
mzta 0:158c61bb030f 1072 #ifndef MRB_GC_FIXED_ARENA
mzta 0:158c61bb030f 1073 int capa = mrb->arena_capa;
mzta 0:158c61bb030f 1074
mzta 0:158c61bb030f 1075 if (idx < capa / 2) {
mzta 0:158c61bb030f 1076 capa = (int)(capa * 0.66);
mzta 0:158c61bb030f 1077 if (capa < MRB_GC_ARENA_SIZE) {
mzta 0:158c61bb030f 1078 capa = MRB_GC_ARENA_SIZE;
mzta 0:158c61bb030f 1079 }
mzta 0:158c61bb030f 1080 if (capa != mrb->arena_capa) {
mzta 0:158c61bb030f 1081 mrb->arena = (struct RBasic**)mrb_realloc(mrb, mrb->arena, sizeof(struct RBasic*)*capa);
mzta 0:158c61bb030f 1082 mrb->arena_capa = capa;
mzta 0:158c61bb030f 1083 }
mzta 0:158c61bb030f 1084 }
mzta 0:158c61bb030f 1085 #endif
mzta 0:158c61bb030f 1086 mrb->arena_idx = idx;
mzta 0:158c61bb030f 1087 }
mzta 0:158c61bb030f 1088
mzta 0:158c61bb030f 1089 /*
mzta 0:158c61bb030f 1090 * Field write barrier
mzta 0:158c61bb030f 1091 * Paint obj(Black) -> value(White) to obj(Black) -> value(Gray).
mzta 0:158c61bb030f 1092 */
mzta 0:158c61bb030f 1093
mzta 0:158c61bb030f 1094 MRB_API void
mzta 0:158c61bb030f 1095 mrb_field_write_barrier(mrb_state *mrb, struct RBasic *obj, struct RBasic *value)
mzta 0:158c61bb030f 1096 {
mzta 0:158c61bb030f 1097 if (!is_black(obj)) return;
mzta 0:158c61bb030f 1098 if (!is_white(value)) return;
mzta 0:158c61bb030f 1099
mzta 0:158c61bb030f 1100 mrb_assert(!is_dead(mrb, value) && !is_dead(mrb, obj));
mzta 0:158c61bb030f 1101 mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_ROOT);
mzta 0:158c61bb030f 1102
mzta 0:158c61bb030f 1103 if (is_generational(mrb) || mrb->gc_state == GC_STATE_MARK) {
mzta 0:158c61bb030f 1104 add_gray_list(mrb, value);
mzta 0:158c61bb030f 1105 }
mzta 0:158c61bb030f 1106 else {
mzta 0:158c61bb030f 1107 mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
mzta 0:158c61bb030f 1108 paint_partial_white(mrb, obj); /* for never write barriers */
mzta 0:158c61bb030f 1109 }
mzta 0:158c61bb030f 1110 }
mzta 0:158c61bb030f 1111
mzta 0:158c61bb030f 1112 /*
mzta 0:158c61bb030f 1113 * Write barrier
mzta 0:158c61bb030f 1114 * Paint obj(Black) to obj(Gray).
mzta 0:158c61bb030f 1115 *
mzta 0:158c61bb030f 1116 * The object that is painted gray will be traversed atomically in final
mzta 0:158c61bb030f 1117 * mark phase. So you use this write barrier if it's frequency written spot.
mzta 0:158c61bb030f 1118 * e.g. Set element on Array.
mzta 0:158c61bb030f 1119 */
mzta 0:158c61bb030f 1120
mzta 0:158c61bb030f 1121 MRB_API void
mzta 0:158c61bb030f 1122 mrb_write_barrier(mrb_state *mrb, struct RBasic *obj)
mzta 0:158c61bb030f 1123 {
mzta 0:158c61bb030f 1124 if (!is_black(obj)) return;
mzta 0:158c61bb030f 1125
mzta 0:158c61bb030f 1126 mrb_assert(!is_dead(mrb, obj));
mzta 0:158c61bb030f 1127 mrb_assert(is_generational(mrb) || mrb->gc_state != GC_STATE_ROOT);
mzta 0:158c61bb030f 1128 paint_gray(obj);
mzta 0:158c61bb030f 1129 obj->gcnext = mrb->atomic_gray_list;
mzta 0:158c61bb030f 1130 mrb->atomic_gray_list = obj;
mzta 0:158c61bb030f 1131 }
mzta 0:158c61bb030f 1132
mzta 0:158c61bb030f 1133 /*
mzta 0:158c61bb030f 1134 * call-seq:
mzta 0:158c61bb030f 1135 * GC.start -> nil
mzta 0:158c61bb030f 1136 *
mzta 0:158c61bb030f 1137 * Initiates full garbage collection.
mzta 0:158c61bb030f 1138 *
mzta 0:158c61bb030f 1139 */
mzta 0:158c61bb030f 1140
mzta 0:158c61bb030f 1141 static mrb_value
mzta 0:158c61bb030f 1142 gc_start(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 1143 {
mzta 0:158c61bb030f 1144 mrb_full_gc(mrb);
mzta 0:158c61bb030f 1145 return mrb_nil_value();
mzta 0:158c61bb030f 1146 }
mzta 0:158c61bb030f 1147
mzta 0:158c61bb030f 1148 /*
mzta 0:158c61bb030f 1149 * call-seq:
mzta 0:158c61bb030f 1150 * GC.enable -> true or false
mzta 0:158c61bb030f 1151 *
mzta 0:158c61bb030f 1152 * Enables garbage collection, returning <code>true</code> if garbage
mzta 0:158c61bb030f 1153 * collection was previously disabled.
mzta 0:158c61bb030f 1154 *
mzta 0:158c61bb030f 1155 * GC.disable #=> false
mzta 0:158c61bb030f 1156 * GC.enable #=> true
mzta 0:158c61bb030f 1157 * GC.enable #=> false
mzta 0:158c61bb030f 1158 *
mzta 0:158c61bb030f 1159 */
mzta 0:158c61bb030f 1160
mzta 0:158c61bb030f 1161 static mrb_value
mzta 0:158c61bb030f 1162 gc_enable(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 1163 {
mzta 0:158c61bb030f 1164 mrb_bool old = mrb->gc_disabled;
mzta 0:158c61bb030f 1165
mzta 0:158c61bb030f 1166 mrb->gc_disabled = FALSE;
mzta 0:158c61bb030f 1167
mzta 0:158c61bb030f 1168 return mrb_bool_value(old);
mzta 0:158c61bb030f 1169 }
mzta 0:158c61bb030f 1170
mzta 0:158c61bb030f 1171 /*
mzta 0:158c61bb030f 1172 * call-seq:
mzta 0:158c61bb030f 1173 * GC.disable -> true or false
mzta 0:158c61bb030f 1174 *
mzta 0:158c61bb030f 1175 * Disables garbage collection, returning <code>true</code> if garbage
mzta 0:158c61bb030f 1176 * collection was already disabled.
mzta 0:158c61bb030f 1177 *
mzta 0:158c61bb030f 1178 * GC.disable #=> false
mzta 0:158c61bb030f 1179 * GC.disable #=> true
mzta 0:158c61bb030f 1180 *
mzta 0:158c61bb030f 1181 */
mzta 0:158c61bb030f 1182
mzta 0:158c61bb030f 1183 static mrb_value
mzta 0:158c61bb030f 1184 gc_disable(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 1185 {
mzta 0:158c61bb030f 1186 mrb_bool old = mrb->gc_disabled;
mzta 0:158c61bb030f 1187
mzta 0:158c61bb030f 1188 mrb->gc_disabled = TRUE;
mzta 0:158c61bb030f 1189
mzta 0:158c61bb030f 1190 return mrb_bool_value(old);
mzta 0:158c61bb030f 1191 }
mzta 0:158c61bb030f 1192
mzta 0:158c61bb030f 1193 /*
mzta 0:158c61bb030f 1194 * call-seq:
mzta 0:158c61bb030f 1195 * GC.interval_ratio -> fixnum
mzta 0:158c61bb030f 1196 *
mzta 0:158c61bb030f 1197 * Returns ratio of GC interval. Default value is 200(%).
mzta 0:158c61bb030f 1198 *
mzta 0:158c61bb030f 1199 */
mzta 0:158c61bb030f 1200
mzta 0:158c61bb030f 1201 static mrb_value
mzta 0:158c61bb030f 1202 gc_interval_ratio_get(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 1203 {
mzta 0:158c61bb030f 1204 return mrb_fixnum_value(mrb->gc_interval_ratio);
mzta 0:158c61bb030f 1205 }
mzta 0:158c61bb030f 1206
mzta 0:158c61bb030f 1207 /*
mzta 0:158c61bb030f 1208 * call-seq:
mzta 0:158c61bb030f 1209 * GC.interval_ratio = fixnum -> nil
mzta 0:158c61bb030f 1210 *
mzta 0:158c61bb030f 1211 * Updates ratio of GC interval. Default value is 200(%).
mzta 0:158c61bb030f 1212 * GC start as soon as after end all step of GC if you set 100(%).
mzta 0:158c61bb030f 1213 *
mzta 0:158c61bb030f 1214 */
mzta 0:158c61bb030f 1215
mzta 0:158c61bb030f 1216 static mrb_value
mzta 0:158c61bb030f 1217 gc_interval_ratio_set(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 1218 {
mzta 0:158c61bb030f 1219 mrb_int ratio;
mzta 0:158c61bb030f 1220
mzta 0:158c61bb030f 1221 mrb_get_args(mrb, "i", &ratio);
mzta 0:158c61bb030f 1222 mrb->gc_interval_ratio = ratio;
mzta 0:158c61bb030f 1223 return mrb_nil_value();
mzta 0:158c61bb030f 1224 }
mzta 0:158c61bb030f 1225
mzta 0:158c61bb030f 1226 /*
mzta 0:158c61bb030f 1227 * call-seq:
mzta 0:158c61bb030f 1228 * GC.step_ratio -> fixnum
mzta 0:158c61bb030f 1229 *
mzta 0:158c61bb030f 1230 * Returns step span ratio of Incremental GC. Default value is 200(%).
mzta 0:158c61bb030f 1231 *
mzta 0:158c61bb030f 1232 */
mzta 0:158c61bb030f 1233
mzta 0:158c61bb030f 1234 static mrb_value
mzta 0:158c61bb030f 1235 gc_step_ratio_get(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 1236 {
mzta 0:158c61bb030f 1237 return mrb_fixnum_value(mrb->gc_step_ratio);
mzta 0:158c61bb030f 1238 }
mzta 0:158c61bb030f 1239
mzta 0:158c61bb030f 1240 /*
mzta 0:158c61bb030f 1241 * call-seq:
mzta 0:158c61bb030f 1242 * GC.step_ratio = fixnum -> nil
mzta 0:158c61bb030f 1243 *
mzta 0:158c61bb030f 1244 * Updates step span ratio of Incremental GC. Default value is 200(%).
mzta 0:158c61bb030f 1245 * 1 step of incrementalGC becomes long if a rate is big.
mzta 0:158c61bb030f 1246 *
mzta 0:158c61bb030f 1247 */
mzta 0:158c61bb030f 1248
mzta 0:158c61bb030f 1249 static mrb_value
mzta 0:158c61bb030f 1250 gc_step_ratio_set(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 1251 {
mzta 0:158c61bb030f 1252 mrb_int ratio;
mzta 0:158c61bb030f 1253
mzta 0:158c61bb030f 1254 mrb_get_args(mrb, "i", &ratio);
mzta 0:158c61bb030f 1255 mrb->gc_step_ratio = ratio;
mzta 0:158c61bb030f 1256 return mrb_nil_value();
mzta 0:158c61bb030f 1257 }
mzta 0:158c61bb030f 1258
mzta 0:158c61bb030f 1259 static void
mzta 0:158c61bb030f 1260 change_gen_gc_mode(mrb_state *mrb, mrb_bool enable)
mzta 0:158c61bb030f 1261 {
mzta 0:158c61bb030f 1262 if (is_generational(mrb) && !enable) {
mzta 0:158c61bb030f 1263 clear_all_old(mrb);
mzta 0:158c61bb030f 1264 mrb_assert(mrb->gc_state == GC_STATE_ROOT);
mzta 0:158c61bb030f 1265 mrb->gc_full = FALSE;
mzta 0:158c61bb030f 1266 }
mzta 0:158c61bb030f 1267 else if (!is_generational(mrb) && enable) {
mzta 0:158c61bb030f 1268 incremental_gc_until(mrb, GC_STATE_ROOT);
mzta 0:158c61bb030f 1269 mrb->majorgc_old_threshold = mrb->gc_live_after_mark/100 * DEFAULT_MAJOR_GC_INC_RATIO;
mzta 0:158c61bb030f 1270 mrb->gc_full = FALSE;
mzta 0:158c61bb030f 1271 }
mzta 0:158c61bb030f 1272 mrb->is_generational_gc_mode = enable;
mzta 0:158c61bb030f 1273 }
mzta 0:158c61bb030f 1274
mzta 0:158c61bb030f 1275 /*
mzta 0:158c61bb030f 1276 * call-seq:
mzta 0:158c61bb030f 1277 * GC.generational_mode -> true or false
mzta 0:158c61bb030f 1278 *
mzta 0:158c61bb030f 1279 * Returns generational or normal gc mode.
mzta 0:158c61bb030f 1280 *
mzta 0:158c61bb030f 1281 */
mzta 0:158c61bb030f 1282
mzta 0:158c61bb030f 1283 static mrb_value
mzta 0:158c61bb030f 1284 gc_generational_mode_get(mrb_state *mrb, mrb_value self)
mzta 0:158c61bb030f 1285 {
mzta 0:158c61bb030f 1286 return mrb_bool_value(mrb->is_generational_gc_mode);
mzta 0:158c61bb030f 1287 }
mzta 0:158c61bb030f 1288
mzta 0:158c61bb030f 1289 /*
mzta 0:158c61bb030f 1290 * call-seq:
mzta 0:158c61bb030f 1291 * GC.generational_mode = true or false -> true or false
mzta 0:158c61bb030f 1292 *
mzta 0:158c61bb030f 1293 * Changes to generational or normal gc mode.
mzta 0:158c61bb030f 1294 *
mzta 0:158c61bb030f 1295 */
mzta 0:158c61bb030f 1296
mzta 0:158c61bb030f 1297 static mrb_value
mzta 0:158c61bb030f 1298 gc_generational_mode_set(mrb_state *mrb, mrb_value self)
mzta 0:158c61bb030f 1299 {
mzta 0:158c61bb030f 1300 mrb_bool enable;
mzta 0:158c61bb030f 1301
mzta 0:158c61bb030f 1302 mrb_get_args(mrb, "b", &enable);
mzta 0:158c61bb030f 1303 if (mrb->is_generational_gc_mode != enable)
mzta 0:158c61bb030f 1304 change_gen_gc_mode(mrb, enable);
mzta 0:158c61bb030f 1305
mzta 0:158c61bb030f 1306 return mrb_bool_value(enable);
mzta 0:158c61bb030f 1307 }
mzta 0:158c61bb030f 1308
mzta 0:158c61bb030f 1309 void
mzta 0:158c61bb030f 1310 mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data)
mzta 0:158c61bb030f 1311 {
mzta 0:158c61bb030f 1312 struct heap_page* page = mrb->heaps;
mzta 0:158c61bb030f 1313
mzta 0:158c61bb030f 1314 while (page != NULL) {
mzta 0:158c61bb030f 1315 RVALUE *p, *pend;
mzta 0:158c61bb030f 1316
mzta 0:158c61bb030f 1317 p = page->objects;
mzta 0:158c61bb030f 1318 pend = p + MRB_HEAP_PAGE_SIZE;
mzta 0:158c61bb030f 1319 for (;p < pend; p++) {
mzta 0:158c61bb030f 1320 (*callback)(mrb, &p->as.basic, data);
mzta 0:158c61bb030f 1321 }
mzta 0:158c61bb030f 1322
mzta 0:158c61bb030f 1323 page = page->next;
mzta 0:158c61bb030f 1324 }
mzta 0:158c61bb030f 1325 }
mzta 0:158c61bb030f 1326
mzta 0:158c61bb030f 1327 #ifdef GC_TEST
mzta 0:158c61bb030f 1328 #ifdef GC_DEBUG
mzta 0:158c61bb030f 1329 static mrb_value gc_test(mrb_state *, mrb_value);
mzta 0:158c61bb030f 1330 #endif
mzta 0:158c61bb030f 1331 #endif
mzta 0:158c61bb030f 1332
mzta 0:158c61bb030f 1333 void
mzta 0:158c61bb030f 1334 mrb_init_gc(mrb_state *mrb)
mzta 0:158c61bb030f 1335 {
mzta 0:158c61bb030f 1336 struct RClass *gc;
mzta 0:158c61bb030f 1337
mzta 0:158c61bb030f 1338 gc = mrb_define_module(mrb, "GC");
mzta 0:158c61bb030f 1339
mzta 0:158c61bb030f 1340 mrb_define_class_method(mrb, gc, "start", gc_start, MRB_ARGS_NONE());
mzta 0:158c61bb030f 1341 mrb_define_class_method(mrb, gc, "enable", gc_enable, MRB_ARGS_NONE());
mzta 0:158c61bb030f 1342 mrb_define_class_method(mrb, gc, "disable", gc_disable, MRB_ARGS_NONE());
mzta 0:158c61bb030f 1343 mrb_define_class_method(mrb, gc, "interval_ratio", gc_interval_ratio_get, MRB_ARGS_NONE());
mzta 0:158c61bb030f 1344 mrb_define_class_method(mrb, gc, "interval_ratio=", gc_interval_ratio_set, MRB_ARGS_REQ(1));
mzta 0:158c61bb030f 1345 mrb_define_class_method(mrb, gc, "step_ratio", gc_step_ratio_get, MRB_ARGS_NONE());
mzta 0:158c61bb030f 1346 mrb_define_class_method(mrb, gc, "step_ratio=", gc_step_ratio_set, MRB_ARGS_REQ(1));
mzta 0:158c61bb030f 1347 mrb_define_class_method(mrb, gc, "generational_mode=", gc_generational_mode_set, MRB_ARGS_REQ(1));
mzta 0:158c61bb030f 1348 mrb_define_class_method(mrb, gc, "generational_mode", gc_generational_mode_get, MRB_ARGS_NONE());
mzta 0:158c61bb030f 1349 #ifdef GC_TEST
mzta 0:158c61bb030f 1350 #ifdef GC_DEBUG
mzta 0:158c61bb030f 1351 mrb_define_class_method(mrb, gc, "test", gc_test, MRB_ARGS_NONE());
mzta 0:158c61bb030f 1352 #endif
mzta 0:158c61bb030f 1353 #endif
mzta 0:158c61bb030f 1354 }
mzta 0:158c61bb030f 1355
mzta 0:158c61bb030f 1356 #ifdef GC_TEST
mzta 0:158c61bb030f 1357 #ifdef GC_DEBUG
mzta 0:158c61bb030f 1358 void
mzta 0:158c61bb030f 1359 test_mrb_field_write_barrier(void)
mzta 0:158c61bb030f 1360 {
mzta 0:158c61bb030f 1361 mrb_state *mrb = mrb_open();
mzta 0:158c61bb030f 1362 struct RBasic *obj, *value;
mzta 0:158c61bb030f 1363
mzta 0:158c61bb030f 1364 puts("test_mrb_field_write_barrier");
mzta 0:158c61bb030f 1365 mrb->is_generational_gc_mode = FALSE;
mzta 0:158c61bb030f 1366 obj = mrb_basic_ptr(mrb_ary_new(mrb));
mzta 0:158c61bb030f 1367 value = mrb_basic_ptr(mrb_str_new_lit(mrb, "value"));
mzta 0:158c61bb030f 1368 paint_black(obj);
mzta 0:158c61bb030f 1369 paint_partial_white(mrb, value);
mzta 0:158c61bb030f 1370
mzta 0:158c61bb030f 1371
mzta 0:158c61bb030f 1372 puts(" in GC_STATE_MARK");
mzta 0:158c61bb030f 1373 mrb->gc_state = GC_STATE_MARK;
mzta 0:158c61bb030f 1374 mrb_field_write_barrier(mrb, obj, value);
mzta 0:158c61bb030f 1375
mzta 0:158c61bb030f 1376 mrb_assert(is_gray(value));
mzta 0:158c61bb030f 1377
mzta 0:158c61bb030f 1378
mzta 0:158c61bb030f 1379 puts(" in GC_STATE_SWEEP");
mzta 0:158c61bb030f 1380 paint_partial_white(mrb, value);
mzta 0:158c61bb030f 1381 mrb->gc_state = GC_STATE_SWEEP;
mzta 0:158c61bb030f 1382 mrb_field_write_barrier(mrb, obj, value);
mzta 0:158c61bb030f 1383
mzta 0:158c61bb030f 1384 mrb_assert(obj->color & mrb->current_white_part);
mzta 0:158c61bb030f 1385 mrb_assert(value->color & mrb->current_white_part);
mzta 0:158c61bb030f 1386
mzta 0:158c61bb030f 1387
mzta 0:158c61bb030f 1388 puts(" fail with black");
mzta 0:158c61bb030f 1389 mrb->gc_state = GC_STATE_MARK;
mzta 0:158c61bb030f 1390 paint_white(obj);
mzta 0:158c61bb030f 1391 paint_partial_white(mrb, value);
mzta 0:158c61bb030f 1392 mrb_field_write_barrier(mrb, obj, value);
mzta 0:158c61bb030f 1393
mzta 0:158c61bb030f 1394 mrb_assert(obj->color & mrb->current_white_part);
mzta 0:158c61bb030f 1395
mzta 0:158c61bb030f 1396
mzta 0:158c61bb030f 1397 puts(" fail with gray");
mzta 0:158c61bb030f 1398 mrb->gc_state = GC_STATE_MARK;
mzta 0:158c61bb030f 1399 paint_black(obj);
mzta 0:158c61bb030f 1400 paint_gray(value);
mzta 0:158c61bb030f 1401 mrb_field_write_barrier(mrb, obj, value);
mzta 0:158c61bb030f 1402
mzta 0:158c61bb030f 1403 mrb_assert(is_gray(value));
mzta 0:158c61bb030f 1404
mzta 0:158c61bb030f 1405
mzta 0:158c61bb030f 1406 {
mzta 0:158c61bb030f 1407 puts("test_mrb_field_write_barrier_value");
mzta 0:158c61bb030f 1408 obj = mrb_basic_ptr(mrb_ary_new(mrb));
mzta 0:158c61bb030f 1409 mrb_value value = mrb_str_new_lit(mrb, "value");
mzta 0:158c61bb030f 1410 paint_black(obj);
mzta 0:158c61bb030f 1411 paint_partial_white(mrb, mrb_basic_ptr(value));
mzta 0:158c61bb030f 1412
mzta 0:158c61bb030f 1413 mrb->gc_state = GC_STATE_MARK;
mzta 0:158c61bb030f 1414 mrb_field_write_barrier_value(mrb, obj, value);
mzta 0:158c61bb030f 1415
mzta 0:158c61bb030f 1416 mrb_assert(is_gray(mrb_basic_ptr(value)));
mzta 0:158c61bb030f 1417 }
mzta 0:158c61bb030f 1418
mzta 0:158c61bb030f 1419 mrb_close(mrb);
mzta 0:158c61bb030f 1420 }
mzta 0:158c61bb030f 1421
mzta 0:158c61bb030f 1422 void
mzta 0:158c61bb030f 1423 test_mrb_write_barrier(void)
mzta 0:158c61bb030f 1424 {
mzta 0:158c61bb030f 1425 mrb_state *mrb = mrb_open();
mzta 0:158c61bb030f 1426 struct RBasic *obj;
mzta 0:158c61bb030f 1427
mzta 0:158c61bb030f 1428 puts("test_mrb_write_barrier");
mzta 0:158c61bb030f 1429 obj = mrb_basic_ptr(mrb_ary_new(mrb));
mzta 0:158c61bb030f 1430 paint_black(obj);
mzta 0:158c61bb030f 1431
mzta 0:158c61bb030f 1432 puts(" in GC_STATE_MARK");
mzta 0:158c61bb030f 1433 mrb->gc_state = GC_STATE_MARK;
mzta 0:158c61bb030f 1434 mrb_write_barrier(mrb, obj);
mzta 0:158c61bb030f 1435
mzta 0:158c61bb030f 1436 mrb_assert(is_gray(obj));
mzta 0:158c61bb030f 1437 mrb_assert(mrb->atomic_gray_list == obj);
mzta 0:158c61bb030f 1438
mzta 0:158c61bb030f 1439
mzta 0:158c61bb030f 1440 puts(" fail with gray");
mzta 0:158c61bb030f 1441 paint_gray(obj);
mzta 0:158c61bb030f 1442 mrb_write_barrier(mrb, obj);
mzta 0:158c61bb030f 1443
mzta 0:158c61bb030f 1444 mrb_assert(is_gray(obj));
mzta 0:158c61bb030f 1445
mzta 0:158c61bb030f 1446 mrb_close(mrb);
mzta 0:158c61bb030f 1447 }
mzta 0:158c61bb030f 1448
mzta 0:158c61bb030f 1449 void
mzta 0:158c61bb030f 1450 test_add_gray_list(void)
mzta 0:158c61bb030f 1451 {
mzta 0:158c61bb030f 1452 mrb_state *mrb = mrb_open();
mzta 0:158c61bb030f 1453 struct RBasic *obj1, *obj2;
mzta 0:158c61bb030f 1454
mzta 0:158c61bb030f 1455 puts("test_add_gray_list");
mzta 0:158c61bb030f 1456 change_gen_gc_mode(mrb, FALSE);
mzta 0:158c61bb030f 1457 mrb_assert(mrb->gray_list == NULL);
mzta 0:158c61bb030f 1458 obj1 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
mzta 0:158c61bb030f 1459 add_gray_list(mrb, obj1);
mzta 0:158c61bb030f 1460 mrb_assert(mrb->gray_list == obj1);
mzta 0:158c61bb030f 1461 mrb_assert(is_gray(obj1));
mzta 0:158c61bb030f 1462
mzta 0:158c61bb030f 1463 obj2 = mrb_basic_ptr(mrb_str_new_lit(mrb, "test"));
mzta 0:158c61bb030f 1464 add_gray_list(mrb, obj2);
mzta 0:158c61bb030f 1465 mrb_assert(mrb->gray_list == obj2);
mzta 0:158c61bb030f 1466 mrb_assert(mrb->gray_list->gcnext == obj1);
mzta 0:158c61bb030f 1467 mrb_assert(is_gray(obj2));
mzta 0:158c61bb030f 1468
mzta 0:158c61bb030f 1469 mrb_close(mrb);
mzta 0:158c61bb030f 1470 }
mzta 0:158c61bb030f 1471
mzta 0:158c61bb030f 1472 void
mzta 0:158c61bb030f 1473 test_gc_gray_mark(void)
mzta 0:158c61bb030f 1474 {
mzta 0:158c61bb030f 1475 mrb_state *mrb = mrb_open();
mzta 0:158c61bb030f 1476 mrb_value obj_v, value_v;
mzta 0:158c61bb030f 1477 struct RBasic *obj;
mzta 0:158c61bb030f 1478 size_t gray_num = 0;
mzta 0:158c61bb030f 1479
mzta 0:158c61bb030f 1480 puts("test_gc_gray_mark");
mzta 0:158c61bb030f 1481
mzta 0:158c61bb030f 1482 puts(" in MRB_TT_CLASS");
mzta 0:158c61bb030f 1483 obj = (struct RBasic*)mrb->object_class;
mzta 0:158c61bb030f 1484 paint_gray(obj);
mzta 0:158c61bb030f 1485 gray_num = gc_gray_mark(mrb, obj);
mzta 0:158c61bb030f 1486 mrb_assert(is_black(obj));
mzta 0:158c61bb030f 1487 mrb_assert(gray_num > 1);
mzta 0:158c61bb030f 1488
mzta 0:158c61bb030f 1489 puts(" in MRB_TT_ARRAY");
mzta 0:158c61bb030f 1490 obj_v = mrb_ary_new(mrb);
mzta 0:158c61bb030f 1491 value_v = mrb_str_new_lit(mrb, "test");
mzta 0:158c61bb030f 1492 paint_gray(mrb_basic_ptr(obj_v));
mzta 0:158c61bb030f 1493 paint_partial_white(mrb, mrb_basic_ptr(value_v));
mzta 0:158c61bb030f 1494 mrb_ary_push(mrb, obj_v, value_v);
mzta 0:158c61bb030f 1495 gray_num = gc_gray_mark(mrb, mrb_basic_ptr(obj_v));
mzta 0:158c61bb030f 1496 mrb_assert(is_black(mrb_basic_ptr(obj_v)));
mzta 0:158c61bb030f 1497 mrb_assert(is_gray(mrb_basic_ptr(value_v)));
mzta 0:158c61bb030f 1498 mrb_assert(gray_num == 1);
mzta 0:158c61bb030f 1499
mzta 0:158c61bb030f 1500 mrb_close(mrb);
mzta 0:158c61bb030f 1501 }
mzta 0:158c61bb030f 1502
mzta 0:158c61bb030f 1503 void
mzta 0:158c61bb030f 1504 test_incremental_gc(void)
mzta 0:158c61bb030f 1505 {
mzta 0:158c61bb030f 1506 mrb_state *mrb = mrb_open();
mzta 0:158c61bb030f 1507 size_t max = ~0, live = 0, total = 0, freed = 0;
mzta 0:158c61bb030f 1508 RVALUE *free;
mzta 0:158c61bb030f 1509 struct heap_page *page;
mzta 0:158c61bb030f 1510
mzta 0:158c61bb030f 1511 puts("test_incremental_gc");
mzta 0:158c61bb030f 1512 change_gen_gc_mode(mrb, FALSE);
mzta 0:158c61bb030f 1513
mzta 0:158c61bb030f 1514 puts(" in mrb_full_gc");
mzta 0:158c61bb030f 1515 mrb_full_gc(mrb);
mzta 0:158c61bb030f 1516
mzta 0:158c61bb030f 1517 mrb_assert(mrb->gc_state == GC_STATE_ROOT);
mzta 0:158c61bb030f 1518 puts(" in GC_STATE_ROOT");
mzta 0:158c61bb030f 1519 incremental_gc(mrb, max);
mzta 0:158c61bb030f 1520 mrb_assert(mrb->gc_state == GC_STATE_MARK);
mzta 0:158c61bb030f 1521 puts(" in GC_STATE_MARK");
mzta 0:158c61bb030f 1522 incremental_gc_until(mrb, GC_STATE_SWEEP);
mzta 0:158c61bb030f 1523 mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
mzta 0:158c61bb030f 1524
mzta 0:158c61bb030f 1525 puts(" in GC_STATE_SWEEP");
mzta 0:158c61bb030f 1526 page = mrb->heaps;
mzta 0:158c61bb030f 1527 while (page) {
mzta 0:158c61bb030f 1528 RVALUE *p = page->objects;
mzta 0:158c61bb030f 1529 RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
mzta 0:158c61bb030f 1530 while (p<e) {
mzta 0:158c61bb030f 1531 if (is_black(&p->as.basic)) {
mzta 0:158c61bb030f 1532 live++;
mzta 0:158c61bb030f 1533 }
mzta 0:158c61bb030f 1534 if (is_gray(&p->as.basic) && !is_dead(mrb, &p->as.basic)) {
mzta 0:158c61bb030f 1535 printf("%p\n", &p->as.basic);
mzta 0:158c61bb030f 1536 }
mzta 0:158c61bb030f 1537 p++;
mzta 0:158c61bb030f 1538 }
mzta 0:158c61bb030f 1539 page = page->next;
mzta 0:158c61bb030f 1540 total += MRB_HEAP_PAGE_SIZE;
mzta 0:158c61bb030f 1541 }
mzta 0:158c61bb030f 1542
mzta 0:158c61bb030f 1543 mrb_assert(mrb->gray_list == NULL);
mzta 0:158c61bb030f 1544
mzta 0:158c61bb030f 1545 incremental_gc(mrb, max);
mzta 0:158c61bb030f 1546 mrb_assert(mrb->gc_state == GC_STATE_SWEEP);
mzta 0:158c61bb030f 1547
mzta 0:158c61bb030f 1548 incremental_gc(mrb, max);
mzta 0:158c61bb030f 1549 mrb_assert(mrb->gc_state == GC_STATE_ROOT);
mzta 0:158c61bb030f 1550
mzta 0:158c61bb030f 1551 free = (RVALUE*)mrb->heaps->freelist;
mzta 0:158c61bb030f 1552 while (free) {
mzta 0:158c61bb030f 1553 freed++;
mzta 0:158c61bb030f 1554 free = (RVALUE*)free->as.free.next;
mzta 0:158c61bb030f 1555 }
mzta 0:158c61bb030f 1556
mzta 0:158c61bb030f 1557 mrb_assert(mrb->live == live);
mzta 0:158c61bb030f 1558 mrb_assert(mrb->live == total-freed);
mzta 0:158c61bb030f 1559
mzta 0:158c61bb030f 1560 puts("test_incremental_gc(gen)");
mzta 0:158c61bb030f 1561 incremental_gc_until(mrb, GC_STATE_SWEEP);
mzta 0:158c61bb030f 1562 change_gen_gc_mode(mrb, TRUE);
mzta 0:158c61bb030f 1563
mzta 0:158c61bb030f 1564 mrb_assert(mrb->gc_full == FALSE);
mzta 0:158c61bb030f 1565 mrb_assert(mrb->gc_state == GC_STATE_ROOT);
mzta 0:158c61bb030f 1566
mzta 0:158c61bb030f 1567 puts(" in minor");
mzta 0:158c61bb030f 1568 mrb_assert(is_minor_gc(mrb));
mzta 0:158c61bb030f 1569 mrb_assert(mrb->majorgc_old_threshold > 0);
mzta 0:158c61bb030f 1570 mrb->majorgc_old_threshold = 0;
mzta 0:158c61bb030f 1571 mrb_incremental_gc(mrb);
mzta 0:158c61bb030f 1572 mrb_assert(mrb->gc_full == TRUE);
mzta 0:158c61bb030f 1573 mrb_assert(mrb->gc_state == GC_STATE_ROOT);
mzta 0:158c61bb030f 1574
mzta 0:158c61bb030f 1575 puts(" in major");
mzta 0:158c61bb030f 1576 mrb_assert(is_major_gc(mrb));
mzta 0:158c61bb030f 1577 do {
mzta 0:158c61bb030f 1578 mrb_incremental_gc(mrb);
mzta 0:158c61bb030f 1579 } while (mrb->gc_state != GC_STATE_ROOT);
mzta 0:158c61bb030f 1580 mrb_assert(mrb->gc_full == FALSE);
mzta 0:158c61bb030f 1581
mzta 0:158c61bb030f 1582 mrb_close(mrb);
mzta 0:158c61bb030f 1583 }
mzta 0:158c61bb030f 1584
mzta 0:158c61bb030f 1585 void
mzta 0:158c61bb030f 1586 test_incremental_sweep_phase(void)
mzta 0:158c61bb030f 1587 {
mzta 0:158c61bb030f 1588 mrb_state *mrb = mrb_open();
mzta 0:158c61bb030f 1589
mzta 0:158c61bb030f 1590 puts("test_incremental_sweep_phase");
mzta 0:158c61bb030f 1591
mzta 0:158c61bb030f 1592 add_heap(mrb);
mzta 0:158c61bb030f 1593 mrb->sweeps = mrb->heaps;
mzta 0:158c61bb030f 1594
mzta 0:158c61bb030f 1595 mrb_assert(mrb->heaps->next->next == NULL);
mzta 0:158c61bb030f 1596 mrb_assert(mrb->free_heaps->next->next == NULL);
mzta 0:158c61bb030f 1597 incremental_sweep_phase(mrb, MRB_HEAP_PAGE_SIZE*3);
mzta 0:158c61bb030f 1598
mzta 0:158c61bb030f 1599 mrb_assert(mrb->heaps->next == NULL);
mzta 0:158c61bb030f 1600 mrb_assert(mrb->heaps == mrb->free_heaps);
mzta 0:158c61bb030f 1601
mzta 0:158c61bb030f 1602 mrb_close(mrb);
mzta 0:158c61bb030f 1603 }
mzta 0:158c61bb030f 1604
mzta 0:158c61bb030f 1605 static mrb_value
mzta 0:158c61bb030f 1606 gc_test(mrb_state *mrb, mrb_value self)
mzta 0:158c61bb030f 1607 {
mzta 0:158c61bb030f 1608 test_mrb_field_write_barrier();
mzta 0:158c61bb030f 1609 test_mrb_write_barrier();
mzta 0:158c61bb030f 1610 test_add_gray_list();
mzta 0:158c61bb030f 1611 test_gc_gray_mark();
mzta 0:158c61bb030f 1612 test_incremental_gc();
mzta 0:158c61bb030f 1613 test_incremental_sweep_phase();
mzta 0:158c61bb030f 1614 return mrb_nil_value();
mzta 0:158c61bb030f 1615 }
mzta 0:158c61bb030f 1616 #endif /* GC_DEBUG */
mzta 0:158c61bb030f 1617 #endif /* GC_TEST */
mzta 0:158c61bb030f 1618