Skip to content

fix(gc): error side tables get move/finalize hooks + a user-props root scanner#5978

Merged
proggeramlug merged 4 commits into
mainfrom
fix/gc-error-side-tables
Jul 4, 2026
Merged

fix(gc): error side tables get move/finalize hooks + a user-props root scanner#5978
proggeramlug merged 4 commits into
mainfrom
fix/gc-error-side-tables

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Third GC deep-set slice from the 2026-07-02 audit. Errors are MOVABLE arena objects, and all seven address-keyed side tables in node_submodules::diagnostics (ERROR_MESSAGE_{CODES,SYSCALLS,ERRNOS,PATHS,DESTS,HOSTNAMES} + ERROR_USER_PROPS) were GC-blind — the in-code 'stale entries are harmless' comment was wrong three ways:

  1. Moved error → entries stranded at the old address: err.code / err.syscall / user-assigned props vanished after an evacuating cycle. → GcMoveHookKind::ErrorSideTables rekeys all seven tables on move.
  2. Swept error → entries persisted: a fresh error allocated at the recycled address inherited the dead error's codes/props. → GcFinalizeHookKind::ErrorSideTables (old-gen sweep) + the clear-dead side-table arm + a copied-minor from-space finalize mirroring the map/set pattern.
  3. Object-valued user prop invisible to GC: err.cause = {...} stored raw bits — the referent was collectable while reachable through the error, and dangled after a move (the devils-advocate suite's err.cause failure signature). → scan_error_user_props_roots_mut registered as a mutable-root scanner; visit_nanbox_u64_slot is tag-aware so numeric/boolean bits are untouched.

Three unit tests (move-rekey incl. stale-key-gone, dead-entry cleanup, object-valued-prop root+rewrite) plus the type-metadata contract update. Full GC unit suite green (386).

Code-only; metadata folded at merge.

Summary by CodeRabbit

  • Bug Fixes
    • Improved garbage collection handling for error “side tables,” ensuring entries are correctly rekeyed when an error moves during copied-minor GC.
    • Cleared side-table data for dead errors during copied-minor finalization to prevent stale user properties from being reused by newly allocated errors at recycled addresses.
    • Added proper root tracking for mutable error user properties so referenced objects remain live and pointer bits are rewritten to moved addresses.

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@proggeramlug, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 13 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a34e0d08-5a97-4a60-a2df-193ac2e5a822

📥 Commits

Reviewing files that changed from the base of the PR and between a06b89e and 8b9aada.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • CHANGELOG.md
  • CLAUDE.md
  • Cargo.toml
  • crates/perry-runtime/src/gc/copying.rs
  • crates/perry-runtime/src/gc/mod.rs
  • crates/perry-runtime/src/gc/tests/alloc.rs
  • crates/perry-runtime/src/gc/tests/error_side_tables.rs
  • crates/perry-runtime/src/gc/tests/mod.rs
  • crates/perry-runtime/src/gc/types.rs
  • crates/perry-runtime/src/node_submodules/diagnostics_gc.rs
  • crates/perry-runtime/src/node_submodules/mod.rs
📝 Walkthrough

Walkthrough

This PR adds error side-table GC support: new ErrorSideTables hook variants for GC_TYPE_ERROR, diagnostics helpers for rekeying and clearing entries, copied-minor finalization for dead errors, mutable root scanning for error user props, and tests covering the updated behavior.

Changes

Error side tables GC integration

Layer / File(s) Summary
GC hook variants and dispatch
crates/perry-runtime/src/gc/types.rs
Adds GcMoveHookKind::ErrorSideTables and GcFinalizeHookKind::ErrorSideTables, updates GC_TYPE_ERROR metadata, and extends move/finalize dispatch to call the new diagnostics helpers.
Diagnostics helpers and GC wiring
crates/perry-runtime/src/node_submodules/mod.rs, crates/perry-runtime/src/node_submodules/diagnostics_gc.rs, crates/perry-runtime/src/gc/copying.rs, crates/perry-runtime/src/gc/mod.rs
Adds the diagnostics_gc module, implements error side-table rekeying/clearing/finalization/root scanning, and wires the finalize pass and mutable root scanner into GC execution.
Tests for error side-table GC behavior
crates/perry-runtime/src/gc/tests/mod.rs, crates/perry-runtime/src/gc/tests/error_side_tables.rs, crates/perry-runtime/src/gc/tests/alloc.rs
Registers the new test module, adds coverage for move/death/root-scanning behavior, and updates the expected GC metadata for error objects.

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

Sequence Diagram(s)

sequenceDiagram
  participant GC as GC
  participant Types as gc/types.rs
  participant Diagnostics as diagnostics_gc.rs
  participant GCInit as gc_init
  participant Visitor as RuntimeRootVisitor

  GC->>Types: gc_type_after_payload_move(old_user, new_user)
  Types->>Diagnostics: error_side_tables_owner_moved(old_user, new_user)
  GC->>Types: gc_type_finalize_unmarked_payload(user_ptr)
  Types->>Diagnostics: error_side_tables_clear_dead(user_ptr)
  GC->>Diagnostics: finalize_dead_copied_minor_from_space_errors()
  Diagnostics->>Diagnostics: identify dead GC_TYPE_ERROR entries and clear them
  GCInit->>Diagnostics: gc_register_mutable_root_scanner(scan_error_user_props_roots_mut)
  Diagnostics->>Visitor: visit_nanbox_u64_slot for ERROR_USER_PROPS Bits entries
Loading

Suggested labels: run-extended-tests

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is informative, but it does not follow the required template and omits Summary, Changes, Related issue, Test plan, and Checklist sections. Rewrite the PR description using the repository template and add the missing sections with concrete bullets, issue reference, test commands, and checklist items.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main GC change: error side-table hooks plus a user-props root scanner.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gc-error-side-tables

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.

Ralph Küpper added 4 commits July 4, 2026 18:00
…t scanner

Errors are MOVABLE arena objects, and all seven address-keyed side tables
in node_submodules::diagnostics (ERROR_MESSAGE_{CODES,SYSCALLS,ERRNOS,
PATHS,DESTS,HOSTNAMES} + ERROR_USER_PROPS) were GC-blind — the in-code
'stale entries are harmless' comment was wrong three ways:

1. A MOVED error's entries stayed keyed by the old address, so err.code /
   err.syscall / user-assigned props VANISHED after an evacuating cycle.
   → GcMoveHookKind::ErrorSideTables rekeys all seven on move.
2. A SWEPT error's entries persisted, so a fresh error allocated at the
   recycled address INHERITED the dead error's codes/props.
   → GcFinalizeHookKind::ErrorSideTables (old-gen sweep), the clear-dead
   side-table arm, and a copied-minor from-space finalize mirroring the
   map/set pattern.
3. An OBJECT-valued user prop (err.cause = {...}) was stored as raw bits
   invisible to GC — collectable while reachable through the error, and
   left dangling after its referent moved.
   → scan_error_user_props_roots_mut registered as a mutable-root scanner
   (tag-aware visit_nanbox_u64_slot; numeric/boolean bits untouched).

Three unit tests: move-rekey (stale key also proven gone), dead-entry
cleanup, and object-valued-prop root+rewrite.
@proggeramlug
proggeramlug force-pushed the fix/gc-error-side-tables branch from a06b89e to 8b9aada Compare July 4, 2026 16:00
@proggeramlug
proggeramlug merged commit f39709c into main Jul 4, 2026
@proggeramlug
proggeramlug deleted the fix/gc-error-side-tables branch July 4, 2026 16:00
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