summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/ruby/test_super.rb13
-rw-r--r--vm_insnhelper.c18
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);
}
}