Skip to content

Commit

Permalink
Use async/await instead of promises for wasm loading. NFC (#23068)
Browse files Browse the repository at this point in the history
These get lowered away by babel when targetting older engines.

Followup to #23066, with code size savings.
  • Loading branch information
sbc100 authored Dec 10, 2024
1 parent ea87423 commit af2da32
Show file tree
Hide file tree
Showing 86 changed files with 193 additions and 199 deletions.
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();
#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

0 comments on commit af2da32

Please sign in to comment.