Skip to content

[browser][wasm] Fix buffered symbol asset loading#127087

Open
elringus wants to merge 7 commits into
dotnet:mainfrom
elringus:fix/symbols-buffer
Open

[browser][wasm] Fix buffered symbol asset loading#127087
elringus wants to merge 7 commits into
dotnet:mainfrom
elringus:fix/symbols-buffer

Conversation

@elringus
Copy link
Copy Markdown
Contributor

This fixes SymbolsAsset.buffer handling in the browser runtime and adds a WBT regression test for buffered runtime assets:

  • Fixed the browser loader so symbols assets supplied via buffer are handled correctly, instead of effectively requiring pendingDownload
  • Kept the symbols path working with the existing text-based symbol map loading flow
  • Added BufferedAssetsTest to WasmBasicTestApp that supplies these runtime assets via buffer:
    • dotnetwasm
    • assemblies
    • pdbs
    • symbols
  • Added a matching ModuleConfigTests.BufferedAssetsTest integration test

The issue was discussed with @pavelsavara on .NET's Discord server.

Note: I was not able to run the browser test end-to-end in the local environment due local WBT/workload packaging setup issues. If anything fails on CI, I’ll follow up and fix the remaining issues there.

Copilot AI review requested due to automatic review settings April 17, 2026 17:42
@elringus elringus requested a review from pavelsavara as a code owner April 17, 2026 17:42
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Apr 17, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes buffered symbols runtime asset loading in the browser WASM loader, and adds a regression scenario in WBT to exercise supplying runtime assets via asset.buffer.

Changes:

  • Adjusted asset instantiation flow to correctly handle symbols assets when provided via buffer (and enabled buffered-response .text() decoding).
  • Added a BufferedAssetsTest scenario to WasmBasicTestApp that assigns buffer for wasm/assemblies/pdbs/symbols during onConfigLoaded.
  • Added a matching ModuleConfigTests.BufferedAssetsTest publish-and-run integration test.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js Adds the BufferedAssetsTest scenario that supplies runtime assets via asset.buffer.
src/mono/wasm/Wasm.Build.Tests/ModuleConfigTests.cs Adds an integration test that publishes and runs the new scenario (with symbol map emission enabled).
src/mono/browser/runtime/loader/assets.ts Fixes loader handling for buffered symbols assets and implements .text() for buffered-response shim.

Comment thread src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js
@elringus
Copy link
Copy Markdown
Contributor Author

It seems the fingerprint stuff doesn't support file names with hashes. Is it somehow possible to generate the symbols file without the hash? Or maybe I should also patch the fingerprint resolver to ignore the hash on symbols?

Found unknown files in C:\helix\work\workitem\e\wbt artifacts\ModuleConfigTests_BufferedAssetsTest_Debug_False_0zxtutco_2je_鿀蜒枛遫䡫煉\App\bin\Debug\net11.0\publish\wwwroot_framework:
dotnet.native.8o3vuf3rfy.js.symbols
Add these to GetAllKnownDotnetFilesToFingerprintMap method

@pavelsavara pavelsavara self-assigned this Apr 18, 2026
@pavelsavara pavelsavara added arch-wasm WebAssembly architecture os-browser Browser variant of arch-wasm labels Apr 18, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

@pavelsavara
Copy link
Copy Markdown
Member

Log

