OSDN Git Service

ruby-1.9.1-rc1
[splhack/AndroidRuby.git] / lib / ruby-1.9.1-rc1 / gc.c
1 /**********************************************************************
2
3   gc.c -
4
5   $Author: yugui $
6   created at: Tue Oct  5 09:44:46 JST 1993
7
8   Copyright (C) 1993-2007 Yukihiro Matsumoto
9   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
10   Copyright (C) 2000  Information-technology Promotion Agency, Japan
11
12 **********************************************************************/
13
14 #include "ruby/ruby.h"
15 #include "ruby/st.h"
16 #include "ruby/re.h"
17 #include "ruby/io.h"
18 #include "ruby/util.h"
19 #include "eval_intern.h"
20 #include "vm_core.h"
21 #include "gc.h"
22 #include <stdio.h>
23 #include <setjmp.h>
24 #include <sys/types.h>
25
26 #ifdef HAVE_SYS_TIME_H
27 #include <sys/time.h>
28 #endif
29
30 #ifdef HAVE_SYS_RESOURCE_H
31 #include <sys/resource.h>
32 #endif
33
34 #if defined _WIN32 || defined __CYGWIN__
35 #include <windows.h>
36 #endif
37
38 #ifdef HAVE_VALGRIND_MEMCHECK_H
39 # include <valgrind/memcheck.h>
40 # ifndef VALGRIND_MAKE_MEM_DEFINED
41 #  define VALGRIND_MAKE_MEM_DEFINED(p, n) VALGRIND_MAKE_READABLE(p, n)
42 # endif
43 # ifndef VALGRIND_MAKE_MEM_UNDEFINED
44 #  define VALGRIND_MAKE_MEM_UNDEFINED(p, n) VALGRIND_MAKE_WRITABLE(p, n)
45 # endif
46 #else
47 # define VALGRIND_MAKE_MEM_DEFINED(p, n) /* empty */
48 # define VALGRIND_MAKE_MEM_UNDEFINED(p, n) /* empty */
49 #endif
50
51 int rb_io_fptr_finalize(struct rb_io_t*);
52
53 #define rb_setjmp(env) RUBY_SETJMP(env)
54 #define rb_jmp_buf rb_jmpbuf_t
55
56 /* Make alloca work the best possible way.  */
57 #ifdef __GNUC__
58 # ifndef atarist
59 #  ifndef alloca
60 #   define alloca __builtin_alloca
61 #  endif
62 # endif /* atarist */
63 #else
64 # ifdef HAVE_ALLOCA_H
65 #  include <alloca.h>
66 # else
67 #  ifdef _AIX
68  #pragma alloca
69 #  else
70 #   ifndef alloca /* predefined by HP cc +Olibcalls */
71 void *alloca ();
72 #   endif
73 #  endif /* AIX */
74 # endif /* HAVE_ALLOCA_H */
75 #endif /* __GNUC__ */
76
77 #ifndef GC_MALLOC_LIMIT
78 #define GC_MALLOC_LIMIT 8000000
79 #endif
80
81 #define nomem_error GET_VM()->special_exceptions[ruby_error_nomemory]
82
83 #define MARK_STACK_MAX 1024
84
85 int ruby_gc_debug_indent = 0;
86
87 #undef GC_DEBUG
88
89 /* for GC profile */
90 #define GC_PROFILE_MORE_DETAIL 0
91 typedef struct gc_profile_record {
92     double gc_time;
93     double gc_mark_time;
94     double gc_sweep_time;
95     double gc_invoke_time;
96     size_t heap_use_slots;
97     size_t heap_live_objects;
98     size_t heap_free_objects;
99     size_t heap_total_objects;
100     size_t heap_use_size;
101     size_t heap_total_size;
102     int have_finalize;
103     size_t allocate_increase;
104     size_t allocate_limit;
105 } gc_profile_record;
106
107 static double
108 getrusage_time(void)
109 {
110 #ifdef RUSAGE_SELF
111     struct rusage usage;
112     struct timeval time;
113     getrusage(RUSAGE_SELF, &usage);
114     time = usage.ru_utime;
115     return time.tv_sec + time.tv_usec * 1e-6;
116 #elif defined _WIN32
117     FILETIME creation_time, exit_time, kernel_time, user_time;
118     ULARGE_INTEGER ui;
119     LONG_LONG q;
120     double t;
121     
122     if (GetProcessTimes(GetCurrentProcess(),
123                         &creation_time, &exit_time, &kernel_time, &user_time) == 0)
124     {
125         return 0.0;
126     }
127     memcpy(&ui, &user_time, sizeof(FILETIME));
128     q = ui.QuadPart / 10L;
129     t = (DWORD)(q % 1000000L) * 1e-6;
130     q /= 1000000L;
131 #ifdef __GNUC__
132     t += q;
133 #else
134     t += (double)(DWORD)(q >> 16) * (1 << 16);
135     t += (DWORD)q & ~(~0 << 16);
136 #endif
137     return t;
138 #else
139     return 0.0;
140 #endif
141 }
142
143 #define GC_PROF_TIMER_START do {\
144         if (objspace->profile.run) {\
145             if (!objspace->profile.record) {\
146                 objspace->profile.size = 1000;\
147                 objspace->profile.record = malloc(sizeof(gc_profile_record) * objspace->profile.size);\
148             }\
149             if (count >= objspace->profile.size) {\
150                 objspace->profile.size += 1000;\
151                 objspace->profile.record = realloc(objspace->profile.record, sizeof(gc_profile_record) * objspace->profile.size);\
152             }\
153             if (!objspace->profile.record) {\
154                 rb_bug("gc_profile malloc or realloc miss");\
155             }\
156             MEMZERO(&objspace->profile.record[count], gc_profile_record, 1);\
157             gc_time = getrusage_time();\
158             objspace->profile.record[count].gc_invoke_time = gc_time - objspace->profile.invoke_time;\
159         }\
160     } while(0)
161
162 #define GC_PROF_TIMER_STOP do {\
163         if (objspace->profile.run) {\
164             gc_time = getrusage_time() - gc_time;\
165             if (gc_time < 0) gc_time = 0;\
166             objspace->profile.record[count].gc_time = gc_time;\
167             objspace->profile.count++;\
168         }\
169     } while(0)
170
171 #if GC_PROFILE_MORE_DETAIL
172 #define INIT_GC_PROF_PARAMS double gc_time = 0, mark_time = 0, sweep_time = 0;\
173     size_t count = objspace->profile.count
174
175 #define GC_PROF_MARK_TIMER_START do {\
176         if (objspace->profile.run) {\
177             mark_time = getrusage_time();\
178         }\
179     } while(0)
180
181 #define GC_PROF_MARK_TIMER_STOP do {\
182         if (objspace->profile.run) {\
183             mark_time = getrusage_time() - mark_time;\
184             if (mark_time < 0) mark_time = 0;\
185             objspace->profile.record[count].gc_mark_time = mark_time;\
186         }\
187     } while(0)
188
189 #define GC_PROF_SWEEP_TIMER_START do {\
190         if (objspace->profile.run) {\
191             sweep_time = getrusage_time();\
192         }\
193     } while(0)
194
195 #define GC_PROF_SWEEP_TIMER_STOP do {\
196         if (objspace->profile.run) {\
197             sweep_time = getrusage_time() - sweep_time;\
198             if (sweep_time < 0) sweep_time = 0;\
199             objspace->profile.record[count].gc_sweep_time = sweep_time;\
200         }\
201     } while(0)
202 #define GC_PROF_SET_MALLOC_INFO do {\
203         if (objspace->profile.run) {\
204             size_t count = objspace->profile.count;\
205             objspace->profile.record[count].allocate_increase = malloc_increase;\
206             objspace->profile.record[count].allocate_limit = malloc_limit; \
207         }\
208     } while(0)
209 #define GC_PROF_SET_HEAP_INFO do {\
210         if (objspace->profile.run) {\
211             size_t count = objspace->profile.count;\
212             objspace->profile.record[count].heap_use_slots = heaps_used;\
213             objspace->profile.record[count].heap_live_objects = live;\
214             objspace->profile.record[count].heap_free_objects = freed;\
215             objspace->profile.record[count].heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
216             objspace->profile.record[count].have_finalize = final_list ? Qtrue : Qfalse;\
217             objspace->profile.record[count].heap_use_size = live * sizeof(RVALUE);\
218             objspace->profile.record[count].heap_total_size = heaps_used * (HEAP_OBJ_LIMIT * sizeof(RVALUE));\
219         }\
220     } while(0)
221
222 #else
223 #define INIT_GC_PROF_PARAMS double gc_time = 0;\
224     size_t count = objspace->profile.count
225 #define GC_PROF_MARK_TIMER_START
226 #define GC_PROF_MARK_TIMER_STOP
227 #define GC_PROF_SWEEP_TIMER_START
228 #define GC_PROF_SWEEP_TIMER_STOP
229 #define GC_PROF_SET_MALLOC_INFO
230 #define GC_PROF_SET_HEAP_INFO do {\
231         if (objspace->profile.run) {\
232             size_t count = objspace->profile.count;\
233             objspace->profile.record[count].heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
234             objspace->profile.record[count].heap_use_size = live * sizeof(RVALUE);\
235             objspace->profile.record[count].heap_total_size = heaps_used * HEAP_SIZE;\
236         }\
237     } while(0)
238 #endif
239
240
241 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
242 #pragma pack(push, 1) /* magic for reducing sizeof(RVALUE): 24 -> 20 */
243 #endif
244
245 typedef struct RVALUE {
246     union {
247         struct {
248             VALUE flags;                /* always 0 for freed obj */
249             struct RVALUE *next;
250         } free;
251         struct RBasic  basic;
252         struct RObject object;
253         struct RClass  klass;
254         struct RFloat  flonum;
255         struct RString string;
256         struct RArray  array;
257         struct RRegexp regexp;
258         struct RHash   hash;
259         struct RData   data;
260         struct RStruct rstruct;
261         struct RBignum bignum;
262         struct RFile   file;
263         struct RNode   node;
264         struct RMatch  match;
265         struct RRational rational;
266         struct RComplex complex;
267     } as;
268 #ifdef GC_DEBUG
269     char *file;
270     int   line;
271 #endif
272 } RVALUE;
273
274 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
275 #pragma pack(pop)
276 #endif
277
278 struct heaps_slot {
279     void *membase;
280     RVALUE *slot;
281     int limit;
282 };
283
284 #define HEAP_MIN_SLOTS 10000
285 #define FREE_MIN  4096
286
287 struct gc_list {
288     VALUE *varptr;
289     struct gc_list *next;
290 };
291
292 #define CALC_EXACT_MALLOC_SIZE 0
293
294 typedef struct rb_objspace {
295     struct {
296         size_t limit;
297         size_t increase;
298 #if CALC_EXACT_MALLOC_SIZE
299         size_t allocated_size;
300         size_t allocations;
301 #endif
302     } malloc_params;
303     struct {
304         size_t increment;
305         struct heaps_slot *ptr;
306         size_t length;
307         size_t used;
308         RVALUE *freelist;
309         RVALUE *range[2];
310         RVALUE *freed;
311     } heap;
312     struct {
313         int dont_gc;
314         int during_gc;
315     } flags;
316     struct {
317         st_table *table;
318         RVALUE *deferred;
319     } final;
320     struct {
321         VALUE buffer[MARK_STACK_MAX];
322         VALUE *ptr;
323         int overflow;
324     } markstack;
325     struct {
326         int run;
327         gc_profile_record *record;
328         size_t count;
329         size_t size;
330         double invoke_time;
331     } profile;
332     struct gc_list *global_list;
333     unsigned int count;
334     int gc_stress;
335 } rb_objspace_t;
336
337 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
338 #define rb_objspace (*GET_VM()->objspace)
339 static int ruby_initial_gc_stress = 0;
340 int *ruby_initial_gc_stress_ptr = &ruby_initial_gc_stress;
341 #else
342 static rb_objspace_t rb_objspace = {{GC_MALLOC_LIMIT}, {HEAP_MIN_SLOTS}};
343 int *ruby_initial_gc_stress_ptr = &rb_objspace.gc_stress;
344 #endif
345 #define malloc_limit            objspace->malloc_params.limit
346 #define malloc_increase         objspace->malloc_params.increase
347 #define heap_slots              objspace->heap.slots
348 #define heaps                   objspace->heap.ptr
349 #define heaps_length            objspace->heap.length
350 #define heaps_used              objspace->heap.used
351 #define freelist                objspace->heap.freelist
352 #define lomem                   objspace->heap.range[0]
353 #define himem                   objspace->heap.range[1]
354 #define heaps_inc               objspace->heap.increment
355 #define heaps_freed             objspace->heap.freed
356 #define dont_gc                 objspace->flags.dont_gc
357 #define during_gc               objspace->flags.during_gc
358 #define finalizer_table         objspace->final.table
359 #define deferred_final_list     objspace->final.deferred
360 #define mark_stack              objspace->markstack.buffer
361 #define mark_stack_ptr          objspace->markstack.ptr
362 #define mark_stack_overflow     objspace->markstack.overflow
363 #define global_List             objspace->global_list
364 #define ruby_gc_stress          objspace->gc_stress
365
366 #define need_call_final         (finalizer_table && finalizer_table->num_entries)
367
368 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
369 rb_objspace_t *
370 rb_objspace_alloc(void)
371 {
372     rb_objspace_t *objspace = malloc(sizeof(rb_objspace_t));
373     memset(objspace, 0, sizeof(*objspace));
374     malloc_limit = GC_MALLOC_LIMIT;
375     ruby_gc_stress = ruby_initial_gc_stress;
376
377     return objspace;
378 }
379 #endif
380
381 /* tiny heap size */
382 /* 32KB */
383 /*#define HEAP_SIZE 0x8000 */
384 /* 128KB */
385 /*#define HEAP_SIZE 0x20000 */
386 /* 64KB */
387 /*#define HEAP_SIZE 0x10000 */
388 /* 16KB */
389 #define HEAP_SIZE 0x4000
390 /* 8KB */
391 /*#define HEAP_SIZE 0x2000 */
392 /* 4KB */
393 /*#define HEAP_SIZE 0x1000 */
394 /* 2KB */
395 /*#define HEAP_SIZE 0x800 */
396
397 #define HEAP_OBJ_LIMIT (HEAP_SIZE / sizeof(struct RVALUE))
398
399 extern VALUE rb_cMutex;
400 extern st_table *rb_class_tbl;
401
402 int ruby_disable_gc_stress = 0;
403
404 static void run_final(rb_objspace_t *objspace, VALUE obj);
405 static int garbage_collect(rb_objspace_t *objspace);
406
407 void
408 rb_global_variable(VALUE *var)
409 {
410     rb_gc_register_address(var);
411 }
412
413 void
414 rb_memerror(void)
415 {
416     rb_thread_t *th = GET_THREAD();
417     if (!nomem_error ||
418         (rb_thread_raised_p(th, RAISED_NOMEMORY) && rb_safe_level() < 4)) {
419         fprintf(stderr, "[FATAL] failed to allocate memory\n");
420         exit(EXIT_FAILURE);
421     }
422     if (rb_thread_raised_p(th, RAISED_NOMEMORY)) {
423         rb_thread_raised_clear(th);
424         GET_THREAD()->errinfo = nomem_error;
425         JUMP_TAG(TAG_RAISE);
426     }
427     rb_thread_raised_set(th, RAISED_NOMEMORY);
428     rb_exc_raise(nomem_error);
429 }
430
431 /*
432  *  call-seq:
433  *    GC.stress                 => true or false
434  *
435  *  returns current status of GC stress mode.
436  */
437
438 static VALUE
439 gc_stress_get(VALUE self)
440 {
441     rb_objspace_t *objspace = &rb_objspace;
442     return ruby_gc_stress ? Qtrue : Qfalse;
443 }
444
445 /*
446  *  call-seq:
447  *    GC.stress = bool          => bool
448  *
449  *  updates GC stress mode.
450  *
451  *  When GC.stress = true, GC is invoked for all GC opportunity:
452  *  all memory and object allocation.
453  *
454  *  Since it makes Ruby very slow, it is only for debugging.
455  */
456
457 static VALUE
458 gc_stress_set(VALUE self, VALUE bool)
459 {
460     rb_objspace_t *objspace = &rb_objspace;
461     rb_secure(2);
462     ruby_gc_stress = RTEST(bool);
463     return bool;
464 }
465
466 /*
467  *  call-seq:
468  *    GC::Profiler.enable?                 => true or false
469  *
470  *  returns current status of GC profile mode.
471  */
472
473 static VALUE
474 gc_profile_enable_get(VALUE self)
475 {
476     rb_objspace_t *objspace = &rb_objspace;
477     return objspace->profile.run;
478 }
479
480 /*
481  *  call-seq:
482  *    GC::Profiler.enable          => nil
483  *
484  *  updates GC profile mode.
485  *  start profiler for GC.
486  *
487  */
488
489 static VALUE
490 gc_profile_enable(void)
491 {
492     rb_objspace_t *objspace = &rb_objspace;
493
494     objspace->profile.run = Qtrue;
495     return Qnil;
496 }
497
498 /*
499  *  call-seq:
500  *    GC::Profiler.disable          => nil
501  *
502  *  updates GC profile mode.
503  *  stop profiler for GC.
504  *
505  */
506
507 static VALUE
508 gc_profile_disable(void)
509 {
510     rb_objspace_t *objspace = &rb_objspace;
511
512     objspace->profile.run = Qfalse;
513     return Qnil;
514 }
515
516 /*
517  *  call-seq:
518  *    GC::Profiler.clear          => nil
519  *
520  *  clear before profile data.
521  *
522  */
523
524 static VALUE
525 gc_profile_clear(void)
526 {
527     rb_objspace_t *objspace = &rb_objspace;
528     MEMZERO(objspace->profile.record, gc_profile_record, objspace->profile.size);
529     objspace->profile.count = 0;
530     return Qnil;
531 }
532
533 static void *
534 vm_xmalloc(rb_objspace_t *objspace, size_t size)
535 {
536     void *mem;
537
538     if (size < 0) {
539         rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
540     }
541     if (size == 0) size = 1;
542
543 #if CALC_EXACT_MALLOC_SIZE
544     size += sizeof(size_t);
545 #endif
546
547     if ((ruby_gc_stress && !ruby_disable_gc_stress) ||
548         (malloc_increase+size) > malloc_limit) {
549         garbage_collect(objspace);
550     }
551     mem = malloc(size);
552     if (!mem) {
553         if (garbage_collect(objspace)) {
554             mem = malloc(size);
555         }
556         if (!mem) {
557             rb_memerror();
558         }
559     }
560     malloc_increase += size;
561
562 #if CALC_EXACT_MALLOC_SIZE
563     objspace->malloc_params.allocated_size += size;
564     objspace->malloc_params.allocations++;
565     ((size_t *)mem)[0] = size;
566     mem = (size_t *)mem + 1;
567 #endif
568
569     return mem;
570 }
571
572 static void *
573 vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size)
574 {
575     void *mem;
576
577     if (size < 0) {
578         rb_raise(rb_eArgError, "negative re-allocation size");
579     }
580     if (!ptr) return ruby_xmalloc(size);
581     if (size == 0) size = 1;
582     if (ruby_gc_stress && !ruby_disable_gc_stress) garbage_collect(objspace);
583
584 #if CALC_EXACT_MALLOC_SIZE
585     size += sizeof(size_t);
586     objspace->malloc_params.allocated_size -= size;
587     ptr = (size_t *)ptr - 1;
588 #endif
589
590     mem = realloc(ptr, size);
591     if (!mem) {
592         if (garbage_collect(objspace)) {
593             mem = realloc(ptr, size);
594         }
595         if (!mem) {
596             rb_memerror();
597         }
598     }
599     malloc_increase += size;
600
601 #if CALC_EXACT_MALLOC_SIZE
602     objspace->malloc_params.allocated_size += size;
603     ((size_t *)mem)[0] = size;
604     mem = (size_t *)mem + 1;
605 #endif
606
607     return mem;
608 }
609
610 static void
611 vm_xfree(rb_objspace_t *objspace, void *ptr)
612 {
613 #if CALC_EXACT_MALLOC_SIZE
614     size_t size;
615     ptr = ((size_t *)ptr) - 1;
616     size = ((size_t*)ptr)[0];
617     objspace->malloc_params.allocated_size -= size;
618     objspace->malloc_params.allocations--;
619 #endif
620
621     free(ptr);
622 }
623
624 void *
625 ruby_xmalloc(size_t size)
626 {
627     return vm_xmalloc(&rb_objspace, size);
628 }
629
630 void *
631 ruby_xmalloc2(size_t n, size_t size)
632 {
633     size_t len = size * n;
634     if (n != 0 && size != len / n) {
635         rb_raise(rb_eArgError, "malloc: possible integer overflow");
636     }
637     return vm_xmalloc(&rb_objspace, len);
638 }
639
640 void *
641 ruby_xcalloc(size_t n, size_t size)
642 {
643     void *mem = ruby_xmalloc2(n, size);
644     memset(mem, 0, n * size);
645
646     return mem;
647 }
648
649 void *
650 ruby_xrealloc(void *ptr, size_t size)
651 {
652     return vm_xrealloc(&rb_objspace, ptr, size);
653 }
654
655 void *
656 ruby_xrealloc2(void *ptr, size_t n, size_t size)
657 {
658     size_t len = size * n;
659     if (n != 0 && size != len / n) {
660         rb_raise(rb_eArgError, "realloc: possible integer overflow");
661     }
662     return ruby_xrealloc(ptr, len);
663 }
664
665 void
666 ruby_xfree(void *x)
667 {
668     if (x)
669       vm_xfree(&rb_objspace, x);
670 }
671
672
673 /*
674  *  call-seq:
675  *     GC.enable    => true or false
676  *
677  *  Enables garbage collection, returning <code>true</code> if garbage
678  *  collection was previously disabled.
679  *
680  *     GC.disable   #=> false
681  *     GC.enable    #=> true
682  *     GC.enable    #=> false
683  *
684  */
685
686 VALUE
687 rb_gc_enable(void)
688 {
689     rb_objspace_t *objspace = &rb_objspace;
690     int old = dont_gc;
691
692     dont_gc = Qfalse;
693     return old;
694 }
695
696 /*
697  *  call-seq:
698  *     GC.disable    => true or false
699  *
700  *  Disables garbage collection, returning <code>true</code> if garbage
701  *  collection was already disabled.
702  *
703  *     GC.disable   #=> false
704  *     GC.disable   #=> true
705  *
706  */
707
708 VALUE
709 rb_gc_disable(void)
710 {
711     rb_objspace_t *objspace = &rb_objspace;
712     int old = dont_gc;
713
714     dont_gc = Qtrue;
715     return old;
716 }
717
718 VALUE rb_mGC;
719
720 void
721 rb_gc_register_mark_object(VALUE obj)
722 {
723     VALUE ary = GET_THREAD()->vm->mark_object_ary;
724     rb_ary_push(ary, obj);
725 }
726
727 void
728 rb_gc_register_address(VALUE *addr)
729 {
730     rb_objspace_t *objspace = &rb_objspace;
731     struct gc_list *tmp;
732
733     tmp = ALLOC(struct gc_list);
734     tmp->next = global_List;
735     tmp->varptr = addr;
736     global_List = tmp;
737 }
738
739 void
740 rb_gc_unregister_address(VALUE *addr)
741 {
742     rb_objspace_t *objspace = &rb_objspace;
743     struct gc_list *tmp = global_List;
744
745     if (tmp->varptr == addr) {
746         global_List = tmp->next;
747         xfree(tmp);
748         return;
749     }
750     while (tmp->next) {
751         if (tmp->next->varptr == addr) {
752             struct gc_list *t = tmp->next;
753
754             tmp->next = tmp->next->next;
755             xfree(t);
756             break;
757         }
758         tmp = tmp->next;
759     }
760 }
761
762
763 static void
764 allocate_heaps(rb_objspace_t *objspace, size_t next_heaps_length)
765 {
766     struct heaps_slot *p;
767     size_t size;
768
769     size = next_heaps_length*sizeof(struct heaps_slot);
770
771     if (heaps_used > 0) {
772         p = (struct heaps_slot *)realloc(heaps, size);
773         if (p) heaps = p;
774     }
775     else {
776         p = heaps = (struct heaps_slot *)malloc(size);
777     }
778
779     if (p == 0) {
780         during_gc = 0;
781         rb_memerror();
782     }
783     heaps_length = next_heaps_length;
784 }
785
786 static void
787 assign_heap_slot(rb_objspace_t *objspace)
788 {
789     RVALUE *p, *pend, *membase;
790     size_t hi, lo, mid;
791     int objs;
792         
793     objs = HEAP_OBJ_LIMIT;
794     p = (RVALUE*)malloc(HEAP_SIZE);
795
796     if (p == 0) {
797         during_gc = 0;
798         rb_memerror();
799     }
800
801     membase = p;
802     if ((VALUE)p % sizeof(RVALUE) != 0) {
803         p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
804         if ((HEAP_SIZE - HEAP_OBJ_LIMIT * sizeof(RVALUE)) < ((char*)p - (char*)membase)) {
805             objs--;
806         }
807     }
808
809     lo = 0;
810     hi = heaps_used;
811     while (lo < hi) {
812         register RVALUE *mid_membase;
813         mid = (lo + hi) / 2;
814         mid_membase = heaps[mid].membase;
815         if (mid_membase < membase) {
816             lo = mid + 1;
817         }
818         else if (mid_membase > membase) {
819             hi = mid;
820         }
821         else {
822             rb_bug("same heap slot is allocated: %p at %"PRIuVALUE, (void *)membase, (VALUE)mid);
823         }
824     }
825     if (hi < heaps_used) {
826         MEMMOVE(&heaps[hi+1], &heaps[hi], struct heaps_slot, heaps_used - hi);
827     }
828     heaps[hi].membase = membase;
829     heaps[hi].slot = p;
830     heaps[hi].limit = objs;
831     pend = p + objs;
832     if (lomem == 0 || lomem > p) lomem = p;
833     if (himem < pend) himem = pend;
834     heaps_used++;
835
836     while (p < pend) {
837         p->as.free.flags = 0;
838         p->as.free.next = freelist;
839         freelist = p;
840         p++;
841     }
842 }
843
844 static void
845 init_heap(rb_objspace_t *objspace)
846 {
847     size_t add, i;
848
849     add = HEAP_MIN_SLOTS / HEAP_OBJ_LIMIT;
850
851     if ((heaps_used + add) > heaps_length) {
852         allocate_heaps(objspace, heaps_used + add);
853     }
854
855     for (i = 0; i < add; i++) {
856         assign_heap_slot(objspace);
857     }
858     heaps_inc = 0;
859     objspace->profile.invoke_time = getrusage_time();
860 }
861
862
863 static void
864 set_heaps_increment(rb_objspace_t *objspace)
865 {
866     size_t next_heaps_length = heaps_used * 1.8;
867     heaps_inc = next_heaps_length - heaps_used;
868
869     if (next_heaps_length > heaps_length) {
870         allocate_heaps(objspace, next_heaps_length);
871     }
872 }
873
874 static int
875 heaps_increment(rb_objspace_t *objspace)
876 {
877     if (heaps_inc > 0) {
878         assign_heap_slot(objspace);
879         heaps_inc--;
880         return Qtrue;
881     }
882     return Qfalse;
883 }
884
885 #define RANY(o) ((RVALUE*)(o))
886
887 static VALUE
888 rb_newobj_from_heap(rb_objspace_t *objspace)
889 {
890     VALUE obj;
891         
892     if ((ruby_gc_stress && !ruby_disable_gc_stress) || !freelist) {
893         if (!heaps_increment(objspace) && !garbage_collect(objspace)) {
894             during_gc = 0;
895             rb_memerror();
896         }
897     }
898
899     obj = (VALUE)freelist;
900     freelist = freelist->as.free.next;
901
902     MEMZERO((void*)obj, RVALUE, 1);
903 #ifdef GC_DEBUG
904     RANY(obj)->file = rb_sourcefile();
905     RANY(obj)->line = rb_sourceline();
906 #endif
907
908     return obj;
909 }
910
911 #if USE_VALUE_CACHE
912 static VALUE
913 rb_fill_value_cache(rb_thread_t *th)
914 {
915     rb_objspace_t *objspace = &rb_objspace;
916     int i;
917     VALUE rv;
918
919     /* LOCK */
920     for (i=0; i<RUBY_VM_VALUE_CACHE_SIZE; i++) {
921         VALUE v = rb_newobj_from_heap(objspace);
922
923         th->value_cache[i] = v;
924         RBASIC(v)->flags = FL_MARK;
925     }
926     th->value_cache_ptr = &th->value_cache[0];
927     rv = rb_newobj_from_heap(objspace);
928     /* UNLOCK */
929     return rv;
930 }
931 #endif
932
933 int
934 rb_during_gc(void)
935 {
936     rb_objspace_t *objspace = &rb_objspace;
937     return during_gc;
938 }
939  
940 VALUE
941 rb_newobj(void)
942 {
943 #if USE_VALUE_CACHE || (defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE)
944     rb_thread_t *th = GET_THREAD();
945 #endif
946 #if USE_VALUE_CACHE
947     VALUE v = *th->value_cache_ptr;
948 #endif
949 #if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
950     rb_objspace_t *objspace = th->vm->objspace;
951 #else
952     rb_objspace_t *objspace = &rb_objspace;
953 #endif
954
955     if (during_gc) {
956         dont_gc = 1;
957         during_gc = 0;
958         rb_bug("object allocation during garbage collection phase");
959     }
960
961 #if USE_VALUE_CACHE
962     if (v) {
963         RBASIC(v)->flags = 0;
964         th->value_cache_ptr++;
965     }
966     else {
967         v = rb_fill_value_cache(th);
968     }
969
970 #if defined(GC_DEBUG)
971     printf("cache index: %d, v: %p, th: %p\n",
972            th->value_cache_ptr - th->value_cache, v, th);
973 #endif
974     return v;
975 #else
976     return rb_newobj_from_heap(objspace);
977 #endif
978 }
979
980 NODE*
981 rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
982 {
983     NODE *n = (NODE*)rb_newobj();
984
985     n->flags |= T_NODE;
986     nd_set_type(n, type);
987
988     n->u1.value = a0;
989     n->u2.value = a1;
990     n->u3.value = a2;
991
992     return n;
993 }
994
995 VALUE
996 rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
997 {
998     NEWOBJ(data, struct RData);
999     if (klass) Check_Type(klass, T_CLASS);
1000     OBJSETUP(data, klass, T_DATA);
1001     data->data = datap;
1002     data->dfree = dfree;
1003     data->dmark = dmark;
1004
1005     return (VALUE)data;
1006 }
1007
1008 #ifdef __ia64
1009 #define SET_STACK_END (SET_MACHINE_STACK_END(&th->machine_stack_end), th->machine_register_stack_end = rb_ia64_bsp())
1010 #else
1011 #define SET_STACK_END SET_MACHINE_STACK_END(&th->machine_stack_end)
1012 #endif
1013
1014 #define STACK_START (th->machine_stack_start)
1015 #define STACK_END (th->machine_stack_end)
1016 #define STACK_LEVEL_MAX (th->machine_stack_maxsize/sizeof(VALUE))
1017
1018 #if STACK_GROW_DIRECTION < 0
1019 # define STACK_LENGTH  (STACK_START - STACK_END)
1020 #elif STACK_GROW_DIRECTION > 0
1021 # define STACK_LENGTH  (STACK_END - STACK_START + 1)
1022 #else
1023 # define STACK_LENGTH  ((STACK_END < STACK_START) ? STACK_START - STACK_END\
1024                                            : STACK_END - STACK_START + 1)
1025 #endif
1026 #if !STACK_GROW_DIRECTION
1027 int ruby_stack_grow_direction;
1028 int
1029 ruby_get_stack_grow_direction(VALUE *addr)
1030 {
1031     rb_thread_t *th = GET_THREAD();
1032     SET_STACK_END;
1033
1034     if (STACK_END > addr) return ruby_stack_grow_direction = 1;
1035     return ruby_stack_grow_direction = -1;
1036 }
1037 #endif
1038
1039 #define GC_WATER_MARK 512
1040
1041 size_t
1042 ruby_stack_length(VALUE **p)
1043 {
1044     rb_thread_t *th = GET_THREAD();
1045     SET_STACK_END;
1046     if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
1047     return STACK_LENGTH;
1048 }
1049
1050 static int
1051 stack_check(void)
1052 {
1053     int ret;
1054     rb_thread_t *th = GET_THREAD();
1055     SET_STACK_END;
1056     ret = STACK_LENGTH > STACK_LEVEL_MAX - GC_WATER_MARK;
1057 #ifdef __ia64
1058     if (!ret) {
1059         ret = (VALUE*)rb_ia64_bsp() - th->machine_register_stack_start >
1060               th->machine_register_stack_maxsize/sizeof(VALUE) - GC_WATER_MARK;
1061     }
1062 #endif
1063     return ret;
1064 }
1065
1066 int
1067 ruby_stack_check(void)
1068 {
1069 #if defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK)
1070     return 0;
1071 #else
1072     return stack_check();
1073 #endif
1074 }
1075
1076 static void
1077 init_mark_stack(rb_objspace_t *objspace)
1078 {
1079     mark_stack_overflow = 0;
1080     mark_stack_ptr = mark_stack;
1081 }
1082
1083 #define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack)
1084
1085 static void gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev);
1086 static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev);
1087
1088 static void
1089 gc_mark_all(rb_objspace_t *objspace)
1090 {
1091     RVALUE *p, *pend;
1092     size_t i;
1093
1094     init_mark_stack(objspace);
1095     for (i = 0; i < heaps_used; i++) {
1096         p = heaps[i].slot; pend = p + heaps[i].limit;
1097         while (p < pend) {
1098             if ((p->as.basic.flags & FL_MARK) &&
1099                 (p->as.basic.flags != FL_MARK)) {
1100                 gc_mark_children(objspace, (VALUE)p, 0);
1101             }
1102             p++;
1103         }
1104     }
1105 }
1106
1107 static void
1108 gc_mark_rest(rb_objspace_t *objspace)
1109 {
1110     VALUE tmp_arry[MARK_STACK_MAX];
1111     VALUE *p;
1112
1113     p = (mark_stack_ptr - mark_stack) + tmp_arry;
1114     MEMCPY(tmp_arry, mark_stack, VALUE, p - tmp_arry);
1115
1116     init_mark_stack(objspace);
1117     while (p != tmp_arry) {
1118         p--;
1119         gc_mark_children(objspace, *p, 0);
1120     }
1121 }
1122
1123 static inline int
1124 is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
1125 {
1126     register RVALUE *p = RANY(ptr);
1127     register struct heaps_slot *heap;
1128     register size_t hi, lo, mid;
1129
1130     if (p < lomem || p > himem) return Qfalse;
1131     if ((VALUE)p % sizeof(RVALUE) != 0) return Qfalse;
1132
1133     /* check if p looks like a pointer using bsearch*/
1134     lo = 0;
1135     hi = heaps_used;
1136     while (lo < hi) {
1137         mid = (lo + hi) / 2;
1138         heap = &heaps[mid];
1139         if (heap->slot <= p) {
1140             if (p < heap->slot + heap->limit)
1141                 return Qtrue;
1142             lo = mid + 1;
1143         }
1144         else {
1145             hi = mid;
1146         }
1147     }
1148     return Qfalse;
1149 }
1150
1151 static void
1152 mark_locations_array(rb_objspace_t *objspace, register VALUE *x, register long n)
1153 {
1154     VALUE v;
1155     while (n--) {
1156         v = *x;
1157         VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v));
1158         if (is_pointer_to_heap(objspace, (void *)v)) {
1159             gc_mark(objspace, v, 0);
1160         }
1161         x++;
1162     }
1163 }
1164
1165 static void
1166 gc_mark_locations(rb_objspace_t *objspace, VALUE *start, VALUE *end)
1167 {
1168     long n;
1169
1170     if (end <= start) return;
1171     n = end - start;
1172     mark_locations_array(objspace, start, n);
1173 }
1174
1175 void
1176 rb_gc_mark_locations(VALUE *start, VALUE *end)
1177 {
1178     gc_mark_locations(&rb_objspace, start, end);
1179 }
1180
1181 #define rb_gc_mark_locations(start, end) gc_mark_locations(objspace, start, end)
1182
1183 struct mark_tbl_arg {
1184     rb_objspace_t *objspace;
1185     int lev;
1186 };
1187
1188 static int
1189 mark_entry(ID key, VALUE value, st_data_t data)
1190 {
1191     struct mark_tbl_arg *arg = (void*)data;
1192     gc_mark(arg->objspace, value, arg->lev);
1193     return ST_CONTINUE;
1194 }
1195
1196 static void
1197 mark_tbl(rb_objspace_t *objspace, st_table *tbl, int lev)
1198 {
1199     struct mark_tbl_arg arg;
1200     if (!tbl) return;
1201     arg.objspace = objspace;
1202     arg.lev = lev;
1203     st_foreach(tbl, mark_entry, (st_data_t)&arg);
1204 }
1205
1206 void
1207 rb_mark_tbl(st_table *tbl)
1208 {
1209     mark_tbl(&rb_objspace, tbl, 0);
1210 }
1211
1212 static int
1213 mark_key(VALUE key, VALUE value, st_data_t data)
1214 {
1215     struct mark_tbl_arg *arg = (void*)data;
1216     gc_mark(arg->objspace, key, arg->lev);
1217     return ST_CONTINUE;
1218 }
1219
1220 static void
1221 mark_set(rb_objspace_t *objspace, st_table *tbl, int lev)
1222 {
1223     struct mark_tbl_arg arg;
1224     if (!tbl) return;
1225     arg.objspace = objspace;
1226     arg.lev = lev;
1227     st_foreach(tbl, mark_key, (st_data_t)&arg);
1228 }
1229
1230 void
1231 rb_mark_set(st_table *tbl)
1232 {
1233     mark_set(&rb_objspace, tbl, 0);
1234 }
1235
1236 static int
1237 mark_keyvalue(VALUE key, VALUE value, st_data_t data)
1238 {
1239     struct mark_tbl_arg *arg = (void*)data;
1240     gc_mark(arg->objspace, key, arg->lev);
1241     gc_mark(arg->objspace, value, arg->lev);
1242     return ST_CONTINUE;
1243 }
1244
1245 static void
1246 mark_hash(rb_objspace_t *objspace, st_table *tbl, int lev)
1247 {
1248     struct mark_tbl_arg arg;
1249     if (!tbl) return;
1250     arg.objspace = objspace;
1251     arg.lev = lev;
1252     st_foreach(tbl, mark_keyvalue, (st_data_t)&arg);
1253 }
1254
1255 void
1256 rb_mark_hash(st_table *tbl)
1257 {
1258     mark_hash(&rb_objspace, tbl, 0);
1259 }
1260
1261 void
1262 rb_gc_mark_maybe(VALUE obj)
1263 {
1264     if (is_pointer_to_heap(&rb_objspace, (void *)obj)) {
1265         gc_mark(&rb_objspace, obj, 0);
1266     }
1267 }
1268
1269 #define GC_LEVEL_MAX 250
1270
1271 static void
1272 gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev)
1273 {
1274     register RVALUE *obj;
1275
1276     obj = RANY(ptr);
1277     if (rb_special_const_p(ptr)) return; /* special const not marked */
1278     if (obj->as.basic.flags == 0) return;       /* free cell */
1279     if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
1280     obj->as.basic.flags |= FL_MARK;
1281
1282     if (lev > GC_LEVEL_MAX || (lev == 0 && stack_check())) {
1283         if (!mark_stack_overflow) {
1284             if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) {
1285                 *mark_stack_ptr = ptr;
1286                 mark_stack_ptr++;
1287             }
1288             else {
1289                 mark_stack_overflow = 1;
1290             }
1291         }
1292         return;
1293     }
1294     gc_mark_children(objspace, ptr, lev+1);
1295 }
1296
1297 void
1298 rb_gc_mark(VALUE ptr)
1299 {
1300     gc_mark(&rb_objspace, ptr, 0);
1301 }
1302
1303 static void
1304 gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
1305 {
1306     register RVALUE *obj = RANY(ptr);
1307
1308     goto marking;               /* skip */
1309
1310   again:
1311     obj = RANY(ptr);
1312     if (rb_special_const_p(ptr)) return; /* special const not marked */
1313     if (obj->as.basic.flags == 0) return;       /* free cell */
1314     if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
1315     obj->as.basic.flags |= FL_MARK;
1316
1317   marking:
1318     if (FL_TEST(obj, FL_EXIVAR)) {
1319         rb_mark_generic_ivar(ptr);
1320     }
1321
1322     switch (BUILTIN_TYPE(obj)) {
1323       case T_NIL:
1324       case T_FIXNUM:
1325         rb_bug("rb_gc_mark() called for broken object");
1326         break;
1327
1328       case T_NODE:
1329         switch (nd_type(obj)) {
1330           case NODE_IF:         /* 1,2,3 */
1331           case NODE_FOR:
1332           case NODE_ITER:
1333           case NODE_WHEN:
1334           case NODE_MASGN:
1335           case NODE_RESCUE:
1336           case NODE_RESBODY:
1337           case NODE_CLASS:
1338           case NODE_BLOCK_PASS:
1339             gc_mark(objspace, (VALUE)obj->as.node.u2.node, lev);
1340             /* fall through */
1341           case NODE_BLOCK:      /* 1,3 */
1342           case NODE_OPTBLOCK:
1343           case NODE_ARRAY:
1344           case NODE_DSTR:
1345           case NODE_DXSTR:
1346           case NODE_DREGX:
1347           case NODE_DREGX_ONCE:
1348           case NODE_ENSURE:
1349           case NODE_CALL:
1350           case NODE_DEFS:
1351           case NODE_OP_ASGN1:
1352           case NODE_ARGS:
1353             gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
1354             /* fall through */
1355           case NODE_SUPER:      /* 3 */
1356           case NODE_FCALL:
1357           case NODE_DEFN:
1358           case NODE_ARGS_AUX:
1359             ptr = (VALUE)obj->as.node.u3.node;
1360             goto again;
1361
1362           case NODE_METHOD:     /* 1,2 */
1363           case NODE_WHILE:
1364           case NODE_UNTIL:
1365           case NODE_AND:
1366           case NODE_OR:
1367           case NODE_CASE:
1368           case NODE_SCLASS:
1369           case NODE_DOT2:
1370           case NODE_DOT3:
1371           case NODE_FLIP2:
1372           case NODE_FLIP3:
1373           case NODE_MATCH2:
1374           case NODE_MATCH3:
1375           case NODE_OP_ASGN_OR:
1376           case NODE_OP_ASGN_AND:
1377           case NODE_MODULE:
1378           case NODE_ALIAS:
1379           case NODE_VALIAS:
1380           case NODE_ARGSCAT:
1381             gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
1382             /* fall through */
1383           case NODE_FBODY:      /* 2 */
1384           case NODE_GASGN:
1385           case NODE_LASGN:
1386           case NODE_DASGN:
1387           case NODE_DASGN_CURR:
1388           case NODE_IASGN:
1389           case NODE_IASGN2:
1390           case NODE_CVASGN:
1391           case NODE_COLON3:
1392           case NODE_OPT_N:
1393           case NODE_EVSTR:
1394           case NODE_UNDEF:
1395           case NODE_POSTEXE:
1396             ptr = (VALUE)obj->as.node.u2.node;
1397             goto again;
1398
1399           case NODE_HASH:       /* 1 */
1400           case NODE_LIT:
1401           case NODE_STR:
1402           case NODE_XSTR:
1403           case NODE_DEFINED:
1404           case NODE_MATCH:
1405           case NODE_RETURN:
1406           case NODE_BREAK:
1407           case NODE_NEXT:
1408           case NODE_YIELD:
1409           case NODE_COLON2:
1410           case NODE_SPLAT:
1411           case NODE_TO_ARY:
1412             ptr = (VALUE)obj->as.node.u1.node;
1413             goto again;
1414
1415           case NODE_SCOPE:      /* 2,3 */
1416           case NODE_CDECL:
1417           case NODE_OPT_ARG:
1418             gc_mark(objspace, (VALUE)obj->as.node.u3.node, lev);
1419             ptr = (VALUE)obj->as.node.u2.node;
1420             goto again;
1421
1422           case NODE_ZARRAY:     /* - */
1423           case NODE_ZSUPER:
1424           case NODE_CFUNC:
1425           case NODE_VCALL:
1426           case NODE_GVAR:
1427           case NODE_LVAR:
1428           case NODE_DVAR:
1429           case NODE_IVAR:
1430           case NODE_CVAR:
1431           case NODE_NTH_REF:
1432           case NODE_BACK_REF:
1433           case NODE_REDO:
1434           case NODE_RETRY:
1435           case NODE_SELF:
1436           case NODE_NIL:
1437           case NODE_TRUE:
1438           case NODE_FALSE:
1439           case NODE_ERRINFO:
1440           case NODE_ATTRSET:
1441           case NODE_BLOCK_ARG:
1442             break;
1443           case NODE_ALLOCA:
1444             mark_locations_array(objspace,
1445                                  (VALUE*)obj->as.node.u1.value,
1446                                  obj->as.node.u3.cnt);
1447             ptr = (VALUE)obj->as.node.u2.node;
1448             goto again;
1449
1450           default:              /* unlisted NODE */
1451             if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) {
1452                 gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
1453             }
1454             if (is_pointer_to_heap(objspace, obj->as.node.u2.node)) {
1455                 gc_mark(objspace, (VALUE)obj->as.node.u2.node, lev);
1456             }
1457             if (is_pointer_to_heap(objspace, obj->as.node.u3.node)) {
1458                 gc_mark(objspace, (VALUE)obj->as.node.u3.node, lev);
1459             }
1460         }
1461         return;                 /* no need to mark class. */
1462     }
1463
1464     gc_mark(objspace, obj->as.basic.klass, lev);
1465     switch (BUILTIN_TYPE(obj)) {
1466       case T_ICLASS:
1467       case T_CLASS:
1468       case T_MODULE:
1469         mark_tbl(objspace, RCLASS_M_TBL(obj), lev);
1470         mark_tbl(objspace, RCLASS_IV_TBL(obj), lev);
1471         ptr = RCLASS_SUPER(obj);
1472         goto again;
1473
1474       case T_ARRAY:
1475         if (FL_TEST(obj, ELTS_SHARED)) {
1476             ptr = obj->as.array.as.heap.aux.shared;
1477             goto again;
1478         }
1479         else {
1480             long i, len = RARRAY_LEN(obj);
1481             VALUE *ptr = RARRAY_PTR(obj);
1482             for (i=0; i < len; i++) {
1483                 gc_mark(objspace, *ptr++, lev);
1484             }
1485         }
1486         break;
1487
1488       case T_HASH:
1489         mark_hash(objspace, obj->as.hash.ntbl, lev);
1490         ptr = obj->as.hash.ifnone;
1491         goto again;
1492
1493       case T_STRING:
1494 #define STR_ASSOC FL_USER3   /* copied from string.c */
1495         if (FL_TEST(obj, RSTRING_NOEMBED) && FL_ANY(obj, ELTS_SHARED|STR_ASSOC)) {
1496             ptr = obj->as.string.as.heap.aux.shared;
1497             goto again;
1498         }
1499         break;
1500
1501       case T_DATA:
1502         if (obj->as.data.dmark) (*obj->as.data.dmark)(DATA_PTR(obj));
1503         break;
1504
1505       case T_OBJECT:
1506         {
1507             long i, len = ROBJECT_NUMIV(obj);
1508             VALUE *ptr = ROBJECT_IVPTR(obj);
1509             for (i  = 0; i < len; i++) {
1510                 gc_mark(objspace, *ptr++, lev);
1511             }
1512         }
1513         break;
1514
1515       case T_FILE:
1516         if (obj->as.file.fptr) {
1517             gc_mark(objspace, obj->as.file.fptr->pathv, lev);
1518             gc_mark(objspace, obj->as.file.fptr->tied_io_for_writing, lev);
1519             gc_mark(objspace, obj->as.file.fptr->writeconv_asciicompat, lev);
1520             gc_mark(objspace, obj->as.file.fptr->writeconv_pre_ecopts, lev);
1521             gc_mark(objspace, obj->as.file.fptr->encs.ecopts, lev);
1522             gc_mark(objspace, obj->as.file.fptr->write_lock, lev);
1523         }
1524         break;
1525
1526       case T_REGEXP:
1527         gc_mark(objspace, obj->as.regexp.src, lev);
1528         break;
1529
1530       case T_FLOAT:
1531       case T_BIGNUM:
1532       case T_ZOMBIE:
1533         break;
1534
1535       case T_MATCH:
1536         gc_mark(objspace, obj->as.match.regexp, lev);
1537         if (obj->as.match.str) {
1538             ptr = obj->as.match.str;
1539             goto again;
1540         }
1541         break;
1542
1543       case T_RATIONAL:
1544         gc_mark(objspace, obj->as.rational.num, lev);
1545         gc_mark(objspace, obj->as.rational.den, lev);
1546         break;
1547
1548       case T_COMPLEX:
1549         gc_mark(objspace, obj->as.complex.real, lev);
1550         gc_mark(objspace, obj->as.complex.imag, lev);
1551         break;
1552
1553       case T_STRUCT:
1554         {
1555             long len = RSTRUCT_LEN(obj);
1556             VALUE *ptr = RSTRUCT_PTR(obj);
1557
1558             while (len--) {
1559                 gc_mark(objspace, *ptr++, lev);
1560             }
1561         }
1562         break;
1563
1564       default:
1565         rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s",
1566                BUILTIN_TYPE(obj), (void *)obj,
1567                is_pointer_to_heap(objspace, obj) ? "corrupted object" : "non object");
1568     }
1569 }
1570
1571 static int obj_free(rb_objspace_t *, VALUE);
1572
1573 static inline void
1574 add_freelist(rb_objspace_t *objspace, RVALUE *p)
1575 {
1576     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
1577     p->as.free.flags = 0;
1578     p->as.free.next = freelist;
1579     freelist = p;
1580 }
1581
1582 static void
1583 finalize_list(rb_objspace_t *objspace, RVALUE *p)
1584 {
1585     while (p) {
1586         RVALUE *tmp = p->as.free.next;
1587         run_final(objspace, (VALUE)p);
1588         if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
1589             add_freelist(objspace, p);
1590         }
1591         else {
1592             struct heaps_slot *slot = (struct heaps_slot *)RDATA(p)->dmark;
1593             slot->limit--;
1594         }
1595         p = tmp;
1596     }
1597 }
1598
1599 static void
1600 free_unused_heaps(rb_objspace_t *objspace)
1601 {
1602     size_t i, j;
1603     RVALUE *last = 0;
1604
1605     for (i = j = 1; j < heaps_used; i++) {
1606         if (heaps[i].limit == 0) {
1607             if (!last) {
1608                 last = heaps[i].membase;
1609             }
1610             else {
1611                 free(heaps[i].membase);
1612             }
1613             heaps_used--;
1614         }
1615         else {
1616             if (i != j) {
1617                 heaps[j] = heaps[i];
1618             }
1619             j++;
1620         }
1621     }
1622     if (last) {
1623         if (last < heaps_freed) {
1624             free(heaps_freed);
1625             heaps_freed = last;
1626         }
1627         else {
1628             free(last);
1629         }
1630     }
1631 }
1632
1633 static void
1634 gc_sweep(rb_objspace_t *objspace)
1635 {
1636     RVALUE *p, *pend, *final_list;
1637     size_t freed = 0;
1638     size_t i;
1639     size_t live = 0, free_min = 0, do_heap_free = 0;
1640
1641     do_heap_free = (heaps_used * HEAP_OBJ_LIMIT) * 0.65;
1642     free_min = (heaps_used * HEAP_OBJ_LIMIT)  * 0.2;
1643
1644     if (free_min < FREE_MIN) {
1645         do_heap_free = heaps_used * HEAP_OBJ_LIMIT;
1646         free_min = FREE_MIN;
1647     }
1648
1649     freelist = 0;
1650     final_list = deferred_final_list;
1651     deferred_final_list = 0;
1652     for (i = 0; i < heaps_used; i++) {
1653         int free_num = 0, final_num = 0;
1654         RVALUE *free = freelist;
1655         RVALUE *final = final_list;
1656         int deferred;
1657
1658         p = heaps[i].slot; pend = p + heaps[i].limit;
1659         while (p < pend) {
1660             if (!(p->as.basic.flags & FL_MARK)) {
1661                 if (p->as.basic.flags &&
1662                     ((deferred = obj_free(objspace, (VALUE)p)) ||
1663                      ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) {
1664                     if (!deferred) {
1665                         p->as.free.flags = T_ZOMBIE;
1666                         RDATA(p)->dfree = 0;
1667                     }
1668                     p->as.free.flags |= FL_MARK;
1669                     p->as.free.next = final_list;
1670                     final_list = p;
1671                     final_num++;
1672                 }
1673                 else {
1674                     add_freelist(objspace, p);
1675                     free_num++;
1676                 }
1677             }
1678             else if (BUILTIN_TYPE(p) == T_ZOMBIE) {
1679                 /* objects to be finalized */
1680                 /* do nothing remain marked */
1681             }
1682             else {
1683                 RBASIC(p)->flags &= ~FL_MARK;
1684                 live++;
1685             }
1686             p++;
1687         }
1688         if (final_num + free_num == heaps[i].limit && freed > do_heap_free) {
1689             RVALUE *pp;
1690
1691             for (pp = final_list; pp != final; pp = pp->as.free.next) {
1692                 RDATA(pp)->dmark = (void *)&heaps[i];
1693                 pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
1694             }
1695             heaps[i].limit = final_num;
1696
1697             freelist = free;    /* cancel this page from freelist */
1698         }
1699         else {
1700             freed += free_num;
1701         }
1702     }
1703     GC_PROF_SET_MALLOC_INFO;
1704     if (malloc_increase > malloc_limit) {
1705         malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
1706         if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
1707     }
1708     malloc_increase = 0;
1709     if (freed < free_min) {
1710         set_heaps_increment(objspace);
1711         heaps_increment(objspace);
1712     }
1713     during_gc = 0;
1714
1715     /* clear finalization list */
1716     if (final_list) {
1717         GC_PROF_SET_HEAP_INFO;
1718         deferred_final_list = final_list;
1719         RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD());
1720     }
1721     else{
1722         free_unused_heaps(objspace);
1723         GC_PROF_SET_HEAP_INFO;
1724     }
1725 }
1726
1727 void
1728 rb_gc_force_recycle(VALUE p)
1729 {
1730     rb_objspace_t *objspace = &rb_objspace;
1731     add_freelist(objspace, (RVALUE *)p);
1732 }
1733
1734 static inline void
1735 make_deferred(RVALUE *p)
1736 {
1737     p->as.basic.flags = (p->as.basic.flags & ~T_MASK) | T_ZOMBIE;
1738 }
1739
1740 static inline void
1741 make_io_deferred(RVALUE *p)
1742 {
1743     rb_io_t *fptr = p->as.file.fptr;
1744     make_deferred(p);
1745     p->as.data.dfree = (void (*)(void*))rb_io_fptr_finalize;
1746     p->as.data.data = fptr;
1747 }
1748
1749 static int
1750 obj_free(rb_objspace_t *objspace, VALUE obj)
1751 {
1752     switch (BUILTIN_TYPE(obj)) {
1753       case T_NIL:
1754       case T_FIXNUM:
1755       case T_TRUE:
1756       case T_FALSE:
1757         rb_bug("obj_free() called for broken object");
1758         break;
1759     }
1760
1761     if (FL_TEST(obj, FL_EXIVAR)) {
1762         rb_free_generic_ivar((VALUE)obj);
1763         FL_UNSET(obj, FL_EXIVAR);
1764     }
1765
1766     switch (BUILTIN_TYPE(obj)) {
1767       case T_OBJECT:
1768         if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) &&
1769             RANY(obj)->as.object.as.heap.ivptr) {
1770             xfree(RANY(obj)->as.object.as.heap.ivptr);
1771         }
1772         break;
1773       case T_MODULE:
1774       case T_CLASS:
1775         rb_clear_cache_by_class((VALUE)obj);
1776         st_free_table(RCLASS_M_TBL(obj));
1777         if (RCLASS_IV_TBL(obj)) {
1778             st_free_table(RCLASS_IV_TBL(obj));
1779         }
1780         if (RCLASS_IV_INDEX_TBL(obj)) {
1781             st_free_table(RCLASS_IV_INDEX_TBL(obj));
1782         }
1783         xfree(RANY(obj)->as.klass.ptr);
1784         break;
1785       case T_STRING:
1786         rb_str_free(obj);
1787         break;
1788       case T_ARRAY:
1789         rb_ary_free(obj);
1790         break;
1791       case T_HASH:
1792         if (RANY(obj)->as.hash.ntbl) {
1793             st_free_table(RANY(obj)->as.hash.ntbl);
1794         }
1795         break;
1796       case T_REGEXP:
1797         if (RANY(obj)->as.regexp.ptr) {
1798             onig_free(RANY(obj)->as.regexp.ptr);
1799         }
1800         break;
1801       case T_DATA:
1802         if (DATA_PTR(obj)) {
1803             if ((long)RANY(obj)->as.data.dfree == -1) {
1804                 xfree(DATA_PTR(obj));
1805             }
1806             else if (RANY(obj)->as.data.dfree) {
1807                 make_deferred(RANY(obj));
1808                 return 1;
1809             }
1810         }
1811         break;
1812       case T_MATCH:
1813         if (RANY(obj)->as.match.rmatch) {
1814             struct rmatch *rm = RANY(obj)->as.match.rmatch;
1815             onig_region_free(&rm->regs, 0);
1816             if (rm->char_offset)
1817                 xfree(rm->char_offset);
1818             xfree(rm);
1819         }
1820         break;
1821       case T_FILE:
1822         if (RANY(obj)->as.file.fptr) {
1823             make_io_deferred(RANY(obj));
1824             return 1;
1825         }
1826         break;
1827       case T_RATIONAL:
1828       case T_COMPLEX:
1829         break;
1830       case T_ICLASS:
1831         /* iClass shares table with the module */
1832         break;
1833
1834       case T_FLOAT:
1835         break;
1836
1837       case T_BIGNUM:
1838         if (!(RBASIC(obj)->flags & RBIGNUM_EMBED_FLAG) && RBIGNUM_DIGITS(obj)) {
1839             xfree(RBIGNUM_DIGITS(obj));
1840         }
1841         break;
1842       case T_NODE:
1843         switch (nd_type(obj)) {
1844           case NODE_SCOPE:
1845             if (RANY(obj)->as.node.u1.tbl) {
1846                 xfree(RANY(obj)->as.node.u1.tbl);
1847             }
1848             break;
1849           case NODE_ALLOCA:
1850             xfree(RANY(obj)->as.node.u1.node);
1851             break;
1852         }
1853         break;                  /* no need to free iv_tbl */
1854
1855       case T_STRUCT:
1856         if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) == 0 &&
1857             RANY(obj)->as.rstruct.as.heap.ptr) {
1858             xfree(RANY(obj)->as.rstruct.as.heap.ptr);
1859         }
1860         break;
1861
1862       default:
1863         rb_bug("gc_sweep(): unknown data type 0x%lx(%p)",
1864                BUILTIN_TYPE(obj), (void*)obj);
1865     }
1866
1867     return 0;
1868 }
1869
1870 #define GC_NOTIFY 0
1871
1872 void rb_vm_mark(void *ptr);
1873
1874 static void
1875 mark_current_machine_context(rb_objspace_t *objspace, rb_thread_t *th)
1876 {
1877     rb_jmp_buf save_regs_gc_mark;
1878     VALUE *stack_start, *stack_end;
1879
1880     SET_STACK_END;
1881 #if STACK_GROW_DIRECTION < 0
1882     stack_start = th->machine_stack_end;
1883     stack_end = th->machine_stack_start;
1884 #elif STACK_GROW_DIRECTION > 0
1885     stack_start = th->machine_stack_start;
1886     stack_end = th->machine_stack_end + 1;
1887 #else
1888     if (th->machine_stack_end < th->machine_stack_start) {
1889         stack_start = th->machine_stack_end;
1890         stack_end = th->machine_stack_start;
1891     }
1892     else {
1893         stack_start = th->machine_stack_start;
1894         stack_end = th->machine_stack_end + 1;
1895     }
1896 #endif
1897
1898     FLUSH_REGISTER_WINDOWS;
1899     /* This assumes that all registers are saved into the jmp_buf (and stack) */
1900     rb_setjmp(save_regs_gc_mark);
1901     mark_locations_array(objspace,
1902                          (VALUE*)save_regs_gc_mark,
1903                          sizeof(save_regs_gc_mark) / sizeof(VALUE));
1904
1905     rb_gc_mark_locations(stack_start, stack_end);
1906 #ifdef __ia64
1907     rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
1908 #endif
1909 #if defined(__mc68000__)
1910     mark_locations_array((VALUE*)((char*)STACK_END + 2),
1911                          (STACK_START - STACK_END));
1912 #endif
1913 }
1914
1915 void rb_gc_mark_encodings(void);
1916
1917 static int
1918 garbage_collect(rb_objspace_t *objspace)
1919 {
1920     struct gc_list *list;
1921     rb_thread_t *th = GET_THREAD();
1922     INIT_GC_PROF_PARAMS;
1923
1924     if (GC_NOTIFY) printf("start garbage_collect()\n");
1925
1926     if (!heaps) {
1927         return Qfalse;
1928     }
1929
1930     if (dont_gc || during_gc) {
1931         if (!freelist) {
1932             if (!heaps_increment(objspace)) {
1933                 set_heaps_increment(objspace);
1934                 heaps_increment(objspace);
1935             }
1936         }
1937         return Qtrue;
1938     }
1939     during_gc++;
1940     objspace->count++;
1941
1942     GC_PROF_TIMER_START;
1943     GC_PROF_MARK_TIMER_START;
1944     SET_STACK_END;
1945
1946     init_mark_stack(objspace);
1947
1948     th->vm->self ? rb_gc_mark(th->vm->self) : rb_vm_mark(th->vm);
1949
1950     if (finalizer_table) {
1951         mark_tbl(objspace, finalizer_table, 0);
1952     }
1953
1954     mark_current_machine_context(objspace, th);
1955
1956     rb_gc_mark_threads();
1957     rb_gc_mark_symbols();
1958     rb_gc_mark_encodings();
1959
1960     /* mark protected global variables */
1961     for (list = global_List; list; list = list->next) {
1962         rb_gc_mark_maybe(*list->varptr);
1963     }
1964     rb_mark_end_proc();
1965     rb_gc_mark_global_tbl();
1966
1967     mark_tbl(objspace, rb_class_tbl, 0);
1968
1969     /* mark generic instance variables for special constants */
1970     rb_mark_generic_ivar_tbl();
1971
1972     rb_gc_mark_parser();
1973
1974     /* gc_mark objects whose marking are not completed*/
1975     while (!MARK_STACK_EMPTY) {
1976         if (mark_stack_overflow) {
1977             gc_mark_all(objspace);
1978         }
1979         else {
1980             gc_mark_rest(objspace);
1981         }
1982     }
1983     GC_PROF_MARK_TIMER_STOP;
1984
1985     GC_PROF_SWEEP_TIMER_START;
1986     gc_sweep(objspace);
1987     GC_PROF_SWEEP_TIMER_STOP;
1988
1989     GC_PROF_TIMER_STOP;
1990     if (GC_NOTIFY) printf("end garbage_collect()\n");
1991     return Qtrue;
1992 }
1993
1994 int
1995 rb_garbage_collect(void)
1996 {
1997     return garbage_collect(&rb_objspace);
1998 }
1999
2000 void
2001 rb_gc_mark_machine_stack(rb_thread_t *th)
2002 {
2003     rb_objspace_t *objspace = &rb_objspace;
2004 #if STACK_GROW_DIRECTION < 0
2005     rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
2006 #elif STACK_GROW_DIRECTION > 0
2007     rb_gc_mark_locations(th->machine_stack_start, th->machine_stack_end);
2008 #else
2009     if (th->machine_stack_start < th->machine_stack_end) {
2010         rb_gc_mark_locations(th->machine_stack_start, th->machine_stack_end);
2011     }
2012     else {
2013         rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
2014     }
2015 #endif
2016 #ifdef __ia64
2017     rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
2018 #endif
2019 }
2020
2021
2022 /*
2023  *  call-seq:
2024  *     GC.start                     => nil
2025  *     gc.garbage_collect           => nil
2026  *     ObjectSpace.garbage_collect  => nil
2027  *
2028  *  Initiates garbage collection, unless manually disabled.
2029  *
2030  */
2031
2032 VALUE
2033 rb_gc_start(void)
2034 {
2035     rb_gc();
2036     return Qnil;
2037 }
2038
2039 #undef Init_stack
2040
2041 void
2042 Init_stack(VALUE *addr)
2043 {
2044     ruby_init_stack(addr);
2045 }
2046
2047 /*
2048  * Document-class: ObjectSpace
2049  *
2050  *  The <code>ObjectSpace</code> module contains a number of routines
2051  *  that interact with the garbage collection facility and allow you to
2052  *  traverse all living objects with an iterator.
2053  *
2054  *  <code>ObjectSpace</code> also provides support for object
2055  *  finalizers, procs that will be called when a specific object is
2056  *  about to be destroyed by garbage collection.
2057  *
2058  *     include ObjectSpace
2059  *
2060  *
2061  *     a = "A"
2062  *     b = "B"
2063  *     c = "C"
2064  *
2065  *
2066  *     define_finalizer(a, proc {|id| puts "Finalizer one on #{id}" })
2067  *     define_finalizer(a, proc {|id| puts "Finalizer two on #{id}" })
2068  *     define_finalizer(b, proc {|id| puts "Finalizer three on #{id}" })
2069  *
2070  *  <em>produces:</em>
2071  *
2072  *     Finalizer three on 537763470
2073  *     Finalizer one on 537763480
2074  *     Finalizer two on 537763480
2075  *
2076  */
2077
2078 void
2079 Init_heap(void)
2080 {
2081     init_heap(&rb_objspace);
2082 }
2083
2084 static VALUE
2085 os_obj_of(rb_objspace_t *objspace, VALUE of)
2086 {
2087     size_t i;
2088     size_t n = 0;
2089     RVALUE *membase = 0;
2090     RVALUE *p, *pend;
2091     volatile VALUE v;
2092
2093     i = 0;
2094     while (i < heaps_used) {
2095         while (0 < i && (uintptr_t)membase < (uintptr_t)heaps[i-1].membase)
2096             i--;
2097         while (i < heaps_used && (uintptr_t)heaps[i].membase <= (uintptr_t)membase )
2098             i++;
2099         if (heaps_used <= i)
2100             break;
2101         membase = heaps[i].membase;
2102
2103         p = heaps[i].slot; pend = p + heaps[i].limit;
2104         for (;p < pend; p++) {
2105             if (p->as.basic.flags) {
2106                 switch (BUILTIN_TYPE(p)) {
2107                   case T_NONE:
2108                   case T_ICLASS:
2109                   case T_NODE:
2110                   case T_ZOMBIE:
2111                     continue;
2112                   case T_CLASS:
2113                     if (FL_TEST(p, FL_SINGLETON)) continue;
2114                   default:
2115                     if (!p->as.basic.klass) continue;
2116                     v = (VALUE)p;
2117                     if (!of || rb_obj_is_kind_of(v, of)) {
2118                         rb_yield(v);
2119                         n++;
2120                     }
2121                 }
2122             }
2123         }
2124     }
2125
2126     return SIZET2NUM(n);
2127 }
2128
2129 /*
2130  *  call-seq:
2131  *     ObjectSpace.each_object([module]) {|obj| ... } => fixnum
2132  *
2133  *  Calls the block once for each living, nonimmediate object in this
2134  *  Ruby process. If <i>module</i> is specified, calls the block
2135  *  for only those classes or modules that match (or are a subclass of)
2136  *  <i>module</i>. Returns the number of objects found. Immediate
2137  *  objects (<code>Fixnum</code>s, <code>Symbol</code>s
2138  *  <code>true</code>, <code>false</code>, and <code>nil</code>) are
2139  *  never returned. In the example below, <code>each_object</code>
2140  *  returns both the numbers we defined and several constants defined in
2141  *  the <code>Math</code> module.
2142  *
2143  *     a = 102.7
2144  *     b = 95       # Won't be returned
2145  *     c = 12345678987654321
2146  *     count = ObjectSpace.each_object(Numeric) {|x| p x }
2147  *     puts "Total count: #{count}"
2148  *
2149  *  <em>produces:</em>
2150  *
2151  *     12345678987654321
2152  *     102.7
2153  *     2.71828182845905
2154  *     3.14159265358979
2155  *     2.22044604925031e-16
2156  *     1.7976931348623157e+308
2157  *     2.2250738585072e-308
2158  *     Total count: 7
2159  *
2160  */
2161
2162 static VALUE
2163 os_each_obj(int argc, VALUE *argv, VALUE os)
2164 {
2165     VALUE of;
2166
2167     rb_secure(4);
2168     if (argc == 0) {
2169         of = 0;
2170     }
2171     else {
2172         rb_scan_args(argc, argv, "01", &of);
2173     }
2174     RETURN_ENUMERATOR(os, 1, &of);
2175     return os_obj_of(&rb_objspace, of);
2176 }
2177
2178 /*
2179  *  call-seq:
2180  *     ObjectSpace.undefine_finalizer(obj)
2181  *
2182  *  Removes all finalizers for <i>obj</i>.
2183  *
2184  */
2185
2186 static VALUE
2187 undefine_final(VALUE os, VALUE obj)
2188 {
2189     rb_objspace_t *objspace = &rb_objspace;
2190     if (finalizer_table) {
2191         st_delete(finalizer_table, (st_data_t*)&obj, 0);
2192     }
2193     return obj;
2194 }
2195
2196 /*
2197  *  call-seq:
2198  *     ObjectSpace.define_finalizer(obj, aProc=proc())
2199  *
2200  *  Adds <i>aProc</i> as a finalizer, to be called after <i>obj</i>
2201  *  was destroyed.
2202  *
2203  */
2204
2205 static VALUE
2206 define_final(int argc, VALUE *argv, VALUE os)
2207 {
2208     rb_objspace_t *objspace = &rb_objspace;
2209     VALUE obj, block, table;
2210
2211     rb_scan_args(argc, argv, "11", &obj, &block);
2212     if (argc == 1) {
2213         block = rb_block_proc();
2214     }
2215     else if (!rb_respond_to(block, rb_intern("call"))) {
2216         rb_raise(rb_eArgError, "wrong type argument %s (should be callable)",
2217                  rb_obj_classname(block));
2218     }
2219     FL_SET(obj, FL_FINALIZE);
2220
2221     block = rb_ary_new3(2, INT2FIX(rb_safe_level()), block);
2222
2223     if (!finalizer_table) {
2224         finalizer_table = st_init_numtable();
2225     }
2226     if (st_lookup(finalizer_table, obj, &table)) {
2227         rb_ary_push(table, block);
2228     }
2229     else {
2230         st_add_direct(finalizer_table, obj, rb_ary_new3(1, block));
2231     }
2232     return block;
2233 }
2234
2235 void
2236 rb_gc_copy_finalizer(VALUE dest, VALUE obj)
2237 {
2238     rb_objspace_t *objspace = &rb_objspace;
2239     VALUE table;
2240
2241     if (!finalizer_table) return;
2242     if (!FL_TEST(obj, FL_FINALIZE)) return;
2243     if (st_lookup(finalizer_table, obj, &table)) {
2244         st_insert(finalizer_table, dest, table);
2245     }
2246     FL_SET(dest, FL_FINALIZE);
2247 }
2248
2249 static VALUE
2250 run_single_final(VALUE arg)
2251 {
2252     VALUE *args = (VALUE *)arg;
2253     rb_eval_cmd(args[0], args[1], (int)args[2]);
2254     return Qnil;
2255 }
2256
2257 static void
2258 run_final(rb_objspace_t *objspace, VALUE obj)
2259 {
2260     long i;
2261     int status;
2262     VALUE args[3], table, objid;
2263
2264     objid = rb_obj_id(obj);     /* make obj into id */
2265     RBASIC(obj)->klass = 0;
2266
2267     if (RDATA(obj)->dfree) {
2268         (*RDATA(obj)->dfree)(DATA_PTR(obj));
2269     }
2270
2271     if (finalizer_table &&
2272         st_delete(finalizer_table, (st_data_t*)&obj, &table)) {
2273         args[1] = 0;
2274         args[2] = (VALUE)rb_safe_level();
2275         if (!args[1] && RARRAY_LEN(table) > 0) {
2276             args[1] = rb_obj_freeze(rb_ary_new3(1, objid));
2277         }
2278         for (i=0; i<RARRAY_LEN(table); i++) {
2279             VALUE final = RARRAY_PTR(table)[i];
2280             args[0] = RARRAY_PTR(final)[1];
2281             args[2] = FIX2INT(RARRAY_PTR(final)[0]);
2282             rb_protect(run_single_final, (VALUE)args, &status);
2283         }
2284     }
2285 }
2286
2287 static void
2288 finalize_deferred(rb_objspace_t *objspace)
2289 {
2290     RVALUE *p = deferred_final_list;
2291     deferred_final_list = 0;
2292
2293     if (p) {
2294         finalize_list(objspace, p);
2295     }
2296 }
2297
2298 static void
2299 gc_finalize_deferred(rb_objspace_t *objspace)
2300 {
2301     finalize_deferred(objspace);
2302     free_unused_heaps(objspace);
2303 }
2304
2305 void
2306 rb_gc_finalize_deferred(void)
2307 {
2308     gc_finalize_deferred(&rb_objspace);
2309 }
2310
2311 static int
2312 chain_finalized_object(st_data_t key, st_data_t val, st_data_t arg)
2313 {
2314     RVALUE *p = (RVALUE *)key, **final_list = (RVALUE **)arg;
2315     if (p->as.basic.flags & FL_FINALIZE) {
2316         if (BUILTIN_TYPE(p) != T_ZOMBIE) {
2317             p->as.free.flags = FL_MARK | T_ZOMBIE; /* remain marked */
2318             RDATA(p)->dfree = 0;
2319         }
2320         p->as.free.next = *final_list;
2321         *final_list = p;
2322         return ST_CONTINUE;
2323     }
2324     else {
2325         return ST_DELETE;
2326     }
2327 }
2328
2329 void
2330 rb_gc_call_finalizer_at_exit(void)
2331 {
2332     rb_objspace_t *objspace = &rb_objspace;
2333     RVALUE *p, *pend;
2334     RVALUE *final_list = 0;
2335     size_t i;
2336
2337     /* run finalizers */
2338     if (finalizer_table) {
2339         finalize_deferred(objspace);
2340         while (finalizer_table->num_entries > 0) {
2341             st_foreach(finalizer_table, chain_finalized_object,
2342                        (st_data_t)&final_list);
2343             if (!(p = final_list)) break;
2344             do {
2345                 final_list = p->as.free.next;
2346                 run_final(objspace, (VALUE)p);
2347             } while ((p = final_list) != 0);
2348         }
2349         st_free_table(finalizer_table);
2350         finalizer_table = 0;
2351     }
2352     /* finalizers are part of garbage collection */
2353     during_gc++;
2354     /* run data object's finalizers */
2355     for (i = 0; i < heaps_used; i++) {
2356         p = heaps[i].slot; pend = p + heaps[i].limit;
2357         while (p < pend) {
2358             if (BUILTIN_TYPE(p) == T_DATA &&
2359                 DATA_PTR(p) && RANY(p)->as.data.dfree &&
2360                 RANY(p)->as.basic.klass != rb_cThread && RANY(p)->as.basic.klass != rb_cMutex) {
2361                 p->as.free.flags = 0;
2362                 if ((long)RANY(p)->as.data.dfree == -1) {
2363                     xfree(DATA_PTR(p));
2364                 }
2365                 else if (RANY(p)->as.data.dfree) {
2366                     make_deferred(RANY(p));
2367                     RANY(p)->as.free.next = final_list;
2368                     final_list = p;
2369                 }
2370             }
2371             else if (BUILTIN_TYPE(p) == T_FILE) {
2372                 if (RANY(p)->as.file.fptr) {
2373                     make_io_deferred(RANY(p));
2374                     RANY(p)->as.free.next = final_list;
2375                     final_list = p;
2376                 }
2377             }
2378             p++;
2379         }
2380     }
2381     during_gc = 0;
2382     if (final_list) {
2383         finalize_list(objspace, final_list);
2384     }
2385 }
2386
2387 void
2388 rb_gc(void)
2389 {
2390     rb_objspace_t *objspace = &rb_objspace;
2391     garbage_collect(objspace);
2392     gc_finalize_deferred(objspace);
2393 }
2394
2395 /*
2396  *  call-seq:
2397  *     ObjectSpace._id2ref(object_id) -> an_object
2398  *
2399  *  Converts an object id to a reference to the object. May not be
2400  *  called on an object id passed as a parameter to a finalizer.
2401  *
2402  *     s = "I am a string"                    #=> "I am a string"
2403  *     r = ObjectSpace._id2ref(s.object_id)   #=> "I am a string"
2404  *     r == s                                 #=> true
2405  *
2406  */
2407
2408 static VALUE
2409 id2ref(VALUE obj, VALUE objid)
2410 {
2411 #if SIZEOF_LONG == SIZEOF_VOIDP
2412 #define NUM2PTR(x) NUM2ULONG(x)
2413 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
2414 #define NUM2PTR(x) NUM2ULL(x)
2415 #endif
2416     rb_objspace_t *objspace = &rb_objspace;
2417     VALUE ptr;
2418     void *p0;
2419
2420     rb_secure(4);
2421     ptr = NUM2PTR(objid);
2422     p0 = (void *)ptr;
2423
2424     if (ptr == Qtrue) return Qtrue;
2425     if (ptr == Qfalse) return Qfalse;
2426     if (ptr == Qnil) return Qnil;
2427     if (FIXNUM_P(ptr)) return (VALUE)ptr;
2428     ptr = objid ^ FIXNUM_FLAG;  /* unset FIXNUM_FLAG */
2429
2430     if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
2431         ID symid = ptr / sizeof(RVALUE);
2432         if (rb_id2name(symid) == 0)
2433             rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
2434         return ID2SYM(symid);
2435     }
2436
2437     if (!is_pointer_to_heap(objspace, (void *)ptr) ||
2438         BUILTIN_TYPE(ptr) > T_FIXNUM || BUILTIN_TYPE(ptr) == T_ICLASS) {
2439         rb_raise(rb_eRangeError, "%p is not id value", p0);
2440     }
2441     if (BUILTIN_TYPE(ptr) == 0 || RBASIC(ptr)->klass == 0) {
2442         rb_raise(rb_eRangeError, "%p is recycled object", p0);
2443     }
2444     return (VALUE)ptr;
2445 }
2446
2447 /*
2448  *  Document-method: __id__
2449  *  Document-method: object_id
2450  *
2451  *  call-seq:
2452  *     obj.__id__       => fixnum
2453  *     obj.object_id    => fixnum
2454  *
2455  *  Returns an integer identifier for <i>obj</i>. The same number will
2456  *  be returned on all calls to <code>id</code> for a given object, and
2457  *  no two active objects will share an id.
2458  *  <code>Object#object_id</code> is a different concept from the
2459  *  <code>:name</code> notation, which returns the symbol id of
2460  *  <code>name</code>. Replaces the deprecated <code>Object#id</code>.
2461  */
2462
2463 /*
2464  *  call-seq:
2465  *     obj.hash    => fixnum
2466  *
2467  *  Generates a <code>Fixnum</code> hash value for this object. This
2468  *  function must have the property that <code>a.eql?(b)</code> implies
2469  *  <code>a.hash == b.hash</code>. The hash value is used by class
2470  *  <code>Hash</code>. Any hash value that exceeds the capacity of a
2471  *  <code>Fixnum</code> will be truncated before being used.
2472  */
2473
2474 VALUE
2475 rb_obj_id(VALUE obj)
2476 {
2477     /*
2478      *                32-bit VALUE space
2479      *          MSB ------------------------ LSB
2480      *  false   00000000000000000000000000000000
2481      *  true    00000000000000000000000000000010
2482      *  nil     00000000000000000000000000000100
2483      *  undef   00000000000000000000000000000110
2484      *  symbol  ssssssssssssssssssssssss00001110
2485      *  object  oooooooooooooooooooooooooooooo00        = 0 (mod sizeof(RVALUE))
2486      *  fixnum  fffffffffffffffffffffffffffffff1
2487      *
2488      *                    object_id space
2489      *                                       LSB
2490      *  false   00000000000000000000000000000000
2491      *  true    00000000000000000000000000000010
2492      *  nil     00000000000000000000000000000100
2493      *  undef   00000000000000000000000000000110
2494      *  symbol   000SSSSSSSSSSSSSSSSSSSSSSSSSSS0        S...S % A = 4 (S...S = s...s * A + 4)
2495      *  object   oooooooooooooooooooooooooooooo0        o...o % A = 0
2496      *  fixnum  fffffffffffffffffffffffffffffff1        bignum if required
2497      *
2498      *  where A = sizeof(RVALUE)/4
2499      *
2500      *  sizeof(RVALUE) is
2501      *  20 if 32-bit, double is 4-byte aligned
2502      *  24 if 32-bit, double is 8-byte aligned
2503      *  40 if 64-bit
2504      */
2505     if (TYPE(obj) == T_SYMBOL) {
2506         return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
2507     }
2508     if (SPECIAL_CONST_P(obj)) {
2509         return LONG2NUM((SIGNED_VALUE)obj);
2510     }
2511     return (VALUE)((SIGNED_VALUE)obj|FIXNUM_FLAG);
2512 }
2513
2514 static int
2515 set_zero(st_data_t key, st_data_t val, st_data_t arg)
2516 {
2517     VALUE k = (VALUE)key;
2518     VALUE hash = (VALUE)arg;
2519     rb_hash_aset(hash, k, INT2FIX(0));
2520     return ST_CONTINUE;
2521 }
2522
2523 /*
2524  *  call-seq:
2525  *     ObjectSpace.count_objects([result_hash]) -> hash
2526  *
2527  *  Counts objects for each type.
2528  *
2529  *  It returns a hash as:
2530  *  {:TOTAL=>10000, :FREE=>3011, :T_OBJECT=>6, :T_CLASS=>404, ...}
2531  *
2532  *  If the optional argument, result_hash, is given,
2533  *  it is overwritten and returned.
2534  *  This is intended to avoid probe effect.
2535  *
2536  *  The contents of the returned hash is implementation defined.
2537  *  It may be changed in future.
2538  *
2539  *  This method is not expected to work except C Ruby.
2540  *
2541  */
2542
2543 static VALUE
2544 count_objects(int argc, VALUE *argv, VALUE os)
2545 {
2546     rb_objspace_t *objspace = &rb_objspace;
2547     size_t counts[T_MASK+1];
2548     size_t freed = 0;
2549     size_t total = 0;
2550     size_t i;
2551     VALUE hash;
2552
2553     if (rb_scan_args(argc, argv, "01", &hash) == 1) {
2554         if (TYPE(hash) != T_HASH)
2555             rb_raise(rb_eTypeError, "non-hash given");
2556     }
2557
2558     for (i = 0; i <= T_MASK; i++) {
2559         counts[i] = 0;
2560     }
2561
2562     for (i = 0; i < heaps_used; i++) {
2563         RVALUE *p, *pend;
2564
2565         p = heaps[i].slot; pend = p + heaps[i].limit;
2566         for (;p < pend; p++) {
2567             if (p->as.basic.flags) {
2568                 counts[BUILTIN_TYPE(p)]++;
2569             }
2570             else {
2571                 freed++;
2572             }
2573         }
2574         total += heaps[i].limit;
2575     }
2576
2577     if (hash == Qnil) {
2578         hash = rb_hash_new();
2579     }
2580     else if (!RHASH_EMPTY_P(hash)) {
2581         st_foreach(RHASH_TBL(hash), set_zero, hash);
2582     }
2583     rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
2584     rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
2585
2586     for (i = 0; i <= T_MASK; i++) {
2587         VALUE type;
2588         switch (i) {
2589 #define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
2590             COUNT_TYPE(T_NONE);
2591             COUNT_TYPE(T_OBJECT);
2592             COUNT_TYPE(T_CLASS);
2593             COUNT_TYPE(T_MODULE);
2594             COUNT_TYPE(T_FLOAT);
2595             COUNT_TYPE(T_STRING);
2596             COUNT_TYPE(T_REGEXP);
2597             COUNT_TYPE(T_ARRAY);
2598             COUNT_TYPE(T_HASH);
2599             COUNT_TYPE(T_STRUCT);
2600             COUNT_TYPE(T_BIGNUM);
2601             COUNT_TYPE(T_FILE);
2602             COUNT_TYPE(T_DATA);
2603             COUNT_TYPE(T_MATCH);
2604             COUNT_TYPE(T_COMPLEX);
2605             COUNT_TYPE(T_RATIONAL);
2606             COUNT_TYPE(T_NIL);
2607             COUNT_TYPE(T_TRUE);
2608             COUNT_TYPE(T_FALSE);
2609             COUNT_TYPE(T_SYMBOL);
2610             COUNT_TYPE(T_FIXNUM);
2611             COUNT_TYPE(T_UNDEF);
2612             COUNT_TYPE(T_NODE);
2613             COUNT_TYPE(T_ICLASS);
2614             COUNT_TYPE(T_ZOMBIE);
2615 #undef COUNT_TYPE
2616           default:              type = INT2NUM(i); break;
2617         }
2618         if (counts[i])
2619             rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
2620     }
2621
2622     return hash;
2623 }
2624
2625 /*
2626  *  call-seq:
2627  *     GC.count -> Integer
2628  *
2629  *  The number of times GC occured.
2630  *
2631  *  It returns the number of times GC occured since the process started.
2632  *
2633  */
2634
2635 static VALUE
2636 gc_count(VALUE self)
2637 {
2638     return UINT2NUM((&rb_objspace)->count);
2639 }
2640
2641 #if CALC_EXACT_MALLOC_SIZE
2642 /*
2643  *  call-seq:
2644  *     GC.malloc_allocated_size -> Integer
2645  *
2646  *  The allocated size by malloc().
2647  *
2648  *  It returns the allocated size by malloc().
2649  */
2650
2651 static VALUE
2652 gc_malloc_allocated_size(VALUE self)
2653 {
2654     return UINT2NUM((&rb_objspace)->malloc_params.allocated_size);
2655 }
2656
2657 /*
2658  *  call-seq:
2659  *     GC.malloc_allocations -> Integer
2660  *
2661  *  The number of allocated memory object by malloc().
2662  *
2663  *  It returns the number of allocated memory object by malloc().
2664  */
2665
2666 static VALUE
2667 gc_malloc_allocations(VALUE self)
2668 {
2669     return UINT2NUM((&rb_objspace)->malloc_params.allocations);
2670 }
2671 #endif
2672
2673 static VALUE
2674 gc_profile_record_get(void)
2675 {
2676     VALUE prof;
2677     VALUE gc_profile = rb_ary_new();
2678     size_t i;
2679     rb_objspace_t *objspace = (&rb_objspace);
2680     
2681     if (!objspace->profile.run) {
2682         return Qnil;
2683     }
2684
2685     for (i =0; i < objspace->profile.count; i++) {
2686         prof = rb_hash_new();
2687         rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DBL2NUM(objspace->profile.record[i].gc_time));
2688         rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DBL2NUM(objspace->profile.record[i].gc_invoke_time));
2689         rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), rb_uint2inum(objspace->profile.record[i].heap_use_size));
2690         rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), rb_uint2inum(objspace->profile.record[i].heap_total_size));
2691         rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_total_objects));
2692 #if GC_PROFILE_MORE_DETAIL
2693         rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DBL2NUM(objspace->profile.record[i].gc_mark_time));
2694         rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DBL2NUM(objspace->profile.record[i].gc_sweep_time));
2695         rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), rb_uint2inum(objspace->profile.record[i].allocate_increase));
2696         rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), rb_uint2inum(objspace->profile.record[i].allocate_limit));
2697         rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SLOTS")), rb_uint2inum(objspace->profile.record[i].heap_use_slots));
2698         rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_live_objects));
2699         rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_free_objects));
2700         rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), objspace->profile.record[i].have_finalize);
2701 #endif
2702         rb_ary_push(gc_profile, prof);
2703     }
2704
2705     return gc_profile;
2706 }
2707
2708 /*
2709  *  call-seq:
2710  *     GC::Profiler.result -> string
2711  *
2712  *  Report profile data to string.
2713  *  
2714  *  It returns a string as:
2715  *   GC 1 invokes.
2716  *   Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC time(ms)
2717  *       1               0.012               159240               212940                10647         0.00000000000001530000
2718  */
2719
2720 static VALUE
2721 gc_profile_result(void)
2722 {
2723     rb_objspace_t *objspace = &rb_objspace;
2724     VALUE record;
2725     VALUE result;
2726     int i;
2727     
2728     record = gc_profile_record_get();
2729     if (objspace->profile.run && objspace->profile.count) {
2730         result = rb_sprintf("GC %d invokes.\n", NUM2INT(gc_count(0)));
2731         rb_str_cat2(result, "Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC Time(ms)\n");
2732         for (i = 0; i < (int)RARRAY_LEN(record); i++) {
2733             VALUE r = RARRAY_PTR(record)[i];
2734             rb_str_catf(result, "%5d %19.3f %20d %20d %20d %30.20f\n",
2735                         i+1, NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_INVOKE_TIME")))),
2736                         NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SIZE")))),
2737                         NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")))),
2738                         NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")))),
2739                         NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_TIME"))))*1000);
2740         }
2741 #if GC_PROFILE_MORE_DETAIL
2742         rb_str_cat2(result, "\n\n");
2743         rb_str_cat2(result, "More detail.\n");
2744         rb_str_cat2(result, "Index Allocate Increase    Allocate Limit  Use Slot  Have Finalize             Mark Time(ms)            Sweep Time(ms)\n");
2745         for (i = 0; i < (int)RARRAY_LEN(record); i++) {
2746             VALUE r = RARRAY_PTR(record)[i];
2747             rb_str_catf(result, "%5d %17d %17d %9d %14s %25.20f %25.20f\n",
2748                         i+1, NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_INCREASE")))),
2749                         NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_LIMIT")))),
2750                         NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SLOTS")))),
2751                         rb_hash_aref(r, ID2SYM(rb_intern("HAVE_FINALIZE")))? "true" : "false",
2752                         NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_MARK_TIME"))))*1000,
2753                         NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_SWEEP_TIME"))))*1000);
2754         }
2755 #endif
2756     }
2757     else {
2758         result = rb_str_new2("");
2759     }
2760     return result;
2761 }
2762
2763
2764 /*
2765  *  call-seq:
2766  *     GC::Profiler.report
2767  *
2768  *  GC::Profiler.result display
2769  *  
2770  */
2771
2772 static VALUE
2773 gc_profile_report(int argc, VALUE *argv, VALUE self)
2774 {
2775     VALUE out;
2776
2777     if (argc == 0) {
2778         out = rb_stdout;
2779     }
2780     else {
2781         rb_scan_args(argc, argv, "01", &out);
2782     }
2783     rb_io_write(out, gc_profile_result());
2784
2785     return Qnil;
2786 }
2787
2788
2789 /*
2790  *  The <code>GC</code> module provides an interface to Ruby's mark and
2791  *  sweep garbage collection mechanism. Some of the underlying methods
2792  *  are also available via the <code>ObjectSpace</code> module.
2793  */
2794
2795 void
2796 Init_GC(void)
2797 {
2798     VALUE rb_mObSpace;
2799     VALUE rb_mProfiler;
2800
2801     rb_mGC = rb_define_module("GC");
2802     rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0);
2803     rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
2804     rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
2805     rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0);
2806     rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1);
2807     rb_define_singleton_method(rb_mGC, "count", gc_count, 0);
2808     rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
2809
2810     rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler");
2811     rb_define_singleton_method(rb_mProfiler, "enabled?", gc_profile_enable_get, 0);
2812     rb_define_singleton_method(rb_mProfiler, "enable", gc_profile_enable, 0);
2813     rb_define_singleton_method(rb_mProfiler, "disable", gc_profile_disable, 0);
2814     rb_define_singleton_method(rb_mProfiler, "clear", gc_profile_clear, 0);
2815     rb_define_singleton_method(rb_mProfiler, "result", gc_profile_result, 0);
2816     rb_define_singleton_method(rb_mProfiler, "report", gc_profile_report, -1);
2817
2818     rb_mObSpace = rb_define_module("ObjectSpace");
2819     rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
2820     rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);
2821
2822     rb_define_module_function(rb_mObSpace, "define_finalizer", define_final, -1);
2823     rb_define_module_function(rb_mObSpace, "undefine_finalizer", undefine_final, 1);
2824
2825     rb_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1);
2826
2827     nomem_error = rb_exc_new3(rb_eNoMemError,
2828                               rb_obj_freeze(rb_str_new2("failed to allocate memory")));
2829     OBJ_TAINT(nomem_error);
2830     OBJ_FREEZE(nomem_error);
2831
2832     rb_define_method(rb_mKernel, "hash", rb_obj_id, 0);
2833     rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0);
2834     rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
2835
2836     rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1);
2837
2838 #if CALC_EXACT_MALLOC_SIZE
2839     rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
2840     rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
2841 #endif
2842 }