зеркало из https://github.com/github/ruby.git
Move modules around
This commit is contained in:
Родитель
6fc336fedc
Коммит
d9c2eb6f42
|
@ -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
|
|
@ -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,47 +1,70 @@
|
|||
require 'mjit/x86_64/assembler'
|
||||
require 'mjit/insn_compiler'
|
||||
require 'mjit/instruction'
|
||||
require 'mjit/x86_assembler'
|
||||
|
||||
class RubyVM::MJIT::Compiler
|
||||
# MJIT internals
|
||||
Assembler = RubyVM::MJIT::Assembler
|
||||
C = RubyVM::MJIT::C
|
||||
module RubyVM::MJIT
|
||||
# Compilation status
|
||||
KeepCompiling = :keep_compiling
|
||||
CantCompile = :cant_compile
|
||||
EndBlock = :end_block
|
||||
|
||||
# Ruby constants
|
||||
Qundef = Fiddle::Qundef
|
||||
class Compiler
|
||||
# Ruby constants
|
||||
Qundef = Fiddle::Qundef
|
||||
|
||||
attr_accessor :write_pos
|
||||
attr_accessor :write_pos
|
||||
|
||||
# @param mem_block [Integer] JIT buffer address
|
||||
def initialize(mem_block)
|
||||
@mem_block = mem_block
|
||||
@write_pos = 0
|
||||
end
|
||||
# @param mem_block [Integer] JIT buffer address
|
||||
def initialize(mem_block)
|
||||
@mem_block = mem_block
|
||||
@write_pos = 0
|
||||
@insn_compiler = InsnCompiler.new
|
||||
end
|
||||
|
||||
# @param iseq [RubyVM::MJIT::CPointer::Struct]
|
||||
def compile(iseq)
|
||||
return if iseq.body.location.label == '<main>'
|
||||
iseq.body.jit_func = compile_iseq(iseq)
|
||||
end
|
||||
# @param iseq [RubyVM::MJIT::CPointer::Struct]
|
||||
def compile(iseq)
|
||||
return if iseq.body.location.label == '<main>'
|
||||
iseq.body.jit_func = compile_iseq(iseq)
|
||||
rescue Exception => e
|
||||
# TODO: check --mjit-verbose
|
||||
$stderr.puts e.full_message
|
||||
end
|
||||
|
||||
def write_addr
|
||||
@mem_block + @write_pos
|
||||
end
|
||||
def write_addr
|
||||
@mem_block + @write_pos
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
# ec -> RDI, cfp -> RSI
|
||||
def compile_iseq(iseq)
|
||||
addr = write_addr
|
||||
asm = Assembler.new
|
||||
# ec -> RDI, cfp -> RSI
|
||||
def compile_iseq(iseq)
|
||||
addr = write_addr
|
||||
asm = X86Assembler.new
|
||||
|
||||
# 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)
|
||||
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
|
||||
|
||||
# return a value
|
||||
asm.mov(:rax, 7)
|
||||
asm.ret
|
||||
asm.compile(self)
|
||||
addr
|
||||
end
|
||||
|
||||
asm.compile(self)
|
||||
addr
|
||||
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
|
||||
|
|
|
@ -35,6 +35,4 @@ module RubyVM::MJIT # :nodoc: all
|
|||
),
|
||||
% end
|
||||
}
|
||||
|
||||
private_constant(*constants)
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче