You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add REENTRANT_JSPI: a shadow stack per JSPI activation
C frames live on the shadow stack in linear memory, which JSPI does not
save across a suspension. When a promising activation ("fiber") resumes
while another one is suspended, its frames are pushed over the suspended
one's, so concurrent promising calls silently corrupt each other. That
rules out server-style programs handling requests concurrently under JSPI.
With -sREENTRANT_JSPI every fiber gets its own shadow stack, allocated
from the heap when the promising export is entered (JSPI_FIBER_STACK_SIZE
bytes, defaulting to STACK_SIZE) and released when it exits, with a small
per-thread pool of released stacks that is freed at thread exit. The stack
pointer is switched at the four lifecycle hooks: to the fiber's stack at
ENTER and RESUME, and back to whatever the host had at SUSPEND and EXIT,
including on the exceptional exits the hook wrappers already route
through. Since the frames never move, imports that write results through
pointers into a suspended fiber's frames (emscripten_promise_await, poll,
EM_ASYNC_JS out-parameters) keep working, and the host's own stack
allocations are never overlapped.
The four __jspi_* exports are now assembly shims around C implementations,
so that the stack pointer they install persists past their return; the
stack limits used by emscripten_stack_get_* and by STACK_OVERFLOW_CHECK=2
are switched the same way, after all C code has returned. A fiber stack
lives in the heap with no address-zero guard like the main stack, so the
setting defaults STACK_OVERFLOW_CHECK to 2 and an overflow traps at the
overflowing store; builds that explicitly opt out get a small guard region
below each stack (JSPI_FIBER_STACK_GUARD) with cookies checked whenever
the fiber suspends or exits. Fibers are
thread-affine and each thread has its own set. Dynamic linking is not
supported with the setting.
Also fixes the decorator order of test_async_ccall_promise, whose `jspi`
variant was running ASYNCIFY (mode decorators must be outermost); the new
`reentrant_jspi` test mode needs it.
Depends on the JSPI lifecycle hooks (<emscripten/jspi.h>).
0 commit comments