summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <[email protected]>2022-12-30 22:16:07 -0800
committerTakashi Kokubun <[email protected]>2023-03-05 22:11:20 -0800
commit36cec59f0a54b817ae6b3836fb0e97e342b999ce (patch)
tree2978e1388c2c093a521456a9c08cf507ca0df7e0
parent7abff797b434ead0653c89f5429490bd0f716f88 (diff)
Implement ocb
-rw-r--r--lib/ruby_vm/mjit/assembler.rb (renamed from lib/ruby_vm/mjit/x86_assembler.rb)63
-rw-r--r--lib/ruby_vm/mjit/code_block.rb2
-rw-r--r--lib/ruby_vm/mjit/compiler.rb15
-rw-r--r--lib/ruby_vm/mjit/exit_compiler.rb2
-rw-r--r--lib/ruby_vm/mjit/insn_compiler.rb27
5 files changed, 79 insertions, 30 deletions
diff --git a/lib/ruby_vm/mjit/x86_assembler.rb b/lib/ruby_vm/mjit/assembler.rb
index 9856d4e4ac..4620430faf 100644
--- a/lib/ruby_vm/mjit/x86_assembler.rb
+++ b/lib/ruby_vm/mjit/assembler.rb
@@ -1,9 +1,14 @@
# frozen_string_literal: true
-# https://www.intel.com/content/dam/develop/public/us/en/documents/325383-sdm-vol-2abcd.pdf
module RubyVM::MJIT
- class X86Assembler
+ # https://www.intel.com/content/dam/develop/public/us/en/documents/325383-sdm-vol-2abcd.pdf
+ # Mostly an x86_64 assembler, but this also has some stuff that is useful for any architecture.
+ class Assembler
class Label < Data.define(:id, :name); end
+ # rel32 is inserted as [Rel32, Rel32Pad..] and converted on #resolve_rel32
+ class Rel32 < Data.define(:addr); end
+ Rel32Pad = Object.new
+
ByteWriter = CType::Immediate.parse('char')
### prefix ###
@@ -18,7 +23,9 @@ module RubyVM::MJIT
end
def assemble(addr)
- link_labels
+ resolve_rel32(addr)
+ resolve_labels
+
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.
@@ -65,12 +72,26 @@ module RubyVM::MJIT
end
end
- # JZ rel8
- # @param [RubyVM::MJIT::X86Assembler::Label] label
- def jz(label)
- # 74 cb
- insn(opcode: 0x74)
- @bytes.push(label)
+ def jnz(dst)
+ case dst
+ # JNZ rel32
+ in Integer => addr
+ # 0F 85 cd
+ insn(opcode: [0x0f, 0x85], imm: rel32(addr))
+ else
+ raise NotImplementedError, "jnz: not-implemented operands: #{dst.inspect}"
+ end
+ end
+
+ def jz(dst)
+ case dst
+ # JZ rel8
+ in Label => label
+ # 74 cb
+ insn(opcode: 0x74, imm: label)
+ else
+ raise NotImplementedError, "jz: not-implemented operands: #{dst.inspect}"
+ end
end
def mov(dst, src)
@@ -244,7 +265,7 @@ module RubyVM::MJIT
Label.new(id: @label_id += 1, name:)
end
- # @param [RubyVM::MJIT::X86Assembler::Label] label
+ # @param [RubyVM::MJIT::Assembler::Label] label
def write_label(label)
@labels[label] = @bytes.size
end
@@ -267,7 +288,7 @@ module RubyVM::MJIT
if prefix
@bytes.push(prefix)
end
- @bytes.push(opcode)
+ @bytes.push(*Array(opcode))
if mod_rm
@bytes.push(mod_rm)
end
@@ -375,7 +396,25 @@ module RubyVM::MJIT
reg.start_with?('r')
end
- def link_labels
+ def rel32(addr)
+ [Rel32.new(addr), Rel32Pad, Rel32Pad, Rel32Pad]
+ end
+
+ def resolve_rel32(write_addr)
+ @bytes.each_with_index do |byte, index|
+ if byte.is_a?(Rel32)
+ src_addr = write_addr + index + 4 # offset 4 bytes for rel32 itself
+ dst_addr = byte.addr
+ rel32 = dst_addr - src_addr
+ raise "unexpected offset: #{rel32}" unless imm32?(rel32)
+ imm32(rel32).each_with_index do |rel_byte, rel_index|
+ @bytes[index + rel_index] = rel_byte
+ end
+ end
+ end
+ end
+
+ def resolve_labels
@bytes.each_with_index do |byte, index|
if byte.is_a?(Label)
src_index = index + 1 # offset 1 byte for rel8 itself
diff --git a/lib/ruby_vm/mjit/code_block.rb b/lib/ruby_vm/mjit/code_block.rb
index 17e2a0053d..464d13ba8d 100644
--- a/lib/ruby_vm/mjit/code_block.rb
+++ b/lib/ruby_vm/mjit/code_block.rb
@@ -9,7 +9,7 @@ module RubyVM::MJIT
@write_pos = 0
end
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def write(asm)
return 0 if @write_pos + asm.size >= @mem_size
diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb
index f872c05bce..e114d43e0d 100644
--- a/lib/ruby_vm/mjit/compiler.rb
+++ b/lib/ruby_vm/mjit/compiler.rb
@@ -1,10 +1,10 @@
+require 'ruby_vm/mjit/assembler'
require 'ruby_vm/mjit/code_block'
require 'ruby_vm/mjit/context'
require 'ruby_vm/mjit/exit_compiler'
require 'ruby_vm/mjit/insn_compiler'
require 'ruby_vm/mjit/instruction'
require 'ruby_vm/mjit/jit_state'
-require 'ruby_vm/mjit/x86_assembler'
module RubyVM::MJIT
# Compilation status
@@ -31,9 +31,10 @@ module RubyVM::MJIT
# @param mem_block [Integer] JIT buffer address
# @param mem_size [Integer] JIT buffer size
def initialize(mem_block, mem_size)
- @cb = CodeBlock.new(mem_block:, mem_size:)
+ @cb = CodeBlock.new(mem_block: mem_block, mem_size: mem_size / 2)
+ @ocb = CodeBlock.new(mem_block: mem_block + mem_size / 2, mem_size: mem_size / 2)
@exit_compiler = ExitCompiler.new
- @insn_compiler = InsnCompiler.new
+ @insn_compiler = InsnCompiler.new(@ocb)
end
# @param iseq [RubyVM::MJIT::CPointer::Struct]
@@ -41,7 +42,7 @@ module RubyVM::MJIT
# TODO: Support has_opt
return if iseq.body.param.flags.has_opt
- asm = X86Assembler.new
+ asm = Assembler.new
asm.comment("Block: #{iseq.body.location.label}@#{pathobj_path(iseq.body.location.pathobj)}:#{iseq.body.location.first_lineno}")
compile_prologue(asm)
compile_block(asm, iseq)
@@ -58,7 +59,7 @@ module RubyVM::MJIT
# Callee-saved: rbx, rsp, rbp, r12, r13, r14, r15
# Caller-saved: rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11
#
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def compile_prologue(asm)
asm.comment("MJIT entry")
@@ -69,7 +70,7 @@ module RubyVM::MJIT
asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
end
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def compile_block(asm, iseq)
jit = JITState.new
ctx = Context.new
@@ -92,7 +93,7 @@ module RubyVM::MJIT
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def compile_insn(jit, ctx, asm, insn)
asm.incr_counter(:mjit_insns_count)
asm.comment("Insn: #{insn.name}")
diff --git a/lib/ruby_vm/mjit/exit_compiler.rb b/lib/ruby_vm/mjit/exit_compiler.rb
index bd1cf67a3e..7f5219ea5b 100644
--- a/lib/ruby_vm/mjit/exit_compiler.rb
+++ b/lib/ruby_vm/mjit/exit_compiler.rb
@@ -4,7 +4,7 @@ module RubyVM::MJIT
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def compile_exit(jit, ctx, asm)
if C.mjit_opts.stats
insn = decode_insn(C.VALUE.new(jit.pc).*)
diff --git a/lib/ruby_vm/mjit/insn_compiler.rb b/lib/ruby_vm/mjit/insn_compiler.rb
index 4c9c24eca6..4c4c86c5f0 100644
--- a/lib/ruby_vm/mjit/insn_compiler.rb
+++ b/lib/ruby_vm/mjit/insn_compiler.rb
@@ -3,9 +3,12 @@ module RubyVM::MJIT
# cfp: rsi
# sp: rbx
# scratch regs: rax
+ #
+ # 4/101
class InsnCompiler
- # 4/101
- def initialize
+ # @param ocb [CodeBlock]
+ def initialize(ocb)
+ @ocb = ocb
@exit_compiler = ExitCompiler.new
freeze
end
@@ -30,7 +33,7 @@ module RubyVM::MJIT
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def putnil(jit, ctx, asm)
asm.mov([SP, C.VALUE.size * ctx.stack_size], Qnil)
ctx.stack_size += 1
@@ -41,7 +44,7 @@ module RubyVM::MJIT
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def putobject(jit, ctx, asm)
# Get operands
val = jit.operand(0)
@@ -102,16 +105,14 @@ module RubyVM::MJIT
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def leave(jit, ctx, asm)
assert_eq!(ctx.stack_size, 1)
asm.comment('RUBY_VM_CHECK_INTS(ec)')
asm.mov(:eax, [EC, C.rb_execution_context_t.offsetof(:interrupt_flag)])
asm.test(:eax, :eax)
- asm.jz(not_interrupted = asm.new_label(:not_interrupted))
- @exit_compiler.compile_exit(jit, ctx, asm) # TODO: use ocb
- asm.write_label(not_interrupted)
+ asm.jnz(compile_side_exit(jit, ctx))
asm.comment('pop stack frame')
asm.add(CFP, C.rb_control_frame_t.size) # cfp = cfp + 1
@@ -164,7 +165,7 @@ module RubyVM::MJIT
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
- # @param asm [RubyVM::MJIT::X86Assembler]
+ # @param asm [RubyVM::MJIT::Assembler]
def getlocal_WC_0(jit, ctx, asm)
# Get operands
idx = jit.operand(0)
@@ -195,5 +196,13 @@ module RubyVM::MJIT
raise "'#{left.inspect}' was not '#{right.inspect}'"
end
end
+
+ # @param jit [RubyVM::MJIT::JITState]
+ # @param ctx [RubyVM::MJIT::Context]
+ def compile_side_exit(jit, ctx)
+ asm = Assembler.new
+ @exit_compiler.compile_exit(jit, ctx, asm)
+ @ocb.write(asm)
+ end
end
end