Skip to content

perf: remove local copy and scalar root-store overhead - #10264

Closed
proggeramlug wants to merge 2 commits into
PerryTS:mainfrom
proggeramlug:perf/generic-function-overhead-20260914
Closed

proggeramlug wants to merge 2 commits into
PerryTS:mainfrom
proggeramlug:perf/generic-function-overhead-20260914

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Plain local copies currently turn into string-sharing and root-shading work that survives LLVM optimization. Remove provably redundant bindings before codegen, and omit incremental root shading when a global/static-field store is proven to contain a scalar.

Against 4945fc1f7498debc76e9f861d7cf1517da5e67c9, the exported three-alias probe drops from 43 to 3 ARM64 instructions, an alias live across a call from 70 to 54, and a constant global write from 11 to 6 under the default -Os policy. These are static instruction counts, including cold blocks and excluding callees; they are not throughput claims.

Changes

  • Add a conservative HIR cleanup after the shape-specific passes. Forward initialized, unwritten local copies and remove unread inert stores in straight-line synchronous functions. Preserve effectful assignments; reject captures, control flow, TDZ preallocation, defaults, arguments objects, and unsupported expressions.
  • Reuse the existing construction-based scalar proof for registered global and static-field stores. The store remains; unknown values, heap values, and declared-only numeric parameters retain root shading.
  • Add transform and codegen fallback tests, a Node-parity/GC regression fixture, and a reproducible ARM64 instruction census with -Os/-O3 results in benchmarks/generic-overhead/README.md.

Callback dispatch is an unchanged control. A separate trial reduced caller instructions but regressed ordinary-callback CPU time by 54%, so it is excluded. Broader callback/runtime, closure, arguments, and leaf-root optimizations remain follow-up work.

Related issue

n/a

Test plan

Built the compiler and matching runtime/stdlib static archives from this worktree with LLVM 22.1.4 on Apple M1 Max. Cargo commands used a dedicated target directory and CARGO_PROFILE_RELEASE_CODEGEN_UNITS=16.

  • cargo build --release -p perry -p perry-runtime-static -p perry-stdlib-static
  • cargo test --release -p perry-codegen --lib: 1,535 passed, 1 ignored
  • cargo test --release -p perry-transform --lib: 137 passed
  • Pinned Node 26.5.1 parity for test_gap_generic_function_overhead.ts, including the canonical parity harness.
  • All six existing static_field parity fixtures pass.
  • Fixture in native and shadow-root modes, normally and with seeded moving-GC stress, protected from-space, and evacuation verification. Each stress run executed 1,411 copying minors and moved 91,275 objects; output matched Node exactly.
  • Shadow LLVM IR: moving-root dominance and unrooted-alloca checks, zero violations across 180 root stores and 162 GC-capable allocas.
  • ARM64 census at -Os and -O3; unknown-value store and callback control counts unchanged.
  • Added tests under test-files/ and both affected crates.
  • Full affected-crate, gap, and documentation suites were not run locally; broader coverage is left to CI.

scripts/pre-tag-check.sh --quick has one pre-existing failure: the published benchmark artifact is stale relative to its inputs. The same check fails on the pristine baseline with identical source and harness fingerprints. This PR does not change those benchmark inputs or regenerate the published artifact.

Checklist

  • No workspace version bump or edits to CLAUDE.md / CHANGELOG.md.
  • Conventional commit prefix.
  • Read CONTRIBUTING.md and Code of Conduct.
  • Added changelog.d/10264-generic-function-overhead.md.

Summary by CodeRabbit

  • Performance

    • Reduced unnecessary overhead in eligible synchronous functions by eliminating redundant local copies and unused assignments.
    • Improved global and static-field stores for values known to be non-reference types, while retaining required memory-safety barriers for other values.
  • Reliability

    • Preserved expected behavior across closures, callbacks, exceptions, temporal dead zones, proxies, and garbage-collection stress scenarios.
    • Added coverage for generic functions, callbacks, assignments, and scalar value handling.
  • Documentation

    • Added benchmark guidance and instruction-count comparisons for measuring generic-function overhead.

@coderabbitai

coderabbitai Bot commented Sep 14, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: a08cc4b6-d6ac-413e-8088-a87717194f32

📥 Commits

Reviewing files that changed from the base of the PR and between 22311fd and 25ded99.

📒 Files selected for processing (15)
  • benchmarks/generic-overhead/README.md
  • benchmarks/generic-overhead/census.py
  • benchmarks/generic-overhead/probes.ts
  • changelog.d/10264-generic-function-overhead.md
  • crates/perry-codegen/src/codegen/static_fields.rs
  • crates/perry-codegen/src/expr/generic_overhead_tests.rs
  • crates/perry-codegen/src/expr/literals_vars.rs
  • crates/perry-codegen/src/expr/mod.rs
  • crates/perry-codegen/src/expr/static_field_meta.rs
  • crates/perry-codegen/src/expr/write_barrier.rs
  • crates/perry-codegen/src/stmt/let_stmt.rs
  • crates/perry-transform/src/lib.rs
  • crates/perry-transform/src/local_copies.rs
  • crates/perry-transform/src/local_copies_tests.rs
  • test-files/test_gap_generic_function_overhead.ts

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


📝 Walkthrough

Walkthrough

Changes

Generic function overhead optimization

Layer / File(s) Summary
Local-copy cleanup pass
crates/perry-transform/src/*
Adds a post-inline pass that rewrites eligible aliases and removes unused inert assignments. It excludes captures, control flow, TDZ-sensitive cases, async and generator functions, and unsupported expressions. Unit tests cover these boundaries.
Expression-aware root stores
crates/perry-codegen/src/expr/*, crates/perry-codegen/src/stmt/let_stmt.rs, crates/perry-codegen/src/codegen/static_fields.rs
Adds expression-based root-store selection. Known non-pointer shadow values use plain stores. Other values retain root barriers.
Codegen and runtime validation
crates/perry-codegen/src/expr/generic_overhead_tests.rs, test-files/test_gap_generic_function_overhead.ts
Adds IR checks for scalar and non-scalar stores. Adds runtime checks for aliases, TDZ behavior, callbacks, closures, argument mapping, and value preservation.
Instruction census and release documentation
benchmarks/generic-overhead/*, changelog.d/10264-generic-function-overhead.md
Adds ARM64 probe compilation and instruction counting. Documents measured results, optimization boundaries, test coverage, and the changelog entry.

Priority: ➖ Normal

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

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant TypeScript
  participant perry_transform
  participant perry_codegen
  participant ARM64_Census
  TypeScript->>perry_transform: compile functions with local copies
  perry_transform->>perry_transform: remove eligible aliases and inert assignments
  perry_transform->>perry_codegen: pass cleaned function body
  perry_codegen->>perry_codegen: select scalar store or root-barrier store
  perry_codegen->>ARM64_Census: emit ARM64 object code
  ARM64_Census->>ARM64_Census: count probe instructions and write JSON
Loading

Merge Risk: ⚪ Minimal · up to 25ded

No concrete correctness, GC-safety, or availability defect remains established for this change.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 60 functions across 13 files. (2 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly and concisely describes the two main performance changes: removing local-copy overhead and reducing scalar root-store overhead.
Description check ✅ Passed The description includes all required sections, explains the changes and scope, identifies the related issue as n/a, and provides detailed test results and limitations. Optional screenshots are not ne…
Full details: Docstring Coverage

Explanation

Docstring coverage is 28.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 60 functions across 13 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 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

Landed via merge train #10276 (v0.5.1570). Source changes preserve authorship, and the merged main tree matches the validated train exactly.

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