diff --git a/lib/mjit/insn_compiler.rb b/lib/mjit/insn_compiler.rb index c6f88b37fb..4dbb19a96e 100644 --- a/lib/mjit/insn_compiler.rb +++ b/lib/mjit/insn_compiler.rb @@ -1,14 +1,21 @@ module RubyVM::MJIT + # ec: rdi + # cfp: rsi + # sp: rbx + # scratch regs: rax class InsnCompiler - def putnil(_asm) - # TODO + # Ruby constants + Qnil = Fiddle::Qnil + + def putnil(asm) + asm.mov([:rbx], Qnil) KeepCompiling end def 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) + asm.add(:rsi, C.rb_control_frame_t.size) # rsi = cfp + 1 + asm.mov([:rdi, C.rb_execution_context_t.offsetof(:cfp)], :rsi) # ec->cfp = rsi # return a value asm.mov(:rax, 1001) diff --git a/lib/mjit/x86_assembler.rb b/lib/mjit/x86_assembler.rb index 934bf071c7..bc447e7808 100644 --- a/lib/mjit/x86_assembler.rb +++ b/lib/mjit/x86_assembler.rb @@ -43,14 +43,24 @@ module RubyVM::MJIT def mov(dst, src) case [dst, src] - # MOV r/m64, imm32 + # MOV r/m64, imm32 (Mod 00) + in [[Symbol => dst_reg], Integer => src_imm] if r_reg?(dst_reg) + # REX.W + C7 /0 id + # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64 + insn( + prefix: REX_W, + opcode: 0xc7, + mod_rm: mod_rm(mod: 0b00, rm: reg_code(dst_reg)), # Mod 00: [reg] + imm: imm32(src_imm), + ) + # MOV r/m64, imm32 (Mod 11) in [Symbol => dst_reg, Integer => src_imm] if r_reg?(dst_reg) # REX.W + C7 /0 id # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64 insn( prefix: REX_W, opcode: 0xc7, - mod_rm: mod_rm(mod: 0b11, rm: reg_code(dst_reg)), + mod_rm: mod_rm(mod: 0b11, rm: reg_code(dst_reg)), # Mod 11: reg imm: imm32(src_imm), ) # MOV r/m64, r64 @@ -60,9 +70,19 @@ module RubyVM::MJIT insn( prefix: REX_W, opcode: 0x89, - mod_rm: mod_rm(mod: 0b01, reg: reg_code(src_reg), rm: reg_code(dst_reg)), # disp8 + mod_rm: mod_rm(mod: 0b01, reg: reg_code(src_reg), rm: reg_code(dst_reg)), # Mod 01: [reg]+disp8 disp: dst_offset, ) + # MOV r64, r/m64 + in [Symbol => dst_reg, [Symbol => src_reg, Integer => src_offset]] if r_reg?(dst_reg) && r_reg?(src_reg) && src_offset <= 0xff + # REX.W + 8B /r + # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r) + insn( + prefix: REX_W, + opcode: 0x8b, + mod_rm: mod_rm(mod: 0b01, reg: reg_code(dst_reg), rm: reg_code(src_reg)), # Mod 01: [reg]+disp8 + disp: src_offset, + ) else raise NotImplementedError, "mov: not-implemented input: #{dst.inspect}, #{src.inspect}" end diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb index 75314501c1..9383c189b2 100644 --- a/lib/ruby_vm/mjit/compiler.rb +++ b/lib/ruby_vm/mjit/compiler.rb @@ -9,9 +9,6 @@ module RubyVM::MJIT EndBlock = :end_block class Compiler - # Ruby constants - Qundef = Fiddle::Qundef - attr_accessor :write_pos # @param mem_block [Integer] JIT buffer address @@ -24,7 +21,11 @@ module RubyVM::MJIT # @param iseq [RubyVM::MJIT::CPointer::Struct] def call(iseq) return if iseq.body.location.label == '
' - iseq.body.jit_func = compile_block(iseq) + + asm = X86Assembler.new + compile_prologue(asm) + compile_block(asm, iseq) + iseq.body.jit_func = compile(asm) rescue Exception => e $stderr.puts e.full_message # TODO: check verbose end @@ -35,6 +36,32 @@ module RubyVM::MJIT 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) start_addr = write_addr @@ -49,32 +76,6 @@ module RubyVM::MJIT start_addr end - # ec -> RDI, cfp -> RSI - def compile_block(iseq) - addr = write_addr - asm = X86Assembler.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 - - compile(asm) - 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 decode_insn(encoded) INSNS.fetch(C.rb_vm_insn_decode(encoded)) end