aboutsummaryrefslogtreecommitdiff
path: root/src/boot/run.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'src/boot/run.mjs')
-rw-r--r--src/boot/run.mjs46
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; }