Skip to content
6 changes: 1 addition & 5 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,6 @@ pub(crate) fn compute_bridge_root_parent_frame<Sym: WalkSym>(
// `root_pc` (`resume_data.frames[0].pc`) is already the post-call resume
// point — the slot the inner frame's result lands in — so its Python
// coordinate is a direct backtranslation (no `semantic_fallthrough_pc`).
// This local remains needed by the outer-active-box collector; the paused
// parent frame itself carries `ParentResumeCoord::Backxlat(root_pc)`.
let root_py_pc = crate::state::backxlat_py_pc(jitcode_index as i32, root_pc as i32) as u32;
// Null the not-yet-produced call-result slot before collecting the active
// boxes (the reconstructed callee supplies it on `SubReturn`), mirroring
// `compute_inline_caller_frame`. Operate on a clone so `root_sym` stays a
Expand Down Expand Up @@ -470,8 +467,7 @@ pub(crate) fn compute_bridge_root_parent_frame<Sym: WalkSym>(
&regs_r,
root_sym.registers_f(),
jitcode_index,
root_py_pc,
None,
false,
// Key the query off the same carried root-frame word the snapshot and
// decode side read from `frames[0].jitcode_pc`, so both resolve the
// identical liveness window.
Expand Down
19 changes: 19 additions & 0 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/diag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,25 @@ pub(crate) fn pcmap_recipe_resultcolor_audit_enabled() -> bool {
*ENABLED.get_or_init(|| std::env::var_os("PYRE_PCMAP_RECIPE_RESULTCOLOR_AUDIT").is_some())
}

/// `PYRE_PCMAP_CONTAINING_AUDIT`: assert the Slice-B floor-only depth twin
/// (`depth_containing_for_jitcode_pc`) equals the raw
/// `depth_at_py_pc[vstack_containing_py_pc(jit_pc)]` read at both consumer
/// seams. Off in production; the gated branch is the only added code.
pub(crate) fn pcmap_containing_audit_enabled() -> bool {
static ENABLED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
*ENABLED.get_or_init(|| std::env::var_os("PYRE_PCMAP_CONTAINING_AUDIT").is_some())
}

/// `PYRE_PCMAP_AFTERRESIDUAL_AUDIT`: assert the Slice-C after-residual depth
/// twin (`depth_after_residual_for_jitcode_pc`) equals the raw
/// `depth_at_py_pc[semantic_fallthrough_pc(python_pc_for_jitcode_pc(jit_pc))]`
/// read at each consumer seam. Off in production; the gated branch is the only
/// added code.
pub(crate) fn pcmap_afterresidual_audit_enabled() -> bool {
static ENABLED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
*ENABLED.get_or_init(|| std::env::var_os("PYRE_PCMAP_AFTERRESIDUAL_AUDIT").is_some())
}

pub(crate) fn pcmap_recipe_resultcolor_audit_probe(site: &'static str, verdict: &'static str) {
if let Some(path) = std::env::var_os("PYRE_PCMAP_RECIPE_RESULTCOLOR_AUDIT_PROBE") {
use std::io::Write;
Expand Down
34 changes: 25 additions & 9 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -927,11 +927,30 @@ pub(crate) fn try_walker_call_assembler_self_recursive<Sym: WalkSym>(
let caller_code = unsafe { &*caller_jitcode.payload.code_ptr };
let call_py_pc = python_pc_for_jitcode_pc(&caller_jitcode.payload.metadata, op.pc) as usize;
let resume_py_pc = crate::pyjitpl::semantic_fallthrough_pc(caller_code, call_py_pc) as u32;
let resume_depth = crate::liveness::liveness_for(caller_jitcode.payload.code_ptr)
.depth_at_py_pc()
.get(resume_py_pc as usize)
.copied()
.unwrap_or(0) as usize;
let raw_depth = || {
crate::liveness::liveness_for(caller_jitcode.payload.code_ptr)
.depth_at_py_pc()
.get(resume_py_pc as usize)
.copied()
.unwrap_or(0) as usize
};
let resume_depth = if caller_jitcode.payload.depth_after_residual_populated() {
let depth = caller_jitcode
.payload
.depth_after_residual_for_jitcode_pc(op.pc)
.unwrap_or(0) as usize;
if pcmap_afterresidual_audit_enabled() {
assert_eq!(
depth,
raw_depth(),
"PYRE_PCMAP_AFTERRESIDUAL_AUDIT: self-recursive CA vstack depth twin diverged at jit_pc {} (py {resume_py_pc})",
op.pc
);
}
depth
} else {
raw_depth()
};
ctx.vstack_boxes.truncate(resume_depth);
ctx.vstack_boxes.resize(resume_depth, OpRef::NONE);
if resume_depth > 0 {
Expand Down Expand Up @@ -1964,8 +1983,6 @@ pub(crate) fn try_walker_inline_resolved_user_call<Sym: WalkSym>(
let jc_index = jc.index as u32;
(jc_index, jc.payload.resume_marker_for_jitcode_pc(op.pc))
};
let call_site_py_pc =
crate::state::backxlat_py_pc(call_site_jc_index as i32, op.pc as i32) as u32;
let call_site_word = match call_site_marker {
Some(m) => m as i32,
None => majit_ir::resumedata::NO_JITCODE_PC,
Expand All @@ -1977,8 +1994,7 @@ pub(crate) fn try_walker_inline_resolved_user_call<Sym: WalkSym>(
ctx.registers_r,
ctx.registers_f,
call_site_jc_index,
call_site_py_pc,
None,
false,
call_site_word,
// Keep the marker for the liveness-bank query, but key
// entry metadata to the raw CALL offset that produced the
Expand Down
44 changes: 30 additions & 14 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3435,8 +3435,7 @@ fn collect_outer_active_boxes<Sym: WalkSym>(
regs_r: &[OpRef],
regs_f: &[OpRef],
outer_jitcode_index: u32,
entry_py_pc: u32,
guard_py_pc: Option<u32>,
guard_present: bool,
// The resume-carried coordinate remains the bank-liveness source. Entry
// metadata can be derived from an earlier raw operation coordinate, so it
// must travel independently rather than inheriting that marker word.
Expand Down Expand Up @@ -3523,7 +3522,7 @@ fn collect_outer_active_boxes<Sym: WalkSym>(
// #348: per-snapshot-coordinate color→slot entries — the color→slot source
// the inversions below consult for every drained (non-portal) jitcode, the
// per-program-point color space the `-live-` markers carry. Branch-guard
// resumes (`guard_py_pc.is_some()`) are fully covered here; a per-opcode-entry
// resumes (`guard_present`) are fully covered here; a per-opcode-entry
// resume whose live Ref colors are all constants/leaked carries no entry (the
// resume snapshot records Variables only), so `semantic_ref_slot_for_reg_color`
// returns `None` and the live color falls to the `regs_r[color]` walk-bank
Expand Down Expand Up @@ -3556,7 +3555,7 @@ fn collect_outer_active_boxes<Sym: WalkSym>(
(!pcdep_entries.is_empty()).then(|| pcdep_entries.as_slice());
let stack_livereg_gate = fbw_stack_livereg_enabled();
let (guard_pcdep_entries, guard_stack_only) = if stack_livereg_gate {
if let Some(gpc) = guard_py_pc {
if guard_present {
if sym.jitcode().is_null() {
(Vec::new(), 0usize)
} else {
Expand Down Expand Up @@ -3619,7 +3618,7 @@ fn collect_outer_active_boxes<Sym: WalkSym>(
format!(
"collect_outer_active_boxes: liveness-active {bank} \
register {reg_idx} holds OpRef::NONE \
(outer_jitcode_index={outer_jitcode_index}, entry_py_pc={entry_py_pc}, \
(outer_jitcode_index={outer_jitcode_index}, entry_jitcode_pc={entry_jitcode_pc}, \
nlocals={nlocals}, owns_vable={owns_vable}, \
vable_len={vable_len}, \
num_regs_i={ni}, num_regs_r={nr}, num_regs_f={nf}, \
Expand Down Expand Up @@ -3651,11 +3650,11 @@ fn collect_outer_active_boxes<Sym: WalkSym>(
// the stale `registers_r[merge_color]` / edge-recovery color heuristics
// below, which read a color the regalloc reused between the guard pc and
// the resume pc (the #424 merge-color-staleness corruption). Scoped to
// the branch-guard reconstruction (`guard_py_pc`); the merge-color
// the branch-guard reconstruction (`guard_present`); the merge-color
// heuristics below remain only as the fallback for slots the mirror does
// not cover (mirror invalid, or an Int-bank temp the Ref-only mirror does
// not hold).
let vstack_mirror: Option<&[OpRef]> = vstack.filter(|_| guard_py_pc.is_some());
let vstack_mirror: Option<&[OpRef]> = vstack.filter(|_| guard_present);
for &idx in &banks.ref_ {
let color = idx as usize;
if let Some(mirror) = vstack_mirror {
Expand Down Expand Up @@ -3791,7 +3790,7 @@ fn collect_outer_active_boxes<Sym: WalkSym>(
let walk_real =
walk_box.filter(|&v| v != OpRef::NONE && !opref_is_null_const_ptr(v));
let guard_pc_proves_slot = stack_livereg_gate
&& guard_py_pc.is_some()
&& guard_present
&& crate::state::semantic_ref_slot_for_reg_color(
nlocals,
guard_stack_only,
Expand All @@ -3817,7 +3816,7 @@ fn collect_outer_active_boxes<Sym: WalkSym>(
let walk_is_real = walk_box
.is_some_and(|b| b != OpRef::NONE && !opref_is_null_const_ptr(b));
let shadow_is_real = vbox.is_some_and(|b| !opref_is_null_const_ptr(b));
if guard_py_pc.is_some() && walk_is_real {
if guard_present && walk_is_real {
walk_box.unwrap_or_else(fallback)
} else if shadow_is_real {
vbox.unwrap_or_else(fallback)
Expand Down Expand Up @@ -4806,11 +4805,28 @@ impl ActiveResumeFrame {
return None;
}
let py_pc = vstack_containing_py_pc(&pjc.metadata, jit_pc);
let depth = crate::liveness::liveness_for(pjc.code_ptr)
.depth_at_py_pc()
.get(py_pc as usize)
.copied()
.unwrap_or(0) as usize;
// Raw py_pc-keyed static-liveness read: the unpopulated-twin fallback
// (skeleton / fixture) and the audit oracle.
let raw_depth = || {
crate::liveness::liveness_for(pjc.code_ptr)
.depth_at_py_pc()
.get(py_pc as usize)
.copied()
.unwrap_or(0) as usize
};
let depth = if pjc.depth_containing_populated() {
let depth = pjc.depth_containing_for_jitcode_pc(jit_pc).unwrap_or(0) as usize;
if pcmap_containing_audit_enabled() {
assert_eq!(
depth,
raw_depth(),
"PYRE_PCMAP_CONTAINING_AUDIT: resume-frame containing-depth twin diverged at jit_pc {jit_pc} (py {py_pc})"
);
}
depth
} else {
raw_depth()
};
Some((py_pc, pjc.code_ptr, depth))
}

Expand Down
Loading
Loading