diff --git a/test/ruby/test_inlinecache.rb b/test/ruby/test_inlinecache.rb index 90d0189d4c..6c2d86aefd 100644 --- a/test/ruby/test_inlinecache.rb +++ b/test/ruby/test_inlinecache.rb @@ -61,4 +61,50 @@ class TestMethod < Test::Unit::TestCase assert_equal :E, test[] EOS end + + def test_module_methods_redefiniton + m0 = Module.new do + def foo + super + end + end + + c1 = Class.new do + def foo + :C1 + end + end + + c2 = Class.new do + def foo + :C2 + end + end + + d1 = Class.new(c1) do + include m0 + end + + d2 = Class.new(c2) do + include m0 + end + + assert_equal :C1, d1.new.foo + + m = Module.new do + def foo + super + end + end + + d1.class_eval do + include m + end + + d2.class_eval do + include m + end + + assert_equal :C2, d2.new.foo + end end diff --git a/vm_method.c b/vm_method.c index d1afb88e40..cce28462cc 100644 --- a/vm_method.c +++ b/vm_method.c @@ -166,15 +166,20 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid) // invalidate cme if found to invalidate the inline method cache. if (METHOD_ENTRY_CACHED(cme)) { - // invalidate cc by invalidating cc->cme - VALUE owner = cme->owner; - rb_callable_method_entry_t *new_cme = - (rb_callable_method_entry_t *)rb_method_entry_clone((const rb_method_entry_t *)cme); - struct rb_id_table *mtbl = RCLASS_M_TBL(RCLASS_ORIGIN(owner)); - rb_id_table_insert(mtbl, mid, (VALUE)new_cme); - RB_OBJ_WRITTEN(owner, cme, new_cme); + if (METHOD_ENTRY_COMPLEMENTED(cme)) { + // do nothing + } + else { + // invalidate cc by invalidating cc->cme + VALUE owner = cme->owner; + VM_ASSERT(BUILTIN_TYPE(owner) == T_CLASS); + rb_callable_method_entry_t *new_cme = + (rb_callable_method_entry_t *)rb_method_entry_clone((const rb_method_entry_t *)cme); + struct rb_id_table *mtbl = RCLASS_M_TBL(RCLASS_ORIGIN(owner)); + rb_id_table_insert(mtbl, mid, (VALUE)new_cme); + RB_OBJ_WRITTEN(owner, cme, new_cme); + } vm_me_invalidate_cache((rb_callable_method_entry_t *)cme); - RB_DEBUG_COUNTER_INC(cc_invalidate_tree_cme); }