There should be a way to abort wasm compilation
Compilation (and instantiation?) of WebAssembly module could be a resource intensive operation so there should be a way for wasm hosts to abort this step in cases when module is not needed anymore for some reasons.
As for JS hosts, theoretically cancellation methods should be in JS API, but JS doesn't have cancellation mechanism for promises yet. There are AbortController and AbortSignal which are used to abort Fetch. Probably they can be used to abort wasm compilation (passing signal as extra parameter to WebAssembly.compile), but they are part of DOM WHATWG spec, so it's only possible to use them in browsers and as a consequence only in Web API.
Note that Promise and Fetch run on the main thread, whereas Wasm compilation (if asynchronous) can be done in background, only the instantiation is blocking.
Also I'm wondering what happens when an module (while compiling) gets garbage collected.
whereas Wasm compilation (if asynchronous) can be done in background
Yes, but the problem is not main thread blocking, but unnecessary operations (fetch also doesn't block main thread). Also it's related to any host, not just browsers.
Also I'm wondering what happens when an module (while compiling) gets garbage collected.
Good question. I think we can test this case aborting fetch while instantiateStreaming / compileStreaming.
Also I'm wondering what happens when an module (while compiling) gets garbage collected.
In Firefox the JS WasmModule object is a front for an internal Module object which is shared among the threads that have a handle to the module; the object is (atomically) refcounted. When the JS WasmModule object is GC'd it just drops its refcount on the Module, but any ongoing background compilation has a reference to the Module object and will keep it alive until the compilation is finished.
but any ongoing background compilation has a reference to the Module object and will keep it alive until the compilation is finished
Is there any plan to stop the compilation in that case? I don't know how common that situation will be.
Also I'm wondering what happens when an module (while compiling) gets garbage collected.
In Firefox the JS WasmModule object is a front for an internal Module object which is shared among the threads that have a handle to the module; the object is (atomically) refcounted. When the JS WasmModule object is GC'd it just drops its refcount on the Module, but any ongoing background compilation has a reference to the Module object and will keep it alive until the compilation is finished.
V8 does it very similarly, except that compilation does not keep the module alive. We cancel compilation when the ref count drops to zero. But note that the WasmModule is only created when baseline compilation finishes, so up until this point compilation cannot be cancelled because there is a promise to be resolved. So cancellation really only applies to tiering.
If you use the wasm streaming JS APIs, I think this already Just Works. E.g., if you have:
var controller = new AbortController();
WebAssembly.compileStreaming(fetch(url, {signal: controller.signal})).then(...);
then if you controller.abort(), this will cause wasm compilation to fail immediately with an AbortError.
For the ArrayBuffer compilation APIs, if the ArrayBuffer is large enough that cancellation is useful, the streaming APIs should really be used instead, for performance reasons. But technically, you could create your own stream (feeding it from the ArrayBuffer), create a Response from the stream, and then fetch() that Response, supplying an AbortSignal... but that's a bit roundabout :)
@lukewagner this won't work for Node.js and other non-browser environments.
You're right, the streaming APIs are in the Web API, but I'm not sure if the solution is to have wasm's JS API to invent its own duplicate version of AbortController; ideally fetch()/Response/AbortController could be implemented in these non-browser environments, thereby enabling cross-environment portable, efficient streaming wasm compilation. I don't know how politically loaded of a solution that is, though.
Cancellation won't be possible at all until we'll have an API for that in compile and instantiate methods.
(Could we add JS embedding label for the issue?)
We now have at least one precedent of using AbortController outside of DOM spec — Web NFC now also uses it.
Web Locks API also uses AbortController.
Related discussions:
- W3C TAG design principles repo
- TC39 Cancellation proposal repo
- Web NFC repo
- some discussions about
AbortControllerin Node.js repo- Web Locks API
- Timers (+discussion on timers in HTML repo)