Repository navigation
[wasm][R2R] Partitioned modules with MIBC-guided hot/cold splitting - #136607
Draft
jtschuster wants to merge 23 commits into
Draft
jtschuster wants to merge 23 commits into
jtschuster wants to merge 23 commits into
Conversation
(cherry picked from commit 9fdb27e)
(cherry picked from commit c517c3a)
(cherry picked from commit 2f27390)
(cherry picked from commit 7941e01)
…les. (cherry picked from commit da9d206)
(cherry picked from commit 574c919)
(cherry picked from commit 236f829)
…otype Describe the two-phase flow as implemented: methods that miss wait for an auxiliary EntryPoints era, methods found in an inactive auxiliary module wait for its activation flag, and activation happens inline at call boundaries. Document that EntryPoints and module activation are independent, how failed activation is handled, and the simulation knobs used by the prototype. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9444d65-1735-42ee-a4a7-119174358f8d
…ulated) Prototype of the first phase of partitioned R2R modules for browser-wasm: a composite image's methods stay interpreted until their auxiliary module is "activated", then switch to their R2R code. The download is simulated by counting calls, without any format, crossgen2 or host changes. - Add FEATURE_AUXILIARY_R2R_MODULES (single-threaded browser-wasm with the interpreter) and DOTNET_R2RDelayedActivationCallCount. Zero preserves eager R2R resolution. - When lookup finds a method in an image whose auxiliary module is not yet activated, record that image's activation flag, keep the method interpreted, and set kPendingAuxiliaryModule on its portable entry point. Stop searching other images once a dependency is recorded. - Cache the flag on InterpMethod (AuxiliaryMethodInfo). Interpreter calls, the R2R-to-interpreter thunk and CallDescrWorkerInternal check it at call boundaries and activate through the prestub. Activation that is rejected or throws leaves the method interpreted. - Do not delay UnmanagedCallersOnly methods, wrapper stubs, stripped-IL images, or lookups for direct calls from R2R code. - Re-enter ExecuteInterpretedMethodWithArgs_PortableEntryPoint_Complex for methods waiting on activation, keeping its MethodImpl handling. - Add the DelayedR2RActivation tests, including a MethodImpl alias case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9444d65-1735-42ee-a4a7-119174358f8d (cherry picked from commit d397db8)
Second phase of partitioned R2R modules: a method's R2R lookup can also miss because the module that maps methods to code (the Auxiliary EntryPoints Module) is not yet available, or because the image that has the code is loaded later. Such methods wait for the next auxiliary EntryPoints era instead of for a specific module, then repeat the lookup. - Add AuxiliaryEntryPointsEra, an opaque value only ReadyToRunInfo creates or compares, and a global era next to the unrelated R2R modules list. The era advances when the simulated EntryPoints download completes and when an image with code for unrelated generics is registered. - Record the era read before the lookup when it misses, set kAwaitingAuxiliaryEntryPoints, and cache the era in AuxiliaryMethodInfo, which becomes a discriminated union of the activation flag and the era. - The lookup treats methods of an image as not found while its EntryPoints module is inactive. - Add DOTNET_R2RDelayedEntryPointsActivationCallCount, defaulting to DOTNET_R2RDelayedActivationCallCount, and the DelayedModuleOnly and DelayedEntryPointsOnly test variants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9444d65-1735-42ee-a4a7-119174358f8d (cherry picked from commit 8806b13)
Same change as dotnet#136497. Revert this commit once that fix is in the branch's base. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9444d65-1735-42ee-a4a7-119174358f8d
A composite image's components register the composite's own ReadyToRunInfo, which has no module, on the unrelated R2R modules list. Looking it up decodes signatures against a NULL module and crashes with "function signature mismatch" on browser-wasm. Skip it until the registration is fixed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9444d65-1735-42ee-a4a7-119174358f8d
The fix landed in main as dotnet#136497. This reverts commit 984183f. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9444d65-1735-42ee-a4a7-119174358f8d
Emit physical entrypoint and cold-code modules with deferred metadata ownership, activate them independently through CoreCLR and browser hosting, and integrate opt-in publishing and compression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0797c2c0-9a42-4488-8454-7761c25a6e19
Duplicate eligible managed helper code and funclets without duplicating logical table slots or metadata. Validate cold helper calls, native GC and exception handling, and document activation scheduling. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0797c2c0-9a42-4488-8454-7761c25a6e19
Record all nine macro scenarios, full module compression sizes, monitored startup/interaction measurements, and separately activation-gated throughput. Preserve reproducible evidence and limitations without claiming statistical significance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0797c2c0-9a42-4488-8454-7761c25a6e19
Use explicit MIBC method membership with canonical generic matching, preserving mandatory primary methods and the no-profile heuristic. Keep auxiliary PGO publishes fully compiled and fix doubled entrypoint-table offsets exposed by generic coverage. Add compiler/SDK regression cases and matched Havit size evidence. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0797c2c0-9a42-4488-8454-7761c25a6e19
Prefer upstream's IMAGE_DATA_DIRECTORY definition and fixup-list wording in the format documentation conflicts while retaining the auxiliary-module additions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0797c2c0-9a42-4488-8454-7761c25a6e19
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Tagging subscribers to this area: @dotnet/crossgen-contrib |
Contributor
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Publish the auxiliary compiler as a standalone module worker, keep generic downloads Response-only, and preserve shared retry and throttle policy. Cover worker preparation and loader compatibility without diagnostic tracing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0797c2c0-9a42-4488-8454-7761c25a6e19
Group cold-exclusive WebAssembly R2R imports before layout
jkotas
reviewed
Oct 29, 2026
|
|
||
| Before assigning import offsets, the WebCIL writer classifies import usage from method fixups and relocations. Each import table and its parallel signature-RVA array use the same primary-first, cold-exclusive-last partition key, retaining the existing deterministic order within each group. GC reference maps follow physical cell order, including empty records for non-method cells. Table identities and entry sizes do not change; fixup lists and relocations are emitted against the new indices and offsets rather than patched afterward. | ||
|
|
||
| Eager, shared, unused, and resident-data-referenced cells stay primary. Signature ownership is computed after symbol deduplication: signatures shared with primary cells or directly referenced by resident data remain primary even when some referencing cells move cold. Cold-exclusive signature blobs are stably grouped at the end of data emission. Alignment gaps are not claimed as cold data, so aligned blobs can still require multiple passive segments. Portable import-thunk records are resident data and pin their referenced cells primary; moving those records would require a separate ownership analysis and is deliberately not inferred from a cold method's use of the cell. GC reference maps remain resident because their stride-indexed encoding covers both groups. |
Member
There was a problem hiding this comment.
stride-indexed encoding
This will be gone once you resolve conflicts with main
Preserve main's per-signature GC reference maps and remove the obsolete stride-indexed map node and tests. Include signature prefixes in cold-data ownership and update the design documentation for Jan's feedback. Advance the partitioned format to version 34 after main independently introduced version 33, and adapt auxiliary function names to the updated WasmSymbol contract. Validated Linux and Browser-WASM Release builds; Browser-WASM ReadyToRun compiler tests: 256 passed, 40 skipped, 0 failed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 776e597c-5437-4660-8e83-6d4a3aa5634e
This was referenced Oct 31, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Warning
This is a totally AI-generated, unreviewed implementation draft.
The implementation and this PR description were generated by GitHub Copilot and have not received human code review. Passing local tests is not a substitute for review or proof of conformance to the specification. This is not ready to merge.
Intent
This should implement the partitioned WebAssembly ReadyToRun (R2R) module specification discussed in #135544, including physical auxiliary modules and MIBC-guided hot/cold placement. It includes the earlier delayed-activation prototype from #136498.
The goal is to enable useful size and performance measurements once we have representative, execution-derived profiles. No real Havit startup profile has been collected yet. The current MIBC measurements use synthetic method lists and do not establish realistic startup size, startup performance, or a production-quality hot set.
The design and implementation notes describe the intended contracts and the limits of the existing evidence.
Implementation
The implemented boundary is single-threaded CoreCLR Browser-WASM, composite R2R, with retained IL. This is not non-composite, multithreaded, or stripped-IL support.
Using profiles
With matching updated compiler and SDK build targets, add the existing item to the application:
Crossgen2 also accepts
--wasm-auxiliary-modules --mibc startup.mibcdirectly. This consumes existing MIBC data; it does not implement browser profile collection. Selection is by method membership, not a CPU-weight threshold.Measurements so far
The committed documentation contains the earlier nine-app, no-profile comparison and a separate matched Havit MIBC size-sensitivity comparison. These measurements predate the merge of current main and were not regenerated after that merge. They must not be interpreted as measured startup PGO results.
For Havit, both sides used the same updated compiler and retained 113,991 managed function/funclet slots. Brotli-compressed R2R module sizes in KiB:
This is an almost-all-cold configuration: the synthetic profile contains only
String.Concat(string, string),String.IsNullOrEmpty(string),Int32.ToString(), andString.StartsWith(string, StringComparison). It demonstrates placement and size sensitivity, not a suitable startup hot set. These are module-file sizes, not whole-app completed network transfers.The earlier heuristic comparison showed smaller primary modules but increased combined R2R payload and regressions in initial interactions and some steady-state throughput. This PR does not claim an overall performance improvement. Long synchronous managed calls can block JavaScript-side activation; representative profiles and activation-aware measurements are still needed.
Exact raw/gzip/Brotli inventories:
Local validation
The merged feature was validated at
e01332100e8, which incorporates upstream main at82b3c9469e092824425186a37ace7b6ab6bc89b0.Passed: Browser-WASM Release runtime, libraries, and host build, zero warnings/errors.
Passed: 233 tests, 39 skipped, zero failures, zero build warnings/errors. The six new MIBC selection cases failed before the selector change and passed afterward.
Passed: 17 tests, zero failures.
Passed: refreshed Browser-WASM Core_Root. The installed Crossgen2 hash matched the newly built compiler, and the runtime/CoreLib timestamps were checked.
The following wrapper was run for each of
PartitionedR2RActivation_Eager,PartitionedR2RActivation_EntryPointsFirst,PartitionedR2RActivation_ModuleFirst,PartitionedR2RActivation_AllHot, andPartitionedR2RActivation_AllCold:Passed: all five physical runtime variants, wrapper exit 0 and actual managed exit 100. Each variant's cached
IL-CG2directory was removed before execution, and a fresh Crossgen2 invocation was verified in every log.Additional retained evidence from the pre-merge checkout at
53380e2f8bb:The extended
Wasm.Build.TestsxUnit fixture was not built or run because its assets/test SDK were not prepared. Direct target probes and real publishes were used for the SDK change instead. Publishing used an isolated SDK package copy with the changed source target overlaid; archived runtime/SDK packages and earlier measurement outputs were preserved.Post-merge build/test logs are under
artifacts/aux-pr-merged-*in the feature checkout. Earlier profile/measurement commands and raw results are indexed byartifacts/mibc-selection-validation.jsonin the feature checkout andartifacts/mibc-hotcold-full-f8b896-20261028/report.jsonin the macro-benchmarks checkout. These local artifacts are not attached to this PR.Draft status and remaining work
Human review of specification conformance, ownership/activation safety, code generation, SDK integration, and tests is required. Real startup/interaction profiles and matched size/performance measurements are also required before drawing conclusions about the tradeoff.
This branch includes the phase-1 prototype ancestry. Upstream main was incorporated with explicit merge commit
e01332100e8; both ReadyToRun format documentation conflict hunks were resolved in favor of main, and that file now matches main exactly. The merged runtime/compiler and physical activation tests passed as described above.Note
This implementation and PR description are entirely AI/Copilot-generated and have not been human-reviewed.