[ruby-dev:14971] Re: alias var and trace_var
From:
"K.Kosako" <kosako@...>
Date:
2001-10-22 04:17:56 UTC
List:
ruby-dev #14971
nobu.nakada@nifty.ne.jpさんの
<200110191357.f9JDv3k23792@sharui.nakada.kanuma.tochigi.jp>から
> > 個人的にはトレースに漏れがあり得るということに
> > 違和感があります。
>
> 一応やってみました。global_entryを分割してますが、おそらくこ
> れが一番確実だと思います。1.48のようにgetter/setterをいじくる方
> 向では、これ以上は無理があるでしょう。
いいですね。
トレースのことは別にしても、こちらのほうがプログラムが
わかり易いので好きです。
仕様としては、トレース情報も共有するので、
alias $a $bを行うと、$aのトレース指定は、$bのトレース指定と
同じになるということですね。
ただ、global_variable構造体のメモリ開放漏れがあるようなので、
中田さんの修正の上に、参照カウンタを追加してみました。
(これも1.47からの差分です。)
--- variable.c.1.47 Mon Oct 22 11:13:32 2001
+++ variable.c Mon Oct 22 12:57:04 2001
@@ -291,8 +291,8 @@
struct trace_var *next;
};
-struct global_entry {
- ID id;
+struct global_variable {
+ int counter;
void *data;
VALUE (*getter)();
void (*setter)();
@@ -301,6 +301,11 @@
struct trace_var *trace;
};
+struct global_entry {
+ struct global_variable *var;
+ ID id;
+};
+
static VALUE undef_getter();
static void undef_setter();
static void undef_marker();
@@ -320,16 +325,20 @@
struct global_entry *entry;
if (!st_lookup(rb_global_tbl, id, &entry)) {
+ struct global_variable *var;
entry = ALLOC(struct global_entry);
st_add_direct(rb_global_tbl, id, entry);
+ var = ALLOC(struct global_variable);
entry->id = id;
- entry->data = 0;
- entry->getter = undef_getter;
- entry->setter = undef_setter;
- entry->marker = undef_marker;
+ entry->var = var;
+ var->counter = 1;
+ var->data = 0;
+ var->getter = undef_getter;
+ var->setter = undef_setter;
+ var->marker = undef_marker;
- entry->block_trace = 0;
- entry->trace = 0;
+ var->block_trace = 0;
+ var->trace = 0;
}
return entry;
}
@@ -345,17 +354,17 @@
}
static void
-undef_setter(val, id, data, entry)
+undef_setter(val, id, data, var)
VALUE val;
ID id;
void *data;
- struct global_entry *entry;
+ struct global_variable *var;
{
- entry->getter = val_getter;
- entry->setter = val_setter;
- entry->marker = val_marker;
+ var->getter = val_getter;
+ var->setter = val_setter;
+ var->marker = val_marker;
- entry->data = (void*)val;
+ var->data = (void*)val;
}
static void
@@ -372,13 +381,13 @@
}
static void
-val_setter(val, id, data, entry)
+val_setter(val, id, data, var)
VALUE val;
ID id;
void *data;
- struct global_entry *entry;
+ struct global_variable *var;
{
- entry->data = (void*)val;
+ var->data = (void*)val;
}
static void
@@ -428,9 +437,10 @@
struct global_entry *entry;
{
struct trace_var *trace;
+ struct global_variable *var = entry->var;
- (*entry->marker)(entry->data);
- trace = entry->trace;
+ (*var->marker)(var->data);
+ trace = var->trace;
while (trace) {
if (trace->data) rb_gc_mark_maybe(trace->data);
trace = trace->next;
@@ -467,14 +477,14 @@
VALUE (*getter)();
void (*setter)();
{
- struct global_entry *entry;
+ struct global_variable *gvar;
ID id = global_id(name);
- entry = rb_global_entry(id);
- entry->data = (void*)var;
- entry->getter = getter?getter:var_getter;
- entry->setter = setter?setter:var_setter;
- entry->marker = var_marker;
+ gvar = rb_global_entry(id)->var;
+ gvar->data = (void*)var;
+ gvar->getter = getter?getter:var_getter;
+ gvar->setter = setter?setter:var_setter;
+ gvar->marker = var_marker;
}
void
@@ -532,20 +542,20 @@
rb_name_error(id, "undefined global variable %s", rb_id2name(id));
}
trace = ALLOC(struct trace_var);
- trace->next = entry->trace;
+ trace->next = entry->var->trace;
trace->func = rb_trace_eval;
trace->data = cmd;
trace->removed = 0;
- entry->trace = trace;
+ entry->var->trace = trace;
return Qnil;
}
static void
-remove_trace(entry)
- struct global_entry *entry;
+remove_trace(var)
+ struct global_variable *var;
{
- struct trace_var *trace = entry->trace;
+ struct trace_var *trace = var->trace;
struct trace_var t;
struct trace_var *next;
@@ -557,9 +567,11 @@
trace->next = next->next;
free(next);
}
- trace = next;
+ else {
+ trace = next;
+ }
}
- entry->trace = t.next;
+ var->trace = t.next;
}
VALUE
@@ -578,7 +590,7 @@
rb_name_error(id, "undefined global variable %s", rb_id2name(id));
}
- trace = entry->trace;
+ trace = entry->var->trace;
if (NIL_P(cmd)) {
VALUE ary = rb_ary_new();
@@ -588,16 +600,15 @@
trace->removed = 1;
trace = next;
}
- entry->trace = 0;
- if (!entry->block_trace) remove_trace(entry);
+ if (!entry->var->block_trace) remove_trace(entry->var);
return ary;
}
else {
while (trace) {
if (trace->data == cmd) {
trace->removed = 1;
- if (!entry->block_trace) remove_trace(entry);
+ if (!entry->var->block_trace) remove_trace(entry->var);
return rb_ary_new3(1, cmd);
}
trace = trace->next;
@@ -605,11 +616,13 @@
}
return Qnil;
}
+
VALUE
rb_gvar_get(entry)
struct global_entry *entry;
{
- return (*entry->getter)(entry->id, entry->data, entry);
+ struct global_variable *var = entry->var;
+ return (*var->getter)(entry->id, var->data, var);
}
struct trace_data {
@@ -631,11 +644,11 @@
}
static VALUE
-trace_en(entry)
- struct global_entry *entry;
+trace_en(var)
+ struct global_variable *var;
{
- entry->block_trace = 0;
- remove_trace(entry);
+ var->block_trace = 0;
+ remove_trace(var);
return Qnil; /* not reached */
}
@@ -645,16 +658,17 @@
VALUE val;
{
struct trace_data trace;
+ struct global_variable *var = entry->var;
if (rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't change global variable value");
- (*entry->setter)(val, entry->id, entry->data, entry);
+ (*var->setter)(val, entry->id, var->data, var);
- if (entry->trace && !entry->block_trace) {
- entry->block_trace = 1;
- trace.trace = entry->trace;
+ if (var->trace && !var->block_trace) {
+ var->block_trace = 1;
+ trace.trace = var->trace;
trace.val = val;
- rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)entry);
+ rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
}
return val;
}
@@ -684,7 +698,7 @@
rb_gvar_defined(entry)
struct global_entry *entry;
{
- if (entry->getter == undef_getter) return Qfalse;
+ if (entry->var->getter == undef_getter) return Qfalse;
return Qtrue;
}
@@ -724,13 +738,27 @@
if (rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't alias global variable");
+
entry1 = rb_global_entry(name1);
entry2 = rb_global_entry(name2);
-
- entry1->data = entry2->data;
- entry1->getter = entry2->getter;
- entry1->setter = entry2->setter;
- entry1->marker = entry2->marker;
+ if (entry1->var != entry2->var) {
+ struct global_variable *var = entry1->var;
+ if (var->block_trace) {
+ rb_raise(rb_eRuntimeError, "can't alias in tracer");
+ }
+ var->counter--;
+ if (var->counter == 0) {
+ struct trace_var *trace = var->trace;
+ while (trace) {
+ trace->removed = 1;
+ trace = trace->next;
+ }
+ remove_trace(var);
+ free(var);
+ }
+ entry2->var->counter++;
+ entry1->var = entry2->var;
+ }
}
static int special_generic_ivar = 0;
--
小迫@ソフネック 渋谷区恵比寿1-15-1