Reduce allocations and redundant work across compiler hot paths - #21516
Conversation
🦋 Changeset detectedLatest commit: 275301d The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
This PR is packaged and the instant preview is available (fbcbe3e). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@fbcbe3e
yarn add -D webpack@https://pkg.pr.new/webpack@fbcbe3e
pnpm add -D webpack@https://pkg.pr.new/webpack@fbcbe3e |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #21516 +/- ##
=======================================
Coverage 93.78% 93.78%
=======================================
Files 620 620
Lines 73703 73741 +38
Branches 21262 21279 +17
=======================================
+ Hits 69123 69161 +38
Misses 4580 4580
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
f7cd524 to
049e57d
Compare
Merging this PR will degrade performance by 52.52%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Memory | benchmark "devtool-eval", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
1.3 MB | 3.1 MB | -57.53% |
| ❌ | Memory | benchmark "asset-modules-resource", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
640.1 KB | 1,205.6 KB | -46.91% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing perf/compiler-hotpath-allocations (275301d) with main (8331267)
049e57d to
eb3036e
Compare
eb3036e to
5e77484
Compare
All changes are behavior-preserving and validated with isolated before/after micro-benchmarks, profiled full-build A/B (GC-event count as a deterministic allocation-churn proxy), full ConfigTestCases (8668, 548 snapshots), TestCasesProduction, and yarn tsc. Exports / reexport resolution (dominant cost on barrel-heavy graphs per CPU profiling — ~21% fewer GC events on a reexport-heavy full build): - ExportsInfo.findTarget: pass a shared empty visited-set (_findTarget only reads it) instead of a fresh Set per call. - ExportsInfo.setTarget: copy exportName only when actually stored. - isStarReexportBackToParent: allocate the visited set lazily. ESM dependency templates (per import specifier / per reexport item): - HarmonyImportSpecifierDependency: reuse the connection resolved in apply() instead of re-fetching it in _getCodeForIds; hoist the imported module's exports info out of the destructuring-replacement loop. - HarmonyExportImportedSpecifierDependency: hoist getConnection and both getExportsInfo lookups out of the normal-reexport item loop; build ignoredExports in getStarReexports without the spread array. - HarmonyImportDependency: drop a redundant template-literal re-wrap of userRequest. Code generation: - InitFragment.addToSource: flat index sort + numeric keyless keys. - Template.getModulesArrayBounds: arithmetic module-id digit count, no string. - HtmlGenerator: memoize module-by-identifier map per compilation (WeakMap). Module concatenation (ConcatenatedModule): - referencesByName single Map lookup; fold the build() dependency filter into the loop; build allIdentifiers Set without spreads. Usage analysis (FlagDependencyUsagePlugin): - Hoist the two stateless setUsedConditionally predicates; lazily allocate the usually-empty mangleableEscapeModules set. Hashing (per module x runtime, every build): - createModuleHashes: build the moduleHash cache key once per runtime. - ChunkGraph graph-hash: hoist activeStateToString to module scope; compute strict only on cache miss. Chunk splitting (SplitChunksPlugin): - Remove the dead reusableChunks Set; hoist the loop-invariant getKey(usedChunks) out of the per-module loop.
5e77484 to
66fe243
Compare
Deno's node:fs.watch compatibility drops or delays change events, so the WatchDetection cases intermittently time out waiting for the final rebuild. Poll (only under Deno) for deterministic change pickup; Node and Bun keep exercising native watching.
Types CoverageCoverage after merging perf/compiler-hotpath-allocations into main will be
Coverage Report |
Summary
Behavior-preserving allocation and redundant-work reductions on several compiler hot paths: code generation, module concatenation, exports/usage analysis, module hashing, and chunk splitting. The largest effect is on reexport/barrel-heavy graphs —
ExportsInfo.findTargetno longer allocates aSetper call (_findTargetonly reads it),isStarReexportBackToParentallocates its visited set lazily, andgetStarReexports/setTargetdrop throwaway copies — for ~21% fewer GC events on a reexport-heavy full build in local CPU/heap profiling. The rest are smaller idiomatic reductions (InitFragment index-sort + numeric keyless keys,Template.getModulesArrayBoundsarithmetic digit count,ConcatenatedModulesingle Map lookups, hoisted loop invariants, and removal of the deadreusableChunksset inSplitChunksPlugin). Retained heap is unchanged. CI CodSpeed should give a controlled instruction-count measurement.What kind of change does this PR introduce?
perf
Did you add tests for your changes?
No — these are behavior-preserving refactors, so no new behavior to test. Correctness is covered by the existing suite: full ConfigTestCases (8668 cases, 548 snapshots), TestCasesProduction, and the CSS/HTML/exports unit tests all pass, and
yarn tscis clean.Does this PR introduce a breaking change?
No.
If relevant, what needs to be documented once your changes are merged or what have you already documented?
n/a
Use of AI
Yes. Claude (Claude Code) was used to CPU- and heap-profile representative builds, identify the hot paths, implement the changes, and measure them with isolated micro-benchmarks and full-build GC-event A/B runs. Every change was validated against the full test suite and type checker before submitting.
Generated by Claude Code