[ruby-dev:14764] Re: [BUG] $_ on thread switching
From:
nobu.nakada@...
Date:
2001-09-09 18:22:04 UTC
List:
ruby-dev #14764
なかだです。
At Sat, 8 Sep 2001 23:14:51 +0900,
Nobuyoshi-Nakada wrote:
> 今やっぱりFRAMEに持ってこうというところがそもそも間違ってるよ
> うなので、むしろSCOPEのlocal_varsからスレッドローカル変数を独立
> させる方向で考えるべきかという気になってます。
SCOPEはObjectだからサイズを増やせないですね。一応なんとかうま
く行きそうな感じですが、かなり不安です。
# というか激しくでかすぎ。
(1) SCOPE#local_varsからFRAME#fvarsに関数スコープな変数を移動
(2) FRAME同士は、例外を除いてNODE_SCOPE単位でfvarsを共有する
(3) 例外として、rb_eval_string_wrap()、rb_eval_cmd()、load、
END{}、スレッド生成時には新しいfvarsを作る
Index: env.h
===================================================================
RCS file: /cvs/ruby/src/ruby/env.h,v
retrieving revision 1.7
diff -u -2 -p -u -r1.7 env.h
--- env.h 2001/02/14 05:51:57 1.7
+++ env.h 2001/09/09 17:28:55
@@ -14,8 +14,15 @@
#define ENV_H
+enum funcvar_type {
+ fvar_lastline,
+ fvar_backref,
+ funcvar_last
+};
+
extern struct FRAME {
VALUE self;
int argc;
VALUE *argv;
+ VALUE *fvars;
ID last_func;
VALUE last_class;
Index: eval.c
===================================================================
RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.203
diff -u -2 -p -u -r1.203 eval.c
--- eval.c 2001/09/08 14:17:09 1.203
+++ eval.c 2001/09/09 18:14:50
@@ -133,4 +133,14 @@ static VALUE safe_getter _((void));
static void safe_setter _((VALUE val));
+#define INIT_FVARS(fv) (fill_nil(fv, funcvar_last), (fv))
+
+static void
+fill_nil(v, i)
+ VALUE *v;
+ int i;
+{
+ do *v++ = Qnil; while (--i > 0);
+}
+
void
rb_secure(level)
@@ -520,4 +530,5 @@ static struct SCOPE *top_scope;
_frame.argc = 0; \
_frame.argv = 0; \
+ _frame.fvars = ruby_frame->fvars; \
_frame.flags = FRAME_ALLOCA; \
ruby_frame = &_frame; \
@@ -1009,4 +1020,5 @@ ruby_init()
static struct FRAME frame;
static struct iter iter;
+ static VALUE funcvars[funcvar_last];
int state;
@@ -1015,4 +1027,5 @@ ruby_init()
initialized = 1;
+ frame.fvars = INIT_FVARS(funcvars);
ruby_frame = top_frame = &frame;
ruby_iter = &iter;
@@ -1027,6 +1040,4 @@ ruby_init()
Init_heap();
PUSH_SCOPE();
- ruby_scope->local_vars = 0;
- ruby_scope->local_tbl = 0;
top_scope = ruby_scope;
/* default visibility is private at toplevel */
@@ -1272,4 +1283,5 @@ rb_eval_string_wrap(str, state)
VALUE wrapper = ruby_wrapper;
VALUE val;
+ VALUE funcvars[funcvar_last];
PUSH_CLASS();
@@ -1280,4 +1292,5 @@ rb_eval_string_wrap(str, state)
ruby_frame->last_func = 0;
ruby_frame->last_class = 0;
+ ruby_frame->fvars = INIT_FVARS(funcvars);
ruby_frame->self = self;
ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_wrapper,0,0);
@@ -1332,4 +1345,5 @@ rb_eval_cmd(cmd, arg)
int state;
VALUE val; /* OK */
+ VALUE funcvars[funcvar_last];
struct SCOPE *saved_scope;
volatile int safe = ruby_safe_level;
@@ -1345,4 +1359,5 @@ rb_eval_cmd(cmd, arg)
ruby_frame->last_func = 0;
ruby_frame->last_class = 0;
+ ruby_frame->fvars = INIT_FVARS(funcvars);
ruby_frame->self = ruby_top_self;
ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_wrapper,0,0);
@@ -1708,6 +1723,33 @@ copy_node_scope(node, rval)
POP_ITER();\
}
+
+#define LAST_LINE ruby_frame->fvars[fvar_lastline]
+#define MATCH_DATA ruby_frame->fvars[fvar_backref]
+
+VALUE
+rb_backref_get()
+{
+ return MATCH_DATA;
+}
+
+void
+rb_backref_set(val)
+ VALUE val;
+{
+ MATCH_DATA = val;
+}
-#define MATCH_DATA ruby_scope->local_vars[node->nd_cnt]
+VALUE
+rb_lastline_get()
+{
+ return LAST_LINE;
+}
+
+void
+rb_lastline_set(val)
+ VALUE val;
+{
+ LAST_LINE = val;
+}
static char* is_defined _((VALUE, NODE*, char*));
@@ -2660,7 +2702,9 @@ rb_eval(self, n)
struct FRAME frame;
NODE *saved_cref = 0;
+ VALUE funcvars[funcvar_last];
frame = *ruby_frame;
frame.tmp = ruby_frame;
+ frame.fvars = INIT_FVARS(funcvars);
ruby_frame = &frame;
@@ -4459,4 +4503,5 @@ rb_call0(klass, recv, id, argc, argv, bo
int state;
VALUE *local_vars; /* OK */
+ VALUE funcvars[funcvar_last];
NODE *saved_cref = 0;
@@ -4479,4 +4524,5 @@ rb_call0(klass, recv, id, argc, argv, bo
ruby_scope->local_tbl = 0;
}
+ ruby_frame->fvars = INIT_FVARS(funcvars);
b2 = body = body->nd_next;
@@ -4519,11 +4565,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;
@@ -5236,4 +5281,5 @@ rb_load(fname, wrap)
{
VALUE tmp;
+ VALUE funcvars[funcvar_last];
int state;
volatile ID last_func;
@@ -5277,4 +5323,5 @@ rb_load(fname, wrap)
ruby_frame->self = self;
ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_class,0,0);
+ ruby_frame->fvars = INIT_FVARS(funcvars);
PUSH_SCOPE();
/* default visibility is private at loading toplevel */
@@ -5852,5 +5899,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])));
@@ -5919,4 +5966,5 @@ call_end_proc(data)
VALUE data;
{
+ VALUE funcvars[funcvar_last];
PUSH_ITER(ITER_NOT);
PUSH_FRAME();
@@ -5924,4 +5972,5 @@ call_end_proc(data)
ruby_frame->last_func = 0;
ruby_frame->last_class = 0;
+ ruby_frame->fvars = INIT_FVARS(funcvars);
proc_call(data, rb_ary_new2(0));
POP_FRAME();
@@ -5932,6 +5981,8 @@ static void
rb_f_END()
{
+ VALUE funcvars[funcvar_last];
PUSH_FRAME();
ruby_frame->argc = 0;
+ ruby_frame->fvars = INIT_FVARS(funcvars);
rb_set_end_proc(call_end_proc, rb_f_lambda());
POP_FRAME();
@@ -7074,6 +7125,4 @@ struct thread {
VALUE errinfo;
VALUE last_status;
- VALUE last_line;
- VALUE last_match;
int safe;
@@ -7169,6 +7218,4 @@ thread_mark(th)
rb_gc_mark((VALUE)th->dyna_vars);
rb_gc_mark(th->errinfo);
- rb_gc_mark(th->last_line);
- rb_gc_mark(th->last_match);
rb_mark_tbl(th->locals);
@@ -7210,8 +7257,14 @@ rb_gc_mark_threads()
{
rb_thread_t th;
+ int i;
+ VALUE *p;
/* static global mark */
rb_gc_mark((VALUE)ruby_cref);
+ p = top_frame->fvars;
+ i = funcvar_last;
+ do {rb_gc_mark(*p++);} while (--i > 0);
+
if (!curr_thread) return;
FOREACH_THREAD(th) {
@@ -7296,10 +7349,4 @@ rb_thread_save_context(th)
th->errinfo = ruby_errinfo;
th->last_status = rb_last_status;
- tval = rb_lastline_get();
- rb_lastline_set(th->last_line);
- th->last_line = tval;
- tval = rb_backref_get();
- rb_backref_set(th->last_match);
- th->last_match = tval;
th->safe = ruby_safe_level;
@@ -7402,11 +7449,4 @@ rb_thread_restore_context(th, exit)
MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len);
- tval = rb_lastline_get();
- rb_lastline_set(tmp->last_line);
- tmp->last_line = tval;
- tval = rb_backref_get();
- rb_backref_set(tmp->last_match);
- tmp->last_match = tval;
-
longjmp(tmp->context, ex);
}
@@ -8211,6 +8251,4 @@ rb_thread_abort_exc_set(thread, val)
th->errinfo = Qnil;\
th->last_status = 0;\
- th->last_line = 0;\
- th->last_match = 0;\
th->abort = 0;\
th->priority = 0;\
@@ -8255,6 +8293,4 @@ int rb_thread_tick = THREAD_TICK;
#endif
-#define SCOPE_SHARED FL_USER1
-
#if defined(HAVE_SETITIMER)
static int thread_init = 0;
@@ -8322,5 +8358,4 @@ rb_thread_start_0(fn, arg, th_arg)
}
scope_dup(ruby_scope);
- FL_SET(ruby_scope, SCOPE_SHARED);
if (!th->next) {
@@ -8398,10 +8433,4 @@ rb_thread_create(fn, arg)
}
-int
-rb_thread_scope_shared_p()
-{
- return FL_TEST(ruby_scope, SCOPE_SHARED);
-}
-
static VALUE
rb_thread_yield(arg, th)
@@ -8409,4 +8438,6 @@ rb_thread_yield(arg, th)
rb_thread_t th;
{
+ VALUE funcvars[funcvar_last];
+ ruby_block->frame.fvars = INIT_FVARS(funcvars);
scope_dup(ruby_block->scope);
return rb_yield_0(mvalue_to_svalue(arg), 0, 0, Qtrue);
Index: intern.h
===================================================================
RCS file: /cvs/ruby/src/ruby/intern.h,v
retrieving revision 1.64
diff -u -2 -p -u -r1.64 intern.h
--- intern.h 2001/09/05 22:31:07 1.64
+++ intern.h 2001/09/09 15:39:32
@@ -134,4 +134,8 @@ VALUE rb_dvar_ref _((ID));
void rb_dvar_asgn _((ID, VALUE));
void rb_dvar_push _((ID, VALUE));
+VALUE rb_backref_get _((void));
+void rb_backref_set _((VALUE));
+VALUE rb_lastline_get _((void));
+void rb_lastline_set _((VALUE));
VALUE rb_eval_cmd _((VALUE, VALUE));
int rb_respond_to _((VALUE, ID));
@@ -171,5 +175,4 @@ VALUE rb_thread_wakeup _((VALUE));
VALUE rb_thread_run _((VALUE));
VALUE rb_thread_create _((VALUE (*)(ANYARGS), void*));
-int rb_thread_scope_shared_p _((void));
void rb_thread_interrupt _((void));
void rb_thread_trap_eval _((VALUE, int));
@@ -270,8 +273,4 @@ int rb_is_const_id _((ID));
int rb_is_instance_id _((ID));
int rb_is_class_id _((ID));
-VALUE rb_backref_get _((void));
-void rb_backref_set _((VALUE));
-VALUE rb_lastline_get _((void));
-void rb_lastline_set _((VALUE));
VALUE rb_sym_all_symbols _((void));
/* process.c */
Index: parse.y
===================================================================
RCS file: /cvs/ruby/src/ruby/parse.y,v
retrieving revision 1.119
diff -u -2 -p -u -r1.119 parse.y
--- parse.y 2001/09/05 06:54:53 1.119
+++ parse.y 2001/09/08 07:41:51
@@ -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;
}
@@ -5162,58 +5151,3 @@ rb_is_instance_id(id)
if (is_instance_id(id)) return Qtrue;
return Qfalse;
-}
-
-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;
-}
-
-void
-rb_backref_set(val)
- VALUE val;
-{
- if (ruby_scope->local_vars) {
- ruby_scope->local_vars[1] = val;
- }
- else {
- special_local_set('~', val);
- }
-}
-
-VALUE
-rb_lastline_get()
-{
- if (ruby_scope->local_vars) {
- return ruby_scope->local_vars[0];
- }
- return Qnil;
-}
-
-void
-rb_lastline_set(val)
- VALUE val;
-{
- if (ruby_scope->local_vars) {
- ruby_scope->local_vars[0] = val;
- }
- else {
- special_local_set('_', val);
- }
}
Index: re.c
===================================================================
RCS file: /cvs/ruby/src/ruby/re.c,v
retrieving revision 1.45
diff -u -2 -p -u -r1.45 re.c
--- re.c 2001/09/05 06:54:53 1.45
+++ re.c 2001/09/09 15:38:10
@@ -646,10 +646,5 @@ rb_reg_search(re, str, pos, reverse)
}
- if (rb_thread_scope_shared_p()) {
- match = Qnil;
- }
- else {
- match = rb_backref_get();
- }
+ match = rb_backref_get();
if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) {
match = match_alloc();
--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