summaryrefslogtreecommitdiff
path: root/lib/ruby_vm/mjit/insn_compiler.rb
diff options
context:
space:
mode:
authorTakashi Kokubun <[email protected]>2023-02-08 00:47:01 -0800
committerTakashi Kokubun <[email protected]>2023-03-05 22:11:20 -0800
commite92edfc7f02edfbc9bedddc5b4e162c00ac141b8 (patch)
tree55e01a7f3e093f4eeda53cd2ef2beba1158141ee /lib/ruby_vm/mjit/insn_compiler.rb
parent0a400f38e8005c280a84bab38b64eeeec99a6316 (diff)
Implement jit_chain_guard
Diffstat (limited to 'lib/ruby_vm/mjit/insn_compiler.rb')
-rw-r--r--lib/ruby_vm/mjit/insn_compiler.rb53
1 files changed, 51 insertions, 2 deletions
diff --git a/lib/ruby_vm/mjit/insn_compiler.rb b/lib/ruby_vm/mjit/insn_compiler.rb
index 7a03726d07..b30f1e7988 100644
--- a/lib/ruby_vm/mjit/insn_compiler.rb
+++ b/lib/ruby_vm/mjit/insn_compiler.rb
@@ -149,6 +149,7 @@ module RubyVM::MJIT
# @param ctx [RubyVM::MJIT::Context]
# @param asm [RubyVM::MJIT::Assembler]
def getinstancevariable(jit, ctx, asm)
+ # Specialize on compile-time receiver, and split a block for chain guards
unless jit.at_current_insn?
defer_compilation(jit, ctx, asm)
return EndBlock
@@ -554,6 +555,51 @@ module RubyVM::MJIT
asm.je(side_exit)
end
+ # @param jit [RubyVM::MJIT::JITState]
+ # @param ctx [RubyVM::MJIT::Context]
+ # @param asm [RubyVM::MJIT::Assembler]
+ def jit_chain_guard(opcode, jit, ctx, asm, side_exit, limit: 10)
+ assert_equal(opcode, :jne) # TODO: support more
+
+ if ctx.chain_depth < limit
+ deeper = ctx.dup
+ deeper.chain_depth += 1
+
+ branch_stub = BranchStub.new(
+ iseq: jit.iseq,
+ shape: Default,
+ target0: BranchTarget.new(ctx: deeper, pc: jit.pc),
+ )
+ branch_stub.target0.address = Assembler.new.then do |ocb_asm|
+ @exit_compiler.compile_branch_stub(deeper, ocb_asm, branch_stub, true)
+ @ocb.write(ocb_asm)
+ end
+ branch_stub.compile = proc do |branch_asm|
+ branch_asm.comment('jit_chain_guard')
+ branch_asm.stub(branch_stub) do
+ case branch_stub.shape
+ in Default
+ asm.jne(branch_stub.target0.address)
+ end
+ end
+ end
+ branch_stub.compile.call(asm)
+ else
+ asm.jne(side_exit)
+ end
+ end
+
+ # @param jit [RubyVM::MJIT::JITState]
+ # @param ctx [RubyVM::MJIT::Context]
+ # @param asm [RubyVM::MJIT::Assembler]
+ def jump_to_next_insn(jit, ctx, asm)
+ reset_depth = ctx.dup
+ reset_depth.chain_depth = 0
+
+ next_pc = jit.pc + jit.insn.len * C.VALUE.size
+ stub_next_block(jit.iseq, next_pc, reset_depth, asm, comment: 'jump_to_next_insn')
+ end
+
# rb_vm_check_ints
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
@@ -571,6 +617,7 @@ module RubyVM::MJIT
# @param asm [RubyVM::MJIT::Assembler]
def jit_getivar(jit, ctx, asm, comptime_obj, ivar_id)
side_exit = side_exit(jit, ctx)
+ starting_ctx = ctx.dup # copy for jit_chain_guard
# Guard not special const
if C.SPECIAL_CONST_P(comptime_obj)
@@ -596,7 +643,7 @@ module RubyVM::MJIT
asm.comment('guard shape')
asm.cmp(DwordPtr[:rax, C.rb_shape_id_offset], shape_id)
- asm.jne(counted_exit(side_exit, :getivar_polymorphic))
+ jit_chain_guard(:jne, jit, starting_ctx, asm, counted_exit(side_exit, :getivar_megamorphic))
index = C.rb_shape_get_iv_index(shape_id, ivar_id)
if index
@@ -618,7 +665,9 @@ module RubyVM::MJIT
stack_opnd = ctx.stack_push
asm.mov(stack_opnd, val_opnd)
- KeepCompiling
+ # Let guard chains share the same successor
+ jump_to_next_insn(jit, ctx, asm)
+ EndBlock
end
# vm_call_method (vm_sendish -> vm_call_general -> vm_call_method)