Skip to content

Use async/await instead of promises for wasm loading. NFC #23068

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ See docs/process.md for more on how version tagging works.
- The file system was updated to independently track atime, mtime and ctime
instead of using the same time for all three. (#22998)
- The minimum supported chrome version was bumped from 32 to 33. (#23077)
- Emscripten-generated code will now use async/await internally when loading
the Wasm module. This will be lowered away by babel when targeting older
browsers. (#23068)

3.1.73 - 11/28/24
-----------------
Expand Down
187 changes: 85 additions & 102 deletions src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ function getBinarySync(file) {
#endif
}

function getBinaryPromise(binaryFile) {
async function getWasmBinary(binaryFile) {
#if !SINGLE_FILE
// If we don't have the binary yet, load it asynchronously using readAsync.
if (!wasmBinary
Expand All @@ -656,16 +656,17 @@ function getBinaryPromise(binaryFile) {
#endif
) {
// Fetch the binary using readAsync
return readAsync(binaryFile).then(
(response) => new Uint8Array(/** @type{!ArrayBuffer} */(response)),
// Fall back to getBinarySync if readAsync fails
() => getBinarySync(binaryFile)
);
try {
var response = await readAsync(binaryFile);
return new Uint8Array(response);
} catch {
// Fall back to getBinarySync below;
}
}
#endif

// Otherwise, getBinarySync should be able to get it synchronously
return Promise.resolve(getBinarySync(binaryFile));
return getBinarySync(binaryFile);
}

#if LOAD_SOURCE_MAP
Expand Down Expand Up @@ -773,56 +774,47 @@ function resetPrototype(constructor, attrs) {
#endif

#if WASM_ASYNC_COMPILATION
function instantiateArrayBuffer(binaryFile, imports) {
async function instantiateArrayBuffer(binaryFile, imports) {
try {
var binary = await getWasmBinary(binaryFile);
var instance = await WebAssembly.instantiate(binary, imports);
#if USE_OFFSET_CONVERTER
var savedBinary;
// wasmOffsetConverter needs to be assigned before calling resolve.
// See comments below in instantiateAsync.
wasmOffsetConverter = new WasmOffsetConverter(binary, instance.module);
#endif
return new Promise((resolve, reject) => {
getBinaryPromise(binaryFile).then((binary) => {
#if USE_OFFSET_CONVERTER
savedBinary = binary;
#endif
return WebAssembly.instantiate(binary, imports);
#if USE_OFFSET_CONVERTER
}).then((instance) => {
// wasmOffsetConverter needs to be assigned before calling resolve.
// See comments below in instantiateAsync.
wasmOffsetConverter = new WasmOffsetConverter(savedBinary, instance.module);
return instance;
#endif
}).then(resolve, (reason) => {
err(`failed to asynchronously prepare wasm: ${reason}`);

return instance;
} catch (reason) {
err(`failed to asynchronously prepare wasm: ${reason}`);
#if WASM == 2
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
if (typeof location != 'undefined') {
#endif
// WebAssembly compilation failed, try running the JS fallback instead.
var search = location.search;
if (search.indexOf('_rwasm=0') < 0) {
location.href += (search ? search + '&' : '?') + '_rwasm=0';
// Return here to avoid calling abort() below. The application
// still has a chance to start successfully do we don't want to
// trigger onAbort or onExit handlers.
return;
}
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
if (typeof location != 'undefined') {
#endif
// WebAssembly compilation failed, try running the JS fallback instead.
var search = location.search;
if (search.indexOf('_rwasm=0') < 0) {
// Reload the page with the `_rwasm=0` argument
location.href += (search ? search + '&' : '?') + '_rwasm=0';
// Return a promise that never resolves. We don't want to
// call abort below, or return an error to our caller.
return new Promise(() => {});
}
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
}
#endif
#endif // WASM == 2

#if ASSERTIONS
// Warn on some common problems.
if (isFileURI(wasmBinaryFile)) {
err(`warning: Loading from a file URI (${wasmBinaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`);
}
// Warn on some common problems.
if (isFileURI(wasmBinaryFile)) {
err(`warning: Loading from a file URI (${wasmBinaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`);
}
#endif
abort(reason);
});
});
abort(reason);
}
}

function instantiateAsync(binary, binaryFile, imports) {
async function instantiateAsync(binary, binaryFile, imports) {
#if !SINGLE_FILE
if (!binary &&
typeof WebAssembly.instantiateStreaming == 'function' &&
Expand All @@ -841,56 +833,41 @@ function instantiateAsync(binary, binaryFile, imports) {
!ENVIRONMENT_IS_NODE &&
#endif
typeof fetch == 'function') {
return new Promise((resolve) => {
fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}}).then((response) => {
// Suppress closure warning here since the upstream definition for
// instantiateStreaming only allows Promise<Repsponse> rather than
// an actual Response.
// TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed.
/** @suppress {checkTypes} */
var result = WebAssembly.instantiateStreaming(response, imports);

try {
var response = fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}});
#if USE_OFFSET_CONVERTER
// We need the wasm binary for the offset converter. Clone the response
// in order to get its arrayBuffer (cloning should be more efficient
// than doing another entire request).
// (We must clone the response now in order to use it later, as if we
// try to clone it asynchronously lower down then we will get a
// "response was already consumed" error.)
var clonedResponsePromise = response.clone().arrayBuffer();
#endif

result.then(
// We need the wasm binary for the offset converter. Clone the response
// in order to get its arrayBuffer (cloning should be more efficient
// than doing another entire request).
// (We must clone the response now in order to use it later, as if we
// try to clone it asynchronously lower down then we will get a
// "response was already consumed" error.)
var clonedResponse = (await response).clone();
Copy link
Member

Choose a reason for hiding this comment

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

Is it perhaps more idiomatic to have the await on line 837? (var x = await fetch(..)) like line 779 etc.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We could but then we would have an extra await there in the non USE_OFFSET_CONVERTER path. For the normal path the response can be passed as a Promise of a Response (i.e. we don't need to await it it in the normal path).

#endif
var instantiationResult = await WebAssembly.instantiateStreaming(response, imports);
#if USE_OFFSET_CONVERTER
(instantiationResult) => {
// When using the offset converter, we must interpose here. First,
// the instantiation result must arrive (if it fails, the error
// handling later down will handle it). Once it arrives, we can
// initialize the offset converter. And only then is it valid to
// call receiveInstantiationResult, as that function will use the
// offset converter (in the case of pthreads, it will create the
// pthreads and send them the offsets along with the wasm instance).

clonedResponsePromise.then((arrayBufferResult) => {
wasmOffsetConverter = new WasmOffsetConverter(new Uint8Array(arrayBufferResult), instantiationResult.module);
resolve(instantiationResult);
},
(reason) => err(`failed to initialize offset-converter: ${reason}`)
);
},
#else
resolve,
#endif
(reason) => {
// We expect the most common failure cause to be a bad MIME type for the binary,
// in which case falling back to ArrayBuffer instantiation should work.
err(`wasm streaming compile failed: ${reason}`);
err('falling back to ArrayBuffer instantiation');
return resolve(instantiateArrayBuffer(binaryFile, imports));
}
);
});
});
// When using the offset converter, we must interpose here. First,
// the instantiation result must arrive (if it fails, the error
// handling later down will handle it). Once it arrives, we can
// initialize the offset converter. And only then is it valid to
// call receiveInstantiationResult, as that function will use the
// offset converter (in the case of pthreads, it will create the
// pthreads and send them the offsets along with the wasm instance).
var arrayBufferResult = await clonedResponse.arrayBuffer();
try {
wasmOffsetConverter = new WasmOffsetConverter(new Uint8Array(arrayBufferResult), instantiationResult.module);
} catch (reason) {
err(`failed to initialize offset-converter: ${reason}`);
}
#endif
return instantiationResult;
} catch (reason) {
// We expect the most common failure cause to be a bad MIME type for the binary,
// in which case falling back to ArrayBuffer instantiation should work.
err(`wasm streaming compile failed: ${reason}`);
err('falling back to ArrayBuffer instantiation');
// fall back of instantiateArrayBuffer below
};
}
#endif
return instantiateArrayBuffer(binaryFile, imports);
Expand Down Expand Up @@ -936,7 +913,7 @@ function getWasmImports() {

// Create the wasm instance.
// Receives the wasm imports, returns the exports.
function createWasm() {
{{{ asyncIf(WASM_ASYNC_COMPILATION) }}} function createWasm() {
// Load the wasm module and create an instance of using native support in the JS engine.
// handle a generated wasm instance, receiving its exports and
// performing other necessary setup
Expand Down Expand Up @@ -1104,17 +1081,23 @@ function createWasm() {
#if RUNTIME_DEBUG
dbg('asynchronously preparing wasm');
#endif
instantiateAsync(wasmBinary, wasmBinaryFile, info).then(receiveInstantiationResult)
#if MODULARIZE
// If instantiation fails, reject the module ready promise.
.catch(readyPromiseReject)
try {
#endif
;
var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info);
receiveInstantiationResult(result);
#if LOAD_SOURCE_MAP
getSourceMapPromise().then(receiveSourceMapJSON);
receiveSourceMapJSON(await getSourceMapPromise());
#endif
return {}; // no exports yet; we'll fill them in later
#else
return result;
#if MODULARIZE
} catch (e) {
// If instantiation fails, reject the module ready promise.
readyPromiseReject(e);
return;
}
#endif
#else // WASM_ASYNC_COMPILATION
var result = instantiateSync(wasmBinaryFile, info);
#if PTHREADS || MAIN_MODULE
return receiveInstance(result[0], result[1]);
Expand All @@ -1124,7 +1107,7 @@ function createWasm() {
// When the regression is fixed, we can remove this if/else.
return receiveInstance(result[0]);
#endif
#endif
#endif // WASM_ASYNC_COMPILATION
}

#if !WASM_BIGINT
Expand Down
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_ctors1.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8592
8576
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_ctors1.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
21002
20969
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_ctors2.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8578
8560
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_ctors2.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20969
20937
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_except.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9626
9614
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_except.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24845
24814
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_except_wasm.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8562
8543
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_except_wasm.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20895
20863
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8562
8543
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20895
20863
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_lto.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8490
8475
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_lto.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20580
20548
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_mangle.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9629
9613
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_mangle.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24845
24814
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_noexcept.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8592
8576
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_noexcept.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
21002
20969
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_wasmfs.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3865
3836
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_cxx_wasmfs.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8639
8606
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_files_js_fs.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7730
7710
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_files_js_fs.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18909
18876
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_files_wasmfs.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2941
2915
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_files_wasmfs.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6244
6214
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_O0.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8043
8034
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_O0.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
21457
21479
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_O1.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2788
2785
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_O1.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7021
7004
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_O2.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2462
2434
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_O2.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4984
4955
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_O3.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2380
2346
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_O3.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4830
4802
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_Os.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2380
2346
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_Os.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4830
4802
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_Oz.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2359
2328
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_Oz.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4797
4769
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_dylink.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6246
6227
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_dylink.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
13767
13729
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1736
1721
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3687
3662
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_wasmfs.gzsize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2380
2346
2 changes: 1 addition & 1 deletion test/other/codesize/test_codesize_hello_wasmfs.jssize
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4830
4802
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1942
1920
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4064
4040
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1976
1957
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4111
4087
Loading
Loading