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
4 changes: 3 additions & 1 deletion majit/majit-metainterp/src/pyjitpl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5256,7 +5256,9 @@ impl<M: Clone> MetaInterp<M> {
// Bridge traces start from rebuilt resume state, not a fresh portal
// entry, so `initial_inputarg_consts` is not seeded with the
// virtualizable inputarg's ConstPtr. The TraceCtx pointer is the
// trace-bound equivalent of `orig_inpargs[idx].getref_base()`.
// trace-bound equivalent of `orig_inpargs[idx].getref_base()`
// (compile.py:510), which reads a value belonging to the trace being
// compiled and never an ambient one.
//
// Prefer it over MetaInterp's ambient pointer: an inlined residual
// callee can temporarily update `self.vable_ptr`, while the residual
Expand Down
46 changes: 26 additions & 20 deletions pyre/bench/synth/getframe_inline_subwalk_multiframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,38 @@
# forces an outer frame while the walk is already inside a residual call.
#
# The walker executes a residual call concretely, so that level gets a real
# frame from the interpreter's own call sequence; an inline push never runs
# that sequence, so its level has none. A force fired from the inlined body
# therefore builds a frame chain that mixes the two, and the chain's root is
# the intermediate residual frame rather than the walked frame -- which is
# what `try_adopt_multi_frame_blackhole` declines on today (it wants the
# `jit.virtual_ref` emit at the inline push, `executioncontext.py:89`). This
# fixture pins that the declined path still returns byte-identical results.
# frame from the interpreter's own call sequence; an inline push did not run
# that sequence, so its level had none. A force fired from the inlined body
# therefore built a frame chain that mixed the two, rooted at the intermediate
# residual frame rather than the walked frame, and
# `try_adopt_multi_frame_blackhole`'s chain-root identity gate declined it. What
# that decline wanted was the `jit.virtual_ref` emit at the inline push
# (`executioncontext.py:89`); `walker_ec_enter` / `walker_ec_leave` landed it.
# The gate no longer fires here: the shape now adopts once per build and returns
# the same result as before. This fixture pins that result.
#
# One `sys._getframe(1)` level does NOT reach the build: the chain needs a
# residual level under the walked frame and an inlined level under that, so
# the force has to reach two frames up. No other fixture in the corpus gets
# here -- swept with `PYRE_FBW_DEBUG_ABORT=1 PYRE_FBW_MULTIFRAME=1`, 0 of 310
# reach `BUILT multi-frame`, so without this one the path has no repro at all.
# here -- in the historical gate-enabled sweep with `PYRE_FBW_DEBUG_ABORT=1`,
# 0 of 310 reached `BUILT multi-frame`, so without this one the path has no
# repro at all.
#
# With the gate at its default the image is not built either, so under a plain
# run this is an output guard; the coverage it adds is for `PYRE_FBW_MULTIFRAME=1`
# (5 builds), which is how the gate's owner exercises the path.
# The multi-frame image is built unconditionally when the latch conditions hold,
# so this is both an output guard and build-path coverage: 5 builds, and now 5
# adopts with zero chain-root declines (`PYRE_FBW_DEBUG_ABORT=1` prints both
# tallies; the other 5 escapes in the run have `inline_subwalk=false` and take
# the single-frame arm).
#
# What the decline is holding back, measured by lifting it: the resumed chain
# shifts every `sys._getframe(n)` up exactly one level, so the read below lands
# on the module frame and raises `KeyError: 'base'`. Variants of this shape that
# cannot raise return a wrong number instead, silently -- `f_locals.get("base",
# -1)` scores -1 for 7, `len(f_locals)` scores the module globals' 12 for this
# frame's 3, `len(f_code.co_name)` scores `<module>`'s 8 for a 9-character
# caller name. So the adopt is wrong for every outcome arm, not only the one
# that carries a resume coordinate.
# What the decline used to hold back, measured by lifting it before the
# execution-context push landed: the resumed chain shifted every
# `sys._getframe(n)` up exactly one level, so the read below landed on the
# module frame and raised `KeyError: 'base'`. Variants of this shape that cannot
# raise returned a wrong number instead, silently -- `f_locals.get("base", -1)`
# scored -1 for 7, `len(f_locals)` scored the module globals' 12 for this
# frame's 3, `len(f_code.co_name)` scored `<module>`'s 8 for a 9-character
# caller name. That is the failure mode this fixture still guards: every outcome
# arm was wrong, not only the one carrying a resume coordinate.
#
# Deliberately carries no `# pyre-check: max-pypy-ratio=` header: this guards
# an output, and the forcing read makes it a poor perf subject.
Expand Down
37 changes: 18 additions & 19 deletions pyre/bench/synth/getframe_while_escaping_read_frame_identity.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
# The frame-identity read that the multi-frame blackhole adopt gets wrong, and
# the acceptance test for flipping `PYRE_FBW_MULTIFRAME` default-ON.
# The frame-identity read the multi-frame blackhole adopt commits, and the
# regression guard for making that path unconditional.
#
# The walk executes the forcing residual CONCRETELY, and an inline push never
# runs the interpreter's call sequence, so `ec.topframeref` still names the
# CALLER while the inlined callee body runs. A `sys._getframe` that is itself
# the escaping call therefore reads the caller's frame at walk time, and the
# adopt commits that answer instead of discarding it the way the legacy
# escape/replay path does.
# runs the interpreter's call sequence. Before `walker_ec_enter` /
# `walker_ec_leave` published the callee frame on the execution context,
# `ec.topframeref` still named the CALLER while the inlined callee body ran, so
# a `sys._getframe` that is itself the escaping call read the caller's frame at
# walk time and the adopt committed that answer instead of discarding it the way
# the legacy escape/replay path does. Measured then as one wrong iteration per
# multi-frame adopt, in each part:
#
# Measured 2026-07-26 with the gate forced on -- one wrong iteration per
# multi-frame adopt, 5 adopts and 5 wrong in each part:
#
# part_a `_gf()` names `main`, not `leaf`
# part_b `_gf(1)` names `<module>`, not `main` -- one level too far up, which
# part_a `_gf()` named `main`, not `leaf`
# part_b `_gf(1)` named `<module>`, not `main` -- one level too far up, which
# is the same error seen through the argument
#
# A `_gf(1)` reading `f_locals` on that shape raises `KeyError` for any caller
# A `_gf(1)` reading `f_locals` on that shape raised `KeyError` for any caller
# local, for the same reason and not because outer locals go unmaterialized.
#
# Both are correct with the gate off, which is the default, so this fixture
# passes today. It exists to fail loudly if the gate is flipped before the
# inlined-call push publishes the callee frame on the execution context. Note
# the read has to be the ESCAPING call: once the escape has happened, a
# `sys._getframe(1)` executed inside the blackhole is correct, because the chain
# publishes each level's frame as it runs.
# Both answers are correct now, with the adopt committing rather than declining
# (`PYRE_FBW_DEBUG_ABORT=1` prints one `adopted multi-frame terminal` per
# iteration that latches, and no `chain rooted at` decline). Note the read has
# to be the ESCAPING call: once the escape has happened, a `sys._getframe(1)`
# executed inside the blackhole was always correct, because the chain publishes
# each level's frame as it runs.
import sys

_gf = sys._getframe
Expand Down
2 changes: 1 addition & 1 deletion pyre/bench/synth/getframe_while_inlined_callee_subwalk.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Coverage guard for the multi-frame blackhole path (PYRE_FBW_MULTIFRAME).
# Coverage guard for the unconditional multi-frame blackhole path.
#
# A vable escape inside an INLINE sub-walk is what latches a multi-frame
# blackhole image. The rest of the corpus never produces one: every other
Expand Down
Loading
Loading