なかだです。

At Sat, 8 Sep 2001 04:39:07 +0900,
matz / ruby-lang.org (Yukihiro Matsumoto) wrote:
> その後、歯磨きしながら考えてたら、以下のパッチで直りそうです。
> 駆け込みでやや不安なのですが。

 残念ながら完全ではないようです。子スレッドから関数を読んだ中
でスイッチすると、元の$_には書き戻せません。

$ cat bug.rb
def foo(t)
  p [:foo, $_ = "foo", Thread.current]
  t.run
end

p [:main, $_ = "main", Thread.current]

t = Thread.new do
  p [:sub, $_ = "sub", Thread.current]
  Thread.stop
  foo(Thread.main)
end
foo(t)
Thread.stop
p [:main, $_, Thread.current]

$ ./miniruby bug.rb
[:main, "main", #<Thread:0x401e1140 run>]
[:sub, "sub", #<Thread:0x401d79ec run>]
[:foo, "foo", #<Thread:0x401e1140 run>]
[:foo, "foo", #<Thread:0x401d79ec run>]
[:main, "sub", #<Thread:0x401e1140 run>]

 一応[ruby-dev:14747]で書いた案のパッチをつけます。これもやっ
ぱり完全ではなくて、make testでエラーが出るんですが、どこから出
てるのがよく分かりません。

$ make test
-e:1:in `sub': $_ value need to be String (nil given) (TypeError)
        from -e:1
test succeeded


Index: env.h =================================================================== RCS file: /cvs/ruby/src/ruby/env.h,v retrieving revision 1.7 diff -u -2 -p -r1.7 env.h --- env.h 2001/02/14 05:51:57 1.7 +++ env.h 2001/09/07 19:42:33 @@ -14,8 +14,15 @@ #define ENV_H +enum framevar_type { + fvar_lastline, + fvar_backref, + framevar_last +}; + extern struct FRAME { VALUE self; int argc; VALUE *argv; + VALUE fvars[framevar_last]; ID last_func; VALUE last_class; Index: eval.c =================================================================== RCS file: /cvs/ruby/src/ruby/eval.c,v retrieving revision 1.202 diff -u -2 -p -r1.202 eval.c --- eval.c 2001/09/03 05:37:42 1.202 +++ eval.c 2001/09/07 20:34:13 @@ -510,4 +510,8 @@ static struct FRAME *top_frame; static struct SCOPE *top_scope; +#define INIT_FVARS(f) { \ + (f)->fvars[fvar_lastline] = Qnil; \ + (f)->fvars[fvar_backref] = Qnil; \ +} #define PUSH_FRAME() { \ struct FRAME _frame; \ @@ -520,4 +524,5 @@ static struct SCOPE *top_scope; _frame.argc = 0; \ _frame.argv = 0; \ + INIT_FVARS(&_frame); \ _frame.flags = FRAME_ALLOCA; \ ruby_frame = &_frame; \ @@ -1041,4 +1046,5 @@ ruby_init() ruby_cref = top_cref; ruby_frame->cbase = (VALUE)ruby_cref; + INIT_FVARS(ruby_frame); rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self)); #ifdef __MACOS__ @@ -1709,5 +1715,5 @@ copy_node_scope(node, rval) } -#define MATCH_DATA ruby_scope->local_vars[node->nd_cnt] +#define MATCH_DATA ruby_frame->fvars[fvar_backref] static char* is_defined _((VALUE, NODE*, char*)); @@ -4519,11 +4525,10 @@ rb_call0(klass, recv, id, argc, argv, bo } ruby_frame->argc = opt; - ruby_frame->argv = local_vars+2; + ruby_frame->argv = local_vars; } if (local_vars) { if (i > 0) { - /* +2 for $_ and $~ */ - MEMCPY(local_vars+2, argv, VALUE, i); + MEMCPY(local_vars, argv, VALUE, i); } argv += i; argc -= i; @@ -5852,5 +5857,5 @@ rb_f_local_variables() if (tbl) { n = *tbl++; - for (i=2; i<n; i++) { /* skip first 2 ($_ and $~) */ + for (i=0; i<n; i++) { if (tbl[i] == 0) continue; /* skip flip states */ rb_ary_push(ary, rb_str_new2(rb_id2name(tbl[i]))); Index: gc.c =================================================================== RCS file: /cvs/ruby/src/ruby/gc.c,v retrieving revision 1.72 diff -u -2 -p -r1.72 gc.c --- gc.c 2001/07/20 15:19:28 1.72 +++ gc.c 2001/09/07 20:08:15 @@ -908,4 +908,5 @@ rb_gc_mark_frame(frame) { mark_locations_array(frame->argv, frame->argc); + mark_locations_array(frame->fvars, framevar_last); rb_gc_mark(frame->cbase); } Index: parse.y =================================================================== RCS file: /cvs/ruby/src/ruby/parse.y,v retrieving revision 1.119 diff -u -2 -p -r1.119 parse.y --- parse.y 2001/09/05 06:54:53 1.119 +++ parse.y 2001/09/07 20:29:54 @@ -3587,5 +3587,4 @@ yylex() /* fall through */ case '~': /* $~: match-data */ - local_cnt(c); /* fall through */ case '*': /* $*: argv */ @@ -4122,6 +4121,4 @@ match_gen(node1, node2) NODE *node2; { - local_cnt('~'); - switch (nd_type(node1)) { case NODE_DREGX: @@ -4612,6 +4609,4 @@ cond0(node) case NODE_DREGX_ONCE: warning_unless_e_option("regex literal in condition"); - local_cnt('_'); - local_cnt('~'); return NEW_MATCH2(node, NEW_GVAR(rb_intern("$_"))); @@ -4636,6 +4631,4 @@ cond0(node) warn_unless_e_option("regex literal in condition"); nd_set_type(node, NODE_MATCH); - local_cnt('_'); - local_cnt('~'); } else { @@ -4795,11 +4788,7 @@ local_append(id) { if (lvtbl->tbl == 0) { - lvtbl->tbl = ALLOC_N(ID, 4); + lvtbl->tbl = ALLOC_N(ID, 2); lvtbl->tbl[0] = 0; - lvtbl->tbl[1] = '_'; - lvtbl->tbl[2] = '~'; - lvtbl->cnt = 2; - if (id == '_') return 0; - if (id == '~') return 1; + lvtbl->cnt = 0; } else { @@ -4832,5 +4821,5 @@ local_id(id) if (lvtbl == 0) return Qfalse; - for (i=3, max=lvtbl->cnt+1; i<max; i++) { + for (i=1, max=lvtbl->cnt+1; i<max; i++) { if (lvtbl->tbl[i] == id) return Qtrue; } @@ -5164,24 +5153,8 @@ rb_is_instance_id(id) } -static void -special_local_set(c, val) - char c; - VALUE val; -{ - int cnt; - - top_local_init(); - cnt = local_cnt(c); - top_local_setup(); - ruby_scope->local_vars[cnt] = val; -} - VALUE rb_backref_get() { - if (ruby_scope->local_vars) { - return ruby_scope->local_vars[1]; - } - return Qnil; + return ruby_frame->fvars[fvar_backref]; } @@ -5190,10 +5163,5 @@ rb_backref_set(val) VALUE val; { - if (ruby_scope->local_vars) { - ruby_scope->local_vars[1] = val; - } - else { - special_local_set('~', val); - } + ruby_frame->fvars[fvar_backref] = val; } @@ -5201,8 +5169,5 @@ VALUE rb_lastline_get() { - if (ruby_scope->local_vars) { - return ruby_scope->local_vars[0]; - } - return Qnil; + return ruby_frame->fvars[fvar_lastline]; } @@ -5211,9 +5176,4 @@ rb_lastline_set(val) VALUE val; { - if (ruby_scope->local_vars) { - ruby_scope->local_vars[0] = val; - } - else { - special_local_set('_', val); - } + ruby_frame->fvars[fvar_lastline] = val; }
-- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