Implement branchif
This commit is contained in:
parent
9bce848b4c
commit
1b0fbd137f
Notes:
git
2023-03-06 07:30:05 +00:00
@ -23,7 +23,7 @@ module RubyVM::MJIT
|
||||
asm.incr_counter(:mjit_insns_count)
|
||||
asm.comment("Insn: #{insn.name}")
|
||||
|
||||
# 30/101
|
||||
# 31/101
|
||||
case insn.name
|
||||
when :nop then nop(jit, ctx, asm)
|
||||
# getlocal
|
||||
@ -88,7 +88,7 @@ module RubyVM::MJIT
|
||||
when :leave then leave(jit, ctx, asm)
|
||||
# throw
|
||||
when :jump then jump(jit, ctx, asm)
|
||||
# branchif
|
||||
when :branchif then branchif(jit, ctx, asm)
|
||||
when :branchunless then branchunless(jit, ctx, asm)
|
||||
# branchnil
|
||||
# once
|
||||
@ -342,7 +342,7 @@ module RubyVM::MJIT
|
||||
# @param asm [RubyVM::MJIT::Assembler]
|
||||
def jump(jit, ctx, asm)
|
||||
# Check for interrupts, but only on backward branches that may create loops
|
||||
jump_offset = jit.operand(0)
|
||||
jump_offset = jit.operand(0, signed: true)
|
||||
if jump_offset < 0
|
||||
jit_check_ints(jit, ctx, asm)
|
||||
end
|
||||
@ -352,14 +352,64 @@ module RubyVM::MJIT
|
||||
EndBlock
|
||||
end
|
||||
|
||||
# branchif
|
||||
# @param jit [RubyVM::MJIT::JITState]
|
||||
# @param ctx [RubyVM::MJIT::Context]
|
||||
# @param asm [RubyVM::MJIT::Assembler]
|
||||
def branchif(jit, ctx, asm)
|
||||
# Check for interrupts, but only on backward branches that may create loops
|
||||
jump_offset = jit.operand(0, signed: true)
|
||||
if jump_offset < 0
|
||||
jit_check_ints(jit, ctx, asm)
|
||||
end
|
||||
|
||||
# TODO: skip check for known truthy
|
||||
|
||||
# This `test` sets ZF only for Qnil and Qfalse, which let jz jump.
|
||||
val = ctx.stack_pop
|
||||
asm.test(val, ~Qnil)
|
||||
|
||||
# Set stubs
|
||||
branch_stub = BranchStub.new(
|
||||
iseq: jit.iseq,
|
||||
shape: Default,
|
||||
target0: BranchTarget.new(ctx:, pc: jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)), # branch target
|
||||
target1: BranchTarget.new(ctx:, pc: jit.pc + C.VALUE.size * jit.insn.len), # fallthrough
|
||||
)
|
||||
branch_stub.target0.address = Assembler.new.then do |ocb_asm|
|
||||
@exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
|
||||
@ocb.write(ocb_asm)
|
||||
end
|
||||
branch_stub.target1.address = Assembler.new.then do |ocb_asm|
|
||||
@exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, false)
|
||||
@ocb.write(ocb_asm)
|
||||
end
|
||||
|
||||
# Jump to target0 on jnz
|
||||
branch_stub.compile = proc do |branch_asm|
|
||||
branch_asm.comment("branchif #{branch_stub.shape}")
|
||||
branch_asm.stub(branch_stub) do
|
||||
case branch_stub.shape
|
||||
in Default
|
||||
branch_asm.jnz(branch_stub.target0.address)
|
||||
branch_asm.jmp(branch_stub.target1.address)
|
||||
in Next0
|
||||
branch_asm.jz(branch_stub.target1.address)
|
||||
in Next1
|
||||
branch_asm.jnz(branch_stub.target0.address)
|
||||
end
|
||||
end
|
||||
end
|
||||
branch_stub.compile.call(asm)
|
||||
|
||||
EndBlock
|
||||
end
|
||||
|
||||
# @param jit [RubyVM::MJIT::JITState]
|
||||
# @param ctx [RubyVM::MJIT::Context]
|
||||
# @param asm [RubyVM::MJIT::Assembler]
|
||||
def branchunless(jit, ctx, asm)
|
||||
# Check for interrupts, but only on backward branches that may create loops
|
||||
jump_offset = jit.operand(0)
|
||||
jump_offset = jit.operand(0, signed: true)
|
||||
if jump_offset < 0
|
||||
jit_check_ints(jit, ctx, asm)
|
||||
end
|
||||
|
@ -12,8 +12,9 @@ module RubyVM::MJIT
|
||||
Compiler.decode_insn(C.VALUE.new(pc).*)
|
||||
end
|
||||
|
||||
def operand(index)
|
||||
C.VALUE.new(pc)[index + 1]
|
||||
def operand(index, signed: false)
|
||||
addr = pc + (index + 1) * Fiddle::SIZEOF_VOIDP
|
||||
Fiddle::Pointer.new(addr)[0, Fiddle::SIZEOF_VOIDP].unpack(signed ? 'q' : 'Q')[0]
|
||||
end
|
||||
|
||||
def at_current_insn?
|
||||
|
Loading…
x
Reference in New Issue
Block a user