From: nobu.nakada@... Date: 2002-09-02T00:58:26+09:00 Subject: [ruby-dev:18138] Re: autoload patch for ruby-1.7 --Multipart_Mon_Sep__2_00:58:25_2002-1 Content-Type: text/plain; charset=ISO-2022-JP なかだです。 At Sun, 1 Sep 2002 15:53:24 +0900, Minero Aoki wrote: > > [ruby-dev:16180]でトップレベル以外の定数についてもautoloadができるよう > > にするパッチを拝見しました。[ruby-dev:16185]でまつもとさんが1.7系に修 > > 正することを提案されてましたが、その後特に動きはないようだったので、 > > > > * 今日のCVS版に合わせて修正する > > * バグっぽかった所を修正する > > * コーディング・スタイルが一部一致していなかった所を修正する > > 惜しいのですが、このパッチでは不十分なんです。 > > Ruby レベルからの定数の参照は「外の」クラスとスーパークラスの > 二方向にリストを検索しているため、variable.c と eval.c の二ヶ所に > 分裂しています。なので eval.c の ev_const_get/defined も同時に > 修正しないといけません。すると autoload_load とか AUTOLOAD_TARGET > を extern にしないとまずいです。 definedは修正する必要はないんじゃないでしょうか。 確かめたわけじゃありませんが、ファイル名とシンボルの配列をキー にするよりも、st_tableを各モジュールに持たせたほうが速いような 気がします。 # 定数の扱いといえば、[ruby-list:33477]もちょっと。 -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦 --Multipart_Mon_Sep__2_00:58:25_2002-1 Content-Type: text/x-diff; type=patch; charset=US-ASCII Content-Disposition: attachment; filename="autoload.diff" Content-Transfer-Encoding: 7bit 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 1 Sep 2002 14:44:12 -0000 @@ -1562,4 +1562,7 @@ 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)) { + if (result == Qundef) { + return rb_mod_autoload_load(klass, id); + } return result; } @@ -3301,7 +3304,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 +3347,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 +6166,24 @@ Init_eval() } -VALUE rb_f_autoload(); +static VALUE +rb_f_autoload(obj, sym, file) + VALUE obj; + VALUE sym; + VALUE file; +{ + /* I use ruby_class instead of obj, as same as NODE_CDECL, + * assuming autoload is another way of const_set. + */ + return rb_mod_autoload(ruby_class, sym, file); +} + +static VALUE +rb_f_autoload_p(self, sym) + VALUE self; + VALUE sym; +{ + /* use ruby_class as same as rb_f_autoload. */ + return rb_mod_autoload_p(ruby_class, sym); +} void @@ -6184,5 +6200,8 @@ Init_load() rb_define_global_function("load", rb_f_load, -1); rb_define_global_function("require", rb_f_require, 1); - rb_define_global_function("autoload", rb_f_autoload, 2); + 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.92 diff -u -2 -p -r1.92 intern.h --- intern.h 19 Aug 2002 05:56:05 -0000 1.92 +++ intern.h 1 Sep 2002 12:04:03 -0000 @@ -399,6 +399,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)); +VALUE rb_mod_autoload _((VALUE, VALUE, VALUE)); +VALUE rb_mod_autoload_load _((VALUE, ID)); +VALUE rb_mod_autoload_p _((VALUE, VALUE)); void rb_gc_mark_global_tbl _((void)); VALUE rb_f_trace_var _((int, VALUE*)); @@ -424,5 +425,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)); @@ -431,5 +431,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.67 diff -u -2 -p -r1.67 variable.c --- variable.c 30 Aug 2002 10:46:37 -0000 1.67 +++ variable.c 1 Sep 2002 14:43:30 -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) @@ -1071,4 +1040,113 @@ rb_obj_remove_instance_variable(obj, nam } +VALUE +rb_mod_autoload(mod, sym, file) + VALUE mod; + VALUE sym; + VALUE file; +{ + ID id = rb_to_id(sym); + VALUE av; + struct st_table *tbl; + + if (!rb_is_const_id(id)) { + rb_raise(rb_eNameError, "autoload must be constant name", + rb_id2name(id)); + } + Check_SafeStr(file); + + if (rb_const_defined_at(mod,id)) + return Qnil; + + 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_dup_frozen(file)); + + return Qnil; +} + +static VALUE +autoload_delete(klass, id) + VALUE klass; + VALUE id; +{ + VALUE val, file = Qnil; + + if (st_lookup(RCLASS(klass)->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(klass)->iv_tbl, &id, &val)) { + rb_gc_force_recycle(val); + } + } + } + + return file; +} + +VALUE +rb_mod_autoload_load(klass, id) + VALUE klass; + ID id; +{ + VALUE file, value; + + if (RCLASS(klass)->iv_tbl) { + VALUE value; + + st_delete(RCLASS(klass)->iv_tbl, &id, &value); + if (value != Qundef) + rb_bug("rb_mod_autoload_laod: removed normal constant: %s::%s", + rb_class2name(klass), rb_id2name(id)); + } + else { + rb_bug("rb_mod_autoload_load: constant not found: %s::%s", + rb_class2name(klass), rb_id2name(id)); + } + + file = autoload_delete(klass, id); + + if (NIL_P(file)) { + rb_bug("autoload file not found for %s::%s", + rb_class2name(klass), rb_id2name(id)); + } + + if (rb_provided(RSTRING(file)->ptr)) return; + + FL_UNSET(file, FL_TAINT); + rb_f_require(Qnil, file); + if (!RCLASS(klass)->iv_tbl || !st_lookup(RCLASS(klass)->iv_tbl, id, &value)) { + rb_loaderror("%s::%s must be defined in %s", + rb_class2name(klass), rb_id2name(id), RSTRING(file)->ptr); + } + return value; +} + +VALUE +rb_mod_autoload_p(mod, sym) + VALUE mod; + VALUE sym; +{ + ID id = rb_to_id(sym); + VALUE file; + + if (RCLASS(mod)->iv_tbl && st_lookup(RCLASS(mod)->iv_tbl, id, &file)) + return file; + return Qnil; +} + static int top_const_get(id, klassp) @@ -1078,11 +1156,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; } @@ -1096,4 +1167,7 @@ rb_const_get_at(klass, id) if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) { + if (value == Qundef) { + return rb_mod_autoload_load(klass, id); + } return value; } @@ -1107,22 +1181,4 @@ rb_const_get_at(klass, id) } -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) @@ -1137,4 +1193,7 @@ rb_const_get(klass, id) while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { + if (value == Qundef) { + return rb_mod_autoload_load(tmp, id); + } return value; } @@ -1175,4 +1234,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; } @@ -1200,16 +1260,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) @@ -1226,7 +1274,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; @@ -1292,13 +1337,4 @@ 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; @@ -1318,5 +1354,5 @@ rb_const_defined(klass, id) if (st_lookup(rb_class_tbl, id, 0)) return Qtrue; - return rb_autoload_defined(id); + return Qfalse; } @@ -1337,6 +1373,9 @@ 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); rb_warn("already initialized %s %s", dest, rb_id2name(id)); } @@ -1377,14 +1416,4 @@ 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) --Multipart_Mon_Sep__2_00:58:25_2002-1--