Skip to content

Fix blackhole failure handling and update documentation references#15

Open
lifthrasiir wants to merge 2 commits into
youknowone:mainfrom
lifthrasiir:bound-bh-retrace-thrashing
Open

Fix blackhole failure handling and update documentation references#15
lifthrasiir wants to merge 2 commits into
youknowone:mainfrom
lifthrasiir:bound-bh-retrace-thrashing

Conversation

@lifthrasiir

@lifthrasiir lifthrasiir commented May 11, 2026

Copy link
Copy Markdown
Contributor

Summary

This pull request primarily updates documentation and code to reflect the migration of the main test script from pyre/check.sh (a shell script) to pyre/check.py (a Python script). In addition, it introduces a new mechanism in the JIT system to record and limit repeated blackhole resume failures, preventing infinite retracing cycles and marking problematic code paths as non-traceable after a threshold. The changes improve robustness in JIT error handling and ensure all documentation and workflows reference the correct test entry point.

Documentation and Workflow Updates:

  • Updated all references in documentation (.claude/skills/merge/SKILL.md, .claude/skills/parity/SKILL.md, .claude/skills/rebase/SKILL.md, and pyre/README.md) from pyre/check.sh to pyre/check.py, ensuring consistency across merge, rebase, and parity workflows.

JIT Blackhole Failure Handling Improvements:

  • Added a new method record_blackhole_failure_and_maybe_invalidate in JitDriver, MetaInterp, and WarmEnterState to track blackhole resume failures per loop ("green key"), incrementing an abort counter and marking the loop as non-traceable after a set limit, thus preventing infinite retrace cycles.

Self-review

Prompt & Model

Model: opus-4.6[1m]

Prompt: /parity

