Skip to content

perf(codegen): speed up generic registry pipelines - #8614

Merged
proggeramlug merged 1 commit into
PerryTS:mainfrom
proggeramlug:fix/8607-pipeline
Aug 22, 2026
Merged

perf(codegen): speed up generic registry pipelines#8614
proggeramlug merged 1 commit into
PerryTS:mainfrom
proggeramlug:fix/8607-pipeline

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Speeds up the pipeline benchmark by keeping stable array-valued fields in local slots for methods called on proven-contained receivers, and by adding a guarded numeric fast path for null-defaulted dynamic counters. Dynamic JavaScript behavior and aliased receiver routes retain their existing fallbacks.

Changes

  • Emit a separate internal $ptr_arrays method clone for eligible loop methods on Phase 3b contained receivers.
  • Snapshot only array fields initialized by array literals, and decline the clone for slot replacement, deletion, or reentrant this/super method calls.
  • Keep aliased, guarded, and dispatch-tower calls on the existing public/$pshape paths.
  • Recognize the (value === null ? 0 : value) + numeric-literal shape and use an inline numeric add after a runtime tag check, with full dynamic add as the fallback.
  • Add IR routing/safety tests and an end-to-end parity regression.

Related issue

Closes #8607

Test plan

  • cargo build --release -p perry
  • cargo test -p perry-codegen --lib --quiet (1,163 passed; 1 ignored)
  • PERRY_SKIP_BUILD=1 ./run_parity_tests.sh --filter test_issue_8607 (1/1 passed, byte-exact against Node)
  • python3 scripts/check_test_registration.py
  • cargo fmt --all -- --check
  • ./scripts/pre-tag-check.sh --quick
  • Full workspace test command from the template. The affected-crate runner completed all 2,634 runtime tests (4 ignored), then stopped in an unchanged perry binary audit because current main does not classify the PERRY_OUTLINE_ENTRY environment variables in the build-cache allow/exclusion lists.

The private m0810 20-row acceptance corpus referenced by repository notes is not present in this checkout; the public pipeline workload and the added parity fixture are byte-exact.

Benchmark

Apple M1 mini, quiet host. Wall spread is 20 shuffled/interleaved five-process batches, normalized per process; batching avoids the 10 ms resolution of macOS /usr/bin/time. Counters are 20 shuffled/interleaved single-process runs. Baseline is 970eab3; final is this branch.

runtime wall median wall range instructions median cycles median peak RSS
baseline 114.101 ms 113.263-115.746 ms 2,131,456,485 348,841,468 22,282,240 B
final 92.976 ms 92.229-95.320 ms 1,784,508,872 283,436,554 22,282,240 B
Node 101.476 ms 99.407-104.134 ms 1,231,885,256 355,256,028 90,112,000 B

Final versus baseline: 18.5% lower wall time with disjoint ranges, 16.3% fewer instructions, 18.7% fewer cycles, and unchanged peak RSS. Final is 8.4% faster than Node by median wall time on this host.

Screenshots / output

pipeline output from both Perry and Node:

55626000 3 3

Checklist

  • I have NOT bumped the workspace version or edited CLAUDE.md / CHANGELOG.md
  • My commit follows the repository commit-prefix convention
  • I have read CONTRIBUTING.md and agree to the Code of Conduct

Summary by CodeRabbit

  • Performance Improvements

    • Improved performance for methods that repeatedly access cached array fields on contained receivers.
    • Added optimized numeric addition for null-defaulted counters while preserving dynamic string-or-number behavior.
  • Bug Fixes

    • Preserved correct behavior for aliased receivers, non-numeric fallback values, and property rebinding scenarios.
  • Tests

    • Added coverage for cached array-field routing and null-defaulted numeric addition, including missing, repeated, and string-valued entries.

@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36df0289-454c-45e8-bb0c-e21581c0b573

📥 Commits

Reviewing files that changed from the base of the PR and between 5f2c6c6 and 68c8eb4.

📒 Files selected for processing (11)
  • changelog.d/8607-pipeline-null-default-add.md
  • crates/perry-codegen/src/codegen/artifacts.rs
  • crates/perry-codegen/src/codegen/method.rs
  • crates/perry-codegen/src/collectors/mod.rs
  • crates/perry-codegen/src/collectors/proven_this.rs
  • crates/perry-codegen/src/collectors/proven_this_routing_tests.rs
  • crates/perry-codegen/src/expr/binary.rs
  • crates/perry-codegen/src/expr/mod.rs
  • crates/perry-codegen/src/expr/null_default_numeric_add_tests.rs
  • crates/perry-codegen/src/lower_call/property_get/dynamic_dispatch.rs
  • test-files/test_issue_8607_null_default_numeric_add.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The change adds guarded numeric lowering for null-defaulted additions and array-field caching for eligible contained receivers. It updates clone compilation and dispatch routing, and adds IR, routing, runtime, and changelog coverage.

