Skip to content

test(gc): scope the #7114 IR assertions to the function under test - #7120

Merged
proggeramlug merged 2 commits into
mainfrom
fix/7116-scope-temp-root-ir-assertions
Jul 31, 2026
Merged

test(gc): scope the #7114 IR assertions to the function under test#7120
proggeramlug merged 2 commits into
mainfrom
fix/7116-scope-temp-root-ir-assertions

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #7116 (merged as 57f9dc31b). Addresses the CodeRabbit finding that
was submitted at 05:03:58 — one minute after the last commit — and so was never
looked at before the merge.

Test-only. No codegen change: git diff 57f9dc31b HEAD -- 'crates/*/src' is
empty.

The finding, and why it is not trivial

ir_for returns the complete module IR. The three .find() calls select the
first matching operation in that module. If another generated function emits
one of these calls, the test can pass without proving that the
Expr::WtfString operand is rooted and re-read after its allocating sibling.

CodeRabbit labelled it Trivial. For a test whose entire job is proving that a
value is re-derived below a collection point, an assertion satisfiable by
some other function's IR is precisely the wrong test. It applied to more than
the WTF-8 case: every ordering assertion added in #7114 searched whole-module IR.

What changed

Sabotage, four directions

Host: perry@perry-macos.local (Apple M1, 8 cores), --release. Every arm below
was run against the scoped assertions, so this is evidence that scoping did
not weaken them.

sabotage result
revert the #7114 fix (temp_root.rs + new.rs to ff85fd483) concat and array_element FAIL; other 10 pass
re-derive unconditionally (drop the collects window) the gate ..._not_re_derived_when_nothing_collects FAILS; other 11 pass
half-close the literal asymmetry (WtfString suppressed in operand_needs_root only) wtf8_..._rooted_not_merely_reused FAILS; other 11 pass
un-scope init_ir (return the whole module) init_ir_slices_only_the_function_under_test FAILS; other 11 pass

Clean run: 12/12 pass.

The fourth row is worth reading honestly: with init_ir un-scoped, the other
eleven tests still passed. In these single-statement modules the unscoped
.find() happened to land on the right function, so the flaw was latent
fragility rather than a live false pass — which is exactly why it needed a gate
rather than an argument. It has one now.

Gates

Because crates/*/src is byte-identical to merged main, the #7116 matrix and
gc-ratchet results carry unchanged; both are restated here with the identity
proof, plus a fresh single-arm ratchet on merged main.

  • codegen contract suite: 12/12 (see sabotage table)
  • GC x repsel matrix --arms all --pressure 8 (on 57f9dc31b's compiler):
    PASS=379 UNVER=100 XFAIL=1 FAIL=0 over 480 cells, byte-exact vs
    node v26.5.1 on 479/480. The #7114 corpus row is PASS on all 20 arms and
    live on the moving ones (evac_minor: 66 cycles / 1 506 487 scavenged;
    default: 50 cycles / 1 121 856 scavenged).
  • gc-ratchet — see below.

gc-ratchet — run locally, pinned-host profile

CI is not the gate (runner pool hours deep; GC Ratchet has been cancelled on
consecutive main commits without reaching a runner), so this was run on the
machine the baseline is pinned to — perry-macos.fritz.box, Apple M1, 8 cores,
which is the exact host recorded in benchmarks/gc_ratchet/baseline/gc-ratchet-v1.json.

1. Current gate, on merged main's compiler (run_gc_ratchet_baseline.sh --check,
pinned_host profile, quiet host confirmed at cpu_active=5.4%):

gc-ratchet: OK

96 gated rows ok/improvement, 0 regressions; correctness=pass against
node v26.5.1 on all 8 probes; heap_used_bytes and heap_total_bytes 0.00%
drift on every probe. The one non-zero semantic drift against the pinned
baseline
is 07_array_grow_evacuate.copied_objects 18 294 → 18 290 (−0.02%,
band 5%), which is the documented sub-0.1% host-dependent component of the
evacuation counters — and it is not from #7114, because the base-vs-fix A/B
below has that counter bit-identical.

2. Base-vs-fix A/B isolating #7114 (ff85fd483 vs ff85fd483+#7114, both
arms --check, exit 0 for both):

result
gated (retention + GC accounting) 72/72 medians bit-identical over 8 probes x 9 metrics
ungated wall_ms 8/8 probes differ, −0.66% … +0.62%
ungated rss_bytes 5/8 probes differ, −0.49% … +0.23%
correctness vs node v26.5.1 pass on all 8 probes, both arms

The ungated spread is the load-bearing half. Bit-identical gated counters are
also exactly what a vacuous A/B looks like when a stale .a makes both arms
the same binary, so a nonzero ungated spread on every row is the evidence that
the two binaries genuinely differed. Independently confirmed by fingerprint:
perry sha256 2df0831b… (base) vs 86d9575a… (fix), with
libperry_runtime.a byte-identical at 143b184c… — correct, since #7114 is a
codegen-only change, so the archive should be identical and the differing
artifact should be perry itself.

Why the A/B was not re-run for this PR: it would be vacuous by construction.
This PR changes only a test file, so both arms would be the same compiler. The
A/B above is the correct isolation of the #7114 change, and
git diff 57f9dc31b HEAD -- 'crates/*/src' being empty is what licenses
carrying it forward.