Answer

  Parity audit

  Files modified and their RPython counterparts:

  Modified file: majit/majit-metainterp/src/warmstate.rs
  RPython counterpart: rpython/jit/metainterp/warmstate.py        
  Status: Exists
  ────────────────────────────────────────
  Modified file: majit/majit-metainterp/src/pyjitpl/mod.rs
  RPython counterpart: rpython/jit/metainterp/pyjitpl.py
  Status: Exists
  ────────────────────────────────────────
  Modified file: majit/majit-metainterp/src/jitdriver.rs
  RPython counterpart: No direct counterpart (pyre-specific driver abstraction)
  Status: PRE-EXISTING-ADAPTATION
  ────────────────────────────────────────
  Modified file: pyre/pyre-jit/src/eval.rs
  RPython counterpart: rpython/jit/metainterp/warmstate.py (warm-entry paths)
  Status: PRE-EXISTING-ADAPTATION (pyre-jit crate)

  Findings:

  1. warmstate.rs:786 — record_blackhole_failure() — No RPython counterpart. RPython's blackhole resume never fails (full SSA liveness), so
  no bounding mechanism exists upstream. This function is defensive hardening of the BlackholeResult::Failed PRE-EXISTING-ADAPTATION. It
  reuses abort_count and DONT_TRACE_HERE in the same pattern as the parity-correct abort_tracing() at :751. [deferred: requires Task #110 
  SSA liveness port to eliminate BlackholeResult::Failed entirely — removing this bound without fixing the root cause reintroduces the 
  thrashing it was written to stop]
  2. pyjitpl/mod.rs:6737 — record_blackhole_failure_and_maybe_invalidate() — No RPython counterpart, same reason. Wrapper combining
  record_blackhole_failure + conditional invalidate_loop. [deferred: same dependency as #1]
  3. jitdriver.rs:3274 — record_blackhole_failure_and_maybe_invalidate() — Passthrough to MetaInterp. [deferred: same dependency as #1]
  4. eval.rs:2979–3000, 3203–3205, 3372–3389 — BlackholeResult::Failed handlers — Changed from bare invalidate_loop to bounded
  record_blackhole_failure_and_maybe_invalidate. The BlackholeResult::Failed path itself is a PRE-EXISTING-ADAPTATION (Task #110). The diff
  replaces unbounded invalidation with bounded invalidation — strictly better behavior within the adaptation. [deferred: same root 
  dependency]

  Summary: All NEW-DEVIATIONs in this diff are defensive hardening of the BlackholeResult::Failed PRE-EXISTING-ADAPTATION. They follow the
  same abort_count / DONT_TRACE_HERE pattern used by the parity-correct abort_tracing(). Removing them without porting RPython's
  SSA-authoritative liveness (Task #110) would reintroduce the compile-guard-blackhole-invalidate-retrace thrashing cycle. No auto-fixes
  warranted — the root cause fix (eliminating BlackholeResult::Failed entirely) exceeds session scope.

  No regressions to auto-fix. The deviations are all in the "defensive hardening of existing adaptation, root fix requires unported
  dependency" category.

  Clean from a regression standpoint — the diff doesn't break any existing parity; it bounds an already-deviant path using parity-correct
  building blocks (abort_count, DONT_TRACE_HERE, MAX_TRACE_ABORT_COUNT).

Summary by CodeRabbit

  • Documentation

    • Updated merge, rebase, and parity validation procedures to reference the updated checker tool.
    • Updated benchmark reproduction instructions in README.
  • Bug Fixes

    • Enhanced blackhole failure handling with improved abort counting and loop invalidation logic to prevent excessive retracing cycles.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@lifthrasiir has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 58 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6becc84a-7f7d-45ab-8927-82a9efcc4cf2

📥 Commits

Reviewing files that changed from the base of the PR and between 3c93d03 and 71efe05.

📒 Files selected for processing (3)
  • majit/majit-metainterp/src/jitdriver.rs
  • majit/majit-metainterp/src/pyjitpl/mod.rs
  • majit/majit-metainterp/src/warmstate.rs

Walkthrough

This PR implements two independent changes: a blackhole failure abort-limit mechanism in the JIT meta-interpreter that prevents infinite retrace cycles, and updates to documentation and workflow skills to reference the new pyre/check.py Python script instead of pyre/check.sh.

Changes

Blackhole Failure Abort Limiting

Layer / File(s) Summary
Warm State Abort Tracking
majit/majit-metainterp/src/warmstate.rs
WarmEnterState::record_blackhole_failure() increments an abort counter for a cell and transitions it to DontTraceHere once count reaches MAX_TRACE_ABORT_COUNT, returning true to signal the limit.
MetaInterp Failure Coordinator
majit/majit-metainterp/src/pyjitpl/mod.rs
MetaInterp::record_blackhole_failure_and_maybe_invalidate() calls into warm state, conditionally invalidates the loop if the abort limit is not reached, and logs when the limit is reached.
JitDriver Public API
majit/majit-metainterp/src/jitdriver.rs
JitDriver::record_blackhole_failure_and_maybe_invalidate() wraps the MetaInterp method to expose the failure-tracking API.
JIT Execution Failure Handling
pyre/pyre-jit/src/eval.rs
Three blackhole failure sites (execute_assembler, bound_reached, try_function_entry_jit) now call the new API instead of unconditionally invalidating, with optional "[jit][BUG] blackhole failed — recording failure" logging.

Check Tool Migration to Python Script

Layer / File(s) Summary
User Documentation
pyre/README.md
Benchmark reproduction instructions updated to run pyre/check.py instead of pyre/check.sh.
Merge Workflow
.claude/skills/merge/SKILL.md
House policy, branch setup, per-slice test command, commit conditions, and hard rules all updated to enforce pyre/check.py green status.
Parity Verification
.claude/skills/parity/SKILL.md
Step 4 end-to-end correctness check now invokes pyre/check.py.
Rebase Workflow
.claude/skills/rebase/SKILL.md
Step 5 final sanity check and /merge interaction reference updated to pyre/check.py.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • youknowone/pyre#2: Introduces pyre/check.py and updates related tooling references; both PRs coordinate on the check script migration.

Poem

🐰 A rabbit hops through JIT traces,
Blackhole failures know their places—
Count them up, then mark the spot,
No more spinning in a knot!
And check.py's the modern way,
Better than shell script's yesterday! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main categories of changes: documentation updates (migration from check.sh to check.py) and new blackhole failure handling logic with abort limiting.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@lifthrasiir

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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)
pyre/pyre-jit/src/eval.rs (1)

2974-2996: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Quarantining the cell still leaves the broken loop executable.

record_blackhole_failure_and_maybe_invalidate() only helps if the failing loop stops being entered. Here the compiled token remains live, while Line 2610 still takes has_compiled_loop(green_key) before consulting DONT_TRACE_HERE, and Line 3282 has the same compiled-entry fast path. Once the abort limit flips DONT_TRACE_HERE, the next hit can still re-enter the same machine code and reproduce BlackholeResult::Failed forever. Please either clear/invalidate the compiled token when the limit is reached, or gate compiled entry on that flag too.

Also applies to: 3204-3206, 3369-3385

🤖 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/src/eval.rs` around lines 2974 - 2996, The current fix only
records a blackhole failure via
driver.record_blackhole_failure_and_maybe_invalidate(green_key) but leaves the
compiled token live so the compiled entry fast paths (the
has_compiled_loop(green_key) checks and the compiled-entry code path) can still
re-enter and reproduce BlackholeResult::Failed; update the logic so that when
record_blackhole_failure_and_maybe_invalidate flips the DONT_TRACE_HERE flag you
also clear or invalidate the compiled loop/token (remove the compiled entry or
drop its token) OR add an explicit gate that checks DONT_TRACE_HERE before any
has_compiled_loop(green_key) fast-path and before the compiled-entry dispatch
(the same paths referenced around record_blackhole_failure_and_maybe_invalidate
and the other locations noted) so that once the abort limit is reached the JIT
cannot re-enter the broken machine code.
🤖 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 @.claude/skills/merge/SKILL.md:
- Around line 10-13: The frontmatter description in
.claude/skills/merge/SKILL.md still references pyre/check.sh even though the
policy text was moved to pyre/check.py (lines that moved are already updated);
update the frontmatter line that mentions "pyre/check.sh" to "pyre/check.py" so
the file header and body are consistent and do not provide conflicting guidance.

In `@majit/majit-metainterp/src/warmstate.rs`:
- Around line 788-789: Replace the plain increment of the monotonic counter with
a saturating add to avoid overflow: change the `cell.abort_count += 1;` update
to use `cell.abort_count = cell.abort_count.saturating_add(1);` (keeping the
existing comparison to `MAX_TRACE_ABORT_COUNT` intact) so `abort_count` never
wraps or panics when it reaches its max value.
- Around line 786-794: record_blackhole_failure is incrementing abort_count only
on the bucket head via self.cells.get_mut(&green_key_hash), which misattributes
failures when multiple keys collide; change it to walk the collision chain
stored in the bucket to find the cell whose key equals the provided green key
(rather than assuming the hash maps to the exact key), then increment that
cell.abort_count and apply the MAX_TRACE_ABORT_COUNT logic (set flags |=
jc_flags::DONT_TRACE_HERE and state = BaseJitCellState::DontTraceHere) only for
the matched cell; ensure you compare the stored key/type identity when
traversing the chain and return false if no matching cell is found.

In `@pyre/README.md`:
- Line 34: Replace the ambiguous invocation "pyre/check.py" in the README with
an executable command form so users can copy-paste safely: update the line
referencing pyre/check.py to use either "python ./pyre/check.py" (explicit
interpreter) or "./pyre/check.py" after making pyre/check.py executable, and
mention the shebang/execute permission if the latter is chosen; this change
targets the README entry that currently shows "pyre/check.py".

---

Outside diff comments:
In `@pyre/pyre-jit/src/eval.rs`:
- Around line 2974-2996: The current fix only records a blackhole failure via
driver.record_blackhole_failure_and_maybe_invalidate(green_key) but leaves the
compiled token live so the compiled entry fast paths (the
has_compiled_loop(green_key) checks and the compiled-entry code path) can still
re-enter and reproduce BlackholeResult::Failed; update the logic so that when
record_blackhole_failure_and_maybe_invalidate flips the DONT_TRACE_HERE flag you
also clear or invalidate the compiled loop/token (remove the compiled entry or
drop its token) OR add an explicit gate that checks DONT_TRACE_HERE before any
has_compiled_loop(green_key) fast-path and before the compiled-entry dispatch
(the same paths referenced around record_blackhole_failure_and_maybe_invalidate
and the other locations noted) so that once the abort limit is reached the JIT
cannot re-enter the broken machine code.
🪄 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

Run ID: 7533ee9d-11c3-4bd8-a7d5-44de993a10fb

📥 Commits

Reviewing files that changed from the base of the PR and between ca912fb and 3c93d03.

📒 Files selected for processing (8)
  • .claude/skills/merge/SKILL.md
  • .claude/skills/parity/SKILL.md
  • .claude/skills/rebase/SKILL.md
  • majit/majit-metainterp/src/jitdriver.rs
  • majit/majit-metainterp/src/pyjitpl/mod.rs
  • majit/majit-metainterp/src/warmstate.rs
  • pyre/README.md
  • pyre/pyre-jit/src/eval.rs

Comment thread .claude/skills/merge/SKILL.md Outdated
Comment thread majit/majit-metainterp/src/warmstate.rs
Comment thread majit/majit-metainterp/src/warmstate.rs
Comment thread pyre/README.md Outdated
@youknowone

Copy link
Copy Markdown
Owner

generated review:


  1. Parity Regressions Versus main
  • The new BlackholeResult::Failed handling is not PyPy-equivalent. In RPython/
    PyPy, handle_fail either compiles a bridge or calls resume_in_blackhole;
    blackhole resume does not return a failure code, it raises a JIT exception
    such as ContinueRunningNormally, DoneWithThisFrame*, or
    ExitFrameWithExceptionRef: rpython/jit/metainterp/compile.py:701, rpython/
    jit/metainterp/blackhole.py:1782.
  • The patch turns Pyre-only blackhole failure into warmstate abort_count and
    eventually DONT_TRACE_HERE: pyre/pyre-jit/src/eval.rs:2974, majit/majit-
    metainterp/src/warmstate.rs:786. PyPy does not use JC_DONT_TRACE_HERE for
    failed blackhole resume.
  • At the limit, the patch leaves the compiled loop valid and marks the key
    DONT_TRACE_HERE: majit/majit-metainterp/src/pyjitpl/mod.rs:6739. Since
    compiled-loop lookup happens before DONT_TRACE_HERE checks, the same broken
    loop can still be entered.
  1. Other Mismatches Introduced By This Patch
  • The helper records failure by green_key, but guard failure data already
    carries the owning loop key via owning_key: majit/majit-metainterp/src/
    pyjitpl/mod.rs:12881. Cross-loop or bridge cases can mutate the wrong cell.
  • bound_reached now mutates warmstate on BlackholeResult::Failed: pyre/pyre-
    jit/src/eval.rs:3204. PyPy bound_reached only manages trace start/finally
    flag cleanup, not blackhole-failure throttling.
  • Documentation replacement is incomplete: .claude/skills/merge/SKILL.md
    frontmatter still says pyre/check.sh while the body says check.py: .claude/
    skills/merge/SKILL.md:3. Also pyre/check.py is not executable, so docs
    using ./pyre/check.py may fail unless run as python ./pyre/check.py.
  1. Pre-Existing Mismatches
  • BlackholeResult::Failed itself has no PyPy counterpart; it is a Pyre-only
    escape for incomplete resume/blackhole paths: pyre/pyre-jit/src/
    call_jit.rs:557.
  • BaseJitCell.abort_count and MAX_TRACE_ABORT_COUNT are not in PyPy’s
    BaseJitCell: majit/majit-metainterp/src/warmstate.rs:98, majit/majit-
    metainterp/src/warmstate.rs:292. PyPy handles guard retry through
    ResumeGuardDescr.status, jitcounter, and retrace/token logic.
  • Existing hash-only warmstate mutation remains a known adaptation. PyPy finds
    cells by typed greenkey chain comparison: rpython/jit/metainterp/
    warmstate.py:453.
  1. Structural Adaptations
  • Representing PyPy’s raised JitExceptions as Rust enum returns is a
    reasonable language-level adaptation.
  • Python opcode/cache differences are structural adaptations.
  • BlackholeResult::Failed is not structural adaptation; it is an
    implementation gap. The patch should fix the underlying blackhole/resume
    failure instead of converting it into permanent warmstate suppression.

@lifthrasiir lifthrasiir force-pushed the bound-bh-retrace-thrashing branch from b588241 to cafaab5 Compare May 14, 2026 01:15
@youknowone

Copy link
Copy Markdown
Owner

generated review

• 1. Regressed PyPy Parity Compared To main

  • pyre/pyre-jit/src/eval.rs:3150, pyre/pyre-jit/src/eval.rs:3362, pyre/pyre-jit/src/eval.rs:3549, majit/majit-metainterp/src/
    warmstate.rs:784, majit/majit-metainterp/src/pyjitpl/mod.rs:6976

    The new BlackholeResult::Failed handling is not equivalent to RPython/PyPy. PyPy’s guard failure path either traces a bridge or calls
    resume_in_blackhole(...); that function runs forever/raises a JIT exception and has no “blackhole failed” return channel. See
    rpython/jit/metainterp/compile.py:701-717 and rpython/jit/metainterp/blackhole.py:1782-1797.

    main explicitly documented this as a Pyre layering problem and only invalidated the loop in two paths, while leaving the key
    retraceable. This patch routes blackhole resume failure through WarmEnterState.abort_count, eventually setting DONT_TRACE_HERE and
    suppressing retracing. That moves the behavior farther from PyPy: RPython does not mark a portal greenkey JC_DONT_TRACE_HERE because
    blackhole resume failed.

  1. Other Mismatches Introduced By This Patch
  • majit/majit-metainterp/src/warmstate.rs:782 vs majit/majit-metainterp/src/pyjitpl/mod.rs:6977

    The new record_blackhole_failure contract says the caller “should NOT invalidate” when the abort limit is reached, but
    record_blackhole_failure_and_maybe_invalidate always calls invalidate_loop(green_key) anyway. This is internally inconsistent and has
    no RPython analogue.

  • pyre/pyre-jit/src/jit/codewriter.rs:6773, pyre/pyre-jit-trace/src/liveness.rs:692

    The patch adds stack-effect-aware codewriter arms for many previously catch-all opcodes, but liveness still falls through to the
    default (d, d) for several of them. Concrete affected opcodes include BinarySlice, CallKw, CallFunctionEx, SetFunctionAttribute,
    FormatWithSpec, UnpackEx, BuildInterpolation, BuildTemplate, LoadSpecial, ReturnGenerator, GetAnext, EndAsyncFor, and CleanupThrow.
    If these appear around control-flow joins or exception edges, codewriter and liveness now disagree.

  1. Mismatches That Already Existed Before This Patch
  • majit/majit-metainterp/src/warmstate.rs:98

    BaseJitCell.abort_count is already a Pyre divergence. RPython’s BaseJitCell has flags, weak procedure token, and next, but no abort
    counter; retrace policy is handled elsewhere, e.g. set_param_retrace_limit routes to memory_manager.retrace_limit in rpython/jit/
    metainterp/warmstate.py:299-310.

  • majit/majit-metainterp/src/warmstate.rs:713

    force_start_tracing refuses tracing when abort_count >= MAX_TRACE_ABORT_COUNT. That is not RPython warmstate behavior.

  • pyre/pyre-jit/src/jit/codewriter.rs:6764

    PopIter updates current_depth but does not pop current_state.stack. Pyre’s pop_iter() delegates to opcode_pop_top in
    pyopcode.rs:1003-1007, so the shadow stack remains too long after iterator cleanup. This was already present on main.

  1. Structural Adaptations

These are not 1:1 PyPy parity issues because they come from Pyre’s Python 3.13/3.14 and CPython-compatible bytecode shape:

  • EndFor as no-op plus PopIter pop: PyPy local source has no matching END_FOR; Pyre’s end_for() is no-op.
  • LoadSuperAttr method-bit stack effect: CPython-style opcode, not local PyPy 3.11 opcode.
  • CallKw and CallFunctionEx: Pyre includes CPython null/self sentinel handling; PyPy’s CALL_FUNCTION_KW/CALL_FUNCTION_EX stack effects
    differ.
  • MakeFunction plus SetFunctionAttribute: CPython split-form differs from PyPy’s _compute_MAKE_FUNCTION(arg).
  • BuildInterpolation, BuildTemplate, LoadFastAndClear, LoadSpecial, LoadFromDictOr*, ReturnGenerator, Send, EndSend, GetAnext,
    CleanupThrow, ExitInitCheck, and async stubs are CPython/Pyre-shape adaptations rather than direct PyPy ports.

Bottom line: the main parity regression is the new blackhole-failure warmstate path. The stack-effect additions are mostly reasonable
structural adaptations, but liveness is now incomplete relative to the new codewriter accounting.

lifthrasiir and others added 2 commits May 19, 2026 20:44
BlackholeResult::Failed → invalidate_loop never incremented the cell's
abort_count, so the compile → guard-fail → bh-fail → invalidate →
retrace cycle could repeat indefinitely.  Add
record_blackhole_failure() which increments abort_count on each
failure; after MAX_TRACE_ABORT_COUNT (5) the key is marked
DONT_TRACE_HERE and the loop is NOT invalidated, stopping the cycle.

Applied to all three BlackholeResult::Failed handlers in eval.rs
(execute_assembler, bound_reached, try_function_entry_jit).

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
At the abort limit, the previous code set DONT_TRACE_HERE but skipped
invalidation, leaving the broken compiled loop in place.  Since
has_compiled_loop is checked before is_dont_trace_here, the same loop
would be re-entered every iteration, failing and falling back to the
interpreter in an infinite cycle.  Now we always invalidate (removing
the compiled code) and at the limit additionally set DONT_TRACE_HERE
to prevent retracing.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@lifthrasiir lifthrasiir force-pushed the bound-bh-retrace-thrashing branch from cafaab5 to 71efe05 Compare May 19, 2026 11:44
@youknowone

Copy link
Copy Markdown
Owner

diagnosis suggests to revert the changes to make it pypy-orthodox


To fix sections 1 and 2 in a PyPy-orthodox way, keep
BlackholeResult::Failed out of warmstate policy.

Concretely:

  1. Remove the new APIs
    • Delete WarmEnterState::record_blackhole_failure().
    • Delete
      MetaInterp::record_blackhole_failure_and_maybe_invalidate().
    • Delete JitDriver::record_blackhole_failure_and_maybe_invalidate().
  2. Revert the three call sites in eval.rs
    • At pyre/pyre-jit/src/eval.rs:3788, use
      driver.invalidate_loop(green_key); None.
    • At pyre/pyre-jit/src/eval.rs:4018, use {} or logging only. Do not
      mutate warmstate.
    • At pyre/pyre-jit/src/eval.rs:4191, use
      driver.invalidate_loop(green_key).
  3. Update comments
    • Remove references to abort_count, abort limit, and
      DONT_TRACE_HERE.
    • Say explicitly:
      • RPython blackhole resume does not return failure.
      • BlackholeResult::Failed is a Pyre-only defensive recovery
        path.
      • This path must not change JitCell policy; the real fix is
        complete/correct resume data.
  4. If infinite retracing is the actual problem
    • Do not solve it with DONT_TRACE_HERE.
    • Fix the cause of BlackholeResult::Failed in
      resume_in_blackhole_from_exit_layout() /
      call_jit::resume_in_blackhole().
    • Audit the existing Failed return sites: empty frames, null
      virtualizable frame, null code, out-of-bounds PC, missing
      pyjitcode, missing pc_map, bad resume sections.

The orthodox patch shape is: remove the warmstate extension, keep Failed
as a local Pyre-only recovery path, and fix the underlying resume-data
mismatch. DONT_TRACE_HERE should remain reserved for trace-too-long /
non-inlinable / force-finish style behavior, matching PyPy.

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.

2 participants