diff options
| author | 2026-10-15 17:03:03 +0330 | |
|---|---|---|
| committer | 2026-10-15 17:03:03 +0330 | |
| commit | 7cb983bbea98d2038b2a8015a6d1f1afd40991c9 (patch) | |
| tree | ec3d88a15801207fc6d8d3c6d142617ffec85460 /src/boot/run.mjs | |
| parent | merge work/borrow: borrow returns before definition, borrows clause, borrow m... (diff) | |
| parent | bench: rss probe path fix (diff) | |
merge work/actors: wasm seed bootstrap (seed/MANIFEST), shared copy-on-write actor memory, top-level hold blocks on all backends and lsp
Diffstat (limited to 'src/boot/run.mjs')
| -rw-r--r-- | src/boot/run.mjs | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/src/boot/run.mjs b/src/boot/run.mjs new file mode 100644 index 0000000..f96c3f4 --- /dev/null +++ b/src/boot/run.mjs @@ -0,0 +1,46 @@ +// 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; } |
