diff --git a/hadrian/src/Base.hs b/hadrian/src/Base.hs index b12b717f66ed984489fd04f62ce95a23290397c2..98c64ce1edd0d5aa4884b32055373af41f90f23d 100644 --- a/hadrian/src/Base.hs +++ b/hadrian/src/Base.hs @@ -154,7 +154,7 @@ ghcLibDeps stage iplace = do , "ghc-usage.txt" , "ghci-usage.txt" , "post-link.mjs" - , "prelude.js" + , "prelude.mjs" ] cxxStdLib <- systemCxxStdLibConfPath (PackageDbLoc stage iplace) return (cxxStdLib : ps) diff --git a/hadrian/src/Rules/Generate.hs b/hadrian/src/Rules/Generate.hs index 5fde5ca742de943eebf8bf91b307198f25613242..7c5b3452753bd8bda56f63242602fd83d9d5eaab 100644 --- a/hadrian/src/Rules/Generate.hs +++ b/hadrian/src/Rules/Generate.hs @@ -215,7 +215,7 @@ copyRules = do copyFile ("utils/jsffi" -/- makeRelative prefix file) file makeExecutable file - prefix -/- "prelude.js" <~ pure "utils/jsffi" + prefix -/- "prelude.mjs" <~ pure "utils/jsffi" prefix -/- "html/**" <~ return "utils/haddock/haddock-api/resources" prefix -/- "latex/**" <~ return "utils/haddock/haddock-api/resources" diff --git a/utils/jsffi/post-link.mjs b/utils/jsffi/post-link.mjs index abd55622581b1ba6fe76a451e5ba35a5ec182cfb..5de39fdc4007ac2262b312de77b86aca8bcb769e 100755 --- a/utils/jsffi/post-link.mjs +++ b/utils/jsffi/post-link.mjs @@ -52,11 +52,14 @@ function parseSections(mod) { return recs; } - export async function postLink(mod) { - let src = await fs.readFile(path.join(import.meta.dirname, "prelude.js"), { - encoding: "utf-8", - }); + let src = ( + await fs.readFile(path.join(import.meta.dirname, "prelude.mjs"), { + encoding: "utf-8", + }) + ).replaceAll("export ", ""); // we only use it as code template, don't export stuff + + // Keep this in sync with dyld.mjs! src = `${src}\nexport default (__exports) => {`; src = `${src}\nconst __ghc_wasm_jsffi_jsval_manager = new JSValManager();`; src = `${src}\nconst __ghc_wasm_jsffi_finalization_registry = new FinalizationRegistry(sp => __exports.rts_freeStablePtr(sp));`; diff --git a/utils/jsffi/prelude.js b/utils/jsffi/prelude.mjs similarity index 63% rename from utils/jsffi/prelude.js rename to utils/jsffi/prelude.mjs index e54a2927901330faa972faba5977b3105ef2ea0f..c9cd6a447d482d8fec202099df5ba947f809d792 100644 --- a/utils/jsffi/prelude.js +++ b/utils/jsffi/prelude.mjs @@ -5,7 +5,7 @@ // Manage a mapping from unique 32-bit ids to actual JavaScript // values. -class JSValManager { +export class JSValManager { #lastk = 0; #kv = new Map(); @@ -49,47 +49,48 @@ class JSValManager { } } -// A simple & fast setImmediate() implementation for browsers. It's -// not a drop-in replacement for node.js setImmediate() because: -// 1. There's no clearImmediate(), and setImmediate() doesn't return -// anything -// 2. There's no guarantee that callbacks scheduled by setImmediate() -// are executed in the same order (in fact it's the opposite lol), -// but you are never supposed to rely on this assumption anyway -class SetImmediate { - #fs = []; - #mc = new MessageChannel(); - - constructor() { - this.#mc.port1.addEventListener("message", () => { - this.#fs.pop()(); - }); - this.#mc.port1.start(); - } - - setImmediate(cb, ...args) { - this.#fs.push(() => cb(...args)); - this.#mc.port2.postMessage(undefined); - } -} - // The actual setImmediate() to be used. This is a ESM module top // level binding and doesn't pollute the globalThis namespace. const setImmediate = await (async () => { - // https://developer.mozilla.org/en-US/docs/Web/API/Scheduler - if (globalThis.scheduler) { - return (cb, ...args) => scheduler.postTask(() => cb(...args)); - } // node, bun, or other scripts might have set this up in the browser if (globalThis.setImmediate) { return globalThis.setImmediate; } + + // deno try { - // deno return (await import("node:timers")).setImmediate; - } catch { - // browsers - const sm = new SetImmediate(); - return (cb, ...args) => sm.setImmediate(cb, ...args); + } catch {} + + // https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/postTask + if (globalThis.scheduler) { + return (cb, ...args) => scheduler.postTask(() => cb(...args)); + } + + // A simple & fast setImmediate() implementation for browsers. It's + // not a drop-in replacement for node.js setImmediate() because: + // 1. There's no clearImmediate(), and setImmediate() doesn't return + // anything + // 2. There's no guarantee that callbacks scheduled by setImmediate() + // are executed in the same order (in fact it's the opposite lol), + // but you are never supposed to rely on this assumption anyway + class SetImmediate { + #fs = []; + #mc = new MessageChannel(); + + constructor() { + this.#mc.port1.addEventListener("message", () => { + this.#fs.pop()(); + }); + this.#mc.port1.start(); + } + + setImmediate(cb, ...args) { + this.#fs.push(() => cb(...args)); + this.#mc.port2.postMessage(undefined); + } } + + const sm = new SetImmediate(); + return (cb, ...args) => sm.setImmediate(cb, ...args); })();