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
Tracking issue so the nursery-scoped-minor rollout (from #6129, addressing #6083) doesn't get forgotten behind its off-by-default flag — and to record the path to a genuinely best-in-class GC.
Gated behind PERRY_NURSERY_SCOPED_MINOR (default off) + a per-minor runtime gate (only when the minor is fully non-moving: no old-page defrag). The compiler is unchanged; this is a runtime env flag.
Off by default because a wrong old→young edge is a silent UAF (memory corruption), and the correctness surface is large (multiple remembered-set parent sources, all retention patterns, evacuation interactions). Validation caught + fixed two real bugs already (remembered-set parent validation; the fallback per-header set).
Flip-to-default-on checklist (exit criteria)
CI soak lane: run gc-stress + a conformance/parity shard with PERRY_NURSERY_SCOPED_MINOR=1 on every PR/push (non-gating at first). This turns "soak" into continuous automated exercise AND prevents the code from rotting.
Differential fuzz/stress in CI: same programs, flag on vs off → byte-identical stdout + comparable RSS, across a spread of retention/allocation patterns (Maps/Sets/WeakMap/WeakRef/FinalizationRegistry, typed arrays, proxies, closures-with-boxes, big graphs).
Remembered-set source audit: confirm step_dirty_old_page_walk includes exactly every parent mark_remembered_set_roots validates (currently: dirty pages, external entries, fallback headers) — add a debug assertion that panics if the mark ever validates a parent not in the young set.
Real-app soak: run a long-lived server workload (SSR/fastify) with the flag on for a sustained window; no corruption, expected RSS/pause.
Flip the default (drop the env gate to on; keep PERRY_NURSERY_SCOPED_MINOR=0 as the escape hatch).
The bigger picture: the actual best-GC path
#6083 optimizes the fallback path (conservative, non-moving, alloc-point-triggered minor). Best-in-class is different: safepoint-based, precise, MOVING (copying) minors — which Perry already implements (gc_collect_minor_copying_fast_path) but currently disables. It's disabled because GC triggers at arbitrary alloc points under conservative scan (registers unspilled), which precludes moving; and the budgeted/sliced stepper that would run precise safepoint copying minors is blocked because ~35 root scanners lack budgeted cursors.
Real win: convert those ~35 sync-only root scanners to budgeted/rewritable form → unblock the budgeted stepper → GC advances at safepoints with precise roots → copying minors run (copy survivors out, bulk-reset the nursery, no sweep). That's the V8-class design and it subsumes[perf] Generational GC unreachable in production → every collection is STW O(total heap) #6083's benefit (copying > non-moving-scoped).
Tracking issue so the nursery-scoped-minor rollout (from #6129, addressing #6083) doesn't get forgotten behind its off-by-default flag — and to record the path to a genuinely best-in-class GC.
State
PERRY_NURSERY_SCOPED_MINOR(default off) + a per-minor runtime gate (only when the minor is fully non-moving: no old-page defrag). The compiler is unchanged; this is a runtime env flag.Flip-to-default-on checklist (exit criteria)
PERRY_NURSERY_SCOPED_MINOR=1on every PR/push (non-gating at first). This turns "soak" into continuous automated exercise AND prevents the code from rotting.step_dirty_old_page_walkincludes exactly every parentmark_remembered_set_rootsvalidates (currently: dirty pages, external entries, fallback headers) — add a debug assertion that panics if the mark ever validates a parent not in the young set.PERRY_NURSERY_SCOPED_MINOR=0as the escape hatch).The bigger picture: the actual best-GC path
#6083 optimizes the fallback path (conservative, non-moving, alloc-point-triggered minor). Best-in-class is different: safepoint-based, precise, MOVING (copying) minors — which Perry already implements (
gc_collect_minor_copying_fast_path) but currently disables. It's disabled because GC triggers at arbitrary alloc points under conservative scan (registers unspilled), which precludes moving; and the budgeted/sliced stepper that would run precise safepoint copying minors is blocked because ~35 root scanners lack budgeted cursors.Suggested sequence: soak+flip #6083 (this issue) → then the budgeted-stepper/copying-minor project as the primary GC push.