00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "ruby/ruby.h"
00015 #include "ruby/st.h"
00016 #include "ruby/re.h"
00017 #include "ruby/io.h"
00018 #include "ruby/util.h"
00019 #include "eval_intern.h"
00020 #include "vm_core.h"
00021 #include "internal.h"
00022 #include "gc.h"
00023 #include "constant.h"
00024 #include "ruby_atomic.h"
00025 #include <stdio.h>
00026 #include <setjmp.h>
00027 #include <sys/types.h>
00028 #include <assert.h>
00029
00030 #ifdef HAVE_SYS_TIME_H
00031 #include <sys/time.h>
00032 #endif
00033
00034 #ifdef HAVE_SYS_RESOURCE_H
00035 #include <sys/resource.h>
00036 #endif
00037
00038 #if defined _WIN32 || defined __CYGWIN__
00039 #include <windows.h>
00040 #endif
00041
00042 #ifdef HAVE_VALGRIND_MEMCHECK_H
00043 # include <valgrind/memcheck.h>
00044 # ifndef VALGRIND_MAKE_MEM_DEFINED
00045 # define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE((p), (n))
00046 # endif
00047 # ifndef VALGRIND_MAKE_MEM_UNDEFINED
00048 # define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE((p), (n))
00049 # endif
00050 #else
00051 # define VALGRIND_MAKE_MEM_DEFINED(p, n)
00052 # define VALGRIND_MAKE_MEM_UNDEFINED(p, n)
00053 #endif
00054
00055 #define rb_setjmp(env) RUBY_SETJMP(env)
00056 #define rb_jmp_buf rb_jmpbuf_t
00057
00058
00059 #ifdef __GNUC__
00060 # ifndef atarist
00061 # ifndef alloca
00062 # define alloca __builtin_alloca
00063 # endif
00064 # endif
00065 #else
00066 # ifdef HAVE_ALLOCA_H
00067 # include <alloca.h>
00068 # else
00069 # ifdef _AIX
00070 #pragma alloca
00071 # else
00072 # ifndef alloca
00073 void *alloca ();
00074 # endif
00075 # endif
00076 # endif
00077 #endif
00078
00079 #ifndef GC_MALLOC_LIMIT
00080 #define GC_MALLOC_LIMIT 8000000
00081 #endif
00082 #define HEAP_MIN_SLOTS 10000
00083 #define FREE_MIN 4096
00084
00085 typedef struct {
00086 unsigned int initial_malloc_limit;
00087 unsigned int initial_heap_min_slots;
00088 unsigned int initial_free_min;
00089 int gc_stress;
00090 } ruby_gc_params_t;
00091
00092 ruby_gc_params_t initial_params = {
00093 GC_MALLOC_LIMIT,
00094 HEAP_MIN_SLOTS,
00095 FREE_MIN,
00096 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
00097 FALSE,
00098 #endif
00099 };
00100
00101 #define nomem_error GET_VM()->special_exceptions[ruby_error_nomemory]
00102
00103 #if SIZEOF_LONG == SIZEOF_VOIDP
00104 # define nonspecial_obj_id(obj) (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG)
00105 # define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG)
00106 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
00107 # define nonspecial_obj_id(obj) LL2NUM((SIGNED_VALUE)(obj) / 2)
00108 # define obj_id_to_ref(objid) (FIXNUM_P(objid) ? \
00109 ((objid) ^ FIXNUM_FLAG) : (NUM2PTR(objid) << 1))
00110 #else
00111 # error not supported
00112 #endif
00113
00114 int ruby_gc_debug_indent = 0;
00115
00116
00117 #define GC_PROFILE_MORE_DETAIL 0
00118 typedef struct gc_profile_record {
00119 double gc_time;
00120 double gc_mark_time;
00121 double gc_sweep_time;
00122 double gc_invoke_time;
00123
00124 size_t heap_use_slots;
00125 size_t heap_live_objects;
00126 size_t heap_free_objects;
00127 size_t heap_total_objects;
00128 size_t heap_use_size;
00129 size_t heap_total_size;
00130
00131 int have_finalize;
00132 int is_marked;
00133
00134 size_t allocate_increase;
00135 size_t allocate_limit;
00136 } gc_profile_record;
00137
00138 static double
00139 getrusage_time(void)
00140 {
00141 #ifdef RUSAGE_SELF
00142 struct rusage usage;
00143 struct timeval time;
00144 getrusage(RUSAGE_SELF, &usage);
00145 time = usage.ru_utime;
00146 return time.tv_sec + time.tv_usec * 1e-6;
00147 #elif defined _WIN32
00148 FILETIME creation_time, exit_time, kernel_time, user_time;
00149 ULARGE_INTEGER ui;
00150 LONG_LONG q;
00151 double t;
00152
00153 if (GetProcessTimes(GetCurrentProcess(),
00154 &creation_time, &exit_time, &kernel_time, &user_time) == 0)
00155 {
00156 return 0.0;
00157 }
00158 memcpy(&ui, &user_time, sizeof(FILETIME));
00159 q = ui.QuadPart / 10L;
00160 t = (DWORD)(q % 1000000L) * 1e-6;
00161 q /= 1000000L;
00162 #ifdef __GNUC__
00163 t += q;
00164 #else
00165 t += (double)(DWORD)(q >> 16) * (1 << 16);
00166 t += (DWORD)q & ~(~0 << 16);
00167 #endif
00168 return t;
00169 #else
00170 return 0.0;
00171 #endif
00172 }
00173
00174 #define GC_PROF_TIMER_START do {\
00175 if (objspace->profile.run) {\
00176 if (!objspace->profile.record) {\
00177 objspace->profile.size = 1000;\
00178 objspace->profile.record = malloc(sizeof(gc_profile_record) * objspace->profile.size);\
00179 }\
00180 if (count >= objspace->profile.size) {\
00181 objspace->profile.size += 1000;\
00182 objspace->profile.record = realloc(objspace->profile.record, sizeof(gc_profile_record) * objspace->profile.size);\
00183 }\
00184 if (!objspace->profile.record) {\
00185 rb_bug("gc_profile malloc or realloc miss");\
00186 }\
00187 MEMZERO(&objspace->profile.record[count], gc_profile_record, 1);\
00188 gc_time = getrusage_time();\
00189 objspace->profile.record[count].gc_invoke_time = gc_time - objspace->profile.invoke_time;\
00190 }\
00191 } while(0)
00192
00193 #define GC_PROF_TIMER_STOP(marked) do {\
00194 if (objspace->profile.run) {\
00195 gc_time = getrusage_time() - gc_time;\
00196 if (gc_time < 0) gc_time = 0;\
00197 objspace->profile.record[count].gc_time = gc_time;\
00198 objspace->profile.record[count].is_marked = !!(marked);\
00199 GC_PROF_SET_HEAP_INFO(objspace->profile.record[count]);\
00200 objspace->profile.count++;\
00201 }\
00202 } while(0)
00203
00204 #if GC_PROFILE_MORE_DETAIL
00205 #define INIT_GC_PROF_PARAMS double gc_time = 0, sweep_time = 0;\
00206 size_t count = objspace->profile.count, total = 0, live = 0
00207
00208 #define GC_PROF_MARK_TIMER_START double mark_time = 0;\
00209 do {\
00210 if (objspace->profile.run) {\
00211 mark_time = getrusage_time();\
00212 }\
00213 } while(0)
00214
00215 #define GC_PROF_MARK_TIMER_STOP do {\
00216 if (objspace->profile.run) {\
00217 mark_time = getrusage_time() - mark_time;\
00218 if (mark_time < 0) mark_time = 0;\
00219 objspace->profile.record[objspace->profile.count].gc_mark_time = mark_time;\
00220 }\
00221 } while(0)
00222
00223 #define GC_PROF_SWEEP_TIMER_START do {\
00224 if (objspace->profile.run) {\
00225 sweep_time = getrusage_time();\
00226 }\
00227 } while(0)
00228
00229 #define GC_PROF_SWEEP_TIMER_STOP do {\
00230 if (objspace->profile.run) {\
00231 sweep_time = getrusage_time() - sweep_time;\
00232 if (sweep_time < 0) sweep_time = 0;\
00233 objspace->profile.record[count].gc_sweep_time = sweep_time;\
00234 }\
00235 } while(0)
00236 #define GC_PROF_SET_MALLOC_INFO do {\
00237 if (objspace->profile.run) {\
00238 gc_profile_record *record = &objspace->profile.record[objspace->profile.count];\
00239 record->allocate_increase = malloc_increase;\
00240 record->allocate_limit = malloc_limit; \
00241 }\
00242 } while(0)
00243 #define GC_PROF_SET_HEAP_INFO(record) do {\
00244 live = objspace->heap.live_num;\
00245 total = heaps_used * HEAP_OBJ_LIMIT;\
00246 (record).heap_use_slots = heaps_used;\
00247 (record).heap_live_objects = live;\
00248 (record).heap_free_objects = total - live;\
00249 (record).heap_total_objects = total;\
00250 (record).have_finalize = deferred_final_list ? Qtrue : Qfalse;\
00251 (record).heap_use_size = live * sizeof(RVALUE);\
00252 (record).heap_total_size = total * sizeof(RVALUE);\
00253 } while(0)
00254 #define GC_PROF_INC_LIVE_NUM objspace->heap.live_num++
00255 #define GC_PROF_DEC_LIVE_NUM objspace->heap.live_num--
00256 #else
00257 #define INIT_GC_PROF_PARAMS double gc_time = 0;\
00258 size_t count = objspace->profile.count, total = 0, live = 0
00259 #define GC_PROF_MARK_TIMER_START
00260 #define GC_PROF_MARK_TIMER_STOP
00261 #define GC_PROF_SWEEP_TIMER_START
00262 #define GC_PROF_SWEEP_TIMER_STOP
00263 #define GC_PROF_SET_MALLOC_INFO
00264 #define GC_PROF_SET_HEAP_INFO(record) do {\
00265 live = objspace->heap.live_num;\
00266 total = heaps_used * HEAP_OBJ_LIMIT;\
00267 (record).heap_total_objects = total;\
00268 (record).heap_use_size = live * sizeof(RVALUE);\
00269 (record).heap_total_size = total * sizeof(RVALUE);\
00270 } while(0)
00271 #define GC_PROF_INC_LIVE_NUM
00272 #define GC_PROF_DEC_LIVE_NUM
00273 #endif
00274
00275
00276 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
00277 #pragma pack(push, 1)
00278 #endif
00279
00280 typedef struct RVALUE {
00281 union {
00282 struct {
00283 VALUE flags;
00284 struct RVALUE *next;
00285 } free;
00286 struct RBasic basic;
00287 struct RObject object;
00288 struct RClass klass;
00289 struct RFloat flonum;
00290 struct RString string;
00291 struct RArray array;
00292 struct RRegexp regexp;
00293 struct RHash hash;
00294 struct RData data;
00295 struct RTypedData typeddata;
00296 struct RStruct rstruct;
00297 struct RBignum bignum;
00298 struct RFile file;
00299 struct RNode node;
00300 struct RMatch match;
00301 struct RRational rational;
00302 struct RComplex complex;
00303 } as;
00304 #ifdef GC_DEBUG
00305 const char *file;
00306 int line;
00307 #endif
00308 } RVALUE;
00309
00310 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
00311 #pragma pack(pop)
00312 #endif
00313
00314 struct heaps_slot {
00315 void *membase;
00316 RVALUE *slot;
00317 size_t limit;
00318 struct heaps_slot *next;
00319 struct heaps_slot *prev;
00320 };
00321
00322 struct sorted_heaps_slot {
00323 RVALUE *start;
00324 RVALUE *end;
00325 struct heaps_slot *slot;
00326 };
00327
00328 struct gc_list {
00329 VALUE *varptr;
00330 struct gc_list *next;
00331 };
00332
00333 #define STACK_CHUNK_SIZE 500
00334
00335 typedef struct stack_chunk {
00336 VALUE data[STACK_CHUNK_SIZE];
00337 struct stack_chunk *next;
00338 } stack_chunk_t;
00339
00340 typedef struct mark_stack {
00341 stack_chunk_t *chunk;
00342 stack_chunk_t *cache;
00343 size_t index;
00344 size_t limit;
00345 size_t cache_size;
00346 size_t unused_cache_size;
00347 } mark_stack_t;
00348
00349 #define CALC_EXACT_MALLOC_SIZE 0
00350
00351 typedef struct rb_objspace {
00352 struct {
00353 size_t limit;
00354 size_t increase;
00355 #if CALC_EXACT_MALLOC_SIZE
00356 size_t allocated_size;
00357 size_t allocations;
00358 #endif
00359 } malloc_params;
00360 struct {
00361 size_t increment;
00362 struct heaps_slot *ptr;
00363 struct heaps_slot *sweep_slots;
00364 struct sorted_heaps_slot *sorted;
00365 size_t length;
00366 size_t used;
00367 RVALUE *freelist;
00368 RVALUE *range[2];
00369 RVALUE *freed;
00370 size_t live_num;
00371 size_t free_num;
00372 size_t free_min;
00373 size_t final_num;
00374 size_t do_heap_free;
00375 } heap;
00376 struct {
00377 int dont_gc;
00378 int dont_lazy_sweep;
00379 int during_gc;
00380 rb_atomic_t finalizing;
00381 } flags;
00382 struct {
00383 st_table *table;
00384 RVALUE *deferred;
00385 } final;
00386 mark_stack_t mark_stack;
00387 struct {
00388 int run;
00389 gc_profile_record *record;
00390 size_t count;
00391 size_t size;
00392 double invoke_time;
00393 } profile;
00394 struct gc_list *global_list;
00395 size_t count;
00396 int gc_stress;
00397 } rb_objspace_t;
00398
00399 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
00400 #define rb_objspace (*GET_VM()->objspace)
00401 #define ruby_initial_gc_stress initial_params.gc_stress
00402 int *ruby_initial_gc_stress_ptr = &ruby_initial_gc_stress;
00403 #else
00404 static rb_objspace_t rb_objspace = {{GC_MALLOC_LIMIT}, {HEAP_MIN_SLOTS}};
00405 int *ruby_initial_gc_stress_ptr = &rb_objspace.gc_stress;
00406 #endif
00407 #define malloc_limit objspace->malloc_params.limit
00408 #define malloc_increase objspace->malloc_params.increase
00409 #define heaps objspace->heap.ptr
00410 #define heaps_length objspace->heap.length
00411 #define heaps_used objspace->heap.used
00412 #define freelist objspace->heap.freelist
00413 #define lomem objspace->heap.range[0]
00414 #define himem objspace->heap.range[1]
00415 #define heaps_inc objspace->heap.increment
00416 #define heaps_freed objspace->heap.freed
00417 #define dont_gc objspace->flags.dont_gc
00418 #define during_gc objspace->flags.during_gc
00419 #define finalizing objspace->flags.finalizing
00420 #define finalizer_table objspace->final.table
00421 #define deferred_final_list objspace->final.deferred
00422 #define global_List objspace->global_list
00423 #define ruby_gc_stress objspace->gc_stress
00424 #define initial_malloc_limit initial_params.initial_malloc_limit
00425 #define initial_heap_min_slots initial_params.initial_heap_min_slots
00426 #define initial_free_min initial_params.initial_free_min
00427
00428 static void rb_objspace_call_finalizer(rb_objspace_t *objspace);
00429
00430 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
00431 rb_objspace_t *
00432 rb_objspace_alloc(void)
00433 {
00434 rb_objspace_t *objspace = malloc(sizeof(rb_objspace_t));
00435 memset(objspace, 0, sizeof(*objspace));
00436 malloc_limit = initial_malloc_limit;
00437 ruby_gc_stress = ruby_initial_gc_stress;
00438
00439 return objspace;
00440 }
00441 #endif
00442
00443 static void initial_expand_heap(rb_objspace_t *objspace);
00444 static void init_mark_stack(mark_stack_t *stack);
00445
00446 void
00447 rb_gc_set_params(void)
00448 {
00449 char *malloc_limit_ptr, *heap_min_slots_ptr, *free_min_ptr;
00450
00451 if (rb_safe_level() > 0) return;
00452
00453 malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
00454 if (malloc_limit_ptr != NULL) {
00455 int malloc_limit_i = atoi(malloc_limit_ptr);
00456 if (RTEST(ruby_verbose))
00457 fprintf(stderr, "malloc_limit=%d (%d)\n",
00458 malloc_limit_i, initial_malloc_limit);
00459 if (malloc_limit_i > 0) {
00460 initial_malloc_limit = malloc_limit_i;
00461 }
00462 }
00463
00464 heap_min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
00465 if (heap_min_slots_ptr != NULL) {
00466 int heap_min_slots_i = atoi(heap_min_slots_ptr);
00467 if (RTEST(ruby_verbose))
00468 fprintf(stderr, "heap_min_slots=%d (%d)\n",
00469 heap_min_slots_i, initial_heap_min_slots);
00470 if (heap_min_slots_i > 0) {
00471 initial_heap_min_slots = heap_min_slots_i;
00472 initial_expand_heap(&rb_objspace);
00473 }
00474 }
00475
00476 free_min_ptr = getenv("RUBY_FREE_MIN");
00477 if (free_min_ptr != NULL) {
00478 int free_min_i = atoi(free_min_ptr);
00479 if (RTEST(ruby_verbose))
00480 fprintf(stderr, "free_min=%d (%d)\n", free_min_i, initial_free_min);
00481 if (free_min_i > 0) {
00482 initial_free_min = free_min_i;
00483 }
00484 }
00485 }
00486
00487 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
00488 static void gc_sweep(rb_objspace_t *);
00489 static void slot_sweep(rb_objspace_t *, struct heaps_slot *);
00490 static void rest_sweep(rb_objspace_t *);
00491 static void free_stack_chunks(mark_stack_t *);
00492
00493 void
00494 rb_objspace_free(rb_objspace_t *objspace)
00495 {
00496 rest_sweep(objspace);
00497 if (objspace->profile.record) {
00498 free(objspace->profile.record);
00499 objspace->profile.record = 0;
00500 }
00501 if (global_List) {
00502 struct gc_list *list, *next;
00503 for (list = global_List; list; list = next) {
00504 next = list->next;
00505 free(list);
00506 }
00507 }
00508 if (objspace->heap.sorted) {
00509 size_t i;
00510 for (i = 0; i < heaps_used; ++i) {
00511 free(objspace->heap.sorted[i].slot->membase);
00512 free(objspace->heap.sorted[i].slot);
00513 }
00514 free(objspace->heap.sorted);
00515 heaps_used = 0;
00516 heaps = 0;
00517 }
00518 free_stack_chunks(&objspace->mark_stack);
00519 free(objspace);
00520 }
00521 #endif
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 #define HEAP_SIZE 0x4000
00532
00533
00534
00535
00536
00537
00538
00539 #define HEAP_OBJ_LIMIT (unsigned int)(HEAP_SIZE / sizeof(struct RVALUE))
00540
00541 extern st_table *rb_class_tbl;
00542
00543 int ruby_disable_gc_stress = 0;
00544
00545 static void run_final(rb_objspace_t *objspace, VALUE obj);
00546 static int garbage_collect(rb_objspace_t *objspace);
00547 static int gc_lazy_sweep(rb_objspace_t *objspace);
00548
00549 void
00550 rb_global_variable(VALUE *var)
00551 {
00552 rb_gc_register_address(var);
00553 }
00554
00555 static void *
00556 ruby_memerror_body(void *dummy)
00557 {
00558 rb_memerror();
00559 return 0;
00560 }
00561
00562 static void
00563 ruby_memerror(void)
00564 {
00565 if (ruby_thread_has_gvl_p()) {
00566 rb_memerror();
00567 }
00568 else {
00569 if (ruby_native_thread_p()) {
00570 rb_thread_call_with_gvl(ruby_memerror_body, 0);
00571 }
00572 else {
00573
00574 fprintf(stderr, "[FATAL] failed to allocate memory\n");
00575 exit(EXIT_FAILURE);
00576 }
00577 }
00578 }
00579
00580 void
00581 rb_memerror(void)
00582 {
00583 rb_thread_t *th = GET_THREAD();
00584 if (!nomem_error ||
00585 (rb_thread_raised_p(th, RAISED_NOMEMORY) && rb_safe_level() < 4)) {
00586 fprintf(stderr, "[FATAL] failed to allocate memory\n");
00587 exit(EXIT_FAILURE);
00588 }
00589 if (rb_thread_raised_p(th, RAISED_NOMEMORY)) {
00590 rb_thread_raised_clear(th);
00591 GET_THREAD()->errinfo = nomem_error;
00592 JUMP_TAG(TAG_RAISE);
00593 }
00594 rb_thread_raised_set(th, RAISED_NOMEMORY);
00595 rb_exc_raise(nomem_error);
00596 }
00597
00598
00599
00600
00601
00602
00603
00604
00605 static VALUE
00606 gc_stress_get(VALUE self)
00607 {
00608 rb_objspace_t *objspace = &rb_objspace;
00609 return ruby_gc_stress ? Qtrue : Qfalse;
00610 }
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 static VALUE
00625 gc_stress_set(VALUE self, VALUE flag)
00626 {
00627 rb_objspace_t *objspace = &rb_objspace;
00628 rb_secure(2);
00629 ruby_gc_stress = RTEST(flag);
00630 return flag;
00631 }
00632
00633
00634
00635
00636
00637
00638
00639
00640 static VALUE
00641 gc_profile_enable_get(VALUE self)
00642 {
00643 rb_objspace_t *objspace = &rb_objspace;
00644 return objspace->profile.run ? Qtrue : Qfalse;
00645 }
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 static VALUE
00656 gc_profile_enable(void)
00657 {
00658 rb_objspace_t *objspace = &rb_objspace;
00659
00660 objspace->profile.run = TRUE;
00661 return Qnil;
00662 }
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672 static VALUE
00673 gc_profile_disable(void)
00674 {
00675 rb_objspace_t *objspace = &rb_objspace;
00676
00677 objspace->profile.run = FALSE;
00678 return Qnil;
00679 }
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689 static VALUE
00690 gc_profile_clear(void)
00691 {
00692 rb_objspace_t *objspace = &rb_objspace;
00693 MEMZERO(objspace->profile.record, gc_profile_record, objspace->profile.size);
00694 objspace->profile.count = 0;
00695 return Qnil;
00696 }
00697
00698 static void *
00699 negative_size_allocation_error_with_gvl(void *ptr)
00700 {
00701 rb_raise(rb_eNoMemError, "%s", (const char *)ptr);
00702 return 0;
00703 }
00704
00705 static void
00706 negative_size_allocation_error(const char *msg)
00707 {
00708 if (ruby_thread_has_gvl_p()) {
00709 rb_raise(rb_eNoMemError, "%s", msg);
00710 }
00711 else {
00712 if (ruby_native_thread_p()) {
00713 rb_thread_call_with_gvl(negative_size_allocation_error_with_gvl, (void *)msg);
00714 }
00715 else {
00716 fprintf(stderr, "[FATAL] %s\n", msg);
00717 exit(EXIT_FAILURE);
00718 }
00719 }
00720 }
00721
00722 static void *
00723 gc_with_gvl(void *ptr)
00724 {
00725 return (void *)(VALUE)garbage_collect((rb_objspace_t *)ptr);
00726 }
00727
00728 static int
00729 garbage_collect_with_gvl(rb_objspace_t *objspace)
00730 {
00731 if (dont_gc) return TRUE;
00732 if (ruby_thread_has_gvl_p()) {
00733 return garbage_collect(objspace);
00734 }
00735 else {
00736 if (ruby_native_thread_p()) {
00737 return (int)(VALUE)rb_thread_call_with_gvl(gc_with_gvl, (void *)objspace);
00738 }
00739 else {
00740
00741 fprintf(stderr, "[FATAL] failed to allocate memory\n");
00742 exit(EXIT_FAILURE);
00743 }
00744 }
00745 }
00746
00747 static void vm_xfree(rb_objspace_t *objspace, void *ptr);
00748
00749 static inline size_t
00750 vm_malloc_prepare(rb_objspace_t *objspace, size_t size)
00751 {
00752 if ((ssize_t)size < 0) {
00753 negative_size_allocation_error("negative allocation size (or too big)");
00754 }
00755 if (size == 0) size = 1;
00756
00757 #if CALC_EXACT_MALLOC_SIZE
00758 size += sizeof(size_t);
00759 #endif
00760
00761 if ((ruby_gc_stress && !ruby_disable_gc_stress) ||
00762 (malloc_increase+size) > malloc_limit) {
00763 garbage_collect_with_gvl(objspace);
00764 }
00765
00766 return size;
00767 }
00768
00769 static inline void *
00770 vm_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
00771 {
00772 malloc_increase += size;
00773
00774 #if CALC_EXACT_MALLOC_SIZE
00775 objspace->malloc_params.allocated_size += size;
00776 objspace->malloc_params.allocations++;
00777 ((size_t *)mem)[0] = size;
00778 mem = (size_t *)mem + 1;
00779 #endif
00780
00781 return mem;
00782 }
00783
00784 #define TRY_WITH_GC(alloc) do { \
00785 if (!(alloc) && \
00786 (!garbage_collect_with_gvl(objspace) || \
00787 !(alloc))) { \
00788 ruby_memerror(); \
00789 } \
00790 } while (0)
00791
00792 static void *
00793 vm_xmalloc(rb_objspace_t *objspace, size_t size)
00794 {
00795 void *mem;
00796
00797 size = vm_malloc_prepare(objspace, size);
00798 TRY_WITH_GC(mem = malloc(size));
00799 return vm_malloc_fixup(objspace, mem, size);
00800 }
00801
00802 static void *
00803 vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size)
00804 {
00805 void *mem;
00806
00807 if ((ssize_t)size < 0) {
00808 negative_size_allocation_error("negative re-allocation size");
00809 }
00810 if (!ptr) return vm_xmalloc(objspace, size);
00811 if (size == 0) {
00812 vm_xfree(objspace, ptr);
00813 return 0;
00814 }
00815 if (ruby_gc_stress && !ruby_disable_gc_stress)
00816 garbage_collect_with_gvl(objspace);
00817
00818 #if CALC_EXACT_MALLOC_SIZE
00819 size += sizeof(size_t);
00820 objspace->malloc_params.allocated_size -= size;
00821 ptr = (size_t *)ptr - 1;
00822 #endif
00823
00824 mem = realloc(ptr, size);
00825 if (!mem) {
00826 if (garbage_collect_with_gvl(objspace)) {
00827 mem = realloc(ptr, size);
00828 }
00829 if (!mem) {
00830 ruby_memerror();
00831 }
00832 }
00833 malloc_increase += size;
00834
00835 #if CALC_EXACT_MALLOC_SIZE
00836 objspace->malloc_params.allocated_size += size;
00837 ((size_t *)mem)[0] = size;
00838 mem = (size_t *)mem + 1;
00839 #endif
00840
00841 return mem;
00842 }
00843
00844 static void
00845 vm_xfree(rb_objspace_t *objspace, void *ptr)
00846 {
00847 #if CALC_EXACT_MALLOC_SIZE
00848 size_t size;
00849 ptr = ((size_t *)ptr) - 1;
00850 size = ((size_t*)ptr)[0];
00851 objspace->malloc_params.allocated_size -= size;
00852 objspace->malloc_params.allocations--;
00853 #endif
00854
00855 free(ptr);
00856 }
00857
00858 void *
00859 ruby_xmalloc(size_t size)
00860 {
00861 return vm_xmalloc(&rb_objspace, size);
00862 }
00863
00864 static inline size_t
00865 xmalloc2_size(size_t n, size_t size)
00866 {
00867 size_t len = size * n;
00868 if (n != 0 && size != len / n) {
00869 rb_raise(rb_eArgError, "malloc: possible integer overflow");
00870 }
00871 return len;
00872 }
00873
00874 void *
00875 ruby_xmalloc2(size_t n, size_t size)
00876 {
00877 return vm_xmalloc(&rb_objspace, xmalloc2_size(n, size));
00878 }
00879
00880 static void *
00881 vm_xcalloc(rb_objspace_t *objspace, size_t count, size_t elsize)
00882 {
00883 void *mem;
00884 size_t size;
00885
00886 size = xmalloc2_size(count, elsize);
00887 size = vm_malloc_prepare(objspace, size);
00888
00889 TRY_WITH_GC(mem = calloc(1, size));
00890 return vm_malloc_fixup(objspace, mem, size);
00891 }
00892
00893 void *
00894 ruby_xcalloc(size_t n, size_t size)
00895 {
00896 return vm_xcalloc(&rb_objspace, n, size);
00897 }
00898
00899 void *
00900 ruby_xrealloc(void *ptr, size_t size)
00901 {
00902 return vm_xrealloc(&rb_objspace, ptr, size);
00903 }
00904
00905 void *
00906 ruby_xrealloc2(void *ptr, size_t n, size_t size)
00907 {
00908 size_t len = size * n;
00909 if (n != 0 && size != len / n) {
00910 rb_raise(rb_eArgError, "realloc: possible integer overflow");
00911 }
00912 return ruby_xrealloc(ptr, len);
00913 }
00914
00915 void
00916 ruby_xfree(void *x)
00917 {
00918 if (x)
00919 vm_xfree(&rb_objspace, x);
00920 }
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936 VALUE
00937 rb_gc_enable(void)
00938 {
00939 rb_objspace_t *objspace = &rb_objspace;
00940 int old = dont_gc;
00941
00942 dont_gc = FALSE;
00943 return old ? Qtrue : Qfalse;
00944 }
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958 VALUE
00959 rb_gc_disable(void)
00960 {
00961 rb_objspace_t *objspace = &rb_objspace;
00962 int old = dont_gc;
00963
00964 dont_gc = TRUE;
00965 return old ? Qtrue : Qfalse;
00966 }
00967
00968 VALUE rb_mGC;
00969
00970 void
00971 rb_gc_register_mark_object(VALUE obj)
00972 {
00973 VALUE ary = GET_THREAD()->vm->mark_object_ary;
00974 rb_ary_push(ary, obj);
00975 }
00976
00977 void
00978 rb_gc_register_address(VALUE *addr)
00979 {
00980 rb_objspace_t *objspace = &rb_objspace;
00981 struct gc_list *tmp;
00982
00983 tmp = ALLOC(struct gc_list);
00984 tmp->next = global_List;
00985 tmp->varptr = addr;
00986 global_List = tmp;
00987 }
00988
00989 void
00990 rb_gc_unregister_address(VALUE *addr)
00991 {
00992 rb_objspace_t *objspace = &rb_objspace;
00993 struct gc_list *tmp = global_List;
00994
00995 if (tmp->varptr == addr) {
00996 global_List = tmp->next;
00997 xfree(tmp);
00998 return;
00999 }
01000 while (tmp->next) {
01001 if (tmp->next->varptr == addr) {
01002 struct gc_list *t = tmp->next;
01003
01004 tmp->next = tmp->next->next;
01005 xfree(t);
01006 break;
01007 }
01008 tmp = tmp->next;
01009 }
01010 }
01011
01012
01013 static void
01014 allocate_sorted_heaps(rb_objspace_t *objspace, size_t next_heaps_length)
01015 {
01016 struct sorted_heaps_slot *p;
01017 size_t size;
01018
01019 size = next_heaps_length*sizeof(struct sorted_heaps_slot);
01020
01021 if (heaps_used > 0) {
01022 p = (struct sorted_heaps_slot *)realloc(objspace->heap.sorted, size);
01023 if (p) objspace->heap.sorted = p;
01024 }
01025 else {
01026 p = objspace->heap.sorted = (struct sorted_heaps_slot *)malloc(size);
01027 }
01028
01029 if (p == 0) {
01030 during_gc = 0;
01031 rb_memerror();
01032 }
01033 heaps_length = next_heaps_length;
01034 }
01035
01036 static void
01037 assign_heap_slot(rb_objspace_t *objspace)
01038 {
01039 RVALUE *p, *pend, *membase;
01040 struct heaps_slot *slot;
01041 size_t hi, lo, mid;
01042 size_t objs;
01043
01044 objs = HEAP_OBJ_LIMIT;
01045 p = (RVALUE*)malloc(HEAP_SIZE);
01046 if (p == 0) {
01047 during_gc = 0;
01048 rb_memerror();
01049 }
01050 slot = (struct heaps_slot *)malloc(sizeof(struct heaps_slot));
01051 if (slot == 0) {
01052 xfree(p);
01053 during_gc = 0;
01054 rb_memerror();
01055 }
01056 MEMZERO((void*)slot, struct heaps_slot, 1);
01057
01058 slot->next = heaps;
01059 if (heaps) heaps->prev = slot;
01060 heaps = slot;
01061
01062 membase = p;
01063 if ((VALUE)p % sizeof(RVALUE) != 0) {
01064 p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
01065 if ((HEAP_SIZE - HEAP_OBJ_LIMIT * sizeof(RVALUE)) < (size_t)((char*)p - (char*)membase)) {
01066 objs--;
01067 }
01068 }
01069
01070 lo = 0;
01071 hi = heaps_used;
01072 while (lo < hi) {
01073 register RVALUE *mid_membase;
01074 mid = (lo + hi) / 2;
01075 mid_membase = objspace->heap.sorted[mid].slot->membase;
01076 if (mid_membase < membase) {
01077 lo = mid + 1;
01078 }
01079 else if (mid_membase > membase) {
01080 hi = mid;
01081 }
01082 else {
01083 rb_bug("same heap slot is allocated: %p at %"PRIuVALUE, (void *)membase, (VALUE)mid);
01084 }
01085 }
01086 if (hi < heaps_used) {
01087 MEMMOVE(&objspace->heap.sorted[hi+1], &objspace->heap.sorted[hi], struct sorted_heaps_slot, heaps_used - hi);
01088 }
01089 objspace->heap.sorted[hi].slot = slot;
01090 objspace->heap.sorted[hi].start = p;
01091 objspace->heap.sorted[hi].end = (p + objs);
01092 heaps->membase = membase;
01093 heaps->slot = p;
01094 heaps->limit = objs;
01095 objspace->heap.free_num += objs;
01096 pend = p + objs;
01097 if (lomem == 0 || lomem > p) lomem = p;
01098 if (himem < pend) himem = pend;
01099 heaps_used++;
01100
01101 while (p < pend) {
01102 p->as.free.flags = 0;
01103 p->as.free.next = freelist;
01104 freelist = p;
01105 p++;
01106 }
01107 }
01108
01109 static void
01110 add_heap_slots(rb_objspace_t *objspace, size_t add)
01111 {
01112 size_t i;
01113
01114 if ((heaps_used + add) > heaps_length) {
01115 allocate_sorted_heaps(objspace, heaps_used + add);
01116 }
01117
01118 for (i = 0; i < add; i++) {
01119 assign_heap_slot(objspace);
01120 }
01121 heaps_inc = 0;
01122 }
01123
01124 static void
01125 init_heap(rb_objspace_t *objspace)
01126 {
01127 add_heap_slots(objspace, HEAP_MIN_SLOTS / HEAP_OBJ_LIMIT);
01128 init_mark_stack(&objspace->mark_stack);
01129 #ifdef USE_SIGALTSTACK
01130 {
01131
01132 rb_thread_t *th = GET_THREAD();
01133 void *tmp = th->altstack;
01134 th->altstack = malloc(ALT_STACK_SIZE);
01135 free(tmp);
01136 }
01137 #endif
01138
01139 objspace->profile.invoke_time = getrusage_time();
01140 finalizer_table = st_init_numtable();
01141 }
01142
01143 static void
01144 initial_expand_heap(rb_objspace_t *objspace)
01145 {
01146 size_t min_size = initial_heap_min_slots / HEAP_OBJ_LIMIT;
01147
01148 if (min_size > heaps_used) {
01149 add_heap_slots(objspace, min_size - heaps_used);
01150 }
01151 }
01152
01153 static void
01154 set_heaps_increment(rb_objspace_t *objspace)
01155 {
01156 size_t next_heaps_length = (size_t)(heaps_used * 1.8);
01157
01158 if (next_heaps_length == heaps_used) {
01159 next_heaps_length++;
01160 }
01161
01162 heaps_inc = next_heaps_length - heaps_used;
01163
01164 if (next_heaps_length > heaps_length) {
01165 allocate_sorted_heaps(objspace, next_heaps_length);
01166 }
01167 }
01168
01169 static int
01170 heaps_increment(rb_objspace_t *objspace)
01171 {
01172 if (heaps_inc > 0) {
01173 assign_heap_slot(objspace);
01174 heaps_inc--;
01175 return TRUE;
01176 }
01177 return FALSE;
01178 }
01179
01180 int
01181 rb_during_gc(void)
01182 {
01183 rb_objspace_t *objspace = &rb_objspace;
01184 return during_gc;
01185 }
01186
01187 #define RANY(o) ((RVALUE*)(o))
01188
01189 VALUE
01190 rb_newobj(void)
01191 {
01192 rb_objspace_t *objspace = &rb_objspace;
01193 VALUE obj;
01194
01195 if (UNLIKELY(during_gc)) {
01196 dont_gc = 1;
01197 during_gc = 0;
01198 rb_bug("object allocation during garbage collection phase");
01199 }
01200
01201 if (UNLIKELY(ruby_gc_stress && !ruby_disable_gc_stress)) {
01202 if (!garbage_collect(objspace)) {
01203 during_gc = 0;
01204 rb_memerror();
01205 }
01206 }
01207
01208 if (UNLIKELY(!freelist)) {
01209 if (!gc_lazy_sweep(objspace)) {
01210 during_gc = 0;
01211 rb_memerror();
01212 }
01213 }
01214
01215 obj = (VALUE)freelist;
01216 freelist = freelist->as.free.next;
01217
01218 MEMZERO((void*)obj, RVALUE, 1);
01219 #ifdef GC_DEBUG
01220 RANY(obj)->file = rb_sourcefile();
01221 RANY(obj)->line = rb_sourceline();
01222 #endif
01223 GC_PROF_INC_LIVE_NUM;
01224
01225 return obj;
01226 }
01227
01228 NODE*
01229 rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
01230 {
01231 NODE *n = (NODE*)rb_newobj();
01232
01233 n->flags |= T_NODE;
01234 nd_set_type(n, type);
01235
01236 n->u1.value = a0;
01237 n->u2.value = a1;
01238 n->u3.value = a2;
01239
01240 return n;
01241 }
01242
01243 VALUE
01244 rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
01245 {
01246 NEWOBJ(data, struct RData);
01247 if (klass) Check_Type(klass, T_CLASS);
01248 OBJSETUP(data, klass, T_DATA);
01249 data->data = datap;
01250 data->dfree = dfree;
01251 data->dmark = dmark;
01252
01253 return (VALUE)data;
01254 }
01255
01256 VALUE
01257 rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type)
01258 {
01259 NEWOBJ(data, struct RTypedData);
01260
01261 if (klass) Check_Type(klass, T_CLASS);
01262
01263 OBJSETUP(data, klass, T_DATA);
01264
01265 data->data = datap;
01266 data->typed_flag = 1;
01267 data->type = type;
01268
01269 return (VALUE)data;
01270 }
01271
01272 size_t
01273 rb_objspace_data_type_memsize(VALUE obj)
01274 {
01275 if (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj)->function.dsize) {
01276 return RTYPEDDATA_TYPE(obj)->function.dsize(RTYPEDDATA_DATA(obj));
01277 }
01278 else {
01279 return 0;
01280 }
01281 }
01282
01283 const char *
01284 rb_objspace_data_type_name(VALUE obj)
01285 {
01286 if (RTYPEDDATA_P(obj)) {
01287 return RTYPEDDATA_TYPE(obj)->wrap_struct_name;
01288 }
01289 else {
01290 return 0;
01291 }
01292 }
01293
01294 #ifdef __ia64
01295 #define SET_STACK_END (SET_MACHINE_STACK_END(&th->machine_stack_end), th->machine_register_stack_end = rb_ia64_bsp())
01296 #else
01297 #define SET_STACK_END SET_MACHINE_STACK_END(&th->machine_stack_end)
01298 #endif
01299
01300 #define STACK_START (th->machine_stack_start)
01301 #define STACK_END (th->machine_stack_end)
01302 #define STACK_LEVEL_MAX (th->machine_stack_maxsize/sizeof(VALUE))
01303
01304 #if STACK_GROW_DIRECTION < 0
01305 # define STACK_LENGTH (size_t)(STACK_START - STACK_END)
01306 #elif STACK_GROW_DIRECTION > 0
01307 # define STACK_LENGTH (size_t)(STACK_END - STACK_START + 1)
01308 #else
01309 # define STACK_LENGTH ((STACK_END < STACK_START) ? (size_t)(STACK_START - STACK_END) \
01310 : (size_t)(STACK_END - STACK_START + 1))
01311 #endif
01312 #if !STACK_GROW_DIRECTION
01313 int ruby_stack_grow_direction;
01314 int
01315 ruby_get_stack_grow_direction(volatile VALUE *addr)
01316 {
01317 VALUE *end;
01318 SET_MACHINE_STACK_END(&end);
01319
01320 if (end > addr) return ruby_stack_grow_direction = 1;
01321 return ruby_stack_grow_direction = -1;
01322 }
01323 #endif
01324
01325
01326
01327 static void push_mark_stack(mark_stack_t *, VALUE);
01328 static int pop_mark_stack(mark_stack_t *, VALUE *);
01329 static void shrink_stack_chunk_cache(mark_stack_t *stack);
01330
01331 static stack_chunk_t *
01332 stack_chunk_alloc(void)
01333 {
01334 stack_chunk_t *res;
01335
01336 res = malloc(sizeof(stack_chunk_t));
01337 if (!res)
01338 rb_memerror();
01339
01340 return res;
01341 }
01342
01343 static inline int
01344 is_mark_stask_empty(mark_stack_t *stack)
01345 {
01346 return stack->chunk == NULL;
01347 }
01348
01349 static void
01350 add_stack_chunk_cache(mark_stack_t *stack, stack_chunk_t *chunk)
01351 {
01352 chunk->next = stack->cache;
01353 stack->cache = chunk;
01354 stack->cache_size++;
01355 }
01356
01357 static void
01358 shrink_stack_chunk_cache(mark_stack_t *stack)
01359 {
01360 stack_chunk_t *chunk;
01361
01362 if (stack->unused_cache_size > (stack->cache_size/2)) {
01363 chunk = stack->cache;
01364 stack->cache = stack->cache->next;
01365 stack->cache_size--;
01366 free(chunk);
01367 }
01368 stack->unused_cache_size = stack->cache_size;
01369 }
01370
01371 static void
01372 push_mark_stack_chunk(mark_stack_t *stack)
01373 {
01374 stack_chunk_t *next;
01375
01376 if (stack->cache_size > 0) {
01377 next = stack->cache;
01378 stack->cache = stack->cache->next;
01379 stack->cache_size--;
01380 if (stack->unused_cache_size > stack->cache_size)
01381 stack->unused_cache_size = stack->cache_size;
01382 }
01383 else {
01384 next = stack_chunk_alloc();
01385 }
01386 next->next = stack->chunk;
01387 stack->chunk = next;
01388 stack->index = 0;
01389 }
01390
01391 static void
01392 pop_mark_stack_chunk(mark_stack_t *stack)
01393 {
01394 stack_chunk_t *prev;
01395
01396 prev = stack->chunk->next;
01397 add_stack_chunk_cache(stack, stack->chunk);
01398 stack->chunk = prev;
01399 stack->index = stack->limit;
01400 }
01401
01402 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
01403 static void
01404 free_stack_chunks(mark_stack_t *stack)
01405 {
01406 stack_chunk_t *chunk = stack->chunk;
01407 stack_chunk_t *next = NULL;
01408
01409 while (chunk != NULL) {
01410 next = chunk->next;
01411 free(chunk);
01412 chunk = next;
01413 }
01414 }
01415 #endif
01416
01417 static void
01418 push_mark_stack(mark_stack_t *stack, VALUE data)
01419 {
01420 if (stack->index == stack->limit) {
01421 push_mark_stack_chunk(stack);
01422 }
01423 stack->chunk->data[stack->index++] = data;
01424 }
01425
01426 static int
01427 pop_mark_stack(mark_stack_t *stack, VALUE *data)
01428 {
01429 if (is_mark_stask_empty(stack)) {
01430 return FALSE;
01431 }
01432 if (stack->index == 1) {
01433 *data = stack->chunk->data[--stack->index];
01434 pop_mark_stack_chunk(stack);
01435 return TRUE;
01436 }
01437 *data = stack->chunk->data[--stack->index];
01438 return TRUE;
01439 }
01440
01441 static void
01442 init_mark_stack(mark_stack_t *stack)
01443 {
01444 int i;
01445
01446 push_mark_stack_chunk(stack);
01447 stack->limit = STACK_CHUNK_SIZE;
01448
01449 for(i=0; i < 4; i++) {
01450 add_stack_chunk_cache(stack, stack_chunk_alloc());
01451 }
01452 stack->unused_cache_size = stack->cache_size;
01453 }
01454
01455
01456 size_t
01457 ruby_stack_length(VALUE **p)
01458 {
01459 rb_thread_t *th = GET_THREAD();
01460 SET_STACK_END;
01461 if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
01462 return STACK_LENGTH;
01463 }
01464
01465 #if !(defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK))
01466 static int
01467 stack_check(int water_mark)
01468 {
01469 int ret;
01470 rb_thread_t *th = GET_THREAD();
01471 SET_STACK_END;
01472 ret = STACK_LENGTH > STACK_LEVEL_MAX - water_mark;
01473 #ifdef __ia64
01474 if (!ret) {
01475 ret = (VALUE*)rb_ia64_bsp() - th->machine_register_stack_start >
01476 th->machine_register_stack_maxsize/sizeof(VALUE) - water_mark;
01477 }
01478 #endif
01479 return ret;
01480 }
01481 #endif
01482
01483 #define STACKFRAME_FOR_CALL_CFUNC 512
01484
01485 int
01486 ruby_stack_check(void)
01487 {
01488 #if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
01489 return 0;
01490 #else
01491 return stack_check(STACKFRAME_FOR_CALL_CFUNC);
01492 #endif
01493 }
01494
01495 #define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack)
01496
01497 static void gc_mark(rb_objspace_t *objspace, VALUE ptr);
01498 static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr);
01499
01500 static void
01501 gc_mark_stacked_objects(rb_objspace_t *objspace)
01502 {
01503 mark_stack_t *mstack = &objspace->mark_stack;
01504 VALUE obj = 0;
01505
01506 if (!mstack->index) return;
01507 while (pop_mark_stack(mstack, &obj)) {
01508 gc_mark_children(objspace, obj);
01509 }
01510 shrink_stack_chunk_cache(mstack);
01511 }
01512
01513 static inline int
01514 is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
01515 {
01516 register RVALUE *p = RANY(ptr);
01517 register struct sorted_heaps_slot *heap;
01518 register size_t hi, lo, mid;
01519
01520 if (p < lomem || p > himem) return FALSE;
01521 if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
01522
01523
01524 lo = 0;
01525 hi = heaps_used;
01526 while (lo < hi) {
01527 mid = (lo + hi) / 2;
01528 heap = &objspace->heap.sorted[mid];
01529 if (heap->start <= p) {
01530 if (p < heap->end)
01531 return TRUE;
01532 lo = mid + 1;
01533 }
01534 else {
01535 hi = mid;
01536 }
01537 }
01538 return FALSE;
01539 }
01540
01541 static void
01542 mark_locations_array(rb_objspace_t *objspace, register VALUE *x, register long n)
01543 {
01544 VALUE v;
01545 while (n--) {
01546 v = *x;
01547 VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v));
01548 if (is_pointer_to_heap(objspace, (void *)v)) {
01549 gc_mark(objspace, v);
01550 }
01551 x++;
01552 }
01553 }
01554
01555 static void
01556 gc_mark_locations(rb_objspace_t *objspace, VALUE *start, VALUE *end)
01557 {
01558 long n;
01559
01560 if (end <= start) return;
01561 n = end - start;
01562 mark_locations_array(objspace, start, n);
01563 }
01564
01565 void
01566 rb_gc_mark_locations(VALUE *start, VALUE *end)
01567 {
01568 gc_mark_locations(&rb_objspace, start, end);
01569 }
01570
01571 #define rb_gc_mark_locations(start, end) gc_mark_locations(objspace, (start), (end))
01572
01573 struct mark_tbl_arg {
01574 rb_objspace_t *objspace;
01575 };
01576
01577 static int
01578 mark_entry(ID key, VALUE value, st_data_t data)
01579 {
01580 struct mark_tbl_arg *arg = (void*)data;
01581 gc_mark(arg->objspace, value);
01582 return ST_CONTINUE;
01583 }
01584
01585 static void
01586 mark_tbl(rb_objspace_t *objspace, st_table *tbl)
01587 {
01588 struct mark_tbl_arg arg;
01589 if (!tbl || tbl->num_entries == 0) return;
01590 arg.objspace = objspace;
01591 st_foreach(tbl, mark_entry, (st_data_t)&arg);
01592 }
01593
01594 static int
01595 mark_key(VALUE key, VALUE value, st_data_t data)
01596 {
01597 struct mark_tbl_arg *arg = (void*)data;
01598 gc_mark(arg->objspace, key);
01599 return ST_CONTINUE;
01600 }
01601
01602 static void
01603 mark_set(rb_objspace_t *objspace, st_table *tbl)
01604 {
01605 struct mark_tbl_arg arg;
01606 if (!tbl) return;
01607 arg.objspace = objspace;
01608 st_foreach(tbl, mark_key, (st_data_t)&arg);
01609 }
01610
01611 void
01612 rb_mark_set(st_table *tbl)
01613 {
01614 mark_set(&rb_objspace, tbl);
01615 }
01616
01617 static int
01618 mark_keyvalue(VALUE key, VALUE value, st_data_t data)
01619 {
01620 struct mark_tbl_arg *arg = (void*)data;
01621 gc_mark(arg->objspace, key);
01622 gc_mark(arg->objspace, value);
01623 return ST_CONTINUE;
01624 }
01625
01626 static void
01627 mark_hash(rb_objspace_t *objspace, st_table *tbl)
01628 {
01629 struct mark_tbl_arg arg;
01630 if (!tbl) return;
01631 arg.objspace = objspace;
01632 st_foreach(tbl, mark_keyvalue, (st_data_t)&arg);
01633 }
01634
01635 void
01636 rb_mark_hash(st_table *tbl)
01637 {
01638 mark_hash(&rb_objspace, tbl);
01639 }
01640
01641 static void
01642 mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
01643 {
01644 const rb_method_definition_t *def = me->def;
01645
01646 gc_mark(objspace, me->klass);
01647 if (!def) return;
01648 switch (def->type) {
01649 case VM_METHOD_TYPE_ISEQ:
01650 gc_mark(objspace, def->body.iseq->self);
01651 break;
01652 case VM_METHOD_TYPE_BMETHOD:
01653 gc_mark(objspace, def->body.proc);
01654 break;
01655 case VM_METHOD_TYPE_ATTRSET:
01656 case VM_METHOD_TYPE_IVAR:
01657 gc_mark(objspace, def->body.attr.location);
01658 break;
01659 default:
01660 break;
01661 }
01662 }
01663
01664 void
01665 rb_mark_method_entry(const rb_method_entry_t *me)
01666 {
01667 mark_method_entry(&rb_objspace, me);
01668 }
01669
01670 static int
01671 mark_method_entry_i(ID key, const rb_method_entry_t *me, st_data_t data)
01672 {
01673 struct mark_tbl_arg *arg = (void*)data;
01674 mark_method_entry(arg->objspace, me);
01675 return ST_CONTINUE;
01676 }
01677
01678 static void
01679 mark_m_tbl(rb_objspace_t *objspace, st_table *tbl)
01680 {
01681 struct mark_tbl_arg arg;
01682 if (!tbl) return;
01683 arg.objspace = objspace;
01684 st_foreach(tbl, mark_method_entry_i, (st_data_t)&arg);
01685 }
01686
01687 static int
01688 free_method_entry_i(ID key, rb_method_entry_t *me, st_data_t data)
01689 {
01690 if (!me->mark) {
01691 rb_free_method_entry(me);
01692 }
01693 return ST_CONTINUE;
01694 }
01695
01696 void
01697 rb_free_m_table(st_table *tbl)
01698 {
01699 st_foreach(tbl, free_method_entry_i, 0);
01700 st_free_table(tbl);
01701 }
01702
01703 static int
01704 mark_const_entry_i(ID key, const rb_const_entry_t *ce, st_data_t data)
01705 {
01706 struct mark_tbl_arg *arg = (void*)data;
01707 gc_mark(arg->objspace, ce->value);
01708 return ST_CONTINUE;
01709 }
01710
01711 static void
01712 mark_const_tbl(rb_objspace_t *objspace, st_table *tbl)
01713 {
01714 struct mark_tbl_arg arg;
01715 if (!tbl) return;
01716 arg.objspace = objspace;
01717 st_foreach(tbl, mark_const_entry_i, (st_data_t)&arg);
01718 }
01719
01720 static int
01721 free_const_entry_i(ID key, rb_const_entry_t *ce, st_data_t data)
01722 {
01723 xfree(ce);
01724 return ST_CONTINUE;
01725 }
01726
01727 void
01728 rb_free_const_table(st_table *tbl)
01729 {
01730 st_foreach(tbl, free_const_entry_i, 0);
01731 st_free_table(tbl);
01732 }
01733
01734 void
01735 rb_mark_tbl(st_table *tbl)
01736 {
01737 mark_tbl(&rb_objspace, tbl);
01738 }
01739
01740 void
01741 rb_gc_mark_maybe(VALUE obj)
01742 {
01743 if (is_pointer_to_heap(&rb_objspace, (void *)obj)) {
01744 gc_mark(&rb_objspace, obj);
01745 }
01746 }
01747
01748 static void
01749 gc_mark(rb_objspace_t *objspace, VALUE ptr)
01750 {
01751 register RVALUE *obj;
01752
01753 obj = RANY(ptr);
01754 if (rb_special_const_p(ptr)) return;
01755 if (obj->as.basic.flags == 0) return;
01756 if (obj->as.basic.flags & FL_MARK) return;
01757 obj->as.basic.flags |= FL_MARK;
01758 objspace->heap.live_num++;
01759
01760 push_mark_stack(&objspace->mark_stack, ptr);
01761 }
01762
01763 void
01764 rb_gc_mark(VALUE ptr)
01765 {
01766 gc_mark(&rb_objspace, ptr);
01767 }
01768
01769 static void
01770 gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
01771 {
01772 register RVALUE *obj = RANY(ptr);
01773
01774 goto marking;
01775
01776 again:
01777 obj = RANY(ptr);
01778 if (rb_special_const_p(ptr)) return;
01779 if (obj->as.basic.flags == 0) return;
01780 if (obj->as.basic.flags & FL_MARK) return;
01781 obj->as.basic.flags |= FL_MARK;
01782 objspace->heap.live_num++;
01783
01784 marking:
01785 if (FL_TEST(obj, FL_EXIVAR)) {
01786 rb_mark_generic_ivar(ptr);
01787 }
01788
01789 switch (BUILTIN_TYPE(obj)) {
01790 case T_NIL:
01791 case T_FIXNUM:
01792 rb_bug("rb_gc_mark() called for broken object");
01793 break;
01794
01795 case T_NODE:
01796 switch (nd_type(obj)) {
01797 case NODE_IF:
01798 case NODE_FOR:
01799 case NODE_ITER:
01800 case NODE_WHEN:
01801 case NODE_MASGN:
01802 case NODE_RESCUE:
01803 case NODE_RESBODY:
01804 case NODE_CLASS:
01805 case NODE_BLOCK_PASS:
01806 gc_mark(objspace, (VALUE)obj->as.node.u2.node);
01807
01808 case NODE_BLOCK:
01809 case NODE_OPTBLOCK:
01810 case NODE_ARRAY:
01811 case NODE_DSTR:
01812 case NODE_DXSTR:
01813 case NODE_DREGX:
01814 case NODE_DREGX_ONCE:
01815 case NODE_ENSURE:
01816 case NODE_CALL:
01817 case NODE_DEFS:
01818 case NODE_OP_ASGN1:
01819 case NODE_ARGS:
01820 gc_mark(objspace, (VALUE)obj->as.node.u1.node);
01821
01822 case NODE_SUPER:
01823 case NODE_FCALL:
01824 case NODE_DEFN:
01825 case NODE_ARGS_AUX:
01826 ptr = (VALUE)obj->as.node.u3.node;
01827 goto again;
01828
01829 case NODE_WHILE:
01830 case NODE_UNTIL:
01831 case NODE_AND:
01832 case NODE_OR:
01833 case NODE_CASE:
01834 case NODE_SCLASS:
01835 case NODE_DOT2:
01836 case NODE_DOT3:
01837 case NODE_FLIP2:
01838 case NODE_FLIP3:
01839 case NODE_MATCH2:
01840 case NODE_MATCH3:
01841 case NODE_OP_ASGN_OR:
01842 case NODE_OP_ASGN_AND:
01843 case NODE_MODULE:
01844 case NODE_ALIAS:
01845 case NODE_VALIAS:
01846 case NODE_ARGSCAT:
01847 gc_mark(objspace, (VALUE)obj->as.node.u1.node);
01848
01849 case NODE_GASGN:
01850 case NODE_LASGN:
01851 case NODE_DASGN:
01852 case NODE_DASGN_CURR:
01853 case NODE_IASGN:
01854 case NODE_IASGN2:
01855 case NODE_CVASGN:
01856 case NODE_COLON3:
01857 case NODE_OPT_N:
01858 case NODE_EVSTR:
01859 case NODE_UNDEF:
01860 case NODE_POSTEXE:
01861 ptr = (VALUE)obj->as.node.u2.node;
01862 goto again;
01863
01864 case NODE_HASH:
01865 case NODE_LIT:
01866 case NODE_STR:
01867 case NODE_XSTR:
01868 case NODE_DEFINED:
01869 case NODE_MATCH:
01870 case NODE_RETURN:
01871 case NODE_BREAK:
01872 case NODE_NEXT:
01873 case NODE_YIELD:
01874 case NODE_COLON2:
01875 case NODE_SPLAT:
01876 case NODE_TO_ARY:
01877 ptr = (VALUE)obj->as.node.u1.node;
01878 goto again;
01879
01880 case NODE_SCOPE:
01881 case NODE_CDECL:
01882 case NODE_OPT_ARG:
01883 gc_mark(objspace, (VALUE)obj->as.node.u3.node);
01884 ptr = (VALUE)obj->as.node.u2.node;
01885 goto again;
01886
01887 case NODE_ZARRAY:
01888 case NODE_ZSUPER:
01889 case NODE_VCALL:
01890 case NODE_GVAR:
01891 case NODE_LVAR:
01892 case NODE_DVAR:
01893 case NODE_IVAR:
01894 case NODE_CVAR:
01895 case NODE_NTH_REF:
01896 case NODE_BACK_REF:
01897 case NODE_REDO:
01898 case NODE_RETRY:
01899 case NODE_SELF:
01900 case NODE_NIL:
01901 case NODE_TRUE:
01902 case NODE_FALSE:
01903 case NODE_ERRINFO:
01904 case NODE_BLOCK_ARG:
01905 break;
01906 case NODE_ALLOCA:
01907 mark_locations_array(objspace,
01908 (VALUE*)obj->as.node.u1.value,
01909 obj->as.node.u3.cnt);
01910 ptr = (VALUE)obj->as.node.u2.node;
01911 goto again;
01912
01913 default:
01914 if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) {
01915 gc_mark(objspace, (VALUE)obj->as.node.u1.node);
01916 }
01917 if (is_pointer_to_heap(objspace, obj->as.node.u2.node)) {
01918 gc_mark(objspace, (VALUE)obj->as.node.u2.node);
01919 }
01920 if (is_pointer_to_heap(objspace, obj->as.node.u3.node)) {
01921 gc_mark(objspace, (VALUE)obj->as.node.u3.node);
01922 }
01923 }
01924 return;
01925 }
01926
01927 gc_mark(objspace, obj->as.basic.klass);
01928 switch (BUILTIN_TYPE(obj)) {
01929 case T_ICLASS:
01930 case T_CLASS:
01931 case T_MODULE:
01932 mark_m_tbl(objspace, RCLASS_M_TBL(obj));
01933 mark_tbl(objspace, RCLASS_IV_TBL(obj));
01934 mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
01935 ptr = RCLASS_SUPER(obj);
01936 goto again;
01937
01938 case T_ARRAY:
01939 if (FL_TEST(obj, ELTS_SHARED)) {
01940 ptr = obj->as.array.as.heap.aux.shared;
01941 goto again;
01942 }
01943 else {
01944 long i, len = RARRAY_LEN(obj);
01945 VALUE *ptr = RARRAY_PTR(obj);
01946 for (i=0; i < len; i++) {
01947 gc_mark(objspace, *ptr++);
01948 }
01949 }
01950 break;
01951
01952 case T_HASH:
01953 mark_hash(objspace, obj->as.hash.ntbl);
01954 ptr = obj->as.hash.ifnone;
01955 goto again;
01956
01957 case T_STRING:
01958 #define STR_ASSOC FL_USER3
01959 if (FL_TEST(obj, RSTRING_NOEMBED) && FL_ANY(obj, ELTS_SHARED|STR_ASSOC)) {
01960 ptr = obj->as.string.as.heap.aux.shared;
01961 goto again;
01962 }
01963 break;
01964
01965 case T_DATA:
01966 if (RTYPEDDATA_P(obj)) {
01967 RUBY_DATA_FUNC mark_func = obj->as.typeddata.type->function.dmark;
01968 if (mark_func) (*mark_func)(DATA_PTR(obj));
01969 }
01970 else {
01971 if (obj->as.data.dmark) (*obj->as.data.dmark)(DATA_PTR(obj));
01972 }
01973 break;
01974
01975 case T_OBJECT:
01976 {
01977 long i, len = ROBJECT_NUMIV(obj);
01978 VALUE *ptr = ROBJECT_IVPTR(obj);
01979 for (i = 0; i < len; i++) {
01980 gc_mark(objspace, *ptr++);
01981 }
01982 }
01983 break;
01984
01985 case T_FILE:
01986 if (obj->as.file.fptr) {
01987 gc_mark(objspace, obj->as.file.fptr->pathv);
01988 gc_mark(objspace, obj->as.file.fptr->tied_io_for_writing);
01989 gc_mark(objspace, obj->as.file.fptr->writeconv_asciicompat);
01990 gc_mark(objspace, obj->as.file.fptr->writeconv_pre_ecopts);
01991 gc_mark(objspace, obj->as.file.fptr->encs.ecopts);
01992 gc_mark(objspace, obj->as.file.fptr->write_lock);
01993 }
01994 break;
01995
01996 case T_REGEXP:
01997 ptr = obj->as.regexp.src;
01998 goto again;
01999
02000 case T_FLOAT:
02001 case T_BIGNUM:
02002 case T_ZOMBIE:
02003 break;
02004
02005 case T_MATCH:
02006 gc_mark(objspace, obj->as.match.regexp);
02007 if (obj->as.match.str) {
02008 ptr = obj->as.match.str;
02009 goto again;
02010 }
02011 break;
02012
02013 case T_RATIONAL:
02014 gc_mark(objspace, obj->as.rational.num);
02015 ptr = obj->as.rational.den;
02016 goto again;
02017
02018 case T_COMPLEX:
02019 gc_mark(objspace, obj->as.complex.real);
02020 ptr = obj->as.complex.imag;
02021 goto again;
02022
02023 case T_STRUCT:
02024 {
02025 long len = RSTRUCT_LEN(obj);
02026 VALUE *ptr = RSTRUCT_PTR(obj);
02027
02028 while (len--) {
02029 gc_mark(objspace, *ptr++);
02030 }
02031 }
02032 break;
02033
02034 default:
02035 rb_bug("rb_gc_mark(): unknown data type 0x%x(%p) %s",
02036 BUILTIN_TYPE(obj), (void *)obj,
02037 is_pointer_to_heap(objspace, obj) ? "corrupted object" : "non object");
02038 }
02039 }
02040
02041 static int obj_free(rb_objspace_t *, VALUE);
02042
02043 static inline void
02044 add_freelist(rb_objspace_t *objspace, RVALUE *p)
02045 {
02046 VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
02047 p->as.free.flags = 0;
02048 p->as.free.next = freelist;
02049 freelist = p;
02050 }
02051
02052 static void
02053 finalize_list(rb_objspace_t *objspace, RVALUE *p)
02054 {
02055 while (p) {
02056 RVALUE *tmp = p->as.free.next;
02057 run_final(objspace, (VALUE)p);
02058 if (!FL_TEST(p, FL_SINGLETON)) {
02059 if (objspace->heap.sweep_slots) {
02060 p->as.free.flags = 0;
02061 }
02062 else {
02063 GC_PROF_DEC_LIVE_NUM;
02064 add_freelist(objspace, p);
02065 }
02066 }
02067 else {
02068 struct heaps_slot *slot = (struct heaps_slot *)(VALUE)RDATA(p)->dmark;
02069 slot->limit--;
02070 }
02071 p = tmp;
02072 }
02073 }
02074
02075 static void
02076 unlink_heap_slot(rb_objspace_t *objspace, struct heaps_slot *slot)
02077 {
02078 if (slot->prev)
02079 slot->prev->next = slot->next;
02080 if (slot->next)
02081 slot->next->prev = slot->prev;
02082 if (heaps == slot)
02083 heaps = slot->next;
02084 if (objspace->heap.sweep_slots == slot)
02085 objspace->heap.sweep_slots = slot->next;
02086 slot->prev = NULL;
02087 slot->next = NULL;
02088 }
02089
02090
02091 static void
02092 free_unused_heaps(rb_objspace_t *objspace)
02093 {
02094 size_t i, j;
02095 RVALUE *last = 0;
02096
02097 for (i = j = 1; j < heaps_used; i++) {
02098 if (objspace->heap.sorted[i].slot->limit == 0) {
02099 if (!last) {
02100 last = objspace->heap.sorted[i].slot->membase;
02101 }
02102 else {
02103 free(objspace->heap.sorted[i].slot->membase);
02104 }
02105 free(objspace->heap.sorted[i].slot);
02106 heaps_used--;
02107 }
02108 else {
02109 if (i != j) {
02110 objspace->heap.sorted[j] = objspace->heap.sorted[i];
02111 }
02112 j++;
02113 }
02114 }
02115 if (last) {
02116 if (last < heaps_freed) {
02117 free(heaps_freed);
02118 heaps_freed = last;
02119 }
02120 else {
02121 free(last);
02122 }
02123 }
02124 }
02125
02126 static void
02127 slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
02128 {
02129 size_t free_num = 0, final_num = 0;
02130 RVALUE *p, *pend;
02131 RVALUE *free = freelist, *final = deferred_final_list;
02132 int deferred;
02133
02134 p = sweep_slot->slot; pend = p + sweep_slot->limit;
02135 while (p < pend) {
02136 if (!(p->as.basic.flags & FL_MARK)) {
02137 if (p->as.basic.flags &&
02138 ((deferred = obj_free(objspace, (VALUE)p)) ||
02139 (FL_TEST(p, FL_FINALIZE)))) {
02140 if (!deferred) {
02141 p->as.free.flags = T_ZOMBIE;
02142 RDATA(p)->dfree = 0;
02143 }
02144 p->as.free.flags |= FL_MARK;
02145 p->as.free.next = deferred_final_list;
02146 deferred_final_list = p;
02147 final_num++;
02148 }
02149 else {
02150 add_freelist(objspace, p);
02151 free_num++;
02152 }
02153 }
02154 else if (BUILTIN_TYPE(p) == T_ZOMBIE) {
02155
02156
02157 }
02158 else {
02159 RBASIC(p)->flags &= ~FL_MARK;
02160 }
02161 p++;
02162 }
02163 if (final_num + free_num == sweep_slot->limit &&
02164 objspace->heap.free_num > objspace->heap.do_heap_free) {
02165 RVALUE *pp;
02166
02167 for (pp = deferred_final_list; pp != final; pp = pp->as.free.next) {
02168 RDATA(pp)->dmark = (void (*)(void *))(VALUE)sweep_slot;
02169 pp->as.free.flags |= FL_SINGLETON;
02170 }
02171 sweep_slot->limit = final_num;
02172 freelist = free;
02173 unlink_heap_slot(objspace, sweep_slot);
02174 }
02175 else {
02176 objspace->heap.free_num += free_num;
02177 }
02178 objspace->heap.final_num += final_num;
02179
02180 if (deferred_final_list && !finalizing) {
02181 rb_thread_t *th = GET_THREAD();
02182 if (th) {
02183 RUBY_VM_SET_FINALIZER_INTERRUPT(th);
02184 }
02185 }
02186 }
02187
02188 static int
02189 ready_to_gc(rb_objspace_t *objspace)
02190 {
02191 if (dont_gc || during_gc) {
02192 if (!freelist) {
02193 if (!heaps_increment(objspace)) {
02194 set_heaps_increment(objspace);
02195 heaps_increment(objspace);
02196 }
02197 }
02198 return FALSE;
02199 }
02200 return TRUE;
02201 }
02202
02203 static void
02204 before_gc_sweep(rb_objspace_t *objspace)
02205 {
02206 freelist = 0;
02207 objspace->heap.do_heap_free = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.65);
02208 objspace->heap.free_min = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.2);
02209 if (objspace->heap.free_min < initial_free_min) {
02210 objspace->heap.do_heap_free = heaps_used * HEAP_OBJ_LIMIT;
02211 objspace->heap.free_min = initial_free_min;
02212 }
02213 objspace->heap.sweep_slots = heaps;
02214 objspace->heap.free_num = 0;
02215
02216
02217 if (GET_VM()->unlinked_method_entry_list) {
02218 rb_sweep_method_entry(GET_VM());
02219 }
02220 }
02221
02222 static void
02223 after_gc_sweep(rb_objspace_t *objspace)
02224 {
02225 GC_PROF_SET_MALLOC_INFO;
02226
02227 if (objspace->heap.free_num < objspace->heap.free_min) {
02228 set_heaps_increment(objspace);
02229 heaps_increment(objspace);
02230 }
02231
02232 if (malloc_increase > malloc_limit) {
02233 malloc_limit += (size_t)((malloc_increase - malloc_limit) * (double)objspace->heap.live_num / (heaps_used * HEAP_OBJ_LIMIT));
02234 if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
02235 }
02236 malloc_increase = 0;
02237
02238 free_unused_heaps(objspace);
02239 }
02240
02241 static int
02242 lazy_sweep(rb_objspace_t *objspace)
02243 {
02244 struct heaps_slot *next;
02245
02246 heaps_increment(objspace);
02247 while (objspace->heap.sweep_slots) {
02248 next = objspace->heap.sweep_slots->next;
02249 slot_sweep(objspace, objspace->heap.sweep_slots);
02250 objspace->heap.sweep_slots = next;
02251 if (freelist) {
02252 during_gc = 0;
02253 return TRUE;
02254 }
02255 }
02256 return FALSE;
02257 }
02258
02259 static void
02260 rest_sweep(rb_objspace_t *objspace)
02261 {
02262 if (objspace->heap.sweep_slots) {
02263 while (objspace->heap.sweep_slots) {
02264 lazy_sweep(objspace);
02265 }
02266 after_gc_sweep(objspace);
02267 }
02268 }
02269
02270 static void gc_marks(rb_objspace_t *objspace);
02271
02272 static int
02273 gc_lazy_sweep(rb_objspace_t *objspace)
02274 {
02275 int res;
02276 INIT_GC_PROF_PARAMS;
02277
02278 if (objspace->flags.dont_lazy_sweep)
02279 return garbage_collect(objspace);
02280
02281
02282 if (!ready_to_gc(objspace)) return TRUE;
02283
02284 during_gc++;
02285 GC_PROF_TIMER_START;
02286 GC_PROF_SWEEP_TIMER_START;
02287
02288 if (objspace->heap.sweep_slots) {
02289 res = lazy_sweep(objspace);
02290 if (res) {
02291 GC_PROF_SWEEP_TIMER_STOP;
02292 GC_PROF_SET_MALLOC_INFO;
02293 GC_PROF_TIMER_STOP(Qfalse);
02294 return res;
02295 }
02296 after_gc_sweep(objspace);
02297 }
02298 else {
02299 if (heaps_increment(objspace)) {
02300 during_gc = 0;
02301 return TRUE;
02302 }
02303 }
02304
02305 gc_marks(objspace);
02306
02307 before_gc_sweep(objspace);
02308 if (objspace->heap.free_min > (heaps_used * HEAP_OBJ_LIMIT - objspace->heap.live_num)) {
02309 set_heaps_increment(objspace);
02310 }
02311
02312 GC_PROF_SWEEP_TIMER_START;
02313 if(!(res = lazy_sweep(objspace))) {
02314 after_gc_sweep(objspace);
02315 if(freelist) {
02316 res = TRUE;
02317 during_gc = 0;
02318 }
02319 }
02320 GC_PROF_SWEEP_TIMER_STOP;
02321
02322 GC_PROF_TIMER_STOP(Qtrue);
02323 return res;
02324 }
02325
02326 static void
02327 gc_sweep(rb_objspace_t *objspace)
02328 {
02329 struct heaps_slot *next;
02330
02331 before_gc_sweep(objspace);
02332
02333 while (objspace->heap.sweep_slots) {
02334 next = objspace->heap.sweep_slots->next;
02335 slot_sweep(objspace, objspace->heap.sweep_slots);
02336 objspace->heap.sweep_slots = next;
02337 }
02338
02339 after_gc_sweep(objspace);
02340
02341 during_gc = 0;
02342 }
02343
02344 void
02345 rb_gc_force_recycle(VALUE p)
02346 {
02347 rb_objspace_t *objspace = &rb_objspace;
02348 GC_PROF_DEC_LIVE_NUM;
02349 if (RBASIC(p)->flags & FL_MARK) {
02350 RANY(p)->as.free.flags = 0;
02351 }
02352 else {
02353 add_freelist(objspace, (RVALUE *)p);
02354 }
02355 }
02356
02357 static inline void
02358 make_deferred(RVALUE *p)
02359 {
02360 p->as.basic.flags = (p->as.basic.flags & ~T_MASK) | T_ZOMBIE;
02361 }
02362
02363 static inline void
02364 make_io_deferred(RVALUE *p)
02365 {
02366 rb_io_t *fptr = p->as.file.fptr;
02367 make_deferred(p);
02368 p->as.data.dfree = (void (*)(void*))rb_io_fptr_finalize;
02369 p->as.data.data = fptr;
02370 }
02371
02372 static int
02373 obj_free(rb_objspace_t *objspace, VALUE obj)
02374 {
02375 switch (BUILTIN_TYPE(obj)) {
02376 case T_NIL:
02377 case T_FIXNUM:
02378 case T_TRUE:
02379 case T_FALSE:
02380 rb_bug("obj_free() called for broken object");
02381 break;
02382 }
02383
02384 if (FL_TEST(obj, FL_EXIVAR)) {
02385 rb_free_generic_ivar((VALUE)obj);
02386 FL_UNSET(obj, FL_EXIVAR);
02387 }
02388
02389 switch (BUILTIN_TYPE(obj)) {
02390 case T_OBJECT:
02391 if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) &&
02392 RANY(obj)->as.object.as.heap.ivptr) {
02393 xfree(RANY(obj)->as.object.as.heap.ivptr);
02394 }
02395 break;
02396 case T_MODULE:
02397 case T_CLASS:
02398 rb_clear_cache_by_class((VALUE)obj);
02399 rb_free_m_table(RCLASS_M_TBL(obj));
02400 if (RCLASS_IV_TBL(obj)) {
02401 st_free_table(RCLASS_IV_TBL(obj));
02402 }
02403 if (RCLASS_CONST_TBL(obj)) {
02404 rb_free_const_table(RCLASS_CONST_TBL(obj));
02405 }
02406 if (RCLASS_IV_INDEX_TBL(obj)) {
02407 st_free_table(RCLASS_IV_INDEX_TBL(obj));
02408 }
02409 xfree(RANY(obj)->as.klass.ptr);
02410 break;
02411 case T_STRING:
02412 rb_str_free(obj);
02413 break;
02414 case T_ARRAY:
02415 rb_ary_free(obj);
02416 break;
02417 case T_HASH:
02418 if (RANY(obj)->as.hash.ntbl) {
02419 st_free_table(RANY(obj)->as.hash.ntbl);
02420 }
02421 break;
02422 case T_REGEXP:
02423 if (RANY(obj)->as.regexp.ptr) {
02424 onig_free(RANY(obj)->as.regexp.ptr);
02425 }
02426 break;
02427 case T_DATA:
02428 if (DATA_PTR(obj)) {
02429 if (RTYPEDDATA_P(obj)) {
02430 RDATA(obj)->dfree = RANY(obj)->as.typeddata.type->function.dfree;
02431 }
02432 if (RANY(obj)->as.data.dfree == (RUBY_DATA_FUNC)-1) {
02433 xfree(DATA_PTR(obj));
02434 }
02435 else if (RANY(obj)->as.data.dfree) {
02436 make_deferred(RANY(obj));
02437 return 1;
02438 }
02439 }
02440 break;
02441 case T_MATCH:
02442 if (RANY(obj)->as.match.rmatch) {
02443 struct rmatch *rm = RANY(obj)->as.match.rmatch;
02444 onig_region_free(&rm->regs, 0);
02445 if (rm->char_offset)
02446 xfree(rm->char_offset);
02447 xfree(rm);
02448 }
02449 break;
02450 case T_FILE:
02451 if (RANY(obj)->as.file.fptr) {
02452 make_io_deferred(RANY(obj));
02453 return 1;
02454 }
02455 break;
02456 case T_RATIONAL:
02457 case T_COMPLEX:
02458 break;
02459 case T_ICLASS:
02460
02461 xfree(RANY(obj)->as.klass.ptr);
02462 break;
02463
02464 case T_FLOAT:
02465 break;
02466
02467 case T_BIGNUM:
02468 if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
02469 xfree(RBIGNUM_DIGITS(obj));
02470 }
02471 break;
02472 case T_NODE:
02473 switch (nd_type(obj)) {
02474 case NODE_SCOPE:
02475 if (RANY(obj)->as.node.u1.tbl) {
02476 xfree(RANY(obj)->as.node.u1.tbl);
02477 }
02478 break;
02479 case NODE_ALLOCA:
02480 xfree(RANY(obj)->as.node.u1.node);
02481 break;
02482 }
02483 break;
02484
02485 case T_STRUCT:
02486 if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
02487 RANY(obj)->as.rstruct.as.heap.ptr) {
02488 xfree(RANY(obj)->as.rstruct.as.heap.ptr);
02489 }
02490 break;
02491
02492 default:
02493 rb_bug("gc_sweep(): unknown data type 0x%x(%p)",
02494 BUILTIN_TYPE(obj), (void*)obj);
02495 }
02496
02497 return 0;
02498 }
02499
02500 #define GC_NOTIFY 0
02501
02502 #if STACK_GROW_DIRECTION < 0
02503 #define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
02504 #elif STACK_GROW_DIRECTION > 0
02505 #define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_START, (end) = STACK_END+(appendix))
02506 #else
02507 #define GET_STACK_BOUNDS(start, end, appendix) \
02508 ((STACK_END < STACK_START) ? \
02509 ((start) = STACK_END, (end) = STACK_START) : ((start) = STACK_START, (end) = STACK_END+(appendix)))
02510 #endif
02511
02512 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
02513
02514 static void
02515 mark_current_machine_context(rb_objspace_t *objspace, rb_thread_t *th)
02516 {
02517 union {
02518 rb_jmp_buf j;
02519 VALUE v[sizeof(rb_jmp_buf) / sizeof(VALUE)];
02520 } save_regs_gc_mark;
02521 VALUE *stack_start, *stack_end;
02522
02523 FLUSH_REGISTER_WINDOWS;
02524
02525 rb_setjmp(save_regs_gc_mark.j);
02526
02527 SET_STACK_END;
02528 GET_STACK_BOUNDS(stack_start, stack_end, 1);
02529
02530 mark_locations_array(objspace, save_regs_gc_mark.v, numberof(save_regs_gc_mark.v));
02531
02532 rb_gc_mark_locations(stack_start, stack_end);
02533 #ifdef __ia64
02534 rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
02535 #endif
02536 #if defined(__mc68000__)
02537 mark_locations_array(objspace, (VALUE*)((char*)STACK_END + 2),
02538 (STACK_START - STACK_END));
02539 #endif
02540 }
02541
02542 static void
02543 gc_marks(rb_objspace_t *objspace)
02544 {
02545 struct gc_list *list;
02546 rb_thread_t *th = GET_THREAD();
02547 GC_PROF_MARK_TIMER_START;
02548
02549 objspace->heap.live_num = 0;
02550 objspace->count++;
02551
02552
02553 SET_STACK_END;
02554
02555 th->vm->self ? rb_gc_mark(th->vm->self) : rb_vm_mark(th->vm);
02556
02557 mark_tbl(objspace, finalizer_table);
02558 mark_current_machine_context(objspace, th);
02559
02560 rb_gc_mark_symbols();
02561 rb_gc_mark_encodings();
02562
02563
02564 for (list = global_List; list; list = list->next) {
02565 rb_gc_mark_maybe(*list->varptr);
02566 }
02567 rb_mark_end_proc();
02568 rb_gc_mark_global_tbl();
02569
02570 mark_tbl(objspace, rb_class_tbl);
02571
02572
02573 rb_mark_generic_ivar_tbl();
02574
02575 rb_gc_mark_parser();
02576
02577 rb_gc_mark_unlinked_live_method_entries(th->vm);
02578
02579
02580 gc_mark_stacked_objects(objspace);
02581
02582 GC_PROF_MARK_TIMER_STOP;
02583 }
02584
02585 static int
02586 garbage_collect(rb_objspace_t *objspace)
02587 {
02588 INIT_GC_PROF_PARAMS;
02589
02590 if (GC_NOTIFY) printf("start garbage_collect()\n");
02591
02592 if (!heaps) {
02593 return FALSE;
02594 }
02595 if (!ready_to_gc(objspace)) {
02596 return TRUE;
02597 }
02598
02599 GC_PROF_TIMER_START;
02600
02601 rest_sweep(objspace);
02602
02603 during_gc++;
02604 gc_marks(objspace);
02605
02606 GC_PROF_SWEEP_TIMER_START;
02607 gc_sweep(objspace);
02608 GC_PROF_SWEEP_TIMER_STOP;
02609
02610 GC_PROF_TIMER_STOP(Qtrue);
02611 if (GC_NOTIFY) printf("end garbage_collect()\n");
02612 return TRUE;
02613 }
02614
02615 int
02616 rb_garbage_collect(void)
02617 {
02618 return garbage_collect(&rb_objspace);
02619 }
02620
02621 void
02622 rb_gc_mark_machine_stack(rb_thread_t *th)
02623 {
02624 rb_objspace_t *objspace = &rb_objspace;
02625 VALUE *stack_start, *stack_end;
02626
02627 GET_STACK_BOUNDS(stack_start, stack_end, 0);
02628 rb_gc_mark_locations(stack_start, stack_end);
02629 #ifdef __ia64
02630 rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
02631 #endif
02632 }
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643
02644
02645 VALUE
02646 rb_gc_start(void)
02647 {
02648 rb_gc();
02649 return Qnil;
02650 }
02651
02652 #undef Init_stack
02653
02654 void
02655 Init_stack(volatile VALUE *addr)
02656 {
02657 ruby_init_stack(addr);
02658 }
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691 void
02692 Init_heap(void)
02693 {
02694 init_heap(&rb_objspace);
02695 }
02696
02697 static VALUE
02698 lazy_sweep_enable(void)
02699 {
02700 rb_objspace_t *objspace = &rb_objspace;
02701
02702 objspace->flags.dont_lazy_sweep = FALSE;
02703 return Qnil;
02704 }
02705
02706 typedef int each_obj_callback(void *, void *, size_t, void *);
02707
02708 struct each_obj_args {
02709 each_obj_callback *callback;
02710 void *data;
02711 };
02712
02713 static VALUE
02714 objspace_each_objects(VALUE arg)
02715 {
02716 size_t i;
02717 RVALUE *membase = 0;
02718 RVALUE *pstart, *pend;
02719 rb_objspace_t *objspace = &rb_objspace;
02720 struct each_obj_args *args = (struct each_obj_args *)arg;
02721 volatile VALUE v;
02722
02723 i = 0;
02724 while (i < heaps_used) {
02725 while (0 < i && (uintptr_t)membase < (uintptr_t)objspace->heap.sorted[i-1].slot->membase)
02726 i--;
02727 while (i < heaps_used && (uintptr_t)objspace->heap.sorted[i].slot->membase <= (uintptr_t)membase)
02728 i++;
02729 if (heaps_used <= i)
02730 break;
02731 membase = objspace->heap.sorted[i].slot->membase;
02732
02733 pstart = objspace->heap.sorted[i].slot->slot;
02734 pend = pstart + objspace->heap.sorted[i].slot->limit;
02735
02736 for (; pstart != pend; pstart++) {
02737 if (pstart->as.basic.flags) {
02738 v = (VALUE)pstart;
02739 break;
02740 }
02741 }
02742 if (pstart != pend) {
02743 if ((*args->callback)(pstart, pend, sizeof(RVALUE), args->data)) {
02744 break;
02745 }
02746 }
02747 }
02748
02749 return Qnil;
02750 }
02751
02752
02753
02754
02755
02756
02757
02758
02759
02760
02761
02762
02763
02764
02765
02766
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787
02788 void
02789 rb_objspace_each_objects(each_obj_callback *callback, void *data)
02790 {
02791 struct each_obj_args args;
02792 rb_objspace_t *objspace = &rb_objspace;
02793
02794 rest_sweep(objspace);
02795 objspace->flags.dont_lazy_sweep = TRUE;
02796
02797 args.callback = callback;
02798 args.data = data;
02799 rb_ensure(objspace_each_objects, (VALUE)&args, lazy_sweep_enable, Qnil);
02800 }
02801
02802 struct os_each_struct {
02803 size_t num;
02804 VALUE of;
02805 };
02806
02807 static int
02808 os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
02809 {
02810 struct os_each_struct *oes = (struct os_each_struct *)data;
02811 RVALUE *p = (RVALUE *)vstart, *pend = (RVALUE *)vend;
02812 volatile VALUE v;
02813
02814 for (; p != pend; p++) {
02815 if (p->as.basic.flags) {
02816 switch (BUILTIN_TYPE(p)) {
02817 case T_NONE:
02818 case T_ICLASS:
02819 case T_NODE:
02820 case T_ZOMBIE:
02821 continue;
02822 case T_CLASS:
02823 if (FL_TEST(p, FL_SINGLETON))
02824 continue;
02825 default:
02826 if (!p->as.basic.klass) continue;
02827 v = (VALUE)p;
02828 if (!oes->of || rb_obj_is_kind_of(v, oes->of)) {
02829 rb_yield(v);
02830 oes->num++;
02831 }
02832 }
02833 }
02834 }
02835
02836 return 0;
02837 }
02838
02839 static VALUE
02840 os_obj_of(VALUE of)
02841 {
02842 struct os_each_struct oes;
02843
02844 oes.num = 0;
02845 oes.of = of;
02846 rb_objspace_each_objects(os_obj_of_i, &oes);
02847 return SIZET2NUM(oes.num);
02848 }
02849
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859
02860
02861
02862
02863
02864
02865
02866
02867
02868
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878
02879
02880
02881
02882
02883
02884
02885
02886 static VALUE
02887 os_each_obj(int argc, VALUE *argv, VALUE os)
02888 {
02889 VALUE of;
02890
02891 rb_secure(4);
02892 if (argc == 0) {
02893 of = 0;
02894 }
02895 else {
02896 rb_scan_args(argc, argv, "01", &of);
02897 }
02898 RETURN_ENUMERATOR(os, 1, &of);
02899 return os_obj_of(of);
02900 }
02901
02902
02903
02904
02905
02906
02907
02908
02909
02910 static VALUE
02911 undefine_final(VALUE os, VALUE obj)
02912 {
02913 rb_objspace_t *objspace = &rb_objspace;
02914 st_data_t data = obj;
02915 rb_check_frozen(obj);
02916 st_delete(finalizer_table, &data, 0);
02917 FL_UNSET(obj, FL_FINALIZE);
02918 return obj;
02919 }
02920
02921
02922
02923
02924
02925
02926
02927
02928
02929
02930 static VALUE
02931 define_final(int argc, VALUE *argv, VALUE os)
02932 {
02933 rb_objspace_t *objspace = &rb_objspace;
02934 VALUE obj, block, table;
02935 st_data_t data;
02936
02937 rb_scan_args(argc, argv, "11", &obj, &block);
02938 rb_check_frozen(obj);
02939 if (argc == 1) {
02940 block = rb_block_proc();
02941 }
02942 else if (!rb_respond_to(block, rb_intern("call"))) {
02943 rb_raise(rb_eArgError, "wrong type argument %s (should be callable)",
02944 rb_obj_classname(block));
02945 }
02946 if (!FL_ABLE(obj)) {
02947 rb_raise(rb_eArgError, "cannot define finalizer for %s",
02948 rb_obj_classname(obj));
02949 }
02950 RBASIC(obj)->flags |= FL_FINALIZE;
02951
02952 block = rb_ary_new3(2, INT2FIX(rb_safe_level()), block);
02953 OBJ_FREEZE(block);
02954
02955 if (st_lookup(finalizer_table, obj, &data)) {
02956 table = (VALUE)data;
02957 rb_ary_push(table, block);
02958 }
02959 else {
02960 table = rb_ary_new3(1, block);
02961 RBASIC(table)->klass = 0;
02962 st_add_direct(finalizer_table, obj, table);
02963 }
02964 return block;
02965 }
02966
02967 void
02968 rb_gc_copy_finalizer(VALUE dest, VALUE obj)
02969 {
02970 rb_objspace_t *objspace = &rb_objspace;
02971 VALUE table;
02972 st_data_t data;
02973
02974 if (!FL_TEST(obj, FL_FINALIZE)) return;
02975 if (st_lookup(finalizer_table, obj, &data)) {
02976 table = (VALUE)data;
02977 st_insert(finalizer_table, dest, table);
02978 }
02979 FL_SET(dest, FL_FINALIZE);
02980 }
02981
02982 static VALUE
02983 run_single_final(VALUE arg)
02984 {
02985 VALUE *args = (VALUE *)arg;
02986 rb_eval_cmd(args[0], args[1], (int)args[2]);
02987 return Qnil;
02988 }
02989
02990 static void
02991 run_finalizer(rb_objspace_t *objspace, VALUE objid, VALUE table)
02992 {
02993 long i;
02994 int status;
02995 VALUE args[3];
02996
02997 if (RARRAY_LEN(table) > 0) {
02998 args[1] = rb_obj_freeze(rb_ary_new3(1, objid));
02999 }
03000 else {
03001 args[1] = 0;
03002 }
03003
03004 args[2] = (VALUE)rb_safe_level();
03005 for (i=0; i<RARRAY_LEN(table); i++) {
03006 VALUE final = RARRAY_PTR(table)[i];
03007 args[0] = RARRAY_PTR(final)[1];
03008 args[2] = FIX2INT(RARRAY_PTR(final)[0]);
03009 status = 0;
03010 rb_protect(run_single_final, (VALUE)args, &status);
03011 if (status)
03012 rb_set_errinfo(Qnil);
03013 }
03014 }
03015
03016 static void
03017 run_final(rb_objspace_t *objspace, VALUE obj)
03018 {
03019 VALUE objid;
03020 RUBY_DATA_FUNC free_func = 0;
03021 st_data_t key, table;
03022
03023 objspace->heap.final_num--;
03024
03025 objid = rb_obj_id(obj);
03026 RBASIC(obj)->klass = 0;
03027
03028 if (RTYPEDDATA_P(obj)) {
03029 free_func = RTYPEDDATA_TYPE(obj)->function.dfree;
03030 }
03031 else {
03032 free_func = RDATA(obj)->dfree;
03033 }
03034 if (free_func) {
03035 (*free_func)(DATA_PTR(obj));
03036 }
03037
03038 key = (st_data_t)obj;
03039 if (st_delete(finalizer_table, &key, &table)) {
03040 run_finalizer(objspace, objid, (VALUE)table);
03041 }
03042 }
03043
03044 static void
03045 finalize_deferred(rb_objspace_t *objspace)
03046 {
03047 RVALUE *p;
03048
03049 while ((p = ATOMIC_PTR_EXCHANGE(deferred_final_list, 0)) != 0) {
03050 finalize_list(objspace, p);
03051 }
03052 }
03053
03054 void
03055 rb_gc_finalize_deferred(void)
03056 {
03057 rb_objspace_t *objspace = &rb_objspace;
03058 if (ATOMIC_EXCHANGE(finalizing, 1)) return;
03059 finalize_deferred(objspace);
03060 ATOMIC_SET(finalizing, 0);
03061 }
03062
03063 struct force_finalize_list {
03064 VALUE obj;
03065 VALUE table;
03066 struct force_finalize_list *next;
03067 };
03068
03069 static int
03070 force_chain_object(st_data_t key, st_data_t val, st_data_t arg)
03071 {
03072 struct force_finalize_list **prev = (struct force_finalize_list **)arg;
03073 struct force_finalize_list *curr = ALLOC(struct force_finalize_list);
03074 curr->obj = key;
03075 curr->table = val;
03076 curr->next = *prev;
03077 *prev = curr;
03078 return ST_CONTINUE;
03079 }
03080
03081 void
03082 rb_gc_call_finalizer_at_exit(void)
03083 {
03084 rb_objspace_call_finalizer(&rb_objspace);
03085 }
03086
03087 static void
03088 rb_objspace_call_finalizer(rb_objspace_t *objspace)
03089 {
03090 RVALUE *p, *pend;
03091 RVALUE *final_list = 0;
03092 size_t i;
03093
03094 rest_sweep(objspace);
03095
03096
03097 finalize_deferred(objspace);
03098 assert(deferred_final_list == 0);
03099
03100 if (ATOMIC_EXCHANGE(finalizing, 1)) return;
03101
03102
03103 while (finalizer_table->num_entries) {
03104 struct force_finalize_list *list = 0;
03105 st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
03106 while (list) {
03107 struct force_finalize_list *curr = list;
03108 run_finalizer(objspace, rb_obj_id(curr->obj), curr->table);
03109 st_delete(finalizer_table, (st_data_t*)&curr->obj, 0);
03110 list = curr->next;
03111 xfree(curr);
03112 }
03113 }
03114
03115
03116 during_gc++;
03117
03118
03119 for (i = 0; i < heaps_used; i++) {
03120 p = objspace->heap.sorted[i].start; pend = objspace->heap.sorted[i].end;
03121 while (p < pend) {
03122 if (BUILTIN_TYPE(p) == T_DATA &&
03123 DATA_PTR(p) && RANY(p)->as.data.dfree &&
03124 !rb_obj_is_thread((VALUE)p) && !rb_obj_is_mutex((VALUE)p) &&
03125 !rb_obj_is_fiber((VALUE)p)) {
03126 p->as.free.flags = 0;
03127 if (RTYPEDDATA_P(p)) {
03128 RDATA(p)->dfree = RANY(p)->as.typeddata.type->function.dfree;
03129 }
03130 if (RANY(p)->as.data.dfree == (RUBY_DATA_FUNC)-1) {
03131 xfree(DATA_PTR(p));
03132 }
03133 else if (RANY(p)->as.data.dfree) {
03134 make_deferred(RANY(p));
03135 RANY(p)->as.free.next = final_list;
03136 final_list = p;
03137 }
03138 }
03139 else if (BUILTIN_TYPE(p) == T_FILE) {
03140 if (RANY(p)->as.file.fptr) {
03141 make_io_deferred(RANY(p));
03142 RANY(p)->as.free.next = final_list;
03143 final_list = p;
03144 }
03145 }
03146 p++;
03147 }
03148 }
03149 during_gc = 0;
03150 if (final_list) {
03151 finalize_list(objspace, final_list);
03152 }
03153
03154 st_free_table(finalizer_table);
03155 finalizer_table = 0;
03156 ATOMIC_SET(finalizing, 0);
03157 }
03158
03159 void
03160 rb_gc(void)
03161 {
03162 rb_objspace_t *objspace = &rb_objspace;
03163 garbage_collect(objspace);
03164 if (!finalizing) finalize_deferred(objspace);
03165 free_unused_heaps(objspace);
03166 }
03167
03168
03169
03170
03171
03172
03173
03174
03175
03176
03177
03178
03179
03180
03181 static VALUE
03182 id2ref(VALUE obj, VALUE objid)
03183 {
03184 #if SIZEOF_LONG == SIZEOF_VOIDP
03185 #define NUM2PTR(x) NUM2ULONG(x)
03186 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
03187 #define NUM2PTR(x) NUM2ULL(x)
03188 #endif
03189 rb_objspace_t *objspace = &rb_objspace;
03190 VALUE ptr;
03191 void *p0;
03192
03193 rb_secure(4);
03194 ptr = NUM2PTR(objid);
03195 p0 = (void *)ptr;
03196
03197 if (ptr == Qtrue) return Qtrue;
03198 if (ptr == Qfalse) return Qfalse;
03199 if (ptr == Qnil) return Qnil;
03200 if (FIXNUM_P(ptr)) return (VALUE)ptr;
03201 ptr = obj_id_to_ref(objid);
03202
03203 if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
03204 ID symid = ptr / sizeof(RVALUE);
03205 if (rb_id2name(symid) == 0)
03206 rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
03207 return ID2SYM(symid);
03208 }
03209
03210 if (!is_pointer_to_heap(objspace, (void *)ptr) ||
03211 BUILTIN_TYPE(ptr) > T_FIXNUM || BUILTIN_TYPE(ptr) == T_ICLASS) {
03212 rb_raise(rb_eRangeError, "%p is not id value", p0);
03213 }
03214 if (BUILTIN_TYPE(ptr) == 0 || RBASIC(ptr)->klass == 0) {
03215 rb_raise(rb_eRangeError, "%p is recycled object", p0);
03216 }
03217 return (VALUE)ptr;
03218 }
03219
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246
03247 VALUE
03248 rb_obj_id(VALUE obj)
03249 {
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278 if (SYMBOL_P(obj)) {
03279 return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
03280 }
03281 if (SPECIAL_CONST_P(obj)) {
03282 return LONG2NUM((SIGNED_VALUE)obj);
03283 }
03284 return nonspecial_obj_id(obj);
03285 }
03286
03287 static int
03288 set_zero(st_data_t key, st_data_t val, st_data_t arg)
03289 {
03290 VALUE k = (VALUE)key;
03291 VALUE hash = (VALUE)arg;
03292 rb_hash_aset(hash, k, INT2FIX(0));
03293 return ST_CONTINUE;
03294 }
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316 static VALUE
03317 count_objects(int argc, VALUE *argv, VALUE os)
03318 {
03319 rb_objspace_t *objspace = &rb_objspace;
03320 size_t counts[T_MASK+1];
03321 size_t freed = 0;
03322 size_t total = 0;
03323 size_t i;
03324 VALUE hash;
03325
03326 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
03327 if (TYPE(hash) != T_HASH)
03328 rb_raise(rb_eTypeError, "non-hash given");
03329 }
03330
03331 for (i = 0; i <= T_MASK; i++) {
03332 counts[i] = 0;
03333 }
03334
03335 for (i = 0; i < heaps_used; i++) {
03336 RVALUE *p, *pend;
03337
03338 p = objspace->heap.sorted[i].start; pend = objspace->heap.sorted[i].end;
03339 for (;p < pend; p++) {
03340 if (p->as.basic.flags) {
03341 counts[BUILTIN_TYPE(p)]++;
03342 }
03343 else {
03344 freed++;
03345 }
03346 }
03347 total += objspace->heap.sorted[i].slot->limit;
03348 }
03349
03350 if (hash == Qnil) {
03351 hash = rb_hash_new();
03352 }
03353 else if (!RHASH_EMPTY_P(hash)) {
03354 st_foreach(RHASH_TBL(hash), set_zero, hash);
03355 }
03356 rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
03357 rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
03358
03359 for (i = 0; i <= T_MASK; i++) {
03360 VALUE type;
03361 switch (i) {
03362 #define COUNT_TYPE(t) case (t): type = ID2SYM(rb_intern(#t)); break;
03363 COUNT_TYPE(T_NONE);
03364 COUNT_TYPE(T_OBJECT);
03365 COUNT_TYPE(T_CLASS);
03366 COUNT_TYPE(T_MODULE);
03367 COUNT_TYPE(T_FLOAT);
03368 COUNT_TYPE(T_STRING);
03369 COUNT_TYPE(T_REGEXP);
03370 COUNT_TYPE(T_ARRAY);
03371 COUNT_TYPE(T_HASH);
03372 COUNT_TYPE(T_STRUCT);
03373 COUNT_TYPE(T_BIGNUM);
03374 COUNT_TYPE(T_FILE);
03375 COUNT_TYPE(T_DATA);
03376 COUNT_TYPE(T_MATCH);
03377 COUNT_TYPE(T_COMPLEX);
03378 COUNT_TYPE(T_RATIONAL);
03379 COUNT_TYPE(T_NIL);
03380 COUNT_TYPE(T_TRUE);
03381 COUNT_TYPE(T_FALSE);
03382 COUNT_TYPE(T_SYMBOL);
03383 COUNT_TYPE(T_FIXNUM);
03384 COUNT_TYPE(T_UNDEF);
03385 COUNT_TYPE(T_NODE);
03386 COUNT_TYPE(T_ICLASS);
03387 COUNT_TYPE(T_ZOMBIE);
03388 #undef COUNT_TYPE
03389 default: type = INT2NUM(i); break;
03390 }
03391 if (counts[i])
03392 rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
03393 }
03394
03395 return hash;
03396 }
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408 static VALUE
03409 gc_count(VALUE self)
03410 {
03411 return UINT2NUM((&rb_objspace)->count);
03412 }
03413
03414
03415
03416
03417
03418
03419
03420
03421
03422
03423
03424
03425
03426
03427
03428
03429
03430
03431
03432
03433
03434
03435
03436
03437
03438
03439 static VALUE
03440 gc_stat(int argc, VALUE *argv, VALUE self)
03441 {
03442 rb_objspace_t *objspace = &rb_objspace;
03443 VALUE hash;
03444
03445 if (rb_scan_args(argc, argv, "01", &hash) == 1) {
03446 if (TYPE(hash) != T_HASH)
03447 rb_raise(rb_eTypeError, "non-hash given");
03448 }
03449
03450 if (hash == Qnil) {
03451 hash = rb_hash_new();
03452 }
03453
03454 rest_sweep(objspace);
03455
03456 rb_hash_aset(hash, ID2SYM(rb_intern("count")), SIZET2NUM(objspace->count));
03457
03458
03459 rb_hash_aset(hash, ID2SYM(rb_intern("heap_used")), SIZET2NUM(objspace->heap.used));
03460 rb_hash_aset(hash, ID2SYM(rb_intern("heap_length")), SIZET2NUM(objspace->heap.length));
03461 rb_hash_aset(hash, ID2SYM(rb_intern("heap_increment")), SIZET2NUM(objspace->heap.increment));
03462 rb_hash_aset(hash, ID2SYM(rb_intern("heap_live_num")), SIZET2NUM(objspace->heap.live_num));
03463 rb_hash_aset(hash, ID2SYM(rb_intern("heap_free_num")), SIZET2NUM(objspace->heap.free_num));
03464 rb_hash_aset(hash, ID2SYM(rb_intern("heap_final_num")), SIZET2NUM(objspace->heap.final_num));
03465 return hash;
03466 }
03467
03468
03469 #if CALC_EXACT_MALLOC_SIZE
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479 static VALUE
03480 gc_malloc_allocated_size(VALUE self)
03481 {
03482 return UINT2NUM((&rb_objspace)->malloc_params.allocated_size);
03483 }
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494 static VALUE
03495 gc_malloc_allocations(VALUE self)
03496 {
03497 return UINT2NUM((&rb_objspace)->malloc_params.allocations);
03498 }
03499 #endif
03500
03501 static VALUE
03502 gc_profile_record_get(void)
03503 {
03504 VALUE prof;
03505 VALUE gc_profile = rb_ary_new();
03506 size_t i;
03507 rb_objspace_t *objspace = (&rb_objspace);
03508
03509 if (!objspace->profile.run) {
03510 return Qnil;
03511 }
03512
03513 for (i =0; i < objspace->profile.count; i++) {
03514 prof = rb_hash_new();
03515 rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DBL2NUM(objspace->profile.record[i].gc_time));
03516 rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DBL2NUM(objspace->profile.record[i].gc_invoke_time));
03517 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), SIZET2NUM(objspace->profile.record[i].heap_use_size));
03518 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), SIZET2NUM(objspace->profile.record[i].heap_total_size));
03519 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_total_objects));
03520 rb_hash_aset(prof, ID2SYM(rb_intern("GC_IS_MARKED")), objspace->profile.record[i].is_marked);
03521 #if GC_PROFILE_MORE_DETAIL
03522 rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DBL2NUM(objspace->profile.record[i].gc_mark_time));
03523 rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DBL2NUM(objspace->profile.record[i].gc_sweep_time));
03524 rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), SIZET2NUM(objspace->profile.record[i].allocate_increase));
03525 rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), SIZET2NUM(objspace->profile.record[i].allocate_limit));
03526 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SLOTS")), SIZET2NUM(objspace->profile.record[i].heap_use_slots));
03527 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_live_objects));
03528 rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_free_objects));
03529 rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), objspace->profile.record[i].have_finalize);
03530 #endif
03531 rb_ary_push(gc_profile, prof);
03532 }
03533
03534 return gc_profile;
03535 }
03536
03537
03538
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548 static VALUE
03549 gc_profile_result(void)
03550 {
03551 rb_objspace_t *objspace = &rb_objspace;
03552 VALUE record;
03553 VALUE result;
03554 int i, index;
03555
03556 record = gc_profile_record_get();
03557 if (objspace->profile.run && objspace->profile.count) {
03558 result = rb_sprintf("GC %d invokes.\n", NUM2INT(gc_count(0)));
03559 index = 1;
03560 rb_str_cat2(result, "Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC Time(ms)\n");
03561 for (i = 0; i < (int)RARRAY_LEN(record); i++) {
03562 VALUE r = RARRAY_PTR(record)[i];
03563 #if !GC_PROFILE_MORE_DETAIL
03564 if (rb_hash_aref(r, ID2SYM(rb_intern("GC_IS_MARKED")))) {
03565 #endif
03566 rb_str_catf(result, "%5d %19.3f %20"PRIuSIZE" %20"PRIuSIZE" %20"PRIuSIZE" %30.20f\n",
03567 index++, NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_INVOKE_TIME")))),
03568 (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SIZE")))),
03569 (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")))),
03570 (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")))),
03571 NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_TIME"))))*1000);
03572 #if !GC_PROFILE_MORE_DETAIL
03573 }
03574 #endif
03575 }
03576 #if GC_PROFILE_MORE_DETAIL
03577 rb_str_cat2(result, "\n\n");
03578 rb_str_cat2(result, "More detail.\n");
03579 rb_str_cat2(result, "Index Allocate Increase Allocate Limit Use Slot Have Finalize Mark Time(ms) Sweep Time(ms)\n");
03580 index = 1;
03581 for (i = 0; i < (int)RARRAY_LEN(record); i++) {
03582 VALUE r = RARRAY_PTR(record)[i];
03583 rb_str_catf(result, "%5d %17"PRIuSIZE" %17"PRIuSIZE" %9"PRIuSIZE" %14s %25.20f %25.20f\n",
03584 index++, (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_INCREASE")))),
03585 (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_LIMIT")))),
03586 (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SLOTS")))),
03587 rb_hash_aref(r, ID2SYM(rb_intern("HAVE_FINALIZE")))? "true" : "false",
03588 NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_MARK_TIME"))))*1000,
03589 NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_SWEEP_TIME"))))*1000);
03590 }
03591 #endif
03592 }
03593 else {
03594 result = rb_str_new2("");
03595 }
03596 return result;
03597 }
03598
03599
03600
03601
03602
03603
03604
03605
03606
03607
03608
03609 static VALUE
03610 gc_profile_report(int argc, VALUE *argv, VALUE self)
03611 {
03612 VALUE out;
03613
03614 if (argc == 0) {
03615 out = rb_stdout;
03616 }
03617 else {
03618 rb_scan_args(argc, argv, "01", &out);
03619 }
03620 rb_io_write(out, gc_profile_result());
03621
03622 return Qnil;
03623 }
03624
03625
03626
03627
03628
03629
03630
03631
03632 static VALUE
03633 gc_profile_total_time(VALUE self)
03634 {
03635 double time = 0;
03636 rb_objspace_t *objspace = &rb_objspace;
03637 size_t i;
03638
03639 if (objspace->profile.run && objspace->profile.count) {
03640 for (i = 0; i < objspace->profile.count; i++) {
03641 time += objspace->profile.record[i].gc_time;
03642 }
03643 }
03644 return DBL2NUM(time);
03645 }
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671
03672
03673
03674 void
03675 Init_GC(void)
03676 {
03677 VALUE rb_mObSpace;
03678 VALUE rb_mProfiler;
03679
03680 rb_mGC = rb_define_module("GC");
03681 rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0);
03682 rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
03683 rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
03684 rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0);
03685 rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1);
03686 rb_define_singleton_method(rb_mGC, "count", gc_count, 0);
03687 rb_define_singleton_method(rb_mGC, "stat", gc_stat, -1);
03688 rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
03689
03690 rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler");
03691 rb_define_singleton_method(rb_mProfiler, "enabled?", gc_profile_enable_get, 0);
03692 rb_define_singleton_method(rb_mProfiler, "enable", gc_profile_enable, 0);
03693 rb_define_singleton_method(rb_mProfiler, "disable", gc_profile_disable, 0);
03694 rb_define_singleton_method(rb_mProfiler, "clear", gc_profile_clear, 0);
03695 rb_define_singleton_method(rb_mProfiler, "result", gc_profile_result, 0);
03696 rb_define_singleton_method(rb_mProfiler, "report", gc_profile_report, -1);
03697 rb_define_singleton_method(rb_mProfiler, "total_time", gc_profile_total_time, 0);
03698
03699 rb_mObSpace = rb_define_module("ObjectSpace");
03700 rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
03701 rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);
03702
03703 rb_define_module_function(rb_mObSpace, "define_finalizer", define_final, -1);
03704 rb_define_module_function(rb_mObSpace, "undefine_finalizer", undefine_final, 1);
03705
03706 rb_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1);
03707
03708 nomem_error = rb_exc_new3(rb_eNoMemError,
03709 rb_obj_freeze(rb_str_new2("failed to allocate memory")));
03710 OBJ_TAINT(nomem_error);
03711 OBJ_FREEZE(nomem_error);
03712
03713 rb_define_method(rb_cBasicObject, "__id__", rb_obj_id, 0);
03714 rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
03715
03716 rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1);
03717
03718 #if CALC_EXACT_MALLOC_SIZE
03719 rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
03720 rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
03721 #endif
03722 }
03723