diff options
-rw-r--r-- | test/ruby/test_super.rb | 13 | ||||
-rw-r--r-- | vm_insnhelper.c | 18 |
2 files changed, 30 insertions, 1 deletions
diff --git a/test/ruby/test_super.rb b/test/ruby/test_super.rb index bbfc581500..7c4beff07b 100644 --- a/test/ruby/test_super.rb +++ b/test/ruby/test_super.rb @@ -583,4 +583,17 @@ class TestSuper < Test::Unit::TestCase def test_super_with_modified_rest_parameter assert_equal [13], TestFor_super_with_modified_rest_parameter.new.foo end + + def test_super_with_define_method + superklass = Class.new do + def foo; :foo; end + def bar; :bar; end + end + subklass = Class.new(superklass) + [:foo, :bar].each do |sym| + subklass.define_method(sym){ super() } + end + assert_equal :foo, subklass.new.foo + assert_equal :bar, subklass.new.bar + end end diff --git a/vm_insnhelper.c b/vm_insnhelper.c index d2b8a63676..9404b0d74a 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -3154,9 +3154,25 @@ vm_search_super_method(const rb_control_frame_t *reg_cfp, struct rb_call_data *c CC_SET_FASTPATH(cc, vm_call_method_missing, TRUE); } else { - /* TODO: use inline cache */ +#if OPT_INLINE_METHOD_CACHE + /* Unlike normal method search, we only consider the first class + * serial. Since we're testing defined_class rather than receiver, + * there's only one valid "warm" value. */ + if (LIKELY(RB_DEBUG_COUNTER_INC_UNLESS(mc_global_state_miss, + GET_GLOBAL_METHOD_STATE() == cc->method_state) && + cc->class_serial[0] == RCLASS_SERIAL(klass)) && + cc->me && ci->mid == cc->me->def->original_id) { + VM_ASSERT(cc->call != NULL); + RB_DEBUG_COUNTER_INC(mc_inline_hit); + return; + } +#endif + CC_SET_ME(cc, rb_callable_method_entry(klass, ci->mid)); CC_SET_FASTPATH(cc, vm_call_super_method, TRUE); + + cc->method_state = GET_GLOBAL_METHOD_STATE(); + cc->class_serial[0] = RCLASS_SERIAL(klass); } } |