Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 18 additions & 21 deletions src/mono/browser/runtime/loader/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,17 @@ export async function mono_download_assets (): Promise<void> {

const instantiate = async (downloadPromise: Promise<AssetEntryInternal>) => {
const asset = await downloadPromise;
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;
}
Comment on lines +189 to +198

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.


if (asset.buffer) {
if (!skipInstantiateByAssetTypes[asset.behavior]) {
mono_assert(asset.buffer && typeof asset.buffer === "object", "asset buffer must be array-like or buffer-like or promise of these");
Expand All @@ -202,24 +213,12 @@ export async function mono_download_assets (): Promise<void> {
runtimeHelpers.instantiate_asset(asset, url, data);
}
} else {
const headersOnly = skipBufferByAssetTypes[asset.behavior];
if (!headersOnly) {
mono_assert(asset.isOptional, "Expected asset to have the downloaded buffer");
if (!skipDownloadsByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) {
loaderHelpers.expected_downloaded_assets_count--;
}
if (!skipInstantiateByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) {
loaderHelpers.expected_instantiated_assets_count--;
}
} else {
if (asset.behavior === "symbols") {
await runtimeHelpers.instantiate_symbols_asset(asset);
cleanupAsset(asset);
}

if (skipBufferByAssetTypes[asset.behavior]) {
++loaderHelpers.actual_downloaded_assets_count;
}
mono_assert(asset.isOptional, "Expected asset to have the downloaded buffer");
if (!skipDownloadsByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) {
loaderHelpers.expected_downloaded_assets_count--;
}
if (!skipInstantiateByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) {
loaderHelpers.expected_instantiated_assets_count--;
}
}
};
Expand Down Expand Up @@ -529,9 +528,7 @@ async function start_asset_download_sources (asset: AssetEntryInternal): Promise
ok: true,
arrayBuffer: () => buffer,
json: () => JSON.parse(new TextDecoder("utf-8").decode(buffer)),
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.

headers: {
get: () => undefined,
}
Expand Down
17 changes: 17 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/ModuleConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,23 @@ public async Task AssetIntegrity()
);
}

[ConditionalFact(typeof(BuildTestBase), nameof(IsMonoRuntime)), TestCategory("bundler-friendly")]
public async Task BufferedAssetsTest()
{
Configuration config = Configuration.Debug;
ProjectInfo info = CopyTestAsset(
config,
aot: false,
TestAsset.WasmBasicTestApp,
"ModuleConfigTests_BufferedAssetsTest",
extraProperties: "<WasmEmitSymbolMap>true</WasmEmitSymbolMap>");
PublishProject(info, config);
await RunForPublishWithWebServer(new BrowserRunOptions(
Configuration: config,
TestScenario: "BufferedAssetsTest"
));
}

[Theory]
[InlineData(false)]
[InlineData(true)]
Expand Down
23 changes: 15 additions & 8 deletions src/mono/wasm/Wasm.Build.Tests/ProjectProviderBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,6 @@ public IReadOnlyDictionary<string, DotNetFileName> FindAndAssertDotnetFiles(

foreach ((string expectedFilename, bool expectFingerprint) in superSet.OrderByDescending(kvp => kvp.Key))
{
string prefix = Path.GetFileNameWithoutExtension(expectedFilename);
string extension = Path.GetExtension(expectedFilename).Substring(1);

dotnetFiles = dotnetFiles
.Where(actualFile =>
{
Expand All @@ -127,7 +124,7 @@ public IReadOnlyDictionary<string, DotNetFileName> FindAndAssertDotnetFiles(
expectFingerprintOnDotnetJs: expectFingerprintOnDotnetJs,
expectFingerprintForThisFile: expectFingerprint))
{
string pattern = $"^{prefix}{s_dotnetVersionHashRegex}{extension}$";
string pattern = GetFingerprintRegexPattern(expectedFilename);
var match = Regex.Match(actualFilename, pattern);
if (!match.Success)
return true;
Expand Down Expand Up @@ -418,6 +415,19 @@ private string[] GetFilesMatchingNameConsideringFingerprinting(string filePath,
public bool ShouldCheckFingerprint(string expectedFilename, bool? expectFingerprintOnDotnetJs, bool expectFingerprintForThisFile)
=> IsFingerprintingEnabled && ((expectedFilename == "dotnet.js" && expectFingerprintOnDotnetJs == true) || expectFingerprintForThisFile);

private static string GetFingerprintRegexPattern(string expectedFilename)
{
const string jsSymbolsSuffix = ".js.symbols";
if (expectedFilename.EndsWith(jsSymbolsSuffix, StringComparison.Ordinal))
{
string prefix = expectedFilename[..^jsSymbolsSuffix.Length];
return $"^{Regex.Escape(prefix)}{s_dotnetVersionHashRegex}js\\.symbols$";
}

string defaultPrefix = Path.GetFileNameWithoutExtension(expectedFilename);
string extension = Path.GetExtension(expectedFilename).Substring(1);
return $"^{Regex.Escape(defaultPrefix)}{s_dotnetVersionHashRegex}{Regex.Escape(extension)}$";
}

public static void AssertRuntimePackPath(string buildOutput, string targetFramework, RuntimeVariant runtimeType = RuntimeVariant.SingleThreaded)
{
Expand Down Expand Up @@ -614,14 +624,11 @@ public BootJsonData AssertBootJson(AssertBundleOptions options)
bool expectFingerprint = knownSet[expectedFilename];
expectedEntries[expectedFilename] = item =>
{
string prefix = Path.GetFileNameWithoutExtension(expectedFilename);
string extension = Path.GetExtension(expectedFilename).Substring(1);

if (ShouldCheckFingerprint(expectedFilename: expectedFilename,
expectFingerprintOnDotnetJs: options.ExpectDotnetJsFingerprinting,
expectFingerprintForThisFile: expectFingerprint))
{
return Regex.Match(item, $"{prefix}{s_dotnetVersionHashRegex}{extension}").Success;
return Regex.Match(item, GetFingerprintRegexPattern(expectedFilename)).Success;
}
else
{
Expand Down
23 changes: 23 additions & 0 deletions src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,26 @@ switch (testCase) {
case "MainWithArgs":
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.

dotnet.withModuleConfig({
onConfigLoaded: (config) => {
Comment thread
elringus marked this conversation as resolved.
const bufferedAssets = [
...config.resources.wasmNative,
...config.resources.assembly,
...config.resources.pdb,
...config.resources.wasmSymbols,
Comment thread
pavelsavara marked this conversation as resolved.
];
Comment on lines +220 to +228

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 +223 to +228

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 +219 to +228
for (const asset of bufferedAssets) {
const url = new URL(`./_framework/${asset.name}`, location.href);
asset.buffer = originalFetch4(url).then(r => {
if (!r.ok) throw new Error(`Failed to fetch buffered asset '${url}': ${r.status} ${r.statusText}`);
return r.arrayBuffer();
});
}
Comment on lines +229 to +235

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.

}
});
break;
}

const { setModuleImports, Module, getAssemblyExports, getConfig, INTERNAL, invokeLibraryInitializers } = await dotnet.create();
Expand Down Expand Up @@ -403,6 +423,9 @@ try {

exit(foundB && retB == 42 ? 0 : 1);

break;
case "BufferedAssetsTest":
await dotnet.runMainAndExit();
break;
default:
console.error(`Unknown test case: ${testCase}`);
Expand Down
Loading