Wasm.Build.Tests.ModuleConfigTests.BufferedAssetsTest [FAIL]
      Found unknown files in /root/helix/work/workitem/e/wbt artifacts/ModuleConfigTests_BufferedAssetsTest_Debug_False_zwqmgjzy_he5_鿀蜒枛遫䡫煉/App/bin/Debug/net11.0/publish/wwwroot/_framework:
          dotnet.native.gkigrwomkb.js.symbols
      Add these to GetAllKnownDotnetFilesToFingerprintMap method
      Expected dotnet.js
        dotnet.native.js
        dotnet.native.wasm
        dotnet.runtime.js
      Options AssertBundleOptions { Configuration = Debug, BuildOptions = PublishOptions { IsPublish = True, TargetFramework = net11.0, AOT = False, ExpectedFileType = FromRuntimePack, GlobalizationMode = Sharded, CustomIcuFile = , UseCache = True, ExpectSuccess = True, AssertAppBundle = True, Label = , WarnAsError = True, RuntimeType = SingleThreaded, ExtraBuildEnvironmentVariables = System.Collections.Generic.Dictionary`2[System.String,System.String], NonDefaultFrameworkDir = , ExtraMSBuildArgs = -p:CompressionEnabled=false -p:WasmEnableHotReload=false, EnableDiagnostics = False, BuildOnlyAfterPublish = True, ExpectRelinkDirWhenPublishing = False }, ExpectedFileType = FromRuntimePack, BinFrameworkDir = /root/helix/work/workitem/e/wbt artifacts/ModuleConfigTests_BufferedAssetsTest_Debug_False_zwqmgjzy_he5_鿀蜒枛遫䡫煉/App/bin/Debug/net11.0/publish/wwwroot/_framework, ExpectSymbolsFile = True, AssertIcuAssets = True, AssertSymbolsFile = False, ExpectDotnetJsFingerprinting =  } 
      
      Stack Trace:
        /_/src/mono/wasm/Wasm.Build.Tests/ProjectProviderBase.cs(165,0): at Wasm.Build.Tests.ProjectProviderBase.FindAndAssertDotnetFiles(String binFrameworkDir, AssertBundleOptions assertOptions, IReadOnlyDictionary`2 superSet, IReadOnlySet`1 expected)
        /_/src/mono/wasm/Wasm.Build.Tests/ProjectProviderBase.cs(83,0): at Wasm.Build.Tests.ProjectProviderBase.FindAndAssertDotnetFiles(AssertBundleOptions assertOptions)
        /_/src/mono/wasm/Wasm.Build.Tests/ProjectProviderBase.cs(49,0): at Wasm.Build.Tests.ProjectProviderBase.AssertBasicBundle(AssertBundleOptions assertOptions)
        /_/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs(111,0): at Wasm.Build.Tests.WasmSdkBasedProjectProvider.AssertBundle(AssertBundleOptions assertOptions)
        /_/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs(97,0): at Wasm.Build.Tests.WasmSdkBasedProjectProvider.AssertBundle(Configuration config, MSBuildOptions buildOptions, Boolean isUsingWorkloads, Nullable`1 isNativeBuild, Nullable`1 wasmFingerprintDotnetJs)
        /_/src/mono/wasm/Wasm.Build.Tests/WasmSdkBasedProjectProvider.cs(181,0): at Wasm.Build.Tests.WasmSdkBasedProjectProvider.AssertWasmSdkBundle(Configuration config, MSBuildOptions buildOptions, Boolean isUsingWorkloads, Nullable`1 isNativeBuild, Nullable`1 wasmFingerprintDotnetJs, String buildOutput)
        /_/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs(265,0): at Wasm.Build.Tests.WasmTemplateTestsBase.BuildProjectCore(ProjectInfo info, Configuration configuration, MSBuildOptions buildOptions, Nullable`1 isNativeBuild, Nullable`1 wasmFingerprintDotnetJs)
        /_/src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs(181,0): at Wasm.Build.Tests.WasmTemplateTestsBase.PublishProject(ProjectInfo info, Configuration configuration, Nullable`1 isNativeBuild, Nullable`1 wasmFingerprintDotnetJs)
        /_/src/mono/wasm/Wasm.Build.Tests/ModuleConfigTests.cs(108,0): at Wasm.Build.Tests.ModuleConfigTests.BufferedAssetsTest()
        --- End of stack trace from previous location ---

Log

 Wasm.Build.Tests.ModuleConfigTests.BufferedAssetsTest [FAIL]
      System.Exception : Expected exit code 0 but got 1.
      consoleOutput=Failed to load resource: the server responded with a status of 404 (Not Found)
      Failed to load resource: the server responded with a status of 404 (Not Found)
      MONO_WASM: onConfigLoaded() failed TypeError: config.resources.corePdb is not iterable
      MONO_WASM: Failed to initialize config TypeError: config.resources.corePdb is not iterable TypeError: config.resources.corePdb is not iterable
          at Object.onConfigLoaded (http://127.0.0.1:41655/main.js:603:21)
          at xe (http://127.0.0.1:41655/main.js:136:20568)
          at async http://127.0.0.1:41655/main.js:136:29683
          at async http://127.0.0.1:41655/main.js:136:34856
          at async Object.create (http://127.0.0.1:41655/main.js:136:34826)
          at async http://127.0.0.1:41655/main.js:616:70
      Error: Failed to initialize config TypeError: config.resources.corePdb is not iterable TypeError: config.resources.corePdb is not iterable
          at Object.onConfigLoaded (http://127.0.0.1:41655/main.js:603:21)
          at xe (http://127.0.0.1:41655/main.js:136:20568)
          at async http://127.0.0.1:41655/main.js:136:29683
          at async http://127.0.0.1:41655/main.js:136:34856
          at async Object.create (http://127.0.0.1:41655/main.js:136:34826)
          at async http://127.0.0.1:41655/main.js:616:70
          at xe (http://127.0.0.1:41655/main.js:136:20880)
          at async http://127.0.0.1:41655/main.js:136:29683
          at async http://127.0.0.1:41655/main.js:136:34856
          at async Object.create (http://127.0.0.1:41655/main.js:136:34826)
          at async http://127.0.0.1:41655/main.js:616:70
      WASM EXIT 1

@pavelsavara
Copy link
Copy Markdown
Member

Log

dotnet.runtime.y92zvik3q0.js }
    Wasm.Build.Tests.ModuleConfigTests.BufferedAssetsTest [FAIL]
      Found unknown files in /root/helix/work/workitem/e/wbt artifacts/ModuleConfigTests_BufferedAssetsTest_Debug_False_j4harjjp_1r1_鿀蜒枛遫䡫煉/App/bin/Debug/net11.0/publish/wwwroot/_framework:
          dotnet.native.gkigrwomkb.js.symbols
      Add these to GetAllKnownDotnetFilesToFingerprintMap method
      Expected dotnet.js
        dotnet.native.js
        dotnet.native.wasm
        dotnet.runtime.js

@elringus
Copy link
Copy Markdown
Contributor Author

dotnet.native.gkigrwomkb.js.symbols

The thing is, dotnet.native.js.symbols already exists under GetAllKnownDotnetFilesToFingerprintMap. But it doesn't seem to support hashes.

protected override IReadOnlyDictionary<string, bool> GetAllKnownDotnetFilesToFingerprintMap(AssertBundleOptions assertOptions)
{
var result = new SortedDictionary<string, bool>()
{
{ "dotnet.js", true },
{ "dotnet.js.map", false },
{ "dotnet.native.js", true },
{ "dotnet.native.js.symbols", true },
{ "dotnet.native.wasm", true },
{ "dotnet.native.worker.mjs", true },
{ "dotnet.runtime.js", true },
{ "dotnet.runtime.js.map", false },
{ "dotnet.diagnostics.js", true },
{ "dotnet.diagnostics.js.map", false },
};
if (assertOptions.ExpectDotnetJsFingerprinting == false)
result["dotnet.js"] = false;
return result;
}

@maraf
Copy link
Copy Markdown
Member

maraf commented Apr 22, 2026

I think the logic that asserts the files incorrectly finds where the fingerprint should be, see https://github.com/elringus/dotnet/blob/fix/symbols-buffer/src/mono/wasm/Wasm.Build.Tests/ProjectProviderBase.cs#L116 (dotnet.native.{FP}.js.symbols vs dotnet.native.js.{FP}.symbols)

@elringus
Copy link
Copy Markdown
Contributor Author

Would it be ok to add a special case for .js.symbols in FindAndAssertDotnetFiles?

Copilot AI review requested due to automatic review settings May 25, 2026 08:31
@pavelsavara
Copy link
Copy Markdown
Member

Would it be ok to add a special case for .js.symbols in FindAndAssertDotnetFiles?

@maraf is that what you mean ?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js
@maraf
Copy link
Copy Markdown
Member

maraf commented Jun 8, 2026

Would it be ok to add a special case for .js.symbols in FindAndAssertDotnetFiles?

@elringus I'm sorry for late reply. Yes, we can add a special case for .js.symbols

Copilot AI review requested due to automatic review settings June 8, 2026 13:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

src/mono/browser/runtime/loader/assets.ts:1

  • TextDecoder is constructed on every json()/text() call. While likely not hot, it’s avoidable overhead and easy to fix by reusing a single TextDecoder instance within the closure (or higher scope) and calling decoder.decode(buffer) in both methods.
// Licensed to the .NET Foundation under one or more agreements.

Comment on lines +220 to +228
const originalFetch4 = globalThis.fetch.bind(globalThis);
dotnet.withModuleConfig({
onConfigLoaded: (config) => {
const bufferedAssets = [
...config.resources.wasmNative,
...config.resources.assembly,
...config.resources.pdb,
...config.resources.wasmSymbols,
];
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's controlled by the test fixtures — nothing can be missing here.

Comment on lines +229 to +232
for (const asset of bufferedAssets) {
const url = new URL(`./_framework/${asset.name}`, location.href);
asset.buffer = originalFetch4(url).then(r => r.arrayBuffer());
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied.

dotnet.withApplicationArgumentsFromQuery();
break;
case "BufferedAssetsTest":
const originalFetch4 = globalThis.fetch.bind(globalThis);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is following the established pattern in the file. Changing the pattern is out of scope of this PR.

@elringus
Copy link
Copy Markdown
Contributor Author

elringus commented Jun 8, 2026

I've renamed the conflicting fetch variable and added support for fingerprinting the symbols file.

Copilot AI review requested due to automatic review settings June 8, 2026 13:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment on lines +223 to +228
const bufferedAssets = [
...config.resources.wasmNative,
...config.resources.assembly,
...config.resources.pdb,
...config.resources.wasmSymbols,
];
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already commented above.

Comment on lines +189 to +198
const headersOnly = skipBufferByAssetTypes[asset.behavior];

if (headersOnly) {
if (asset.behavior === "symbols") {
await runtimeHelpers.instantiate_symbols_asset(asset);
cleanupAsset(asset);
}
++loaderHelpers.actual_downloaded_assets_count;
return;
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope for this PR.

text: () => {
throw new Error("NotImplementedException");
},
text: () => new TextDecoder("utf-8").decode(buffer),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of scope for this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-Build-mono community-contribution Indicates that the PR has been added by a community member os-browser Browser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants