From: nobu.nakada@... Date: 2002-02-15T11:58:06+09:00 Subject: [ruby-dev:15889] Re: GC after load なかだです。 At Sun, 3 Feb 2002 18:21:06 +0900, Minero Aoki wrote: > > |ところでずっと疑問だったんですが、そもそもコンパイル中にノードを > > |GC できないのってどうしてですか? yacc のスタックをマークできる > > |保証がないからでしょうか? 他の理由もあります? > > > > いや、それだけです。bisonならマシンスタックを使うのですけど、 > > 正統yaccは配列にスタックを取るので。 > > ということは、alloca とそれを使う bison がある環境ならば NODE を > GC してもいいし、結果として load_file の rb_gc() も外せるんですね。 > でも条件の検出がちょっと難しいでしょうか。 #if defined(YYBISON) && defined(YYSTACK_USE_ALLOCA) ならalloca()が使われます。 あるいは、parse.yのmalloc()とかを置き換えてマークするとか。 Index: gc.c =================================================================== RCS file: /cvs/ruby/src/ruby/gc.c,v retrieving revision 1.87 diff -u -2 -p -r1.87 gc.c --- gc.c 2002/02/13 09:01:09 1.87 +++ gc.c 2002/02/15 02:12:23 @@ -830,4 +830,28 @@ static void obj_free _((VALUE)); static void +finalize_list(p) + RVALUE *p; +{ + while (p) { + RVALUE *tmp = p->as.free.next; + run_final((VALUE)p); + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; + p = tmp; + } +} + +void +rb_gc_finalize_deferred() +{ + RVALUE *p; + while (p = deferred_final_list) { + deferred_final_list = 0; + finalize_list(p); + } +} + +static void gc_sweep() { @@ -837,13 +861,5 @@ gc_sweep() if (ruby_in_compile) { - /* should not reclaim nodes during compilation */ - for (i = 0; i < 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) - rb_gc_mark((VALUE)p); - p++; - } - } + rb_gc_mark_parser(); } @@ -890,17 +906,9 @@ gc_sweep() /* clear finalization list */ if (final_list) { - RVALUE *tmp; - if (rb_prohibit_interrupt || ruby_in_compile) { deferred_final_list = final_list; - return; } - - for (p = final_list; p; p = tmp) { - tmp = p->as.free.next; - run_final((VALUE)p); - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + else { + finalize_list(final_list); } } @@ -1420,12 +1428,6 @@ rb_gc_call_finalizer_at_exit() /* run finalizers */ if (need_call_final) { - if (deferred_final_list) { - p = deferred_final_list; - while (p) { - RVALUE *tmp = p; - p = p->as.free.next; - run_final((VALUE)tmp); - } - } + finalize_list(deferred_final_list); + for (i = 0; i < heaps_used; i++) { p = heaps[i]; pend = p + heaps_limits[i]; Index: intern.h =================================================================== RCS file: /cvs/ruby/src/ruby/intern.h,v retrieving revision 1.79 diff -u -2 -p -r1.79 intern.h --- intern.h 2002/02/13 09:01:09 1.79 +++ intern.h 2002/02/15 02:57:09 @@ -202,4 +202,5 @@ void rb_gc_mark_locations _((VALUE*, VAL void rb_mark_tbl _((struct st_table*)); void rb_mark_hash _((struct st_table*)); +void rb_gc_finalize_deferred _((void)); void rb_gc_mark_maybe _((VALUE)); void rb_gc_mark _((VALUE)); @@ -280,4 +281,5 @@ EXTERN char *ruby_sourcefile; #define yydebug ruby_yydebug int yyparse _((void)); +void rb_gc_mark_parser _((void)); ID rb_id_attrset _((ID)); void rb_parser_append_print _((void)); Index: parse.y =================================================================== RCS file: /cvs/ruby/src/ruby/parse.y,v retrieving revision 1.153 diff -u -2 -p -r1.153 parse.y --- parse.y 2002/02/14 08:47:58 1.153 +++ parse.y 2002/02/15 02:53:29 @@ -149,4 +154,15 @@ static void top_local_init(); static void top_local_setup(); +#if !(defined YYBISON && defined HAVE_ALLOCA) +static inline void *parser_malloc _((int)); +static inline void *parser_calloc _((int)); +static inline void *parser_realloc _((void *, int)); +static inline void parser_free _((void *)); +#define malloc(size) parser_malloc(size) +#define calloc(size) parser_calloc(size) +#define realloc(ptr, size) parser_realloc(ptr, size) +#define free(ptr) parser_free(ptr) +#endif + %} @@ -2115,4 +2126,114 @@ int ruby__end__seen; static VALUE ruby_debug_lines; +#if !(defined YYBISON && defined HAVE_ALLOCA) +#undef malloc +#undef calloc +#undef realloc +#undef free + +static struct { + VALUE **ptr; + int count; +} stacks; + +static void ** +stack_holder(ptr) + void *ptr; +{ + int i; + if (!stacks.ptr) { + stacks.count = 4; + stacks.ptr = ALLOC_N(VALUE*, stacks.count); + MEMZERO(stacks.ptr, VALUE*, stacks.count); + return stacks.ptr; + } + for (i = 0; i < stacks.count; ++i) { + if (stacks.ptr[i] == ptr) return &stacks.ptr[i]; + } + if (ptr) { + for (i = 0; i < stacks.count; ++i) { + if (!stacks.ptr[i]) return &stacks.ptr[i]; + } + } + i = stacks.count << 1; + REALLOC_N(stacks.ptr, VALUE*, i); + MEMZERO(stacks.ptr + stacks.count, VALUE*, i - stacks.count); + stacks.count = i; + return &stacks.ptr[i]; +} + +static void *inline +parser_malloc(size) + int size; +{ +#if defined YYBISON && defined YYSTACK_USE_ALLOCA + return malloc(size); +#else + void **holder = stack_holder(0); + VALUE *p = xmalloc(size + sizeof(VALUE)); + *holder = p; + *p = size; + return p + 1; +#endif +} + +static void *inline +parser_calloc(size) + int size; +{ +#if defined YYBISON && defined YYSTACK_USE_ALLOCA + return calloc(size); +#else + void *p = parser_malloc(size); + memset(p, 0, size); + return p; +#endif +} + +static void *inline +parser_realloc(ptr, size) + void *ptr; + int size; +{ +#if defined YYBISON && defined YYSTACK_USE_ALLOCA + return realloc(ptr, size); +#else + void **holder = stack_holder(ptr); + VALUE *p = xrealloc(ptr, size + sizeof(VALUE)); + *holder = p; + *p = size; + return p + 1; +#endif +} + +static void inline +parser_free(ptr) + void *ptr; +{ +#if !(defined YYBISON && defined YYSTACK_USE_ALLOCA) + *stack_holder(ptr) = 0; +#endif + free(ptr); +} +#endif + +void +rb_gc_mark_parser() +{ +#if defined YYBISON && defined HAVE_ALLOCA + if (!ruby_in_compile) return; + rb_gc_mark_maybe(yylval.val); +#else + int i; + if (!ruby_in_compile || !stacks.ptr) return; + rb_gc_mark_maybe(yylval.val); + for (i = 0; i < stacks.count; ++i) { + VALUE *p = stacks.ptr[i]; + if (!p || !*p) continue; + rb_gc_mark_locations(p + 1, (char *)p + *p); + } +#endif +} + static NODE* yycompile(f, line) @@ -2162,4 +2283,6 @@ yycompile(f, line) cur_mid = 0; + rb_gc_finalize_deferred(); + if (n == 0) node = ruby_eval_tree; return node; Index: ruby.c =================================================================== RCS file: /cvs/ruby/src/ruby/ruby.c,v retrieving revision 1.56 diff -u -2 -p -r1.56 ruby.c --- ruby.c 2002/02/10 07:55:40 1.56 +++ ruby.c 2002/02/15 02:31:33 @@ -857,5 +857,4 @@ load_file(fname, script) rb_io_close(f); } - rb_gc(); } -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