2022-12-30 21:27:12 -08:00
|
|
|
module RubyVM::MJIT
|
|
|
|
class ExitCompiler
|
2022-12-31 13:41:32 -08:00
|
|
|
def initialize
|
|
|
|
# TODO: Use GC offsets
|
|
|
|
@gc_refs = []
|
|
|
|
end
|
2022-12-30 21:27:12 -08:00
|
|
|
|
2023-01-02 14:11:06 -08:00
|
|
|
# Used for invalidating a block on entry.
|
|
|
|
# @param pc [Integer]
|
|
|
|
# @param asm [RubyVM::MJIT::Assembler]
|
|
|
|
def compile_entry_exit(pc, asm, cause:)
|
|
|
|
# Increment per-insn exit counter
|
2023-01-03 23:51:37 -08:00
|
|
|
incr_insn_exit(pc, asm)
|
2023-01-02 14:11:06 -08:00
|
|
|
|
|
|
|
# TODO: Saving pc and sp may be needed later
|
|
|
|
|
|
|
|
# Restore callee-saved registers
|
|
|
|
asm.comment("#{cause}: entry exit")
|
|
|
|
asm.pop(SP)
|
|
|
|
asm.pop(EC)
|
|
|
|
asm.pop(CFP)
|
|
|
|
|
|
|
|
asm.mov(:rax, Qundef)
|
|
|
|
asm.ret
|
|
|
|
end
|
|
|
|
|
2023-01-07 21:24:30 -08:00
|
|
|
# @param ocb [CodeBlock]
|
|
|
|
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
|
|
|
|
|
2022-12-30 21:27:12 -08:00
|
|
|
# @param jit [RubyVM::MJIT::JITState]
|
|
|
|
# @param ctx [RubyVM::MJIT::Context]
|
2022-12-30 22:16:07 -08:00
|
|
|
# @param asm [RubyVM::MJIT::Assembler]
|
2023-01-02 14:11:06 -08:00
|
|
|
def compile_side_exit(jit, ctx, asm)
|
|
|
|
# Increment per-insn exit counter
|
2023-01-03 23:51:37 -08:00
|
|
|
incr_insn_exit(jit.pc, asm)
|
2022-12-30 21:27:12 -08:00
|
|
|
|
2022-12-31 13:41:32 -08:00
|
|
|
# Fix pc/sp offsets for the interpreter
|
2023-01-02 22:53:14 -08:00
|
|
|
save_pc_and_sp(jit, ctx.dup, asm) # dup to avoid sp_offset update
|
2022-12-30 21:27:12 -08:00
|
|
|
|
|
|
|
# Restore callee-saved registers
|
2023-01-02 22:53:14 -08:00
|
|
|
asm.comment("exit to interpreter on #{pc_to_insn(jit.pc).name}")
|
2022-12-30 21:27:12 -08:00
|
|
|
asm.pop(SP)
|
2022-12-31 14:14:53 -08:00
|
|
|
asm.pop(EC)
|
|
|
|
asm.pop(CFP)
|
2022-12-30 21:27:12 -08:00
|
|
|
|
|
|
|
asm.mov(:rax, Qundef)
|
|
|
|
asm.ret
|
|
|
|
end
|
2022-12-31 13:41:32 -08:00
|
|
|
|
2023-01-04 00:12:16 -08:00
|
|
|
# @param ctx [RubyVM::MJIT::Context]
|
2022-12-31 13:41:32 -08:00
|
|
|
# @param asm [RubyVM::MJIT::Assembler]
|
2023-01-07 13:21:14 -08:00
|
|
|
# @param block_stub [RubyVM::MJIT::BlockStub]
|
2023-01-07 21:24:30 -08:00
|
|
|
def compile_block_stub(ctx, asm, block_stub)
|
2023-01-07 13:21:14 -08:00
|
|
|
# Call rb_mjit_block_stub_hit
|
|
|
|
asm.comment("block stub hit: #{block_stub.iseq.body.location.label}@#{C.rb_iseq_path(block_stub.iseq)}:#{iseq_lineno(block_stub.iseq, block_stub.pc)}")
|
|
|
|
asm.mov(:rdi, to_value(block_stub))
|
|
|
|
asm.mov(:esi, ctx.sp_offset)
|
|
|
|
asm.call(C.rb_mjit_block_stub_hit)
|
|
|
|
|
|
|
|
# Jump to the address returned by rb_mjit_stub_hit
|
|
|
|
asm.jmp(:rax)
|
|
|
|
end
|
2022-12-31 13:41:32 -08:00
|
|
|
|
2023-01-07 13:21:14 -08:00
|
|
|
# @param jit [RubyVM::MJIT::JITState]
|
|
|
|
# @param ctx [RubyVM::MJIT::Context]
|
|
|
|
# @param asm [RubyVM::MJIT::Assembler]
|
|
|
|
# @param branch_stub [RubyVM::MJIT::BranchStub]
|
2023-02-07 00:17:13 -08:00
|
|
|
# @param target0_p [TrueClass,FalseClass]
|
|
|
|
def compile_branch_stub(jit, ctx, asm, branch_stub, target0_p)
|
2023-01-07 13:21:14 -08:00
|
|
|
# Call rb_mjit_branch_stub_hit
|
2023-02-07 00:17:13 -08:00
|
|
|
asm.comment("branch stub hit: #{branch_stub.iseq.body.location.label}@#{C.rb_iseq_path(branch_stub.iseq)}:#{iseq_lineno(branch_stub.iseq, target0_p ? branch_stub.target0.pc : branch_stub.target1.pc)}")
|
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-01-07 13:21:14 -08:00
|
|
|
asm.call(C.rb_mjit_branch_stub_hit)
|
2022-12-31 13:41:32 -08:00
|
|
|
|
|
|
|
# Jump to the address returned by rb_mjit_stub_hit
|
|
|
|
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-01-03 23:51:37 -08:00
|
|
|
# @param asm [RubyVM::MJIT::Assembler]
|
|
|
|
def incr_insn_exit(pc, asm)
|
2023-01-02 14:11:06 -08:00
|
|
|
if C.mjit_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}")
|
|
|
|
asm.mov(:rax, (C.mjit_insn_exits + insn.bin).to_i)
|
|
|
|
asm.add([:rax], 1) # TODO: lock
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-12-31 13:41:32 -08:00
|
|
|
# @param jit [RubyVM::MJIT::JITState]
|
|
|
|
# @param ctx [RubyVM::MJIT::Context]
|
|
|
|
# @param asm [RubyVM::MJIT::Assembler]
|
|
|
|
def save_pc_and_sp(jit, ctx, asm)
|
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")
|
2022-12-31 13:41:32 -08:00
|
|
|
asm.mov(:rax, jit.pc) # rax = jit.pc
|
|
|
|
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
|
|
|
|
ctx.sp_offset = 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_value(obj)
|
|
|
|
@gc_refs << obj
|
|
|
|
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)
|
|
|
|
end
|
2022-12-30 21:27:12 -08:00
|
|
|
end
|
|
|
|
end
|