1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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; }
|