00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "ruby.h"
00016 #include "rubysig.h"
00017 #include "st.h"
00018 #include "node.h"
00019 #include "env.h"
00020 #include "re.h"
00021 #include <stdio.h>
00022 #include <setjmp.h>
00023 #include <sys/types.h>
00024
00025 #ifdef HAVE_SYS_TIME_H
00026 #include <sys/time.h>
00027 #endif
00028
00029 #ifdef HAVE_SYS_RESOURCE_H
00030 #include <sys/resource.h>
00031 #endif
00032
00033 #ifdef __ia64__
00034 #include <ucontext.h>
00035 #if defined(__FreeBSD__)
00036
00037
00038
00039
00040 #define __libc_ia64_register_backing_store_base (4ULL<<61)
00041 #else
00042 #pragma weak __libc_ia64_register_backing_store_base
00043 extern unsigned long __libc_ia64_register_backing_store_base;
00044 #endif
00045 #endif
00046
00047 #if defined _WIN32 || defined __CYGWIN__
00048 #include <windows.h>
00049 #endif
00050
00051 void re_free_registers (struct re_registers*);
00052 void rb_io_fptr_finalize (struct OpenFile*);
00053
00054 #if !defined(setjmp) && defined(HAVE__SETJMP)
00055 #define setjmp(env) _setjmp(env)
00056 #endif
00057
00058
00059 #ifdef __GNUC__
00060 # ifndef atarist
00061 # ifndef alloca
00062 # define alloca __builtin_alloca
00063 # endif
00064 # endif
00065 #else
00066 # ifdef HAVE_ALLOCA_H
00067 # include <alloca.h>
00068 # else
00069 # ifdef _AIX
00070 #pragma alloca
00071 # else
00072 # ifndef alloca
00073 void *alloca ();
00074 # endif
00075 # endif
00076 # endif
00077 #endif
00078
00079 #ifndef GC_MALLOC_LIMIT
00080 #if defined(MSDOS) || defined(__human68k__)
00081 #define GC_MALLOC_LIMIT 200000
00082 #else
00083 #define GC_MALLOC_LIMIT 8000000
00084 #endif
00085 #endif
00086
00087 static unsigned long malloc_increase = 0;
00088 static unsigned long malloc_limit = GC_MALLOC_LIMIT;
00089 static void run_final();
00090 static VALUE nomem_error;
00091 static void garbage_collect();
00092
00093 void
00094 rb_memerror()
00095 {
00096 static int recurse = 0;
00097
00098 if (recurse > 0 && rb_safe_level() < 4) {
00099 fprintf(stderr, "[FATAL] failed to allocate memory\n");
00100 exit(1);
00101 }
00102 recurse++;
00103 rb_exc_raise(nomem_error);
00104 }
00105
00106 void *
00107 ruby_xmalloc(size)
00108 long size;
00109 {
00110 void *mem;
00111
00112 if (size < 0) {
00113 rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
00114 }
00115 if (size == 0) size = 1;
00116 malloc_increase += size;
00117
00118 if (malloc_increase > malloc_limit) {
00119 garbage_collect();
00120 }
00121 RUBY_CRITICAL(mem = malloc(size));
00122 if (!mem) {
00123 garbage_collect();
00124 RUBY_CRITICAL(mem = malloc(size));
00125 if (!mem) {
00126 rb_memerror();
00127 }
00128 }
00129
00130 return mem;
00131 }
00132
00133 void *
00134 ruby_xcalloc(n, size)
00135 long n, size;
00136 {
00137 void *mem;
00138
00139 mem = xmalloc(n * size);
00140 memset(mem, 0, n * size);
00141
00142 return mem;
00143 }
00144
00145 void *
00146 ruby_xrealloc(ptr, size)
00147 void *ptr;
00148 long size;
00149 {
00150 void *mem;
00151
00152 if (size < 0) {
00153 rb_raise(rb_eArgError, "negative re-allocation size");
00154 }
00155 if (!ptr) return xmalloc(size);
00156 if (size == 0) size = 1;
00157 malloc_increase += size;
00158 RUBY_CRITICAL(mem = realloc(ptr, size));
00159 if (!mem) {
00160 garbage_collect();
00161 RUBY_CRITICAL(mem = realloc(ptr, size));
00162 if (!mem) {
00163 rb_memerror();
00164 }
00165 }
00166
00167 return mem;
00168 }
00169
00170 void
00171 ruby_xfree(x)
00172 void *x;
00173 {
00174 if (x)
00175 RUBY_CRITICAL(free(x));
00176 }
00177
00178 extern int ruby_in_compile;
00179 static int dont_gc;
00180 static int during_gc;
00181 static int need_call_final = 0;
00182 static st_table *finalizer_table = 0;
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 VALUE
00199 rb_gc_enable()
00200 {
00201 int old = dont_gc;
00202
00203 dont_gc = Qfalse;
00204 return old;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 VALUE
00220 rb_gc_disable()
00221 {
00222 int old = dont_gc;
00223
00224 dont_gc = Qtrue;
00225 return old;
00226 }
00227
00228 VALUE rb_mGC;
00229
00230 static struct gc_list {
00231 VALUE *varptr;
00232 struct gc_list *next;
00233 } *global_List = 0;
00234
00235 void
00236 rb_gc_register_address(addr)
00237 VALUE *addr;
00238 {
00239 struct gc_list *tmp;
00240
00241 tmp = ALLOC(struct gc_list);
00242 tmp->next = global_List;
00243 tmp->varptr = addr;
00244 global_List = tmp;
00245 }
00246
00247 void
00248 rb_gc_unregister_address(addr)
00249 VALUE *addr;
00250 {
00251 struct gc_list *tmp = global_List;
00252
00253 if (tmp->varptr == addr) {
00254 global_List = tmp->next;
00255 RUBY_CRITICAL(free(tmp));
00256 return;
00257 }
00258 while (tmp->next) {
00259 if (tmp->next->varptr == addr) {
00260 struct gc_list *t = tmp->next;
00261
00262 tmp->next = tmp->next->next;
00263 RUBY_CRITICAL(free(t));
00264 break;
00265 }
00266 tmp = tmp->next;
00267 }
00268 }
00269
00270 #undef GC_DEBUG
00271
00272 void
00273 rb_global_variable(var)
00274 VALUE *var;
00275 {
00276 rb_gc_register_address(var);
00277 }
00278
00279 typedef struct RVALUE {
00280 union {
00281 struct {
00282 unsigned long flags;
00283 struct RVALUE *next;
00284 } free;
00285 struct RBasic basic;
00286 struct RObject object;
00287 struct RClass klass;
00288 struct RFloat flonum;
00289 struct RString string;
00290 struct RArray array;
00291 struct RRegexp regexp;
00292 struct RHash hash;
00293 struct RData data;
00294 struct RStruct rstruct;
00295 struct RBignum bignum;
00296 struct RFile file;
00297 struct RNode node;
00298 struct RMatch match;
00299 struct RVarmap varmap;
00300 struct SCOPE scope;
00301 } as;
00302 #ifdef GC_DEBUG
00303 char *file;
00304 int line;
00305 #endif
00306 } RVALUE;
00307
00308 static RVALUE *freelist = 0;
00309 static RVALUE *deferred_final_list = 0;
00310
00311 #define HEAPS_INCREMENT 10
00312 static struct heaps_slot {
00313 RVALUE *slot;
00314 int limit;
00315 } *heaps;
00316 static int heaps_length = 0;
00317 static int heaps_used = 0;
00318
00319 #define HEAP_MIN_SLOTS 10000
00320 static int heap_slots = HEAP_MIN_SLOTS;
00321
00322 #define FREE_MIN 4096
00323
00324 static RVALUE *himem, *lomem;
00325
00326 static void
00327 add_heap()
00328 {
00329 RVALUE *p, *pend;
00330
00331 if (heaps_used == heaps_length) {
00332
00333 struct heaps_slot *p;
00334 int length;
00335
00336 heaps_length += HEAPS_INCREMENT;
00337 length = heaps_length*sizeof(struct heaps_slot);
00338 RUBY_CRITICAL(
00339 if (heaps_used > 0) {
00340 p = (struct heaps_slot *)realloc(heaps, length);
00341 if (p) heaps = p;
00342 }
00343 else {
00344 p = heaps = (struct heaps_slot *)malloc(length);
00345 });
00346 if (p == 0) rb_memerror();
00347 }
00348
00349 for (;;) {
00350 RUBY_CRITICAL(p = heaps[heaps_used].slot = (RVALUE*)malloc(sizeof(RVALUE)*heap_slots));
00351 heaps[heaps_used].limit = heap_slots;
00352 if (p == 0) {
00353 if (heap_slots == HEAP_MIN_SLOTS) {
00354 rb_memerror();
00355 }
00356 heap_slots = HEAP_MIN_SLOTS;
00357 continue;
00358 }
00359 break;
00360 }
00361 pend = p + heap_slots;
00362 if (lomem == 0 || lomem > p) lomem = p;
00363 if (himem < pend) himem = pend;
00364 heaps_used++;
00365 heap_slots *= 1.8;
00366
00367 while (p < pend) {
00368 p->as.free.flags = 0;
00369 p->as.free.next = freelist;
00370 freelist = p;
00371 p++;
00372 }
00373 }
00374 #define RANY(o) ((RVALUE*)(o))
00375
00376 VALUE
00377 rb_newobj()
00378 {
00379 VALUE obj;
00380
00381 if (!freelist) garbage_collect();
00382
00383 obj = (VALUE)freelist;
00384 freelist = freelist->as.free.next;
00385 MEMZERO((void*)obj, RVALUE, 1);
00386 #ifdef GC_DEBUG
00387 RANY(obj)->file = ruby_sourcefile;
00388 RANY(obj)->line = ruby_sourceline;
00389 #endif
00390 return obj;
00391 }
00392
00393 VALUE
00394 rb_data_object_alloc(klass, datap, dmark, dfree)
00395 VALUE klass;
00396 void *datap;
00397 RUBY_DATA_FUNC dmark;
00398 RUBY_DATA_FUNC dfree;
00399 {
00400 NEWOBJ(data, struct RData);
00401 if (klass) Check_Type(klass, T_CLASS);
00402 OBJSETUP(data, klass, T_DATA);
00403 data->data = datap;
00404 data->dfree = dfree;
00405 data->dmark = dmark;
00406
00407 return (VALUE)data;
00408 }
00409
00410 extern st_table *rb_class_tbl;
00411 VALUE *rb_gc_stack_start = 0;
00412
00413 #ifdef DJGPP
00414
00415 unsigned int _stklen = 0x180000;
00416 #endif
00417
00418 #if defined(DJGPP) || defined(_WIN32_WCE)
00419 static unsigned int STACK_LEVEL_MAX = 65535;
00420 #elif defined(__human68k__)
00421 unsigned int _stacksize = 262144;
00422 # define STACK_LEVEL_MAX (_stacksize - 4096)
00423 # undef HAVE_GETRLIMIT
00424 #elif defined(HAVE_GETRLIMIT)
00425 static unsigned int STACK_LEVEL_MAX = 655300;
00426 #else
00427 # define STACK_LEVEL_MAX 655300
00428 #endif
00429
00430 #ifdef C_ALLOCA
00431 # define SET_STACK_END VALUE stack_end; alloca(0);
00432 # define STACK_END (&stack_end)
00433 #else
00434 # if defined(__GNUC__) && defined(USE_BUILTIN_FRAME_ADDRESS) && !defined(__ia64__)
00435 # if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3
00436 __attribute__ ((noinline))
00437 # endif
00438 static VALUE *
00439 stack_end_address(void)
00440 {
00441 return (VALUE *)__builtin_frame_address(0);
00442 }
00443 # define SET_STACK_END VALUE *stack_end = stack_end_address()
00444 # else
00445 # define SET_STACK_END VALUE *stack_end = alloca(1)
00446 # endif
00447 # define STACK_END (stack_end)
00448 #endif
00449 #if defined(sparc) || defined(__sparc__)
00450 # define STACK_LENGTH (rb_gc_stack_start - STACK_END + 0x80)
00451 #elif STACK_GROW_DIRECTION < 0
00452 # define STACK_LENGTH (rb_gc_stack_start - STACK_END)
00453 #elif STACK_GROW_DIRECTION > 0
00454 # define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1)
00455 #else
00456 # define STACK_LENGTH ((STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END\
00457 : STACK_END - rb_gc_stack_start + 1)
00458 #endif
00459 #if STACK_GROW_DIRECTION > 0
00460 # define STACK_UPPER(x, a, b) a
00461 #elif STACK_GROW_DIRECTION < 0
00462 # define STACK_UPPER(x, a, b) b
00463 #else
00464 static int grow_direction;
00465 static int
00466 stack_grow_direction(addr)
00467 VALUE *addr;
00468 {
00469 SET_STACK_END;
00470
00471 if (STACK_END > addr) return grow_direction = 1;
00472 return grow_direction = -1;
00473 }
00474 # define stack_growup_p(x) ((grow_direction ? grow_direction : stack_grow_direction(x)) > 0)
00475 # define STACK_UPPER(x, a, b) (stack_growup_p(x) ? a : b)
00476 #endif
00477
00478 #define GC_WATER_MARK 512
00479
00480 #define CHECK_STACK(ret) do {\
00481 SET_STACK_END;\
00482 (ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
00483 } while (0)
00484
00485 int
00486 ruby_stack_length(p)
00487 VALUE **p;
00488 {
00489 SET_STACK_END;
00490 if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END);
00491 return STACK_LENGTH;
00492 }
00493
00494 int
00495 ruby_stack_check()
00496 {
00497 int ret;
00498
00499 CHECK_STACK(ret);
00500 return ret;
00501 }
00502
00503 #define MARK_STACK_MAX 1024
00504 static VALUE mark_stack[MARK_STACK_MAX];
00505 static VALUE *mark_stack_ptr;
00506 static int mark_stack_overflow;
00507
00508 static void
00509 init_mark_stack()
00510 {
00511 mark_stack_overflow = 0;
00512 mark_stack_ptr = mark_stack;
00513 }
00514
00515 #define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack)
00516
00517 static st_table *source_filenames;
00518
00519 char *
00520 rb_source_filename(f)
00521 const char *f;
00522 {
00523 char *name;
00524
00525 if (!st_lookup(source_filenames, (st_data_t)f, (st_data_t *)&name)) {
00526 long len = strlen(f) + 1;
00527 char *ptr = name = ALLOC_N(char, len + 1);
00528 *ptr++ = 0;
00529 MEMCPY(ptr, f, char, len);
00530 st_add_direct(source_filenames, (st_data_t)ptr, (st_data_t)name);
00531 return ptr;
00532 }
00533 return name + 1;
00534 }
00535
00536 static void
00537 mark_source_filename(f)
00538 char *f;
00539 {
00540 if (f) {
00541 f[-1] = 1;
00542 }
00543 }
00544
00545 static int
00546 sweep_source_filename(key, value)
00547 char *key, *value;
00548 {
00549 if (*value) {
00550 *value = 0;
00551 return ST_CONTINUE;
00552 }
00553 else {
00554 free(value);
00555 return ST_DELETE;
00556 }
00557 }
00558
00559 static void gc_mark (VALUE ptr, int lev);
00560 static void gc_mark_children (VALUE ptr, int lev);
00561
00562 static void
00563 gc_mark_all()
00564 {
00565 RVALUE *p, *pend;
00566 int i;
00567
00568 init_mark_stack();
00569 for (i = 0; i < heaps_used; i++) {
00570 p = heaps[i].slot; pend = p + heaps[i].limit;
00571 while (p < pend) {
00572 if ((p->as.basic.flags & FL_MARK) &&
00573 (p->as.basic.flags != FL_MARK)) {
00574 gc_mark_children((VALUE)p, 0);
00575 }
00576 p++;
00577 }
00578 }
00579 }
00580
00581 static void
00582 gc_mark_rest()
00583 {
00584 VALUE tmp_arry[MARK_STACK_MAX];
00585 VALUE *p;
00586
00587 p = (mark_stack_ptr - mark_stack) + tmp_arry;
00588 MEMCPY(tmp_arry, mark_stack, VALUE, MARK_STACK_MAX);
00589
00590 init_mark_stack();
00591 while(p != tmp_arry){
00592 p--;
00593 gc_mark_children(*p, 0);
00594 }
00595 }
00596
00597 static inline int
00598 is_pointer_to_heap(ptr)
00599 void *ptr;
00600 {
00601 register RVALUE *p = RANY(ptr);
00602 register RVALUE *heap_org;
00603 register long i;
00604
00605 if (p < lomem || p > himem) return Qfalse;
00606
00607
00608 for (i=0; i < heaps_used; i++) {
00609 heap_org = heaps[i].slot;
00610 if (heap_org <= p && p < heap_org + heaps[i].limit &&
00611 ((((char*)p)-((char*)heap_org))%sizeof(RVALUE)) == 0)
00612 return Qtrue;
00613 }
00614 return Qfalse;
00615 }
00616
00617 static void
00618 mark_locations_array(x, n)
00619 register VALUE *x;
00620 register long n;
00621 {
00622 VALUE v;
00623 while (n--) {
00624 v = *x;
00625 if (is_pointer_to_heap((void *)v)) {
00626 gc_mark(v, 0);
00627 }
00628 x++;
00629 }
00630 }
00631
00632 void
00633 rb_gc_mark_locations(start, end)
00634 VALUE *start, *end;
00635 {
00636 long n;
00637
00638 n = end - start;
00639 mark_locations_array(start,n);
00640 }
00641
00642 static int
00643 mark_entry(key, value, lev)
00644 ID key;
00645 VALUE value;
00646 int lev;
00647 {
00648 gc_mark(value, lev);
00649 return ST_CONTINUE;
00650 }
00651
00652 static void
00653 mark_tbl(tbl, lev)
00654 st_table *tbl;
00655 int lev;
00656 {
00657 if (!tbl) return;
00658 st_foreach(tbl, mark_entry, lev);
00659 }
00660
00661 void
00662 rb_mark_tbl(tbl)
00663 st_table *tbl;
00664 {
00665 mark_tbl(tbl, 0);
00666 }
00667
00668 static int
00669 mark_keyvalue(key, value, lev)
00670 VALUE key;
00671 VALUE value;
00672 int lev;
00673 {
00674 gc_mark(key, lev);
00675 gc_mark(value, lev);
00676 return ST_CONTINUE;
00677 }
00678
00679 static void
00680 mark_hash(tbl, lev)
00681 st_table *tbl;
00682 int lev;
00683 {
00684 if (!tbl) return;
00685 st_foreach(tbl, mark_keyvalue, lev);
00686 }
00687
00688 void
00689 rb_mark_hash(tbl)
00690 st_table *tbl;
00691 {
00692 mark_hash(tbl, 0);
00693 }
00694
00695 void
00696 rb_gc_mark_maybe(obj)
00697 VALUE obj;
00698 {
00699 if (is_pointer_to_heap((void *)obj)) {
00700 gc_mark(obj, 0);
00701 }
00702 }
00703
00704 #define GC_LEVEL_MAX 250
00705
00706 static void
00707 gc_mark(ptr, lev)
00708 VALUE ptr;
00709 int lev;
00710 {
00711 register RVALUE *obj;
00712
00713 obj = RANY(ptr);
00714 if (rb_special_const_p(ptr)) return;
00715 if (obj->as.basic.flags == 0) return;
00716 if (obj->as.basic.flags & FL_MARK) return;
00717 obj->as.basic.flags |= FL_MARK;
00718
00719 if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) {
00720 if (!mark_stack_overflow) {
00721 if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) {
00722 *mark_stack_ptr = ptr;
00723 mark_stack_ptr++;
00724 }
00725 else {
00726 mark_stack_overflow = 1;
00727 }
00728 }
00729 return;
00730 }
00731 gc_mark_children(ptr, lev+1);
00732 }
00733
00734 void
00735 rb_gc_mark(ptr)
00736 VALUE ptr;
00737 {
00738 gc_mark(ptr, 0);
00739 }
00740
00741 static void
00742 gc_mark_children(ptr, lev)
00743 VALUE ptr;
00744 int lev;
00745 {
00746 register RVALUE *obj = RANY(ptr);
00747
00748 goto marking;
00749
00750 again:
00751 obj = RANY(ptr);
00752 if (rb_special_const_p(ptr)) return;
00753 if (obj->as.basic.flags == 0) return;
00754 if (obj->as.basic.flags & FL_MARK) return;
00755 obj->as.basic.flags |= FL_MARK;
00756
00757 marking:
00758 if (FL_TEST(obj, FL_EXIVAR)) {
00759 rb_mark_generic_ivar(ptr);
00760 }
00761
00762 switch (obj->as.basic.flags & T_MASK) {
00763 case T_NIL:
00764 case T_FIXNUM:
00765 rb_bug("rb_gc_mark() called for broken object");
00766 break;
00767
00768 case T_NODE:
00769 mark_source_filename(obj->as.node.nd_file);
00770 switch (nd_type(obj)) {
00771 case NODE_IF:
00772 case NODE_FOR:
00773 case NODE_ITER:
00774 case NODE_CREF:
00775 case NODE_WHEN:
00776 case NODE_MASGN:
00777 case NODE_RESCUE:
00778 case NODE_RESBODY:
00779 case NODE_CLASS:
00780 gc_mark((VALUE)obj->as.node.u2.node, lev);
00781
00782 case NODE_BLOCK:
00783 case NODE_ARRAY:
00784 case NODE_DSTR:
00785 case NODE_DXSTR:
00786 case NODE_DREGX:
00787 case NODE_DREGX_ONCE:
00788 case NODE_FBODY:
00789 case NODE_ENSURE:
00790 case NODE_CALL:
00791 case NODE_DEFS:
00792 case NODE_OP_ASGN1:
00793 gc_mark((VALUE)obj->as.node.u1.node, lev);
00794
00795 case NODE_SUPER:
00796 case NODE_FCALL:
00797 case NODE_DEFN:
00798 case NODE_NEWLINE:
00799 ptr = (VALUE)obj->as.node.u3.node;
00800 goto again;
00801
00802 case NODE_WHILE:
00803 case NODE_UNTIL:
00804 case NODE_AND:
00805 case NODE_OR:
00806 case NODE_CASE:
00807 case NODE_SCLASS:
00808 case NODE_DOT2:
00809 case NODE_DOT3:
00810 case NODE_FLIP2:
00811 case NODE_FLIP3:
00812 case NODE_MATCH2:
00813 case NODE_MATCH3:
00814 case NODE_OP_ASGN_OR:
00815 case NODE_OP_ASGN_AND:
00816 case NODE_MODULE:
00817 gc_mark((VALUE)obj->as.node.u1.node, lev);
00818
00819 case NODE_METHOD:
00820 case NODE_NOT:
00821 case NODE_GASGN:
00822 case NODE_LASGN:
00823 case NODE_DASGN:
00824 case NODE_DASGN_CURR:
00825 case NODE_IASGN:
00826 case NODE_CVDECL:
00827 case NODE_CVASGN:
00828 case NODE_COLON3:
00829 case NODE_OPT_N:
00830 case NODE_EVSTR:
00831 ptr = (VALUE)obj->as.node.u2.node;
00832 goto again;
00833
00834 case NODE_HASH:
00835 case NODE_LIT:
00836 case NODE_STR:
00837 case NODE_XSTR:
00838 case NODE_DEFINED:
00839 case NODE_MATCH:
00840 case NODE_RETURN:
00841 case NODE_BREAK:
00842 case NODE_NEXT:
00843 case NODE_YIELD:
00844 case NODE_COLON2:
00845 case NODE_ARGS:
00846 case NODE_SPLAT:
00847 case NODE_TO_ARY:
00848 case NODE_SVALUE:
00849 ptr = (VALUE)obj->as.node.u1.node;
00850 goto again;
00851
00852 case NODE_SCOPE:
00853 case NODE_BLOCK_PASS:
00854 case NODE_CDECL:
00855 gc_mark((VALUE)obj->as.node.u3.node, lev);
00856 ptr = (VALUE)obj->as.node.u2.node;
00857 goto again;
00858
00859 case NODE_ZARRAY:
00860 case NODE_ZSUPER:
00861 case NODE_CFUNC:
00862 case NODE_VCALL:
00863 case NODE_GVAR:
00864 case NODE_LVAR:
00865 case NODE_DVAR:
00866 case NODE_IVAR:
00867 case NODE_CVAR:
00868 case NODE_NTH_REF:
00869 case NODE_BACK_REF:
00870 case NODE_ALIAS:
00871 case NODE_VALIAS:
00872 case NODE_REDO:
00873 case NODE_RETRY:
00874 case NODE_UNDEF:
00875 case NODE_SELF:
00876 case NODE_NIL:
00877 case NODE_TRUE:
00878 case NODE_FALSE:
00879 case NODE_ATTRSET:
00880 case NODE_BLOCK_ARG:
00881 case NODE_POSTEXE:
00882 break;
00883 case NODE_ALLOCA:
00884 mark_locations_array((VALUE*)obj->as.node.u1.value,
00885 obj->as.node.u3.cnt);
00886 ptr = (VALUE)obj->as.node.u2.node;
00887 goto again;
00888
00889 default:
00890 if (is_pointer_to_heap(obj->as.node.u1.node)) {
00891 gc_mark((VALUE)obj->as.node.u1.node, lev);
00892 }
00893 if (is_pointer_to_heap(obj->as.node.u2.node)) {
00894 gc_mark((VALUE)obj->as.node.u2.node, lev);
00895 }
00896 if (is_pointer_to_heap(obj->as.node.u3.node)) {
00897 gc_mark((VALUE)obj->as.node.u3.node, lev);
00898 }
00899 }
00900 return;
00901 }
00902
00903 gc_mark(obj->as.basic.klass, lev);
00904 switch (obj->as.basic.flags & T_MASK) {
00905 case T_ICLASS:
00906 case T_CLASS:
00907 case T_MODULE:
00908 mark_tbl(obj->as.klass.m_tbl, lev);
00909 mark_tbl(obj->as.klass.iv_tbl, lev);
00910 ptr = obj->as.klass.super;
00911 goto again;
00912
00913 case T_ARRAY:
00914 if (FL_TEST(obj, ELTS_SHARED)) {
00915 ptr = obj->as.array.aux.shared;
00916 goto again;
00917 }
00918 else {
00919 long i, len = obj->as.array.len;
00920 VALUE *ptr = obj->as.array.ptr;
00921
00922 for (i=0; i < len; i++) {
00923 gc_mark(*ptr++, lev);
00924 }
00925 }
00926 break;
00927
00928 case T_HASH:
00929 mark_hash(obj->as.hash.tbl, lev);
00930 ptr = obj->as.hash.ifnone;
00931 goto again;
00932
00933 case T_STRING:
00934 #define STR_ASSOC FL_USER3
00935 if (FL_TEST(obj, ELTS_SHARED|STR_ASSOC)) {
00936 ptr = obj->as.string.aux.shared;
00937 goto again;
00938 }
00939 break;
00940
00941 case T_DATA:
00942 if (obj->as.data.dmark) (*obj->as.data.dmark)(DATA_PTR(obj));
00943 break;
00944
00945 case T_OBJECT:
00946 mark_tbl(obj->as.object.iv_tbl, lev);
00947 break;
00948
00949 case T_FILE:
00950 case T_REGEXP:
00951 case T_FLOAT:
00952 case T_BIGNUM:
00953 case T_BLKTAG:
00954 break;
00955
00956 case T_MATCH:
00957 if (obj->as.match.str) {
00958 ptr = obj->as.match.str;
00959 goto again;
00960 }
00961 break;
00962
00963 case T_VARMAP:
00964 gc_mark(obj->as.varmap.val, lev);
00965 ptr = (VALUE)obj->as.varmap.next;
00966 goto again;
00967
00968 case T_SCOPE:
00969 if (obj->as.scope.local_vars && (obj->as.scope.flags & SCOPE_MALLOC)) {
00970 int n = obj->as.scope.local_tbl[0]+1;
00971 VALUE *vars = &obj->as.scope.local_vars[-1];
00972
00973 while (n--) {
00974 gc_mark(*vars++, lev);
00975 }
00976 }
00977 break;
00978
00979 case T_STRUCT:
00980 {
00981 long len = obj->as.rstruct.len;
00982 VALUE *ptr = obj->as.rstruct.ptr;
00983
00984 while (len--) {
00985 gc_mark(*ptr++, lev);
00986 }
00987 }
00988 break;
00989
00990 default:
00991 rb_bug("rb_gc_mark(): unknown data type 0x%lx(0x%lx) %s",
00992 obj->as.basic.flags & T_MASK, obj,
00993 is_pointer_to_heap(obj) ? "corrupted object" : "non object");
00994 }
00995 }
00996
00997 static void obj_free (VALUE);
00998
00999 static void
01000 finalize_list(p)
01001 RVALUE *p;
01002 {
01003 while (p) {
01004 RVALUE *tmp = p->as.free.next;
01005 run_final((VALUE)p);
01006 if (!FL_TEST(p, FL_SINGLETON)) {
01007 p->as.free.flags = 0;
01008 p->as.free.next = freelist;
01009 freelist = p;
01010 }
01011 p = tmp;
01012 }
01013 }
01014
01015 static void
01016 free_unused_heaps()
01017 {
01018 int i, j;
01019
01020 for (i = j = 1; j < heaps_used; i++) {
01021 if (heaps[i].limit == 0) {
01022 free(heaps[i].slot);
01023 heaps_used--;
01024 }
01025 else {
01026 if (i != j) {
01027 heaps[j] = heaps[i];
01028 }
01029 j++;
01030 }
01031 }
01032 }
01033
01034 static void
01035 gc_sweep()
01036 {
01037 RVALUE *p, *pend, *final_list;
01038 int freed = 0;
01039 int i;
01040 unsigned long live = 0;
01041
01042 if (ruby_in_compile && ruby_parser_stack_on_heap()) {
01043
01044
01045 for (i = 0; i < heaps_used; i++) {
01046 p = heaps[i].slot; pend = p + heaps[i].limit;
01047 while (p < pend) {
01048 if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE)
01049 gc_mark((VALUE)p, 0);
01050 p++;
01051 }
01052 }
01053 }
01054
01055 mark_source_filename(ruby_sourcefile);
01056 if (source_filenames) {
01057 st_foreach(source_filenames, sweep_source_filename, 0);
01058 }
01059
01060 freelist = 0;
01061 final_list = deferred_final_list;
01062 deferred_final_list = 0;
01063 for (i = 0; i < heaps_used; i++) {
01064 int n = 0;
01065 RVALUE *free = freelist;
01066 RVALUE *final = final_list;
01067
01068 p = heaps[i].slot; pend = p + heaps[i].limit;
01069 while (p < pend) {
01070 if (!(p->as.basic.flags & FL_MARK)) {
01071 if (p->as.basic.flags) {
01072 obj_free((VALUE)p);
01073 }
01074 if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
01075 p->as.free.flags = FL_MARK;
01076 p->as.free.next = final_list;
01077 final_list = p;
01078 }
01079 else {
01080 p->as.free.flags = 0;
01081 p->as.free.next = freelist;
01082 freelist = p;
01083 }
01084 n++;
01085 }
01086 else if (RBASIC(p)->flags == FL_MARK) {
01087
01088
01089 }
01090 else {
01091 RBASIC(p)->flags &= ~FL_MARK;
01092 live++;
01093 }
01094 p++;
01095 }
01096 if (n == heaps[i].limit && freed > FREE_MIN) {
01097 RVALUE *pp;
01098
01099 heaps[i].limit = 0;
01100 for (pp = final_list; pp != final; pp = pp->as.free.next) {
01101 p->as.free.flags |= FL_SINGLETON;
01102 }
01103 freelist = free;
01104 }
01105 else {
01106 freed += n;
01107 }
01108 }
01109 if (malloc_increase > malloc_limit) {
01110 malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
01111 if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
01112 }
01113 malloc_increase = 0;
01114 if (freed < FREE_MIN) {
01115 add_heap();
01116 }
01117 during_gc = 0;
01118
01119
01120 if (final_list) {
01121 deferred_final_list = final_list;
01122 return;
01123 }
01124 free_unused_heaps();
01125 }
01126
01127 void
01128 rb_gc_force_recycle(p)
01129 VALUE p;
01130 {
01131 RANY(p)->as.free.flags = 0;
01132 RANY(p)->as.free.next = freelist;
01133 freelist = RANY(p);
01134 }
01135
01136 static void
01137 obj_free(obj)
01138 VALUE obj;
01139 {
01140 switch (RANY(obj)->as.basic.flags & T_MASK) {
01141 case T_NIL:
01142 case T_FIXNUM:
01143 case T_TRUE:
01144 case T_FALSE:
01145 rb_bug("obj_free() called for broken object");
01146 break;
01147 }
01148
01149 if (FL_TEST(obj, FL_EXIVAR)) {
01150 rb_free_generic_ivar((VALUE)obj);
01151 }
01152
01153 switch (RANY(obj)->as.basic.flags & T_MASK) {
01154 case T_OBJECT:
01155 if (RANY(obj)->as.object.iv_tbl) {
01156 st_free_table(RANY(obj)->as.object.iv_tbl);
01157 }
01158 break;
01159 case T_MODULE:
01160 case T_CLASS:
01161 rb_clear_cache_by_class((VALUE)obj);
01162 st_free_table(RANY(obj)->as.klass.m_tbl);
01163 if (RANY(obj)->as.object.iv_tbl) {
01164 st_free_table(RANY(obj)->as.object.iv_tbl);
01165 }
01166 break;
01167 case T_STRING:
01168 if (RANY(obj)->as.string.ptr && !FL_TEST(obj, ELTS_SHARED)) {
01169 RUBY_CRITICAL(free(RANY(obj)->as.string.ptr));
01170 }
01171 break;
01172 case T_ARRAY:
01173 if (RANY(obj)->as.array.ptr && !FL_TEST(obj, ELTS_SHARED)) {
01174 RUBY_CRITICAL(free(RANY(obj)->as.array.ptr));
01175 }
01176 break;
01177 case T_HASH:
01178 if (RANY(obj)->as.hash.tbl) {
01179 st_free_table(RANY(obj)->as.hash.tbl);
01180 }
01181 break;
01182 case T_REGEXP:
01183 if (RANY(obj)->as.regexp.ptr) {
01184 re_free_pattern(RANY(obj)->as.regexp.ptr);
01185 }
01186 if (RANY(obj)->as.regexp.str) {
01187 RUBY_CRITICAL(free(RANY(obj)->as.regexp.str));
01188 }
01189 break;
01190 case T_DATA:
01191 if (DATA_PTR(obj)) {
01192 if ((long)RANY(obj)->as.data.dfree == -1) {
01193 RUBY_CRITICAL(free(DATA_PTR(obj)));
01194 }
01195 else if (RANY(obj)->as.data.dfree) {
01196 (*RANY(obj)->as.data.dfree)(DATA_PTR(obj));
01197 }
01198 }
01199 break;
01200 case T_MATCH:
01201 if (RANY(obj)->as.match.regs) {
01202 re_free_registers(RANY(obj)->as.match.regs);
01203 RUBY_CRITICAL(free(RANY(obj)->as.match.regs));
01204 }
01205 break;
01206 case T_FILE:
01207 if (RANY(obj)->as.file.fptr) {
01208 rb_io_fptr_finalize(RANY(obj)->as.file.fptr);
01209 RUBY_CRITICAL(free(RANY(obj)->as.file.fptr));
01210 }
01211 break;
01212 case T_ICLASS:
01213
01214 break;
01215
01216 case T_FLOAT:
01217 case T_VARMAP:
01218 case T_BLKTAG:
01219 break;
01220
01221 case T_BIGNUM:
01222 if (RANY(obj)->as.bignum.digits) {
01223 RUBY_CRITICAL(free(RANY(obj)->as.bignum.digits));
01224 }
01225 break;
01226 case T_NODE:
01227 switch (nd_type(obj)) {
01228 case NODE_SCOPE:
01229 if (RANY(obj)->as.node.u1.tbl) {
01230 RUBY_CRITICAL(free(RANY(obj)->as.node.u1.tbl));
01231 }
01232 break;
01233 case NODE_ALLOCA:
01234 RUBY_CRITICAL(free(RANY(obj)->as.node.u1.node));
01235 break;
01236 }
01237 return;
01238
01239 case T_SCOPE:
01240 if (RANY(obj)->as.scope.local_vars &&
01241 RANY(obj)->as.scope.flags != SCOPE_ALLOCA) {
01242 VALUE *vars = RANY(obj)->as.scope.local_vars-1;
01243 if (vars[0] == 0)
01244 RUBY_CRITICAL(free(RANY(obj)->as.scope.local_tbl));
01245 if (RANY(obj)->as.scope.flags & SCOPE_MALLOC)
01246 RUBY_CRITICAL(free(vars));
01247 }
01248 break;
01249
01250 case T_STRUCT:
01251 if (RANY(obj)->as.rstruct.ptr) {
01252 RUBY_CRITICAL(free(RANY(obj)->as.rstruct.ptr));
01253 }
01254 break;
01255
01256 default:
01257 rb_bug("gc_sweep(): unknown data type 0x%lx(0x%lx)",
01258 RANY(obj)->as.basic.flags & T_MASK, obj);
01259 }
01260 }
01261
01262 void
01263 rb_gc_mark_frame(frame)
01264 struct FRAME *frame;
01265 {
01266 mark_locations_array(frame->argv, frame->argc);
01267 gc_mark((VALUE)frame->node, 0);
01268 }
01269
01270 #ifdef __GNUC__
01271 #if defined(__human68k__) || defined(DJGPP)
01272 #if defined(__human68k__)
01273 typedef unsigned long rb_jmp_buf[8];
01274 __asm__ (".even\n\
01275 _rb_setjmp:\n\
01276 move.l 4(sp),a0\n\
01277 movem.l d3-d7/a3-a5,(a0)\n\
01278 moveq.l #0,d0\n\
01279 rts");
01280 #ifdef setjmp
01281 #undef setjmp
01282 #endif
01283 #else
01284 #if defined(DJGPP)
01285 typedef unsigned long rb_jmp_buf[6];
01286 __asm__ (".align 4\n\
01287 _rb_setjmp:\n\
01288 pushl %ebp\n\
01289 movl %esp,%ebp\n\
01290 movl 8(%ebp),%ebp\n\
01291 movl %eax,(%ebp)\n\
01292 movl %ebx,4(%ebp)\n\
01293 movl %ecx,8(%ebp)\n\
01294 movl %edx,12(%ebp)\n\
01295 movl %esi,16(%ebp)\n\
01296 movl %edi,20(%ebp)\n\
01297 popl %ebp\n\
01298 xorl %eax,%eax\n\
01299 ret");
01300 #endif
01301 #endif
01302 int rb_setjmp (rb_jmp_buf);
01303 #define jmp_buf rb_jmp_buf
01304 #define setjmp rb_setjmp
01305 #endif
01306 #endif
01307
01308 static void
01309 garbage_collect()
01310 {
01311 struct gc_list *list;
01312 struct FRAME * volatile frame;
01313 jmp_buf save_regs_gc_mark;
01314 SET_STACK_END;
01315
01316 #ifdef HAVE_NATIVETHREAD
01317 if (!is_ruby_native_thread()) {
01318 rb_bug("cross-thread violation on rb_gc()");
01319 }
01320 #endif
01321 if (dont_gc || during_gc) {
01322 if (!freelist) {
01323 add_heap();
01324 }
01325 return;
01326 }
01327 if (during_gc) return;
01328 during_gc++;
01329
01330 init_mark_stack();
01331
01332
01333 for (frame = ruby_frame; frame; frame = frame->prev) {
01334 rb_gc_mark_frame(frame);
01335 if (frame->tmp) {
01336 struct FRAME *tmp = frame->tmp;
01337 while (tmp) {
01338 rb_gc_mark_frame(tmp);
01339 tmp = tmp->prev;
01340 }
01341 }
01342 }
01343 gc_mark((VALUE)ruby_scope, 0);
01344 gc_mark((VALUE)ruby_dyna_vars, 0);
01345 if (finalizer_table) {
01346 mark_tbl(finalizer_table, 0);
01347 }
01348
01349 FLUSH_REGISTER_WINDOWS;
01350
01351 setjmp(save_regs_gc_mark);
01352 mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
01353 #if STACK_GROW_DIRECTION < 0
01354 rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
01355 #elif STACK_GROW_DIRECTION > 0
01356 rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1);
01357 #else
01358 if ((VALUE*)STACK_END < rb_gc_stack_start)
01359 rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
01360 else
01361 rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1);
01362 #endif
01363 #ifdef __ia64__
01364
01365
01366 {
01367 ucontext_t ctx;
01368 VALUE *top, *bot;
01369 getcontext(&ctx);
01370 mark_locations_array((VALUE*)&ctx.uc_mcontext,
01371 ((size_t)(sizeof(VALUE)-1 + sizeof ctx.uc_mcontext)/sizeof(VALUE)));
01372 bot = (VALUE*)__libc_ia64_register_backing_store_base;
01373 #if defined(__FreeBSD__)
01374 top = (VALUE*)ctx.uc_mcontext.mc_special.bspstore;
01375 #else
01376 top = (VALUE*)ctx.uc_mcontext.sc_ar_bsp;
01377 #endif
01378 rb_gc_mark_locations(bot, top);
01379 }
01380 #endif
01381 #if defined(__human68k__) || defined(__mc68000__)
01382 rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
01383 (VALUE*)((char*)rb_gc_stack_start + 2));
01384 #endif
01385 rb_gc_mark_threads();
01386
01387
01388 for (list = global_List; list; list = list->next) {
01389 rb_gc_mark_maybe(*list->varptr);
01390 }
01391 rb_mark_end_proc();
01392 rb_gc_mark_global_tbl();
01393
01394 rb_mark_tbl(rb_class_tbl);
01395 rb_gc_mark_trap_list();
01396
01397
01398 rb_mark_generic_ivar_tbl();
01399
01400 rb_gc_mark_parser();
01401
01402
01403 while (!MARK_STACK_EMPTY){
01404 if (mark_stack_overflow){
01405 gc_mark_all();
01406 }
01407 else {
01408 gc_mark_rest();
01409 }
01410 }
01411 gc_sweep();
01412 }
01413
01414 void
01415 rb_gc()
01416 {
01417 garbage_collect();
01418 rb_gc_finalize_deferred();
01419 }
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431 VALUE
01432 rb_gc_start()
01433 {
01434 rb_gc();
01435 return Qnil;
01436 }
01437
01438 void
01439 ruby_set_stack_size(size)
01440 size_t size;
01441 {
01442 #ifndef STACK_LEVEL_MAX
01443 STACK_LEVEL_MAX = size / sizeof(VALUE);
01444 #endif
01445 }
01446
01447 void
01448 Init_stack(addr)
01449 VALUE *addr;
01450 {
01451 #if defined(_WIN32) || defined(__CYGWIN__)
01452 MEMORY_BASIC_INFORMATION m;
01453 memset(&m, 0, sizeof(m));
01454 VirtualQuery(&m, &m, sizeof(m));
01455 rb_gc_stack_start =
01456 STACK_UPPER((VALUE *)&m, (VALUE *)m.BaseAddress,
01457 (VALUE *)((char *)m.BaseAddress + m.RegionSize) - 1);
01458 #elif defined(STACK_END_ADDRESS)
01459 extern void *STACK_END_ADDRESS;
01460 rb_gc_stack_start = STACK_END_ADDRESS;
01461 #else
01462 if (!addr) addr = (VALUE *)&addr;
01463 STACK_UPPER(&addr, addr, ++addr);
01464 if (rb_gc_stack_start) {
01465 if (STACK_UPPER(&addr,
01466 rb_gc_stack_start > addr,
01467 rb_gc_stack_start < addr))
01468 rb_gc_stack_start = addr;
01469 return;
01470 }
01471 rb_gc_stack_start = addr;
01472 #endif
01473 #ifdef HAVE_GETRLIMIT
01474 {
01475 struct rlimit rlim;
01476
01477 if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
01478 unsigned int space = rlim.rlim_cur/5;
01479
01480 if (space > 1024*1024) space = 1024*1024;
01481 STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE);
01482 }
01483 }
01484 #endif
01485 }
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511