Skip to content

Share exact retained function and class source ranges - #10065

Closed
proggeramlug wants to merge 2 commits into
mainfrom
fix/retained-source-range-pool-20260911
Closed

proggeramlug wants to merge 2 commits into
mainfrom
fix/retained-source-range-pool-20260911

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Share exact nested function/closure/class/method source byte ranges within each module. This is an independent compiler optimization: no application source, runtime API changes, deletion of reflection data or dependency on the in-flight Bun compression PR.

The pool interns identical texts, uses deterministic longest-parent-first substring matching with the already-locked aho-corasick 1.1.4 contiguous NFA, and emits only parent constants. Each existing source registration keeps its original order, symbol/class identity, byte length and strictness bit. Executables retain the static registration API; dylib/staticlib output retains the copying API; class registration still copies. GEP offsets refer to exact bytes, including UTF-8 and NULs. Below 4 KiB or above 8 MiB of unique pattern bytes the matcher is skipped; a 1,000,000-match budget leaves unmatched sources independent. No new environment switch.

Validation so far

  • Normal-debug codegen library suite: 1,467 passed, 0 failed, 1 ignored. Includes five pool tests plus real emitted-IR assertions for shared parents, nonzero offsets, exact registration order/flags/lengths, deterministic output and executable/dylib/staticlib API choices.
  • Standalone gap fixture and native driver added. The driver compares exact reflection output with pinned Node 26.5.1, hides the source during execution and requires moving-GC counters; it also asserts that source-range sharing was actually emitted. Default and compact modes are separate arms.
  • Frozen pre-pooling toolchain d8c817e (same base 603b074 plus independent asset compression): both baseline native arms pass, each with 201 copying minors, 42,629 moved objects and 4,000 loop polls; zero shared source calls as expected. This is not candidate-native evidence.
  • Clean candidate bf7f87e61, frozen compiler and all nine matching archives: six native acceptance arms pass (default/compact × text transport/unsplit native construction/two-unit native construction). Every arm emits two live shared source calls, matches pinned Node's full reflection output with input hidden, and reports 201 copying minors, 42,629 moved objects, 4,000 loop polls. No source/stamp substitution. Compiler build 9m21s; provider/Wasm build 10m29s.
  • Actual emitted IR for the standalone fixture reduces byte-array constants 24 → 22, 16,413 → 11,058 bytes. Both the nested-function text and class-method text go from two physical copies to one. Small Mach-O executable file size changes only 16–32 bytes due to page-rounded segments and linkage differences; this is not a full-application size result or a solely-source-pooling executable A/B.
  • Full script lint: 75 passed, 1 failed, 2 CI-only skipped; compile-tier gates explicitly skipped. The sole failure is the public benchmark freshness gate, with the same input-staleness message already observed on base 603b074. Syntax and the Rust 2,000-line file limit also pass.
  • CI at bf7f87e61 is complete (run 34589238833): compilation, warnings and security pass. Lint fails on the same base public benchmark freshness. The runtime phase reports 3,504 passed, one failed, four ignored; its sole failure is the same base native_stack.rs:53/:60 worker-bound assertion. That fail-fast job did not reach the new codegen unit tests, so the local codegen results above are not presented as Linux CI results. The green scoped-E2E job has no new Rust integration entry point here and is not counted as source-pool native evidence.
  • Linux gap CI actually executed and passed test_gap_retained_source_pool (shard 3, 11:14:40 UTC). Shards 4 and 6 pass; all 11 printed failure/crash diagnostics in shards 1/2/3/5 exactly match main 603b074ac run 34565492075, including the WebCrypto 10-second timeout. This compares reported exits and printed output excerpts, not full stdout, and does not relabel the red fan-in green. GC stress matches Node in 588/588 cells: 429 PASS, 159 UNVERIFIED, 0 FAIL; the 159 inert arms are not counted as moving-GC evidence.

Readiness / limits

Ready: the candidate native acceptance hold is cleared. All six candidate and six pre-pooling baseline arms pass. The unsplit-native candidate pair was initially refused before launch by the disk guard; after space recovered it actually executed and passed at 11:05 UTC. No failed/unfinished arm is counted as successful. All local build/test jobs have finished.

