Skip to content

jit: retire two default-on FBW inline gates; const-class carrier-raise handler fix - #759

Merged
youknowone merged 3 commits into
mainfrom
single-walker
Jul 24, 2026
Merged

youknowone merged 3 commits into
mainfrom
single-walker

Conversation

@youknowone

@youknowone youknowone commented Jul 23, 2026 •

Copy link
Copy Markdown
Collaborator

Reduced to the unique delta over main after #723 (exc-edge try-block cluster) and #748 (gh#343 branchy plain-branch int-binop inline, landed unconditional) absorbed this branch's earlier work, and rebased onto current main (which includes #765 fixing the #763 build break).

What this PR does

1. Retire two default-on FBW inline gates (fd1a528)

PYRE_FBW_TRYBLOCK_INLINE and PYRE_FBW_CARRIER_RAISE were verified default-on with no remaining reason to toggle off, so their behavior is made unconditional and the gates dropped:

  • a try-block CALL whose except handler rejoins a loop always multi-frame-inlines; decline_inline_caller_frame_for_catch_marker now runs the any-loop rejoin test directly instead of branching between it and a specific-loop fallback.
  • the depth-2 carrier-boundary raise delivery in drive_bridge_carrier_walk is always active.
  • deletes the now-dead exc_handler_rejoins_specific_loop / enclosing_loop_header_jit_pc and the now-unused call_jit_pc parameter of decline_inline_caller_frame_for_catch_marker.
  • PYRE_CARRIER_EXC_RESUME stays (default-off lever).

2. gate-triage note (12ae744)

The branchy inlined-callee continuation gap's plain-branch subcase is closed unconditionally by #748; its exception-unwind subcase is handled by the now-unconditional try-block callee inline + carrier-boundary raise delivery. PYRE_CARRIER_EXC_RESUME recorded as kept (default-off; its bridge_guard_exc GC-rooting and unconditional execute_ll_raised assign are the parity gaps to close before enabling).

3. const-class carrier-raise handler fix (7b219bb)

Set class_of_last_exc_is_const on the carrier-raise handler entry. #723 shipped the carrier_raise_seed branch without setting it.

Verification

python3 ./pyre/check.py: dynasm 303/303, cranelift 303/303, wasm 300/300.

— commented by Claude

@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The changes add bridge-guard exception storage to TraceCtx, enable single-recipe carrier-raise handling without its feature gate, mark seeded exceptions as constant-class, simplify inline caller-frame checks, remove obsolete FBW helpers, and update gate-triage documentation and tests.

Changes

Bridge exception-resume and inline-walk behavior

Layer / File(s) Summary
Bridge guard exception storage
majit/majit-metainterp/src/trace_ctx.rs
TraceCtx stores, initializes, and exposes the raw exception payload associated with exception-guarded bridges.
Try-block inline admission
pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs, pyre/pyre-jit-trace/src/jitcode_dispatch/resume_snapshot.rs, pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs
Inline caller-frame checks use handler-target discovery and generic loop-rejoin analysis; obsolete exact-loop helpers are removed and call sites and tests use the revised signature.
Carrier raise seeding and sub-walk resume
pyre/pyre-jit-trace/src/trace.rs, pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs, pyre/pyre-jit-trace/src/jitcode_dispatch/fbw_state.rs, pyre/gate-triage.md
Single-recipe carrier raises enter root compilation without the removed gate, seeded exceptions are marked constant-class, and related gate-retirement records are updated.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant drive_bridge_carrier_walk
  participant full_body_walk_trace
  participant dispatch_via_miframe
  participant walk_position
  drive_bridge_carrier_walk->>full_body_walk_trace: compile root after single-recipe SubRaise
  full_body_walk_trace->>dispatch_via_miframe: resume carrier walk with raise seed
  dispatch_via_miframe->>walk_position: consume carrier_raise_seed
  walk_position->>walk_position: mark exception class as constant
Loading

Possibly related PRs

Poem

