Repository navigation
Description
native-roots-aarch64 cannot pass on current main. Four of its steps run
09_try_catch_roots through the explicit statepoint bridge, and since #7330
that module refuses to compile — by design.
Nobody has seen it because GitHub's queue has not started a gc-native-roots
job in hours; every run on main and on open PRs is sitting in queued.
Reproduced locally at e98dfdb25
macOS/aarch64, cargo build --profile perry-dev -p perry -p perry-runtime-static -p perry-stdlib-static with the workflow's own RUSTFLAGS:
01_nursery_churn: ok 05_closure_capture: ok
02_survivor_promotion: ok 06_string_retention: ok
03_cross_gen_writes: ok 07_array_grow_evacuate: ok
04_dead_after_deep_stack: ok 08_map_set_sidetables: ok
09_try_catch_roots: COMPILE FAILED
statepoint forced-evacuation matrix: 8/9
thread 'perry-main' panicked at crates/perry-codegen/src/function/precise_roots.rs:722:17:
perry: native-root lowering cannot yet express a safepoint on an `invoke` —
`<indirect-or-unsupported>` in @perry_fn__09_try_catch_roots_ts__roundTrip has 1
live root(s) across it. … PERRY_RS4GC=1 handles invokes, but needs
PERRY_LLVM_CLANG pointing at a version-matched LLVM 22 …
Same result on aarch64-unknown-linux-gnu, so it is not host-specific.
The steps that break
All are in native-roots-aarch64, all use set -euo pipefail, so each dies at
the perry invocation:
Probe matrix, statepoint mode, forced evacuation— globs*.tsand
assertspass == total; total is derived from the glob (9) precisely so it
cannot go stale, so it can only be satisfied by 09 compiling.Safepoint-only contract changes codegen (differential)— globs*.ts
and runs--statepoint-report=jsonon each.Probe matrix, safepoint-only contract in strict mode— globs*.ts.Probe matrix under both non-default walkers— globs*.ts.
And one more that is not a glob:
Root-pressure report fails closed (--statepoint-report)hardcodes
probe=benchmarks/gc_ratchet/probes/09_try_catch_roots.ts. That step exists
to assertplain_stack_maps == 0andstatepoint_fallbacks == 0, and it now
cannot run at all.
native-roots-rs4gc-aarch64 is unaffected — RS4GC handles invokes.
Why this is awkward rather than obvious
09_try_catch_roots was added by #7314 because nothing in the suite contained
a try at all — 0 of 8 probes. Dropping it from the explicit-bridge matrix
gives that coverage straight back up, and #7330's own changelog is explicit that
"this leaves no working statepoint path for try-carrying code on a default
toolchain".
So the options are not equal:
- Assert the refusal (the
statepoints-refuse-x86pattern): the bridge must
refuse 09 with that message, and 09 must still pass under RS4GC. Keeps the
gate red if the refusal ever silently becomes a rootless binary. Cheapest, and
it does not pretend the coverage exists. - Skip 09 in the bridge arm. Same effect on CI, but nothing then notices if
the refusal regresses. - Teach the bridge to form a statepoint from an
invoke— the statepoint
becomes an invoke, withgc.resultand the relocates in the normal successor.
fix(gc): the statepoint bridge must refuse an invoke it cannot root (#7327) #7330 calls this "real work"; it is also the only option that restores the
coverage rather than documenting its absence.
I have deliberately not reshaped the gate, since which of these is right is a
call about how long try-carrying code stays uncovered.
Note on the fifth step
Whatever is chosen, step 5's report probe has to move to a module the bridge can
compile, or its assertions are simply not running — which is CLAUDE.md's fourth
failure mode (the gate runs, its subject never did).
Activity
ci(gc): stop the bridge job compiling a probe the bridge now refuses (#…