summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2024-03-18 12:02:22 -0400
committerGitHub <noreply@github.com>2024-03-18 16:02:22 +0000
commit802e857ae6553bdc441d11892af0259a400f504e (patch)
tree29656b01e09eb04fd56de2848a8ba573788fc2ff
parent97810cbbf2bf3346c6ad7bd67b38808f0eb11d61 (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.rb16
-rw-r--r--yjit/src/codegen.rs20
-rw-r--r--yjit/src/stats.rs2
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,