summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ruby_vm/rjit/insn_compiler.rb41
-rw-r--r--rjit_c.h3
-rw-r--r--rjit_c.rb3
3 files changed, 37 insertions, 10 deletions
diff --git a/lib/ruby_vm/rjit/insn_compiler.rb b/lib/ruby_vm/rjit/insn_compiler.rb
index 6fadd77996..0620269467 100644
--- a/lib/ruby_vm/rjit/insn_compiler.rb
+++ b/lib/ruby_vm/rjit/insn_compiler.rb
@@ -4217,7 +4217,7 @@ module RubyVM::RJIT
return CantCompile
end
- # block_arg = flags & C::VM_CALL_ARGS_BLOCKARG != 0
+ block_arg = flags & C::VM_CALL_ARGS_BLOCKARG != 0
# jit_caller_setup_arg_block already handled send_blockarg_not_nil_or_proxy
# If we have unfilled optional arguments and keyword arguments then we
@@ -4318,9 +4318,17 @@ module RubyVM::RJIT
end
end
if flags & C::VM_CALL_ARGS_SPLAT != 0 && !iseq_has_rest
- splat_array_length = false
- asm.incr_counter(:send_iseq_splat)
- return CantCompile
+ array = jit.peek_at_stack(block_arg ? 1 : 0)
+ splat_array_length = if array.nil?
+ 0
+ else
+ array.length
+ end
+
+ if opt_num == 0 && required_num != splat_array_length + argc - 1
+ asm.incr_counter(:send_iseq_splat_arity_error)
+ return CantCompile
+ end
end
# We will not have CantCompile from here.
@@ -4350,8 +4358,25 @@ module RubyVM::RJIT
# push_splat_args does stack manipulation so we can no longer side exit
if splat_array_length
- asm.incr_counter(:send_iseq_splat)
- return CantCompile
+ remaining_opt = (opt_num + required_num) - (splat_array_length + (argc - 1))
+
+ if opt_num > 0
+ # We are going to jump to the correct offset based on how many optional
+ # params are remaining.
+ offset = opt_num - remaining_opt
+ start_pc_offset = iseq.body.param.opt_table[offset]
+ end
+ # We are going to assume that the splat fills
+ # all the remaining arguments. In the generated code
+ # we test if this is true and if not side exit.
+ argc = argc - 1 + splat_array_length + remaining_opt
+ push_splat_args(splat_array_length, jit, ctx, asm)
+
+ remaining_opt.times do
+ # We need to push nil for the optional arguments
+ stack_ret = ctx.stack_push
+ asm.mov(stack_ret, Qnil)
+ end
end
# This is a .send call and we need to adjust the stack
@@ -4730,7 +4755,7 @@ module RubyVM::RJIT
# So the number of args should just equal the number of args the cfunc takes.
# In the generated code we test if this is true and if not side exit.
argc = cfunc.argc
- jit_caller_setup_arg_splat(jit, ctx, asm, required_args)
+ push_splat_args(required_args, jit, ctx, asm)
end
# We will not have side exits from here. Adjust the stack, which was skipped in jit_call_opt_send.
@@ -5344,7 +5369,7 @@ module RubyVM::RJIT
# @param jit [RubyVM::RJIT::JITState]
# @param ctx [RubyVM::RJIT::Context]
# @param asm [RubyVM::RJIT::Assembler]
- def jit_caller_setup_arg_splat(jit, ctx, asm, required_args)
+ def push_splat_args(required_args, jit, ctx, asm)
side_exit = side_exit(jit, ctx)
asm.comment('push_splat_args')
diff --git a/rjit_c.h b/rjit_c.h
index b8946c83a9..d1ec8a44c9 100644
--- a/rjit_c.h
+++ b/rjit_c.h
@@ -64,7 +64,6 @@ RJIT_RUNTIME_COUNTERS(
send_iseq_has_no_kw,
send_iseq_zsuper,
send_iseq_materialized_block,
- send_iseq_splat_with_kw,
send_iseq_has_rest,
send_iseq_block_arg0_splat,
send_iseq_kw_call,
@@ -74,6 +73,8 @@ RJIT_RUNTIME_COUNTERS(
send_iseq_missing_optional_kw,
send_iseq_too_many_kwargs,
send_iseq_kwargs_mismatch,
+ send_iseq_splat_with_kw,
+ send_iseq_splat_arity_error,
send_cfunc_variadic,
send_cfunc_too_many_args,
diff --git a/rjit_c.rb b/rjit_c.rb
index b6d2e164f5..780326b15d 100644
--- a/rjit_c.rb
+++ b/rjit_c.rb
@@ -1350,7 +1350,6 @@ module RubyVM::RJIT # :nodoc: all
send_iseq_has_no_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_no_kw)")],
send_iseq_zsuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_zsuper)")],
send_iseq_materialized_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_materialized_block)")],
- send_iseq_splat_with_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_with_kw)")],
send_iseq_has_rest: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest)")],
send_iseq_block_arg0_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_block_arg0_splat)")],
send_iseq_kw_call: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kw_call)")],
@@ -1360,6 +1359,8 @@ module RubyVM::RJIT # :nodoc: all
send_iseq_missing_optional_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_missing_optional_kw)")],
send_iseq_too_many_kwargs: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_too_many_kwargs)")],
send_iseq_kwargs_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kwargs_mismatch)")],
+ send_iseq_splat_with_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_with_kw)")],
+ send_iseq_splat_arity_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_arity_error)")],
send_cfunc_variadic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_variadic)")],
send_cfunc_too_many_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_too_many_args)")],
send_cfunc_ruby_array_varg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_ruby_array_varg)")],