ruby/lib/ruby_vm/rjit/exit_compiler.rb

165 lines
4.8 KiB
Ruby
Raw Normal View History

2023-03-06 23:15:30 -08:00
module RubyVM::RJIT
2022-12-30 21:27:12 -08:00
class ExitCompiler
def initialize = freeze
2023-01-02 14:11:06 -08:00
# Used for invalidating a block on entry.
# @param pc [Integer]
2023-03-06 23:15:30 -08:00
# @param asm [RubyVM::RJIT::Assembler]
2023-02-08 10:24:13 -08:00
def compile_entry_exit(pc, ctx, asm, cause:)
# Fix pc/sp offsets for the interpreter
save_pc_and_sp(pc, ctx, asm, reset_sp_offset: false)
2023-01-02 14:11:06 -08:00
2023-03-12 13:55:39 -07:00
# Increment per-insn exit counter
count_insn_exit(pc, asm)
2023-01-02 14:11:06 -08:00
# Restore callee-saved registers
asm.comment("#{cause}: entry exit")
asm.pop(SP)
asm.pop(EC)
asm.pop(CFP)
2023-02-10 22:07:34 -08:00
asm.mov(C_RET, Qundef)
2023-01-02 14:11:06 -08:00
asm.ret
end
2023-02-10 11:43:53 -08:00
# Set to cfp->jit_return by default for leave insn
2023-03-06 23:15:30 -08:00
# @param asm [RubyVM::RJIT::Assembler]
2023-01-07 21:24:30 -08:00
def compile_leave_exit(asm)
2023-02-03 22:42:13 -08:00
asm.comment('default cfp->jit_return')
2023-01-07 21:24:30 -08:00
# Restore callee-saved registers
asm.pop(SP)
asm.pop(EC)
asm.pop(CFP)
# :rax is written by #leave
asm.ret
end
2023-02-10 11:43:53 -08:00
# Fire cfunc events on invalidation by TracePoint
2023-03-06 23:15:30 -08:00
# @param asm [RubyVM::RJIT::Assembler]
2023-02-10 11:43:53 -08:00
def compile_full_cfunc_return(asm)
# This chunk of code expects REG_EC to be filled properly and
# RAX to contain the return value of the C method.
asm.comment('full cfunc return')
2023-02-10 22:07:34 -08:00
asm.mov(C_ARGS[0], EC)
asm.mov(C_ARGS[1], :rax)
asm.call(C.rjit_full_cfunc_return)
2023-02-10 11:43:53 -08:00
# TODO: count the exit
# Restore callee-saved registers
asm.pop(SP)
asm.pop(EC)
asm.pop(CFP)
2023-02-10 22:07:34 -08:00
asm.mov(C_RET, Qundef)
2023-02-10 11:43:53 -08:00
asm.ret
end
2023-03-06 23:15:30 -08:00
# @param jit [RubyVM::RJIT::JITState]
# @param ctx [RubyVM::RJIT::Context]
# @param asm [RubyVM::RJIT::Assembler]
2023-02-16 22:29:58 -08:00
def compile_side_exit(pc, ctx, asm)
2022-12-31 13:41:32 -08:00
# Fix pc/sp offsets for the interpreter
2023-02-16 22:29:58 -08:00
save_pc_and_sp(pc, ctx.dup, asm) # dup to avoid sp_offset update
2022-12-30 21:27:12 -08:00
2023-03-12 13:55:39 -07:00
# Increment per-insn exit counter
count_insn_exit(pc, asm)
2022-12-30 21:27:12 -08:00
# Restore callee-saved registers
2023-02-16 22:29:58 -08:00
asm.comment("exit to interpreter on #{pc_to_insn(pc).name}")
2022-12-30 21:27:12 -08:00
asm.pop(SP)
asm.pop(EC)
asm.pop(CFP)
2022-12-30 21:27:12 -08:00
2023-02-10 22:07:34 -08:00
asm.mov(C_RET, Qundef)
2022-12-30 21:27:12 -08:00
asm.ret
end
2022-12-31 13:41:32 -08:00
2023-04-02 15:26:46 -07:00
# @param asm [RubyVM::RJIT::Assembler]
# @param entry_stub [RubyVM::RJIT::EntryStub]
def compile_entry_stub(asm, entry_stub)
# Call rb_rjit_entry_stub_hit
asm.comment('entry stub hit')
asm.mov(C_ARGS[0], to_value(entry_stub))
asm.call(C.rb_rjit_entry_stub_hit)
# Jump to the address returned by rb_rjit_entry_stub_hit
asm.jmp(:rax)
end
2023-03-06 23:15:30 -08:00
# @param ctx [RubyVM::RJIT::Context]
# @param asm [RubyVM::RJIT::Assembler]
# @param branch_stub [RubyVM::RJIT::BranchStub]
2023-02-07 00:17:13 -08:00
# @param target0_p [TrueClass,FalseClass]
2023-02-07 11:36:45 -08:00
def compile_branch_stub(ctx, asm, branch_stub, target0_p)
2023-03-06 23:17:25 -08:00
# Call rb_rjit_branch_stub_hit
2023-03-01 23:15:51 -08:00
iseq = branch_stub.iseq
if C.rjit_opts.dump_disasm && C.imemo_type_p(iseq, C.imemo_iseq) # Guard against ISEQ GC at random moments
2023-03-01 23:15:51 -08:00
asm.comment("branch stub hit: #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{iseq_lineno(iseq, target0_p ? branch_stub.target0.pc : branch_stub.target1.pc)}")
end
2023-01-07 13:21:14 -08:00
asm.mov(:rdi, to_value(branch_stub))
2023-01-04 00:12:16 -08:00
asm.mov(:esi, ctx.sp_offset)
2023-02-07 00:17:13 -08:00
asm.mov(:edx, target0_p ? 1 : 0)
2023-03-06 23:17:25 -08:00
asm.call(C.rb_rjit_branch_stub_hit)
2022-12-31 13:41:32 -08:00
2023-04-02 15:26:46 -07:00
# Jump to the address returned by rb_rjit_branch_stub_hit
2022-12-31 13:41:32 -08:00
asm.jmp(:rax)
end
private
2023-01-02 22:53:14 -08:00
def pc_to_insn(pc)
Compiler.decode_insn(C.VALUE.new(pc).*)
end
2023-01-02 14:11:06 -08:00
# @param pc [Integer]
2023-03-06 23:15:30 -08:00
# @param asm [RubyVM::RJIT::Assembler]
2023-03-12 13:55:39 -07:00
def count_insn_exit(pc, asm)
2023-03-06 23:17:25 -08:00
if C.rjit_opts.stats
2023-01-03 23:51:37 -08:00
insn = Compiler.decode_insn(C.VALUE.new(pc).*)
2023-01-02 14:11:06 -08:00
asm.comment("increment insn exit: #{insn.name}")
2023-03-06 23:17:25 -08:00
asm.mov(:rax, (C.rjit_insn_exits + insn.bin).to_i)
2023-01-02 14:11:06 -08:00
asm.add([:rax], 1) # TODO: lock
end
2023-03-12 13:55:39 -07:00
if C.rjit_opts.trace_exits
asm.comment('rjit_record_exit_stack')
asm.mov(C_ARGS[0], pc)
asm.call(C.rjit_record_exit_stack)
end
2023-01-02 14:11:06 -08:00
end
2023-03-06 23:15:30 -08:00
# @param jit [RubyVM::RJIT::JITState]
# @param ctx [RubyVM::RJIT::Context]
# @param asm [RubyVM::RJIT::Assembler]
2023-02-08 10:24:13 -08:00
def save_pc_and_sp(pc, ctx, asm, reset_sp_offset: true)
2023-01-02 14:11:06 -08:00
# Update pc (TODO: manage PC offset?)
2023-01-07 21:24:30 -08:00
asm.comment("save PC#{' and SP' if ctx.sp_offset != 0} to CFP")
2023-02-08 10:24:13 -08:00
asm.mov(:rax, pc) # rax = jit.pc
2022-12-31 13:41:32 -08:00
asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax
# Update sp
if ctx.sp_offset != 0
asm.add(SP, C.VALUE.size * ctx.sp_offset) # sp += stack_size
asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP) # cfp->sp = sp
2023-02-08 10:24:13 -08:00
if reset_sp_offset
ctx.sp_offset = 0
end
2022-12-31 13:41:32 -08:00
end
end
def to_value(obj)
2023-02-21 00:19:37 -08:00
GC_REFS << obj
2022-12-31 13:41:32 -08:00
C.to_value(obj)
end
2023-01-07 13:21:14 -08:00
def iseq_lineno(iseq, pc)
C.rb_iseq_line_no(iseq, (pc - iseq.body.iseq_encoded.to_i) / C.VALUE.size)
2023-02-10 15:23:57 -08:00
rescue RangeError # bignum too big to convert into `unsigned long long' (RangeError)
-1
2023-01-07 13:21:14 -08:00
end
2022-12-30 21:27:12 -08:00
end
end