Skip to content
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

Add ASYNCIFY+JSPI support to MINIMAL_RUNTIME build mode. #22501

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
59 changes: 39 additions & 20 deletions src/postamble_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,50 @@
{{{ exportRuntime() }}}

#if HAS_MAIN // Only if user is exporting a C main(), we will generate a run() function that can be used to launch main.
function run() {
#if MEMORYPROFILER
emscriptenMemoryProfiler.onPreloadComplete();
#endif

<<< ATMAINS >>>

#if PROXY_TO_PTHREAD
// User requested the PROXY_TO_PTHREAD option, so call a stub main which
// pthread_create()s a new thread that will call the user's real main() for
// the application.
var ret = __emscripten_proxy_main();
#else
var ret = _main();

#if EXIT_RUNTIME
function exitRuntime(ret) {
callRuntimeCallbacks(__ATEXIT__);
<<< ATEXITS >>>
#if PTHREADS
PThread.terminateAllThreads();
#endif

#endif

#if EXIT_RUNTIME

#if ASSERTIONS
runtimeExited = true;
#endif

_proc_exit(ret);

#if STACK_OVERFLOW_CHECK
checkStackCookie();
#endif
}
#endif

function run() {
#if MEMORYPROFILER
emscriptenMemoryProfiler.onPreloadComplete();
#endif
#endif // PROXY_TO_PTHREAD

<<< ATMAINS >>>

#if PROXY_TO_PTHREAD
// User requested the PROXY_TO_PTHREAD option, so call a stub main which
// pthread_create()s a new thread that will call the user's real main() for
// the application.
__emscripten_proxy_main();
#elif ASYNCIFY == 2 && EXIT_RUNTIME
// In JSPI-enabled build mode, the main() function will return a Promise,
// which resolves to the process exit code.
_main().then(exitRuntime);
#elif EXIT_RUNTIME
// In regular exitRuntime mode, exit with the given return code from main().
exitRuntime(_main());
#else
// Run a persistent (never-exiting) application starting at main().
_main();
#endif

#if STACK_OVERFLOW_CHECK
checkStackCookie();
Expand Down Expand Up @@ -101,6 +112,10 @@ function loadModule() {
assignWasmImports();
#endif

#if ASYNCIFY
Asyncify.instrumentWasmImports(wasmImports);
#endif

var imports = {
#if MINIFY_WASM_IMPORTED_MODULES
'a': wasmImports,
Expand Down Expand Up @@ -138,7 +153,7 @@ if (!Module['wasm']) throw 'Must load WebAssembly Module in to variable Module.w
WebAssembly.instantiate(Module['wasm'], imports).then((output) => {
#endif

#if !LibraryManager.has('library_exports.js')
#if !LibraryManager.has('library_exports.js') && ASYNCIFY != 1
// If not using the emscripten_get_exported_function() API, keep the
// `wasmExports` variable in local scope to this instantiate function to save
// code size. (otherwise access it without to export it to outer scope)
Expand Down Expand Up @@ -169,6 +184,10 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => {
wasmExports = output.instance.exports;
#endif

#if ASYNCIFY
wasmExports = Asyncify.instrumentWasmExports(wasmExports);
#endif

#if MEMORY64 || CAN_ADDRESS_2GB
wasmExports = applySignatureConversions(wasmExports);
#endif
Expand Down
7 changes: 7 additions & 0 deletions src/preamble_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@ function assert(condition, text) {
}
#endif

#if ASYNCIFY == 1 // ASYNCIFY-mode requires checking ABORT variable to avoid operating if code has aborted during an unwind
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this a debug feature or do we need to add this new variable even in release builds?

I worry that this makes the feature matrix even more complicated and there could be other places in the codebase that deal with ABORT that need to be changes now that ABORT does exist undef MINIMAL_RUNTIME but only with ASYNCIFY is enabled.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added that variable to help places like this and this to compile.

There seem to be places that call to it in library_async.js: https://github.com/emscripten-core/emscripten/blob/main/src/library_async.js#L18 so looks like in ASYNCIFY==1 mode we cannot avoid adding ABORT in the build. In ASYNCIFY==2 mode, maybe we could.

Overall, I think the support would be ok to be expanded incrementally via proof by test cases.

var ABORT = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems like this relates to ASYNCIFY == 1 but the PR title talks about JSPI. Does this change cover both?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Err, yes. Updated the title to clarify that this PR addresses both ASYNCIFY and JSPI.

#endif

/** @param {string|number=} what */
function abort(what) {
#if ASYNCIFY == 1
ABORT = 1;
#endif
throw {{{ ASSERTIONS ? 'new Error(what)' : 'what' }}};
}

Expand Down
2 changes: 2 additions & 0 deletions test/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3153,8 +3153,10 @@ def test_cocos2d_hello(self):

@parameterized({
'asyncify': (['-sASYNCIFY=1'],),
'asyncify_minimal_runtime': (['-sMINIMAL_RUNTIME', '-sASYNCIFY=1'],),
'jspi': (['-sASYNCIFY=2', '-Wno-experimental'],),
'jspi_wasm_bigint': (['-sASYNCIFY=2', '-sWASM_BIGINT', '-Wno-experimental'],),
'jspi_wasm_bigint_minimal_runtime': (['-sMINIMAL_RUNTIME', '-sASYNCIFY=2', '-sWASM_BIGINT', '-Wno-experimental'],),
})
def test_async(self, args):
if is_jspi(args) and not is_chrome():
Expand Down
Loading