ruby/lib/ruby_vm/mjit/exit_compiler.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

106 lines
2.9 KiB
Ruby
Raw Normal View History

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
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)
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
# @param jit [RubyVM::MJIT::JITState]
# @param asm [RubyVM::MJIT::Assembler]
# @param stub [RubyVM::MJIT::BlockStub]
def compile_jump_stub(jit, asm, stub)
case stub
when BlockStub
asm.comment("block stub hit: #{stub.iseq.body.location.label}@#{C.rb_iseq_path(stub.iseq)}:#{stub.iseq.body.location.first_lineno}")
else
raise "unexpected stub object: #{stub.inspect}"
end
# Call rb_mjit_stub_hit
asm.mov(:rdi, to_value(stub))
asm.call(C.rb_mjit_stub_hit)
# 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?)
2022-12-31 13:41:32 -08:00
asm.comment("save pc #{'and sp' if ctx.sp_offset != 0}")
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
2022-12-30 21:27:12 -08:00
end
end