aboutsummaryrefslogtreecommitdiff
path: root/run-wasm.js
blob: 21a74a220acf0edfaa0751cc22ce7609222e41e7 (plain)
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
"use strict";

const fs = require("fs");
const {WASI} = require("wasi");

const separatorIndex = process.argv.indexOf("--");
const runWasmArgs = process.argv.slice(1, separatorIndex)
const isWasm64 = runWasmArgs.includes("--wasm64");
const isPatioTest = runWasmArgs.includes("--patio-test");
const wasmExecutablePath = process.argv[separatorIndex + 1];

const createWasi = isWasm64 ? createWasiForWasm64 : createWasiForWasm32;

function createWasiForWasm32() {
    return new WASI({
        version: "preview1",
        args: process.argv.slice(2),
        env: process.env,
        returnOnExit: false,
    });
}

function createWasiForWasm64() {
    // When using the builtin WASI with wasm64, nothing seems to get printed to
    // stdout. It's not clear whether the compiler makes an incorrect assumption
    // about what node thinks the API for fd_write is on wasm64, or whether WASI
    // isn't supported by node on wasm64, but given that (so far as I known)
    // WASI isn't really defined for wasm64, it seems reasonable to roll our own
    // implementation for now.

    let runningInstance = null;

    const wasiImport = {
        fd_write: (fd, iovsPtr, iovsLen, nwritten) => {
            iovsPtr = Number(iovsPtr);

            const memoryBuffer = runningInstance.exports.memory.buffer;
            const memoryDataView = new DataView(memoryBuffer);

            for (let iovsIndex = 0; iovsIndex < iovsLen; iovsIndex++) {
                const iovPtr = iovsPtr + iovsIndex * 16;
                const bufPtr = Number(memoryDataView.getBigUint64(iovPtr, true));
                const bufLen = Number(memoryDataView.getBigUint64(iovPtr + 8, true));
                const buf = Buffer.from(memoryBuffer, bufPtr, bufLen);
                // TODO: handle fd !== 1
                process.stdout.write(buf);
            }

            // TODO: update nwritten
        },

        proc_exit: (exitCode) => {
            process.exit(exitCode);
        },
    };

    const start = (instance) => {
        runningInstance = instance;
        instance.exports._start();
    };

    return {wasiImport, start};
}

(async () => {
    const wasi = createWasi();
    const importObject = {
        "wasi_snapshot_preview1": wasi.wasiImport,
    };

    if (isPatioTest) {
        importObject["env"] = {
            patio__test__emit_int: (value) => {
                console.log(value.toString());
            },
        };
    }

    const wasm = await WebAssembly.compile(fs.readFileSync(wasmExecutablePath));
    const instance = await WebAssembly.instantiate(wasm, importObject);
    wasi.start(instance);
})();