[browser][coreCLR] browserhost to load R2R#129634
Draft
pavelsavara wants to merge 12 commits into
Draft
Conversation
Contributor
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends the WebAssembly build/publish pipeline to support ReadyToRun (R2R) “webcil-in-wasm” assemblies by staging prebuilt R2R .wasm images, emitting webcil payload/table sizing into the boot config, and updating the JS loader/host to instantiate webcil modules using those sizes (enabling streaming instantiation and avoiding runtime-side wasm parsing).
Changes:
- Add an MSBuild path to crossgen selected assemblies to R2R webcil-in-wasm and feed those artifacts into webcil conversion/staging.
- Emit
payloadSize(andtableSizefor R2R) into the boot config assets so the loader can instantiate without callinggetWebcilSize/ parsing wasm. - Update the JS loader/host surface and typings to pass these sizes through to
instantiateWebcilModule.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs | Plumbs webcil size metadata into boot config generation and passes it to asset transformation. |
| src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ConvertDllsToWebCil.cs | Adds optional staging of prebuilt R2R .wasm replacements and emits a WebcilSizes output by parsing wasm. |
| src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs | Extends boot asset schema with tableSize/payloadSize fields. |
| src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonBuilderHelper.cs | Writes payloadSize/tableSize onto boot assets during resources→assets transformation. |
| src/native/libs/Common/JavaScript/types/public-api.ts | Exposes tableSize/payloadSize on AssemblyAsset in public TS types. |
| src/native/libs/Common/JavaScript/types/internal.ts | Adds internal asset fields for tableSize/payloadSize. |
| src/native/libs/Common/JavaScript/types/ems-ambient.ts | Extends ambient emscripten symbol typing for wasm exports needed by R2R webcil imports. |
| src/native/libs/Common/JavaScript/loader/dotnet.d.ts | Updates loader .d.ts for AssemblyAsset to include tableSize/payloadSize. |
| src/native/libs/Common/JavaScript/loader/assets.ts | Passes tableSize/payloadSize to browser-host instantiateWebcilModule. |
| src/native/libs/Common/JavaScript/host/assets.ts | Reworks instantiateWebcilModule to allocate payload and instantiate webcil wasm (streaming when possible) using boot-config sizes. |
| src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets | Wires R2R candidates into ConvertDllsToWebcil, propagates WebcilSizes, and adds a _WasmCrossgenReadyToRunAssemblies target. |
| src/mono/browser/build/WasmApp.InTree.props | Defines in-tree crossgen2/jit/reference paths consumed by the new R2R target. |
| src/mono/sample/wasm/browser-R2R/Wasm.Browser.R2R.csproj | Adds a new sample that opts its app assembly into R2R cross-compilation. |
| src/mono/sample/wasm/browser-R2R/Program.cs | Sample app entrypoint. |
| src/mono/sample/wasm/browser-R2R/wwwroot/index.html | Sample web page host. |
| src/mono/sample/wasm/browser-R2R/wwwroot/main.js | Sample boot/run script using dotnet.js. |
This was referenced Jun 20, 2026
Comment on lines
+258
to
+265
| // Key by the logical assembly name (".dll"), not the produced ".wasm" file name: the boot | ||
| // config lists webcil assemblies under their logical ".dll" name, and GenerateWasmBootJson | ||
| // looks these sizes up by that name (resourceName). Using ".wasm" here would never match. | ||
| // Keying by ".dll" also avoids colliding with same-stem assets (e.g. a "X.pdb" never matches | ||
| // "X.dll"). | ||
| string fileName = Path.ChangeExtension(Path.GetFileName(webcilPath), ".dll"); | ||
| string key = string.IsNullOrEmpty(culture) ? fileName : culture + "/" + fileName; | ||
| var item = new TaskItem(key); |
Comment on lines
+49
to
+55
| export async function instantiateWebcilModule(webcilPromise: Promise<Response>, memory: WebAssembly.Memory, virtualPath: string, tableSize?: number, payloadSize?: number): Promise<void> { | ||
| // The boot config carries payloadSize for every webcil asset (and tableSize for R2R images), so | ||
| // the loader never buffers the bytes, parses the data section or calls getWebcilSize. Assets | ||
| // without a tableSize are plain (Webcil wrapper version 0) images. | ||
| if (typeof payloadSize !== "number" || payloadSize === 0) { | ||
| throw new Error(`Webcil asset '${virtualPath}' is missing payloadSize in the boot config.`); | ||
| } |
Comment on lines
+424
to
+433
| <ConvertDllsToWebcil | ||
| Candidates="@(_WasmDllBuildCandidates)" | ||
| IntermediateOutputPath="$(_WasmBuildTmpWebcilPath)" | ||
| OutputPath="$(_WasmBuildWebcilPath)" | ||
| IsEnabled="$(_WasmEnableWebcil)" | ||
| WebcilVersion="$(_WasmWebcilVersion)" | ||
| R2RWebcilCandidates="@(WasmR2RWebcilCandidate)"> | ||
| <Output TaskParameter="FileWrites" ItemName="FileWrites" /> | ||
| <Output TaskParameter="FileWrites" ItemName="_WasmConvertedWebcilOutputs" /> | ||
| <Output TaskParameter="WebcilSizes" ItemName="_WasmWebcilSizes" /> |
Comment on lines
+89
to
+94
| /// <summary> | ||
| /// Payload/table sizes for each webcil (keyed by the logical assembly name, e.g. "App.dll"), | ||
| /// produced by ConvertDllsToWebcil. Emitted into the boot config so the runtime loader doesn't | ||
| /// parse the wasm or call getWebcilSize. | ||
| /// </summary> | ||
| public ITaskItem[] WebcilSizes { get; set; } |
Comment on lines
+40
to
+47
| /// <summary> | ||
| /// Payload/table sizes for each produced webcil, keyed by the logical assembly name as it | ||
| /// appears in the boot config: the file name (e.g. "System.Console.dll"), or | ||
| /// "{culture}/{name}.dll" for satellite assemblies so that same-named satellites in different | ||
| /// cultures don't collide. Lets the boot config carry the sizes so the runtime loader doesn't | ||
| /// buffer/parse the wasm. PayloadSize is set for every webcil; TableSize is non-zero only for | ||
| /// R2R images. | ||
| /// </summary> |
Comment on lines
339
to
342
| extern "C" UINT_PTR STDCALL GetCurrentIP(void) | ||
| { | ||
| PORTABILITY_ASSERT("GetCurrentIP is not implemented on wasm"); | ||
| // WASM-TODO: Implement this function to return the current instruction pointer in the interpreter. | ||
| return 0; |
Comment on lines
+326
to
+336
| int want = dataLength >= 8 ? 8 : 4; | ||
| byte[] sizes = new byte[8]; | ||
| if (!TryFill(fs, sizes, want)) | ||
| { | ||
| failureReason = "data segment 0 was truncated before the sizes could be read"; | ||
| return false; | ||
| } | ||
|
|
||
| payloadSize = (int)ReadUInt32LE(sizes, 0); | ||
| tableSize = want == 8 ? (int)ReadUInt32LE(sizes, 4) : 0; | ||
| return true; |
Comment on lines
+6
to
+20
| function displayMeaning(meaning) { | ||
| console.log(`Meaning of life is ${meaning}`); | ||
| document.getElementById("out").innerHTML = `${meaning}`; | ||
| } | ||
|
|
||
| function delay(ms) { | ||
| return new Promise(resolve => setTimeout(resolve, ms)); | ||
| } | ||
|
|
||
| try { | ||
| const { setModuleImports, getAssemblyExports } = await dotnet | ||
| .withConfig({ appendElementOnExit: true, exitOnUnhandledError: true, forwardConsole: true, logExitCode: true }) | ||
| .withDiagnosticTracing(true) | ||
| .withApplicationArguments("--meaning", "42") | ||
| .create(); |
3 tasks
…thods CallDescrWorkerInternal (the wasm reflection/CallDescr invoke path) resolved the interpreter byte code via MethodDesc::GetInterpreterCode() and, after a DoPrestub retry, passed the pointer straight to ExecuteInterpretedMethodWithArgs. When the target method has no interpreter byte code because it was compiled to native (R2R) code, GetInterpreterCode() returns NULL. On wasm a NULL pointer reads zeroed low linear memory instead of faulting, so the interpreter dispatched the NULL byte code as INTOP_INVALID and aborted with Unimplemented or invalid interpreter opcode plus a secondary stackwalk assert. Add the InvokeManagedMethod fallback (the interpreter->R2R thunk) when there is no interpreter code, mirroring the existing pattern in ExecuteInterpretedMethodWithArgs_PortableEntryPoint_Complex and the CALL_INTERP_METHOD path in InterpExecMethod. Also harden the sibling entry points: ExecuteInterpretedMethodFromUnmanaged now takes the same fallback, and ExecuteInterpretedMethodWithArgs asserts a non-NULL targetIp so future misuse fails loudly at the point of error.
Comment on lines
+4
to
+7
| using System; | ||
| using System.Runtime.InteropServices.JavaScript; | ||
| using System.Runtime.InteropServices; | ||
| using System.Threading.Tasks; |
Comment on lines
+47
to
+49
| /// </summary> | ||
| [Output] | ||
| public ITaskItem[] WebcilSizes { get; set; } |
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.
No description provided.