From: nobu.nakada@... Date: 2003-07-15T09:33:52+09:00 Subject: [ruby-dev:20672] clear cache for added method なかだです。 先日、rubiconが失敗するのに気づいて適当に直してしまいましたが、 やっぱりあれだけでは不十分なようです。 class C1 def foo "C1#foo" end end class C2 < C1 end class C3 < C2 end x = C3.new # x.foo # (1) class C2 undef foo end p x.foo ここで(1)を有効にすると、NoMethodErrorにならなくなります。ある いはundefの代わりにfooを再定義しても"C1#foo"が出力されます。 結局、親クラスで定義されたメソッドと孫クラスでのキャッシュに割 り込む形でmethod bodyを追加する場合には、idに対してクリアしない といけないと思います。本来はサブクラスのキャッシュだけでいいは ずですが、いちいち継承関係を調べるくらいなら思い切って消してし まったほうが速いような気がします。 Index: eval.c =================================================================== RCS file: /cvs/ruby/src/ruby/eval.c,v retrieving revision 1.479 diff -u -2 -p -r1.479 eval.c --- eval.c 11 Jul 2003 19:23:13 -0000 1.479 +++ eval.c 14 Jul 2003 22:26:14 -0000 @@ -232,4 +232,20 @@ rb_clear_cache_for_undef(klass, id) } +static void +rb_clear_cache_by_id(id) + ID id; +{ + struct cache_entry *ent, *end; + + if (!ruby_running) return; + ent = cache; end = ent + CACHE_SIZE; + while (ent < end) { + if (ent->mid == id) { + ent->mid = 0; + } + ent++; + } +} + void rb_clear_cache_by_class(klass) @@ -277,5 +293,5 @@ rb_add_method(klass, mid, node, noex) } if (OBJ_FROZEN(klass)) rb_error_frozen("class/module"); - rb_clear_cache_for_undef(klass, mid); + rb_clear_cache_by_id(mid); body = NEW_METHOD(node, noex); st_insert(RCLASS(klass)->m_tbl, mid, (st_data_t)body); @@ -1821,5 +1837,4 @@ rb_undef(klass, id) rb_id2name(id),s0,rb_class2name(c)); } - if (klass != origin) rb_clear_cache_for_undef(origin, id); rb_add_method(klass, id, 0, NOEX_PUBLIC); if (FL_TEST(klass, FL_SINGLETON)) { @@ -1880,5 +1895,5 @@ rb_alias(klass, name, def) } - rb_clear_cache_for_undef(klass, name); + rb_clear_cache_by_id(name); st_insert(RCLASS(klass)->m_tbl, name, (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex)); -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