diff options
author | Brendan Dahl <brendan.dahl@gmail.com> | 2022-09-16 13:26:51 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-16 13:26:51 -0700 |
commit | 241dee74dd8e58e166a4aa64c15e0f71ed1819bf (patch) | |
tree | d3b55aa23fc28dd4c0bf12bd11844c14c96a3105 /src | |
parent | b3e4d55b223b19c1c3179357861ca1b43c61e9df (diff) | |
download | binaryen-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.cpp | 28 |
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); |