Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pub(crate) fn decode_side_other_target(
/// genuine not-taken-arm jitcode offset (`derived` / other_target) DIRECTLY:
/// `decode_side_other_target` picks the not-taken arm from `orgpc` + flavor and
/// that jitcode offset IS the returned value. The former py_pc round-trip
/// (`python_pc_for_jitcode_pc` -> `skip_python_trivia_forward` ->
/// (`containing_py_pc_for_jitcode_pc` -> `skip_python_trivia_forward` ->
/// historical Python-pc translation, with its `num_instrs` overshoot clamp) is
/// deleted:
/// it is byte-identical because the encode self-cert
Expand Down Expand Up @@ -225,8 +225,8 @@ pub(crate) fn branch_resume_target_stack_depth(
}
// Source the not-taken-arm depth off the genuine jitcode `target` through
// the compile-time `depth_trivia` twin, retiring the
// `python_pc_for_jitcode_pc` inversion + runtime
// `skip_python_trivia_forward` + static-liveness read. The twin is built for
// `containing_py_pc_for_jitcode_pc` + runtime `skip_python_trivia_forward`
// + static-liveness read. The twin is built for
// every drained real-code jitcode (codewriter.rs), and the encode census
// (`PYRE_M73_ENCODE_AUDIT`) proved the empty-twin fallback is never reached
// here (0 fallback trips / 162 programs; this reader 1181 hits, all
Expand Down
2 changes: 1 addition & 1 deletion pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1010,7 +1010,7 @@ pub(crate) fn recipe_parent_frame_from_recipe(
call_jitcode_pc: call_jit_pc,
call_stack_overrides: Vec::new(),
blackhole,
// The recipe's resolved word was `backxlat_py_pc(jitcode_index,
// The recipe's resolved word was `trivia_normalized_py_pc_for_jitcode_pc(jitcode_index,
// jitcode_pc)` by construction, exactly the bridge-root flavor.
resume_coord: ParentResumeCoord::Backxlat(recipe.jitcode_pc as usize),
resume_marker_jit_pc,
Expand Down
81 changes: 24 additions & 57 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/diag.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
//! pc-map inversion helpers and `PYRE_PCMAP_*` audit probes.
//! pc-map audit probes.
//!
//! **Parity:** pyre-specific — the jitcode-pc <-> python-pc inversion and
//! the `PYRE_PCMAP_*` audit probes have no `rpython/jit/metainterp/`
//! counterpart (PyPy's pc handling is codewriter-side).
//! **Parity:** pyre-specific — the `PYRE_PCMAP_*` audit probes have no
//! `rpython/jit/metainterp/` counterpart (PyPy's pc handling is
//! codewriter-side).
//!
//! Extracted verbatim from `jitcode_dispatch/mod.rs`: the jitcode-pc ->
//! python-pc inversion (`python_pc_for_jitcode_pc` + floor-boundary
//! helpers), the `skip_python_trivia_forward` boundary walker, and the
//! report-only `PYRE_PCMAP_*` audit probes.
//! Extracted verbatim from `jitcode_dispatch/mod.rs`: the
//! `skip_python_trivia_forward` boundary walker and the report-only
//! `PYRE_PCMAP_*` audit probes.

use super::*;

Expand All @@ -31,7 +30,7 @@ pub(crate) fn pcmap_containing_audit_enabled() -> bool {

/// `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))]`
/// `depth_at_py_pc[semantic_fallthrough_pc(containing_py_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 {
Expand Down Expand Up @@ -90,14 +89,16 @@ pub(crate) fn pcmap_recipe_resultcolor_audit_probe(site: &'static str, verdict:
pub(crate) fn resolve_parent_resume_py_pc(parent: &InlineParentFrame) -> Option<u32> {
match parent.resume_coord {
ParentResumeCoord::Backxlat(jitcode_pc) => {
// #73: read the forward py_pc twin (a codewriter-built,
// trivia-normalized twin of `backxlat_py_pc`'s result — proven equal
// corpus-wide in Slice 3'). The inversion survives only for the
// empty-twin class (skeleton / fixture jitcodes).
// #73: read the forward py_pc twin, a codewriter-built
// trivia-normalized twin of the containing coordinate. The
// containing lookup survives only for the empty-twin class.
let twin = crate::state::pyjitcode_for_jitcode_index(parent.jitcode_index as i32)
.and_then(|pjc| pjc.forward_py_pc_for_jitcode_pc(jitcode_pc));
Some(twin.unwrap_or_else(|| {
crate::state::backxlat_py_pc(parent.jitcode_index as i32, jitcode_pc as i32) as u32
crate::py_coord::trivia_normalized_py_pc_for_jitcode_pc(
parent.jitcode_index as i32,
jitcode_pc as i32,
) as u32
}))
}
ParentResumeCoord::CallFallthrough(call_jit_pc) => {
Expand All @@ -108,11 +109,13 @@ pub(crate) fn resolve_parent_resume_py_pc(parent: &InlineParentFrame) -> Option<
if pjc.code_ptr.is_null() {
return None;
}
// #73 Slice 4: read the forward after-residual fallthrough twin. The
// inversion survives only for the empty-twin class (populated code
// with no Python map) and as the audit oracle.
// #73 Slice 4: read the forward after-residual fallthrough twin.
// The containing lookup survives only for the empty-twin class
// (populated code with no Python map) and as the audit oracle.
let legacy = || {
let call_py_pc = python_pc_for_jitcode_pc(&pjc.metadata, call_jit_pc) as usize;
let call_py_pc =
crate::py_coord::containing_py_pc_for_jitcode_pc(&pjc.metadata, call_jit_pc)
as usize;
let code = unsafe { &*pjc.code_ptr };
crate::pyjitpl::semantic_fallthrough_pc(code, call_py_pc) as u32
};
Expand All @@ -137,43 +140,6 @@ pub(crate) fn resolve_parent_resume_py_pc(parent: &InlineParentFrame) -> Option<
}
}

pub(crate) fn floor_boundary_at_or_after(
metadata: &crate::PyJitCodeMetadata,
jit_pc: usize,
) -> Option<(usize, u32)> {
let table = &metadata.py_floor_by_jit_pc;
let idx = table.partition_point(|&(off, _)| (off as usize) < jit_pc);
table.get(idx).map(|&(off, py)| (off as usize, py))
}

pub(crate) fn first_floor_boundary_for_py(
metadata: &crate::PyJitCodeMetadata,
py_pc: u32,
) -> Option<(usize, u32)> {
metadata
.py_floor_by_jit_pc
.iter()
.find(|&&(_, py)| py == py_pc)
.map(|&(off, py)| (off as usize, py))
}

pub(crate) fn python_pc_for_jitcode_pc(metadata: &crate::PyJitCodeMetadata, jit_pc: usize) -> u32 {
if !metadata.py_floor_by_jit_pc.is_empty() {
let pivot = metadata
.block_head_py_by_jit_pc
.binary_search_by_key(&jit_pc, |&(off, _)| off)
.ok()
.map(|i| metadata.block_head_py_by_jit_pc[i].1)
.or_else(|| {
crate::pyjitcode::floor_segment_for_jitcode_pc(&metadata.py_floor_by_jit_pc, jit_pc)
.map(|(_, py)| py)
})
.expect("drained JitCode PC floor pivot must begin at byte offset zero");
return pivot;
}
0
}

/// Resolve an in-flight body channel exactly where a stash match needs its
/// Python body pc. A missing JitCode entry is deliberately `None`: callers
/// treat it as no match and retain the legacy replay/delivery fallback.
Expand All @@ -183,8 +149,9 @@ pub(crate) fn inflight_foriter_body_pc(body: InflightForiterBody) -> Option<usiz
InflightForiterBody::Jit {
outer_jitcode_index,
op_pc,
} => crate::state::pyjitcode_for_jitcode_index(outer_jitcode_index as i32)
.map(|jc| python_pc_for_jitcode_pc(&jc.metadata, op_pc) as usize + 1),
} => crate::state::pyjitcode_for_jitcode_index(outer_jitcode_index as i32).map(|jc| {
crate::py_coord::containing_py_pc_for_jitcode_pc(&jc.metadata, op_pc) as usize + 1
}),
}
}

Expand Down
12 changes: 8 additions & 4 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/fbw_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1692,9 +1692,10 @@ pub(crate) fn fbw_publish_exit_last_instr<Sym: WalkSym>(
let session = ctx.session.borrow();
(session.recording_frame_ptr, session.recording_jitcode_index)
};
let Some(py_pc) =
crate::state::python_pc_for_jitcode_pc_public(jitcode_index, opcode_position as i32)
else {
let Some(py_pc) = crate::py_coord::containing_py_pc_for_jitcode_pc_public(
jitcode_index,
opcode_position as i32,
) else {
return;
};
let Some(vbox) = ctx.trace_ctx.standard_virtualizable_box() else {
Expand Down Expand Up @@ -1802,7 +1803,10 @@ pub(crate) fn fbw_abort_resume_py_pc<Sym: WalkSym>(
if jc.payload.code_ptr.is_null() {
return None;
}
Some(python_pc_for_jitcode_pc(&jc.payload.metadata, abort_jit_pc) as usize)
Some(
crate::py_coord::containing_py_pc_for_jitcode_pc(&jc.payload.metadata, abort_jit_pc)
as usize,
)
}

/// Every pc in `body_code` that some op can branch to: the `goto` family and
Expand Down
99 changes: 61 additions & 38 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1004,11 +1004,13 @@ pub(crate) fn try_walker_call_assembler_self_recursive<Sym: WalkSym>(
let caller_jitcode = unsafe { &*sym.jitcode() };
let caller_code = unsafe { &*caller_jitcode.payload.code_ptr };
// #73 Slice 4: forward after-residual fallthrough coordinate; the
// inversion survives only for the empty-twin class and as the audit
// oracle.
// containing lookup survives only for the empty-twin class and as the
// audit oracle.
let legacy_resume_py_pc = || {
let call_py_pc =
python_pc_for_jitcode_pc(&caller_jitcode.payload.metadata, op.pc) as usize;
let call_py_pc = crate::py_coord::containing_py_pc_for_jitcode_pc(
&caller_jitcode.payload.metadata,
op.pc,
) as usize;
crate::pyjitpl::semantic_fallthrough_pc(caller_code, call_py_pc) as u32
};
let resume_py_pc = match caller_jitcode
Expand Down Expand Up @@ -2098,40 +2100,56 @@ pub(crate) fn try_walker_inline_builtin_call<Sym: WalkSym>(
if sym.jitcode().is_null() {
return Ok(None);
}
let (call_site_py_pc, vsd_value, outer_jitcode_index, call_site_marker) =
if nested_helper_entry.is_some() {
(
ctx.entry_py_pc(),
0,
ctx.outer_jitcode_index,
ctx.outer_resume_marker_jit_pc,
)
} else {
unsafe {
let jc = &*sym.jitcode();
let jc_index = jc.index as u32;
let marker = jc.payload.resume_marker_for_jitcode_pc(op.pc);
let mut py = python_pc_for_jitcode_pc(&jc.payload.metadata, op.pc);
if jc.payload.code_ptr.is_null() {
(py, sym.valuestackdepth() as i64, jc_index, marker)
let (call_site_py_pc, vsd_value, outer_jitcode_index, call_site_marker) = if nested_helper_entry
.is_some()
{
(
ctx.entry_py_pc(),
0,
ctx.outer_jitcode_index,
ctx.outer_resume_marker_jit_pc,
)
} else {
unsafe {
let jc = &*sym.jitcode();
let jc_index = jc.index as u32;
let marker = jc.payload.resume_marker_for_jitcode_pc(op.pc);
// Forward py twin first (#73 phase-3): equals the
// containing coordinate plus trivia normalization by
// construction; the containing lookup survives for the
// empty-twin class, and the trivia skip below is an identity
// on the twin path.
let mut py = jc
.payload
.forward_py_pc_for_jitcode_pc(op.pc)
.unwrap_or_else(|| {
crate::py_coord::note_empty_twin_fallback(
"builtin_call",
jc.index,
op.pc as i32,
);
crate::py_coord::containing_py_pc_for_jitcode_pc(&jc.payload.metadata, op.pc)
});
if jc.payload.code_ptr.is_null() {
(py, sym.valuestackdepth() as i64, jc_index, marker)
} else {
let codeobj = &*jc.payload.code_ptr;
py = skip_python_trivia_forward(codeobj, py as usize) as u32;
let depth = if jc.payload.depth_trivia_populated() {
jc.payload.depth_trivia_for_jitcode_pc(op.pc)
} else {
let codeobj = &*jc.payload.code_ptr;
py = skip_python_trivia_forward(codeobj, py as usize) as u32;
let depth = if jc.payload.depth_trivia_populated() {
jc.payload.depth_trivia_for_jitcode_pc(op.pc)
} else {
crate::liveness::liveness_for(jc.payload.code_ptr)
.depth_at_py_pc()
.get(py as usize)
.copied()
};
let vsd = depth
.map(|d| (sym.nlocals() + d as usize) as i64)
.unwrap_or(sym.valuestackdepth() as i64);
(py, vsd, jc_index, marker)
}
crate::liveness::liveness_for(jc.payload.code_ptr)
.depth_at_py_pc()
.get(py as usize)
.copied()
};
let vsd = depth
.map(|d| (sym.nlocals() + d as usize) as i64)
.unwrap_or(sym.valuestackdepth() as i64);
(py, vsd, jc_index, marker)
}
};
}
};
let call_site_word = call_site_marker
.map(|marker| marker as i32)
.unwrap_or(majit_ir::resumedata::NO_JITCODE_PC);
Expand Down Expand Up @@ -4084,7 +4102,9 @@ pub(crate) fn try_walker_inline_resolved_user_call<Sym: WalkSym>(
let callee_pjc =
crate::state::pyjitcode_for_code(w_code).ok_or("no callee pyjitcode")?;
let metadata = &callee_pjc.metadata;
let callee_py_pc = python_pc_for_jitcode_pc(metadata, abort_pc) as usize;
let callee_py_pc =
crate::py_coord::containing_py_pc_for_jitcode_pc(metadata, abort_pc)
as usize;
// Both abort kinds sit at the head of an opcode the walker
// could not take, behind at most that opcode's own vable
// spill; the marker kind is the narrower of the two.
Expand All @@ -4096,7 +4116,10 @@ pub(crate) fn try_walker_inline_resolved_user_call<Sym: WalkSym>(
body.code,
callee_py_pc,
abort_pc,
|op_pc| python_pc_for_jitcode_pc(metadata, op_pc) as usize,
|op_pc| {
crate::py_coord::containing_py_pc_for_jitcode_pc(metadata, op_pc)
as usize
},
);
if !anchor_ok {
if fbw_debug_abort_enabled() {
Expand Down
24 changes: 14 additions & 10 deletions pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ fn record_inline_application_traceback<Sym: WalkSym>(
// substitute `frame.last_instr`. Whether an unmappable coordinate
// should still contribute a node is a separate question from which
// frame the node names.
let node_frame = crate::state::python_pc_for_jitcode_pc_public(
let node_frame = crate::py_coord::containing_py_pc_for_jitcode_pc_public(
consts.jitcode_index,
opcode_position as i32,
)
Expand Down Expand Up @@ -811,8 +811,10 @@ fn traceback_node_site<Sym: WalkSym>(
return None;
}
let jitcode = crate::state::pyjitcode_for_jitcode_index(jitcode_index)?;
let last_instruction =
crate::state::python_pc_for_jitcode_pc_public(jitcode_index, opcode_position as i32)?;
let last_instruction = crate::py_coord::containing_py_pc_for_jitcode_pc_public(
jitcode_index,
opcode_position as i32,
)?;
let raw_code = crate::state::raw_code_for_jitcode_index(jitcode_index)?;
let lineno =
unsafe { pyre_interpreter::pyframe::offset2lineno(&*raw_code, last_instruction as isize) }
Expand Down Expand Up @@ -1081,8 +1083,9 @@ impl<Sym: WalkSym> Copy for FbwWalkMode<Sym> {}

/// The outer snapshot's Python-PC coordinate. Non-root producers preserve the
/// raw JitCode offset that produced the Python word, postponing the exact
/// `backxlat_py_pc` inversion until a consumer needs it. Root entries and test
/// fixtures have no such native coordinate and retain their Python value.
/// `trivia_normalized_py_pc_for_jitcode_pc` lookup until a consumer needs it.
/// Root entries and test fixtures have no such native coordinate and retain
/// their Python value.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum EntryPyPc {
Py(u32),
Expand Down Expand Up @@ -1387,7 +1390,7 @@ pub struct WalkContext<'frame, 'static_a: 'frame, Sym: WalkSym> {
/// was reconciled).
pub vstack_depth: usize,
/// #73: the Python pc of the opcode currently being walked. A change
/// in `python_pc_for_jitcode_pc(jit_pc)` from this value marks a
/// in `containing_py_pc_for_jitcode_pc(jit_pc)` from this value marks a
/// Python-opcode boundary, where the previous opcode's stack effect is
/// reconciled into `vstack_boxes` (see [`reconcile_vstack_at_boundary`]).
pub vstack_cur_pypc: u32,
Expand Down Expand Up @@ -1429,7 +1432,7 @@ impl<Sym: WalkSym> WalkContext<'_, '_, Sym> {
fn entry_py_pc(&self) -> u32 {
match self.entry_py_pc {
EntryPyPc::Py(py_pc) => py_pc,
EntryPyPc::Jit(jitcode_pc) => crate::state::forward_py_pc_or_backxlat(
EntryPyPc::Jit(jitcode_pc) => crate::py_coord::resume_py_pc_for_jitcode_word(
self.outer_jitcode_index as i32,
jitcode_pc as i32,
) as u32,
Expand Down Expand Up @@ -5145,11 +5148,11 @@ struct InlineParentBlackhole {
/// The derivation flavor of a paused caller frame's Python resume pc.
#[derive(Clone, Copy)]
enum ParentResumeCoord {
/// `resume_py_pc = backxlat_py_pc(jitcode_index, jitcode_pc)`. Used by
/// `resume_py_pc = trivia_normalized_py_pc_for_jitcode_pc(jitcode_index, jitcode_pc)`. Used by
/// both bridge-root and reconstructed-recipe parent frames.
Backxlat(usize),
/// `resume_py_pc = semantic_fallthrough_pc(code,
/// python_pc_for_jitcode_pc(metadata, call_jitcode_pc))`.
/// containing_py_pc_for_jitcode_pc(metadata, call_jitcode_pc))`.
CallFallthrough(usize),
}

Expand Down Expand Up @@ -8068,7 +8071,8 @@ fn walker_foriter_green_key<Sym: WalkSym>(
if w_code.is_null() {
return None;
}
let foriter_start_pc = python_pc_for_jitcode_pc(&jitcode.payload.metadata, op_pc) as usize;
let foriter_start_pc =
crate::py_coord::containing_py_pc_for_jitcode_pc(&jitcode.payload.metadata, op_pc) as usize;
Some(crate::driver::make_green_key(w_code, foriter_start_pc))
}

Expand Down
3 changes: 2 additions & 1 deletion pyre/pyre-jit-trace/src/jitcode_dispatch/residual_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1963,7 +1963,8 @@ pub(crate) fn probe_resid_decline_ctx<Sym: WalkSym>(
let s = unsafe { &*sym };
if !s.jitcode().is_null() {
let jc = unsafe { &*s.jitcode() };
let pc = python_pc_for_jitcode_pc(&jc.payload.metadata, op_pc) as usize;
let pc = crate::py_coord::containing_py_pc_for_jitcode_pc(&jc.payload.metadata, op_pc)
as usize;
let op = if !jc.payload.code_ptr.is_null() {
pyre_interpreter::decode_instruction_at(unsafe { &*jc.payload.code_ptr }, pc)
.map(|(i, _)| format!("{i:?}"))
Expand Down
Loading
Loading