Skip to content

perf(codegen): refresh rooted arrays, gate super-scope, and count store safepoints - #8680

Merged
proggeramlug merged 1 commit into
mainfrom
merge/b7
Aug 24, 2026
Merged

perf(codegen): refresh rooted arrays, gate super-scope, and count store safepoints#8680
proggeramlug merged 1 commit into
mainfrom
merge/b7

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Lands four reviewed PRs as one squash: #8670, #8673, #8668, #8678.

#8678 (#8583) is the notable one — it was the last blocker to a working cc binary. PropertySet/PropertyUpdate/IndexSet lower to collecting runtime calls that rewrite-statepoints-for-gc gives a statepoint, but count_safepoint_sites counted none of them. A closed-shape object literal compiles to a constructor that is one long run of this.field = v stores, so its estimate was ~0, it was never spilled to the shadow frame, and RS4GC grew one __AnonShape_*_constructor from 34,009 to 2,280,128 instructions — overrunning the #8586 per-function budget and refusing the whole module.

Reads (PropertyGet/IndexGet) are deliberately excluded: they frequently inline to a shape-cached load with no call, so counting them would over-spill read-heavy hot loops. That asymmetry is documented at the match arm.

Validation (on the merged 4-PR result, not per-branch)

Version bump stripped per maintainer policy; the Cargo.lock diff was confirmed version-only first. Four changelog.d/ fragments carried through.

Follow-up (not a blocker)

#8678 improves estimate accuracy; fully spilling that constructor also needs the spill threshold reconciled with the #8586 budget — #8623's 32M sits above the 1.57M budget. Tracked separately.

Summary by CodeRabbit

  • Performance

    • Numeric indexing on stable Array subclasses is now significantly faster while preserving correct behavior for holes, accessors, proxies, and prototype changes.
    • Array length and index reads use optimized paths where applicable.
  • Bug Fixes

    • Rooted-array iteration now remains accurate after storage relocation or length changes.
    • Safepoint reporting now includes collecting property and index stores.
  • Improvements

    • Size reports better identify and separate Rust standard-library internal dependencies from duplicate crates.

…re safepoints

Lands four reviewed PRs as one squash.

- #8670: refresh rooted arrays during iteration.
- #8673: fix a `--report-size` false positive from std-internal crate names.
- #8668: specialize dense Array-subclass indexing.
- #8678 (#8583): count property/index STORES as GC safepoint sites in the
  spill estimate. `PropertySet`/`PropertyUpdate`/`IndexSet` lower to
  collecting runtime calls that rewrite-statepoints-for-gc gives a
  statepoint, but none were counted, so a closed-shape object literal's
  constructor -- one long run of `this.field = v` -- estimated ~0, was
  never spilled to the shadow frame, and RS4GC grew one
  `__AnonShape_*_constructor` from 34,009 to 2,280,128 instructions,
  overrunning the #8586 per-function budget and refusing the whole
  module. Reads are deliberately not counted: they frequently inline to
  a shape-cached load with no call, so counting them would over-spill
  read-heavy hot loops.

Version bump stripped per maintainer policy; the Cargo.lock diff was
verified version-only before stripping.
@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 68a8c8b4-d2d8-472c-ae43-063c1d1d1ee2

📥 Commits

Reviewing files that changed from the base of the PR and between f5739b5 and 2b3248f.

📒 Files selected for processing (16)
  • changelog.d/8583-count-store-safepoints.md
  • changelog.d/8668-array-subclass-indexing.md
  • changelog.d/8670-refresh-rooted-arrays-iteration.md
  • changelog.d/8673-report-size-std-internal-filter.md
  • crates/perry-codegen/src/collectors/safepoint_sites.rs
  • crates/perry-codegen/src/expr/index_get/inline_dyn_typed_array.rs
  • crates/perry-codegen/src/runtime_decls/strings.rs
  • crates/perry-runtime/src/array/iter_methods.rs
  • crates/perry-runtime/src/array/mod.rs
  • crates/perry-runtime/src/array/subclass.rs
  • crates/perry-runtime/src/array/subclass_tests.rs
  • crates/perry-runtime/src/object/mod.rs
  • crates/perry-runtime/src/object/polymorphic_index.rs
  • crates/perry-runtime/src/value/dynamic_object.rs
  • crates/perry/src/commands/compile/size_report.rs
  • crates/perry/tests/issue_8655_array_subclass_indexing.rs

📝 Walkthrough

Walkthrough

