Skip to content

perf(codegen): inline births are black and seeded; omit redundant root-store shading (#11929) - #12059

Merged
proggeramlug merged 2 commits into
PerryTS:mainfrom
proggeramlug:cs-11929-birth-color
Oct 5, 2026
Merged

proggeramlug merged 2 commits into
PerryTS:mainfrom
proggeramlug:cs-11929-birth-color

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Closes #11929. Re-lands #12037 (reverted by #12038) with the inline-birth hole closed structurally.

What

Codegen no longer emits incremental-mark shading on stores into GENERATED GC roots: compiler-managed locals, temporary roots, module globals, persistent scalar/array root aliases. Root bindings/registrations, heap/runtime barriers (closure captures stay heap slots with js_write_barrier_slot) and all GC gates are unchanged.

Removing root-store shading is sound because of two things TOGETHER:

  1. FinalRootRemark rescans every mutable root, including the perf(codegen): use stable homes for root-heavy functions (#11926) #11960 stable homes (cycle.rs → roots.rs → bound_ptr()).
  2. Every inline birth is black and seeded.

Neither alone suffices.

Inline births (the hole that caused the revert)

Both inline codegen allocators, new and small array literals/bundles, now go through ONE shared mechanism that mirrors the runtime allocator:

  1. read the LIVE per-thread birth flags at each birth;
  2. write the header with the flags in one store;
  3. initialize every slot (undefined / +0.0 F64 birth lanes / elements);
  4. seed non-leaf objects through the existing mark-seed queue (js_gc_note_black_birth, which rechecks MARKED and pointer-free itself);
  5. publish.

There is no safepoint inside that window. The array literal's re-entering numeric-layout normalizer runs after it, with the array rooted. During a budgeted sweep the flags are 0, so there is no MARKED bit and no seed, exactly as in the runtime allocators. Those births fall past the sweep snapshot's recorded fill (#11842).

There is no exact gc_flags == GC_FLAG_ARENA precheck in the source or the emitted IR, so black births don't fall to the slow path.

The audit covers every allocation path:

  • runtime objects, arrays, closures, strings, typed arrays and containers already use the runtime allocator (flags + type-dependent seeding);
  • static templates, stack storage and foreign backing are not collectible births.

Results (qb6, 5 interleaved runs, medians; main → head)

instructions CPU s RSS KiB binary
tsc 10,198,988,430 → 10,131,745,462 (−0.66%) 2.29 → 2.05 221,660 → 215,996 −5.71 MB
Zod 785,455,172 → 783,296,310 (−0.27%) 0.13 → 0.12 56,772 → 56,620 −213 KB
hello 1,223,220 → 1,222,913 — 15,832 → 15,664 unchanged; relocations unchanged

Root-shading calls: generic witness 26 → 0, q200 2,608 → 0.

Verification

  • Runtime suite 5,105 passed; codegen 2,544 passed; gc-root-dominance and fmt pass.
  • 60 GC proof/sabotage executions: the white-birth sabotages for new and array literals, and seed-before-init under a forced step, all fail as intended.
  • 18 fixture runs match node across all GC knob sets, including instrumented PERRY_GC_BUDGETED_OLD_RECLAIM=1 + PERRY_GC_PROTECT_OLD_SWEEP=1 (quarantine banner confirmed).
  • The proof tests were adapted to main's removed RememberedSetRebuild phase; no gate was weakened.
  • GC subsets and lint show only failures main already has.

Reviewed by the GC owner before opening: seed ordering for new across the constructor, the array-literal ordering, sweep-phase flags = 0, and seed lifetime across DisableBarrier → sweep snapshot.

@coderabbitai

coderabbitai Bot commented Oct 5, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 08878487-4f09-4e7e-826f-172fb8a3d865
📥 Commits

Reviewing files that changed from the base of the PR and between 44de841 and 2793669.

⛔ Files ignored due to path filters (4)
  • crates/perry-codegen/src/gc_effects/linux-x86_64.tsv is excluded by !**/*.tsv
  • crates/perry-codegen/src/gc_effects/macos-aarch64.tsv is excluded by !**/*.tsv
  • crates/perry-codegen/src/gc_effects/windows-x86_64.tsv is excluded by !**/*.tsv
  • crates/perry-codegen/src/wasm32/runtime_abi.tsv is excluded by !**/*.tsv
📒 Files selected for processing (34)
  • changelog.d/PENDING-11929r-inline-birth.md
  • crates/perry-codegen/src/expr/array_literal.rs
  • crates/perry-codegen/src/expr/array_push_guard_tests.rs
  • crates/perry-codegen/src/expr/generic_overhead_tests.rs
  • crates/perry-codegen/src/expr/hit_path_access_tests.rs
  • crates/perry-codegen/src/expr/hit_path_tests.rs
  • crates/perry-codegen/src/expr/inline_birth.rs
  • crates/perry-codegen/src/expr/mod.rs
  • crates/perry-codegen/src/expr/packed_loop_shadow_barrier_tests.rs
  • crates/perry-codegen/src/expr/scalar_slot_root.rs
  • crates/perry-codegen/src/expr/shadow_inline.rs
  • crates/perry-codegen/src/expr/shadow_slot.rs
  • crates/perry-codegen/src/expr/write_barrier.rs
  • crates/perry-codegen/src/lower_call/alloc_hot_tests.rs
  • crates/perry-codegen/src/lower_call/ctor_prologue_stores.rs
  • crates/perry-codegen/src/lower_call/inline_birth_invariant.rs
  • crates/perry-codegen/src/lower_call/new_alloc.rs
  • crates/perry-codegen/src/rooting/temp_root.rs
  • crates/perry-codegen/src/runtime_decls/strings.rs
  • crates/perry-codegen/tests/scalar_replaced_slot_roots.rs
  • crates/perry-codegen/tests/shadow_slot_hygiene.rs
  • crates/perry-codegen/tests/typed_feedback.rs
  • crates/perry-runtime/src/arena/block.rs
  • crates/perry-runtime/src/arena/inline.rs
  • crates/perry-runtime/src/gc/barrier/mod.rs
  • crates/perry-runtime/src/gc/tests/cycle_state.rs
  • crates/perry-runtime/src/gc/tests/cycle_state/birth_color_controls.rs
  • crates/perry-runtime/src/gc/tests/cycle_state/inline_birth.rs
  • crates/perry-runtime/src/gc/tests/cycle_state/root_remark.rs
  • crates/perry-runtime/src/gc/trace.rs
  • test-files/test_gap_gc_11929_inline_births.ts
  • test-files/test_gap_gc_11929_stable_home_marking.ts
  • test-files/test_gap_gc_generated_root_final_remark.ts
  • test-parity/gc_repsel_corpus.txt
 __________________________________________________
< Are you not entertained? By the bugs I've found? >
 --------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proggeramlug
proggeramlug merged commit 17e324e into PerryTS:main Oct 5, 2026
23 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

~480k out-of-line js_write_barrier_root_nanbox call sites in Claude Code: decide what a root store needs

1 participant