diff --git a/utils/jsffi/dyld.mjs b/utils/jsffi/dyld.mjs index 3820d78a5557cd0b1b75fb882d36dfde9f8776ee..caa699ee1cb476de8193f707c4ac2d9b2c3f9ecc 100755 --- a/utils/jsffi/dyld.mjs +++ b/utils/jsffi/dyld.mjs @@ -87,10 +87,6 @@ // -opti GHC flag to pass process arguments, like RTS flags or -opti-v // to dump the iserv messages. -import fs from "node:fs"; -import path from "node:path"; -import stream from "node:stream"; -import { WASI } from "node:wasi"; import { JSValManager, setImmediate } from "./prelude.mjs"; import { parseRecord, parseSections } from "./post-link.mjs"; @@ -265,6 +261,28 @@ async function parseDyLink0(reader) { return r; } +// Browser/node portable code stays above this watermark. +const isNode = Boolean(globalThis?.process?.versions?.node); + +// Too cumbersome to only import at use sites. Too troublesome to +// factor out browser-only/node-only logic into different modules. For +// now, just make these global let bindings optionally initialized if +// isNode and be careful to not use them in browser-only logic. +let fs, path, require, stream, wasi; + +if (isNode) { + require = (await import("node:module")).createRequire(import.meta.url); + + fs = require("fs"); + path = require("path"); + stream = require("stream"); + wasi = require("wasi"); +} else { + wasi = await import( + "https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.4.1/dist/index.js" + ); +} + // The real stuff class DyLD { // Wasm page size. @@ -342,12 +360,31 @@ class DyLD { #regs = {}; constructor({ args }) { - this.#wasi = new WASI({ - version: "preview1", - args, - env: { PATH: "", PWD: process.cwd() }, - preopens: { "/": "/" }, - }); + if (isNode) { + this.#wasi = new wasi.WASI({ + version: "preview1", + args, + env: { PATH: "", PWD: process.cwd() }, + preopens: { "/": "/" }, + }); + } else { + this.#wasi = new wasi.WASI( + args, + [], + [ + new wasi.OpenFile( + new wasi.File(new Uint8Array(), { readonly: true }) + ), + wasi.ConsoleStdout.lineBuffered((msg) => + console.log(`[WASI stdout] ${msg}`) + ), + wasi.ConsoleStdout.lineBuffered((msg) => + console.warn(`[WASI stderr] ${msg}`) + ), + ], + { debug: false } + ); + } // Keep this in sync with rts/wasm/Wasm.S! for (let i = 1; i <= 10; ++i) { @@ -740,11 +777,7 @@ class DyLD { } } -function isMain() { - return import.meta.filename === process.argv[1]; -} - -if (isMain()) { +if (isNode) { // sysroot libdir that contains libc.so etc const libdir = process.argv[2], ghci_so_path = process.argv[3];