1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

YJIT: Add support for ruby array cfuncs (argc=-2)

This adds support for cfuncs which take variable arguments using a Ruby
array. This is specified with the method entry's argc == -2.
This commit is contained in:
John Hawthorn 2022-01-05 01:07:52 -08:00
parent b5c039125f
commit 18b97eee5a
Notes: git 2022-01-09 04:41:20 +09:00
3 changed files with 42 additions and 7 deletions

View file

@ -2766,3 +2766,23 @@ assert_equal 'ok', %q{
foo(s) rescue :ok foo(s) rescue :ok
foo(s) rescue :ok foo(s) rescue :ok
} }
# File.join is a cfunc accepting variable arguments as a Ruby array (argc = -2)
assert_equal 'foo/bar', %q{
def foo
File.join("foo", "bar")
end
foo
foo
}
# File.join is a cfunc accepting variable arguments as a Ruby array (argc = -2)
assert_equal '', %q{
def foo
File.join()
end
foo
foo
}

1
yjit.c
View file

@ -69,7 +69,6 @@ YJIT_DECLARE_COUNTERS(
send_missing_method, send_missing_method,
send_bmethod, send_bmethod,
send_refined_method, send_refined_method,
send_cfunc_ruby_array_varg,
send_cfunc_argc_mismatch, send_cfunc_argc_mismatch,
send_cfunc_toomany_args, send_cfunc_toomany_args,
send_cfunc_tracing, send_cfunc_tracing,

View file

@ -3244,12 +3244,6 @@ gen_send_cfunc(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const
{ {
const rb_method_cfunc_t *cfunc = UNALIGNED_MEMBER_PTR(cme->def, body.cfunc); const rb_method_cfunc_t *cfunc = UNALIGNED_MEMBER_PTR(cme->def, body.cfunc);
// If the function expects a Ruby array of arguments
if (cfunc->argc < 0 && cfunc->argc != -1) {
GEN_COUNTER_INC(cb, send_cfunc_ruby_array_varg);
return YJIT_CANT_COMPILE;
}
// If the argument count doesn't match // If the argument count doesn't match
if (cfunc->argc >= 0 && cfunc->argc != argc) { if (cfunc->argc >= 0 && cfunc->argc != argc) {
GEN_COUNTER_INC(cb, send_cfunc_argc_mismatch); GEN_COUNTER_INC(cb, send_cfunc_argc_mismatch);
@ -3402,6 +3396,28 @@ gen_send_cfunc(jitstate_t *jit, ctx_t *ctx, const struct rb_callinfo *ci, const
lea(cb, C_ARG_REGS[1], ctx_stack_opnd(ctx, argc - 1)); lea(cb, C_ARG_REGS[1], ctx_stack_opnd(ctx, argc - 1));
mov(cb, C_ARG_REGS[2], ctx_stack_opnd(ctx, argc)); mov(cb, C_ARG_REGS[2], ctx_stack_opnd(ctx, argc));
} }
// Variadic method with Ruby array
if (cfunc->argc == -2) {
// Create a Ruby array from the arguments.
//
// This follows similar behaviour to vm_call_cfunc_with_frame() and
// call_cfunc_m2(). We use rb_ec_ary_new_from_values() instead of
// rb_ary_new4() since we have REG_EC available.
//
// Before getting here we will have set the new CFP in the EC, and the
// stack at CFP's SP will contain the values we are inserting into the
// Array, so they will be properly marked if we hit a GC.
// rb_ec_ary_new_from_values(rb_execution_context_t *ec, long n, const VLAUE *elts)
mov(cb, C_ARG_REGS[0], REG_EC);
mov(cb, C_ARG_REGS[1], imm_opnd(argc));
lea(cb, C_ARG_REGS[2], ctx_stack_opnd(ctx, argc - 1));
call_ptr(cb, REG0, (void *)rb_ec_ary_new_from_values);
// rb_file_s_join(VALUE recv, VALUE args)
mov(cb, C_ARG_REGS[0], ctx_stack_opnd(ctx, argc));
mov(cb, C_ARG_REGS[1], RAX);
}
// Pop the C function arguments from the stack (in the caller) // Pop the C function arguments from the stack (in the caller)
ctx_stack_pop(ctx, argc + 1); ctx_stack_pop(ctx, argc + 1);