summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTakashi Kokubun <[email protected]>2023-01-01 23:13:43 -0800
committerTakashi Kokubun <[email protected]>2023-03-05 22:11:20 -0800
commit4b6c7381808110e725d3bc08f3fbdbb13c44128f (patch)
tree97138c7fa7d6712277769d8e51b6ecb96c03cf29 /lib
parentc3d99d0f12e2b494e16a5c61134ca312a3a6e3a5 (diff)
Rewrite the stub if it's the last code
Diffstat (limited to 'lib')
-rw-r--r--lib/ruby_vm/mjit/assembler.rb17
-rw-r--r--lib/ruby_vm/mjit/block_stub.rb9
-rw-r--r--lib/ruby_vm/mjit/code_block.rb14
-rw-r--r--lib/ruby_vm/mjit/compiler.rb26
-rw-r--r--lib/ruby_vm/mjit/insn_compiler.rb5
5 files changed, 45 insertions, 26 deletions
diff --git a/lib/ruby_vm/mjit/assembler.rb b/lib/ruby_vm/mjit/assembler.rb
index bd2da22d69..87701a7102 100644
--- a/lib/ruby_vm/mjit/assembler.rb
+++ b/lib/ruby_vm/mjit/assembler.rb
@@ -31,7 +31,8 @@ module RubyVM::MJIT
@labels = {}
@label_id = 0
@comments = Hash.new { |h, k| h[k] = [] }
- @stubs = Hash.new { |h, k| h[k] = [] }
+ @stub_starts = Hash.new { |h, k| h[k] = [] }
+ @stub_ends = Hash.new { |h, k| h[k] = [] }
end
def assemble(addr)
@@ -307,7 +308,10 @@ module RubyVM::MJIT
end
def stub(stub)
- @stubs[@bytes.size] << stub
+ @stub_starts[@bytes.size] << stub
+ yield
+ ensure
+ @stub_ends[@bytes.size] << stub
end
def new_label(name)
@@ -492,9 +496,12 @@ module RubyVM::MJIT
end
def set_stub_addrs(write_addr)
- @bytes.each_with_index do |byte, index|
- @stubs.fetch(index, []).each do |stub|
- stub.addr = write_addr + index
+ (@bytes.size + 1).times do |index|
+ @stub_starts.fetch(index, []).each do |stub|
+ stub.start_addr = write_addr + index
+ end
+ @stub_ends.fetch(index, []).each do |stub|
+ stub.end_addr = write_addr + index
stub.freeze
end
end
diff --git a/lib/ruby_vm/mjit/block_stub.rb b/lib/ruby_vm/mjit/block_stub.rb
index c6908d09ca..e6a0a867b9 100644
--- a/lib/ruby_vm/mjit/block_stub.rb
+++ b/lib/ruby_vm/mjit/block_stub.rb
@@ -1,7 +1,8 @@
class RubyVM::MJIT::BlockStub < Struct.new(
- :iseq, # @param [RubyVM::MJIT::CPointer::Struct_rb_iseq_struct] Jump target ISEQ
- :pc, # @param [Integer] Jump target pc
- :ctx, # @param [RubyVM::MJIT::Context] Jump target context
- :addr, # @param [Integer] Jump source address to be re-generated
+ :iseq, # @param [RubyVM::MJIT::CPointer::Struct_rb_iseq_struct] Stub target ISEQ
+ :pc, # @param [Integer] Stub target pc
+ :ctx, # @param [RubyVM::MJIT::Context] Stub target context
+ :start_addr, # @param [Integer] Stub source start address to be re-generated
+ :end_addr, # @param [Integer] Stub source end address to be re-generated
)
end
diff --git a/lib/ruby_vm/mjit/code_block.rb b/lib/ruby_vm/mjit/code_block.rb
index ad91f53404..15589b91d0 100644
--- a/lib/ruby_vm/mjit/code_block.rb
+++ b/lib/ruby_vm/mjit/code_block.rb
@@ -37,21 +37,25 @@ module RubyVM::MJIT
start_addr
end
- def with_addr(addr)
- old_write_pos = @write_pos
+ def set_write_addr(addr)
@write_pos = addr - @mem_block
- @comments.delete(addr) # TODO: clean up old comments for all overwritten insns?
+ @comments.delete(addr) # TODO: clean up old comments for all the overwritten range?
+ end
+
+ def with_write_addr(addr)
+ old_write_pos = @write_pos
+ set_addr(addr)
yield
ensure
@write_pos = old_write_pos
end
- private
-
def write_addr
@mem_block + @write_pos
end
+ private
+
def dump_disasm(from, to)
C.dump_disasm(from, to).each do |address, mnemonic, op_str|
@comments.fetch(address, []).each do |comment|
diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb
index 8491ac68c6..2bd22fcb98 100644
--- a/lib/ruby_vm/mjit/compiler.rb
+++ b/lib/ruby_vm/mjit/compiler.rb
@@ -63,22 +63,28 @@ module RubyVM::MJIT
# Update cfp->pc for `jit.at_current_insn?`
cfp.pc = stub.pc
- # Compile the jump target
- new_addr = Assembler.new.then do |asm|
+ # Prepare the jump target
+ new_asm = Assembler.new.tap do |asm|
jit = JITState.new(iseq: stub.iseq, cfp:)
index = (stub.pc - stub.iseq.body.iseq_encoded.to_i) / C.VALUE.size
compile_block(asm, jit:, index:, ctx: stub.ctx)
- @cb.write(asm)
end
- # Re-generate the jump source
- @cb.with_addr(stub.addr) do
- asm = Assembler.new
- asm.comment('regenerate block stub')
- asm.jmp(new_addr)
- @cb.write(asm)
+ # Rewrite the stub
+ if @cb.write_addr == stub.end_addr
+ # If the stub jump is the last code, overwrite the jump with the new code.
+ @cb.set_write_addr(stub.start_addr)
+ @cb.write(new_asm)
+ else
+ # If the stub jump is old code, change the jump target to the new code.
+ new_addr = @cb.write(new_asm)
+ @cb.with_write_addr(stub.start_addr) do
+ asm = Assembler.new
+ asm.comment('regenerate block stub')
+ asm.jmp(new_addr)
+ @cb.write(asm)
+ end
end
- new_addr
end
private
diff --git a/lib/ruby_vm/mjit/insn_compiler.rb b/lib/ruby_vm/mjit/insn_compiler.rb
index 0d40cb6f50..10aa61fb28 100644
--- a/lib/ruby_vm/mjit/insn_compiler.rb
+++ b/lib/ruby_vm/mjit/insn_compiler.rb
@@ -224,8 +224,9 @@ module RubyVM::MJIT
end
asm.comment('defer_compilation: block stub')
- asm.stub(block_stub)
- asm.jmp(stub_hit)
+ asm.stub(block_stub) do
+ asm.jmp(stub_hit)
+ end
end
# @param jit [RubyVM::MJIT::JITState]