No full application rebuild has been launched. That remains gated on merged main and its 15 GiB start-space guard. This PR is independently implementable/testable and makes no working-application claim.

The gap fixture is included in the normal gap sweep, and pool/IR tests run in the codegen unit suite. The standalone driver is a manual additional acceptance command:

PERRY_BIN=/path/to/matched/perry PERRY_RUNTIME_DIR=/path/to/matched/archives \
  PERRY_TEST_WASM=1 node scripts/test-retained-source-pool.mjs

Use PERRY_TEST_WASM=1 only for a provider graph built with wasm-host; otherwise omit it. --expect-unshared is the explicit pre-fix baseline control, not the acceptance mode.

Size scope

Earlier diagnostic registration-only objects over three real retained-source corpora saved 2,238,856 bytes combined (3,514,976 → 1,276,120), with exact range checks. Those were a separate prototype, synthetic registration identities and LLVM objects—not this production compiler or a full application. No final executable-size saving or working Claude prompt is claimed here.

No version bump: left to the maintainer at merge time.

@coderabbitai

coderabbitai Bot commented Sep 11, 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: ae94b2ed-87a4-4260-8e82-14f4fc049342

📥 Commits

Reviewing files that changed from the base of the PR and between 603b074 and bf7f87e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • Cargo.toml
  • changelog.d/10065-retained-source-range-pool.md
  • crates/perry-codegen/Cargo.toml
  • crates/perry-codegen/src/codegen/emission_order_tests.rs
  • crates/perry-codegen/src/codegen/mod.rs
  • crates/perry-codegen/src/codegen/retained_source_pool.rs
  • crates/perry-codegen/src/codegen/string_pool.rs
  • scripts/test-retained-source-pool.mjs
  • test-files/test_gap_retained_source_pool.ts

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


📝 Walkthrough

Walkthrough

The code generator now pools retained source strings into shared LLVM globals and records byte ranges for nested sources. Function and class registrations use pooled pointers and lengths. Unit, IR, reflection, native, and moving-GC tests validate the behavior.

Changes

Retained source pooling

Layer / File(s) Summary
Source range planning and emission
Cargo.toml, crates/perry-codegen/Cargo.toml, crates/perry-codegen/src/codegen/mod.rs, crates/perry-codegen/src/codegen/retained_source_pool.rs
Adds the aho-corasick dependency and a SourcePool that deduplicates sources, emits parent globals, computes byte ranges, and falls back to independent ranges under configured limits.
Code generation registration integration
crates/perry-codegen/src/codegen/string_pool.rs, crates/perry-codegen/src/codegen/emission_order_tests.rs
Uses pooled pointers and lengths for function and class registrations. Tests verify deterministic IR, offsets, registration APIs, lengths, strictness, and ownership behavior across output kinds.
Reflection and native acceptance validation
test-files/test_gap_retained_source_pool.ts, scripts/test-retained-source-pool.mjs, changelog.d/10065-retained-source-range-pool.md
Adds reflection and memory-churn coverage. The native driver checks shared IR pointers, hidden-source execution, Node output parity, and moving-GC counters in default and compact modes.

Priority: ⬇️ Low

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

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant SourcePool
  participant StringPool
  participant LLVMIR
  participant NativeDriver
  SourcePool->>StringPool: provide pooled source ranges
  StringPool->>LLVMIR: emit shared globals and registrations
  NativeDriver->>LLVMIR: inspect shared pointers and registration calls
  NativeDriver->>NativeDriver: execute reflection and moving-GC checks
Loading

Merge Risk: ⚪ Minimal · up to bf7f8

The retained-source pooling change preserves the tested reflection and registration behavior across supported output modes, with no unresolved merge-blocking risk identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 6 files. (3 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 main change: sharing exact retained source ranges for functions and classes.
Description check ✅ Passed The description is detailed and directly covers the implementation, validation, known limitations, and lack of version changes. It does not use the template's explicit Changes, Related issue, or Check…
Full details: Docstring Coverage

Explanation

Docstring coverage is 64.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 6 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/retained-source-range-pool-20260911

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 with preserved authorship via #10082 (rebase merge 435d639); the merged tree was verified byte-identical to the audited Train160 tree. Closing this superseded original PR.

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