Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# gc.c

Go to the documentation of this file.

    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