diff options
author | Takashi Kokubun <takashikkbn@gmail.com> | 2022-12-17 13:39:35 -0800 |
---|---|---|
committer | Takashi Kokubun <takashikkbn@gmail.com> | 2023-03-05 22:11:20 -0800 |
commit | d9c2eb6f4288e5a0b03222854b4ad62c2047cd2b (patch) | |
tree | 2c17f14c8b6230dec9a5a2b58dc9ccf2f672d23d | |
parent | 6fc336fedcbf58cceedd272ecf1ac2f725662f73 (diff) | |
download | ruby-d9c2eb6f4288e5a0b03222854b4ad62c2047cd2b.tar.gz |
Move modules around
-rw-r--r-- | lib/mjit/insn_compiler.rb | 19 | ||||
-rw-r--r-- | lib/mjit/x86_64/assembler.rb | 60 | ||||
-rw-r--r-- | lib/mjit/x86_assembler.rb | 62 | ||||
-rw-r--r-- | lib/ruby_vm/mjit/compiler.rb | 91 | ||||
-rw-r--r-- | tool/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb | 2 |
5 files changed, 138 insertions, 96 deletions
diff --git a/lib/mjit/insn_compiler.rb b/lib/mjit/insn_compiler.rb new file mode 100644 index 0000000000..c32dd808db --- /dev/null +++ b/lib/mjit/insn_compiler.rb @@ -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 diff --git a/lib/mjit/x86_64/assembler.rb b/lib/mjit/x86_64/assembler.rb deleted file mode 100644 index be6480bba7..0000000000 --- a/lib/mjit/x86_64/assembler.rb +++ /dev/null @@ -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 diff --git a/lib/mjit/x86_assembler.rb b/lib/mjit/x86_assembler.rb new file mode 100644 index 0000000000..b89438f552 --- /dev/null +++ b/lib/mjit/x86_assembler.rb @@ -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 diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb index 4b980c1400..1dfa3a3592 100644 --- a/lib/ruby_vm/mjit/compiler.rb +++ b/lib/ruby_vm/mjit/compiler.rb @@ -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 = X86Assembler.new - # ec -> RDI, cfp -> RSI - def compile_iseq(iseq) - addr = write_addr - asm = Assembler.new + 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 - # 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) + asm.compile(self) + addr + end - # return a value - asm.mov(:rax, 7) - asm.ret + 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 - asm.compile(self) - addr + def decode_insn(encoded) + INSNS.fetch(C.rb_vm_insn_decode(encoded)) + end end end diff --git a/tool/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb b/tool/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb index 4b20e896a2..38b9c1f92e 100644 --- a/tool/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb +++ b/tool/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb @@ -35,6 +35,4 @@ module RubyVM::MJIT # :nodoc: all ), % end } - - private_constant(*constants) end |