From: MOROHOSHI Akihiko Date: 2002-03-03T20:51:43+09:00 Subject: [ruby-dev:16180] Re: autoload (Re: Re: : and ::) --Multipart_Sun_Mar__3_20:51:39_2002-1 Content-Type: text/plain; charset=ISO-2022-JP なかださん wrote: > > +static VALUE autoload_tbl = 0; > > +static VALUE autoload_target = 0; > > +#define AUTOLOAD_TARGET autoload_target > > +#define IS_AUTOLOAD_TARGET(obj) ((obj)==autoload_target) > > Qundefでもいいかも。 なるほど、それを使うのが良さそうですね。 というわけで、変更してみました。 先の差分からの変更点は、他に以下の点です。 - 1.6.7を元にした - 定数書き換え時のautoload情報削除し忘れを修正 - rb_hash_delete()を直接使うようにした - autoload?(mod,sym) を mod.autoload?(sym) に変更 -- MOROHOSHI Akihiko --Multipart_Sun_Mar__3_20:51:39_2002-1 Content-Type: text/plain;; charset=US-ASCII Content-Disposition: attachment; filename="ruby-1.6.7-autoload.patch" Content-Transfer-Encoding: 7bit diff -ruN --exclude config* --exclude *~ --exclude Makefile --exclude ext --exclude *.rb ruby-1.6.7.orig/eval.c ruby-1.6.7/eval.c --- ruby-1.6.7.orig/eval.c Wed Feb 27 13:50:29 2002 +++ ruby-1.6.7/eval.c Sun Mar 3 19:15:23 2002 @@ -3079,9 +3079,6 @@ } 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); } @@ -3126,9 +3123,6 @@ rb_raise(rb_eTypeError, "no outer class/module"); } 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); } @@ -6057,8 +6051,6 @@ #endif } -VALUE rb_f_autoload(); - void Init_load() { @@ -6072,7 +6064,6 @@ 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_global_variable(&ruby_wrapper); ruby_dln_librefs = rb_ary_new(); diff -ruN --exclude config* --exclude *~ --exclude Makefile --exclude ext --exclude *.rb ruby-1.6.7.orig/hash.c ruby-1.6.7/hash.c --- ruby-1.6.7.orig/hash.c Mon Feb 25 18:16:41 2002 +++ ruby-1.6.7/hash.c Sun Mar 3 19:34:02 2002 @@ -386,7 +386,7 @@ return indexes; } -static VALUE +VALUE rb_hash_delete(hash, key) VALUE hash, key; { diff -ruN --exclude config* --exclude *~ --exclude Makefile --exclude ext --exclude *.rb ruby-1.6.7.orig/inits.c ruby-1.6.7/inits.c --- ruby-1.6.7.orig/inits.c Wed Mar 21 17:04:11 2001 +++ ruby-1.6.7/inits.c Sun Mar 3 20:01:02 2002 @@ -13,6 +13,7 @@ #include "ruby.h" void Init_Array _((void)); +void Init_autoload _((void)); void Init_Bignum _((void)); void Init_Comparable _((void)); void Init_Dir _((void)); @@ -72,6 +73,7 @@ Init_signal(); Init_process(); Init_load(); + Init_autoload(); Init_Proc(); Init_Math(); Init_GC(); diff -ruN --exclude config* --exclude *~ --exclude Makefile --exclude ext --exclude *.rb ruby-1.6.7.orig/intern.h ruby-1.6.7/intern.h --- ruby-1.6.7.orig/intern.h Wed Feb 27 13:50:30 2002 +++ ruby-1.6.7/intern.h Sun Mar 3 19:34:40 2002 @@ -200,6 +200,7 @@ VALUE rb_hash_freeze _((VALUE)); VALUE rb_hash_aref _((VALUE, VALUE)); VALUE rb_hash_aset _((VALUE, VALUE, VALUE)); +VALUE rb_hash_delete _((VALUE, VALUE)); VALUE rb_hash_delete_if _((VALUE)); int rb_path_check _((char *)); int rb_env_path_tainted _((void)); @@ -358,8 +359,6 @@ void rb_set_class_path _((VALUE, VALUE, const char*)); 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_gc_mark_global_tbl _((void)); VALUE rb_f_trace_var _((int, VALUE*)); VALUE rb_f_untrace_var _((int, VALUE*)); @@ -380,14 +379,12 @@ VALUE rb_mod_const_of _((VALUE, 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)); VALUE rb_const_get_at _((VALUE, ID)); void rb_const_set _((VALUE, ID, VALUE)); void rb_const_assign _((VALUE, ID, VALUE)); VALUE rb_mod_constants _((VALUE)); -void rb_autoload_load _((ID)); void rb_cvar_declare _((VALUE, ID, VALUE)); VALUE rb_cvar_defined _((VALUE, ID)); void rb_cvar_set _((VALUE, ID, VALUE)); diff -ruN --exclude config* --exclude *~ --exclude Makefile --exclude ext --exclude *.rb ruby-1.6.7.orig/variable.c ruby-1.6.7/variable.c --- ruby-1.6.7.orig/variable.c Tue Feb 19 13:48:04 2002 +++ ruby-1.6.7/variable.c Sun Mar 3 20:18:26 2002 @@ -245,40 +245,6 @@ rb_iv_set(klass, "__classid__", ID2SYM(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_raise(rb_eNameError, "autoload must be constant name", - rb_id2name(id)); - } - - 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), STR2CSTR(file)); - return Qnil; -} - char * rb_class2name(klass) VALUE klass; @@ -1032,22 +998,115 @@ return val; } +static VALUE autoload_tbl = Qnil; +#define AUTOLOAD_TARGET Qundef +#define IS_AUTOLOAD_TARGET(obj) ((obj)==Qundef) +#define AUTOLOAD_KEY_NEW(klass,id) rb_ary_new3(2,klass,ID2SYM(id)) + +static void +autoload_add(VALUE klass, ID id, VALUE file) { + VALUE key; + + rb_secure(4); + Check_SafeStr(file); + if (!rb_is_const_id(id)) { + rb_raise(rb_eNameError, "autoload must be constant name", + rb_id2name(id)); + } + + key = AUTOLOAD_KEY_NEW(klass, id); + rb_hash_aset(autoload_tbl, key, file); +} + +static VALUE +rb_mod_autoload(VALUE mod, VALUE sym, VALUE file) { + ID id = rb_to_id(sym); + + if (rb_const_defined_at(mod,id)) + return Qnil; + + rb_const_set(mod, id, AUTOLOAD_TARGET); + autoload_add(mod, id, file); + + return Qnil; +} + +static VALUE +rb_f_autoload(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 void +autoload_delete(VALUE klass, VALUE id) { + VALUE key = AUTOLOAD_KEY_NEW(klass, id); + rb_hash_delete(autoload_tbl, key); +} + +static void +autoload_load(VALUE klass, ID id) { + VALUE key, file; + + if (RCLASS(klass)->iv_tbl) { + VALUE value; + st_delete(ROBJECT(klass)->iv_tbl, &id, &value); + if (! IS_AUTOLOAD_TARGET(value)) + rb_bug("autoload_laod: removed normal constant: %s::%s", + rb_class2name(klass), rb_id2name(id)); + } else { + rb_bug("autoload_load: constant not found: %s::%s", + rb_class2name(klass), rb_id2name(id)); + } + + key = AUTOLOAD_KEY_NEW(klass, id); + file = rb_hash_delete(autoload_tbl, key); + + 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); +} + +static VALUE +rb_mod_autoload_p(VALUE mod, VALUE sym) { + ID id = rb_to_id(sym); + return NIL_P(rb_hash_aref(autoload_tbl, AUTOLOAD_KEY_NEW(mod,id))) ? + Qfalse : Qtrue; +} + +static VALUE +rb_f_autoload_p(VALUE self, VALUE sym) { + /* use ruby_class as same as rb_f_autoload. */ + return rb_mod_autoload_p(ruby_class, sym); +} + +void +Init_autoload() { + autoload_tbl = rb_hash_new(); + rb_global_variable(&autoload_tbl); + + 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); +} + static int top_const_get(id, klassp) ID id; VALUE *klassp; { - VALUE value; - /* 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; } @@ -1058,7 +1117,12 @@ { VALUE value; +retry: if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &value)) { + if (IS_AUTOLOAD_TARGET(value)) { + autoload_load(klass, id); + goto retry; + } return value; } if (klass == rb_cObject && top_const_get(id, &value)) { @@ -1070,24 +1134,6 @@ 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) VALUE klass; @@ -1100,6 +1146,10 @@ retry: while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { + if (IS_AUTOLOAD_TARGET(value)) { + autoload_load(tmp,id); + goto retry; + } return value; } if (tmp == rb_cObject && top_const_get(id, &value)) return value; @@ -1128,6 +1178,7 @@ VALUE value; VALUE ary; { + /* autoload constants: included. */ if (rb_is_const_id(key)) { VALUE kval = rb_str_new2(rb_id2name(key)); if (!rb_ary_includes(ary, kval)) { @@ -1152,7 +1203,15 @@ if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); if (RCLASS(mod)->iv_tbl && st_delete(ROBJECT(mod)->iv_tbl, &id, &val)) { - return val; + if (IS_AUTOLOAD_TARGET(val)) { + /* cancel autoload and go through. + * + * XXX - should we do autoload and retry? + */ + autoload_delete(mod, id); + } else { + return val; + } } if (rb_const_defined_at(mod, id)) { rb_raise(rb_eNameError, "cannot remove %s::%s", @@ -1163,19 +1222,6 @@ return Qnil; /* not reached */ } -static int -autoload_i(key, name, ary) - ID key; - const char *name; - VALUE ary; -{ - VALUE kval = rb_str_new2(rb_id2name(key)); - if (!rb_ary_includes(ary, kval)) { - rb_ary_push(ary, kval); - } - return ST_CONTINUE; -} - VALUE rb_mod_const_at(mod, ary) VALUE mod, ary; @@ -1185,9 +1231,6 @@ } if ((VALUE)mod == rb_cObject) { st_foreach(rb_class_tbl, sv_i, ary); - if (autoload_tbl) { - st_foreach(autoload_tbl, autoload_i, ary); - } } return ary; } @@ -1217,6 +1260,7 @@ VALUE klass; ID id; { + /* autoload constants: included */ if (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, 0)) { return Qtrue; } @@ -1227,21 +1271,13 @@ } 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; + /* autoload constants: included */ while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) { return Qtrue; @@ -1253,7 +1289,7 @@ } if (st_lookup(rb_class_tbl, id, 0)) return Qtrue; - return rb_autoload_defined(id); + return Qfalse; } static void @@ -1272,8 +1308,12 @@ RCLASS(klass)->iv_tbl = st_init_numtable(); } else if (isconst) { - if (st_lookup(RCLASS(klass)->iv_tbl, id, 0) || - (klass == rb_cObject && st_lookup(rb_class_tbl, id, 0))) { + VALUE value; + if (st_lookup(RCLASS(klass)->iv_tbl, id, &value)) { + if (IS_AUTOLOAD_TARGET(value)) + autoload_delete(klass, id); + rb_warn("already initialized %s %s", dest, rb_id2name(id)); + } else if (klass == rb_cObject && st_lookup(rb_class_tbl, id, 0)) { rb_warn("already initialized %s %s", dest, rb_id2name(id)); } } @@ -1297,9 +1337,15 @@ VALUE val; { VALUE tmp = klass; - + +retry: while (tmp) { - if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,0)) { + VALUE value; + if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { + if (IS_AUTOLOAD_TARGET(value)) { + autoload_load(tmp,id); + goto retry; + } st_insert(RCLASS(tmp)->iv_tbl, id, val); return; } @@ -1308,16 +1354,6 @@ /* pre-defined class */ if (st_lookup(rb_class_tbl, id, 0)) { st_delete(rb_class_tbl, id, 0); - st_insert(RCLASS(rb_cObject)->iv_tbl, id, val); - return; - } - - /* 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; } --Multipart_Sun_Mar__3_20:51:39_2002-1--