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