Support Asyncify + Try-Catch [Can't build web-gphoto2 with -fwasm-exceptions instead of -fexceptions]
web-gphoto2 builds with pthreads, Asyncify, exceptions and LTO, and I'm not sure which combo is specifically problematic here, but the end result is that it crashes when trying to switch from -fexceptions to -fwasm-exceptions:
unexpected expression type
UNREACHABLE executed at /b/s/w/ir/cache/builder/emscripten-releases/binaryen/src/passes/Asyncify.cpp:998!
emcc: error: '/emsdk/upstream/bin/wasm-opt --strip-dwarf --post-emscripten -Os --low-memory-unused --asyncify [email protected]_*,env.__call_main,env.emscripten_sleep,env.emscripten_wget,env.emscripten_wget_data,env.emscripten_idb_load,env.emscripten_idb_store,env.emscripten_idb_delete,env.emscripten_idb_exists,env.emscripten_idb_load_blob,env.emscripten_idb_store_blob,env.SDL_Delay,env.emscripten_scan_registers,env.emscripten_lazy_load_code,env.emscripten_fiber_swap,wasi_snapshot_preview1.fd_sync,env.__wasi_fd_sync,env._emval_await,env._dlopen_js,env.__asyncjs__* --zero-filled-memory --strip-debug --strip-producers ui/libapi.wasm -o ui/libapi.wasm --mvp-features --enable-threads --enable-mutable-globals --enable-bulk-memory --enable-sign-ext --enable-exception-handling' failed (received SIGABRT (-6))
A branch that's failing can be checked out from here: https://github.com/GoogleChromeLabs/web-gphoto2/tree/fwasm-exceptions. It should be pretty reproducible as it uses Docker, so all you need to do is run ./build.sh in the checkout folder.
cc @kripken @aheejin
I think that is this:
https://github.com/WebAssembly/binaryen/blob/060442225165d0423d06ea33ab865e850b54f61b/src/passes/Asyncify.cpp#L995-L999
So the issue is supporting the Try control flow structure in that pass. It needs special handling for each one since it needs to be able to resume execution back into the middle.
For Try, the hard part would be to get back into the catch when rewinding... maybe we could construct and throw another exception just to get there? Or maybe we should move the code out of the catch, and guard it with a condition, so it can be reached either from the catch or from a resume, something like that.
@RReverser did you find a work around (other than just sticking with -fexceptions) for this?
This code here seems sufficient enough to reproduce the problem:
#include <iostream>
#include <stdexcept>
__attribute__((import_module("env"), import_name("external_async_function")))
void external_async_function();
int main() {
try {
throw std::invalid_argument("test");
}
catch(const std::invalid_argument& e) {
std::cout << "caught" << std::endl;
}
std::cout << "before" << std::endl;
external_async_function();
std::cout << "after" << std::endl;
return 0;
}
compiling with: em++ -fwasm-exceptions -s WARN_ON_UNDEFINED_SYMBOLS=0 -s ASYNCIFY -s 'ASYNCIFY_IMPORTS=["external_async_function"]' index.cpp -o index.html
- wasm-opt version: 103 (version_103-24-g62d83d5fc)
- emcc version: 3.0.1 (5ebe1d421445fa9a4a02c1efc6d42bde3ac90da2)
Tested the same code with the latest versions (as follows) but I seem to hit the same error.
- wasm-opt version: 106 (version_106-10-g22d24fda9)
- emcc version: 3.1.8 (3ff7eff373d31d8c0179895165462019221f192e)
Yes, no work has been done on this so far. The work that would need to be done is mentioned in https://github.com/WebAssembly/binaryen/issues/4470#issuecomment-1018733852
@RReverser this might be possible soon: https://github.com/WebAssembly/binaryen/pull/5475
@allsey87 fwiw I am porting a game of my own from desktop to wasm and I would like to use wasm exceptions but, so far, I will also need ASYNCIFY. So this support would be great.