-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Update stack switching API to match V8 #17545
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
Conversation
Per v8/v8@ff44012, this moves `returnPromiseOnSuspend` and `suspendOnReturnedPromise` from `Suspender` to `WebAssembly`, and removes the uses of `Asyncify.suspender` from the code.
The CI errors out with:
@fgmccabe @thibaudmichaud Do you have any idea why it complains about the incorrect signature of |
Thanks for working on this! Yes, I know why it complains. The PR seems to be missing a crucial difference of the static API: the export and import functions now expect an additional Here is a before/after comparison with a small example: Before: let suspender = new WebAssembly.Suspender();
let wrapped_import = suspender.suspendOnReturnedPromise(
new WebAssembly.Function({params: [], results: ['i32']}, js_import);
let instance = WebAssembly.instantiate(..., {m: {import: wrapped_import}});
let wrapped_export = suspender.returnPromiseOnSuspend(instance.exports.export);
let promise = wrapped_export(); (module
(import $import "m" "import" (func (result i32)))
(func (export "export") (result i32)
(call $import) ;; Suspend when $import returns a promise
)
) After: let wrapped_import = WebAssembly.suspendOnReturnedPromise(
new WebAssembly.Function({params: [], results: ['i32']}, js_import);
let instance = WebAssembly.instantiate(..., {m: {import: wrapped_import}});
let wrapped_export = WebAssembly.returnPromiseOnSuspend(instance.exports.export);
let promise = wrapped_export(); (module
(import $import "m" "import" (func (param externref) (result i32)))
(func (export "export") (param $suspender externref) (result i32)
(call $import (local.get $suspender)) ;; Suspend $suspender when $import returns a promise
)
) Here I pass the suspender using the local index directly, but I imagine that Emscripten will want to store it in a global for instance, so that it can be loaded from anywhere in the module. The API was implemented in a series of commit in V8, and the one you linked is not the last one. This is the first commit where the implementation is complete: Also FYI, there is another smaller API change in flight: After this change, my example above would look like this: let wrapped_import = new WebAssembly.Function({params: [], results: ['externref']}, js_import, {suspending: 'first'});
let instance = WebAssembly.instantiate(..., {m: {import: wrapped_import}});
let wrapped_export = new WebAssembly.Function({params: [], results: ['externref']}, instance.exports.export, {promising: 'first'});
let promise = wrapped_export(); |
Thanks! I'm not sure on how the signature changed though.. (Your 'before' and 'after' code's signatures look the same despite that the latter is in So now every function needs emscripten/src/library_async.js Lines 104 to 107 in 0e75ea8
|
In the JS code, yes, they are the same. In the wasm module the signatures are different, they take an additional The code you pasted is for the result type. It's an externref so we can return a Promise, that doesn't change. This is unrelated to the Suspender externref argument. BTW the upcoming API change that I mentioned at the end of my previous comment is now in V8: There have been some subtle changes to the typing rules, so here is the full example again for reference: function js_import() { return Promise.resolve(0); }
let wrapped_import = new WebAssembly.Function({params: ['externref'], results: ['i32']}, js_import, {suspending: 'first'});
let instance = WebAssembly.instantiate(..., {m: {import: wrapped_import}});
let wrapped_export = new WebAssembly.Function({params: [], results: ['externref']}, instance.exports.export, {promising: 'first'});
let promise = wrapped_export(); (module
(import $import "m" "import" (func (param externref) (result i32)))
(func (export "export") (param $suspender externref) (result i32)
(call $import (local.get $suspender)) ;; Suspend $suspender when $import returns a promise
)
) Please see the PR for a more detailed explanation and for the general typing rules. |
Thanks @thibaudmichaud for the detailed explanation! Apparently this is more complicated than I expected... We need not only JS API changes but the generated wasm code should change. I'll put this on hold then for the moment. |
I think it has been taken care a while ago by @brendandahl. |
Per
v8/v8@ff44012,
this moves
returnPromiseOnSuspend
andsuspendOnReturnedPromise
fromSuspender
toWebAssembly
, and removes the uses ofAsyncify.suspender
from the code.@fgmccabe @thibaudmichaud