A rabbit hops through bridge and gate,
With guarded exceptions carried straight.
Seeds wake walks, const classes shine,
Inline frames rejoin the line.
Obsolete toggles fade from sight—
Hop, hop, the trace resumes just right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main themes: retiring FBW inline gates and fixing carrier-raise handler state.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch single-walker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3132c754a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// `catch_exception/L` for the enclosing try sits BEHIND it (between the
// CALL's post-call `-live-` and the next op), so scan backward — the same
// lookup the single-frame exception-edge router uses.
let candidate = crate::jitcode_dispatch::find_catch_before_resume_live(code, root_pc);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Probe the carrier catch from the live marker

For a carrier resume, the root frame pc is the after-residual -live- marker stored in the parent snapshot, while the CALL's catch_exception/L is immediately after that marker (the existing inline-call SubRaise path probes forward with try_catch_exception_at(code, op.next_pc)). Scanning backward from root_pc therefore misses the root handler, so carrier-boundary raises inside these try-block callees record RaiseNoRootCatch and fall back/deopt on every hot raise; the default-on inline widening makes those shapes eligible but then unable to bridge. Probe forward from the live marker instead.

AGENTS.md reference: AGENTS.md:L194-L195

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
majit/majit-metainterp/src/trace_ctx.rs (1)

1342-1361: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Doc comment now misdescribes set_bridge_guard_exc; it belongs on bridge_source_is_exception_guard.

The comment "True only for bridge traces sourced from an exception guard descr." was attached to bridge_source_is_exception_guard() before this change; inserting set_bridge_guard_exc/bridge_guard_exc() between the comment and the method left it misplaced, and bridge_source_is_exception_guard() now has no doc comment.

📝 Proposed fix
-    /// True only for bridge traces sourced from an exception guard descr.
     pub fn set_bridge_guard_exc(&mut self, guard_exc: i64) {
         self.bridge_guard_exc = guard_exc;
     }

     /// The exception value grabbed at the guard failure that triggered this
     /// bridge (0 when none). See `bridge_guard_exc`.
     pub fn bridge_guard_exc(&self) -> i64 {
         self.bridge_guard_exc
     }

+    /// True only for bridge traces sourced from an exception guard descr.
     pub fn bridge_source_is_exception_guard(&self) -> bool {
         self.bridge_source_is_exception_guard
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@majit/majit-metainterp/src/trace_ctx.rs` around lines 1342 - 1361, Move the
“True only for bridge traces sourced from an exception guard descr.” doc comment
from set_bridge_guard_exc to bridge_source_is_exception_guard, placing it
immediately before that method. Add an appropriate doc comment for
set_bridge_guard_exc or bridge_guard_exc describing the stored exception value,
preserving the existing bridge_guard_exc semantics.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pyre/gate-triage.md`:
- Line 173: Update the §5 gate inventory in pyre/gate-triage.md to include
PYRE_CARRIER_EXC_RESUME alongside PYRE_FBW_BRIDGE_SUBWALK_BINOP_INLINE, marking
it as the new default-off carrier-resume gate.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs`:
- Around line 380-393: Set the walker’s class-of-last-exception constant flag to
true in the carrier_raise_seed catch-entry branch before calling
vstack_enter_exception_handler, matching the sibling exc_edge_catch_target and
raise/r handler paths.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/resume_snapshot.rs`:
- Around line 1076-1112: Restructure the `fbw_carrier_raise_enabled()` path in
the `rejoins` calculation so it resolves only
`try_catch_exception_at(caller_jitcode, resume_pos)` and passes that target to
`exc_handler_rejoins_loop`, without requiring `enclosing_loop_header_jit_pc`.
Preserve the existing `.zip()` and `exc_handler_rejoins_specific_loop`
requirement for the carrier-disabled path, which still needs the call’s own loop
header.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs`:
- Around line 73-85: Add positive-path tests to
inline_caller_frame_distinguishes_try_block_catch_marker_decline, using real
jitcode with a handler that rejoins its loop. Cover both
fbw_carrier_raise_enabled() ANY-loop-rejoin admission and
exc_handler_rejoins_specific_loop admission, ensuring the assertions accept the
caller frame and exercise the relevant loop/catch metadata rather than empty
jitcode.

---

Outside diff comments:
In `@majit/majit-metainterp/src/trace_ctx.rs`:
- Around line 1342-1361: Move the “True only for bridge traces sourced from an
exception guard descr.” doc comment from set_bridge_guard_exc to
bridge_source_is_exception_guard, placing it immediately before that method. Add
an appropriate doc comment for set_bridge_guard_exc or bridge_guard_exc
describing the stored exception value, preserving the existing bridge_guard_exc
semantics.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0d1f0be9-7cb5-481b-8f4a-40d60ec77317

📥 Commits

Reviewing files that changed from the base of the PR and between 0a4c5a1 and 3132c75.

📒 Files selected for processing (15)
  • majit/majit-metainterp/src/jitdriver.rs
  • majit/majit-metainterp/src/trace_ctx.rs
  • pyre/bench/bridge_branchy_callee_regression.py
  • pyre/check.py
  • pyre/gate-triage.md
  • pyre/pyre-interpreter/src/executioncontext.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/fbw_state.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/resume_snapshot.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs
  • pyre/pyre-jit-trace/src/state.rs
  • pyre/pyre-jit-trace/src/trace.rs
  • pyre/pyre-jit/src/call_jit.rs
💤 Files with no reviewable changes (1)
  • pyre/pyre-interpreter/src/executioncontext.rs

Comment thread pyre/gate-triage.md Resolved
Comment on lines 73 to 85
fn inline_caller_frame_distinguishes_try_block_catch_marker_decline() {
// No after-residual catch resume → not a try-block CALL → accept.
assert_eq!(
decline_inline_caller_frame_for_catch_marker(Some(42)),
decline_inline_caller_frame_for_catch_marker(None, &[], 0),
Ok(()),
);
// A try-block CALL with no resolvable loop header / catch (empty jitcode)
// cannot prove its handler rejoins the CALL's loop → decline.
assert_eq!(
decline_inline_caller_frame_for_catch_marker(Some(42), &[], 0),
Err(InlineCallerFrameDecline::TryBlockCatchMarker),
);
assert_eq!(decline_inline_caller_frame_for_catch_marker(None), Ok(()));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add positive-path coverage for the try-block rejoin admission.

Both new cases only test the decline path (no resume, or unresolvable loop/catch on an empty jitcode). Neither the fbw_carrier_raise_enabled() ANY-loop-rejoin branch nor the exc_handler_rejoins_specific_loop branch is exercised with a real jitcode where the handler does rejoin a loop — the case this rework exists to admit. Since both gating flags default on, this is the production path and currently has no regression coverage; a test here would also have caught the .zip() conservatism gap flagged in resume_snapshot.rs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs` around lines 73 - 85, Add
positive-path tests to
inline_caller_frame_distinguishes_try_block_catch_marker_decline, using real
jitcode with a handler that rejoins its loop. Cover both
fbw_carrier_raise_enabled() ANY-loop-rejoin admission and
exc_handler_rejoins_specific_loop admission, ensuring the assertions accept the
caller frame and exercise the relevant loop/catch metadata rather than empty
jitcode.

@github-actions

github-actions Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit 7b219bb).
Updated: 2026-07-24T15:13:22.305Z

Files in the reviewed diff
majit/majit-metainterp/src/trace_ctx.rs
pyre/gate-triage.md
pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/fbw_state.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/resume_snapshot.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs
pyre/pyre-jit-trace/src/trace.rs

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

None.

3. Pre-existing mismatches (already present before this patch)

  • bridge_subwalk.rs:432 ↔ pyjitpl.py:1694: bridge walkback stores only last_exc_box and class_of_last_exc_is_const; it deliberately does not restore the concrete sym.last_exc_value. PyPy’s opimpl_raise updates all three fields, including last_exc_value = exc_value_box.getref(...). The new const-class assignment fixes one part, but not this older missing concrete-value writeback.

  • trace_ctx.rs:526 ↔ pyjitpl.py:3125: bridge_guard_exc is an unrooted raw integer pointer. PyPy retains the exception as a GC-visible object while preparing exception resumption. If PYRE_CARRIER_EXC_RESUME is enabled, a collection between storing and consuming this value can leave a stale pointer.

4. Structural adaptations

  • resume_snapshot.rs:1066 ↔ pyjitpl.py:2530: Pyre’s carrier-boundary eligibility analysis and explicit root-handler re-entry are a Rust/translated-JitCode adaptation. PyPy instead retains the complete framestack and repeatedly pops/reroutes frames in finishframe_exception; widening from the caller’s own loop to any enclosing loop is consistent with that model.

  • bridge_subwalk.rs:390 ↔ pyjitpl.py:1688: setting class_of_last_exc_is_const for a carrier-delivered inline raise is equivalent to PyPy’s opimpl_raise state transition. It is a necessary adaptation of Pyre’s split walker/symbol state, not a parity divergence.

@youknowone

Copy link
Copy Markdown
Collaborator Author

Review dispositions

Addressed the automated reviews (Codex + CodeRabbit + CI parity review). Two new commits: 2eb3ea3b3d2 (retire the three verified default-on gates) and d153e5126e3 (the confirmed handler-flag fix + caveats).

Fixed

  • bridge_subwalk.rs — class_of_last_exc_is_const stale on the carrier-raise handler entry (CodeRabbit, Major): confirmed real. The carrier-boundary raise branch seeded last_exc_value but left the flag at its pre-bridge value, unlike the sibling exc_edge_catch_target branch and the walk-level SubRaise routing (opimpl_raise). A reraise in the handler read stale exception state. Set it true to match. A reraise-in-handler repro is bit-exact (875000) on both backends and its carrier bridge compiles (loops_aborted=0).
  • resume_snapshot.rs:1112 — .zip() required a resolvable loop header even in the ANY-loop branch (CodeRabbit, Minor): already resolved by 2eb3ea3b3d2, which retires the gate and rewrites the decline to try_catch_exception_at(...).is_some_and(exc_handler_rejoins_loop) — no enclosing_loop_header_jit_pc dependency.
  • gate-triage.md — document PYRE_CARRIER_EXC_RESUME (CodeRabbit, Minor): added to the WIP-keep inventory with its pre-flip-on parity gaps.

Not a bug (verified)

  • trace.rs — "probe the carrier catch from the live marker" / backward scan misses the handler (Codex, P2): empirically refuted. PYRE_P2_DIAG shows carrier_root_catch_target (backward find_catch_before_resume_live) finds the root handler for every carrier try-block callee — catch_before=Some(2892) rejoins=true on exceptions, Some(1077) on break_except, Some(2820) on the reraise repro — and the bridges compile with loops_aborted=0. The forward try_catch_exception_at returns None at the carrier root_pc (the CALL's post-call -live-, catch sits behind); the forward probe is for the inline-call op.next_pc coordinate, a different site.

Deferred (inert / staged)

Structural adaptations (intended)

  • CI parity §2 carrier.recipes.len() == 1 — the delivery targets the depth-2 single-recipe carrier; deeper/return-out handlers stay on the residual path (correct, just not bridged) — incremental scope.
  • CI parity §2 TLS FBW_CARRIER_RAISE_SEED — set in drive_bridge_carrier_walk, consumed once in dispatch_via_miframe across the carrier boundary, with a defensive post-walk clear; the walk-context threading is a follow-up.
  • CI parity §4 sentinel-w_code skip and static exc_handler_rejoins_* analysis — deliberate adaptations to Pyre's synthetic virtualizable frames and CPython-compatible JitCode coordinates (commented in-code).

check.py dynasm 301/301, cranelift 301/301, wasm 297/297.

— commented by Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d153e5126e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// #343/#126 depth-2 exception-resume slice is validated bit-exact.
pub fn carrier_exc_resume_enabled() -> bool {
static ENABLED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
*ENABLED.get_or_init(|| std::env::var_os("PYRE_CARRIER_EXC_RESUME").is_some())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor PYRE_CARRIER_EXC_RESUME=0 as disabled

When a user or test harness exports PYRE_CARRIER_EXC_RESUME=0 to keep this default-off carrier exception resume disabled, this is_some() check still returns true. That unexpectedly runs the new exception-guard seeding path in setup_bridge_sym despite the comment advertising =1 enablement and the gate being documented as validation-only; use a value check such as == "1" or != "0" so rollback configs don't turn the experimental path on.

Useful? React with 👍 / 👎.

@youknowone youknowone changed the title jit: exc-edge try-block callee inline + carrier-raise; #343 branchy plain-branch subcase default-on jit: #343 branchy plain-branch subcase default-on; retire FBW inline gates; const-class carrier-raise fix Jul 24, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pyre/pyre-jit-trace/src/trace.rs (1)

1434-1609: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Require blackhole continuations to apply or abort without later replay.

drive_single_frame_blackhole resumes the frame through resume_mainloop()/run(), so side-effecting bytecode can execute before apply_single_frame_blackhole_crn() is reached. If that reconciliation returns false, try_adopt_single_frame_blackhole() returns false and walks back to the legacy residual-call path, which does not know about the blackhole continuation’s concrete effects. Track this case as a no-replay/abort condition so any run that produced execution effects cannot be followed by bytecode replay.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-jit-trace/src/trace.rs` around lines 1434 - 1609, Update
try_adopt_single_frame_blackhole and its caller to distinguish “not adopted”
from “abort without replay” when drive_single_frame_blackhole has executed
effects but apply_single_frame_blackhole_crn fails. Propagate a no-replay/abort
result through the walk-back path so the legacy residual-call path is never
entered after blackhole execution, while preserving normal fallback only when no
execution effects occurred.
pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs (1)

329-332: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Move CarrierRaiseSeed out of TLS and onto the active walk owner.

This is interpreter-owned exception-routing state tied to a specific multi-frame carrier walk, not reusable thread-local cache. Store it on WalkSession or a TraceCtx-scoped context and consume it there so its ownership, lifetime, and GC rooting stay trace-scoped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs` around lines 329
- 332, Replace the TLS-based carrier raise seed retrieval in the bridge sub-walk
flow with state owned by the active WalkSession or TraceCtx-scoped walk context.
Update the code that seeds and consumes CarrierRaiseSeed, including
drive_bridge_carrier_walk and the current bridge sub-walk owner, so the seed is
consumed exactly once from that walk-scoped state and remains GC-rooted for the
walk lifetime; remove reliance on take_carrier_raise_seed TLS storage.

Source: Coding guidelines

♻️ Duplicate comments (1)
pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs (1)

73-85: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing positive-path test for the try-block rejoin admission (unaddressed from prior review).

Both test cases only exercise the decline path. Neither the ANY-loop-rejoin admission nor a case where exc_handler_rejoins_loop actually returns true is exercised, so the production-path behavior this PR cohort is centered on (widening try-block CALL inlining when the handler rejoins a loop) has no regression coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs` around lines 73 - 85,
Extend inline_caller_frame_distinguishes_try_block_catch_marker_decline with a
positive try-block CALL case whose resolvable catch handler makes
exc_handler_rejoins_loop return true. Assert that
decline_inline_caller_frame_for_catch_marker returns Ok(()) for this
loop-rejoining handler, while preserving the existing no-resolvable-catch
decline case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pyre/gate-triage.md`:
- Around line 70-84: Synchronize gate lifecycle documentation: in
pyre/gate-triage.md lines 70-84, document only the verified subwalk/drain gates
as retired and retain PYRE_CARRIER_EXC_RESUME as default-off in the gate
inventory; in pyre/bench/bridge_branchy_callee_regression.py lines 16-22, remove
wording that presents the gates as active or explicitly mark it historical.

---

Outside diff comments:
In `@pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs`:
- Around line 329-332: Replace the TLS-based carrier raise seed retrieval in the
bridge sub-walk flow with state owned by the active WalkSession or
TraceCtx-scoped walk context. Update the code that seeds and consumes
CarrierRaiseSeed, including drive_bridge_carrier_walk and the current bridge
sub-walk owner, so the seed is consumed exactly once from that walk-scoped state
and remains GC-rooted for the walk lifetime; remove reliance on
take_carrier_raise_seed TLS storage.

In `@pyre/pyre-jit-trace/src/trace.rs`:
- Around line 1434-1609: Update try_adopt_single_frame_blackhole and its caller
to distinguish “not adopted” from “abort without replay” when
drive_single_frame_blackhole has executed effects but
apply_single_frame_blackhole_crn fails. Propagate a no-replay/abort result
through the walk-back path so the legacy residual-call path is never entered
after blackhole execution, while preserving normal fallback only when no
execution effects occurred.

---

Duplicate comments:
In `@pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs`:
- Around line 73-85: Extend
inline_caller_frame_distinguishes_try_block_catch_marker_decline with a positive
try-block CALL case whose resolvable catch handler makes
exc_handler_rejoins_loop return true. Assert that
decline_inline_caller_frame_for_catch_marker returns Ok(()) for this
loop-rejoining handler, while preserving the existing no-resolvable-catch
decline case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4b68487d-fde6-4aee-b701-25f88edf3caa

📥 Commits

Reviewing files that changed from the base of the PR and between 3132c75 and aef820e.

📒 Files selected for processing (11)
  • majit/majit-metainterp/src/trace_ctx.rs
  • pyre/bench/bridge_branchy_callee_regression.py
  • pyre/check.py
  • pyre/gate-triage.md
  • pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/fbw_state.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/resume_snapshot.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs
  • pyre/pyre-jit-trace/src/trace.rs

Comment thread pyre/gate-triage.md Resolved

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@majit/majit-metainterp/src/trace_ctx.rs`:
- Around line 532-539: Update TraceCtx::bridge_guard_exc so the exception
reference is kept through a TraceCtx-owned GC-rooted mechanism, or re-grabbed
from a valid rooted source immediately before consumption; remove the untraced
raw i64 storage. Ensure set_bridge_guard_exc and the corresponding seed/read
path preserve the reference across moving collections and retain interpreter/JIT
semantic parity when the gate is enabled.

In `@pyre/pyre-jit-trace/src/trace.rs`:
- Line 1274: Update the single-recipe path around the carrier recipe check to
stop sourcing CarrierRaiseSeed from TLS; store it on the active TraceCtx/bridge
context and drain it from that same context. Ensure the seed’s exception payload
is properly rooted for its lifetime, then make this path unconditional without
relying on thread-local state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: da0f0e7c-3ba4-48c2-af27-593bedfa7840

📥 Commits

Reviewing files that changed from the base of the PR and between aef820e and 34ad94c.

📒 Files selected for processing (11)
  • majit/majit-metainterp/src/trace_ctx.rs
  • pyre/bench/bridge_branchy_callee_regression.py
  • pyre/check.py
  • pyre/gate-triage.md
  • pyre/pyre-jit-trace/src/jitcode_dispatch/bridge_subwalk.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/fbw_state.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/inline_call.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/resume_snapshot.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/tests.rs
  • pyre/pyre-jit-trace/src/trace.rs
💤 Files with no reviewable changes (1)
  • pyre/pyre-jit-trace/src/jitcode_dispatch/fbw_state.rs

Comment on lines +532 to 539
///
/// NOT a traced GC root: it is stored unconditionally but only dereferenced
/// under the default-off `PYRE_CARRIER_EXC_RESUME` gate, so today no live
/// deref can outlive a moving collection. Before that gate is flipped on
/// this must become a real root (or be re-grabbed at read time), since a
/// collection between `set_bridge_guard_exc` and the seed read would leave
/// the raw integer stale — tracked as a pre-flip-on parity gap.
pub(crate) bridge_guard_exc: i64,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Root bridge_guard_exc before this can be enabled.

This stores a GC reference as an untraced i64; a moving collection between write and consume leaves a stale pointer. A default-off environment gate does not make an enableable JIT semantic divergence safe. Store it through a rooted TraceCtx-owned mechanism or re-grab it at consumption. As per coding guidelines, “The generated JIT must preserve the interpreter's semantics.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@majit/majit-metainterp/src/trace_ctx.rs` around lines 532 - 539, Update
TraceCtx::bridge_guard_exc so the exception reference is kept through a
TraceCtx-owned GC-rooted mechanism, or re-grabbed from a valid rooted source
immediately before consumption; remove the untraced raw i64 storage. Ensure
set_bridge_guard_exc and the corresponding seed/read path preserve the reference
across moving collections and retain interpreter/JIT semantic parity when the
gate is enabled.

Source: Coding guidelines

};
if let Some((exc, exc_concrete)) = subwalk_raise {
if carrier.recipes.len() == 1 && crate::jitcode_dispatch::fbw_carrier_raise_enabled() {
if carrier.recipes.len() == 1 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Move CarrierRaiseSeed off TLS before making this path unconditional.

This seed belongs to the active bridge/TraceCtx, not the OS thread. TLS can leak or be consumed by a reentrant same-thread walk; keep it in TraceCtx and drain it from that same context, with its exception payload properly rooted. As per coding guidelines, “Do not use TLS for process-global or interpreter-owned runtime state.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyre/pyre-jit-trace/src/trace.rs` at line 1274, Update the single-recipe path
around the carrier recipe check to stop sourcing CarrierRaiseSeed from TLS;
store it on the active TraceCtx/bridge context and drain it from that same
context. Ensure the seed’s exception payload is properly rooted for its
lifetime, then make this path unconditional without relying on thread-local
state.

Source: Coding guidelines

PYRE_FBW_TRYBLOCK_INLINE and PYRE_FBW_CARRIER_RAISE both defaulted on with
no remaining reason to toggle off once verified, so make their behavior
unconditional and drop the gates:

- a try-block CALL whose except handler rejoins a loop always
  multi-frame-inlines; decline_inline_caller_frame_for_catch_marker now
  runs the any-loop rejoin test directly instead of branching between it
  and a specific-loop fallback.
- the depth-2 carrier-boundary raise delivery in drive_bridge_carrier_walk
  is always active.

Deletes the now-dead exc_handler_rejoins_specific_loop and
enclosing_loop_header_jit_pc (only the carrier-raise-off branch used them)
and the now-unused call_jit_pc parameter of
decline_inline_caller_frame_for_catch_marker. PYRE_CARRIER_EXC_RESUME stays
(default-off lever).

exceptions / exception_args_virtual / break_except_live_local bit-exact
with loops_aborted=0; bridge_branchy_callee regression passes; check.py
dynasm 303/303, cranelift 303/303, wasm 300/300.

Assisted-by: Claude
…ume keep

Record in the PYRE_P2_DRAIN retirement note that the branchy inlined-callee
continuation gap's plain-branch subcase is closed unconditionally (the
carrier-resume sub-walk int-binop inline landed without a gate in #748), and
its exception-unwind subcase is handled by the now-unconditional try-block
callee inline + carrier-boundary raise delivery (PYRE_FBW_TRYBLOCK_INLINE /
PYRE_FBW_CARRIER_RAISE retired). Add PYRE_CARRIER_EXC_RESUME to Judged KEEP
(default-off; the bridge_guard_exc GC-rooting and the unconditional
execute_ll_raised exception assign are the parity gaps to close before it is
enabled by default).

Assisted-by: Claude
The carrier-boundary raise handler-entry branch in dispatch_via_miframe
seeded last_exc_value + the handler-entry operand stack but left
class_of_last_exc_is_const at its stale pre-bridge value, unlike the
sibling exc_edge_catch_target branch and the walk-level SubRaise routing
(opimpl_raise), which set it true. The seed's exception is a const-class
raise (the callee's inline RAISE recorded a NewWithVtable of a known
class), so a reraise in the handler read the standing exception state
from the stale flag. Set it true to match the siblings.

Document the default-off PYRE_CARRIER_EXC_RESUME pre-flip-on parity gaps
(gate-triage.md, trace_ctx.rs): the bridge_guard_exc GCREF-as-i64 is not a
traced root and the seed's execute_ll_raised assign is guarded by is_null
rather than unconditional; both are inert while the gate is off.

reraise-in-handler repro bit-exact (875000) on both backends; check.py
dynasm 301/301, cranelift 301/301, wasm 297/297.

Assisted-by: Claude
@youknowone youknowone changed the title jit: #343 branchy plain-branch subcase default-on; retire FBW inline gates; const-class carrier-raise fix jit: retire two default-on FBW inline gates; const-class carrier-raise handler fix Jul 24, 2026
@youknowone
youknowone merged commit 1d6fdc9 into main Jul 24, 2026
41 of 45 checks passed
@youknowone
youknowone deleted the single-walker branch July 24, 2026 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant