Skip to content

perf(runtime): delete REGEX_SOURCE_TABLE; identify RegExps by header - #11518

Merged
proggeramlug merged 2 commits into
mainfrom
claude/eloquent-rubin-2arn2p
Sep 27, 2026
Merged

proggeramlug merged 2 commits into
mainfrom
claude/eloquent-rubin-2arn2p

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This deletes REGEX_SOURCE_TABLE. It was an address-keyed thread-local PtrHashMap<usize, RegexMetadata>, and its only payload was registered_owner: bool. Even so, every RegExp construction inserted into it, every copying minor rekeyed it, and every collection walked it twice just to find dead RegExps and clear their expandos. The shared dead-owner fan-out (prune_dead_exotic_expando_owners) already does that clearing in the same windows. A RegExp is now identified by its own GC header.

Changes

  • Identity (regex.rs): is_regex_pointer, is_valid_regex_ptr and is_registered_regex now answer from the header alone (GC_TYPE_REGEXP + size + REGEXP_MAGIC). They already checked the header first; the table fallback only changed the answer for a stale entry. I checked every reader of registered_owner: the probe fallback, the rekey merge and the two death walks. All of them are "is this a regex we allocated" membership checks, with no other meaning.
  • GC wiring (gc/types.rs): GC_TYPE_REGEXP now uses the shared GcMoveHookKind::ExoticExpandoOwner move hook and GcFinalizeHookKind::None. The following are removed:
    • GcMoveHookKind::RegExpSideTables and GcFinalizeHookKind::RegExpSideTables
    • regex_header_moved_for_gc, _clear_dead_for_gc and _finalize_for_gc
    • the copied-minor finalize_dead_copied_minor_from_space_regexps pass and its +regex: diag field
    • the sweep's dead_regexps subphase (collect_dead_registered_regexps_post_trace / finalize_collected_dead_regexp)
    • the REGEX_EVER_REGISTERED latch
    • prefetch_gc_owner_headers and exotic_expando_owner_clear_dead, whose only callers were the removed code
  • Death: a dead RegExp's expando entry is dropped by the dead-owner fan-out, like Promise's. expando_clear_on_alloc at construction still covers an address that gets reused. The sweeper keeps pinned objects live, so no path frees a RegExp without the fan-out seeing it first. block_skip may now reclaim whole dead blocks holding RegExps without visiting them.
  • Gates:
    • Deleted the REGEX_SOURCE_TABLE entry from scripts/gc_runtime_root_holders.json.
    • scripts/shape_descriptor_census.py now requires RegExp's type metadata to carry ExoticExpandoOwner and GcFinalizeHookKind::None.
    • gc_rekeyed_key_tables.json and DEAD_KEY_PRUNES had no entry for this table: it was rekeyed by a move hook, not a visit_metadata_* site, so nothing needed deleting there.
  • Stale doc comments updated in dead_owner.rs, json_tape_store.rs, hot_diag.rs (the regex side-table counters are now documented as zeroed after-controls) and exotic_expando.rs.
  • Not touched: the version in Cargo.toml / CLAUDE.md, and Cargo.lock.

Related issue

Closes #11503 (part of #9908).

Test plan

New and updated tests:

  • regex::tests::regexp_identity_is_the_header_not_an_address_registry: a header registered nowhere is identified by all three probes, and clearing its magic makes all three say no.
  • regex::tests::regexp_gc_type_needs_no_bespoke_side_table_hooks
  • gc::tests::dead_owner_side_tables::regexp_expandos::test_dead_regexp_expando_pruned_on_full_gc (uses full_gc_with_no_block_persistence, so the owner is really dead) and test_live_regexp_expando_survives_full_gc
  • nursery_regexp_that_dies_young_is_finalized_by_the_copied_minor: sets expandos through the production [[Set]] path. It checks that a copying minor ran, that the dead RegExp's entry is gone, and that the live one's value moved to its new address.
  • test_movable_regexp_evacuation_migrates_all_address_owned_state: now checks the copying minor ran and the expando migrated, instead of reading the deleted table.

