Move modules around
This commit is contained in:
parent
6fc336fedc
commit
d9c2eb6f42
19
lib/mjit/insn_compiler.rb
Normal file
19
lib/mjit/insn_compiler.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
module RubyVM::MJIT
|
||||||
|
class InsnCompiler
|
||||||
|
def compile_putnil(_asm)
|
||||||
|
# TODO
|
||||||
|
KeepCompiling
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile_leave(asm)
|
||||||
|
# pop the current frame (ec->cfp++)
|
||||||
|
asm.add(:rsi, C.rb_control_frame_t.size)
|
||||||
|
asm.mov([:rdi, C.rb_execution_context_t.offsetof(:cfp)], :rsi)
|
||||||
|
|
||||||
|
# return a value
|
||||||
|
asm.mov(:rax, 7)
|
||||||
|
asm.ret
|
||||||
|
EndBlock
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,60 +0,0 @@
|
|||||||
class RubyVM::MJIT::Assembler
|
|
||||||
ByteWriter = RubyVM::MJIT::CType::Immediate.parse('char')
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@bytes = []
|
|
||||||
end
|
|
||||||
|
|
||||||
def compile(compiler) = with_dump_disasm(compiler) do
|
|
||||||
RubyVM::MJIT::C.mjit_mark_writable
|
|
||||||
write_bytes(compiler.write_addr, @bytes)
|
|
||||||
RubyVM::MJIT::C.mjit_mark_executable
|
|
||||||
|
|
||||||
compiler.write_pos += @bytes.size
|
|
||||||
@bytes.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
def add(_reg, imm)
|
|
||||||
# REX.W [83] RSI ib
|
|
||||||
@bytes.push(0x48, 0x83, 0xc6, imm)
|
|
||||||
end
|
|
||||||
|
|
||||||
def mov(reg, val)
|
|
||||||
case reg
|
|
||||||
when :rax
|
|
||||||
# REX.W [C7] RAX imm32
|
|
||||||
@bytes.push(0x48, 0xc7, 0xc0, val, 0x00, 0x00, 0x00)
|
|
||||||
else
|
|
||||||
# REX.W [89] [rdi+val],rsi
|
|
||||||
@bytes.push(0x48, 0x89, 0x77, reg.last)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ret
|
|
||||||
# Near return
|
|
||||||
# [C3]
|
|
||||||
@bytes.push(0xc3)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def with_dump_disasm(compiler)
|
|
||||||
from = compiler.write_addr
|
|
||||||
yield
|
|
||||||
to = compiler.write_addr
|
|
||||||
if RubyVM::MJIT::C.mjit_opts.dump_disasm && from < to
|
|
||||||
RubyVM::MJIT::C.dump_disasm(from, to).each do |address, mnemonic, op_str|
|
|
||||||
puts " 0x#{"%p" % address}: #{mnemonic} #{op_str}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def write_bytes(addr, bytes)
|
|
||||||
writer = ByteWriter.new(addr)
|
|
||||||
# If you pack bytes containing \x00, Ruby fails to recognize bytes after \x00.
|
|
||||||
# So writing byte by byte to avoid hitting that situation.
|
|
||||||
bytes.each_with_index do |byte, index|
|
|
||||||
writer[index] = byte
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
62
lib/mjit/x86_assembler.rb
Normal file
62
lib/mjit/x86_assembler.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
module RubyVM::MJIT
|
||||||
|
class X86Assembler
|
||||||
|
ByteWriter = CType::Immediate.parse('char')
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@bytes = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile(compiler) = with_dump_disasm(compiler) do
|
||||||
|
C.mjit_mark_writable
|
||||||
|
write_bytes(compiler.write_addr, @bytes)
|
||||||
|
C.mjit_mark_executable
|
||||||
|
|
||||||
|
compiler.write_pos += @bytes.size
|
||||||
|
@bytes.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def add(_reg, imm)
|
||||||
|
# REX.W [83] RSI ib
|
||||||
|
@bytes.push(0x48, 0x83, 0xc6, imm)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mov(reg, val)
|
||||||
|
case reg
|
||||||
|
when :rax
|
||||||
|
# REX.W [C7] RAX imm32
|
||||||
|
@bytes.push(0x48, 0xc7, 0xc0, val, 0x00, 0x00, 0x00)
|
||||||
|
else
|
||||||
|
# REX.W [89] [rdi+val],rsi
|
||||||
|
@bytes.push(0x48, 0x89, 0x77, reg.last)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ret
|
||||||
|
# Near return
|
||||||
|
# [C3]
|
||||||
|
@bytes.push(0xc3)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def with_dump_disasm(compiler)
|
||||||
|
from = compiler.write_addr
|
||||||
|
yield
|
||||||
|
to = compiler.write_addr
|
||||||
|
if C.mjit_opts.dump_disasm && from < to
|
||||||
|
C.dump_disasm(from, to).each do |address, mnemonic, op_str|
|
||||||
|
puts " 0x#{"%p" % address}: #{mnemonic} #{op_str}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_bytes(addr, bytes)
|
||||||
|
writer = ByteWriter.new(addr)
|
||||||
|
# If you pack bytes containing \x00, Ruby fails to recognize bytes after \x00.
|
||||||
|
# So writing byte by byte to avoid hitting that situation.
|
||||||
|
bytes.each_with_index do |byte, index|
|
||||||
|
writer[index] = byte
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,10 +1,14 @@
|
|||||||
require 'mjit/x86_64/assembler'
|
require 'mjit/insn_compiler'
|
||||||
|
require 'mjit/instruction'
|
||||||
|
require 'mjit/x86_assembler'
|
||||||
|
|
||||||
class RubyVM::MJIT::Compiler
|
module RubyVM::MJIT
|
||||||
# MJIT internals
|
# Compilation status
|
||||||
Assembler = RubyVM::MJIT::Assembler
|
KeepCompiling = :keep_compiling
|
||||||
C = RubyVM::MJIT::C
|
CantCompile = :cant_compile
|
||||||
|
EndBlock = :end_block
|
||||||
|
|
||||||
|
class Compiler
|
||||||
# Ruby constants
|
# Ruby constants
|
||||||
Qundef = Fiddle::Qundef
|
Qundef = Fiddle::Qundef
|
||||||
|
|
||||||
@ -14,12 +18,16 @@ class RubyVM::MJIT::Compiler
|
|||||||
def initialize(mem_block)
|
def initialize(mem_block)
|
||||||
@mem_block = mem_block
|
@mem_block = mem_block
|
||||||
@write_pos = 0
|
@write_pos = 0
|
||||||
|
@insn_compiler = InsnCompiler.new
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param iseq [RubyVM::MJIT::CPointer::Struct]
|
# @param iseq [RubyVM::MJIT::CPointer::Struct]
|
||||||
def compile(iseq)
|
def compile(iseq)
|
||||||
return if iseq.body.location.label == '<main>'
|
return if iseq.body.location.label == '<main>'
|
||||||
iseq.body.jit_func = compile_iseq(iseq)
|
iseq.body.jit_func = compile_iseq(iseq)
|
||||||
|
rescue Exception => e
|
||||||
|
# TODO: check --mjit-verbose
|
||||||
|
$stderr.puts e.full_message
|
||||||
end
|
end
|
||||||
|
|
||||||
def write_addr
|
def write_addr
|
||||||
@ -31,17 +39,32 @@ class RubyVM::MJIT::Compiler
|
|||||||
# ec -> RDI, cfp -> RSI
|
# ec -> RDI, cfp -> RSI
|
||||||
def compile_iseq(iseq)
|
def compile_iseq(iseq)
|
||||||
addr = write_addr
|
addr = write_addr
|
||||||
asm = Assembler.new
|
asm = X86Assembler.new
|
||||||
|
|
||||||
# pop the current frame (ec->cfp++)
|
index = 0
|
||||||
asm.add(:rsi, C.rb_control_frame_t.size)
|
while index < iseq.body.iseq_size
|
||||||
asm.mov([:rdi, C.rb_execution_context_t.offsetof(:cfp)], :rsi)
|
insn = decode_insn(iseq.body.iseq_encoded[index])
|
||||||
|
status = compile_insn(asm, insn)
|
||||||
# return a value
|
if status == EndBlock
|
||||||
asm.mov(:rax, 7)
|
break
|
||||||
asm.ret
|
end
|
||||||
|
index += insn.len
|
||||||
|
end
|
||||||
|
|
||||||
asm.compile(self)
|
asm.compile(self)
|
||||||
addr
|
addr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def compile_insn(asm, insn)
|
||||||
|
case insn.name
|
||||||
|
when :putnil then @insn_compiler.compile_putnil(asm)
|
||||||
|
when :leave then @insn_compiler.compile_leave(asm)
|
||||||
|
else raise NotImplementedError, "insn '#{insn.name}' is not supported yet"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def decode_insn(encoded)
|
||||||
|
INSNS.fetch(C.rb_vm_insn_decode(encoded))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -35,6 +35,4 @@ module RubyVM::MJIT # :nodoc: all
|
|||||||
),
|
),
|
||||||
% end
|
% end
|
||||||
}
|
}
|
||||||
|
|
||||||
private_constant(*constants)
|
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user