From d7a35d19b7eacbcc9d980a4a46e512b121b1a66a Mon Sep 17 00:00:00 2001
From: Cheng Shao <terrorjack@type.dance>
Date: Mon, 16 Sep 2024 06:08:19 +0000
Subject: [PATCH] rts: rename prelude.js to prelude.mjs

This commit renames prelude.js to prelude.mjs for wasm backend rts
jsbits, and slightly adjusts the jsbits contents. This is for
preparing the implementation of dyld.mjs that contains wasm dynamic
linker logic, which needs to import prelude.mjs as a proper ESM
module.

(cherry picked from commit 71a471e7495f1fbf6b44cfbe4e930c99131c583e)
---
 hadrian/src/Base.hs                     |  2 +-
 hadrian/src/Rules/Generate.hs           |  2 +-
 utils/jsffi/post-link.mjs               | 11 ++--
 utils/jsffi/{prelude.js => prelude.mjs} | 69 +++++++++++++------------
 4 files changed, 44 insertions(+), 40 deletions(-)
 rename utils/jsffi/{prelude.js => prelude.mjs} (63%)

diff --git a/hadrian/src/Base.hs b/hadrian/src/Base.hs
index b12b717f66e..98c64ce1edd 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 5fde5ca742d..7c5b3452753 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 abd55622581..5de39fdc400 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 e54a2927901..c9cd6a447d4 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);
 })();
-- 
GitLab