Sabotage checks. For each one I applied the sabotage, rebuilt and saw the tests go red, then restored the code:

  1. prune_dead_exotic_expando_owners made to skip RegExp owners → test_dead_regexp_expando_pruned_on_full_gc and nursery_regexp_that_dies_young… fail at their "expando must be pruned" assertions.
  2. RegExp move hook set to GcMoveHookKind::None → test_movable_regexp_evacuation…, nursery_regexp_that_dies_young… and regexp_gc_type_needs_no_bespoke_side_table_hooks fail.
  3. regex_header_has_magic made to ignore the magic word → regexp_identity_is_the_header_not_an_address_registry fails.

Results:

  • RUST_TEST_THREADS=1 cargo test --lib -p perry-runtime: 4646 passed, 0 failed, 4 ignored.
  • PERRY_GC_FORCE_EVACUATE=1 PERRY_GC_VERIFY_EVACUATION=1, filters regex perex regexp_expando: 210 passed, 0 failed.
  • With the filter widened to copying dead_owner under the same knobs, 4 copying tests fail: set_index::{old_identity_keys_are_skipped_by_a_minor, young_identity_half_prunes_dead_keys_and_follows_moved_ones} and test_copying_minor_rewrites_exact_{closure_pointer_capture,object_pointer_slot}_only. They fail identically on pristine main under these knobs, because they assert exact slot-read counts. Not caused by this PR.
  • RUSTFLAGS="-D warnings" cargo check -p perry-runtime -p perry-stdlib --all-targets, plus -p perry-runtime --no-default-features: clean. cargo check --locked -p perry-stdlib --no-default-features (as CI runs it): clean. cargo clippy -p perry-runtime --all-targets: no new findings in any touched file compared with main.
  • SKIP_COMPILE_GATES=1 scripts/run_lint_gates.sh: 91/94 pass, including every GC inventory gate, cargo fmt --check and check_file_size.sh. The 3 that fail do so for reasons outside this PR: no Bun on the host, no cargo-xwin, and ci_public_baseline_check.py, which fails identically on pristine main in this container.
  • cargo build --release and the regex gap tests: not run locally. perry needs LLVM 22, and this container's network policy blocks apt.llvm.org. The PR-tier gap-suite shards cover the default run. I have not run the gap tests under PERRY_GC_FORCE_EVACUATE=1 PERRY_GC_VERIFY_EVACUATION=1; that part of the issue's Verify list is still open.
  • Added #[test]s in the affected crate.
  • n/a: docs/src/ (no API change).

Checklist

  • I have NOT bumped the workspace version or edited CLAUDE.md / CHANGELOG.md
  • Commit follows the perf: prefix convention
  • Read CONTRIBUTING.md

Generated by Claude Code

Summary by CodeRabbit

  • Updates

    • RegExp identity is now checked using allocation metadata rather than a separate registry.
    • Garbage collection now cleans up RegExp expandos through shared dead-object handling. Live RegExp expandos remain associated with their objects through collection.
    • Removed RegExp-specific finalization work from garbage collection diagnostics.
  • Tests

    • Added coverage for RegExp identity checks, expando cleanup, and expando preservation across garbage collection.

`REGEX_SOURCE_TABLE` was an address-keyed thread-local map whose only
payload was `registered_owner: bool`. Every construction inserted into it,
every copying minor rekeyed it, and every collection walked it twice (the
copied-minor from-space finalizer and the sweep-entry dead-regexp
subphase) only to clear dead RegExps' expandos, which the dead-owner
fan-out (`prune_dead_exotic_expando_owners`) already did in the same
windows.

- `is_regex_pointer` / `is_valid_regex_ptr` / `is_registered_regex`
  answer from the header (GC_TYPE_REGEXP + size + REGEXP_MAGIC), which
  they already checked first. Every `registered_owner` reader was a
  membership check, so no other semantics are lost.
- GC_TYPE_REGEXP uses the shared ExoticExpandoOwner move hook and no
  finalize hook. The RegExpSideTables hook kinds, the copied-minor regex
  finalizer, the sweep's dead_regexps list, the REGEX_EVER_REGISTERED
  latch, and the now-unused prefetch_gc_owner_headers /
  exotic_expando_owner_clear_dead helpers are removed.
- Gates: drop the REGEX_SOURCE_TABLE entry from
  gc_runtime_root_holders.json; shape_descriptor_census.py now pins
  RegExp to ExoticExpandoOwner + GcFinalizeHookKind::None.

Tests cover header-only identity, the hook wiring, expando pruning for
a dead RegExp on a full GC and on a copying minor (asserting the minor
ran), and expando migration for a live RegExp that moves.

Closes #11503
@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: deaf0bae-8a09-4983-acff-311f80c80154

📥 Commits

Reviewing files that changed from the base of the PR and between c1d93bb and b471ff8.

📒 Files selected for processing (19)
  • changelog.d/11518-delete-regex-source-table.md
  • crates/perry-runtime/src/gc/copying_phase.rs
  • crates/perry-runtime/src/gc/dead_owner.rs
  • crates/perry-runtime/src/gc/oldgen.rs
  • crates/perry-runtime/src/gc/prefetch.rs
  • crates/perry-runtime/src/gc/tests/copying/survival_and_malloc.rs
  • crates/perry-runtime/src/gc/tests/dead_owner_side_tables.rs
  • crates/perry-runtime/src/gc/tests/dead_owner_side_tables/regexp_expandos.rs
  • crates/perry-runtime/src/gc/tests/runtime_roots/perex_lifecycle.rs
  • crates/perry-runtime/src/gc/trace/block_skip.rs
  • crates/perry-runtime/src/gc/types.rs
  • crates/perry-runtime/src/hot_diag.rs
  • crates/perry-runtime/src/json_tape_store.rs
  • crates/perry-runtime/src/object/exotic_expando.rs
  • crates/perry-runtime/src/regex.rs
  • crates/perry-runtime/src/regex/perex_construct.rs
  • crates/perry-runtime/src/regex/tests.rs
  • scripts/gc_runtime_root_holders.json
  • scripts/shape_descriptor_census.py
💤 Files with no reviewable changes (3)
  • scripts/gc_runtime_root_holders.json
  • crates/perry-runtime/src/gc/prefetch.rs
  • crates/perry-runtime/src/gc/oldgen.rs

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

The change removes the RegExp address registry and its GC rekeying and finalization paths. RegExp identity checks use GC header metadata, while expando cleanup uses shared dead-owner handling. Tests and GC metadata checks are updated. The GC owner-header prefetch helper is also removed.

Changes

RegExp identity and GC lifecycle

Layer / File(s) Summary
Header-based identity and construction
crates/perry-runtime/src/regex.rs, crates/perry-runtime/src/regex/perex_construct.rs, crates/perry-runtime/src/regex/tests.rs, crates/perry-runtime/src/gc/tests/runtime_roots/perex_lifecycle.rs
RegExp pointer checks use header type, size, and magic instead of registry membership. Construction no longer inserts receiver metadata into the source table. Tests check header-based identity and GC pointer state.
Shared expando-owner GC hooks
crates/perry-runtime/src/gc/types.rs, crates/perry-runtime/src/object/exotic_expando.rs, crates/perry-runtime/src/gc/trace/block_skip.rs, crates/perry-runtime/src/gc/dead_owner.rs, crates/perry-runtime/src/json_tape_store.rs, crates/perry-runtime/src/hot_diag.rs, scripts/gc_runtime_root_holders.json, scripts/shape_descriptor_census.py
RegExp uses the shared ExoticExpandoOwner move hook and has no finalize hook. Related dead-owner cleanup documentation and GC metadata checks are updated.
Collection paths and regression tests
crates/perry-runtime/src/gc/copying_phase.rs, crates/perry-runtime/src/gc/oldgen.rs, crates/perry-runtime/src/gc/tests/copying/survival_and_malloc.rs, crates/perry-runtime/src/gc/tests/dead_owner_side_tables.rs, crates/perry-runtime/src/gc/tests/dead_owner_side_tables/regexp_expandos.rs, changelog.d/11518-delete-regex-source-table.md
Copying-minor and incremental-sweep paths no longer collect or finalize registered RegExps. Tests cover relocation and dead or live RegExp expando state. The changelog records the registry removal and related GC changes.

