Skip to content

Commit 892991b

Browse files
authored
ZJIT: Fallback ifunc invokeblock when tag check fails (ruby#16608)
1 parent 9ef2153 commit 892991b

File tree

2 files changed

+47
-22
lines changed

2 files changed

+47
-22
lines changed

zjit/src/hir.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8051,7 +8051,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
80518051
});
80528052

80538053
let result = if is_ifunc {
8054-
// Get the local EP to load the block handler
8054+
// Load the block handler from LEP
80558055
let level = get_lvar_level(fun.iseq);
80568056
let lep = fun.push_insn(block, Insn::GetEP { level });
80578057
let block_handler = fun.push_insn(block, Insn::LoadField {
@@ -8061,23 +8061,34 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
80618061
return_type: types::CInt64,
80628062
});
80638063

8064-
// Guard that the block handler is an IFUNC (tag bits & 0x3 == 0x3),
8065-
// matching VM_BH_IFUNC_P() in the interpreter.
8064+
// Check IFUNC tag: (block_handler & 0x3) == 0x3
80668065
let tag_mask = fun.push_insn(block, Insn::Const { val: Const::CInt64(0x3) });
80678066
let tag_bits = fun.push_insn(block, Insn::IntAnd { left: block_handler, right: tag_mask });
8068-
fun.push_insn(block, Insn::GuardBitEquals {
8069-
val: tag_bits,
8070-
expected: Const::CInt64(0x3),
8071-
reason: SideExitReason::InvokeBlockNotIfunc,
8072-
state: exit_id,
8073-
});
8067+
let ifunc_tag = fun.push_insn(block, Insn::Const { val: Const::CInt64(0x3) });
8068+
let is_ifunc_match = fun.push_insn(block, Insn::IsBitEqual { left: tag_bits, right: ifunc_tag });
80748069

8075-
fun.push_insn(block, Insn::InvokeBlockIfunc {
8070+
// Branch: on match, call InvokeBlockIfunc directly
8071+
let join_block = fun.new_block(insn_idx);
8072+
let join_param = fun.push_insn(join_block, Insn::Param);
8073+
let ifunc_block = fun.new_block(insn_idx);
8074+
fun.push_insn(block, Insn::IfTrue { val: is_ifunc_match, target: BranchEdge { target: ifunc_block, args: vec![] } });
8075+
let ifunc_result = fun.push_insn(ifunc_block, Insn::InvokeBlockIfunc {
80768076
cd,
80778077
block_handler,
8078-
args,
8078+
args: args.clone(),
80798079
state: exit_id,
8080-
})
8080+
});
8081+
fun.push_insn(ifunc_block, Insn::Jump(BranchEdge { target: join_block, args: vec![ifunc_result] }));
8082+
8083+
// In the fallthrough case, use generic rb_vm_invokeblock and join
8084+
let fallback_result = fun.push_insn(block, Insn::InvokeBlock {
8085+
cd, args, state: exit_id, reason: InvokeBlockNotSpecialized,
8086+
});
8087+
fun.push_insn(block, Insn::Jump(BranchEdge { target: join_block, args: vec![fallback_result] }));
8088+
8089+
// Continue compilation from the join block
8090+
block = join_block;
8091+
join_param
80818092
} else {
80828093
fun.push_insn(block, Insn::InvokeBlock { cd, args, state: exit_id, reason: InvokeBlockNotSpecialized })
80838094
};

zjit/src/hir/opt_tests.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15268,17 +15268,31 @@ mod hir_opt_tests {
1526815268
v13:CInt64 = LoadField v12, :_env_data_index_specval@0x1000
1526915269
v14:CInt64[3] = Const CInt64(3)
1527015270
v15:CInt64 = IntAnd v13, v14
15271-
v16:CInt64[3] = GuardBitEquals v15, CInt64(3)
15272-
v17:BasicObject = InvokeBlockIfunc v13, v10
15273-
v21:Fixnum[2] = Const Value(2)
15274-
v23:CPtr = GetEP 0
15275-
v24:CInt64 = LoadField v23, :_env_data_index_specval@0x1000
15276-
v25:CInt64[3] = Const CInt64(3)
15277-
v26:CInt64 = IntAnd v24, v25
15278-
v27:CInt64[3] = GuardBitEquals v26, CInt64(3)
15279-
v28:BasicObject = InvokeBlockIfunc v24, v21
15271+
v16:CInt64[3] = Const CInt64(3)
15272+
v17:CBool = IsBitEqual v15, v16
15273+
IfTrue v17, bb5()
15274+
v22:BasicObject = InvokeBlock, v10 # SendFallbackReason: InvokeBlock: not yet specialized
15275+
Jump bb4(v22)
15276+
bb5():
15277+
v20:BasicObject = InvokeBlockIfunc v13, v10
15278+
Jump bb4(v20)
15279+
bb4(v18:BasicObject):
15280+
v27:Fixnum[2] = Const Value(2)
15281+
v29:CPtr = GetEP 0
15282+
v30:CInt64 = LoadField v29, :_env_data_index_specval@0x1000
15283+
v31:CInt64[3] = Const CInt64(3)
15284+
v32:CInt64 = IntAnd v30, v31
15285+
v33:CInt64[3] = Const CInt64(3)
15286+
v34:CBool = IsBitEqual v32, v33
15287+
IfTrue v34, bb7()
15288+
v39:BasicObject = InvokeBlock, v27 # SendFallbackReason: InvokeBlock: not yet specialized
15289+
Jump bb6(v39)
15290+
bb7():
15291+
v37:BasicObject = InvokeBlockIfunc v30, v27
15292+
Jump bb6(v37)
15293+
bb6(v35:BasicObject):
1528015294
CheckInterrupts
15281-
Return v28
15295+
Return v35
1528215296
");
1528315297
}
1528415298
}

0 commit comments

Comments
 (0)