Skip to content

perf(codegen): const-len Uint8Array inline + skip unused scalar literal inits (salvage andrewtdiz #5341/#5367)#5401

Merged
proggeramlug merged 4 commits into
mainfrom
restack-independent
Jun 18, 2026
Merged

perf(codegen): const-len Uint8Array inline + skip unused scalar literal inits (salvage andrewtdiz #5341/#5367)#5401
proggeramlug merged 4 commits into
mainfrom
restack-independent

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Salvages the two cleanly-rebasable commits from andrewtdiz's perf-optimization stack (originally #5341 and #5367) onto current main, with original authorship preserved:

Why just these two

The original 41-PR stack (#5302#5380) went stale during review: #5291 (representation-aware type lowering) and the #5334 codegen levers merged to main and implement overlapping work. The stack's numeric-array base (#5302) is now superseded by #5291, and main has advanced ~25 commits into the same files.

Attempting to rebase/cherry-pick the stack showed the commits are a tightly-coupled series that does not extract cleanly:

These two commits are the only ones that rebased onto current main and pass the full perry-codegen + perry-runtime test suites locally. The rest needs an integrated rebase by the original author against current main.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Performance Improvements
    • Optimized non-escaping array scalar replacement by evaluating only elements that are actually read.
    • Optimized non-escaping object literal scalar replacement by evaluating only fields that are actually accessed/updated.
    • Improved typed-array codegen when buffer lengths come from known constants/locals, enabling more inline byte-level operations and fewer runtime helper calls.
  • Tests
    • Added/expanded coverage for non-escaping array/object field/element usage and constant/local-derived Uint8Array length scenarios.

@coderabbitai

coderabbitai Bot commented Jun 18, 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: da986251-72af-48c6-ac09-e99b0e3ab8f3

📥 Commits

Reviewing files that changed from the base of the PR and between 25194e1 and 6cf4408.

📒 Files selected for processing (1)
  • crates/perry-codegen/src/codegen/method.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/perry-codegen/src/codegen/method.rs

📝 Walkthrough

Walkthrough

Adds two new HIR-level escape analysis collectors that track which array indices and object-literal fields are actually read for non-escaping locals. These facts flow through EscapeFacts/TypeFacts into FnCtx and scalar-replacement lowering, enabling elision of pure unobserved initializers. Separately, noalias Uint8Array detection is refactored to propagate a flow-sensitive known_length_locals set across control flow, allowing constant-local-derived lengths to qualify.

Changes

Escape Analysis Precision and Scalar Replacement Elision

Layer / File(s) Summary
EscapeFacts data shapes, new collectors, and TypeFacts wiring
crates/perry-codegen/src/collectors/hir_facts.rs, crates/perry-codegen/src/collectors/escape_arrays.rs, crates/perry-codegen/src/collectors/escape_objects.rs
EscapeFacts gains non_escaping_array_used_indices and non_escaping_object_literal_used_fields maps; TypeFacts adds accessors; collect_type_facts wires in two new collector functions that walk HIR to gather constant IndexGet reads and PropertyGet/PropertyUpdate field names for non-escaping candidates.
Flow-sensitive noalias Uint8Array length tracking
crates/perry-codegen/src/collectors/hir_facts.rs, crates/perry-codegen/tests/native_proof_buffer_views.rs
collect_known_noalias_buffer_locals introduces a known_length_locals set propagated across all control-flow constructs; is_owned_u8_buffer_alloc and new is_fresh_uint8array_length_expr validate Uint8Array size using that set; unit and integration tests cover constant-local-derived lengths as noalias sources.
FnCtx fields and codegen wiring
crates/perry-codegen/src/expr/mod.rs, crates/perry-codegen/src/codegen/closure.rs, crates/perry-codegen/src/codegen/entry.rs, crates/perry-codegen/src/codegen/function.rs, crates/perry-codegen/src/codegen/method.rs
FnCtx gains two new tracking-map fields; all five codegen entry points (closure, entry entry/init, function, method, static method) clone the new maps from native_facts into the constructed context.
Scalar replacement lowering and pure-expression elision
crates/perry-codegen/src/stmt/let_stmt.rs, crates/perry-codegen/tests/typed_shape_descriptors.rs
lower_let consults the new context maps to skip unobserved array element and object-literal field initializers via lower_unused_expr; lower_unused_expr gains an early-return for expressions proven pure and non-throwing by new helpers; tests validate that pure unobserved initializers are elided while observable or read-required ones are retained.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 A rabbit hops through escaping arrays,
Counting which indices earn their keep.
Pure fields unobserved? We skip their phase,
And noalias buffers sleep more deep.
known_length_locals blooms in flow,
Less allocation, faster go! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main changes: inlining Uint8Array access for const-length arrays and skipping unused scalar literal initializations, with performance context.
Description check ✅ Passed The description fully covers required sections: explains what is being salvaged, why (context of stale stack and conflicts), which commits are included, and why others are excluded. It provides clear rationale and scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 restack-independent

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/perry-codegen/tests/native_proof_buffer_views.rs`:
- Around line 1623-1629: The assertions checking for `@js_uint8array_set` and
`@js_uint8array_get` helper calls are matching full call signatures including
return types (call void and call i32), which makes them fragile if those
signatures change. Instead of matching the complete call signatures, update both
assertion string patterns to match only the helper symbol names themselves.
Replace the full patterns like "call void `@js_uint8array_set`" and "call i32
`@js_uint8array_get`" with just the symbol names "`@js_uint8array_set`" and
"`@js_uint8array_get`" so the assertions remain robust to future signature
changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cf66badf-1fa1-467d-816a-ceb36616e0fb

📥 Commits

Reviewing files that changed from the base of the PR and between 54ebb6c and 25194e1.

📒 Files selected for processing (11)
  • crates/perry-codegen/src/codegen/closure.rs
  • crates/perry-codegen/src/codegen/entry.rs
  • crates/perry-codegen/src/codegen/function.rs
  • crates/perry-codegen/src/codegen/method.rs
  • crates/perry-codegen/src/collectors/escape_arrays.rs
  • crates/perry-codegen/src/collectors/escape_objects.rs
  • crates/perry-codegen/src/collectors/hir_facts.rs
  • crates/perry-codegen/src/expr/mod.rs
  • crates/perry-codegen/src/stmt/let_stmt.rs
  • crates/perry-codegen/tests/native_proof_buffer_views.rs
  • crates/perry-codegen/tests/typed_shape_descriptors.rs

Comment on lines +1623 to +1629
assert!(
!ir.contains("call void @js_uint8array_set"),
"inline Uint8Array set should not call the runtime helper:\n{ir}"
);
assert!(
!ir.contains("call i32 @js_uint8array_get"),
"inline Uint8Array get should not call the runtime helper:\n{ir}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Harden helper-call assertions against signature drift.

Line 1624 and Line 1628 assert full call signatures; if runtime helper signatures change, fallback helper calls could slip through undetected. Match the helper symbol names instead.

Suggested patch
     assert!(
-        !ir.contains("call void `@js_uint8array_set`"),
+        !ir.contains("`@js_uint8array_set`("),
         "inline Uint8Array set should not call the runtime helper:\n{ir}"
     );
     assert!(
-        !ir.contains("call i32 `@js_uint8array_get`"),
+        !ir.contains("`@js_uint8array_get`("),
         "inline Uint8Array get should not call the runtime helper:\n{ir}"
     );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert!(
!ir.contains("call void @js_uint8array_set"),
"inline Uint8Array set should not call the runtime helper:\n{ir}"
);
assert!(
!ir.contains("call i32 @js_uint8array_get"),
"inline Uint8Array get should not call the runtime helper:\n{ir}"
assert!(
!ir.contains("`@js_uint8array_set`("),
"inline Uint8Array set should not call the runtime helper:\n{ir}"
);
assert!(
!ir.contains("`@js_uint8array_get`("),
"inline Uint8Array get should not call the runtime helper:\n{ir}"
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/perry-codegen/tests/native_proof_buffer_views.rs` around lines 1623 -
1629, The assertions checking for `@js_uint8array_set` and `@js_uint8array_get`
helper calls are matching full call signatures including return types (call void
and call i32), which makes them fragile if those signatures change. Instead of
matching the complete call signatures, update both assertion string patterns to
match only the helper symbol names themselves. Replace the full patterns like
"call void `@js_uint8array_set`" and "call i32 `@js_uint8array_get`" with just the
symbol names "`@js_uint8array_set`" and "`@js_uint8array_get`" so the assertions
remain robust to future signature changes.

@proggeramlug proggeramlug merged commit eaadc74 into main Jun 18, 2026
15 checks passed
@proggeramlug proggeramlug deleted the restack-independent branch June 18, 2026 18:55
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.

2 participants