diff options
author | Koichi Sasada <[email protected]> | 2020-03-11 02:45:49 +0900 |
---|---|---|
committer | Koichi Sasada <[email protected]> | 2020-03-11 02:50:44 +0900 |
commit | 2943ff9d4441485a18773aa745bab7f47767dde2 (patch) | |
tree | af02635e8f3629930d572fb22f1517952c4672e1 | |
parent | ec78b8b62a84fd57eb93d7b5de5b83ea517ad7c4 (diff) |
fix bug on method cache invalidation.
To invalidate cached method entry, existing method entry (ment)
is marked as invalidated and replace with copied ment. However,
complemented method entry (method entries in Module) should not
be set to Module's m_tbl.
[Bug #16669]
-rw-r--r-- | test/ruby/test_inlinecache.rb | 46 | ||||
-rw-r--r-- | vm_method.c | 21 |
2 files changed, 59 insertions, 8 deletions
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); } |