summaryrefslogtreecommitdiff
path: root/lib/ruby_vm/mjit
diff options
context:
space:
mode:
authorTakashi Kokubun <[email protected]>2023-02-07 13:03:47 -0800
committerTakashi Kokubun <[email protected]>2023-03-05 22:11:20 -0800
commita026bcedc87a2f502befbd7476a997a9fe030203 (patch)
treee7b4345e3330474cc4d8317dc68054db3b7a2298 /lib/ruby_vm/mjit
parentd415f1e3178625fa90ab908dcc5636b7e2e21c16 (diff)
Allow reusing existing blocks
Diffstat (limited to 'lib/ruby_vm/mjit')
-rw-r--r--lib/ruby_vm/mjit/compiler.rb63
1 files changed, 39 insertions, 24 deletions
diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb
index 26e3d75d34..9c58786be2 100644
--- a/lib/ruby_vm/mjit/compiler.rb
+++ b/lib/ruby_vm/mjit/compiler.rb
@@ -32,6 +32,8 @@ module RubyVM::MJIT
class Compiler
attr_accessor :write_pos
+ IseqBlocks = Hash.new { |h, k| h[k] = {} }
+
def self.decode_insn(encoded)
INSNS.fetch(C.rb_vm_insn_decode(encoded))
end
@@ -77,14 +79,13 @@ module RubyVM::MJIT
target = target0_p ? branch_stub.target0 : branch_stub.target1
cfp.pc = target.pc
- # Prepare the jump target
- new_asm = Assembler.new.tap do |asm|
- jit = JITState.new(iseq: branch_stub.iseq, cfp:)
- compile_block(asm, jit:, pc: target.pc, ctx: target.ctx.dup)
- end
+ # Reuse an existing block if it already exists
+ block = find_block(branch_stub.iseq, target.pc, target.ctx)
- # Rewrite the branch stub
- if @cb.write_addr == branch_stub.end_addr
+ # If the branch stub's jump is the last code, allow overwriting part of
+ # the old branch code with the new block code.
+ fallthrough = block.nil? && @cb.write_addr == branch_stub.end_addr
+ if fallthrough
# If the branch stub's jump is the last code, allow overwriting part of
# the old branch code with the new block code.
@cb.set_write_addr(branch_stub.start_addr)
@@ -93,22 +94,22 @@ module RubyVM::MJIT
branch_stub.compile.call(branch_asm)
@cb.write(branch_asm)
end
+ end
- # Compile a fallthrough right after the new branch code
- if target0_p
- branch_stub.target0.address = @cb.write(new_asm)
- else
- branch_stub.target1.address = @cb.write(new_asm)
- end
+ # Reuse or generate a block
+ if block
+ target.address = block.start_addr
else
- # Otherwise, just prepare the new block somewhere
- if target0_p
- branch_stub.target0.address = @cb.write(new_asm)
- else
- branch_stub.target1.address = @cb.write(new_asm)
+ jit = JITState.new(iseq: branch_stub.iseq, cfp:)
+ target.address = Assembler.new.then do |asm|
+ compile_block(asm, jit:, pc: target.pc, ctx: target.ctx.dup)
+ @cb.write(asm)
end
+ set_block(branch_stub.iseq, target.pc, target.ctx, jit.block)
+ end
- # Update jump destinations
+ # Re-generate the branch code for non-fallthrough cases
+ unless fallthrough
@cb.with_write_addr(branch_stub.start_addr) do
branch_asm = Assembler.new
branch_stub.compile.call(branch_asm)
@@ -116,11 +117,7 @@ module RubyVM::MJIT
end
end
- if target0_p
- branch_stub.target0.address
- else
- branch_stub.target1.address
- end
+ return target.address
end
private
@@ -184,5 +181,23 @@ module RubyVM::MJIT
C.rb_mjit_counters[name][0] += 1
end
end
+
+ def mjit_blocks(iseq)
+ iseq.body.mjit_blocks ||= {}
+ end
+
+ # @param [Integer] pc
+ # @param [RubyVM::MJIT::Context] ctx
+ # @return [RubyVM::MJIT::Block,NilClass]
+ def find_block(iseq, pc, ctx)
+ IseqBlocks[iseq.to_i][[pc, ctx]]
+ end
+
+ # @param [Integer] pc
+ # @param [RubyVM::MJIT::Context] ctx
+ # @param [RubyVM::MJIT::Block] block
+ def set_block(iseq, pc, ctx, block)
+ IseqBlocks[iseq.to_i][[pc, ctx]] = block
+ end
end
end