Skip to content

Commit

Permalink
[wasm] Asserts for externaly configured assets, more pendingDownload (#…
Browse files Browse the repository at this point in the history
…79886)

* asserts for assets
* allow to pass .wasm as pendingDownload
  • Loading branch information
pavelsavara authored Dec 29, 2022
1 parent fa7d049 commit 1d15f21
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 25 deletions.
52 changes: 29 additions & 23 deletions src/mono/wasm/runtime/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,30 +67,18 @@ export async function mono_download_assets(): Promise<void> {
// start fetching and instantiating all assets in parallel
for (const a of runtimeHelpers.config.assets!) {
const asset: AssetEntryInternal = a;
mono_assert(typeof asset === "object", "asset must be object");
mono_assert(typeof asset.behavior === "string", "asset behavior must be known string");
mono_assert(typeof asset.name === "string", "asset name must be string");
mono_assert(!asset.resolvedUrl || typeof asset.resolvedUrl === "string", "asset resolvedUrl could be string");
mono_assert(!asset.hash || typeof asset.hash === "string", "asset resolvedUrl could be string");
mono_assert(!asset.pendingDownload || typeof asset.pendingDownload === "object", "asset pendingDownload could be object");
if (!skipInstantiateByAssetTypes[asset.behavior]) {
expected_instantiated_assets_count++;
}
if (!skipDownloadsByAssetTypes[asset.behavior]) {
const headersOnly = skipBufferByAssetTypes[asset.behavior];// `response.arrayBuffer()` can't be called twice. Some usecases are calling it on response in the instantiation.
expected_downloaded_assets_count++;
if (asset.pendingDownload) {
asset.pendingDownloadInternal = asset.pendingDownload;
const waitForExternalData: () => Promise<AssetWithBuffer> = async () => {
const response = await asset.pendingDownloadInternal!.response;
++actual_downloaded_assets_count;
if (!headersOnly) {
asset.buffer = await response.arrayBuffer();
}
return { asset, buffer: asset.buffer };
};
promises_of_assets_with_buffer.push(waitForExternalData());
} else {
const waitForExternalData: () => Promise<AssetWithBuffer> = async () => {
asset.buffer = await start_asset_download_with_retries(asset, !headersOnly);
return { asset, buffer: asset.buffer };
};
promises_of_assets_with_buffer.push(waitForExternalData());
}
promises_of_assets_with_buffer.push(start_asset_download(asset));
}
}
allDownloadsQueued.promise_control.resolve();
Expand All @@ -103,6 +91,7 @@ export async function mono_download_assets(): Promise<void> {
if (assetWithBuffer.buffer) {
if (!skipInstantiateByAssetTypes[asset.behavior]) {
const url = asset.pendingDownloadInternal!.url;
mono_assert(asset.buffer && typeof asset.buffer === "object", "asset buffer must be array or buffer like");
const data = new Uint8Array(asset.buffer!);
asset.pendingDownloadInternal = null as any; // GC
asset.pendingDownload = null as any; // GC
Expand Down Expand Up @@ -146,8 +135,25 @@ export async function mono_download_assets(): Promise<void> {
}
}

export async function start_asset_download(asset: AssetEntryInternal) {
// `response.arrayBuffer()` can't be called twice. Some use-cases are calling it on response in the instantiation.
const headersOnly = skipBufferByAssetTypes[asset.behavior];
if (asset.pendingDownload) {
asset.pendingDownloadInternal = asset.pendingDownload;
const response = await asset.pendingDownloadInternal!.response;
++actual_downloaded_assets_count;
if (!headersOnly) {
asset.buffer = await response.arrayBuffer();
}
return { asset, buffer: asset.buffer };
} else {
asset.buffer = await start_asset_download_with_retries(asset, !headersOnly);
return { asset, buffer: asset.buffer };
}
}

// FIXME: Connection reset is probably the only good one for which we should retry
export async function start_asset_download_with_retries(asset: AssetEntryInternal, downloadData: boolean): Promise<ArrayBuffer | undefined> {
async function start_asset_download_with_retries(asset: AssetEntryInternal, downloadData: boolean): Promise<ArrayBuffer | undefined> {
try {
return await start_asset_download_with_throttle(asset, downloadData);
} catch (err: any) {
Expand Down Expand Up @@ -294,7 +300,7 @@ function resolve_path(asset: AssetEntry, sourcePrefix: string): string {
: asset.name;
}
else if (asset.behavior === "resource") {
const path = asset.culture !== "" ? `${asset.culture}/${asset.name}` : asset.name;
const path = asset.culture && asset.culture !== "" ? `${asset.culture}/${asset.name}` : asset.name;
attemptUrl = assemblyRootFolder
? (assemblyRootFolder + "/" + path)
: path;
Expand Down Expand Up @@ -422,7 +428,7 @@ function _instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array) {
Module.printErr(`MONO_WASM: Error loading ICU asset ${asset.name}`);
}
else if (asset.behavior === "resource") {
cwraps.mono_wasm_add_satellite_assembly(virtualName, asset.culture!, offset!, bytes.length);
cwraps.mono_wasm_add_satellite_assembly(virtualName, asset.culture || "", offset!, bytes.length);
}
endMeasure(mark, MeasuredBlock.instantiateAsset, asset.name);
++actual_instantiated_assets_count;
Expand All @@ -433,7 +439,7 @@ export async function instantiate_wasm_asset(
wasmModuleImports: WebAssembly.Imports,
successCallback: InstantiateWasmSuccessCallback,
): Promise<void> {
mono_assert(pendingAsset && pendingAsset.pendingDownloadInternal, "Can't load dotnet.wasm");
mono_assert(pendingAsset && pendingAsset.pendingDownloadInternal && pendingAsset.pendingDownloadInternal.response, "Can't load dotnet.wasm");
const response = await pendingAsset.pendingDownloadInternal.response;
const contentType = response.headers ? response.headers.get("Content-Type") : undefined;
let compiledInstance: WebAssembly.Instance;
Expand Down
4 changes: 2 additions & 2 deletions src/mono/wasm/runtime/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { init_legacy_exports } from "./net6-legacy/corebindings";
import { cwraps_internal } from "./exports-internal";
import { cwraps_binding_api, cwraps_mono_api } from "./net6-legacy/exports-legacy";
import { CharPtr, InstantiateWasmCallBack, InstantiateWasmSuccessCallback } from "./types/emscripten";
import { instantiate_wasm_asset, mono_download_assets, resolve_asset_path, start_asset_download_with_retries, wait_for_all_assets } from "./assets";
import { instantiate_wasm_asset, mono_download_assets, resolve_asset_path, start_asset_download, wait_for_all_assets } from "./assets";
import { BINDING, MONO } from "./net6-legacy/imports";
import { readSymbolMapFile } from "./logging";
import { mono_wasm_init_diagnostics } from "./diagnostics";
Expand Down Expand Up @@ -445,7 +445,7 @@ async function instantiate_wasm_module(
if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module");
const assetToLoad = resolve_asset_path("dotnetwasm");
// FIXME: this would not apply re-try (on connection reset during download) for dotnet.wasm because we could not download the buffer before we pass it to instantiate_wasm_asset
await start_asset_download_with_retries(assetToLoad, false);
await start_asset_download(assetToLoad);
await beforePreInit.promise;
Module.addRunDependency("instantiate_wasm_module");
await instantiate_wasm_asset(assetToLoad, imports, successCallback);
Expand Down

0 comments on commit 1d15f21

Please sign in to comment.