The PR adds guarded dense indexing for Array subclasses, refreshes rooted array iteration after relocation, counts collecting store expressions as safepoints, and separates Rust standard-library internal backtrace crates in size reports. It adds runtime, compiler, integration, unit, and changelog coverage.

Changes

Array-subclass indexing

Layer / File(s) Summary
Array-subclass cache and runtime dispatch
crates/perry-runtime/src/array/subclass.rs, crates/perry-runtime/src/array/mod.rs, crates/perry-runtime/src/object/mod.rs
The runtime caches dense Array-subclass layouts by class and shape. It adds guarded length and index accessors, packed-arraylike dispatch, and required re-exports.
Codegen inline-cache integration
crates/perry-codegen/src/expr/index_get/inline_dyn_typed_array.rs, crates/perry-codegen/src/runtime_decls/strings.rs, crates/perry-runtime/src/object/polymorphic_index.rs, crates/perry-runtime/src/value/dynamic_object.rs
Code generation validates cached subclass facts and loads inline or spill slots. Runtime declarations and length/index paths use the packed-arraylike dispatcher before generic lookup.
Regression coverage and changelog
crates/perry-runtime/src/array/subclass_tests.rs, crates/perry/tests/issue_8655_array_subclass_indexing.rs, changelog.d/8668-array-subclass-indexing.md
Tests cover dense reads, shape changes, rejected object brands, holes, accessors, proxies, and element-kind changes. Integration tests verify generated calls and fallback behavior.

Rooted array iteration

Layer / File(s) Summary
Forwarded array refresh and validation
crates/perry-runtime/src/array/iter_methods.rs, changelog.d/8670-refresh-rooted-arrays-iteration.md
Iteration refreshes forwarded pointers and roots, checks live length, and tests relocation with growth and shrinkage.

Safepoint counting

Layer / File(s) Summary
Store safepoint classification
crates/perry-codegen/src/collectors/safepoint_sites.rs, changelog.d/8583-count-store-safepoints.md
Property, property-update, and index stores count as safepoints. Property and index reads remain excluded. Tests cover these classifications and nested calls.

Size-report filtering

Layer / File(s) Summary
Standard-library internal crate classification
crates/perry/src/commands/compile/size_report.rs, changelog.d/8673-report-size-std-internal-filter.md
The report classifies known internal backtrace crates with symbol markers, excludes them from duplicate findings, and emits their bytes, symbol counts, and names separately. Tests cover detection and veto cases.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GeneratedGetter
  participant ArraySubclassCache
  participant PackedArraylikeDispatcher
  participant GenericPropertyLookup

  GeneratedGetter->>ArraySubclassCache: validate class, shape, length, and dense slot
  ArraySubclassCache-->>GeneratedGetter: return inline or spill value
  GeneratedGetter->>PackedArraylikeDispatcher: dispatch cache miss
  PackedArraylikeDispatcher->>GenericPropertyLookup: resolve holes, accessors, proxies, or rejected shapes
  GenericPropertyLookup-->>PackedArraylikeDispatcher: return generic property result
Loading
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch merge/b7

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 added a commit that referenced this pull request Aug 24, 2026
Lands #8685. main was red on `lint` and `cargo-test` independently of any
in-flight PR: three checkers went stale after correct code landed.

- `shape_descriptor_census.py` still asserted the pre-#8665 fail-closed
  shape in the generic property-read PIC, and its callsite baseline was
  missing two legitimate `object_header_size_bytes(...)` sites that #8680
  added in `inline_dyn_typed_array.rs`.
- `addr_class_inventory.py`'s `lone-valid-obj-ptr` rule reimplemented a
  1-line lookahead instead of reusing the comment/blank-aware
  `band_predicate_near` helper the `handle-floor` rule already uses. That
  flagged two correctly-paired `is_valid_obj_ptr` + `try_read_gc_header`
  guards in `array/subclass.rs` as false positives.
- `codegen_env_vars_are_build_cache_inputs` failed on two unclassified
  env vars: `PERRY_CONST_ARRAY_DESCRIPTOR` (changes emitted IR, so a
  build-cache input) and `PERRY_DIALECT_DUMP` (read only on an already
  fatal dialect-construction failure, so excluded).

The addr-class ratchet baseline was regenerated from the merged tree
rather than hand-merged through its conflict. Every change is in the
strict direction: four entries removed outright and
`class_registry/construct.rs` 5 -> 3, nothing loosened. The rule still
detects real violations (`--self-test` passes).

Version bump stripped per maintainer policy; the changelog fragment was
renamed to its own PR number.

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
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