Conversation
|
We can also use this to insert a sleep into the Python main loop, so that the print statements from the Python loop and the Javascript loop are interleaved: for(let i = 1; i < 100; i++){
sleep(100*i).then(() => console.log("jsi", i));
}
f = py.runPython(`
def f():
for i in range(100_000):
if i % 100 == 0:
print("pyi", i)
import pytest # segfaults if pytest hasn't been imported before =(
f
`);
await f.callSyncifying({});So the stack switching is extremely promising. It also seems likely that we will be able to make a version of Pyodide that uses stack switching if it is available but gracefully falls back if it is not available. |
|
Thanks for the investigation @hoodmane! Indeed it looks quite promising.
Nice. Since node v18 is now in an LTS state, I think it is okay to use new features of v18. |
|
Apparently they completely rearranged this proposal though. It seems like it now requires wasm reference types to use, and they may have removed the Both the backwards compatibility problem and the how-do-we-even-emit-code problem could be solved by hand coding the wrapper like what I did for |
|
I will have to try rewriting this to use the newer approach and see if it fixes the segfaults... |
|
Okay, so this works great in node v19 with flags This feature magically transcends our most annoying limitations. I think the trickiest design question is how to deal with mixing syncifying calls with non syncifying calls. Syncifying calls always return a promise. Non syncifying calls trap if a promise is syncified. It should be possible to set a flag on entry to the vm indicating whether it was a syncifying entry or a nonsyncifying one. A more sophisticated approach to reentrancy might be needed as well. |
|
We should probably look into using the wasm binary toolkit to convert wat text source files to wasm. Then we can convert the wasm to base64, create javascript files which define the module binaries, and inject these javascript files with |
|
@rth @ryanking13 this is ready to review. By splitting off a bunch of stuff, I've gotten it down to 408 lines added for features and 326 lines for tests which is more than a 2x decrease in size from before. The current state of this PR leaves out three things:
I have dealt with all three of these issues on local branches and will make more followup PRs after this is merged to fix them. |
ryanking13
left a comment
There was a problem hiding this comment.
Thanks @hodmane! This is awesome.
The changes generally look good to me. I just have a few comments (questions). Probably it would be good to have Roman's review too before merging.
for more information, see https://pre-commit.ci
|
Thanks for doing this work! I'll review it tomorrow. |
rth
left a comment
There was a problem hiding this comment.
That's certainly ambitious work that would solve a lot of Podide's problems! Thanks @hoodmane !
I'm not following all of what's happening on the lower level side, but some more comments are below and +1 from me for merging.
Maybe the major point is to make sure that there are no changes in behavior if JSPI is disabled, so maybe we should still run tests without JSPI (but rather adds CI runs where it's enabled). I'm not sure.
For the documentation, are you planning to add it separately (even if it's experimental). In particular, I would be interested in how this compares, broadly speaking, to ASYNCIFY=2 in Emscripten which also uses JSPI from what I understand.
|
|
||
| import { build } from "esbuild"; | ||
| import { readFileSync } from "node:fs"; | ||
| import loadWabt from "../../js/node_modules/wabt/index.js"; |
There was a problem hiding this comment.
Can we avoid the hardcoded assumption as to where node_modules are? It doesn't work with a non relative import?
There was a problem hiding this comment.
Problem is that this directory isn't under node_modules. Most likely there is a better way, like moving this script into src/js or something. But I'm not sure what the best approach is.
There was a problem hiding this comment.
I would like to leave fixing this to a followup.
| "--enable-experimental-webassembly-features", | ||
| ] | ||
| ) | ||
| pytest_pyodide.runner.NODE_FLAGS.extend(["--experimental-wasm-stack-switching"]) |
There was a problem hiding this comment.
So the idea is that we are still running Firefox tests without JSPI right?
I wonder if it wouldn't be good to still run some tests for chrome (and possibly node) without this flag. Since that's the default configuration where most users are currently.
There was a problem hiding this comment.
I think it would be good to run the fpcast tests, the C++ exception handling tests, the ctypes tests, the rust tests, and the recursion limit tests in the core test suite in both configurations. The remaining tests can be run in just one or the other.
There was a problem hiding this comment.
I'll fix this in a followup PR.
|
@rth okay to merge this? |
|
Sorry for the delay @hoodmane . Yes, no objection on my part. Thanks for doing all this work! |
Uses the JS Promise integration stack switching API to allow blocking for JavaScript promises and `PyodideFuture` objects. It's a bit complicated... This doesn't include support for reentrant switching, currently doing that will corrupt the Python VM.
Uses the JS Promise integration stack switching API to allow blocking for JavaScript promises and `PyodideFuture` objects. It's a bit complicated... This doesn't include support for reentrant switching, currently doing that will corrupt the Python VM.
Uses the JS Promise integration stack switching API to allow blocking for JavaScript promises and `PyodideFuture` objects. It's a bit complicated... This doesn't include support for reentrant switching, currently doing that will corrupt the Python VM.
Uses the JS Promise integration stack switching API to allow blocking for JavaScript promises and `PyodideFuture` objects. It's a bit complicated... This doesn't include support for reentrant switching, currently doing that will corrupt the Python VM.
Uses the JS Promise integration stack switching API to allow blocking for JavaScript promises and `PyodideFuture` objects. It's a bit complicated... This doesn't include support for reentrant switching, currently doing that will corrupt the Python VM.
Uses the JS Promise integration stack switching API to allow blocking for JavaScript promises and `PyodideFuture` objects. It's a bit complicated... This doesn't include support for reentrant switching, currently doing that will corrupt the Python VM.
Uses the JS Promise integration stack switching API to allow blocking for JavaScript promises and `PyodideFuture` objects. It's a bit complicated... This doesn't include support for reentrant switching, currently doing that will corrupt the Python VM.
Uses the JS Promise integration stack switching API to allow blocking for JavaScript promises and PyodideFuture objects.