diff options
author | Takashi Kokubun <takashikkbn@gmail.com> | 2023-04-01 17:10:19 -0700 |
---|---|---|
committer | Takashi Kokubun <takashikkbn@gmail.com> | 2023-04-01 17:17:41 -0700 |
commit | f42cf3fd1ed6bb43822f85a90c1cda119e75a68d (patch) | |
tree | e55eb0d68452b2d56c140687df650055b07d2efe | |
parent | cfea319772faeef1d3d0ff69916221c29b691ee0 (diff) | |
download | ruby-f42cf3fd1ed6bb43822f85a90c1cda119e75a68d.tar.gz |
RJIT: Migrate invokeblock to jit_call_iseq
-rw-r--r-- | lib/ruby_vm/rjit/insn_compiler.rb | 276 |
1 files changed, 4 insertions, 272 deletions
diff --git a/lib/ruby_vm/rjit/insn_compiler.rb b/lib/ruby_vm/rjit/insn_compiler.rb index c3e3a16282..779a817f9d 100644 --- a/lib/ruby_vm/rjit/insn_compiler.rb +++ b/lib/ruby_vm/rjit/insn_compiler.rb @@ -1559,15 +1559,7 @@ module RubyVM::RJIT block_changed_exit = counted_exit(side_exit, :invokeblock_iseq_block_changed) jit_chain_guard(:jne, jit, ctx, asm, block_changed_exit) - opt_pc = jit_callee_setup_block_arg(jit, ctx, asm, calling, comptime_iseq, arg_setup_type: :arg_setup_block) - if opt_pc == CantCompile - return CantCompile - end - - jit_call_iseq_setup_normal( - jit, ctx, asm, nil, calling, comptime_iseq, opt_pc, - frame_type: C::VM_FRAME_MAGIC_BLOCK, - ) + jit_call_iseq(jit, ctx, asm, nil, calling, comptime_iseq, frame_type: C::VM_FRAME_MAGIC_BLOCK) elsif comptime_handler & 0x3 == 0x3 # VM_BH_IFUNC_P # We aren't handling CALLER_SETUP_ARG and CALLER_REMOVE_EMPTY_KW_SPLAT yet. if calling.flags & C::VM_CALL_ARGS_SPLAT != 0 @@ -4309,68 +4301,6 @@ module RubyVM::RJIT EndBlock end - # vm_call_iseq_setup_normal (vm_call_iseq_setup_2 -> vm_call_iseq_setup_normal) - # @param jit [RubyVM::RJIT::JITState] - # @param ctx [RubyVM::RJIT::Context] - # @param asm [RubyVM::RJIT::Assembler] - def jit_call_iseq_setup_normal(jit, ctx, asm, cme, calling, iseq, opt_pc, frame_type:, prev_ep: nil) - argc = calling.argc - flags = calling.flags - send_shift = calling.send_shift - block_handler = calling.block_handler - - # Push splat args, which was skipped in jit_caller_setup_arg. - if flags & C::VM_CALL_ARGS_SPLAT != 0 - lead_num = iseq.body.param.lead_num - opt_num = iseq.body.param.opt_num - - array_length = jit.peek_at_stack(flags & C::VM_CALL_ARGS_BLOCKARG != 0 ? 1 : 0)&.length || 0 # blockarg is not popped yet - if opt_num == 0 && lead_num != array_length + argc - 1 - asm.incr_counter(:send_args_splat_arity_error) - return CantCompile - end - - remaining_opt = (opt_num + lead_num) - (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. - opt_pc = iseq.body.param.opt_table[opt_num - remaining_opt] - 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 + array_length - jit_caller_setup_arg_splat(jit, ctx, asm, array_length) - end - - # We will not have side exits from here. Adjust the stack, which was skipped in jit_call_opt_send. - if flags & C::VM_CALL_OPT_SEND != 0 - jit_call_opt_send_shift_stack(ctx, asm, argc, send_shift:) - end - - if block_handler == C::VM_BLOCK_HANDLER_NONE && iseq.body.builtin_attrs & C::BUILTIN_ATTR_LEAF != 0 - if jit_leaf_builtin_func(jit, ctx, asm, flags, iseq) - return KeepCompiling - end - end - - frame_type ||= C::VM_FRAME_MAGIC_METHOD | C::VM_ENV_FLAG_LOCAL - jit_push_frame( - jit, ctx, asm, cme, flags, argc, frame_type, block_handler, - iseq: iseq, - local_size: iseq.body.local_table_size - iseq.body.param.size, - stack_max: iseq.body.stack_max, - prev_ep:, - push_opts: true, - ) - - # Jump to a stub for the callee ISEQ - callee_ctx = Context.new - pc = (iseq.body.iseq_encoded + opt_pc).to_i - jit_direct_jump(iseq, pc, callee_ctx, asm) - - EndBlock - end - def jit_leaf_builtin_func(jit, ctx, asm, flags, iseq) builtin_func = builtin_function(iseq) if builtin_func.nil? @@ -4728,7 +4658,7 @@ module RubyVM::RJIT asm.incr_counter(:send_optimized_send_send) return CantCompile end - # Lazily handle stack shift in jit_call_iseq_setup_normal + # Lazily handle stack shift in jit_call_opt_send_shift_stack calling.send_shift += 1 jit_call_symbol(jit, ctx, asm, cme, calling, known_recv_class, C::VM_CALL_FCALL) @@ -4904,7 +4834,7 @@ module RubyVM::RJIT # @param jit [RubyVM::RJIT::JITState] # @param ctx [RubyVM::RJIT::Context] # @param asm [RubyVM::RJIT::Assembler] - def jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, block_handler, iseq: nil, local_size: 0, stack_max: 0, prev_ep: nil, push_opts: false) + def jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, block_handler, iseq: nil, local_size: 0, stack_max: 0, prev_ep: nil) # CHECK_VM_STACK_OVERFLOW0: next_cfp <= sp + (local_size + stack_max) asm.comment('stack overflow check') asm.lea(:rax, ctx.sp_opnd(C.rb_control_frame_t.size + C.VALUE.size * (local_size + stack_max))) @@ -4932,12 +4862,6 @@ module RubyVM::RJIT ctx.stack_pop(1) end - if iseq && push_opts - # This was not handled in jit_callee_setup_arg - opts_filled = argc - iseq.body.param.lead_num # TODO: kwarg - opts_missing = iseq.body.param.opt_num - opts_filled - local_size += opts_missing - end local_size.times do |i| asm.comment('set local variables') if i == 0 local_index = ctx.sp_offset + i @@ -5041,198 +4965,6 @@ module RubyVM::RJIT asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], cfp_reg) end - # vm_callee_setup_arg (ISEQ only): Set up args and return opt_pc (or CantCompile) - # @param jit [RubyVM::RJIT::JITState] - # @param ctx [RubyVM::RJIT::Context] - # @param asm [RubyVM::RJIT::Assembler] - def jit_callee_setup_arg(jit, ctx, asm, flags, argc, iseq) - if flags & C::VM_CALL_KW_SPLAT == 0 - if C.rb_simple_iseq_p(iseq) - if jit_caller_setup_arg(jit, ctx, asm, flags, splat: true) == CantCompile - return CantCompile - end - if jit_caller_remove_empty_kw_splat(jit, ctx, asm, flags) == CantCompile - return CantCompile - end - - if argc != iseq.body.param.lead_num - # argument_arity_error - return CantCompile - end - - return 0 - elsif C.rb_iseq_only_optparam_p(iseq) - if jit_caller_setup_arg(jit, ctx, asm, flags, splat: true) == CantCompile - return CantCompile - end - if jit_caller_remove_empty_kw_splat(jit, ctx, asm, flags) == CantCompile - return CantCompile - end - - lead_num = iseq.body.param.lead_num - opt_num = iseq.body.param.opt_num - opt = argc - lead_num - - if opt < 0 || opt > opt_num - asm.incr_counter(:send_arity) - return CantCompile - end - - # Qnil push is handled in jit_push_frame - - return iseq.body.param.opt_table[opt] - elsif C.rb_iseq_only_kwparam_p(iseq) && (flags & C::VM_CALL_ARGS_SPLAT) == 0 - asm.incr_counter(:send_iseq_kwparam) - return CantCompile - end - end - - return jit_setup_parameters_complex(jit, ctx, asm, flags, argc, iseq) - end - - # vm_callee_setup_block_arg (ISEQ only): Set up args and return opt_pc (or CantCompile) - # @param jit [RubyVM::RJIT::JITState] - # @param ctx [RubyVM::RJIT::Context] - # @param asm [RubyVM::RJIT::Assembler] - def jit_callee_setup_block_arg(jit, ctx, asm, calling, iseq, arg_setup_type:) - if C.rb_simple_iseq_p(iseq) - if jit_caller_setup_arg(jit, ctx, asm, calling.flags, splat: true) == CantCompile - return CantCompile - end - - if arg_setup_type == :arg_setup_block && - calling.argc == 1 && - iseq.body.param.flags.has_lead && - !iseq.body.param.flags.ambiguous_param0 - asm.incr_counter(:invokeblock_iseq_arg0_splat) - return CantCompile - end - - if calling.argc != iseq.body.param.lead_num - if arg_setup_type == :arg_setup_block - if calling.argc < iseq.body.param.lead_num - (iseq.body.param.lead_num - calling.argc).times do - asm.mov(ctx.stack_push, Qnil) - end - calling.argc = iseq.body.param.lead_num # fill rest parameters - elsif calling.argc > iseq.body.param.lead_num - ctx.stack_pop(calling.argc - iseq.body.param.lead_num) - calling.argc = iseq.body.param.lead_num # simply truncate arguments - end - else # not used yet - asm.incr_counter(:invokeblock_iseq_arity) - return CantCompile - end - end - - return 0 - else - return jit_setup_parameters_complex(jit, ctx, asm, calling.flags, calling.argc, iseq, arg_setup_type:) - end - end - - # setup_parameters_complex (ISEQ only) - # @param jit [RubyVM::RJIT::JITState] - # @param ctx [RubyVM::RJIT::Context] - # @param asm [RubyVM::RJIT::Assembler] - def jit_setup_parameters_complex(jit, ctx, asm, flags, argc, iseq, arg_setup_type: nil) - min_argc = iseq.body.param.lead_num + iseq.body.param.post_num - max_argc = (iseq.body.param.flags.has_rest == false) ? min_argc + iseq.body.param.opt_num : C::UNLIMITED_ARGUMENTS - kw_flag = flags & (C::VM_CALL_KWARG | C::VM_CALL_KW_SPLAT | C::VM_CALL_KW_SPLAT_MUT) - opt_pc = 0 - keyword_hash = nil - flag_keyword_hash = nil - given_argc = argc - - if kw_flag & C::VM_CALL_KWARG != 0 - asm.incr_counter(:send_iseq_complex_kwarg) - return CantCompile - end - - if flags & C::VM_CALL_ARGS_SPLAT != 0 && flags & C::VM_CALL_KW_SPLAT != 0 - asm.incr_counter(:send_iseq_complex_kw_splat) - return CantCompile - elsif flags & C::VM_CALL_ARGS_SPLAT != 0 - # Lazily handle splat in jit_call_iseq_setup_normal - else - if argc > 0 && kw_flag & C::VM_CALL_KW_SPLAT != 0 - asm.incr_counter(:send_iseq_complex_kw_splat) - return CantCompile - end - end - - if flag_keyword_hash && C.RB_TYPE_P(flag_keyword_hash, C::RUBY_T_HASH) - raise NotImplementedError # unreachable - end - - if kw_flag != 0 && iseq.body.param.flags.accepts_no_kwarg - asm.incr_counter(:send_iseq_complex_accepts_no_kwarg) - return CantCompile - end - - case arg_setup_type - when :arg_setup_block - asm.incr_counter(:send_iseq_complex_arg_setup_block) - return CantCompile - end - - if given_argc < min_argc - asm.incr_counter(:send_iseq_complex_arity) - return CantCompile - end - - if given_argc > max_argc && max_argc != C::UNLIMITED_ARGUMENTS - asm.incr_counter(:send_iseq_complex_arity) - return CantCompile - end - - if iseq.body.param.flags.has_lead - asm.incr_counter(:send_iseq_complex_has_lead) - return CantCompile - end - - if iseq.body.param.flags.has_rest || iseq.body.param.flags.has_post - asm.incr_counter(iseq.body.param.flags.has_rest ? :send_iseq_complex_has_rest : :send_iseq_complex_has_post) - return CantCompile - end - - if iseq.body.param.flags.has_post - asm.incr_counter(:send_iseq_complex_has_post) - return CantCompile - end - - if iseq.body.param.flags.has_opt - asm.incr_counter(:send_iseq_complex_has_opt) - return CantCompile - end - - if iseq.body.param.flags.has_rest - asm.incr_counter(:send_iseq_complex_has_rest) - return CantCompile - end - - if iseq.body.param.flags.has_kw - asm.incr_counter(:send_iseq_complex_has_kw) - return CantCompile - elsif iseq.body.param.flags.has_kwrest - asm.incr_counter(:send_iseq_complex_has_kwrest) - return CantCompile - elsif !keyword_hash.nil? && keyword_hash.size > 0 # && arg_setup_type == :arg_setup_method - raise NotImplementedError # unreachable - end - - if iseq.body.param.flags.has_block - if iseq.body.local_iseq.to_i == iseq.to_i - # Do nothing - else - asm.incr_counter(:send_iseq_complex_has_block) - return CantCompile - end - end - - return opt_pc - end - # CALLER_SETUP_ARG: Return CantCompile if not supported # @param jit [RubyVM::RJIT::JITState] # @param ctx [RubyVM::RJIT::Context] @@ -5243,7 +4975,7 @@ module RubyVM::RJIT return CantCompile elsif flags & C::VM_CALL_ARGS_SPLAT != 0 if splat - # Lazily handle splat in jit_call_iseq_setup_normal, jit_call_cfunc_with_frame + # Lazily handle splat in jit_call_cfunc_with_frame else # splat is not supported in this path asm.incr_counter(:send_args_splat) |