mirror of
https://github.com/ruby/ruby.git
synced 2025-08-27 06:56:13 +02:00
Implement initial side exit
This commit is contained in:
parent
e750e1e3ee
commit
b99d62bf92
3 changed files with 101 additions and 43 deletions
|
@ -4,9 +4,6 @@ module RubyVM::MJIT
|
||||||
# sp: rbx
|
# sp: rbx
|
||||||
# scratch regs: rax
|
# scratch regs: rax
|
||||||
class InsnCompiler
|
class InsnCompiler
|
||||||
# Ruby constants
|
|
||||||
Qnil = Fiddle::Qnil
|
|
||||||
|
|
||||||
def putnil(asm)
|
def putnil(asm)
|
||||||
asm.mov([:rbx], Qnil)
|
asm.mov([:rbx], Qnil)
|
||||||
KeepCompiling
|
KeepCompiling
|
||||||
|
|
|
@ -27,7 +27,7 @@ module RubyVM::MJIT
|
||||||
def add(dst, src)
|
def add(dst, src)
|
||||||
case [dst, src]
|
case [dst, src]
|
||||||
# ADD r/m64, imm8
|
# ADD r/m64, imm8
|
||||||
in [Symbol => dst_reg, Integer => src_imm] if r_reg?(dst_reg) && src_imm <= 0xff
|
in [Symbol => dst_reg, Integer => src_imm] if r64?(dst_reg) && imm8?(src_imm)
|
||||||
# REX.W + 83 /0 ib
|
# REX.W + 83 /0 ib
|
||||||
# MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
|
# MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
|
||||||
insn(
|
insn(
|
||||||
|
@ -44,7 +44,7 @@ module RubyVM::MJIT
|
||||||
def mov(dst, src)
|
def mov(dst, src)
|
||||||
case [dst, src]
|
case [dst, src]
|
||||||
# MOV r/m64, imm32 (Mod 00)
|
# MOV r/m64, imm32 (Mod 00)
|
||||||
in [[Symbol => dst_reg], Integer => src_imm] if r_reg?(dst_reg)
|
in [[Symbol => dst_reg], Integer => src_imm] if r64?(dst_reg)
|
||||||
# REX.W + C7 /0 id
|
# REX.W + C7 /0 id
|
||||||
# MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
|
# MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
|
||||||
insn(
|
insn(
|
||||||
|
@ -54,7 +54,7 @@ module RubyVM::MJIT
|
||||||
imm: imm32(src_imm),
|
imm: imm32(src_imm),
|
||||||
)
|
)
|
||||||
# MOV r/m64, imm32 (Mod 11)
|
# MOV r/m64, imm32 (Mod 11)
|
||||||
in [Symbol => dst_reg, Integer => src_imm] if r_reg?(dst_reg)
|
in [Symbol => dst_reg, Integer => src_imm] if r64?(dst_reg) && imm32?(src_imm)
|
||||||
# REX.W + C7 /0 id
|
# REX.W + C7 /0 id
|
||||||
# MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
|
# MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
|
||||||
insn(
|
insn(
|
||||||
|
@ -63,8 +63,17 @@ module RubyVM::MJIT
|
||||||
mod_rm: mod_rm(mod: 0b11, rm: reg_code(dst_reg)), # Mod 11: reg
|
mod_rm: mod_rm(mod: 0b11, rm: reg_code(dst_reg)), # Mod 11: reg
|
||||||
imm: imm32(src_imm),
|
imm: imm32(src_imm),
|
||||||
)
|
)
|
||||||
|
# MOV r64, imm64
|
||||||
|
in [Symbol => dst_reg, Integer => src_imm] if r64?(dst_reg) && imm64?(src_imm)
|
||||||
|
# REX.W + B8+ rd io
|
||||||
|
# OI: Operand 1: opcode + rd (w), Operand 2: imm8/16/32/64
|
||||||
|
insn(
|
||||||
|
prefix: REX_W,
|
||||||
|
opcode: 0xb8 + reg_code(dst_reg),
|
||||||
|
imm: imm64(src_imm),
|
||||||
|
)
|
||||||
# MOV r/m64, r64
|
# MOV r/m64, r64
|
||||||
in [[Symbol => dst_reg, Integer => dst_offset], Symbol => src_reg] if r_reg?(dst_reg) && r_reg?(src_reg) && dst_offset <= 0xff
|
in [[Symbol => dst_reg, Integer => dst_offset], Symbol => src_reg] if r64?(dst_reg) && r64?(src_reg) && imm8?(dst_offset)
|
||||||
# REX.W + 89 /r
|
# REX.W + 89 /r
|
||||||
# MR: Operand 1: ModRM:r/m (w), Operand 2: ModRM:reg (r)
|
# MR: Operand 1: ModRM:r/m (w), Operand 2: ModRM:reg (r)
|
||||||
insn(
|
insn(
|
||||||
|
@ -74,7 +83,7 @@ module RubyVM::MJIT
|
||||||
disp: dst_offset,
|
disp: dst_offset,
|
||||||
)
|
)
|
||||||
# MOV r64, r/m64 (Mod 00)
|
# MOV r64, r/m64 (Mod 00)
|
||||||
in [Symbol => dst_reg, [Symbol => src_reg]] if r_reg?(dst_reg) && r_reg?(src_reg)
|
in [Symbol => dst_reg, [Symbol => src_reg]] if r64?(dst_reg) && r64?(src_reg)
|
||||||
# REX.W + 8B /r
|
# REX.W + 8B /r
|
||||||
# RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
|
# RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
|
||||||
insn(
|
insn(
|
||||||
|
@ -83,7 +92,7 @@ module RubyVM::MJIT
|
||||||
mod_rm: mod_rm(mod: 0b00, reg: reg_code(dst_reg), rm: reg_code(src_reg)), # Mod 00: [reg]
|
mod_rm: mod_rm(mod: 0b00, reg: reg_code(dst_reg), rm: reg_code(src_reg)), # Mod 00: [reg]
|
||||||
)
|
)
|
||||||
# MOV r64, r/m64 (Mod 01)
|
# MOV r64, r/m64 (Mod 01)
|
||||||
in [Symbol => dst_reg, [Symbol => src_reg, Integer => src_offset]] if r_reg?(dst_reg) && r_reg?(src_reg) && src_offset <= 0xff
|
in [Symbol => dst_reg, [Symbol => src_reg, Integer => src_offset]] if r64?(dst_reg) && r64?(src_reg) && imm8?(src_offset)
|
||||||
# REX.W + 8B /r
|
# REX.W + 8B /r
|
||||||
# RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
|
# RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
|
||||||
insn(
|
insn(
|
||||||
|
@ -166,27 +175,59 @@ module RubyVM::MJIT
|
||||||
|
|
||||||
# ib: 1 byte
|
# ib: 1 byte
|
||||||
def imm8(imm)
|
def imm8(imm)
|
||||||
if imm > 0xff
|
unless imm8?(imm)
|
||||||
raise ArgumentError, "unexpected imm8: #{imm}"
|
raise ArgumentError, "unexpected imm8: #{imm}"
|
||||||
end
|
end
|
||||||
[imm]
|
imm_bytes(imm, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
# id: 4 bytes
|
# id: 4 bytes
|
||||||
def imm32(imm)
|
def imm32(imm)
|
||||||
|
unless imm32?(imm)
|
||||||
|
raise ArgumentError, "unexpected imm32: #{imm}"
|
||||||
|
end
|
||||||
|
imm_bytes(imm, 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
# io: 8 bytes
|
||||||
|
def imm64(imm)
|
||||||
|
unless imm64?(imm)
|
||||||
|
raise ArgumentError, "unexpected imm64: #{imm}"
|
||||||
|
end
|
||||||
|
imm_bytes(imm, 8)
|
||||||
|
end
|
||||||
|
|
||||||
|
def imm_bytes(imm, num_bytes)
|
||||||
bytes = []
|
bytes = []
|
||||||
bits = imm
|
bits = imm
|
||||||
4.times do
|
num_bytes.times do
|
||||||
bytes << (bits & 0xff)
|
bytes << (bits & 0xff)
|
||||||
bits >>= 8
|
bits >>= 8
|
||||||
end
|
end
|
||||||
if bits != 0
|
if bits != 0
|
||||||
raise ArgumentError, "unexpected imm32: #{imm}"
|
raise ArgumentError, "unexpected imm with #{num_bytes} bytes: #{imm}"
|
||||||
end
|
end
|
||||||
bytes
|
bytes
|
||||||
end
|
end
|
||||||
|
|
||||||
def r_reg?(reg)
|
def imm8?(imm)
|
||||||
|
# TODO: consider negative values
|
||||||
|
imm <= 0xff
|
||||||
|
end
|
||||||
|
|
||||||
|
def imm32?(imm)
|
||||||
|
# TODO: consider negative values
|
||||||
|
# TODO: consider rejecting small values
|
||||||
|
imm <= 0xffff_ffff
|
||||||
|
end
|
||||||
|
|
||||||
|
def imm64?(imm)
|
||||||
|
# TODO: consider negative values
|
||||||
|
# TODO: consider rejecting small values
|
||||||
|
imm <= 0xffff_ffff_ffff_ffff
|
||||||
|
end
|
||||||
|
|
||||||
|
def r64?(reg)
|
||||||
reg.start_with?('r')
|
reg.start_with?('r')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,9 +4,13 @@ require 'mjit/x86_assembler'
|
||||||
|
|
||||||
module RubyVM::MJIT
|
module RubyVM::MJIT
|
||||||
# Compilation status
|
# Compilation status
|
||||||
KeepCompiling = :keep_compiling
|
KeepCompiling = :KeepCompiling
|
||||||
CantCompile = :cant_compile
|
CantCompile = :CantCompile
|
||||||
EndBlock = :end_block
|
EndBlock = :EndBlock
|
||||||
|
|
||||||
|
# Ruby constants
|
||||||
|
Qnil = Fiddle::Qnil
|
||||||
|
Qundef = Fiddle::Qundef
|
||||||
|
|
||||||
class Compiler
|
class Compiler
|
||||||
attr_accessor :write_pos
|
attr_accessor :write_pos
|
||||||
|
@ -36,32 +40,6 @@ module RubyVM::MJIT
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# ec: rdi
|
|
||||||
# cfp: rsi
|
|
||||||
def compile_prologue(asm)
|
|
||||||
asm.mov(:rbx, [:rsi, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
|
|
||||||
end
|
|
||||||
|
|
||||||
def compile_block(asm, iseq)
|
|
||||||
index = 0
|
|
||||||
while index < iseq.body.iseq_size
|
|
||||||
insn = decode_insn(iseq.body.iseq_encoded[index])
|
|
||||||
status = compile_insn(asm, insn)
|
|
||||||
if status == EndBlock
|
|
||||||
break
|
|
||||||
end
|
|
||||||
index += insn.len
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def compile_insn(asm, insn)
|
|
||||||
case insn.name
|
|
||||||
when :putnil then @insn_compiler.putnil(asm)
|
|
||||||
when :leave then @insn_compiler.leave(asm)
|
|
||||||
else raise NotImplementedError, "insn '#{insn.name}' is not supported yet"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def compile(asm)
|
def compile(asm)
|
||||||
start_addr = write_addr
|
start_addr = write_addr
|
||||||
|
|
||||||
|
@ -76,6 +54,48 @@ module RubyVM::MJIT
|
||||||
start_addr
|
start_addr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# ec: rdi
|
||||||
|
# cfp: rsi
|
||||||
|
def compile_prologue(asm)
|
||||||
|
asm.mov(:rbx, [:rsi, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile_block(asm, iseq)
|
||||||
|
index = 0
|
||||||
|
while index < iseq.body.iseq_size
|
||||||
|
insn = decode_insn(iseq.body.iseq_encoded[index])
|
||||||
|
case compile_insn(asm, insn)
|
||||||
|
when EndBlock
|
||||||
|
break
|
||||||
|
when CantCompile
|
||||||
|
compile_exit(asm, (iseq.body.iseq_encoded + index).to_i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
index += insn.len
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile_insn(asm, insn)
|
||||||
|
case insn.name
|
||||||
|
when :putnil then @insn_compiler.putnil(asm)
|
||||||
|
#when :leave then @insn_compiler.leave(asm)
|
||||||
|
else CantCompile
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile_exit(asm, exit_pc)
|
||||||
|
# update pc
|
||||||
|
asm.mov(:rax, exit_pc) # rax = exit_pc
|
||||||
|
asm.mov([:rsi, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax
|
||||||
|
|
||||||
|
# update sp (TODO: consider JIT state)
|
||||||
|
asm.add(:rbx, C.VALUE.size) # rbx += 1
|
||||||
|
asm.mov([:rsi, C.rb_control_frame_t.offsetof(:sp)], :rbx) # cfp->sp = rbx
|
||||||
|
|
||||||
|
asm.mov(:rax, Qundef)
|
||||||
|
asm.ret
|
||||||
|
end
|
||||||
|
|
||||||
def decode_insn(encoded)
|
def decode_insn(encoded)
|
||||||
INSNS.fetch(C.rb_vm_insn_decode(encoded))
|
INSNS.fetch(C.rb_vm_insn_decode(encoded))
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue