Skip to content

fix: harden dynamic imports and accelerate numeric/JSON fast paths#6810

Merged
proggeramlug merged 3 commits into
PerryTS:mainfrom
proggeramlug:fix/audit-dynamic-addr-perf
Jul 23, 2026
Merged

fix: harden dynamic imports and accelerate numeric/JSON fast paths#6810
proggeramlug merged 3 commits into
PerryTS:mainfrom
proggeramlug:fix/audit-dynamic-addr-perf

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Hardens runtime validation around AOT-specialized paths and removes several high-impact performance cliffs found during an audit of dynamic imports, address classification, numeric arrays, and JSON parsing.

The changes preserve ordinary JS lowering as the fallback whenever a runtime specialization cannot prove its preconditions.

Changes

  • Always compare the post-loader-hook runtime specifier for dynamic imports, including single-candidate AOT sites. Runtime mismatches now reject with ERR_MODULE_NOT_FOUND rather than silently loading the sole compiled candidate.
  • Route PIC keys, prototype metadata, and typed-feedback shape checks through validated GC-header/address classification and tighten the ratchet baseline.
  • Admit exact guarded numeric store loops after conservative pre-loop call hazards when the loop body itself cannot invalidate the runtime guard.
  • Add a transactional mixed-layout numeric-window helper for exact arr[i] = arr[i] + constant loops. It validates the complete window before mutation and falls back without partial effects for holes, non-numbers, frozen arrays, descriptors, or unsupported receivers.
  • Avoid redundant pointer normalization/header reads in packed numeric index guards.
  • Validate JSON with serde::de::IgnoredAny instead of constructing and immediately dropping a second full serde_json::Value tree before Perry builds its runtime representation.

Benchmark results

Measured on the same machine/build configuration; checksums and the large-pipeline output hash were unchanged.

Workload Before After
Numeric number[] loop 154–155 ms 77–78 ms
Downgraded/mixed any[] loop 2481–2485 ms 22 ms
Matrix loop 728–1100 ms 687–694 ms
Integer loop 736–798 ms 575–581 ms
JSON roundtrip 609–674 ms 250–256 ms
107 MB JSON pipeline 3.74 s / ~1008 MiB RSS 3.39 s / ~785 MiB RSS

The matrix baseline was noisy due to concurrent local work; the after range is included rather than claiming precision beyond the measurements.

AOT boundary

This fixes the single-candidate silent-wrong-module case and honors the post-hook specifier. Perry remains closed-world for dynamic imports: a hook redirect to a module absent from the compiled candidate set rejects rather than loading arbitrary new source at runtime.

Related issue

n/a — standalone audit findings.

Test plan

  • cargo check -p perry-codegen -p perry-runtime

  • cargo build --release -p perry -p perry-runtime-static -p perry-stdlib-static

  • cargo test -p perry-codegen --test native_proof_regressions — 245 passed

  • cargo test -p perry --test issue_6660_closure_dynamic_import -- --test-threads=1 — 6 passed

  • cargo test -p perry-runtime typed_feedback -- --test-threads=1 — 49 passed

  • cargo test -p perry-runtime numeric_range_add -- --test-threads=1

  • Focused JSON direct-parse and malformed/trailing-input tests

  • python3 scripts/addr_class_inventory.py — 800 files scanned, 265 allowlisted, 567 known sites held by the ratchet

  • cargo fmt --all

  • git diff --check

  • Affected release targets build clean

  • Full non-UI workspace test suite was not run locally

  • Added regression tests in the affected compiler/runtime crates

  • Documentation not required: the new runtime ABI helpers are internal codegen support, not public APIs

Screenshots / output

Not applicable.

Checklist

  • I have NOT bumped the workspace version or edited CLAUDE.md / CHANGELOG.md (maintainer handles these at merge)
  • My commit follows the loose feat: / fix: / docs: / chore: prefix convention used in the log
  • I've read CONTRIBUTING.md and agree to the Code of Conduct

Summary by CodeRabbit

  • New Features
    • Faster numeric array “range add” updates via a dedicated helper, including end-from-length support.
  • Bug Fixes
    • Dynamic import() now validates the runtime module specifier correctly after loader/resolver hook redirects, including single-candidate resolution, preventing silent misloads.
    • Hardened runtime guards for numeric store-loop fast paths, object/metadata safety, and packed numeric handling (including frozen array rejection).
    • JSON parsing rejects malformed JSON with trailing input while reducing intermediate allocations.
  • Tests
    • Added regression and unit tests for dynamic imports, transactional numeric range updates, and JSON validation.

@coderabbitai

coderabbitai Bot commented Jul 23, 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: c948c7a7-5ece-406d-9e43-01b65e379522

📥 Commits

Reviewing files that changed from the base of the PR and between 79962df and 5b6f41b.

📒 Files selected for processing (1)
  • scripts/check_file_size.sh

📝 Walkthrough

Walkthrough

The PR fixes single-candidate dynamic import matching, adds transactional numeric range-add loop fast paths, refines packed-loop guards, reduces JSON validation allocation, and strengthens runtime GC-header and numeric-array checks.

Changes

Dynamic import resolution

Layer / File(s) Summary
Runtime candidate verification
crates/perry-codegen/src/expr/dyn_extern_i18n.rs, crates/perry/tests/issue_6660_closure_dynamic_import.rs
Dynamic imports compare runtime specifiers even with one candidate, with tests covering mismatches and resolver-hook redirects.

Numeric range-add optimization

Layer / File(s) Summary
Numeric range-add loop lowering
crates/perry-codegen/src/stmt/loops.rs, crates/perry-codegen/src/runtime_decls/arrays.rs
Loop matching emits range-add helpers before falling back to generic loop lowering.
Transactional runtime helpers and validation
crates/perry-runtime/src/array/{indexing.rs,mod.rs,tests.rs}, crates/perry-codegen/tests/native_proof_regressions/invalidation.rs
Helpers validate complete ranges before mutation and tests cover mixed layouts, invalid ranges, runtime starts, and frozen arrays.
Packed-loop eligibility and hoisting
crates/perry-codegen/src/stmt/loops.rs, benchmarks/compiler_output/workloads.toml
Guarded store loops use refined hoisting and eligibility checks with updated IR assertions.

Runtime validation and parsing

Layer / File(s) Summary
JSON syntax validation
crates/perry-runtime/Cargo.toml, crates/perry-runtime/src/json/{parse_api.rs,mod.rs}
JSON parsing validates into IgnoredAny while preserving syntax errors and adds malformed/trailing-input tests.
Object and array guard validation
crates/perry-runtime/src/object/{field_get_set/ic_miss.rs,prototype_chain.rs}, crates/perry-runtime/src/typed_feedback.rs
GC-header reads and numeric array guards use validated-header and raw-layout checks.
Address-class baseline and release metadata
scripts/addr_class_ratchet_baseline.txt, scripts/check_file_size.sh, benchmarks/results/public-node-bun-v1.json, changelog.d/6810-aot-runtime-fast-paths.md
Baselines, file-size allowlisting, benchmark freshness metadata, and changelog text are updated.

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

Sequence Diagram(s)

sequenceDiagram
  participant ForLoopLowering
  participant ArrayRangeHelper
  participant ArrayStorage
  participant GenericLoop
  ForLoopLowering->>ArrayRangeHelper: call numeric range-add helper
  ArrayRangeHelper->>ArrayStorage: validate range and numeric slots
  ArrayRangeHelper->>ArrayStorage: apply delta transactionally
  ArrayRangeHelper-->>ForLoopLowering: return end or -1
  ForLoopLowering->>GenericLoop: lower original loop on failure
Loading

Possibly related PRs

  • PerryTS/perry#6665: Modifies the same dynamic import candidate and runtime-specifier lowering paths.
  • PerryTS/perry#6750: Modifies the same packed-f64 loop guard and lowering logic.
  • PerryTS/perry#6807: Modifies overlapping typed-feedback shape-token and guard handling.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change set: hardening dynamic imports and speeding up numeric/JSON paths.
Description check ✅ Passed The PR description follows the template with summary, changes, related issue, test plan, screenshots, and checklist sections.
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.
✨ 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.

@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.

🧹 Nitpick comments (1)
crates/perry-codegen/src/stmt/loops.rs (1)

304-438: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Store-shape destructuring here duplicates supported_packed_numeric_loop_store_kind (Lines 2729-2749).

Lines 354-374 and Lines 2729-2749 both destructure the loop body into (object/target, index/key, value) with the identical IndexSet | PutValueSet { receiver == target } accept rule. These two matchers must stay in lockstep (one drives the optimization, the other the fallback shape); a shared helper such as match_indexed_store_shape(store) -> Option<(&Expr, &Expr, &Expr)> removes the drift risk.

🤖 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/src/stmt/loops.rs` around lines 304 - 438, Extract the
duplicated IndexSet/PutValueSet destructuring and receiver-target validation
from match_numeric_range_add_loop and supported_packed_numeric_loop_store_kind
into a shared match_indexed_store_shape helper returning object, index, and
value expressions. Replace both inline matchers with this helper while
preserving their existing acceptance rules and downstream behavior.
🤖 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.

Nitpick comments:
In `@crates/perry-codegen/src/stmt/loops.rs`:
- Around line 304-438: Extract the duplicated IndexSet/PutValueSet destructuring
and receiver-target validation from match_numeric_range_add_loop and
supported_packed_numeric_loop_store_kind into a shared match_indexed_store_shape
helper returning object, index, and value expressions. Replace both inline
matchers with this helper while preserving their existing acceptance rules and
downstream behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 01a176e5-1644-4522-b49e-ec8737aaefd7

📥 Commits

Reviewing files that changed from the base of the PR and between bb6614f and 19ff55b.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • crates/perry-codegen/src/expr/dyn_extern_i18n.rs
  • crates/perry-codegen/src/runtime_decls/arrays.rs
  • crates/perry-codegen/src/stmt/loops.rs
  • crates/perry-codegen/tests/native_proof_regressions/invalidation.rs
  • crates/perry-runtime/Cargo.toml
  • crates/perry-runtime/src/array/indexing.rs
  • crates/perry-runtime/src/array/mod.rs
  • crates/perry-runtime/src/array/tests.rs
  • crates/perry-runtime/src/json/mod.rs
  • crates/perry-runtime/src/json/parse_api.rs
  • crates/perry-runtime/src/object/field_get_set/ic_miss.rs
  • crates/perry-runtime/src/object/prototype_chain.rs
  • crates/perry-runtime/src/typed_feedback.rs
  • crates/perry/tests/issue_6660_closure_dynamic_import.rs
  • scripts/addr_class_ratchet_baseline.txt

@proggeramlug
proggeramlug merged commit c873da6 into PerryTS:main Jul 23, 2026
30 checks passed
@proggeramlug
proggeramlug deleted the fix/audit-dynamic-addr-perf branch July 23, 2026 17:52
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