GC owner-header prefetch removal

Layer / File(s) Summary
Remove owner-header prefetch helper
crates/perry-runtime/src/gc/prefetch.rs
Removes the helper that prefetched GC owner headers on AArch64 and x86_64.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Refactor

Possibly related PRs

  • PerryTS/perry#9845: Introduced the nursery RegExp allocation and registry-based movement and finalization paths that this change removes.

Suggested labels: run-extended-tests

Merge Risk: ⚪ Minimal · up to b471f

No merge-blocking issue was established; the change is mergeable after normal checks.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to b471f

The change affects how the runtime recognizes and cleans up RegExp objects across garbage collections. The inspected paths support the replacement design, and no new security failure was established, but incomplete lifecycle coverage leaves some uncertainty in a memory-sensitive component.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — A broken identity or cleanup invariant could affect RegExp receivers and address-keyed expando state across collection modes within the runtime; the inspected change does not establish a new service or tenant boundary.

Trust Boundaries and Controls

  • inferred — Header recognition alone does not demonstrate rejection of a dead-but-not-yet-reused receiver: the inspected header reader checks plausibility and alignment, not GC liveness. The prior header-first identity path limits evidence that this PR newly creates that condition.

Resilience and Maintainability Implications

  • observed — Lifecycle tests cover relocated live RegExp expando ownership and dead-owner pruning, but their presence does not establish that every collection and interruption path was executed in this review.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The implementation satisfies the main [#11503] changes. It removes REGEX_SOURCE_TABLE, uses GC-header identity, routes RegExp moves through ExoticExpandoOwner, removes RegExp-specific cleanup hook… Run the required regex gap tests and runtime regex tests with default settings and with PERRY_GC_FORCE_EVACUATE=1 PERRY_GC_VERIFY_EVACUATION=1, and record that a copying minor ran. Confirm and remove any remaining RegExp entry in `scripts…
Docstring Coverage ⚠️ Warning Docstring coverage is 77.42% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 31 functions across 15 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changed GC diagnostics, dead-owner documentation, sweep logic, prefetch removal, tests, inventory update, census update, and changelog all support removal of the RegExp registry and its hooks in […
Title check ✅ Passed The title clearly and concisely identifies the two main changes: deleting REGEX_SOURCE_TABLE and identifying RegExps by their GC header.
Description check ✅ Passed The description follows the repository template and covers the summary, concrete changes, related issue, detailed test plan, test results, known unrun checks, screenshots status, and checklist. It cle…
Full details: Linked Issues check

Explanation

The implementation satisfies the main [#11503] changes. It removes REGEX_SOURCE_TABLE, uses GC-header identity, routes RegExp moves through ExoticExpandoOwner, removes RegExp-specific cleanup hooks, updates the shape census, and adds identity, migration, and dead-expando tests. The PR evidence states that regex gap tests were not run and that gap tests with PERRY_GC_FORCE_EVACUATE=1 PERRY_GC_VERIFY_EVACUATION=1 remain unverified. The evidence also shows no change to scripts/gc_rekeyed_key_tables.json; deletion of any required stale RegExp entry there is not demonstrated.

Resolution

Run the required regex gap tests and runtime regex tests with default settings and with PERRY_GC_FORCE_EVACUATE=1 PERRY_GC_VERIFY_EVACUATION=1, and record that a copying minor ran. Confirm and remove any remaining RegExp entry in scripts/gc_rekeyed_key_tables.json or related DEAD_KEY_PRUNES inventory.

Full details: Docstring Coverage

Explanation

Docstring coverage is 77.42% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 31 functions across 15 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR

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 force-pushed the claude/eloquent-rubin-2arn2p branch from b471ff8 to 440ccf0 Compare September 27, 2026 12:34
@proggeramlug
proggeramlug merged commit b105e8a into main Sep 27, 2026
19 of 20 checks passed
@proggeramlug
proggeramlug deleted the claude/eloquent-rubin-2arn2p branch September 27, 2026 12:34
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.

perf(runtime): delete REGEX_SOURCE_TABLE (its only payload is a bool); identify RegExps by obj_type

2 participants