mirror of
https://github.com/ruby/ruby.git
synced 2025-08-25 22:14:37 +02:00
Allow reusing existing blocks
This commit is contained in:
parent
d415f1e317
commit
a026bcedc8
2 changed files with 40 additions and 25 deletions
|
@ -32,6 +32,8 @@ module RubyVM::MJIT
|
||||||
class Compiler
|
class Compiler
|
||||||
attr_accessor :write_pos
|
attr_accessor :write_pos
|
||||||
|
|
||||||
|
IseqBlocks = Hash.new { |h, k| h[k] = {} }
|
||||||
|
|
||||||
def self.decode_insn(encoded)
|
def self.decode_insn(encoded)
|
||||||
INSNS.fetch(C.rb_vm_insn_decode(encoded))
|
INSNS.fetch(C.rb_vm_insn_decode(encoded))
|
||||||
end
|
end
|
||||||
|
@ -77,14 +79,13 @@ module RubyVM::MJIT
|
||||||
target = target0_p ? branch_stub.target0 : branch_stub.target1
|
target = target0_p ? branch_stub.target0 : branch_stub.target1
|
||||||
cfp.pc = target.pc
|
cfp.pc = target.pc
|
||||||
|
|
||||||
# Prepare the jump target
|
# Reuse an existing block if it already exists
|
||||||
new_asm = Assembler.new.tap do |asm|
|
block = find_block(branch_stub.iseq, target.pc, target.ctx)
|
||||||
jit = JITState.new(iseq: branch_stub.iseq, cfp:)
|
|
||||||
compile_block(asm, jit:, pc: target.pc, ctx: target.ctx.dup)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Rewrite the branch stub
|
# If the branch stub's jump is the last code, allow overwriting part of
|
||||||
if @cb.write_addr == branch_stub.end_addr
|
# 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
|
# If the branch stub's jump is the last code, allow overwriting part of
|
||||||
# the old branch code with the new block code.
|
# the old branch code with the new block code.
|
||||||
@cb.set_write_addr(branch_stub.start_addr)
|
@cb.set_write_addr(branch_stub.start_addr)
|
||||||
|
@ -93,22 +94,22 @@ module RubyVM::MJIT
|
||||||
branch_stub.compile.call(branch_asm)
|
branch_stub.compile.call(branch_asm)
|
||||||
@cb.write(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
|
|
||||||
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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update jump destinations
|
# Reuse or generate a block
|
||||||
|
if block
|
||||||
|
target.address = block.start_addr
|
||||||
|
else
|
||||||
|
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
|
||||||
|
|
||||||
|
# Re-generate the branch code for non-fallthrough cases
|
||||||
|
unless fallthrough
|
||||||
@cb.with_write_addr(branch_stub.start_addr) do
|
@cb.with_write_addr(branch_stub.start_addr) do
|
||||||
branch_asm = Assembler.new
|
branch_asm = Assembler.new
|
||||||
branch_stub.compile.call(branch_asm)
|
branch_stub.compile.call(branch_asm)
|
||||||
|
@ -116,11 +117,7 @@ module RubyVM::MJIT
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if target0_p
|
return target.address
|
||||||
branch_stub.target0.address
|
|
||||||
else
|
|
||||||
branch_stub.target1.address
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -184,5 +181,23 @@ module RubyVM::MJIT
|
||||||
C.rb_mjit_counters[name][0] += 1
|
C.rb_mjit_counters[name][0] += 1
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
2
mjit.c
2
mjit.c
|
@ -281,7 +281,7 @@ mjit_child_after_fork(void)
|
||||||
void
|
void
|
||||||
mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body)
|
mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body)
|
||||||
{
|
{
|
||||||
rb_gc_mark(body->mjit_blocks);
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile ISeq to C code in `f`. It returns true if it succeeds to compile.
|
// Compile ISeq to C code in `f`. It returns true if it succeeds to compile.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue