From c0fe73989d3027f0d7c196d01951ece6d112d98b Mon Sep 17 00:00:00 2001 From: matz Date: Wed, 31 Oct 2001 06:53:22 +0000 Subject: * eval.c (POP_VARS): should not set DVAR_DONT_RECYCLE if _old ruby_vars is already force_recycled. * gc.c (rb_gc): handles mark stack overflow. * gc.c (PUSH_MARK): use static mark stack, no more recursion. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1807 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 11 ++++ config.sub | 2 +- eval.c | 16 ++--- gc.c | 200 ++++++++++++++++++++++++++++++++++++++++++++----------------- string.c | 3 +- version.h | 4 +- 6 files changed, 169 insertions(+), 67 deletions(-) diff --git a/ChangeLog b/ChangeLog index 13e9b2bbb7..0205c6cb29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Wed Oct 31 15:09:28 2001 Yukihiro Matsumoto + + * eval.c (POP_VARS): should not set DVAR_DONT_RECYCLE if _old + ruby_vars is already force_recycled. + +Wed Oct 31 10:28:49 2001 Yukihiro Matsumoto + + * gc.c (rb_gc): handles mark stack overflow. + + * gc.c (PUSH_MARK): use static mark stack, no more recursion. + Wed Oct 31 02:44:06 2001 Wakou Aoyama * lib/cgi.rb: CGI::Cookie::parse(): Ignore duplicate keys caused by diff --git a/config.sub b/config.sub index 0387ee530f..a2d8b0d596 100644 --- a/config.sub +++ b/config.sub @@ -117,7 +117,7 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*) + nto-qnx* | linux-gnu* | linux-libc1 | storm-chaos* | os2-emx*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; diff --git a/eval.c b/eval.c index e270209268..bea650cc56 100644 --- a/eval.c +++ b/eval.c @@ -594,15 +594,17 @@ new_blktag() } struct RVarmap *ruby_dyna_vars; -#define PUSH_VARS() { \ - struct RVarmap * volatile _old; \ - _old = ruby_dyna_vars; \ +#define PUSH_VARS() { \ + struct RVarmap * volatile _old; \ + _old = ruby_dyna_vars; \ ruby_dyna_vars = 0; -#define POP_VARS() \ - if (_old && (ruby_scope->flags & SCOPE_DONT_RECYCLE)) \ - FL_SET(_old, DVAR_DONT_RECYCLE); \ - ruby_dyna_vars = _old; \ +#define POP_VARS() \ + if (_old && (ruby_scope->flags & SCOPE_DONT_RECYCLE)) {\ + if (RBASIC(_old)->flags) /* unless it's already recycled */ \ + FL_SET(_old, DVAR_DONT_RECYCLE); \ + }\ + ruby_dyna_vars = _old; \ } #define DVAR_DONT_RECYCLE FL_USER2 diff --git a/gc.c b/gc.c index c3e62fdf35..c555f511e0 100644 --- a/gc.c +++ b/gc.c @@ -135,7 +135,7 @@ ruby_xrealloc(ptr, size) rb_gc(); RUBY_CRITICAL(mem = realloc(ptr, size)); if (!mem) { - if (size >= 50 * 1024 * 1024) { + if (size >= 10 * 1024 * 1024) { rb_raise(rb_eNoMemError, "tried to re-allocate too big memory"); } mem_error("failed to allocate memory(realloc)"); @@ -182,7 +182,7 @@ VALUE rb_mGC; static struct gc_list { VALUE *varptr; struct gc_list *next; -} *Global_List = 0; +} *global_List = 0; void rb_gc_register_address(addr) @@ -191,19 +191,19 @@ rb_gc_register_address(addr) struct gc_list *tmp; tmp = ALLOC(struct gc_list); - tmp->next = Global_List; + tmp->next = global_List; tmp->varptr = addr; - Global_List = tmp; + global_List = tmp; } void rb_gc_unregister_address(addr) VALUE *addr; { - struct gc_list *tmp = Global_List; + struct gc_list *tmp = global_List; if (tmp->varptr == addr) { - Global_List = tmp->next; + global_List = tmp->next; RUBY_CRITICAL(free(tmp)); return; } @@ -249,6 +249,7 @@ typedef struct RVALUE { struct RVarmap varmap; struct SCOPE scope; } as; + int type; } RVALUE; static RVALUE *freelist = 0; @@ -301,7 +302,7 @@ add_heap() if (lomem == 0 || lomem > p) lomem = p; if (himem < pend) himem = pend; heaps_used++; - heap_slots *= 2; + heap_slots *= 1.5; while (p < pend) { p->as.free.flags = 0; @@ -364,6 +365,33 @@ is_pointer_to_heap(ptr) return Qfalse; } +#define MARK_STACK_SIZE 4096 +static VALUE mark_stack_base[MARK_STACK_SIZE]; +static VALUE *mark_stack; +static int mark_stack_overflow = 0; + +#define PUSH_MARK(obj) do {\ + if (!mark_stack_overflow) {\ + if (mark_stack - mark_stack_base >= MARK_STACK_SIZE) {\ + mark_stack_overflow = 1;\ +printf("mark stack overflow\n");\ + }\ + else {\ + if ( rb_special_const_p(obj) /* special const not marked */\ + || RBASIC(obj)->flags == 0 /* free cell */\ + || FL_TEST((obj),FL_MARK)) /* already marked */ {\ + }\ + else {\ + *mark_stack++ = (obj);\ + }\ + }\ + }\ +} while (0) + +#define POP_MARK() (*--mark_stack) + +#define MARK_EMPTY() (mark_stack == mark_stack_base) + static void mark_locations_array(x, n) register VALUE *x; @@ -437,19 +465,14 @@ rb_gc_mark_maybe(obj) } } -void -rb_gc_mark(ptr) +static void +gc_mark_children(ptr) VALUE ptr; { register RVALUE *obj = RANY(ptr); Top: - if (rb_special_const_p((VALUE)obj)) return; /* special const not marked */ - if (obj->as.basic.flags == 0) return; /* free cell */ - if (obj->as.basic.flags & FL_MARK) return; /* already marked */ - obj->as.basic.flags |= FL_MARK; - if (FL_TEST(obj, FL_EXIVAR)) { rb_mark_generic_ivar((VALUE)obj); } @@ -470,7 +493,7 @@ rb_gc_mark(ptr) case NODE_MASGN: case NODE_RESCUE: case NODE_RESBODY: - rb_gc_mark((VALUE)obj->as.node.u2.node); + PUSH_MARK((VALUE)obj->as.node.u2.node); /* fall through */ case NODE_BLOCK: /* 1,3 */ case NODE_ARRAY: @@ -484,14 +507,14 @@ rb_gc_mark(ptr) case NODE_CALL: case NODE_DEFS: case NODE_OP_ASGN1: - rb_gc_mark((VALUE)obj->as.node.u1.node); + PUSH_MARK((VALUE)obj->as.node.u1.node); /* fall through */ case NODE_SUPER: /* 3 */ case NODE_FCALL: case NODE_DEFN: case NODE_NEWLINE: obj = RANY(obj->as.node.u3.node); - goto Top; + goto Again; case NODE_WHILE: /* 1,2 */ case NODE_UNTIL: @@ -507,7 +530,7 @@ rb_gc_mark(ptr) case NODE_MATCH3: case NODE_OP_ASGN_OR: case NODE_OP_ASGN_AND: - rb_gc_mark((VALUE)obj->as.node.u1.node); + PUSH_MARK((VALUE)obj->as.node.u1.node); /* fall through */ case NODE_METHOD: /* 2 */ case NODE_NOT: @@ -523,7 +546,7 @@ rb_gc_mark(ptr) case NODE_COLON3: case NODE_OPT_N: obj = RANY(obj->as.node.u2.node); - goto Top; + goto Again; case NODE_HASH: /* 1 */ case NODE_LIT: @@ -538,14 +561,14 @@ rb_gc_mark(ptr) case NODE_COLON2: case NODE_ARGS: obj = RANY(obj->as.node.u1.node); - goto Top; + goto Again; case NODE_SCOPE: /* 2,3 */ case NODE_CLASS: case NODE_BLOCK_PASS: - rb_gc_mark((VALUE)obj->as.node.u3.node); + PUSH_MARK((VALUE)obj->as.node.u3.node); obj = RANY(obj->as.node.u2.node); - goto Top; + goto Again; case NODE_ZARRAY: /* - */ case NODE_ZSUPER: @@ -577,53 +600,59 @@ rb_gc_mark(ptr) mark_locations_array((VALUE*)obj->as.node.u1.value, obj->as.node.u3.cnt); obj = RANY(obj->as.node.u2.node); - goto Top; + goto Again; #endif default: if (is_pointer_to_heap(obj->as.node.u1.node)) { - rb_gc_mark((VALUE)obj->as.node.u1.node); + PUSH_MARK((VALUE)obj->as.node.u1.node); } if (is_pointer_to_heap(obj->as.node.u2.node)) { - rb_gc_mark((VALUE)obj->as.node.u2.node); + PUSH_MARK((VALUE)obj->as.node.u2.node); } if (is_pointer_to_heap(obj->as.node.u3.node)) { obj = RANY(obj->as.node.u3.node); - goto Top; + goto Again; } } return; /* no need to mark class. */ } - rb_gc_mark(obj->as.basic.klass); + PUSH_MARK(obj->as.basic.klass); switch (obj->as.basic.flags & T_MASK) { case T_ICLASS: case T_CLASS: case T_MODULE: - rb_gc_mark(obj->as.klass.super); + PUSH_MARK(obj->as.klass.super); rb_mark_tbl(obj->as.klass.m_tbl); rb_mark_tbl(obj->as.klass.iv_tbl); break; case T_ARRAY: - { - int i, len = obj->as.array.len; - VALUE *ptr = obj->as.array.ptr; - - for (i=0; i < len; i++) - rb_gc_mark(*ptr++); - } - break; + { + int i, len = obj->as.array.len - 1; + VALUE *ptr = obj->as.array.ptr; + + for (i=0; i < len; i++) { + PUSH_MARK(*ptr); + ptr++; + } + if (len >= 0) { + obj = RANY(*ptr); + goto Again; + } + } + break; case T_HASH: rb_mark_hash(obj->as.hash.tbl); - rb_gc_mark(obj->as.hash.ifnone); + PUSH_MARK(obj->as.hash.ifnone); break; case T_STRING: if (obj->as.string.orig) { obj = RANY(obj->as.string.orig); - goto Top; + goto Again; } break; @@ -645,14 +674,14 @@ rb_gc_mark(ptr) case T_MATCH: if (obj->as.match.str) { obj = RANY(obj->as.match.str); - goto Top; + goto Again; } break; case T_VARMAP: - rb_gc_mark(obj->as.varmap.val); + PUSH_MARK(obj->as.varmap.val); obj = RANY(obj->as.varmap.next); - goto Top; + goto Again; break; case T_SCOPE: @@ -661,27 +690,58 @@ rb_gc_mark(ptr) VALUE *vars = &obj->as.scope.local_vars[-1]; while (n--) { - rb_gc_mark(*vars); + PUSH_MARK(*vars); vars++; } } break; case T_STRUCT: - { - int i, len = obj->as.rstruct.len; - VALUE *ptr = obj->as.rstruct.ptr; - - for (i=0; i < len; i++) - rb_gc_mark(*ptr++); - } - break; + { + int i, len = obj->as.rstruct.len - 1; + VALUE *ptr = obj->as.rstruct.ptr; + + for (i=0; i < len; i++) { + PUSH_MARK(*ptr); + ptr++; + } + if (len >= 0) { + obj = RANY(ptr); + goto Again; + } + } + break; default: rb_bug("rb_gc_mark(): unknown data type 0x%x(0x%x) %s", obj->as.basic.flags & T_MASK, obj, is_pointer_to_heap(obj)?"corrupted object":"non object"); } + return; + + Again: + if (rb_special_const_p(obj)) return; /* special const not marked */ + if (RBASIC(obj)->flags == 0) return; /* free cell */ + if (FL_TEST((obj),FL_MARK)) return; /* already marked */ + goto Top; +} + +void +rb_gc_mark(ptr) + VALUE ptr; +{ + if (rb_special_const_p(ptr)) return; /* special const not marked */ + if (RBASIC(ptr)->flags == 0) return; /* free cell */ + if (FL_TEST((ptr),FL_MARK)) return; /* already marked */ + gc_mark_children(ptr); +} + +static void +gc_mark() +{ + while (!MARK_EMPTY()) { + rb_gc_mark(POP_MARK()); + } } static void obj_free _((VALUE)); @@ -691,24 +751,31 @@ gc_sweep() { RVALUE *p, *pend, *final_list; int freed = 0; - int i, used = heaps_used; + int i; if (ruby_in_compile) { + int marked = 0; + /* should not reclaim nodes during compilation */ - for (i = 0; i < used; i++) { + for (i = 0; i < heaps_used; i++) { p = heaps[i]; pend = p + heaps_limits[i]; while (p < pend) { - if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE) + if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE) { rb_gc_mark((VALUE)p); + marked = 1; + } p++; } } + if (marked) { + gc_mark(); + } } freelist = 0; final_list = deferred_final_list; deferred_final_list = 0; - for (i = 0; i < used; i++) { + for (i = 0; i < heaps_used; i++) { int n = 0; p = heaps[i]; pend = p + heaps_limits[i]; @@ -768,6 +835,7 @@ void rb_gc_force_recycle(p) VALUE p; { + RANY(p)->type = BUILTIN_TYPE(p); RANY(p)->as.free.flags = 0; RANY(p)->as.free.next = freelist; freelist = RANY(p); @@ -897,7 +965,7 @@ obj_free(obj) break; default: - rb_bug("gc_sweep(): unknown data type %d", + rb_bug("gc_sweep(): unknown data type 0x%x(%d)", obj, RANY(obj)->as.basic.flags & T_MASK); } } @@ -980,6 +1048,8 @@ rb_gc() if (during_gc) return; during_gc++; + mark_stack = mark_stack_base; + mark_stack_overflow = 0; /* mark frame stack */ for (frame = ruby_frame; frame; frame = frame->prev) { rb_gc_mark_frame(frame); @@ -1010,7 +1080,7 @@ rb_gc() rb_gc_mark_threads(); /* mark protected global variables */ - for (list = Global_List; list; list = list->next) { + for (list = global_List; list; list = list->next) { rb_gc_mark(*list->varptr); } rb_mark_end_proc(); @@ -1022,6 +1092,24 @@ rb_gc() /* mark generic instance variables for special constants */ rb_mark_generic_ivar_tbl(); + gc_mark(); + while (mark_stack_overflow) { + RVALUE *p, *pend; + int i; + + mark_stack_overflow = 0; + for (i = 0; i < heaps_used; i++) { + p = heaps[i]; pend = p + heaps_limits[i]; + while (p < pend) { + if (p->as.basic.flags&FL_MARK) { + gc_mark_children((VALUE)p); + } + p++; + } + } + gc_mark(); + } + gc_sweep(); } diff --git a/string.c b/string.c index c57ebb5a5b..3981e54d01 100644 --- a/string.c +++ b/string.c @@ -1101,7 +1101,8 @@ rb_str_aref(str, indx) return rb_str_subpat(str, indx, 0); case T_STRING: - if (rb_str_index(str, indx, 0) != -1) return indx; + if (rb_str_index(str, indx, 0) != -1) + return rb_str_dup(indx); return Qnil; default: diff --git a/version.h b/version.h index 93a7ff5975..52d381d790 100644 --- a/version.h +++ b/version.h @@ -1,4 +1,4 @@ #define RUBY_VERSION "1.7.1" -#define RUBY_RELEASE_DATE "2001-10-30" +#define RUBY_RELEASE_DATE "2001-10-31" #define RUBY_VERSION_CODE 171 -#define RUBY_RELEASE_CODE 20011030 +#define RUBY_RELEASE_CODE 20011031 -- cgit v1.2.3