summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstraptest/test_yjit.rb57
-rw-r--r--yjit_codegen.c6
-rw-r--r--yjit_iface.c6
3 files changed, 66 insertions, 3 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index fd1310b04e..fc0b693ec2 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1238,3 +1238,60 @@ assert_equal '[:A, [:A, :B]]', %q{
C.new.bar
}
+
+# Same invokesuper bytecode, multiple destinations
+assert_equal '[:Forward, :SecondTerminus]', %q{
+ module Terminus
+ def foo = :Terminus
+ end
+
+ module SecondTerminus
+ def foo = :SecondTerminus
+ end
+
+
+ module Forward
+ def foo = [:Forward, super]
+ end
+
+ class B
+ include SecondTerminus
+ end
+
+ class A < B
+ include Terminus
+ include Forward
+ end
+
+ A.new.foo
+ A.new.foo # compile
+
+ class B
+ include Forward
+ alias bar foo
+ end
+
+ # A.ancestors.take(5) == [A, Forward, Terminus, B, Forward, SecondTerminus]
+
+ A.new.bar
+}
+
+# invokesuper calling into itself
+assert_equal '[:B, [:B, :m]]', %q{
+ module M
+ def foo = :m
+ end
+
+ class B
+ include M
+ def foo = [:B, super]
+ end
+
+ ins = B.new
+ ins.singleton_class # materialize the singleton class
+ ins.foo
+ ins.foo # compile
+
+ ins.singleton_class.define_method(:bar, B.instance_method(:foo))
+ ins.bar
+}
diff --git a/yjit_codegen.c b/yjit_codegen.c
index 68fadfc820..d61206c2c1 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -2995,7 +2995,8 @@ gen_send(jitstate_t *jit, ctx_t *ctx)
return gen_send_general(jit, ctx, cd, block);
}
-RBIMPL_ATTR_MAYBE_UNUSED() // not in use as it has problems in some situations.
+// Not in use as it's incorrect in some situations. See comments.
+RBIMPL_ATTR_MAYBE_UNUSED()
static codegen_status_t
gen_invokesuper(jitstate_t *jit, ctx_t *ctx)
{
@@ -3096,6 +3097,9 @@ gen_invokesuper(jitstate_t *jit, ctx_t *ctx)
insn_opnd_t recv_opnd = OPND_STACK(argc);
mov(cb, REG0, recv);
+ // FIXME: This guard and the assume_method_lookup_stable() call below isn't
+ // always enough to correctly replicate the interpreter's behavior of
+ // searching at runtime for the callee through the method entry of the stack frame.
if (!jit_guard_known_klass(jit, ctx, comptime_recv_klass, recv_opnd, comptime_recv, SEND_MAX_DEPTH, side_exit)) {
return YJIT_CANT_COMPILE;
}
diff --git a/yjit_iface.c b/yjit_iface.c
index ba3e5bbb83..3d589f5e5e 100644
--- a/yjit_iface.c
+++ b/yjit_iface.c
@@ -218,8 +218,9 @@ add_lookup_dependency_i(st_data_t *key, st_data_t *value, st_data_t data, int ex
return ST_CONTINUE;
}
-// Remember that a block assumes that rb_callable_method_entry(receiver_klass, mid) == cme and that
-// cme is vald.
+// Remember that a block assumes that
+// `rb_callable_method_entry(receiver_klass, cme->called_id) == cme` and that
+// `cme` is valid.
// When either of these assumptions becomes invalid, rb_yjit_method_lookup_change() or
// rb_yjit_cme_invalidate() invalidates the block.
//
@@ -230,6 +231,7 @@ assume_method_lookup_stable(VALUE receiver_klass, const rb_callable_method_entry
RUBY_ASSERT(!block->receiver_klass && !block->callee_cme);
RUBY_ASSERT(cme_validity_dependency);
RUBY_ASSERT(method_lookup_dependency);
+ RUBY_ASSERT(rb_callable_method_entry(receiver_klass, cme->called_id) == cme);
RUBY_ASSERT_ALWAYS(RB_TYPE_P(receiver_klass, T_CLASS));
RUBY_ASSERT_ALWAYS(!rb_objspace_garbage_object_p(receiver_klass));