WASI & syscalls
Compiled binaries from clang, and any wasm32-wasi module you bring,
run on the Nimbus wasi_snapshot_preview1 host. 45 of the 46 preview1
functions work. The missing one is sock_accept, so WASM servers can’t
take /port traffic yet. Preview1 has no sock_open, bind, or listen;
an inbound-socket extension is designed but not shipped.
Blocking I/O uses JSPI. Socket calls and poll_oneoff are wrapped in
WebAssembly.Suspending, and _start runs under
WebAssembly.promising. This is feature-detected and has a fallback.
Outbound TCP uses path_open('/dev/tcp/<host>/<port>') to open a real
cloudflare:sockets connection. poll_oneoff can mix fd, clock, and
socket subscriptions.
JSPI suspends a call; it cannot snapshot a stack. Programs that need
fork or setjmp — bash above all — are additionally instrumented with
Asyncify, which can unwind a running program’s call stack to memory and
rewind it in another instance. The process
fabric covers what that unlocked.
Smaller POSIX details are handled too. O_NOFOLLOW and O_APPEND work,
symlinks survive path_rename, and read(2) on a socket fd goes to the
socket. wasi-libc maps read to fd_read for every fd, so the host has to
route it correctly.
Programs see NIMBUS_ABI=wasm32-wasi-nimbus. The in-session clang emits
it, and the runtime catalog uses it to classify artifacts. WASM magic or
a saved exec bit sends ./prog through the WASI runner with a pid and a
process tab.
workerd blocks request-time WASM compilation from raw bytes. Modules must arrive pre-compiled in the module map. Pyodide extension packages must therefore be declared startup modules, while arbitrary dynamic loading fails with a clear diagnostic.
The remaining gaps are tracked with designs.
WASI files still use snapshot-plus-diff-flush, which fits one-shots but
not long-running processes. stdin is EOF. There are no inbound sockets.
wasi-threads is refused at link time: a partial version could corrupt
data, and
the design note
explains why.