The default fast x29-chain stack-map walker computes wrong slot addresses, and it affects both statepoint backends.
Evidence
PERRY_STACKMAP_WALKER=verify panics: the fast walker and the unwinder each visit 6 slots, and 5 of them differ by 368 bytes — a constant frame-base offset, i.e. the fast walk is anchored to the wrong base rather than reading garbage.
Forcing PERRY_STACKMAP_WALKER=unwind makes the failing probe clean and raises objects copied from 23 to 110 — the wrong addresses were causing live objects to be missed, so the collector was doing less work than it should and freeing things it should not.
Why the shipped configuration is the dangerous one
verify is not the default. In the ordinary run the fast walker is used alone, so there is nothing to disagree with it — this defect is invisible unless someone opts into verify.
Worse, on any host where the x29 chain walk is unavailable the unwinder is the walker, so a configuration that finds no roots enumerates through the same path and forced evacuation stays quiet.
Related, same soak
js_gc_memory_pressure's live-frame oracle (gc/pressure.rs:91) is shadow_stack_has_active_frame(), which is always false under statepoints. Host pressure therefore takes the "precise root set is complete, no conservative scan needed" branch and runs a copying minor with generated frames live — in the shipped default. That is a second way the same configuration loses roots, and it is not gated behind any knob.
Reproducer: PERRY_STACKMAP_WALKER=verify on wt-spsoak/gc-soak/notry_control.ts. Found during the statepoint adoption soak.
The default fast x29-chain stack-map walker computes wrong slot addresses, and it affects both statepoint backends.
Evidence
PERRY_STACKMAP_WALKER=verifypanics: the fast walker and the unwinder each visit 6 slots, and 5 of them differ by 368 bytes — a constant frame-base offset, i.e. the fast walk is anchored to the wrong base rather than reading garbage.Forcing
PERRY_STACKMAP_WALKER=unwindmakes the failing probe clean and raises objects copied from 23 to 110 — the wrong addresses were causing live objects to be missed, so the collector was doing less work than it should and freeing things it should not.Why the shipped configuration is the dangerous one
verifyis not the default. In the ordinary run the fast walker is used alone, so there is nothing to disagree with it — this defect is invisible unless someone opts intoverify.Worse, on any host where the x29 chain walk is unavailable the unwinder is the walker, so a configuration that finds no roots enumerates through the same path and forced evacuation stays quiet.
Related, same soak
js_gc_memory_pressure's live-frame oracle (gc/pressure.rs:91) isshadow_stack_has_active_frame(), which is always false under statepoints. Host pressure therefore takes the "precise root set is complete, no conservative scan needed" branch and runs a copying minor with generated frames live — in the shipped default. That is a second way the same configuration loses roots, and it is not gated behind any knob.Reproducer:
PERRY_STACKMAP_WALKER=verifyonwt-spsoak/gc-soak/notry_control.ts. Found during the statepoint adoption soak.