YJIT: Support invokesuper in a block (#7264)

Support invokesuper in a block on YJIT

invokesuper previously side exited when it is in a block. To make sure we're compiling the correct method in super, we now use the local environment pointer (LEP) to get the method, which will work in a block.

Co-authored-by: John Hawthorn <john@hawthorn.email>
This commit is contained in:
Maple Ong 2023-02-09 10:41:29 -05:00 committed by GitHub
parent 0601ba6a1b
commit 381bdee118
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2023-02-09 15:41:50 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>
2 changed files with 37 additions and 14 deletions

View File

@ -1940,6 +1940,38 @@ assert_equal '[:A, :Btwo]', %q{
ins.foo
}
# invokesuper with a block
assert_equal 'true', %q{
class A
def foo = block_given?
end
class B < A
def foo = super()
end
B.new.foo { }
B.new.foo { }
}
# invokesuper in a block
assert_equal '[0, 2]', %q{
class A
def foo(x) = x * 2
end
class B < A
def foo
2.times.map do |x|
super(x)
end
end
end
B.new.foo
B.new.foo
}
# Call to fixnum
assert_equal '[true, false]', %q{
def is_odd(obj)

View File

@ -6623,22 +6623,15 @@ fn gen_invokesuper(
// Guard that the receiver has the same class as the one from compile time
let side_exit = get_side_exit(jit, ocb, ctx);
let cfp = unsafe { get_ec_cfp(jit.ec.unwrap()) };
let ep = unsafe { get_cfp_ep(cfp) };
let cref_me = unsafe { *ep.offset(VM_ENV_DATA_INDEX_ME_CREF.try_into().unwrap()) };
let me_as_value = VALUE(me as usize);
if cref_me != me_as_value {
// This will be the case for super within a block
return CantCompile;
}
asm.comment("guard known me");
let ep_opnd = asm.load(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_EP));
let lep_opnd = gen_get_lep(jit, asm);
let ep_me_opnd = Opnd::mem(
64,
ep_opnd,
lep_opnd,
SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_ME_CREF,
);
let me_as_value = VALUE(me as usize);
asm.cmp(ep_me_opnd, me_as_value.into());
asm.jne(counted_exit!(ocb, side_exit, invokesuper_me_changed));
@ -6650,11 +6643,9 @@ fn gen_invokesuper(
// TODO: this could properly forward the current block handler, but
// would require changes to gen_send_*
asm.comment("guard no block given");
// EP is in REG0 from above
let ep_opnd = asm.load(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_EP));
let ep_specval_opnd = Opnd::mem(
64,
ep_opnd,
lep_opnd,
SIZEOF_VALUE_I32 * VM_ENV_DATA_INDEX_SPECVAL,
);
asm.cmp(ep_specval_opnd, VM_BLOCK_HANDLER_NONE.into());