-
Notifications
You must be signed in to change notification settings - Fork 268
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
Ship the JSPI kitchen-sink build to Chrome users #134
Comments
JSPI is available in Node.js behind the Here's some notes I took to find that flag:
It's available in Node 17, 18, 19, and 20. Node 16 exists with a |
I tried:
(not all of these functions are needed but I just wanted to get something working) And ran
And got this error:
Turns out
And got one step further:
Seems like an error in a dynamic call, so I added
But I'm not sure if that was a good step, the error now is:
I am running on latest emsdk as of today, which wraps the imports in: imports[x2] = original = new WebAssembly.Function(type, original, {
suspending: "first"
}); And the exports in: return new WebAssembly.Function({
parameters,
results: ["externref"]
}, original, {
promising: "first"
}); |
I'm stuck at this point and the JSPI API is still experimental – let's revisit this once the API is stable. |
@adamziel is there a short version of what |
@dmsnell pretty much yes – it rewrites these functions as a continuable state machine. When the async call is made, it saves the call stack and sets a global flag to make all the functions on that call stack short-circuit. Then it synchronously returns. When the async call is finished, it restores the call stack, sets other global flags, and continues right after the async call. Note that we need to use |
Related: #404 |
JSPI seems to be now available via Origin Trials. I wonder if Playground should ship JSPI code for Chrome and Asyncify code for other browsers. It would be a maintenance burden for a while, but it would get a lot more stable in Chrome. CC @bgrgicak |
The issue of different browsers is likely to be a temporary phenomenon. E.g., Mozilla is already working on their implementation of JSPI in Firefox. |
Let's explore switching to JSPI for the Node.js version of Playground as it would solve a lot of the "null function or function signature mismatch" issues. A few questions to answer:
cc @brandonpayton – would you look into that next? Also CC @bgrgicak – let's hold on with fixing these one-off "null function or function signature mismatch" errors until we can confirm or reject the JSPI usage in the short term. They take a lot of time to fix and that time is not a good long-term investment considering the new API will solve it all in one go. Also CC @mho22 as that's relevant to your libcurl explorations. |
A couple of comments:
I hope that this helps in understanding the current status of JSPI. |
Webassembly indicates that The last |
Resource about feature flags – sometimes you use Chrome flags, Node flags, V8 flags – I'm confused which is which, but maybe one of those listed there would work https://webassembly.org/features/ |
I am planning to look at this next, starting with testing a simple C program with no Playground involved. From @adamziel:
|
I got frustrated with an Asyncify error and spent some time exploring this again and writing up some notes. The last time I failed, I couldn't make it past the
Prep workInstall Emscripten Create a simple #include <emscripten.h>
#include <stdlib.h>
#include <stdio.h>
unsigned int async_call_sleep(unsigned int time)
{
emscripten_sleep(time * 1000);
return time;
}
int main()
{
printf("Hello, World (JSPI!)\n");
async_call_sleep(3);
printf("Goodbye, World (JSPI!)\n");
return 0;
} Create a
Building for Chrome
You should see
The feature flag isn't a show-stopper. JSPI can be enabled for the entire playground.wordpress.net site via origin trials (https://v8.dev/blog/jspi-ot). Building for Node.js
You should see
JSPI is only available in Node.js, not Bun, and only in v22 You can see a list of all V8 options Node supports with
Also, it doesn't work with Bun yet:
|
@adamziel if we implement JSPI support, would we have access to the kinds of calls that were being made from PHP -> JS and possibly be able to log those if they aren't in our current Asyncify list? If so, maybe real world usage of JSPI could help us update the Asyncify lists and avoid crashes in the non-JSPI builds. |
You sir are a genius @brandonpayton |
Next steps#134 works in Node.js v22 and Chrome – both require a feature flag or applying to an origin trial. I don't expect stable JSPI support in all major runtimes (Chrome, Firefox, Safari, mobile browsers, last 3 Node versions) for the next year, two, or even three. I'm happy to be wrong here, but I didn't see any proof of imminent rollout. Here's what we could do:
This should get us:
|
Related to #134 Enables the [JSPI origin trial](https://developer.chrome.com/origintrials/#/register_trial/1603844417297317889) on Chrome. Read more about [origin trials](https://developer.chrome.com/docs/web-platform/origin-trials).
Firefox just shipped JSPI support. I'm not sure how extensive it is, but I just managed to run a simple JSPI program in Firefox nightly. I haven't tested PHP.wasm. |
## Motivation Ships every PHP.wasm build and dependency in two versions: JSPI, Asyncify. Updates `@php-wasm/web` and `@php-wasm/node` to use the JSPI version when the current runtime supports it, and and fall back to Asyncify otherwise. Why use JSPI? See #134. Tl;dr it will make PHP.wasm a whole lot more reliable. ## Implementation details This builds on top of the explorations done in #1339 – check the description and discussion there for the full "getting there" journey and detailed learnings. ### @php-wasm/compile The main Makefile ships an `_asyncify` and a `_jspi` version of every build task. Libraries, such as `libcurl` and `libedit`, store now each ship an Asyncify build and a JSPI build. Every JSPI build uses `-sSUPPORT_LONGJMP=wasm -fwasm-exceptions` flags. Asyncify builds are the same as before this PR and don't use those flags. ### @php-wasm/web and @php-wasm/node * PHP builds are shipped in `jspi` and `asyncify` subdirectories. * Emscripten doesn't export `free()` when using JSPI so we're exporting our own `wasm_free()` function. * `getPHPLoaderModule()` uses [wasm-feature-detect](https://github.com/GoogleChromeLabs/wasm-feature-detect) to check for JSPI support and load the right build. * Asynchronous JavaScript functions were moved from `phpwasm-emscripten-library.js` to `php_wasm.c` using the `EM_ASYNC_JS` macro for JSPI builds and `EM_JS` macro for Asyncify builds. * Unit tests are now ran separately on JSPI and Asyncify builds. ## Runtime support as of Oct 10th, 2024 JSPI is supported in: - ✅ Google Chrome with `#enable-experimental-webassembly-jspi` enabled at `chrome://flags`, or with sites where the JSPI origin trial is enabled. playground.wordpress.net is enrolled in the origin trial. - ✅ Node.js v22+ with `--experimental-wasm-stack-switching` feature flag. - ✅ Deno, with `--v8-flags=--experimental-wasm-jspi` feature flag - ✅ [Firefox](https://bugzilla.mozilla.org/show_bug.cgi?id=1850627) - ? Chrome-based browsers like Edge - ❌ Safari - ❌ Non-Chrome, non-Firefox web browsers - ❌ Node.js <= 21 - ❌ Non-v8 JS runtimes like Bun ## Testing instructions The E2E tests are a great source of insights: * Chrome supports JSPI * Firefox supports JSPI but has a separate implementation * Safari doesn't support JSPI and will use the Asyncify build We should also run the unit tests in Node v20 and v23 using with the experimental JSPI support flag.
Done in #1867 🎉 JSPI-enabled browsers (FF, Chrome) will load the JSPI version and the rest will load the Asyncify versions. It's based on feature detection so we don't have to do anything special to upgrade other browsers here. Let's just revisit this every couple of months until we can remove the Asyncify builds for the web. |
Description
We use Asyncify to call asynchronous JavaScript functions from synchronous WebAssembly code.
However, Asyncify forces us to maintain a large list of all the C functions that can be at the call stack at the time of making an asynchronous call must be listed during the build. When we miss even one, that code path triggers a fatal crash (
"unreachable" WASM instruction executed
). People report those crashes rather often.JSPI (proposal) is the new API that doesn't require maintaining that list and produces a smaller and faster binary.
Let's explore migrating to JSPI to solve these issues and more:
Next steps
We have a PR adding JSPI Support. It works in Node.js v22 and Chrome – both require a feature flag or applying to an origin trial.
I don't expect stable JSPI support in all major runtimes (Chrome, Firefox, Safari, mobile browsers, last 3 Node versions) for the next year, two, or even three. I'm happy to be wrong here, but I didn't see any proof of imminent rollout.
Here's what we could do:
This should get us:
Runtime support as of April 29th, 2024
JSPI is supported on:
#enable-experimental-webassembly-jspi
enabled atchrome://flags
, or with sites where the JSPI origin trial is enabled.--experimental-wasm-stack-switching
feature flag.The text was updated successfully, but these errors were encountered: