Skip to content

Commit cd1cd80

Browse files
committed
RJIT: Support splat args
1 parent 6f2535d commit cd1cd80

3 files changed

Lines changed: 37 additions & 10 deletions

File tree

lib/ruby_vm/rjit/insn_compiler.rb

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4217,7 +4217,7 @@ def jit_call_iseq(jit, ctx, asm, cme, calling, iseq, frame_type: nil, prev_ep: n
42174217
return CantCompile
42184218
end
42194219

4220-
# block_arg = flags & C::VM_CALL_ARGS_BLOCKARG != 0
4220+
block_arg = flags & C::VM_CALL_ARGS_BLOCKARG != 0
42214221
# jit_caller_setup_arg_block already handled send_blockarg_not_nil_or_proxy
42224222

42234223
# If we have unfilled optional arguments and keyword arguments then we
@@ -4318,9 +4318,17 @@ def jit_call_iseq(jit, ctx, asm, cme, calling, iseq, frame_type: nil, prev_ep: n
43184318
end
43194319
end
43204320
if flags & C::VM_CALL_ARGS_SPLAT != 0 && !iseq_has_rest
4321-
splat_array_length = false
4322-
asm.incr_counter(:send_iseq_splat)
4323-
return CantCompile
4321+
array = jit.peek_at_stack(block_arg ? 1 : 0)
4322+
splat_array_length = if array.nil?
4323+
0
4324+
else
4325+
array.length
4326+
end
4327+
4328+
if opt_num == 0 && required_num != splat_array_length + argc - 1
4329+
asm.incr_counter(:send_iseq_splat_arity_error)
4330+
return CantCompile
4331+
end
43244332
end
43254333

43264334
# We will not have CantCompile from here.
@@ -4350,8 +4358,25 @@ def jit_call_iseq(jit, ctx, asm, cme, calling, iseq, frame_type: nil, prev_ep: n
43504358

43514359
# push_splat_args does stack manipulation so we can no longer side exit
43524360
if splat_array_length
4353-
asm.incr_counter(:send_iseq_splat)
4354-
return CantCompile
4361+
remaining_opt = (opt_num + required_num) - (splat_array_length + (argc - 1))
4362+
4363+
if opt_num > 0
4364+
# We are going to jump to the correct offset based on how many optional
4365+
# params are remaining.
4366+
offset = opt_num - remaining_opt
4367+
start_pc_offset = iseq.body.param.opt_table[offset]
4368+
end
4369+
# We are going to assume that the splat fills
4370+
# all the remaining arguments. In the generated code
4371+
# we test if this is true and if not side exit.
4372+
argc = argc - 1 + splat_array_length + remaining_opt
4373+
push_splat_args(splat_array_length, jit, ctx, asm)
4374+
4375+
remaining_opt.times do
4376+
# We need to push nil for the optional arguments
4377+
stack_ret = ctx.stack_push
4378+
asm.mov(stack_ret, Qnil)
4379+
end
43554380
end
43564381

43574382
# This is a .send call and we need to adjust the stack
@@ -4730,7 +4755,7 @@ def jit_call_cfunc_with_frame(jit, ctx, asm, cme, flags, argc, block_handler, kn
47304755
# So the number of args should just equal the number of args the cfunc takes.
47314756
# In the generated code we test if this is true and if not side exit.
47324757
argc = cfunc.argc
4733-
jit_caller_setup_arg_splat(jit, ctx, asm, required_args)
4758+
push_splat_args(required_args, jit, ctx, asm)
47344759
end
47354760

47364761
# We will not have side exits from here. Adjust the stack, which was skipped in jit_call_opt_send.
@@ -5344,7 +5369,7 @@ def move_rest_args_to_stack(array, num_args, jit, ctx, asm)
53445369
# @param jit [RubyVM::RJIT::JITState]
53455370
# @param ctx [RubyVM::RJIT::Context]
53465371
# @param asm [RubyVM::RJIT::Assembler]
5347-
def jit_caller_setup_arg_splat(jit, ctx, asm, required_args)
5372+
def push_splat_args(required_args, jit, ctx, asm)
53485373
side_exit = side_exit(jit, ctx)
53495374

53505375
asm.comment('push_splat_args')

rjit_c.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ RJIT_RUNTIME_COUNTERS(
6464
send_iseq_has_no_kw,
6565
send_iseq_zsuper,
6666
send_iseq_materialized_block,
67-
send_iseq_splat_with_kw,
6867
send_iseq_has_rest,
6968
send_iseq_block_arg0_splat,
7069
send_iseq_kw_call,
@@ -74,6 +73,8 @@ RJIT_RUNTIME_COUNTERS(
7473
send_iseq_missing_optional_kw,
7574
send_iseq_too_many_kwargs,
7675
send_iseq_kwargs_mismatch,
76+
send_iseq_splat_with_kw,
77+
send_iseq_splat_arity_error,
7778

7879
send_cfunc_variadic,
7980
send_cfunc_too_many_args,

rjit_c.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1350,7 +1350,6 @@ def C.rb_rjit_runtime_counters
13501350
send_iseq_has_no_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_no_kw)")],
13511351
send_iseq_zsuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_zsuper)")],
13521352
send_iseq_materialized_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_materialized_block)")],
1353-
send_iseq_splat_with_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_with_kw)")],
13541353
send_iseq_has_rest: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest)")],
13551354
send_iseq_block_arg0_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_block_arg0_splat)")],
13561355
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 @@ def C.rb_rjit_runtime_counters
13601359
send_iseq_missing_optional_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_missing_optional_kw)")],
13611360
send_iseq_too_many_kwargs: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_too_many_kwargs)")],
13621361
send_iseq_kwargs_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kwargs_mismatch)")],
1362+
send_iseq_splat_with_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_with_kw)")],
1363+
send_iseq_splat_arity_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_arity_error)")],
13631364
send_cfunc_variadic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_variadic)")],
13641365
send_cfunc_too_many_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_too_many_args)")],
13651366
send_cfunc_ruby_array_varg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_ruby_array_varg)")],

0 commit comments

Comments
 (0)