Skip to content

wasm backend: PR #691 review follow-ups (GuardSubclass width, IntSignext/indexed-GC decline, bridge-iter journal root) - #737

Merged
youknowone merged 8 commits into
mainfrom
wasm-jit
Jul 25, 2026
Merged

wasm backend: PR #691 review follow-ups (GuardSubclass width, IntSignext/indexed-GC decline, bridge-iter journal root)#737
youknowone merged 8 commits into
mainfrom
wasm-jit

Conversation

@youknowone

@youknowone youknowone commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Follow-up fixes from the Codex/CodeRabbit review of the (now-merged) #691, verified against current main.

Commits

  1. wasm: correct GuardSubclass field width; decline runtime IntSignext and indexed GC ops — three majit-backend-wasm/src/codegen.rs fixes:
    • GuardSubclass read subclassrange_min at size_of::<usize>() (4 bytes on wasm32); PyType::subclassrange_min is AtomicI64, so read 8 bytes on both the vtable and gcremovetypeptr paths.
    • IntSignext with a non-constant num_bytes operand aborted via panic!; a non-constant width is a valid IR shape (the cranelift backend resolves arg(1) at runtime), so return BackendError::Unsupported for interpreter fallback.
    • gc_load_indexed_* / gc_store_indexed_* are real frontend blackhole ops that can reach the backend; decline the indexed forms with Unsupported instead of panicking. The bare GcLoad*/GcStore GC-rewrite forms keep the loud panic.
  2. jit: root the FBW bridge iterator cursor journalFBW_BRIDGE_ITER_JOURNAL held range-iterator refs across an authoritative bridge walk but was visited by no root walker, unlike its five sibling FBW journals. Wire it into FbwStoreJournalRootArea / fbw_store_journal_root_walker_area so a minor collection forwards the iterator before the non-commit rollback restores its cursor.
  3. check.py: report exec times and true ratio in perf-gate FAIL lines — the FAIL line printed raw run times and the gate threshold formatted as if it were the measured ratio. Print the startup-subtracted exec times the gate actually compared, their ratio, and the threshold.

Review findings not acted on

  • "Roll back bridge iterator journal on subwalk abort" — inert: the carrier subwalk runs with inline_subwalk: true, so try_walker_specialize_for_iter_next declines before the journal push; the journal is never populated in a subwalk.
  • ovf-flag local drift — already centralized to a single computed local upstream.
  • Descriptor-driven string/unicode getitem/len lowering — a real perf gap (the current decline is correct, just falls back to the interpreter). Deferred as a follow-up commit on this branch.

Verification

python3 pyre/check.py --backend wasm → 290/290. python3 pyre/check.py --backend dynasm → 293/293. Both green, 0 failures.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Preserved full-width integer constants during native code generation, preventing incorrect results for large values.
    • Improved WebAssembly handling for unsupported operations by returning clear compilation errors instead of failing unexpectedly.
    • Corrected WebAssembly subclass-range checks to avoid value truncation.
    • Improved runtime safety during bridge and rollback processing by retaining required objects during garbage collection.
  • Performance

    • Enhanced performance-check failure messages with clearer measured-to-baseline ratios and thresholds.
    • Added string indexing and length benchmarks covering multiple Unicode formats.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 46 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 Plus

Run ID: 9704af4e-fd9e-4a74-a075-b9f282c94bce

📥 Commits

Reviewing files that changed from the base of the PR and between 6aecc6e and 2801368.

📒 Files selected for processing (14)
  • majit/majit-backend-dynasm/src/x86/assembler.rs
  • majit/majit-backend-dynasm/tests/basic_loop.rs
  • majit/majit-backend-wasm/src/codegen.rs
  • pyre/bench/synth/exception_metadata_jitstress.py
  • pyre/bench/synth/exception_reraise_tb_depth_hot.py
  • pyre/bench/synth/exception_reraise_tb_depth_jitstress.py
  • pyre/bench/synth/str_getitem_len_hot.py
  • pyre/check.py
  • pyre/pyre-interpreter/src/call.rs
  • pyre/pyre-interpreter/src/importing.rs
  • pyre/pyre-interpreter/src/module/mod.rs
  • pyre/pyre-interpreter/src/module/pypyjit/mod.rs
  • pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
  • pyre/pyre-jit/src/eval.rs

Walkthrough

The changes preserve wide x86 immediates, add wasm unsupported-operation handling and full-width loads, introduce a Unicode string benchmark, improve performance-gate failure details, and GC-root bridge iterator journals.

Changes

