// runs the bootstrap seed (a WASI preview1 module) under node: stdin in, stdout out, // exit code back. usage: node src/boot/run.mjs MODULE.wasm < in > out // the seed imports only fd_read, fd_write, path_open (read-only, relative to the // current directory, preopened as fd 3), fd_close and proc_exit, so they are here // directly, without node:wasi. import { readFileSync, readSync, writeSync, openSync, closeSync } from 'node:fs'; const EXIT = Symbol('exit'); let mem; const u8 = () => new Uint8Array(mem.buffer), dv = () => new DataView(mem.buffer); const fds = new Map([[0, 0], [1, 1], [2, 2]]); let nextFd = 4; function iovs(p, n, f) { let total = 0; for (let i = 0; i < n; i++) { const b = dv().getUint32(p + 8 * i, true), l = dv().getUint32(p + 8 * i + 4, true); const k = f(b, l); total += k; if (k < l) break; } return total; } const wasi = { fd_read(fd, p, n, out) { if (!fds.has(fd)) return 8; let k; try { k = iovs(p, n, (b, l) => { try { return readSync(fds.get(fd), u8(), b, l, null); } catch (e) { if (e.code === 'EAGAIN') return 0; if (e.code === 'EOF') return 0; throw e; } }); } catch (e) { return 29; } dv().setUint32(out, k, true); return 0; }, fd_write(fd, p, n, out) { if (!fds.has(fd)) return 8; const k = iovs(p, n, (b, l) => { let d = 0; while (d < l) d += writeSync(fds.get(fd), u8(), b + d, l - d); return l; }); dv().setUint32(out, k, true); return 0; }, path_open(dir, dirflags, path, len, oflags, rights, inherit, fdflags, out) { if (dir !== 3 || oflags !== 0) return 76; const name = Buffer.from(u8().subarray(path, path + len)).toString(); if (name.startsWith('/') || name.split('/').includes('..')) return 76; let h; try { h = openSync(name, 'r'); } catch (e) { return 44; } const fd = nextFd++; fds.set(fd, h); dv().setUint32(out, fd, true); return 0; }, fd_close(fd) { if (fd < 3 || !fds.has(fd)) return 8; closeSync(fds.get(fd)); fds.delete(fd); return 0; }, proc_exit(code) { throw { [EXIT]: code }; }, }; const { instance } = await WebAssembly.instantiate(readFileSync(process.argv[2]), { wasi_snapshot_preview1: wasi }); mem = instance.exports.memory; try { instance.exports._start(); process.exitCode = 0; } catch (e) { if (e && EXIT in e) process.exitCode = e[EXIT]; else throw e; }