Skip to content

Commit 60c299c

Browse files
committed
Use async/await instead of promises for wasm loading. NFC
These get lowered away by babel when targetting older engines.
1 parent 1e05a29 commit 60c299c

File tree

4 files changed

+117
-116
lines changed

4 files changed

+117
-116
lines changed

src/preamble.js

+93-100
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ function getBinarySync(file) {
649649
#endif
650650
}
651651

652-
function getBinaryPromise(binaryFile) {
652+
async function getWasmBinary(binaryFile) {
653653
#if !SINGLE_FILE
654654
// If we don't have the binary yet, load it asynchronously using readAsync.
655655
if (!wasmBinary
@@ -658,16 +658,18 @@ function getBinaryPromise(binaryFile) {
658658
#endif
659659
) {
660660
// Fetch the binary using readAsync
661-
return readAsync(binaryFile).then(
662-
(response) => new Uint8Array(/** @type{!ArrayBuffer} */(response)),
663-
// Fall back to getBinarySync if readAsync fails
664-
() => getBinarySync(binaryFile)
665-
);
661+
try {
662+
/** @type{!ArrayBuffer} */
663+
var response = await readAsync(binaryFile);
664+
return new Uint8Array(response);
665+
} catch {
666+
// Fall back to getBinarySync below;
667+
}
666668
}
667669
#endif
668670

669671
// Otherwise, getBinarySync should be able to get it synchronously
670-
return Promise.resolve(getBinarySync(binaryFile));
672+
return getBinarySync(binaryFile);
671673
}
672674

673675
#if LOAD_SOURCE_MAP
@@ -775,56 +777,47 @@ function resetPrototype(constructor, attrs) {
775777
#endif
776778

777779
#if WASM_ASYNC_COMPILATION
778-
function instantiateArrayBuffer(binaryFile, imports) {
780+
async function instantiateArrayBuffer(binaryFile, imports) {
781+
try {
782+
var binary = await getWasmBinary(binaryFile);
783+
var instance = await WebAssembly.instantiate(binary, imports);
779784
#if USE_OFFSET_CONVERTER
780-
var savedBinary;
785+
// wasmOffsetConverter needs to be assigned before calling resolve.
786+
// See comments below in instantiateAsync.
787+
wasmOffsetConverter = new WasmOffsetConverter(binary, instance.module);
781788
#endif
782-
return new Promise((resolve, reject) => {
783-
getBinaryPromise(binaryFile).then((binary) => {
784-
#if USE_OFFSET_CONVERTER
785-
savedBinary = binary;
786-
#endif
787-
return WebAssembly.instantiate(binary, imports);
788-
#if USE_OFFSET_CONVERTER
789-
}).then((instance) => {
790-
// wasmOffsetConverter needs to be assigned before calling resolve.
791-
// See comments below in instantiateAsync.
792-
wasmOffsetConverter = new WasmOffsetConverter(savedBinary, instance.module);
793-
return instance;
794-
#endif
795-
}).then(resolve, (reason) => {
796-
err(`failed to asynchronously prepare wasm: ${reason}`);
797-
789+
return instance;
790+
} catch (reason) {
791+
err(`failed to asynchronously prepare wasm: ${reason}`);
798792
#if WASM == 2
799793
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
800-
if (typeof location != 'undefined') {
801-
#endif
802-
// WebAssembly compilation failed, try running the JS fallback instead.
803-
var search = location.search;
804-
if (search.indexOf('_rwasm=0') < 0) {
805-
location.href += (search ? search + '&' : '?') + '_rwasm=0';
806-
// Return here to avoid calling abort() below. The application
807-
// still has a chance to start successfully do we don't want to
808-
// trigger onAbort or onExit handlers.
809-
return;
810-
}
811-
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
794+
if (typeof location != 'undefined') {
795+
#endif
796+
// WebAssembly compilation failed, try running the JS fallback instead.
797+
var search = location.search;
798+
if (search.indexOf('_rwasm=0') < 0) {
799+
location.href += (search ? search + '&' : '?') + '_rwasm=0';
800+
// Return here to avoid calling abort() below. The application
801+
// still has a chance to start successfully do we don't want to
802+
// trigger onAbort or onExit handlers.
803+
return;
812804
}
805+
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
806+
}
813807
#endif
814808
#endif // WASM == 2
815809

816810
#if ASSERTIONS
817-
// Warn on some common problems.
818-
if (isFileURI(wasmBinaryFile)) {
819-
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`);
820-
}
811+
// Warn on some common problems.
812+
if (isFileURI(wasmBinaryFile)) {
813+
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`);
814+
}
821815
#endif
822-
abort(reason);
823-
});
824-
});
816+
abort(reason);
817+
}
825818
}
826819

827-
function instantiateAsync(binary, binaryFile, imports) {
820+
async function instantiateAsync(binary, binaryFile, imports) {
828821
#if !SINGLE_FILE
829822
if (!binary &&
830823
typeof WebAssembly.instantiateStreaming == 'function' &&
@@ -843,56 +836,44 @@ function instantiateAsync(binary, binaryFile, imports) {
843836
!ENVIRONMENT_IS_NODE &&
844837
#endif
845838
typeof fetch == 'function') {
846-
return new Promise((resolve) => {
847-
fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}}).then((response) => {
848-
// Suppress closure warning here since the upstream definition for
849-
// instantiateStreaming only allows Promise<Repsponse> rather than
850-
// an actual Response.
851-
// TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed.
852-
/** @suppress {checkTypes} */
853-
var result = WebAssembly.instantiateStreaming(response, imports);
854-
839+
try {
840+
var response = fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}});
855841
#if USE_OFFSET_CONVERTER
856-
// We need the wasm binary for the offset converter. Clone the response
857-
// in order to get its arrayBuffer (cloning should be more efficient
858-
// than doing another entire request).
859-
// (We must clone the response now in order to use it later, as if we
860-
// try to clone it asynchronously lower down then we will get a
861-
// "response was already consumed" error.)
862-
var clonedResponsePromise = response.clone().arrayBuffer();
863-
#endif
864-
865-
result.then(
842+
// We need the wasm binary for the offset converter. Clone the response
843+
// in order to get its arrayBuffer (cloning should be more efficient
844+
// than doing another entire request).
845+
// (We must clone the response now in order to use it later, as if we
846+
// try to clone it asynchronously lower down then we will get a
847+
// "response was already consumed" error.)
848+
var clonedResponse = (await response).clone();
849+
#endif
850+
var result = WebAssembly.instantiateStreaming(response, imports);
866851
#if USE_OFFSET_CONVERTER
867-
(instantiationResult) => {
868-
// When using the offset converter, we must interpose here. First,
869-
// the instantiation result must arrive (if it fails, the error
870-
// handling later down will handle it). Once it arrives, we can
871-
// initialize the offset converter. And only then is it valid to
872-
// call receiveInstantiationResult, as that function will use the
873-
// offset converter (in the case of pthreads, it will create the
874-
// pthreads and send them the offsets along with the wasm instance).
875-
876-
clonedResponsePromise.then((arrayBufferResult) => {
877-
wasmOffsetConverter = new WasmOffsetConverter(new Uint8Array(arrayBufferResult), instantiationResult.module);
878-
resolve(instantiationResult);
879-
},
880-
(reason) => err(`failed to initialize offset-converter: ${reason}`)
881-
);
882-
},
852+
// When using the offset converter, we must interpose here. First,
853+
// the instantiation result must arrive (if it fails, the error
854+
// handling later down will handle it). Once it arrives, we can
855+
// initialize the offset converter. And only then is it valid to
856+
// call receiveInstantiationResult, as that function will use the
857+
// offset converter (in the case of pthreads, it will create the
858+
// pthreads and send them the offsets along with the wasm instance).
859+
var instantiationResult = await result;
860+
var arrayBufferResult = await clonedResponse.arrayBuffer();
861+
try {
862+
wasmOffsetConverter = new WasmOffsetConverter(new Uint8Array(arrayBufferResult), instantiationResult.module);
863+
} catch (reason) {
864+
err(`failed to initialize offset-converter: ${reason}`);
865+
}
866+
return instantiationResult;
883867
#else
884-
resolve,
885-
#endif
886-
(reason) => {
887-
// We expect the most common failure cause to be a bad MIME type for the binary,
888-
// in which case falling back to ArrayBuffer instantiation should work.
889-
err(`wasm streaming compile failed: ${reason}`);
890-
err('falling back to ArrayBuffer instantiation');
891-
return resolve(instantiateArrayBuffer(binaryFile, imports));
892-
}
893-
);
894-
});
895-
});
868+
return await result;
869+
#endif
870+
} catch (reason) {
871+
// We expect the most common failure cause to be a bad MIME type for the binary,
872+
// in which case falling back to ArrayBuffer instantiation should work.
873+
err(`wasm streaming compile failed: ${reason}`);
874+
err('falling back to ArrayBuffer instantiation');
875+
// fall back of instantiateArrayBuffer below
876+
};
896877
}
897878
#endif
898879
return instantiateArrayBuffer(binaryFile, imports);
@@ -938,7 +919,13 @@ function getWasmImports() {
938919

939920
// Create the wasm instance.
940921
// Receives the wasm imports, returns the exports.
922+
#if WASM_ASYNC_COMPILATION
923+
// Funnily enough in JS the `async` keyword has to be on the same line as the
924+
// function keyword.
925+
async function createWasm() {
926+
#else
941927
function createWasm() {
928+
#endif
942929
// Load the wasm module and create an instance of using native support in the JS engine.
943930
// handle a generated wasm instance, receiving its exports and
944931
// performing other necessary setup
@@ -1106,17 +1093,23 @@ function createWasm() {
11061093
#if RUNTIME_DEBUG
11071094
dbg('asynchronously preparing wasm');
11081095
#endif
1109-
instantiateAsync(wasmBinary, wasmBinaryFile, info).then(receiveInstantiationResult)
11101096
#if MODULARIZE
1111-
// If instantiation fails, reject the module ready promise.
1112-
.catch(readyPromiseReject)
1097+
try {
11131098
#endif
1114-
;
1099+
var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info);
1100+
receiveInstantiationResult(result);
11151101
#if LOAD_SOURCE_MAP
1116-
getSourceMapPromise().then(receiveSourceMapJSON);
1102+
receiveSourceMapJSON(await getSourceMapPromise());
11171103
#endif
1118-
return {}; // no exports yet; we'll fill them in later
1119-
#else
1104+
return result;
1105+
#if MODULARIZE
1106+
} catch (e) {
1107+
// If instantiation fails, reject the module ready promise.
1108+
readyPromiseReject(e);
1109+
throw e;
1110+
}
1111+
#endif
1112+
#else // WASM_ASYNC_COMPILATION
11201113
var result = instantiateSync(wasmBinaryFile, info);
11211114
#if PTHREADS || MAIN_MODULE
11221115
return receiveInstance(result[0], result[1]);
@@ -1126,7 +1119,7 @@ function createWasm() {
11261119
// When the regression is fixed, we can remove this if/else.
11271120
return receiveInstance(result[0]);
11281121
#endif
1129-
#endif
1122+
#endif // WASM_ASYNC_COMPILATION
11301123
}
11311124

11321125
#if !WASM_BIGINT

test/test_browser.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5519,7 +5519,7 @@ def test(args, expect_fail):
55195519
if expect_fail:
55205520
js = read_file('a.out.js')
55215521
create_file('a.out.js', 'let origFetch = fetch; fetch = undefined;\n' + js)
5522-
return self.run_browser('a.out.html', '/report_result?exception:fetch is not a function')
5522+
return self.run_browser('a.out.html', '/report_result?abort:both async and sync fetching of the wasm failed')
55235523
else:
55245524
return self.run_browser('a.out.html', '/report_result?exit:42')
55255525

test/test_other.py

+19-14
Original file line numberDiff line numberDiff line change
@@ -2955,20 +2955,25 @@ def test_m_mm(self):
29552955
self.assertNotContained('error', proc.stderr)
29562956

29572957
@uses_canonical_tmp
2958-
def test_emcc_debug_files(self):
2959-
for opts in (0, 1, 2, 3):
2960-
for debug in (None, '1', '2'):
2961-
print(opts, debug)
2962-
if os.path.exists(self.canonical_temp_dir):
2963-
shutil.rmtree(self.canonical_temp_dir)
2964-
2965-
with env_modify({'EMCC_DEBUG': debug}):
2966-
self.run_process([EMCC, test_file('hello_world.c'), '-O' + str(opts)], stderr=PIPE)
2967-
if debug is None:
2968-
self.assertFalse(os.path.exists(self.canonical_temp_dir))
2969-
else:
2970-
print(sorted(os.listdir(self.canonical_temp_dir)))
2971-
self.assertExists(os.path.join(self.canonical_temp_dir, 'emcc-03-original.js'))
2958+
@parameterized({
2959+
'O0': ('-O0',),
2960+
'O1': ('-O1',),
2961+
'O2': ('-O2',),
2962+
'O3': ('-O3',),
2963+
})
2964+
def test_emcc_debug_files(self, opt):
2965+
for debug in (None, '1', '2'):
2966+
print('debug =', debug)
2967+
if os.path.exists(self.canonical_temp_dir):
2968+
shutil.rmtree(self.canonical_temp_dir)
2969+
2970+
with env_modify({'EMCC_DEBUG': debug}):
2971+
self.run_process([EMCC, test_file('hello_world.c'), opt], stderr=PIPE)
2972+
if debug is None:
2973+
self.assertFalse(os.path.exists(self.canonical_temp_dir))
2974+
else:
2975+
print(sorted(os.listdir(self.canonical_temp_dir)))
2976+
self.assertExists(os.path.join(self.canonical_temp_dir, 'emcc-03-original.js'))
29722977

29732978
def test_debuginfo_line_tables_only(self):
29742979
def test(do_compile):

tools/emscripten.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,10 @@ def create_module(receiving, metadata, global_exports, library_symbols):
989989
module.append('var wasmImports = %s;\n' % sending)
990990

991991
if not settings.MINIMAL_RUNTIME:
992-
module.append("var wasmExports = createWasm();\n")
992+
if settings.WASM_ASYNC_COMPILATION:
993+
module.append("var wasmExports;\ncreateWasm();\n")
994+
else:
995+
module.append("var wasmExports = createWasm();\n")
993996

994997
module.append(receiving)
995998
if settings.SUPPORT_LONGJMP == 'emscripten' or not settings.DISABLE_EXCEPTION_CATCHING:

0 commit comments

Comments
 (0)