Changes

Pipeline optimizations

Layer / File(s) Summary
Guarded numeric addition
crates/perry-codegen/src/expr/binary.rs, crates/perry-codegen/src/expr/mod.rs, crates/perry-codegen/src/expr/null_default_numeric_add_tests.rs, test-files/test_issue_8607_null_default_numeric_add.ts
Null-defaulted locals can use guarded numeric addition. Non-numeric and string cases retain dynamic dispatch. Tests cover IR and runtime behavior.
Array-field cache analysis
crates/perry-codegen/src/collectors/proven_this.rs, crates/perry-codegen/src/collectors/mod.rs
Eligible looping methods snapshot stable array fields and rewrite later reads. Mutations, deletes, computed writes, super operations, internal calls, and nested closures prevent or limit caching.
Array-cache clone compilation
crates/perry-codegen/src/codegen/artifacts.rs, crates/perry-codegen/src/codegen/method.rs
Code generation emits pointer-array-cache clones with dedicated symbols and propagates the clone flag through lowering calls.
Dispatch routing and regression coverage
crates/perry-codegen/src/lower_call/property_get/dynamic_dispatch.rs, crates/perry-codegen/src/collectors/proven_this_routing_tests.rs, changelog.d/8607-pipeline-null-default-add.md
Proven receivers prefer array-cache clones. Aliased receivers continue to use exact-shape routing. Tests cover contained receivers and rejected field rebinding cases.

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

Merge Risk: ⚪ Minimal · up to 68c8e

The change is merge-ready after normal checks and review; no actionable merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant DynamicDispatch
  participant ArrayCacheClone
  participant PShapeClone
  Caller->>DynamicDispatch: invoke instance method
  DynamicDispatch->>ArrayCacheClone: select cached clone for proven receiver
  DynamicDispatch->>PShapeClone: select shape clone for aliased receiver
Loading
sequenceDiagram
  participant ExpressionLowering
  participant NumericGuard
  participant DynamicAddition
  ExpressionLowering->>NumericGuard: detect null-defaulted value plus literal
  NumericGuard->>DynamicAddition: retain fallback for non-numeric values
  DynamicAddition-->>ExpressionLowering: emit guarded numeric control flow
Loading

Suggested reviewers: thehypnoo, jdalton

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 34 functions across 10 files. (1 skipped: 1 unsupported.) Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the code generation performance improvement for generic registry pipelines.
Description check ✅ Passed The description covers the required summary, changes, issue, tests, benchmark results, output, and checklist, with a justified full-suite exception.
Linked Issues check ✅ Passed The changes address issue #8607 by optimizing pipeline code generation, preserving dynamic behavior, adding tests, and reporting improved wall time with unchanged RSS.
Out of Scope Changes check ✅ Passed The code, tests, parity fixture, and changelog entry are related to the pipeline performance objectives in issue #8607.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown
Contributor Author

Merging as a validated batch of three, stacked on current main.

check result
cargo check --workspace --all-targets exit 0
perry-codegen --lib 1167 passed, 1 ignored
perry-runtime --lib (RUST_TEST_THREADS=1) 2634 passed, 4 ignored
all seven ratchets 0
cargo fmt --all -- --check 0

Ratchets re-run against the current baseline immediately before merge.

#8610's ratchet debt is resolved. It was held twice for +2 bare raw-handle reads in class_registry/construct.rs (7 against a ceiling of 5) and +1 open-coded StringHeader payload offset. On head c9b994d0f both gates now report clean — 925/925 raw-handle reads, 108 modules within ceilings, payload inventory exit 0. Converted rather than baseline-refreshed, which was the right call given the counts had gone up. Thanks for taking that rather than reaching for --write-baseline; construct.rs runs during instance construction, so a raw handle held across an allocating call there is exactly the shape that yields a stale pointer surfacing cycles later somewhere unrelated.

#8613 and #8614 are aimed at the two tickets filed after the last sweep#8606 (typed_array round 2, where the wall ratio now exceeds the instruction ratio) and #8607 (pipeline, still 1.74x instructions at ~1.05x cycles). Worth being explicit about what this validation does and does not establish: the gates and suites say these are safe to land, not that they are faster. Both are perf changes, and the corpus sweep after merging is the actual verdict. I will run it and report against those tickets.

Two metadata fixes applied while staging (fork PRs, so they could not be pushed to the branches): #8610 shipped without a changelog.d fragment, so I wrote one; #8614's was keyed 8607- after its issue and is now PR-keyed.

@proggeramlug
proggeramlug merged commit c7645d1 into PerryTS:main Aug 22, 2026
45 of 48 checks passed
@proggeramlug
proggeramlug deleted the fix/8607-pipeline branch August 22, 2026 17:17
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.

Opt target — pipeline: 1.12x Node, **1.74x instructions at ~1.05x cycles**

1 participant