Skip to content

Commit

Permalink
YJIT: Support **nil for cfuncs
Browse files Browse the repository at this point in the history
Similar to the iseq call support. Fairly straight forward.
  • Loading branch information
XrXr committed Feb 17, 2024
1 parent 075b6ac commit 548a1b2
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 12 deletions.
4 changes: 2 additions & 2 deletions test/ruby/test_yjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1574,11 +1574,11 @@ def test_send_polymorphic_method_name
end

def test_kw_splat_nil
assert_compiles(<<~'RUBY', result: %i[ok ok], no_send_fallbacks: true)
assert_compiles(<<~'RUBY', result: %i[ok ok ok], no_send_fallbacks: true)
def id(x) = x
def kw_fw(arg, **) = id(arg, **)
def fw(...) = id(...)
def use = [fw(:ok), kw_fw(:ok)]
def use = [fw(:ok), kw_fw(:ok), :ok.itself(**nil)]
use
RUBY
Expand Down
30 changes: 21 additions & 9 deletions yjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6037,11 +6037,8 @@ fn gen_send_cfunc(
return None;
}

// Don't JIT calls with keyword splat
if flags & VM_CALL_KW_SPLAT != 0 {
gen_counter_incr(asm, Counter::send_cfunc_kw_splat);
return None;
}
exit_if_kwsplat_non_nil(asm, flags, Counter::send_cfunc_kw_splat_non_nil)?;
let kw_splat = flags & VM_CALL_KW_SPLAT != 0;

let kw_arg = unsafe { vm_ci_kwarg(ci) };
let kw_arg_num = if kw_arg.is_null() {
Expand All @@ -6065,7 +6062,11 @@ fn gen_send_cfunc(
gen_counter_incr(asm, Counter::num_send_cfunc);

// Delegate to codegen for C methods if we have it.
if kw_arg.is_null() && flags & VM_CALL_OPT_SEND == 0 && flags & VM_CALL_ARGS_SPLAT == 0 && (cfunc_argc == -1 || argc == cfunc_argc) {
if kw_arg.is_null() &&
!kw_splat &&
flags & VM_CALL_OPT_SEND == 0 &&
flags & VM_CALL_ARGS_SPLAT == 0 &&
(cfunc_argc == -1 || argc == cfunc_argc) {
let expected_stack_after = asm.ctx.get_stack_size() as i32 - argc;
if let Some(known_cfunc_codegen) = lookup_cfunc_codegen(unsafe { (*cme).def }) {
if perf_call!("gen_send_cfunc: ", known_cfunc_codegen(jit, asm, ocb, ci, cme, block, argc, recv_known_class)) {
Expand Down Expand Up @@ -6098,6 +6099,10 @@ fn gen_send_cfunc(
argc - kw_arg_num + 1
};

if kw_splat {
passed_argc -= 1;
}

// If the argument count doesn't match
if cfunc_argc >= 0 && cfunc_argc != passed_argc && flags & VM_CALL_ARGS_SPLAT == 0 {
gen_counter_incr(asm, Counter::send_cfunc_argc_mismatch);
Expand Down Expand Up @@ -6147,6 +6152,13 @@ fn gen_send_cfunc(
}
}

if kw_splat {
// Only `**nil` is supported right now. Checked in exit_if_kwsplat_non_nil()
assert_eq!(Type::Nil, asm.ctx.get_opnd_type(StackOpnd(0)));
asm.stack_pop(1);
argc -= 1;
}

// push_splat_args does stack manipulation so we can no longer side exit
if flags & VM_CALL_ARGS_SPLAT != 0 {
assert!(cfunc_argc >= 0);
Expand Down Expand Up @@ -6559,7 +6571,7 @@ fn gen_send_iseq(
exit_if_stack_too_large(iseq)?;
exit_if_tail_call(asm, ci)?;
exit_if_has_post(asm, iseq)?;
exit_if_kwsplat_non_nil(asm, flags)?;
exit_if_kwsplat_non_nil(asm, flags, Counter::send_iseq_kw_splat_non_nil)?;
exit_if_has_rest_and_captured(asm, iseq_has_rest, captured_opnd)?;
exit_if_has_kwrest_and_captured(asm, has_kwrest, captured_opnd)?;
exit_if_has_rest_and_supplying_kws(asm, iseq_has_rest, supplying_kws)?;
Expand Down Expand Up @@ -7560,10 +7572,10 @@ fn exit_if_has_post(asm: &mut Assembler, iseq: *const rb_iseq_t) -> Option<()> {
}

#[must_use]
fn exit_if_kwsplat_non_nil(asm: &mut Assembler, flags: u32) -> Option<()> {
fn exit_if_kwsplat_non_nil(asm: &mut Assembler, flags: u32, counter: Counter) -> Option<()> {
let kw_splat = flags & VM_CALL_KW_SPLAT != 0;
let kw_splat_stack = StackOpnd((flags & VM_CALL_ARGS_BLOCKARG != 0).into());
exit_if(asm, kw_splat && asm.ctx.get_opnd_type(kw_splat_stack) != Type::Nil, Counter::send_iseq_kw_splat_non_nil)
exit_if(asm, kw_splat && asm.ctx.get_opnd_type(kw_splat_stack) != Type::Nil, counter)
}

#[must_use]
Expand Down
2 changes: 1 addition & 1 deletion yjit/src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ make_counters! {
send_missing_method,
send_refined_method,
send_private_not_fcall,
send_cfunc_kw_splat,
send_cfunc_kw_splat_non_nil,
send_cfunc_ruby_array_varg,
send_cfunc_argc_mismatch,
send_cfunc_block_arg,
Expand Down

0 comments on commit 548a1b2

Please sign in to comment.