You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Statepoint bridge emits no statepoint on invoke — every call inside a try is unrooted #7327
The explicit statepoint bridge emits no statepoint on invoke, so every call inside a try is unrooted under PERRY_STATEPOINTS=1.
Evidence
In the emitted IR: 58 invokes, 0 carrying gc.statepoint. Invoked callees include allocating runtime helpers — js_object_alloc_class_inline_keys, js_array_push_f64, js_native_call_method_by_id.
Isolation, same program and runtime, PERRY_STACKMAP_WALKER=unwind:
backend
result
explicit bridge
0/3 clean
RS4GC
3/3
shadow stack
3/3
So this is bridge-specific; RS4GC covers invoke correctly.
The reporting is silent about it
--statepoint-report counts "310 textual calls" and never sees these. "0 parser fallbacks" therefore says nothing about any call inside a try — the report's clean bill of health has a hole exactly where exceptions are.
This matters because #7302 moved exception lowering to invoke/landingpad precisely so that try-carrying functions could take statepoints like any other, and #7314 added 09_try_catch_roots.ts because nothing in the suite contained a try at all (0 of 8 probes). The probe passes; the bridge still does not root invoked calls.
Reproducer: wt-spsoak/gc-soak/try_root_probe.ts. Found during the statepoint adoption soak.
Fixed in #7330 — but as a refusal, not as invoke support, and the reason matters for the plan.
is_call matched only call/tail call, so an invoke skipped both the statepoint conversion and the fail-closed panic! beneath it. It now refuses when an invoke carries live roots (and the callee is neither an llvm.* intrinsic nor in the audited cannot-collect table), and invokes are counted by --statepoint-report so the census stops overstating its coverage.
The finding underneath is larger than the bug: there is currently no working statepoint path for try-carrying code on a default toolchain.
The bridge cannot express a statepoint on an invoke.
RS4GC can, but on a default macOS toolchain it fails at clang -c with error: unterminated attribute group under Apple clang 21, and needs PERRY_LLVM_CLANG pointed at a version-matched LLVM 22. Verified pre-existing — identical failure with an unmodified binary built before fix(gc): the statepoint bridge must refuse an invoke it cannot root (#7327) #7330.
Exceptions are not an edge case, so this is on the critical path for removing the shadow stack. Two ways forward, and they are not equivalent:
Teach the bridge invokes — the statepoint must itself become an invoke, with gc.result and the relocates in the normal successor. RS4GC is the in-tree reference for the shape.
Option 2 looks structurally better: #7301 already pins LLVM 22 in-process and its rs4gc_schedules_in_process test proves RS4GC schedules there. The version-skew problem this hits is exactly what the in-process backend exists to remove.
Activity
fix(gc): the statepoint bridge must refuse an invoke it cannot root (#…
proggeramlug commentedon Aug 3, 2026
Fixed in #7330 — but as a refusal, not as invoke support, and the reason matters for the plan.
is_callmatched onlycall/tail call, so aninvokeskipped both the statepoint conversion and the fail-closedpanic!beneath it. It now refuses when an invoke carries live roots (and the callee is neither anllvm.*intrinsic nor in the audited cannot-collect table), and invokes are counted by--statepoint-reportso the census stops overstating its coverage.The finding underneath is larger than the bug: there is currently no working statepoint path for try-carrying code on a default toolchain.
clang -cwitherror: unterminated attribute groupunder Apple clang 21, and needsPERRY_LLVM_CLANGpointed at a version-matched LLVM 22. Verified pre-existing — identical failure with an unmodified binary built before fix(gc): the statepoint bridge must refuse an invoke it cannot root (#7327) #7330.Exceptions are not an edge case, so this is on the critical path for removing the shadow stack. Two ways forward, and they are not equivalent:
invoke, withgc.resultand the relocates in the normal successor. RS4GC is the in-tree reference for the shape.Option 2 looks structurally better: #7301 already pins LLVM 22 in-process and its
rs4gc_schedules_in_processtest proves RS4GC schedules there. The version-skew problem this hits is exactly what the in-process backend exists to remove.