Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YJIT: Properly deal with cfunc splat when no args needed #7413

Merged
merged 1 commit into from Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions bootstraptest/test_yjit.rb
Expand Up @@ -3584,3 +3584,13 @@ def a.test = :test
assert_equal 'true', %q{
1.send(:==, 1, *[])
}

# Test send with splat to a cfunc
assert_equal '2', %q{
def foo
Integer.sqrt(4, *[])
end
# call twice to deal with constant exiting
foo
foo
}
28 changes: 17 additions & 11 deletions yjit/src/codegen.rs
Expand Up @@ -4864,23 +4864,29 @@ fn gen_send_cfunc(

// push_splat_args does stack manipulation so we can no longer side exit
if flags & VM_CALL_ARGS_SPLAT != 0 {
if flags & VM_CALL_OPT_SEND != 0 {
// FIXME: This combination is buggy.
// For example `1.send(:==, 1, *[])` fails to adjust the stack properly
gen_counter_incr!(asm, send_cfunc_splat_send);
return CantCompile;
}
let required_args : u32 = (cfunc_argc as u32).saturating_sub(argc as u32 - 1);
// + 1 because we pass self
if required_args + 1 >= C_ARG_OPNDS.len() as u32 {
gen_counter_incr!(asm, send_cfunc_toomany_args);
return CantCompile;
}
// We are going to assume that the splat fills
// all the remaining arguments. In the generated code
// we test if this is true and if not side exit.
argc = required_args as i32;
passed_argc = argc;

if required_args == 0 {
// The splat is not going to supply us any arguments
// so we set the argc to the number of arguments
// the cfunc expects.
// We still need to do all the splat logic because someone
// could pass in a non-zero sized array and we need to
// exit to error.
argc = cfunc_argc;
passed_argc = argc;
} else {
// We are going to assume that the splat fills
// all the remaining arguments. In the generated code
// we test if this is true and if not side exit.
argc = required_args as i32;
passed_argc = argc;
}
push_splat_args(required_args, ctx, asm, ocb, side_exit)
}

Expand Down