[ruby-dev:18181] Re: autoload patch for ruby-1.7
From:
nobu.nakada@...
Date:
2002-09-05 03:28:30 UTC
List:
ruby-dev #18181
なかだです。
At Mon, 2 Sep 2002 18:08:44 +0900,
Yoshinori K. Okuji <okuji@enbug.org> wrote:
> > 失敗はしないと思います。warningは出ますが。
>
> すいません。ここは私の書き方が良くなかったです。定数の場合は確かに
> warningだけですが、モジュールやクラスの場合には結構奇妙なエラーになっ
> てしまいます。
>
> 例えば、foo.rbにこういうコードを書いて、
>
> module Foo; def self.msg; puts 'foo'; end; end
> module Bar; def self.msg; puts 'bar'; end; end
>
> シェルで、
>
> $ ruby -e 'autoload :Foo, "foo"; autoload :Bar, "foo"; Foo.msg(); Bar.msg()'
>
> とすると、
>
> uninitialized constant Bar (NameError)
>
> になるはずです。
load中のファイルからautoloadされる定数を未定義とみなすようにし
てみました。結局ev_const_defined()での対応も必要になったり、関
数の構成を変えたりしたので、ちょっと大きいですがパッチを作り直
しました。
[ruby-dev:18139]の
> それなり速くて素直なのは、逆方向のハッシュテーブルを別に持ち、あるファ
> イルからautoloadされるべき定数のリストを簡単に見られるようにしておく方
> 法です。
とどっちがいいか…。
Index: class.c
===================================================================
RCS file: /cvs/ruby/src/ruby/class.c,v
retrieving revision 1.45
diff -u -2 -p -r1.45 class.c
--- class.c 4 Sep 2002 06:37:35 -0000 1.45
+++ class.c 4 Sep 2002 13:58:21 -0000
@@ -190,7 +190,4 @@ rb_define_class(name, super)
id = rb_intern(name);
- if (rb_autoload_defined(id)) {
- rb_autoload_load(id);
- }
if (rb_const_defined(rb_cObject, id)) {
klass = rb_const_get(rb_cObject, id);
@@ -279,7 +276,4 @@ rb_define_module(name)
id = rb_intern(name);
- if (rb_autoload_defined(id)) {
- rb_autoload_load(id);
- }
if (rb_const_defined(rb_cObject, id)) {
module = rb_const_get(rb_cObject, id);
Index: eval.c
===================================================================
RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.323
diff -u -2 -p -r1.323 eval.c
--- eval.c 29 Aug 2002 09:08:15 -0000 1.323
+++ eval.c 2 Sep 2002 01:30:54 -0000
@@ -1535,4 +1535,5 @@ ev_const_defined(cref, id, self)
{
NODE *cbase = cref;
+ VALUE result;
while (cbase && cbase->nd_next) {
@@ -1540,5 +1541,8 @@ ev_const_defined(cref, id, self)
if (NIL_P(klass)) return rb_const_defined(CLASS_OF(self), id);
- if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, 0)) {
+ if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, &result)) {
+ if (result == Qundef && NIL_P(rb_autoload_p((VALUE)klass, id))) {
+ return Qfalse;
+ }
return Qtrue;
}
@@ -1561,5 +1565,9 @@ ev_const_get(cref, id, self)
if (NIL_P(klass)) return rb_const_get(CLASS_OF(self), id);
- if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &result)) {
+ while (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &result)) {
+ if (result == Qundef) {
+ rb_autoload_load(klass, id);
+ continue;
+ }
return result;
}
@@ -3301,7 +3309,4 @@ rb_eval(self, n)
klass = 0;
- if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) {
- rb_autoload_load(node->nd_cname);
- }
if (rb_const_defined_at(ruby_class, node->nd_cname)) {
klass = rb_const_get(ruby_class, node->nd_cname);
@@ -3347,7 +3352,4 @@ rb_eval(self, n)
}
module = 0;
- if ((ruby_class == rb_cObject) && rb_autoload_defined(node->nd_cname)) {
- rb_autoload_load(node->nd_cname);
- }
if (rb_const_defined_at(ruby_class, node->nd_cname)) {
module = rb_const_get(ruby_class, node->nd_cname);
@@ -6169,5 +6171,41 @@ Init_eval()
}
-VALUE rb_f_autoload();
+static VALUE
+rb_mod_autoload(mod, sym, file)
+ VALUE mod;
+ VALUE sym;
+ VALUE file;
+{
+ ID id = rb_to_id(sym);
+
+ Check_SafeStr(file);
+ rb_autoload(mod, id, RSTRING(file)->ptr);
+ return Qnil;
+}
+
+static VALUE
+rb_mod_autoload_p(mod, sym)
+ VALUE mod, sym;
+{
+ return rb_autoload_p(mod, rb_to_id(sym));
+}
+
+static VALUE
+rb_f_autoload(obj, sym, file)
+ VALUE obj;
+ VALUE sym;
+ VALUE file;
+{
+ return rb_mod_autoload(ruby_class, sym, file);
+}
+
+static VALUE
+rb_f_autoload_p(obj, sym)
+ VALUE obj;
+ VALUE sym;
+{
+ /* use ruby_class as same as rb_f_autoload. */
+ return rb_mod_autoload_p(ruby_class, sym);
+}
void
@@ -6184,5 +6222,8 @@ Init_load()
rb_define_global_function("load", rb_f_load, -1);
rb_define_global_function("require", rb_f_require, 1);
+ rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
+ rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
rb_define_global_function("autoload", rb_f_autoload, 2);
+ rb_define_global_function("autoload?", rb_f_autoload_p, 1);
rb_global_variable(&ruby_wrapper);
Index: intern.h
===================================================================
RCS file: /cvs/ruby/src/ruby/intern.h,v
retrieving revision 1.95
diff -u -2 -p -r1.95 intern.h
--- intern.h 3 Sep 2002 10:00:45 -0000 1.95
+++ intern.h 4 Sep 2002 07:37:19 -0000
@@ -400,6 +400,7 @@ void rb_set_class_path _((VALUE, VALUE,
VALUE rb_path2class _((const char*));
void rb_name_class _((VALUE, ID));
-void rb_autoload _((const char*, const char*));
-VALUE rb_f_autoload _((VALUE, VALUE, VALUE));
+void rb_autoload _((VALUE, ID, const char*));
+void rb_autoload_load _((VALUE, ID));
+VALUE rb_autoload_p _((VALUE, ID));
void rb_gc_mark_global_tbl _((void));
VALUE rb_f_trace_var _((int, VALUE*));
@@ -425,5 +426,4 @@ VALUE rb_mod_constants _((VALUE));
VALUE rb_mod_remove_const _((VALUE, VALUE));
int rb_const_defined_at _((VALUE, ID));
-int rb_autoload_defined _((ID));
int rb_const_defined _((VALUE, ID));
VALUE rb_const_get _((VALUE, ID));
@@ -432,5 +432,4 @@ void rb_const_set _((VALUE, ID, VALUE));
void rb_const_assign _((VALUE, ID, VALUE));
VALUE rb_mod_constants _((VALUE));
-void rb_autoload_load _((ID));
VALUE rb_cvar_defined _((VALUE, ID));
void rb_cvar_set _((VALUE, ID, VALUE, int));
Index: variable.c
===================================================================
RCS file: /cvs/ruby/src/ruby/variable.c,v
retrieving revision 1.68
diff -u -2 -p -r1.68 variable.c
--- variable.c 3 Sep 2002 05:20:07 -0000 1.68
+++ variable.c 3 Sep 2002 08:48:05 -0000
@@ -21,4 +21,5 @@
static st_table *rb_global_tbl;
st_table *rb_class_tbl;
+static ID autoload;
void
@@ -27,4 +28,5 @@ Init_var_tables()
rb_global_tbl = st_init_numtable();
rb_class_tbl = st_init_numtable();
+ autoload = rb_intern("__autoload__");
}
@@ -254,37 +256,4 @@ rb_name_class(klass, id)
}
-static st_table *autoload_tbl = 0;
-
-static void
-rb_autoload_id(id, filename)
- ID id;
- const char *filename;
-{
- rb_secure(4);
- if (!rb_is_const_id(id)) {
- rb_name_error(id, "autoload must be constant name");
- }
-
- if (!autoload_tbl) {
- autoload_tbl = st_init_numtable();
- }
- st_insert(autoload_tbl, id, strdup(filename));
-}
-
-void
-rb_autoload(klass, filename)
- const char *klass, *filename;
-{
- rb_autoload_id(rb_intern(klass), filename);
-}
-
-VALUE
-rb_f_autoload(obj, klass, file)
- VALUE obj, klass, file;
-{
- rb_autoload_id(rb_to_id(klass), StringValuePtr(file));
- return Qnil;
-}
-
char *
rb_class2name(klass)
@@ -1079,4 +1048,137 @@ rb_obj_remove_instance_variable(obj, nam
}
+NORETURN(static void uninitialized_constant _((VALUE, ID)));
+static void
+uninitialized_constant(klass, id)
+ VALUE klass;
+ ID id;
+{
+ if (klass && klass != rb_cObject)
+ rb_name_error(id, "uninitialized constant %s::%s",
+ RSTRING(rb_class_path(klass))->ptr,
+ rb_id2name(id));
+ else {
+ rb_name_error(id, "uninitialized constant %s",rb_id2name(id));
+ }
+}
+
+void
+rb_autoload(mod, id, file)
+ VALUE mod;
+ ID id;
+ const char *file;
+{
+ VALUE av;
+ struct st_table *tbl;
+
+ if (!rb_is_const_id(id)) {
+ rb_raise(rb_eNameError, "autoload must be constant name",
+ rb_id2name(id));
+ }
+ if (!file || !*file) {
+ rb_raise(rb_eArgError, "empty file name");
+ }
+
+ if ((tbl = RCLASS(mod)->iv_tbl) && st_lookup(tbl, id, &av) && av != Qundef)
+ return;
+
+ rb_const_set(mod, id, Qundef);
+ tbl = RCLASS(mod)->iv_tbl;
+ if (st_lookup(tbl, autoload, &av)) {
+ tbl = (struct st_table*)DATA_PTR(av);
+ }
+ else {
+ av = Data_Wrap_Struct(rb_cData, rb_mark_tbl, st_free_table, 0);
+ st_add_direct(tbl, autoload, av);
+ DATA_PTR(av) = tbl = st_init_numtable();
+ }
+ st_insert(tbl, id, rb_str_new2(file));
+}
+
+static VALUE
+autoload_delete(mod, id)
+ VALUE mod;
+ ID id;
+{
+ VALUE val, file = Qnil;
+
+ if (st_lookup(RCLASS(mod)->iv_tbl, autoload, &val)) {
+ struct st_table *tbl = DATA_PTR(val);
+
+ st_delete(tbl, &id, &file);
+ if (!tbl->num_entries) {
+ DATA_PTR(val) = 0;
+ st_free_table(tbl);
+ id = autoload;
+ if (st_delete(RCLASS(mod)->iv_tbl, &id, &val)) {
+ rb_gc_force_recycle(val);
+ }
+ }
+ }
+
+ return file;
+}
+
+void
+rb_autoload_load(klass, id)
+ VALUE klass;
+ ID id;
+{
+ VALUE file, value;
+
+ file = autoload_delete(klass, id);
+ if (NIL_P(file)) {
+ uninitialized_constant(klass, id);
+ }
+ if (rb_provided(RSTRING(file)->ptr)) {
+ uninitialized_constant(klass, id);
+ }
+ FL_UNSET(file, FL_TAINT);
+ rb_f_require(Qnil, file);
+}
+
+static VALUE
+autoload_file(mod, id)
+ VALUE mod;
+ ID id;
+{
+ VALUE val, file;
+ struct st_table *tbl;
+
+ if (!st_lookup(RCLASS(mod)->iv_tbl, autoload, &val) ||
+ !(tbl = DATA_PTR(val)) || !st_lookup(tbl, id, &file)) {
+ return Qnil;
+ }
+ if (!rb_provided(RSTRING(file)->ptr)) {
+ return file;
+ }
+
+ /* already loaded but not defined */
+ st_delete(tbl, &id, 0);
+ if (!tbl->num_entries) {
+ DATA_PTR(val) = 0;
+ st_free_table(tbl);
+ id = autoload;
+ if (st_delete(RCLASS(mod)->iv_tbl, &id, &val)) {
+ rb_gc_force_recycle(val);
+ }
+ }
+ return Qnil;
+}
+
+VALUE
+rb_autoload_p(mod, id)
+ VALUE mod;
+ ID id;
+{
+ struct st_table *tbl = RCLASS(mod)->iv_tbl;
+ VALUE val;
+
+ if (!tbl || !st_lookup(tbl, id, &val) || val != Qundef) {
+ return Qnil;
+ }
+ return autoload_file(mod, id);
+}
+
static int
top_const_get(id, klassp)
@@ -1086,11 +1188,4 @@ top_const_get(id, klassp)
/* pre-defined class */
if (st_lookup(rb_class_tbl, id, klassp)) return Qtrue;
-
- /* autoload */
- if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) {
- rb_autoload_load(id);
- *klassp = rb_const_get(rb_cObject, id);
- return Qtrue;
- }
return Qfalse;
}
@@ -1103,5 +1198,9 @@ rb_const_get_at(klass, id)
VALUE value;
- if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+ while (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+ if (value == Qundef) {
+ rb_autoload_load(klass, id);
+ continue;
+ }
return value;
}
@@ -1109,28 +1208,8 @@ rb_const_get_at(klass, id)
return value;
}
- rb_name_error(id, "uninitialized constant %s::%s",
- RSTRING(rb_class_path(klass))->ptr,
- rb_id2name(id));
+ uninitialized_constant(klass, id);
return Qnil; /* not reached */
}
-void
-rb_autoload_load(id)
- ID id;
-{
- char *modname;
- VALUE module;
-
- st_delete(autoload_tbl, &id, &modname);
- if (rb_provided(modname)) {
- free(modname);
- return;
- }
- module = rb_str_new2(modname);
- free(modname);
- FL_UNSET(module, FL_TAINT);
- rb_f_require(Qnil, module);
-}
-
VALUE
rb_const_get(klass, id)
@@ -1144,5 +1223,9 @@ rb_const_get(klass, id)
retry:
while (tmp) {
- if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
+ while (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) {
+ if (value == Qundef) {
+ rb_autoload_load(tmp, id);
+ continue;
+ }
return value;
}
@@ -1156,14 +1239,8 @@ rb_const_get(klass, id)
}
- /* Uninitialized constant */
- if (klass && klass != rb_cObject) {
- rb_name_error(id, "uninitialized constant %s at %s",
- rb_id2name(id),
- RSTRING(rb_class_path(klass))->ptr);
+ uninitialized_constant(klass, id);
+ return Qnil; /* not reached */
}
- else { /* global_uninitialized */
- rb_name_error(id, "uninitialized constant %s",rb_id2name(id));
}
- return Qnil; /* not reached */
}
@@ -1183,4 +1260,5 @@ rb_mod_remove_const(mod, name)
if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, &id, &val)) {
+ if (val == Qundef) autoload_delete(mod, id);
return val;
}
@@ -1208,16 +1286,4 @@ sv_i(key, value, tbl)
}
-static int
-autoload_i(key, name, tbl)
- ID key;
- const char *name;
- st_table *tbl;
-{
- if (!st_lookup(tbl, key, 0)) {
- st_insert(tbl, key, key);
- }
- return ST_CONTINUE;
-}
-
void*
rb_mod_const_at(mod, data)
@@ -1234,7 +1300,4 @@ rb_mod_const_at(mod, data)
if ((VALUE)mod == rb_cObject) {
st_foreach(rb_class_tbl, sv_i, tbl);
- if (autoload_tbl) {
- st_foreach(autoload_tbl, autoload_i, tbl);
- }
}
return tbl;
@@ -1290,5 +1353,9 @@ rb_const_defined_at(klass, id)
ID id;
{
- if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, 0)) {
+ VALUE value;
+
+ if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) {
+ if (value == Qundef && NIL_P(autoload_file(klass, id)))
+ return Qfalse;
return Qtrue;
}
@@ -1300,21 +1367,14 @@ rb_const_defined_at(klass, id)
int
-rb_autoload_defined(id)
- ID id;
-{
- if (autoload_tbl && st_lookup(autoload_tbl, id, 0))
- return Qtrue;
- return Qfalse;
-}
-
-int
rb_const_defined(klass, id)
VALUE klass;
ID id;
{
- VALUE tmp = klass;
+ VALUE tmp = klass, value;
while (tmp) {
- if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) {
+ if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl, id, &value)) {
+ if (value == Qundef && NIL_P(autoload_file(klass, id)))
+ return Qfalse;
return Qtrue;
}
@@ -1326,5 +1386,5 @@ rb_const_defined(klass, id)
if (st_lookup(rb_class_tbl, id, 0))
return Qtrue;
- return rb_autoload_defined(id);
+ return Qfalse;
}
@@ -1345,6 +1405,11 @@ mod_av_set(klass, id, val, isconst)
}
else if (isconst) {
- if (st_lookup(RCLASS(klass)->iv_tbl, id, 0) ||
+ VALUE value = Qfalse;
+
+ if (st_lookup(RCLASS(klass)->iv_tbl, id, &value) ||
(klass == rb_cObject && st_lookup(rb_class_tbl, id, 0))) {
+ if (value == Qundef)
+ autoload_delete(klass, id);
+ else
rb_warn("already initialized %s %s", dest, rb_id2name(id));
}
@@ -1385,22 +1450,5 @@ rb_const_assign(klass, id, val)
}
- /* autoload */
- if (autoload_tbl && st_lookup(autoload_tbl, id, 0)) {
- char *modname;
-
- st_delete(autoload_tbl, &id, &modname);
- free(modname);
- st_insert(RCLASS(rb_cObject)->iv_tbl, id, val);
- return;
- }
-
- /* Uninitialized constant */
- if (klass && klass != rb_cObject)
- rb_name_error(id, "uninitialized constant %s::%s",
- RSTRING(rb_class_path(klass))->ptr,
- rb_id2name(id));
- else {
- rb_name_error(id, "uninitialized constant %s",rb_id2name(id));
- }
+ uninitialized_constant(klass, id);
}
--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