diff options
| author | Alan Wu <XrXr@users.noreply.github.com> | 2024-03-18 12:02:22 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-18 16:02:22 +0000 |
| commit | 802e857ae6553bdc441d11892af0259a400f504e (patch) | |
| tree | 29656b01e09eb04fd56de2848a8ba573788fc2ff | |
| parent | 97810cbbf2bf3346c6ad7bd67b38808f0eb11d61 (diff) | |
YJIT: Support arity=-2 cfuncs (#10268)
This type of cfuncs shows up as consume a lot of cycles in profiles of
the lobsters benchmark, even though in the stats they don't happen that
frequently. Might be a bug in the profiling, but these calls are not
too bad to support, so might as well do it.
Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>
| -rw-r--r-- | bootstraptest/test_yjit.rb | 16 | ||||
| -rw-r--r-- | yjit/src/codegen.rs | 20 | ||||
| -rw-r--r-- | yjit/src/stats.rs | 2 |
3 files changed, 33 insertions, 5 deletions
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index 6fc0d48c87..ddd1e321a0 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -4678,3 +4678,19 @@ assert_equal '[0, {1=>1}]', %q{ test(KwInit, [Hash.ruby2_keywords_hash({1 => 1})]) } + +# arity=-2 cfuncs +assert_equal '["", "1/2", [0, [:ok, 1]]]', %q{ + def test_cases(file, chain) + new_chain = chain.allocate # to call initialize directly + new_chain.send(:initialize, [0], ok: 1) + + [ + file.join, + file.join("1", "2"), + new_chain.to_a, + ] + end + + test_cases(File, Enumerator::Chain) +} diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 292de96f70..745433ab00 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -6174,9 +6174,9 @@ fn gen_send_cfunc( let variable_splat = flags & VM_CALL_ARGS_SPLAT != 0 && cfunc_argc == -1; let block_arg = flags & VM_CALL_ARGS_BLOCKARG != 0; - // If the function expects a Ruby array of arguments - if cfunc_argc < 0 && cfunc_argc != -1 { - gen_counter_incr(asm, Counter::send_cfunc_ruby_array_varg); + // If it's a splat and the method expects a Ruby array of arguments + if cfunc_argc == -2 && flags & VM_CALL_ARGS_SPLAT != 0 { + gen_counter_incr(asm, Counter::send_cfunc_splat_neg2); return None; } @@ -6461,7 +6461,19 @@ fn gen_send_cfunc( asm.stack_opnd(argc), ] } - else { + // Variadic method taking a Ruby array + else if cfunc_argc == -2 { + // Slurp up all the arguments into an array + let stack_args = asm.lea(asm.ctx.sp_opnd(-argc * SIZEOF_VALUE_I32)); + let args_array = asm.ccall( + rb_ec_ary_new_from_values as _, + vec![EC, passed_argc.into(), stack_args] + ); + + // Example signature: + // VALUE neg2_method(VALUE self, VALUE argv) + vec![asm.stack_opnd(argc), args_array] + } else { panic!("unexpected cfunc_args: {}", cfunc_argc) }; diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs index 5fa2bfedfb..c1315aad90 100644 --- a/yjit/src/stats.rs +++ b/yjit/src/stats.rs @@ -354,7 +354,7 @@ make_counters! { send_refined_method, send_private_not_fcall, send_cfunc_kw_splat_non_nil, - send_cfunc_ruby_array_varg, + send_cfunc_splat_neg2, send_cfunc_argc_mismatch, send_cfunc_block_arg, send_cfunc_toomany_args, |
