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