Skip to content

perf(codegen): inline masked string array lengths - #9171

Merged
proggeramlug merged 2 commits into
PerryTS:mainfrom
proggeramlug:fix/9160-inline-string-array-length
Aug 30, 2026
Merged

perf(codegen): inline masked string array lengths#9171
proggeramlug merged 2 commits into
PerryTS:mainfrom
proggeramlug:fix/9160-inline-string-array-length

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • version masked string[] length-accumulation loops behind a one-time plain-array, bounds, element-tag, and accumulator guard
  • lower covered array reads to raw boxed-slot loads and proven string lengths to SSO/heap-only inline dispatch
  • preserve the generic loop for erased annotation lies, descriptors, prototype pollution, holes, and non-number accumulators

Performance

On perrymaster.skelpo.net, the issue-shaped strings[i & 3].length benchmark improves from 5.58 ns/access to 1.14 ns/access (4.9x faster). Node measures 0.63 ns/access on the same host, reducing the gap from about 8.9x to 1.8x.

Testing

  • cargo test -p perry-codegen --test string_array_length_9160
  • cargo test -p perry-runtime typed_feedback --lib
  • parity: test_gap_string_array_masked_length_9160
  • scripts/local_binding_type_audit.py
  • scripts/check_test_registration.py
  • scripts/check_file_size.sh
  • cargo fmt --all -- --check

Fixes #9160

Summary by CodeRabbit

  • Performance

    • Improved performance for masked indexed access to string-array elements.
    • Accelerated loops that accumulate string lengths, with benchmark results showing up to 4.9× faster access.
  • Bug Fixes

    • Preserved correct behavior for empty, multibyte, and invalid string elements through safe fallback handling.
    • Improved support for repeated indexed string-array access and mixed accumulator values.
  • Tests

    • Added coverage for optimized string-array length calculations and runtime edge cases.

@coderabbitai

coderabbitai Bot commented Aug 30, 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: f2fc7f08-ea5e-41b1-8824-18a4ee98aa09

📥 Commits

Reviewing files that changed from the base of the PR and between 3411c9d and f16242a.

📒 Files selected for processing (20)
  • changelog.d/9171-string-array-length.md
  • 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/expr/index_get.rs
  • crates/perry-codegen/src/expr/mod.rs
  • crates/perry-codegen/src/expr/property_get.rs
  • crates/perry-codegen/src/expr/string_length.rs
  • crates/perry-codegen/src/expr/string_window.rs
  • crates/perry-codegen/src/runtime_decls/objects.rs
  • crates/perry-codegen/src/stmt/loops.rs
  • crates/perry-codegen/src/stmt/mod.rs
  • crates/perry-codegen/src/stmt/string_length_loop.rs
  • crates/perry-codegen/src/type_analysis/numeric.rs
  • crates/perry-codegen/src/type_analysis/strings.rs
  • crates/perry-codegen/tests/string_array_length_9160.rs
  • crates/perry-runtime/src/typed_feedback.rs
  • crates/perry-runtime/src/typed_feedback/tests.rs
  • test-files/test_gap_string_array_masked_length_9160.ts

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


📝 Walkthrough

Walkthrough

This change adds guarded fast-path lowering for masked string[] length-accumulation loops. It validates the array window once, loads boxed string slots directly, extracts SSO or heap-string lengths inline, and preserves generic fallback behavior for invalid cases.

Changes

String array length optimization

Layer / File(s) Summary
String facts and inline length lowering
crates/perry-codegen/src/expr/*, crates/perry-codegen/src/codegen/*
Adds scoped string-window facts, initializes them in all FnCtx constructors, and centralizes inline SSO and heap-string length lowering.
Guarded string length loop
crates/perry-codegen/src/stmt/*, crates/perry-codegen/src/runtime_decls/objects.rs, crates/perry-runtime/src/typed_feedback.rs
Recognizes eligible loops, calls js_string_array_range_loop_guard, and emits fast and generic fallback loop paths.
String-window read integration
crates/perry-codegen/src/expr/index_get.rs, crates/perry-codegen/src/expr/string_window.rs, crates/perry-codegen/src/type_analysis/*
Loads covered array slots directly and uses active facts to prove string elements and numeric accumulators.
Codegen and runtime regression coverage
crates/perry-codegen/tests/string_array_length_9160.rs, crates/perry-runtime/src/typed_feedback/tests.rs, test-files/test_gap_string_array_masked_length_9160.ts, changelog.d/9171-string-array-length.md
Checks optimized IR, keepalive registration, runtime-invalid elements, dynamic accumulator behavior, and the reported benchmark result.

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

Merge Risk: ⚪ Minimal · up to f1624

The PR adds a guarded fast path for masked string-array length reads while retaining the generic implementation when validation fails. No actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant LoopLowering
  participant RuntimeGuard
  participant StringWindow
  participant StringLength
  LoopLowering->>RuntimeGuard: Validate array and index window
  RuntimeGuard-->>LoopLowering: Return eligibility
  LoopLowering->>StringWindow: Register validated window fact
  StringWindow->>StringLength: Load boxed string and classify length
  StringLength-->>LoopLowering: Emit inline SSO or heap length
  LoopLowering-->>LoopLowering: Merge fast path with generic fallback
Loading

Possibly related PRs

  • PerryTS/perry#6750: Extends the masked-window loop-versioning and IndexGet lowering infrastructure used by this specialization.

Suggested reviewers: thehypnoo

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 56.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 30 functions across 19 files. (1 skipped:… 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 and concisely describes the primary change: inlining masked string-array length access in code generation.
Description check ✅ Passed The description covers the optimization, performance impact, linked issue, testing performed, and fallback behavior. It does not reproduce every template heading or checklist item, but the required te…
Linked Issues check ✅ Passed The implementation satisfies issue #9160 by adding guarded string-array loop specialization, inline SSO and heap-string length extraction, and generic fallback behavior for invalid or dynamic cases.
Out of Scope Changes check ✅ Passed The changes remain within scope for issue #9160. The added codegen paths, runtime guard, regression tests, audits, and changelog entry directly support the optimization and its validation.
Full details: Description check

Explanation

The description covers the optimization, performance impact, linked issue, testing performed, and fallback behavior. It does not reproduce every template heading or checklist item, but the required technical information is present.

Full details: Docstring Coverage

Explanation

Docstring coverage is 56.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 30 functions across 19 files. (1 skipped: 1 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
proggeramlug force-pushed the fix/9160-inline-string-array-length branch from f16242a to 488b786 Compare August 30, 2026 13:46
@proggeramlug

Copy link
Copy Markdown
Contributor Author

Merged via a merge train — cherry-picked with three other PRs onto one branch and validated together in a single build. Combined validation: codegen 1357 passed, runtime 2844 passed (exit 0, 0 abort markers), perry --bins 1066, fmt clean, check_file_size.sh PASS, run_lint_gates.sh all 60 gates passed, git diff origin/main --diff-filter=D empty.

20 files, all covered by the combined codegen and runtime suites above.

@proggeramlug
proggeramlug merged commit a3b2e2d into PerryTS:main Aug 30, 2026
17 of 19 checks passed
proggeramlug added a commit that referenced this pull request Aug 30, 2026
* fix(transform): route labeled breaks through yielding switches (#9186)

* fix(ci): classify string array length suite (#9171)

* docs(changelog): record labeled switch fix (#9189)

* fix(hir): keep loop hoist off recursive stack (#9194)

---------

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.

String .length is a runtime call — 15.6x vs node; SSO length is already in the box

1 participant