Skip to content

jit: remove dead loop-trace operand-stack seed from run_perfn_walk#520

Merged
youknowone merged 1 commit into
mainfrom
nbody
Jul 13, 2026
Merged

jit: remove dead loop-trace operand-stack seed from run_perfn_walk#520
youknowone merged 1 commit into
mainfrom
nbody

Conversation

@youknowone

Copy link
Copy Markdown
Owner

Design cleanup following the gh#152 per-iteration FOR_ITER reload (#436): the walk-side loop-trace operand-stack seed no longer has a consumer.

Change

run_perfn_walk's argboxes seeding had a non-bridge arm that copied sym.registers_r operand-stack colors (nlocals..nlocals+depth) into the walk register file and stamped their concrete pointers from the live frame's locals_cells_stack_w. Its stated justification — "without this, a ForIterNext(iterator) residual declines execution" — predates #436: since the codewriter's Instruction::ForIter handler reloads the iterator through getarrayitem_vable_r on every iteration (the peekvalue() port, pyopcode.py:1303-1304 / jtransform.py:760-767), the residual consumes that in-loop read instead of an entry register. The nlocals+depth slot→color shortcut in this seed is also the mechanism class that produced the original color mis-seed the reload eliminated.

Both bridge seed arms (bridge_registers_r color seeding, bridge_stack_oprefs slot seeding) are unchanged — they serve bridge-resume paths, not loop entry.

Evidence (A/B, arm neutralized vs baseline)

Over kept_stack_deep_var_{condexpr,nested_call,shortcircuit,shortcircuit_mutate}, foriter_call_body, foriter_loadglobal_body, while_is_none, int_loop, nested_loop, fib_loop: identical stdout, identical PYRE_FBW_DEBUG_ABORT census (zero new aborts/declines), identical MAJIT_STATS compile stats (loops_compiled/bridges_compiled/loops_aborted/guard_failures).

Verification

🤖 Generated with Claude Code

The non-bridge arm of the argboxes seeding in run_perfn_walk copied
sym.registers_r operand-stack colors (nlocals..nlocals+depth) into the
walk register file and stamped their concrete pointers from the live
frame's locals_cells_stack_w. Since the codewriter's Instruction::ForIter
handler reloads the iterator through getarrayitem_vable_r on every
iteration (fab987c), the ForIterNext residual consumes that in-loop
read instead of an entry register, and the seed no longer has a consumer.

A/B over kept_stack_deep_var_{condexpr,nested_call,shortcircuit,
shortcircuit_mutate}, foriter_call_body, foriter_loadglobal_body,
while_is_none, int_loop, nested_loop, fib_loop shows identical stdout,
identical abort/decline census, and identical compile stats with the arm
removed. Both bridge seed arms are unchanged.

Assisted-by: Claude
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@youknowone, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 17 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1b0e87c1-725b-4004-b3cd-7a4258b2b797

📥 Commits

Reviewing files that changed from the base of the PR and between beff3e8 and c02c3b4.

📒 Files selected for processing (1)
  • pyre/pyre-jit-trace/src/trace.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch nbody

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.

@github-actions

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit 5f3c49c).

1. Regressions to PyPy parity introduced by this patch

  • pyre/pyre-jit-trace/src/trace.rs:1649 ↔ rpython/jit/metainterp/pyjitpl.py:1862 — “Loop-trace entry seeds no operand-stack colors” removes reconstruction of live loop-entry stack registers. PyPy’s MIFrame reaches the body with its register bank populated by normal execution; its setup_call writes supplied boxes into registers. Pyre’s full-body walker instead allocates OpRef::NONE banks and begins past the merge point, so live loop stack values can remain unbound. The claimed ForIter reload is not a general replacement for all live stack colors.

2. Other mismatches introduced by this patch

None.

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

  • pyre/pyre-jit-trace/src/trace.rs:702 ↔ rpython/jit/metainterp/pyjitpl.py:1537 — Pyre explicitly declines nested-loop header entries because it “miscompiles the bridges an inner nested loop closes into”; PyPy’s opimpl_jit_merge_point handles merge points through the normal loop-header protocol rather than disabling nested-loop tracing.

4. Structural adaptations

  • pyre/pyre-jit-trace/src/trace.rs:1584 ↔ rpython/jit/metainterp/pyjitpl.py:1862 — Pyre must construct a color-indexed argboxes_r vector to initialize its separately allocated Rust walker register bank, whereas PyPy’s MIFrame.setup_call receives typed boxes and fills its native MIFrame registers. This is a Rust/full-body-walker adaptation, but it must preserve the same live-register state.

@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: c02c3b47f2

ℹ️ 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".

Comment on lines +1649 to +1652
// Loop-trace entry seeds no operand-stack colors. The codewriter's
// `Instruction::ForIter` handler emits `getarrayitem_vable_r` to reload
// the iterator from the virtualizable on every iteration, so the
// residual consumes that in-loop read rather than an entry register.

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 Preserve non-iterator stack inputs at loop entry

This only accounts for FOR_ITER's TOS iterator, but loop headers can have other live operand-stack values. A hot list comprehension enters the loop with the result list below the iterator, and Instruction::ListAppend peeks that accumulator from current_state.stack and passes it as the first jit_list_append residual arg (see pyre/pyre-jit/src/jit/codewriter.rs:9953-9981); it is not reloaded by the ForIter-only getarrayitem_vable_r. With the non-bridge stack seed removed, that lower stack value is left OpRef::NONE at a FOR_ITER loop entry, so the LIST_APPEND fold/residual aborts instead of compiling hot list-comprehension loops.

Useful? React with 👍 / 👎.

@youknowone youknowone merged commit 4dbbdb0 into main Jul 13, 2026
29 of 30 checks passed
@youknowone youknowone deleted the nbody branch July 13, 2026 06:44
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