Gap parity suite (partial, informational)

./run_parity_tests.sh --filter test_gap_ on merged main's compiler, stopped
at 166/438 to free the host for the ratchet (the ratchet needs a quiet host
and the suite was pacing at ~4 hours). Three failures, none attributable to
#7114
:

test status
test_gap_2159_defineproperty_class_prototype in test-parity/known_failures.json
test_gap_2514_settracesigint in test-parity/known_failures.json
test_gap_6301_event_target_subclass not triaged — verified byte-identical output on pristine ff85fd483, so pre-existing. It is the native-base-subclassing weak area; a known_failures.json provenance gap (#797).

Ralph Küpper added 2 commits July 31, 2026 07:32
…7116 review)

ir_for returns the WHOLE module, so a bare .find() over it answers with
whichever function comes first in the file. Every ordering assertion in the
#7114 section is now sliced to @main via function_ir/init_ir and paired with an
exact count of the operand-specific opcode inside that slice, so 'this is the
operand I meant' is a property of the test rather than of module layout.

Claude-Session: https://claude.ai/code/session_018ZFER8EEg8K7ez2n6oDrT9
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The tests now extract LLVM IR for @main only. They verify exact opcode counts and instruction ordering for string concatenation, array-element reloads, non-allocating operands, and WTF-8 literal rooting.

Changes

LLVM IR regression tests

Layer / File(s) Summary
Scoped @main IR extraction
crates/perry-codegen/tests/temp_root_operand_temporaries.rs
Added helpers that extract one generated function and verify that the result excludes other module functions.
Temporary-rooting assertions
crates/perry-codegen/tests/temp_root_operand_temporaries.rs
Updated regression tests to use @main IR and assert exact counts and ordering for allocations, handle loads, temporary-root pushes, and operand re-reads.

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

Possibly related PRs

  • PerryTS/perry#6840: Scopes LLVM IR assertions to @main to avoid false positives from unrelated functions.
  • PerryTS/perry#6972: Introduces temporary-rooting behavior validated by these regression tests.
  • PerryTS/perry#7007: Adds scalar-replaced slot rooting and reload behavior covered by these tests.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly and concisely describes scoping the #7114 IR assertions to the function under test.
Description check ✅ Passed The description explains the purpose, changes, related issues, validation results, and test evidence in sufficient detail.
✨ 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 fix/7116-scope-temp-root-ir-assertions

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.

@proggeramlug
proggeramlug merged commit e7bc73b into main Jul 31, 2026
29 of 37 checks passed
@proggeramlug
proggeramlug deleted the fix/7116-scope-temp-root-ir-assertions branch July 31, 2026 06:19
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