summaryrefslogtreecommitdiff
path: root/yjit.c
diff options
context:
space:
mode:
authorAlan Wu <[email protected]>2024-02-27 12:50:38 -0500
committerGitHub <[email protected]>2024-02-27 17:50:38 +0000
commit11f121364ab0b113bcc721ed375a321148e0e8f5 (patch)
treeac3b85bb2fea74037ee5fa8b01ca480c85604a5d /yjit.c
parent1f740cd1115fd96d5da7e7c08223de5396e8b5f1 (diff)
YJIT: Support splat with C methods with -1 arity
Usually we deal with splats by speculating that they're of a specific size. In this case, the C method takes a pointer and a length, so we can support changing sizes just fine.
Diffstat (limited to 'yjit.c')
-rw-r--r--yjit.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/yjit.c b/yjit.c
index 207974073b..8632361699 100644
--- a/yjit.c
+++ b/yjit.c
@@ -890,6 +890,51 @@ rb_yjit_ruby2_keywords_splat_p(VALUE obj)
return FL_TEST_RAW(last, RHASH_PASS_AS_KEYWORDS);
}
+// Checks to establish preconditions for rb_yjit_splat_varg_cfunc()
+VALUE
+rb_yjit_splat_varg_checks(VALUE *sp, VALUE splat_array, rb_control_frame_t *cfp)
+{
+ // We inserted a T_ARRAY guard before this call
+ long len = RARRAY_LEN(splat_array);
+
+ // Large splat arrays need a separate allocation
+ if (len < 0 || len > VM_ARGC_STACK_MAX) return Qfalse;
+
+ // Would we overflow if we put the contents of the array onto the stack?
+ if (sp + len > (VALUE *)(cfp - 2)) return Qfalse;
+
+ return Qtrue;
+}
+
+// Push array elements to the stack for a C method that has a variable number
+// of parameters. Returns the number of arguments the splat array contributes.
+int
+rb_yjit_splat_varg_cfunc(VALUE *stack_splat_array, bool sole_splat)
+{
+ VALUE splat_array = *stack_splat_array;
+ int len;
+
+ // We already checked that length fits in `int`
+ RUBY_ASSERT(RB_TYPE_P(splat_array, T_ARRAY));
+ len = (int)RARRAY_LEN(splat_array);
+
+ // If this is a splat call without any keyword arguments, exclude the
+ // ruby2_keywords hash if it's empty
+ if (sole_splat && len > 0) {
+ VALUE last_hash = RARRAY_AREF(splat_array, len - 1);
+ if (RB_TYPE_P(last_hash, T_HASH) &&
+ FL_TEST_RAW(last_hash, RHASH_PASS_AS_KEYWORDS) &&
+ RHASH_EMPTY_P(last_hash)) {
+ len--;
+ }
+ }
+
+ // Push the contents of the array onto the stack
+ MEMCPY(stack_splat_array, RARRAY_CONST_PTR(splat_array), VALUE, len);
+
+ return len;
+}
+
// Print the Ruby source location of some ISEQ for debugging purposes
void
rb_yjit_dump_iseq_loc(const rb_iseq_t *iseq, uint32_t insn_idx)