summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrendan Dahl <brendan.dahl@gmail.com>2022-09-16 13:26:51 -0700
committerGitHub <noreply@github.com>2022-09-16 13:26:51 -0700
commit241dee74dd8e58e166a4aa64c15e0f71ed1819bf (patch)
treed3b55aa23fc28dd4c0bf12bd11844c14c96a3105 /src
parentb3e4d55b223b19c1c3179357861ca1b43c61e9df (diff)
downloadbinaryen-241dee74dd8e58e166a4aa64c15e0f71ed1819bf.tar.gz
binaryen-241dee74dd8e58e166a4aa64c15e0f71ed1819bf.tar.bz2
binaryen-241dee74dd8e58e166a4aa64c15e0f71ed1819bf.zip
JPSI - Support re-entering a suspended Wasm module. (#5044)
Fixes: https://github.com/emscripten-core/emscripten/issues/17846 More detailed explanation of the issue from Thibaud: - A promising export is entered, generating a suspender s1, which is stored in the global - The wasm code calls a wrapped import, passing it the value in the global (s1) and suspends - Another export is entered, generating suspender s2, which is stored in the global - We call another wrapped import, which suspends s2 (so far so good) - We return to the event loop and s1 is resumed And now we are in an inconsistent state: the active suspender is "s1", but the object in the global is "s2". So the next time we call a wrapped import, there is a mismatch, which is what this runtime error reports.
Diffstat (limited to 'src')
-rw-r--r--src/passes/JSPI.cpp28
1 files changed, 26 insertions, 2 deletions
diff --git a/src/passes/JSPI.cpp b/src/passes/JSPI.cpp
index 8ed2ba832..c7c8493d8 100644
--- a/src/passes/JSPI.cpp
+++ b/src/passes/JSPI.cpp
@@ -155,9 +155,33 @@ private:
params.push_back(param);
++i;
}
-
+ auto* block = builder.makeBlock();
+ // Store the suspender so it can be restored after the call in case it is
+ // modified by another entry into a Wasm export.
+ auto supsenderCopyIndex = Builder::addVar(stub.get(), externref);
+ // If there's a return value we need to store it so it can be returned
+ // after restoring the suspender.
+ std::optional<Index> returnIndex;
+ if (stub->getResults().isConcrete()) {
+ returnIndex = Builder::addVar(stub.get(), stub->getResults());
+ }
+ block->list.push_back(builder.makeLocalSet(
+ supsenderCopyIndex, builder.makeGlobalGet(suspender, externref)));
+ if (returnIndex) {
+ block->list.push_back(builder.makeLocalSet(*returnIndex, call));
+ } else {
+ block->list.push_back(call);
+ }
+ // Restore the suspender.
+ block->list.push_back(builder.makeGlobalSet(
+ suspender, builder.makeLocalGet(supsenderCopyIndex, externref)));
+ if (returnIndex) {
+ block->list.push_back(
+ builder.makeLocalGet(*returnIndex, stub->getResults()));
+ }
+ block->finalize();
call->type = im->getResults();
- stub->body = call;
+ stub->body = block;
wrapperIm->type = Signature(Type(params), call->type);
module->removeFunction(im->name);