mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
mbed-mruby
How to use
Class
src/gc.c@0:158c61bb030f, 2015-03-25 (annotated)
- Committer:
- mzta
- Date:
- Wed Mar 25 17:36:16 2015 +0000
- Revision:
- 0:158c61bb030f
mirb_mbed initial commit;
Who changed what in which revision?
User | Revision | Line number | New 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 |