Skip to content

Commit 8dc2676

Browse files
committed
ZJIT: Drop has_blockiseq guard on local variable access
1 parent bdb3b86 commit 8dc2676

File tree

3 files changed

+46
-57
lines changed

3 files changed

+46
-57
lines changed

zjit/src/hir.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6085,14 +6085,12 @@ pub fn jit_entry_insns(iseq: IseqPtr) -> Vec<u32> {
60856085

60866086
struct BytecodeInfo {
60876087
jump_targets: Vec<u32>,
6088-
has_blockiseq: bool,
60896088
}
60906089

60916090
fn compute_bytecode_info(iseq: *const rb_iseq_t, opt_table: &[u32]) -> BytecodeInfo {
60926091
let iseq_size = unsafe { get_iseq_encoded_size(iseq) };
60936092
let mut insn_idx = 0;
60946093
let mut jump_targets: HashSet<u32> = opt_table.iter().copied().collect();
6095-
let mut has_blockiseq = false;
60966094
while insn_idx < iseq_size {
60976095
// Get the current pc and opcode
60986096
let pc = unsafe { rb_iseq_pc_at_idx(iseq, insn_idx) };
@@ -6116,18 +6114,12 @@ fn compute_bytecode_info(iseq: *const rb_iseq_t, opt_table: &[u32]) -> BytecodeI
61166114
jump_targets.insert(insn_idx);
61176115
}
61186116
}
6119-
YARVINSN_send | YARVINSN_invokesuper => {
6120-
let blockiseq: IseqPtr = get_arg(pc, 1).as_iseq();
6121-
if !blockiseq.is_null() {
6122-
has_blockiseq = true;
6123-
}
6124-
}
61256117
_ => {}
61266118
}
61276119
}
61286120
let mut result = jump_targets.into_iter().collect::<Vec<_>>();
61296121
result.sort();
6130-
BytecodeInfo { jump_targets: result, has_blockiseq }
6122+
BytecodeInfo { jump_targets: result }
61316123
}
61326124

61336125
#[derive(Debug, PartialEq, Clone, Copy)]
@@ -6242,7 +6234,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
62426234

62436235
// Compute a map of PC->Block by finding jump targets
62446236
let jit_entry_insns = jit_entry_insns(iseq);
6245-
let BytecodeInfo { jump_targets, has_blockiseq } = compute_bytecode_info(iseq, &jit_entry_insns);
6237+
let BytecodeInfo { jump_targets } = compute_bytecode_info(iseq, &jit_entry_insns);
62466238

