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
gc: the seeded schedule never arms the poll word — SCHEDULE_RATE=1 sees 6 safepoints where zeal sees 9,648 (blocks #7741) #7781
Found while testing #7741's precondition, and it blocks #7741
The maintainer's condition for #7741 (removing PERRY_GC_ZEAL) is that the SCHEDULE_RATE=1 equivalence be demonstrated on one of the four reproductions zeal closed this week. Tested on #7606's rooting tests, same binary (main @ v0.5.1450), same quarantine settings:
instrument
rest_argument
same_module_call
PERRY_GC_ZEAL=1
379 collections, 115,536 moved, 9,648 loop polls
749 collections, 231,012 moved, 19,248 polls
PERRY_GC_SCHEDULE_SEED=… RATE=1
safepoints=6, 6 collections
safepoints=6, 6 collections
RATE=1 is the "collect at every opportunity" end of the dial. It saw six opportunities.
Cause
#7735 collapsed the loop back-edge poll's no-work path to one load of PERRY_GC_POLL_ARMED. The word is kept armed for zeal (resolve_poll_seed retains the startup seed when gc_zeal_enabled()), and ZealGuard arms/releases it for tests. Nothing arms it for the schedule mode — so with schedule-on/zeal-off, every back-edge poll takes the disarmed fast path, js_gc_loop_safepoint is never entered, and the loop-safepoint bypass #7317 added sits behind a gate that never opens. The schedule's only surviving entry point is the microtask-pump boundary: six per run on this test.
This is #7735's own design note played out: the arming word is a counter of reasons, and a new reason (a mode whose collection decision lives inside the safepoint) must register itself. The schedule mode was written before the word existed and was merged across it (#7317's rebase) without gaining an arm.
Fix
resolve_poll_seed keeps the startup seed when schedule::gc_schedule_enabled(), exactly as for zeal.
The second test was added after #7782 and covers the real startup-seed resolution branch that the PR review originally noted was not exercised.
I also rebuilt the exact current compiler/runtime/stdlib triple and reran test_gap_gc_rest_argument_rooting.ts with the issue's environment, including from-space protection at depth 800. It printed bad 0, exited 0, and the schedule footer reported:
The current post-#7741 scheduler deliberately paces 9,274 of those polls, so the collection count is no longer the earlier 9,653 figure. The load-bearing acceptance is still demonstrated: the schedule sees all 9,648 loop polls instead of being trapped at the old six event-loop boundaries, and its eligible polls drive 379 copying minors with the expected 115,536 moved objects.
Activity
fix(gc): the seeded schedule arms the poll word, like zeal (#7781) (#…
proggeramlug commentedon Aug 12, 2026
Verified fixed on current
main(5b3dc14f0). Merge commit9499a8c10from #7782 is present.Current-main focused coverage is non-vacuous and green:
the_schedule_holds_the_poll_word_armed: 1 passed, 0 failedthe_startup_seed_is_kept_only_for_a_resolved_seed: 1 passed, 0 failedThe second test was added after #7782 and covers the real startup-seed resolution branch that the PR review originally noted was not exercised.
I also rebuilt the exact current compiler/runtime/stdlib triple and reran
test_gap_gc_rest_argument_rooting.tswith the issue's environment, including from-space protection at depth 800. It printedbad 0, exited 0, and the schedule footer reported:The current post-#7741 scheduler deliberately paces 9,274 of those polls, so the collection count is no longer the earlier 9,653 figure. The load-bearing acceptance is still demonstrated: the schedule sees all 9,648 loop polls instead of being trapped at the old six event-loop boundaries, and its eligible polls drive 379 copying minors with the expected 115,536 moved objects.
Closing as fixed by #7782.