Dynasm immediate handling

Layer / File(s) Summary
Wide immediate emission and validation
majit/majit-backend-dynasm/src/x86/assembler.rs, majit/majit-backend-dynasm/tests/basic_loop.rs
x86 immediate values are range-checked before imm32 encoding, with wide constants materialized in the scratch register; tests cover IntAnd and IntAdd.

Wasm codegen handling

Layer / File(s) Summary
Wasm operation validation and field loading
majit/majit-backend-wasm/src/codegen.rs
Dynamic IntSignext widths and indexed GC operations return unsupported errors, while GuardSubclass loads subclassrange_min as an 8-byte i64 field.

String benchmark tooling

Layer / File(s) Summary
String hot-loop benchmark
pyre/bench/synth/str_getitem_len_hot.py
Adds checksum and length loops for ASCII, latin1, BMP, and astral strings, printing per-category and aggregate results.

Performance gate reporting

Layer / File(s) Summary
Unified gate failure details
pyre/check.py
A shared helper formats startup-adjusted measured times, ratios, and thresholds for failed cpython and pypy performance checks.

Bridge iterator GC rooting

Layer / File(s) Summary
Bridge journal root tracking
pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
Adds the bridge iterator journal to root-area initialization and forwards its iterator objects during GC root walking.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Poem

A bunny checked each constant wide,
And kept the wasm fields full inside.
Hot strings hopped through every hue,
GC roots held their iterators true.
“No truncation!” cried the hare—
“Clean reports now fill the air!”

🚥 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 highlights a major subset of the PR’s changes and is specific enough to be useful.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wasm-jit

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

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 2801368).
Updated: 2026-07-24T18:50:08.901Z

Files in the reviewed diff
majit/majit-backend-dynasm/src/x86/assembler.rs
majit/majit-backend-dynasm/tests/basic_loop.rs
majit/majit-backend-wasm/src/codegen.rs
pyre/bench/synth/exception_metadata_jitstress.py
pyre/bench/synth/exception_reraise_tb_depth_hot.py
pyre/bench/synth/exception_reraise_tb_depth_jitstress.py
pyre/bench/synth/str_getitem_len_hot.py
pyre/check.py
pyre/pyre-interpreter/src/call.rs
pyre/pyre-interpreter/src/importing.rs
pyre/pyre-interpreter/src/module/mod.rs
pyre/pyre-interpreter/src/module/pypyjit/mod.rs
pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs
pyre/pyre-jit/src/eval.rs

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

  • pyre/pyre-interpreter/src/module/pypyjit/mod.rs:66 ↔ pypy/module/pypyjit/interp_jit.py:160 — keyword parameters are serialized into a user-parameter string, so an unknown keyword raises ValueError; PyPy validates the name and raises TypeError("no JIT parameter ...").

  • pyre/pyre-interpreter/src/module/pypyjit/mod.rs:58 ↔ pypy/module/pypyjit/interp_jit.py:160 — serialization changes keyword boundaries: **{"threshold=1,trace_limit": 2} becomes accepted parameter text, and commas in enable_opts are interpreted as additional parameters. PyPy treats each keyword name/value independently and rejects the former as an unknown parameter.

  • pyre/pyre-interpreter/src/module/pypyjit/mod.rs:77 ↔ pypy/module/pypyjit/moduledef.py:7 — the new module exports only set_param; PyPy also exports residual_call, not_from_assembler, JIT-cell/tracing controls, release/statistics/hook APIs, operation wrapper classes, PARAMETER_DOCS, and initializes defaults.

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

  • pyre/pyre-jit/src/eval.rs:4426 ↔ rpython/rlib/jit.py:860apply_jit_param_string("unknown=1") calls a setter that ignores unknown names and returns success; RPython exhausts unroll_parameters and raises ValueError.

  • pyre/pyre-jit/src/eval.rs:4418 ↔ rpython/rlib/jit.py:850 — empty comma components are skipped, so "threshold=1," succeeds; RPython processes every split component and raises ValueError for the empty component.

  • pyre/pyre-jit/src/eval.rs:4422 ↔ rpython/rlib/jit.py:852split_once('=') accepts enable_opts=a=b, whereas RPython requires exactly two =-split parts and raises ValueError.

4. Structural adaptations

  • pyre/pyre-interpreter/src/call.rs:262 ↔ pypy/module/pypyjit/interp_jit.py:154 — Rust crate layering prevents pyre-interpreter from directly calling JIT state, so it uses an optional callback. Without pyre-jit registered, pypyjit.set_param(...) succeeds as a no-op; PyPy directly invokes jit.set_user_param.

  • majit/majit-backend-wasm/src/codegen.rs:2695 ↔ rpython/jit/backend/x86/assembler.py:1706 — wasm declines indexed GC-memory operations for interpreter fallback rather than implementing PyPy’s descriptor-based machine-code lowering. This is a backend-capability adaptation, not a silent semantic miscompile.

@youknowone
youknowone force-pushed the wasm-jit branch 4 times, most recently from 5d5fab9 to 6aecc6e Compare July 23, 2026 17:49

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

🤖 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/bench/synth/str_getitem_len_hot.py`:
- Around line 18-22: Update the loop in hot_len to use an underscore instead of
the unused i variable, changing the iteration target to for _ in range(n) while
preserving the existing accumulation behavior.
- Line 27: Update latin1_s in the test data to remove the U+2014 em dash and use
a one-byte Latin-1 character instead, then add hot_len(n, latin1_s) to the
hot_len benchmark alongside bmp_s and astral_s. Preserve the existing benchmark
structure and other inputs.

In `@pyre/check.py`:
- Around line 1137-1157: Update _gate_fail_detail so the reported ratio
preserves sufficient precision to remain distinguishable from the gate threshold
for failures just above it. Replace the one-decimal ratio formatting with higher
precision, or mark the ratio as approximate rather than asserting an exact
displayed “>” relationship; keep the existing execution-time values and fallback
handling unchanged.
🪄 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: e6768e48-e014-4108-b775-69c5c53368ae

📥 Commits

Reviewing files that changed from the base of the PR and between 27c5d5f and 6aecc6e.

📒 Files selected for processing (6)
  • majit/majit-backend-dynasm/src/x86/assembler.rs
  • majit/majit-backend-dynasm/tests/basic_loop.rs
  • majit/majit-backend-wasm/src/codegen.rs
  • pyre/bench/synth/str_getitem_len_hot.py
  • pyre/check.py
  • pyre/pyre-jit-trace/src/jitcode_dispatch/mod.rs

Comment on lines +18 to +22
def hot_len(n, s):
acc = 0
for i in range(n):
acc += len(s)
return acc

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

Use an underscore for the intentionally unused loop variable.

hot_len does not read i; use for _ in range(n) to express the intent and clear Ruff B007.

🧰 Tools
🪛 Ruff (0.15.21)

[warning] 20-20: Loop control variable i not used within loop body

Rename unused i to _i

(B007)

🤖 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/bench/synth/str_getitem_len_hot.py` around lines 18 - 22, Update the
loop in hot_len to use an underscore instead of the unused i variable, changing
the iteration target to for _ in range(n) while preserving the existing
accumulation behavior.

Source: Linters/SAST tools


def main():
ascii_s = "The quick brown fox jumps over the lazy dog 0123456789!?"
latin1_s = "café déjà vu naïve résumé — ¡Hola! ½¾ ©®µ"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate file =="
git ls-files | grep -F 'pyre/bench/synth/str_getitem_len_hot.py' || true

echo "== File contents =="
if [ -f pyre/bench/synth/str_getitem_len_hot.py ]; then
  cat -n pyre/bench/synth/str_getitem_len_hot.py
fi

echo "== String encoding facts =="
python3 - <<'PY'
s = "café déjà vu naïve résumé — ¡Hola! ½¾ ©®µ"
print("encoding:", s.encode('latin-1').decode('latin-1') == s)
print("len_utf8_bytes:", len(s.encode('utf-8')))
print("unicode_points_high:", [(c, hex(ord(c))) for c in s if ord(c) > 0xFF])
PY

echo "== Search related benchmark helpers =="
rg -n "hot_len|hot_getitem|latin1_s|iconv|item_size|STRGETITEM|STRLEN" pyre/bench pyre -g '*.py' || true

Repository: youknowone/pyre

Length of output: 2063


Exercise the actual Latin-1 path and include it in hot_len.

latin1_s includes U+2014, so it falls back to a wider Unicode representation; replacing the em dash with a one-byte character restores the intended Latin-1 STRGETITEM input. Also call hot_len(n, latin1_s) so the STRLEN Latin-1 path is exercised alongside bmp_s and astral_s.

🤖 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/bench/synth/str_getitem_len_hot.py` at line 27, Update latin1_s in the
test data to remove the U+2014 em dash and use a one-byte Latin-1 character
instead, then add hot_len(n, latin1_s) to the hot_len benchmark alongside bmp_s
and astral_s. Preserve the existing benchmark structure and other inputs.

Comment thread pyre/check.py
Comment on lines +1137 to +1157
def _gate_fail_detail(self, backend, baseline, measured, baseline_time, limit):
"""One-line FAIL detail using the exact numbers the gate compared.

The gate decides on startup-subtracted exec times
(``_exec_time(backend, measured) <= _exec_time(baseline, baseline_time)
* limit``), so those exec times — not the raw run times — are printed,
alongside their true measured ratio and the gate threshold. On a FAIL
the ratio necessarily exceeds the threshold, so every number on the
line is arithmetically self-consistent: exec_measured / exec_baseline
equals the shown ratio, which is above the shown gate.
"""
exec_m = self._exec_time(backend, measured)
exec_b = self._exec_time(baseline, baseline_time)
if exec_b in (None, "-") or float(exec_b) <= 0:
ratio = "-"
else:
ratio = f"{float(exec_m) / float(exec_b):.1f}x"
return (
f"exec {exec_m:.2f}s > {baseline} {exec_b:.2f}s "
f"ratio {ratio} > gate {float(limit):g}x"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve enough precision for the reported gate comparison.

With :.1f, a real failure just above a threshold can print identical rounded values (ratio 1.1x > gate 1.1x). Use more precision or describe the ratio as approximate instead of asserting the displayed > relation.

🧰 Tools
🪛 Ruff (0.15.21)

[warning] 1137-1137: Missing return type annotation for private function _gate_fail_detail

Add return type annotation: str

(ANN202)

🤖 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/check.py` around lines 1137 - 1157, Update _gate_fail_detail so the
reported ratio preserves sufficient precision to remain distinguishable from the
gate threshold for failures just above it. Replace the one-decimal ratio
formatting with higher precision, or mark the ratio as approximate rather than
asserting an exact displayed “>” relationship; keep the existing execution-time
values and fallback handling unchanged.

@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: 061219ee01

ℹ️ 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 549 to 550
if session.last_caught_exception_value == exc_value {
return;

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 traceback recording for explicit re-raises

When the same exception object was previously caught and the frame later executes an explicit raise e inside another handled block, caught is true but last_caught_exception_value still matches e; this unconditional return suppresses the new traceback entry and makes the JIT-recorded exception diverge from interpreter semantics. The old !caught guard was needed so only bare re-raises skip recording; the identical predicate in the inline-frame helper has the same issue.

AGENTS.md reference: AGENTS.md:L14-L18

Useful? React with 👍 / 👎.

@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

https://github.com/youknowone/pyre/blob/59d3cfe589f3d9ef91c2b9394d978ccc965b0004/pyre-jit/src/call_jit.rs#L706-L708
P2 Badge Preserve traceback for invalid bare raise

When a hot frame executes a bare raise with no active exception (for example try: raise; except RuntimeError as e: ...), the interpreter creates a new RuntimeError with attach_tb=true, so the caught exception must get a traceback node at this RAISE_VARARGS 0 line. This opcode-only predicate treats every argc-0 raise as a re-raise and record_caught_blackhole_traceback then returns before recording, so JIT/blackhole execution loses the traceback for that normal Python error; the skip needs to distinguish an actual active-exception re-raise from the freshly-created RuntimeError path.

AGENTS.md reference: AGENTS.md:L14-L18


https://github.com/youknowone/pyre/blob/59d3cfe589f3d9ef91c2b9394d978ccc965b0004/pyre-interpreter/src/module/pypyjit/mod.rs#L60-L64
P2 Badge Reject unknown pypyjit keyword parameters

For keyword calls such as pypyjit.set_param(no_such=1), this serializes the unknown name into no_such=1 and sends it through call::set_jit_param_string; that path ultimately calls WarmEnterState::set_param, whose default arm ignores unknown names, so the call silently succeeds. PyPy's interp_jit.py keyword loop raises TypeError("no JIT parameter ..."), and the old direct implementation in pyre-jit/src/eval.rs had the same is_known_jit_param check, so this new module should validate keyword names before or while applying them.

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

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

@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: 3ea2b9375d

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

// interp_jit.py:151-156 — positional string → set_user_param(None, text).
if let Some(&text_obj) = pos.first() {
let text = crate::baseobjspace::text_w(text_obj)?;
if crate::call::set_jit_param_string(&text).is_err() {

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 Reject unknown pypyjit parameters

When a caller misspells a parameter in the positional string, for example pypyjit.set_param("thresholdd=1"), this is_err() check never fires: the registered hook uses apply_jit_param_string, which delegates unknown names to WarmEnterState::set_param, and that method's unknown-name arm is a no-op. PyPy's set_user_param raises ValueError for unknown names, so pyre now reports success while leaving the requested JIT knob unchanged, making stress/benchmark configuration silently ineffective.

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

Useful? React with 👍 / 👎.

…nd indexed GC ops

- GuardSubclass read subclassrange_min at size_of::<usize>() (4 bytes on
  wasm32); PyType::subclassrange_min is AtomicI64, so read 8 bytes on both the
  vtable and gcremovetypeptr paths.
- IntSignext with a non-constant num_bytes operand aborted via panic; return
  BackendError::Unsupported so the trace declines to interpreter fallback.
- gc_load_indexed_*/gc_store_indexed_* are frontend blackhole ops that can
  reach the backend; return Unsupported for the indexed forms instead of
  panicking. The bare GcLoad*/GcStore GC-rewrite forms keep the panic.

Assisted-by: Claude
FBW_BRIDGE_ITER_JOURNAL stores range-iterator refs across an authoritative
bridge walk but was visited by no root walker, unlike the five sibling FBW
journals. Add it to FbwStoreJournalRootArea and fbw_store_journal_root_walker_
area so a minor collection forwards the iterator before the non-commit rollback
restores its cursor via w_range_iter_set_cursor.

Assisted-by: Claude
The FAIL line printed raw run times and the gate threshold formatted as if it
were the measured ratio, so the numbers were not self-consistent. Add
_gate_fail_detail to print the startup-subtracted exec times the gate actually
compared, their ratio, and the threshold.

Assisted-by: Claude
…decline as verified inert

- bench/synth/str_getitem_len_hot.py: hot str/unicode subscript and len over
  ASCII/latin1/BMP/astral strings (item_size 1/2/4), routed through the
  GETARRAYITEM/ARRAYLEN paths; output asserted cpython==pypy.
- codegen.rs: a str-subscript / len / compare / find hot loop traces to
  GETARRAYITEM, never STRGETITEM (verified with PYRE_DUMP_PERFN_JITCODE), so the
  STRGETITEM/UNICODEGETITEM/STRLEN/UNICODELEN decline covers ops no trace emits;
  note this so the decline is not mistaken for a missing descr-driven lowering.

Assisted-by: Claude
emit_binop_reg_loc's Loc::Immed arm truncated the value with `as i32`,
encoding an out-of-i32-range immediate as a sign-extended imm32 —
`x & 0xFFFF_FFFF_FFFF` degenerated to `x & -1` in compiled code, the
wrong output of synth/str_getitem_len_hot on dynasm. Follow
regloc.py:456-464: mov the value into X86_64_SCRATCH_REG and retry the
reg-reg form. The IntAdd LEA emitter gets the same fallback for its
immediate arm, which the consider_binop_symm path reaches with an
arbitrary 64-bit constant; its two symmetric arms are merged. Two
backend tests compile and execute AND/ADD with wide immediates.
Register a pypyjit module whose set_param accepts the positional-string
form ("name=value,…", "off", "default") and keyword arguments, routing
both through the JIT's set_user_param parser. pyre-interpreter cannot
import pyre-jit, so add a SET_JIT_PARAM_STRING_HOOK alongside the existing
per-pair SET_JIT_PARAM_HOOK; pyre-jit registers
set_jit_param_string_via_warmstate at boot and per-eval. The hook is an
in-process function pointer, so a pypyjit.set_param call configures the
warmstate on every backend including the wasm guest, which sees no
environment.
…nches

exception_metadata_jitstress and exception_reraise_tb_depth_jitstress call
pypyjit.set_param("threshold=1,function_threshold=1") so trace recording
fires on the earliest iterations of every section rather than after the
~1600-iteration warmup. Recording then lands on the traceback/context/
exc_info/reraise shapes on every run and every backend, making coverage of
the recording path deterministic instead of dependent on which iteration a
warmup pass happens to hit. The import is guarded so the benches run
unchanged under CPython, which has no pypyjit. Output matches the
natural-threshold twins.
A module-level hot loop executes bare re-raise (depth 2), named re-raise
(depth 3), and finally-passthrough (depth 2) so the recording iteration itself
runs the re-raise chain. Guards the instruction-keyed traceback recording
against spurious nodes at re-raise / handler-cleanup coordinates.
@youknowone
youknowone merged commit 6ad30ac into main Jul 25, 2026
30 of 31 checks passed
@youknowone
youknowone deleted the wasm-jit branch July 25, 2026 00:39
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