62476239
// Make all empty basic blocks. The ordering of the BBs matters for getting fallthrough jumps
62486240
// in good places, but it's not necessary for correctness. TODO: Higher quality scheduling during lowering.
@@ -6607,7 +6599,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
66076599
// Use FrameState to get kw_bits when possible, just like getlocal_WC_0.
66086600
let val = if !local_inval {
66096601
state.getlocal(ep_offset)
6610-
} else if ep_escaped || has_blockiseq {
6602+
} else if ep_escaped {
66116603
fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0, use_sp: false, rest_param: false })
66126604
} else {
66136605
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.without_locals() });
@@ -6730,7 +6722,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
67306722
// In case of JIT-to-JIT send locals might never end up in EP memory.
67316723
let val = state.getlocal(ep_offset);
67326724
state.stack_push(val);
6733-
} else if ep_escaped || has_blockiseq { // TODO: figure out how to drop has_blockiseq here
6725+
} else if ep_escaped {
67346726
// Read the local using EP
67356727
let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0, use_sp: false, rest_param: false });
67366728
state.setlocal(ep_offset, val); // remember the result to spill on side-exits
@@ -6751,7 +6743,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
67516743
YARVINSN_setlocal_WC_0 => {
67526744
let ep_offset = get_arg(pc, 0).as_u32();
67536745
let val = state.stack_pop()?;
6754-
if ep_escaped || has_blockiseq { // TODO: figure out how to drop has_blockiseq here
6746+
if ep_escaped {
67556747
// Write the local using EP
67566748
fun.push_insn(block, Insn::SetLocal { val, ep_offset, level: 0 });
67576749
} else if local_inval {

zjit/src/hir/opt_tests.rs

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2926,15 +2926,14 @@ mod hir_opt_tests {
29262926
Jump bb2(v5, v6)
29272927
bb2(v8:BasicObject, v9:NilClass):
29282928
v13:Fixnum[1] = Const Value(1)
2929-
SetLocal :a, l0, EP@3, v13
29302929
PatchPoint NoSingletonClass(Object@0x1000)
29312930
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
29322931
v31:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v8, HeapObject[class_exact*:Object@VALUE(0x1000)]
29332932
IncrCounter inline_iseq_optimized_send_count
2934-
v20:BasicObject = GetLocal :a, l0, EP@3
2935-
v24:BasicObject = GetLocal :a, l0, EP@3
2933+
v19:BasicObject = GetLocal :a, l0, EP@3
2934+
PatchPoint NoEPEscape(test)
29362935
CheckInterrupts
2937-
Return v24
2936+
Return v19
29382937
");
29392938
}
29402939

@@ -3415,15 +3414,14 @@ mod hir_opt_tests {
34153414
Jump bb2(v6, v7, v8)
34163415
bb2(v10:BasicObject, v11:BasicObject, v12:NilClass):
34173416
v16:ArrayExact = NewArray
3418-
SetLocal :a, l0, EP@3, v16
3419-
v22:TrueClass = Const Value(true)
3417+
v21:TrueClass = Const Value(true)
34203418
IncrCounter complex_arg_pass_caller_kwarg
3421-
v24:BasicObject = Send v11, 0x1000, :each_line, v22 # SendFallbackReason: Complex argument passing
3422-
v25:BasicObject = GetLocal :s, l0, EP@4
3423-
v26:BasicObject = GetLocal :a, l0, EP@3
3424-
v30:BasicObject = GetLocal :a, l0, EP@3
3419+
v23:BasicObject = Send v11, 0x1000, :each_line, v21 # SendFallbackReason: Complex argument passing
3420+
v24:BasicObject = GetLocal :s, l0, EP@4
3421+
v25:BasicObject = GetLocal :a, l0, EP@3
3422+
PatchPoint NoEPEscape(test)
34253423
CheckInterrupts
3426-
Return v30
3424+
Return v25
34273425
");
34283426
}
34293427

@@ -6523,7 +6521,6 @@ mod hir_opt_tests {
65236521
Jump bb2(v5, v6)
65246522
bb2(v8:BasicObject, v9:NilClass):
65256523
v13:ArrayExact = NewArray
6526-
SetLocal :result, l0, EP@3, v13
65276524
PatchPoint SingleRactorMode
65286525
PatchPoint StableConstantNames(0x1000, A)
65296526
v36:ArrayExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
@@ -6533,10 +6530,10 @@ mod hir_opt_tests {
65336530
PatchPoint NoSingletonClass(Array@0x1020)
65346531
PatchPoint MethodRedefined(Array@0x1020, zip@0x1028, cme:0x1030)
65356532
v43:BasicObject = CCallVariadic v36, :zip@0x1058, v39
6536-
v25:BasicObject = GetLocal :result, l0, EP@3
6537-
v29:BasicObject = GetLocal :result, l0, EP@3
6533+
v24:BasicObject = GetLocal :result, l0, EP@3
6534+
PatchPoint NoEPEscape(test)
65386535
CheckInterrupts
6539-
Return v29
6536+
Return v24
65406537
");
65416538
}
65426539

@@ -10559,25 +10556,24 @@ mod hir_opt_tests {
1055910556
Jump bb2(v8, v9, v10, v11, v12)
1056010557
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:BasicObject, v18:NilClass):
1056110558
CheckInterrupts
10562-
SetLocal :formatted, l0, EP@3, v15
1056310559
PatchPoint SingleRactorMode
10564-
v57:HeapBasicObject = GuardType v14, HeapBasicObject
10565-
v58:CShape = LoadField v57, :_shape_id@0x1000
10566-
v59:CShape[0x1001] = GuardBitEquals v58, CShape(0x1001)
10567-
StoreField v57, :@formatted@0x1002, v15
10568-
WriteBarrier v57, v15
10569-
v62:CShape[0x1003] = Const CShape(0x1003)
10570-
StoreField v57, :_shape_id@0x1000, v62
10571-
v46:Class[VMFrozenCore] = Const Value(VALUE(0x1008))
10560+
v56:HeapBasicObject = GuardType v14, HeapBasicObject
10561+
v57:CShape = LoadField v56, :_shape_id@0x1000
10562+
v58:CShape[0x1001] = GuardBitEquals v57, CShape(0x1001)
10563+
StoreField v56, :@formatted@0x1002, v15
10564+
WriteBarrier v56, v15
10565+
v61:CShape[0x1003] = Const CShape(0x1003)
10566+
StoreField v56, :_shape_id@0x1000, v61
10567+
v45:Class[VMFrozenCore] = Const Value(VALUE(0x1008))
1057210568
PatchPoint NoSingletonClass(Class@0x1010)
1057310569
PatchPoint MethodRedefined(Class@0x1010, lambda@0x1018, cme:0x1020)
10574-
v67:BasicObject = CCallWithFrame v46, :RubyVM::FrozenCore.lambda@0x1048, block=0x1050
10575-
v49:BasicObject = GetLocal :a, l0, EP@6
10576-
v50:BasicObject = GetLocal :_b, l0, EP@5
10577-
v51:BasicObject = GetLocal :_c, l0, EP@4
10578-
v52:BasicObject = GetLocal :formatted, l0, EP@3
10570+
v66:BasicObject = CCallWithFrame v45, :RubyVM::FrozenCore.lambda@0x1048, block=0x1050
10571+
v48:BasicObject = GetLocal :a, l0, EP@6
10572+
v49:BasicObject = GetLocal :_b, l0, EP@5
10573+
v50:BasicObject = GetLocal :_c, l0, EP@4
10574+
v51:BasicObject = GetLocal :formatted, l0, EP@3
1057910575
CheckInterrupts
10580-
Return v67
10576+
Return v66
1058110577
");
1058210578
}
1058310579

@@ -11579,9 +11575,8 @@ mod hir_opt_tests {
1157911575
v35:HeapObject[class_exact:B] = GuardType v10, HeapObject[class_exact:B]
1158011576
v36:BasicObject = CCallWithFrame v35, :Kernel#proc@0x1038, block=0x1040
1158111577
v18:BasicObject = GetLocal :blk, l0, EP@4
11582-
SetLocal :other_block, l0, EP@3, v36
11583-
v25:BasicObject = GetLocal :other_block, l0, EP@3
11584-
v27:BasicObject = InvokeSuper v10, 0x1048, v25 # SendFallbackReason: super: complex argument passing to `super` call
11578+
PatchPoint NoEPEscape(foo)
11579+
v27:BasicObject = InvokeSuper v10, 0x1048, v36 # SendFallbackReason: super: complex argument passing to `super` call
1158511580
CheckInterrupts
1158611581
Return v27
1158711582
");

zjit/src/invariants.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,20 +206,22 @@ pub extern "C" fn rb_zjit_invalidate_no_ep_escape(iseq: IseqPtr) {
206206
return;
207207
}
208208

209-
// Remember that this ISEQ may escape EP
210-
let invariants = ZJITState::get_invariants();
211-
invariants.ep_escape_iseqs.insert(iseq);
209+
with_vm_lock(src_loc!(), || {
210+
// Remember that this ISEQ may escape EP
211+
let invariants = ZJITState::get_invariants();
212+
invariants.ep_escape_iseqs.insert(iseq);
212213

213-
// If the ISEQ has been compiled assuming it doesn't escape EP, invalidate the JIT code.
214-
if let Some(patch_points) = invariants.no_ep_escape_iseq_patch_points.get(&iseq) {
215-
debug!("EP is escaped: {}", iseq_name(iseq));
214+
// If the ISEQ has been compiled assuming it doesn't escape EP, invalidate the JIT code.
215+
if let Some(patch_points) = invariants.no_ep_escape_iseq_patch_points.get(&iseq) {
216+
debug!("EP is escaped: {}", iseq_name(iseq));
216217

217-
// Invalidate the patch points for this ISEQ
218-
let cb = ZJITState::get_code_block();
219-
compile_patch_points!(cb, patch_points, "EP is escaped: {}", iseq_name(iseq));
218+
// Invalidate the patch points for this ISEQ
219+
let cb = ZJITState::get_code_block();
220+
compile_patch_points!(cb, patch_points, "EP is escaped: {}", iseq_name(iseq));
220221

221-
cb.mark_all_executable();
222-
}
222+
cb.mark_all_executable();
223+
}
224+
});
223225
}
224226

225227
/// Track that JIT code for a ISEQ will assume that base pointer is equal to environment pointer.

0 commit comments

Comments
 (0)