Skip to content

Merge train 184s: #10217 - #10233

Merged
proggeramlug merged 4 commits into
mainfrom
train184s
Sep 13, 2026
Merged

proggeramlug merged 4 commits into
mainfrom
train184s

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Merge train 184s: lands #10217 (reclaim dead blocks without visiting them in the synchronous full sweep; Part 1 of #10182) at 0e782c659a, plus the workspace version bump to 0.5.1562. (The "s" suffix keeps clear of the other merge lane's train numbers.)

The three PR commits were cherry-picked onto 6000a00dfe without conflicts.

Validation (macOS arm64)

Validation ran on the same PR over bb9aa5a641. Main has since gained only #10225 (regex files), which #10217 does not touch.

  • scripts/run_lint_gates.sh: 80 of 83 pass. The 3 failures are the same steps as main: public benchmark evidence freshness, API docs drift, and -D warnings stopping on main's global_this_webassembly.rs dead code.
  • raw_handle_debt.py (both invocations), gc_runtime_root_holders.py, shape_descriptor_census.py, gc_store_site_inventory.py, fmt, file size: pass. check_thread_locals.py: only main's regex/perex_owner.rs.
  • cargo test --release -p perry-runtime: 3786 passed / 1 failed. This run includes the test-build safety net that re-walks every skipped block. The failure is gc::tests::heap_generation::a_free_or_move_outside_every_scope_is_caught_in_debug_builds, already on main from perf(regex): resume JS-level searches on non-ASCII strings from the previous call's position #10205. --lib block_skip: 11 / 0.
  • Full gap suite (779 tests): 766 pass. Gated failures are main's known set (2899_2779_2777_static_helpers, disposablestack_2875, iterator_prototype_next_patch, gc_http2_pending_event_callback_rooting) plus 9592_child_timeout_threads, where the Node oracle fails on this host. Two further entries were timing flakes on a loaded host: 9574_unlink_waits_for_parked_write passes 3/3 on this build and also fails intermittently with a 9b911855f8 compiler, and 9676_stdin_unref_ref_keeps_reader hit the 10 s harness timeout once, then passed 3/3 on this build and 2/2 with the old compiler.
  • The skip's subject is live. A parse-and-drop probe (40k-record documents parsed eight times with three retained, maps, explicit gc()) under PERRY_GC_DIAG=1 reports block_skip_reclaimed_blocks up to 3 and a block of 23,834 objects reclaimed without visiting it. Its output matches Node except the final WeakRef.deref() of an unreferenced object, which Perry clears after gc() while Node still holds it. JS permits either, and it is identical across the plain, diagnostic and GC-stress runs. Under PERRY_GC_SCHEDULE_SEED 7 and 184 at rate 0.2, with forced evacuation, verification and from-space protection (917 and 935 copying minors), the output is identical to the plain run.

Confirmation on this exact tree: RUSTFLAGS=-Dwarnings cargo check -p perry --bins; cargo test --release -p perry-runtime 3791 passed / 1 failed (the same #10205 test).

CI attribution (#10217 run 34769800931 vs main's run at b5a82cfeae)

The same failing lint/check/warnings/cargo-test steps and errors, the same native_stack failure, the same four gated gap regressions with identical output, and the same gc-stress failure.

Review notes

A block is skipped only when no census membership query landed in it (every census-built mark is preceded by one) and the census recorded no per-object obligation: pinned, forwarded or pre-marked headers, non-arena, finalize hooks, Error/RegExp/LazyArray dead-payload hooks, raw-f64/holes array layouts, or legacy overflow and wasm-wrapper entries while those tables are non-empty. Allocate-black births are excluded by the bump-offset comparison and block persistence by the recent-window exclusion. Budgeted fulls and minors keep the per-object walk. Page bookkeeping for skipped old blocks goes through the existing unregister_old_block_pages.

Summary by CodeRabbit

  • New Features

    • Synchronous full garbage collections can now reclaim eligible untouched memory blocks without scanning every object, improving collection efficiency.
    • GC diagnostics report reclaimed blocks, objects, and bytes when enabled with PERRY_GC_DIAG=1.
  • Documentation

    • Updated garbage-collector documentation to explain block-level reclamation, eligibility limits, and diagnostic output.
  • Chores

    • Updated the application version from 0.5.1561 to 0.5.1562.

Ralph Küpper added 4 commits September 14, 2026 00:26
… sweep (#10182)

A synchronous full sweep walked every arena object; each dead one paid for
old-page accounting, finalize_dead_arena_payload and a page-index removal
before the block cleanup reset the block wholesale. After a parse/scan loop
most blocks hold only dead objects, so a full's cost scaled with garbage.

The exact census (ValidPointerSetBuilder) now seals its address-ordered runs
at block boundaries and records, per block, the object count, bytes, and
whether any header owes per-object work (pinned, forwarded, pre-marked, no
ARENA flag, a finalize hook, an error/regexp/lazy-tape hook, raw-f64 array
layout bits, or an object while the legacy overflow table or the wasm
module-wrapper registry has entries). A successful census membership query
marks the query's block as reached; every mark a census-built cycle sets is
preceded by one, and the two mark paths that are not (allocate-black births,
block-persistence force marks) are excluded by construction (a block whose
bump offset moved since the census, and the recent general window, are never
skipped).

ArenaSweepObjectsState skips a block that is censused, unreached, free of
obligations, unchanged since the census, and reclaimed by the cleanup when it
has no live object (general blocks outside the recent window, survivor and
old blocks). Freed/Eden-dead bytes come from the census sums; the block
cleanup's unregister_old_block_pages supersedes the per-object page
bookkeeping; element-shape, per-object layout and closure side tables are
already dropped by the full trace's dead-owner fan-out. The require-marked
old-to-young remembered-set rebuild skips the same unreached blocks. Test
builds re-walk every skipped block and assert it holds no marked or pinned
header.

Budgeted fulls (classifier membership, mutator windows) and minors keep the
per-object walk. ArenaSweepObjectsState moves to gc/oldgen/sweep_objects.rs
for the 2000-line cap. PERRY_GC_DIAG prints block_skip_reclaimed_blocks /
_objects / _bytes on each sweep's [gc] blocks: line.

(cherry picked from commit 27ad15e)
(cherry picked from commit 0b81857)
@proggeramlug
proggeramlug merged commit d8bfa28 into main Sep 13, 2026
21 of 24 checks passed
@proggeramlug
proggeramlug deleted the train184s branch September 13, 2026 22:34
@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: f8d9cbec-ab3b-4ae5-9dab-7dab8ca5f65a

📥 Commits

Reviewing files that changed from the base of the PR and between 6000a00 and 5f0cade.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • CLAUDE.md
  • Cargo.toml
  • changelog.d/10217-gc-block-granular-sweep.md
  • crates/perry-runtime/src/arena/mod.rs
  • crates/perry-runtime/src/arena/reset.rs
  • crates/perry-runtime/src/arena/walk.rs
  • crates/perry-runtime/src/array/element_shape.rs
  • crates/perry-runtime/src/array/mod.rs
  • crates/perry-runtime/src/gc/cycle.rs
  • crates/perry-runtime/src/gc/oldgen.rs
  • crates/perry-runtime/src/gc/oldgen/sweep_objects.rs
  • crates/perry-runtime/src/gc/tests/block_skip.rs
  • crates/perry-runtime/src/gc/tests/mod.rs
  • crates/perry-runtime/src/gc/trace.rs
  • crates/perry-runtime/src/gc/trace/block_skip.rs
  • crates/perry-runtime/src/gc/verify.rs
  • crates/perry-runtime/src/object/global_this.rs
  • crates/perry-runtime/src/object/global_this_webassembly.rs
  • docs/src/internals/garbage-collector.md
  • scripts/gc_runtime_root_holders.json

📝 Walkthrough

Walkthrough

Changes

Block-granular garbage collection

Layer / File(s) Summary
Census and block-walk infrastructure
crates/perry-runtime/src/arena/..., crates/perry-runtime/src/gc/trace..., crates/perry-runtime/src/object/...
Arena cursors now support skipped block indices. BlockCensus records block contents, reachability, and per-object sweep obligations.
Sweep and remembered-set integration
crates/perry-runtime/src/gc/cycle.rs, crates/perry-runtime/src/gc/oldgen.rs, crates/perry-runtime/src/gc/oldgen/sweep_objects.rs, crates/perry-runtime/src/gc/verify.rs
Synchronous full cycles skip eligible unreached blocks during remembered-set rebuilding and sweeping. Budgeted cycles and minors continue to walk blocks.
Safety tests and test fixtures
crates/perry-runtime/src/array/..., crates/perry-runtime/src/gc/tests/...
Tests cover reclamation, live objects, finalizers, side tables, weak references, sabotage cases, and budgeted full collections.
Documentation and release metadata
CLAUDE.md, Cargo.toml, changelog.d/..., docs/src/internals/..., scripts/gc_runtime_root_holders.json
Version records, changelog text, collector documentation, and GC holder metadata describe the implementation and diagnostics.

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant FullGC
  participant BlockCensus
  participant RememberedSetRebuild
  participant ArenaSweep
  FullGC->>BlockCensus: collect reachability and sweep obligations
  BlockCensus-->>RememberedSetRebuild: provide unreached block set
  RememberedSetRebuild->>ArenaObjectCursor: skip selected blocks
  FullGC->>ArenaSweep: pass census
  ArenaSweep->>ArenaSweep: reclaim eligible blocks without object walking
Loading
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch train184s

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.

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.

1 participant