Skip to content

Commit

Permalink
RJIT: Implement invokeblock with ISeq
Browse files Browse the repository at this point in the history
  • Loading branch information
k0kubun committed Mar 20, 2023
1 parent 80890e6 commit 2d8ecfc
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 10 deletions.
72 changes: 64 additions & 8 deletions lib/ruby_vm/rjit/insn_compiler.rb
Expand Up @@ -1484,8 +1484,8 @@ def invokeblock(jit, ctx, asm)
# Get call info
cd = C.rb_call_data.new(jit.operand(0))
ci = cd.ci
_argc = C.vm_ci_argc(ci)
_flags = C.vm_ci_flag(ci)
argc = C.vm_ci_argc(ci)
flags = C.vm_ci_flag(ci)

# Get block_handler
cfp = jit.cfp
Expand All @@ -1497,8 +1497,49 @@ def invokeblock(jit, ctx, asm)
asm.incr_counter(:invokeblock_none)
CantCompile
elsif comptime_handler & 0x3 == 0x1 # VM_BH_ISEQ_BLOCK_P
asm.incr_counter(:invokeblock_iseq)
CantCompile
asm.comment('get local EP')
ep_reg = :rax
jit_get_lep(jit, asm, reg: ep_reg)
asm.mov(:rax, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler_opnd

asm.comment('guard block_handler type')
side_exit = side_exit(jit, ctx)
asm.mov(:rcx, :rax)
asm.and(:rcx, 0x3) # block_handler is a tagged pointer
asm.cmp(:rcx, 0x1) # VM_BH_ISEQ_BLOCK_P
tag_changed_exit = counted_exit(side_exit, :invokeblock_tag_changed)
jit_chain_guard(:jne, jit, ctx, asm, tag_changed_exit)

comptime_captured = C.rb_captured_block.new(comptime_handler & ~0x3)
comptime_iseq = comptime_captured.code.iseq

asm.comment('guard known ISEQ')
asm.and(:rax, ~0x3) # captured
asm.mov(:rax, [:rax, C.VALUE.size * 2]) # captured->iseq
asm.mov(:rcx, comptime_iseq.to_i)
asm.cmp(:rax, :rcx)
block_changed_exit = counted_exit(side_exit, :invokeblock_iseq_block_changed)
jit_chain_guard(:jne, jit, ctx, asm, block_changed_exit)

jit_call_iseq_setup(
jit, ctx, asm, nil, flags, argc, comptime_iseq, :captured,
send_shift: 0, frame_type: C::VM_FRAME_MAGIC_BLOCK,
)
#gen_send_iseq(
# jit,
# ctx,
# asm,
# ocb,
# comptime_iseq,
# ci,
# VM_FRAME_MAGIC_BLOCK,
# None,
# 0,
# None,
# flags,
# argc,
# Some(captured_opnd),
#)
elsif comptime_handler & 0x3 == 0x3 # VM_BH_IFUNC_P
asm.incr_counter(:invokeblock_ifunc)
CantCompile
Expand Down Expand Up @@ -3990,8 +4031,9 @@ def jit_call_iseq_setup_normal(jit, ctx, asm, cme, flags, argc, iseq, block_hand
# Save caller SP and PC before pushing a callee frame for backtrace and side exits
asm.comment('save SP to caller CFP')
recv_idx = argc + (flags & C::VM_CALL_ARGS_BLOCKARG != 0 ? 1 : 0) # blockarg is not popped yet
recv_idx += (block_handler == :captured) ? 0 : 1 # receiver is not on stack when captured->self is used
# Skip setting this to SP register. This cfp->sp will be copied to SP on leave insn.
asm.lea(:rax, ctx.sp_opnd(C.VALUE.size * -(1 + recv_idx))) # Pop receiver and arguments to prepare for side exits
asm.lea(:rax, ctx.sp_opnd(C.VALUE.size * -recv_idx)) # Pop receiver and arguments to prepare for side exits
asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], :rax)
jit_save_pc(jit, asm, comment: 'save PC to caller CFP')

Expand Down Expand Up @@ -4455,6 +4497,15 @@ def jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, block_handler, i
if prev_ep
asm.mov(:rax, prev_ep.to_i | 1) # tagged prev ep
asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax)
elsif block_handler == :captured
# Set captured->ep, saving captured in :rcx for captured->self
ep_reg = :rcx
jit_get_lep(jit, asm, reg: ep_reg)
asm.mov(:rcx, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler
asm.and(:rcx, ~0x3) # captured
asm.mov(:rax, [:rcx, C.VALUE.size]) # captured->ep
asm.or(:rax, 0x1) # GC_GUARDED_PTR
asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax)
elsif block_handler == C::VM_BLOCK_HANDLER_NONE
asm.mov([SP, C.VALUE.size * (ep_offset - 1)], C::VM_BLOCK_HANDLER_NONE)
elsif block_handler == C.rb_block_param_proxy
Expand All @@ -4481,8 +4532,12 @@ def jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, block_handler, i
end
asm.mov(:rax, iseq.to_i)
asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:iseq)], :rax)
self_index = ctx.sp_offset - (1 + argc) # blockarg has been popped
asm.mov(:rax, [SP, C.VALUE.size * self_index])
if block_handler == :captured
asm.mov(:rax, [:rcx]) # captured->self
else
self_index = ctx.sp_offset - (1 + argc) # blockarg has been popped
asm.mov(:rax, [SP, C.VALUE.size * self_index])
end
asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:self)], :rax)
asm.lea(:rax, [SP, C.VALUE.size * ep_offset])
asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:ep)], :rax)
Expand All @@ -4497,7 +4552,8 @@ def jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, block_handler, i
if iseq
# Stub cfp->jit_return
return_ctx = ctx.dup
return_ctx.stack_size -= argc # Pop args. blockarg has been popped
return_ctx.stack_size -= argc + ((block_handler == :captured) ? 0 : 1) # Pop args and receiver. blockarg has been popped
return_ctx.stack_size += 1 # push callee's return value
return_ctx.sp_offset = 1 # SP is in the position after popping a receiver and arguments
return_ctx.chain_depth = 0
branch_stub = BranchStub.new(
Expand Down
3 changes: 2 additions & 1 deletion rjit_c.h
Expand Up @@ -84,10 +84,11 @@ RJIT_RUNTIME_COUNTERS(
invokesuper_same_me,

invokeblock_none,
invokeblock_iseq,
invokeblock_ifunc,
invokeblock_symbol,
invokeblock_proc,
invokeblock_tag_changed,
invokeblock_iseq_block_changed,

getivar_megamorphic,
getivar_not_heap,
Expand Down
3 changes: 2 additions & 1 deletion rjit_c.rb
Expand Up @@ -1316,10 +1316,11 @@ def C.rb_rjit_runtime_counters
invokesuper_me_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokesuper_me_changed)")],
invokesuper_same_me: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokesuper_same_me)")],
invokeblock_none: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_none)")],
invokeblock_iseq: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq)")],
invokeblock_ifunc: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_ifunc)")],
invokeblock_symbol: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_symbol)")],
invokeblock_proc: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_proc)")],
invokeblock_tag_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_tag_changed)")],
invokeblock_iseq_block_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_block_changed)")],
getivar_megamorphic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_megamorphic)")],
getivar_not_heap: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_not_heap)")],
getivar_special_const: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_special_const)")],
Expand Down

0 comments on commit 2d8ecfc

Please sign in to comment.