diff options
author | Alan Wu <[email protected]> | 2024-02-27 12:50:38 -0500 |
---|---|---|
committer | GitHub <[email protected]> | 2024-02-27 17:50:38 +0000 |
commit | 11f121364ab0b113bcc721ed375a321148e0e8f5 (patch) | |
tree | ac3b85bb2fea74037ee5fa8b01ca480c85604a5d /yjit.c | |
parent | 1f740cd1115fd96d5da7e7c08223de5396e8b5f1 (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.c | 45 |
1 files changed, 45 insertions, 0 deletions
@@ -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) |