packages feed

ghc-internal 9.1201.0 → 9.1203.0

raw patch · 9 files changed

+338/−102 lines, 9 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ GHC.Internal.Base: pattern MkSolo# :: () => a -> Solo# a
+ GHC.Internal.Exception.Backtrace: Backtraces :: Maybe (Ptr CostCentreStack) -> Maybe CallStack -> Maybe [Location] -> Maybe [StackEntry] -> Backtraces
+ GHC.Internal.Exception.Backtrace: EnabledBacktraceMechanisms :: !Bool -> !Bool -> !Bool -> !Bool -> EnabledBacktraceMechanisms
+ GHC.Internal.Exception.Backtrace: [btrCostCentre] :: Backtraces -> Maybe (Ptr CostCentreStack)
+ GHC.Internal.Exception.Backtrace: [btrExecutionStack] :: Backtraces -> Maybe [Location]
+ GHC.Internal.Exception.Backtrace: [btrHasCallStack] :: Backtraces -> Maybe CallStack
+ GHC.Internal.Exception.Backtrace: [btrIpe] :: Backtraces -> Maybe [StackEntry]
+ GHC.Internal.Exception.Backtrace: [costCentreBacktraceEnabled] :: EnabledBacktraceMechanisms -> !Bool
+ GHC.Internal.Exception.Backtrace: [executionBacktraceEnabled] :: EnabledBacktraceMechanisms -> !Bool
+ GHC.Internal.Exception.Backtrace: [hasCallStackBacktraceEnabled] :: EnabledBacktraceMechanisms -> !Bool
+ GHC.Internal.Exception.Backtrace: [ipeBacktraceEnabled] :: EnabledBacktraceMechanisms -> !Bool
+ GHC.Internal.Exception.Backtrace: backtraceMechanismEnabled :: BacktraceMechanism -> EnabledBacktraceMechanisms -> Bool
+ GHC.Internal.Exception.Backtrace: collectBacktraces' :: (?callStack :: CallStack) => EnabledBacktraceMechanisms -> IO Backtraces
+ GHC.Internal.Exception.Backtrace: data EnabledBacktraceMechanisms
+ GHC.Internal.Exception.Backtrace: defaultEnabledBacktraceMechanisms :: EnabledBacktraceMechanisms
+ GHC.Internal.Exception.Backtrace: enabledBacktraceMechanismsRef :: IORef EnabledBacktraceMechanisms
+ GHC.Internal.Exception.Backtrace: getEnabledBacktraceMechanisms :: IO EnabledBacktraceMechanisms
+ GHC.Internal.Exception.Backtrace: setBacktraceMechanismEnabled :: BacktraceMechanism -> Bool -> EnabledBacktraceMechanisms -> EnabledBacktraceMechanisms
+ GHC.Internal.Exts: pattern MkSolo# :: () => a -> Solo# a

Files

+ cbits/RtsIface.c view
@@ -0,0 +1,66 @@+/*+ * (c) The GHC Team, 2025-2026+ *+ * RTS/ghc-internal interface+ *+ * See Note [RTS/ghc-internal interface].+ */++#include "Rts.h"++void init_ghc_hs_iface(void);++// Forward declarations+#define CLOSURE(module, symbol) \+    extern StgClosure ghczminternal_##module##_##symbol;++#define PRIMCLOSURE(module, symbol) \+    extern StgClosure ghczmprim_##module##_##symbol;++#define UNDEF_CLOSURE(module, symbol)++#define INFO_TBL(module, symbol) \+    extern const StgInfoTable ghczminternal_##module##_##symbol;++#define PRIM_INFO_TBL(module, symbol) \+    extern const StgInfoTable ghczmprim_##module##_##symbol;++#include "RtsIfaceSymbols.h"++#undef CLOSURE+#undef PRIMCLOSURE+#undef UNDEF_CLOSURE+#undef INFO_TBL+#undef PRIM_INFO_TBL++// HsIface definition+#define CLOSURE(module, symbol) \+    .symbol = &ghczminternal_##module##_##symbol,++#define PRIMCLOSURE(module, symbol) \+    .symbol = &ghczmprim_##module##_##symbol,++#define UNDEF_CLOSURE(module, symbol) \+    .symbol = NULL,++#define INFO_TBL(module, symbol) \+    .symbol = &ghczminternal_##module##_##symbol,++#define PRIM_INFO_TBL(module, symbol) \+    .symbol = &ghczmprim_##module##_##symbol,++static HsIface the_ghc_hs_iface = {+#include "RtsIfaceSymbols.h"+};++void init_ghc_hs_iface(void)+{+    /*+     * N.B. ghc-internal may be load multiple times, e.g., when the+     * RTS linker is in use. For this reason we explicitly refuse to+     * override ghc_hs_iface if it has already been initialized.+     */+    if (ghc_hs_iface == NULL) {+        ghc_hs_iface = &the_ghc_hs_iface;+    }+}
ghc-internal.cabal view
@@ -4,7 +4,7 @@ name:           ghc-internal -- The project is ghc's version plus ghc-internal's version suffix. -- For example, for ghc=9.10.1, ghc-internal's version will be 9.1001.0.-version:        9.1201.0+version:        9.1203.0 license:        BSD-3-Clause license-file:   LICENSE maintainer:     The GHC Developers <ghc-devs@haskell.org>@@ -40,6 +40,7 @@     include/md5.h     include/fs.h     include/winio_structs.h+    include/RtsIfaceSymbols.h     install-sh  source-repository head@@ -345,6 +346,7 @@           cbits/sysconf.c           cbits/fs.c           cbits/strerror.c+          cbits/RtsIface.c        cmm-sources:           cbits/StackCloningDecoding.cmm
+ include/RtsIfaceSymbols.h view
@@ -0,0 +1,66 @@+// See Note [RTS/ghc-internal interface].++#if defined(mingw32_HOST_OS)+CLOSURE(GHCziInternalziEventziWindows, processRemoteCompletion_closure)+#else+UNDEF_CLOSURE(GHCziInternalziEventziWindows, processRemoteCompletion_closure)+#endif+CLOSURE(GHCziInternalziTopHandler, runIO_closure)+CLOSURE(GHCziInternalziTopHandler, runNonIO_closure)+PRIMCLOSURE(GHCziTuple, Z0T_closure)+PRIMCLOSURE(GHCziTypes, True_closure)+PRIMCLOSURE(GHCziTypes, False_closure)+CLOSURE(GHCziInternalziPack, unpackCString_closure)+CLOSURE(GHCziInternalziWeakziFinalizze, runFinalizzerBatch_closure)+CLOSURE(GHCziInternalziIOziException, stackOverflow_closure)+CLOSURE(GHCziInternalziIOziException, heapOverflow_closure)+CLOSURE(GHCziInternalziIOPort, doubleReadException_closure)+CLOSURE(GHCziInternalziIOziException, allocationLimitExceeded_closure)+CLOSURE(GHCziInternalziIOziException, blockedIndefinitelyOnMVar_closure)+CLOSURE(GHCziInternalziIOziException, blockedIndefinitelyOnSTM_closure)+CLOSURE(GHCziInternalziIOziException, cannotCompactFunction_closure)+CLOSURE(GHCziInternalziIOziException, cannotCompactPinned_closure)+CLOSURE(GHCziInternalziIOziException, cannotCompactMutable_closure)+CLOSURE(GHCziInternalziControlziExceptionziBase, nonTermination_closure)+CLOSURE(GHCziInternalziControlziExceptionziBase, nestedAtomically_closure)+CLOSURE(GHCziInternalziControlziExceptionziBase, noMatchingContinuationPrompt_closure)+#if defined(mingw32_HOST_OS)+UNDEF_CLOSURE(GHCziInternalziEventziThread, blockedOnBadFD_closure)+#else+CLOSURE(GHCziInternalziEventziThread, blockedOnBadFD_closure)+#endif+CLOSURE(GHCziInternalziConcziSync, runSparks_closure)+CLOSURE(GHCziInternalziConcziIO, ensureIOManagerIsRunning_closure)+CLOSURE(GHCziInternalziConcziIO, interruptIOManager_closure)+CLOSURE(GHCziInternalziConcziIO, ioManagerCapabilitiesChanged_closure)+CLOSURE(GHCziInternalziConcziSignal, runHandlersPtr_closure)+CLOSURE(GHCziInternalziTopHandler, flushStdHandles_closure)+CLOSURE(GHCziInternalziTopHandler, runMainIO_closure)+PRIM_INFO_TBL(GHCziTypes, Czh_con_info)+PRIM_INFO_TBL(GHCziTypes, Izh_con_info)+PRIM_INFO_TBL(GHCziTypes, Fzh_con_info)+PRIM_INFO_TBL(GHCziTypes, Dzh_con_info)+PRIM_INFO_TBL(GHCziTypes, Wzh_con_info)+PRIMCLOSURE(GHCziPrimziPanic, absentSumFieldError_closure)+INFO_TBL(GHCziInternalziPtr, Ptr_con_info)+INFO_TBL(GHCziInternalziPtr, FunPtr_con_info)+INFO_TBL(GHCziInternalziInt, I8zh_con_info)+INFO_TBL(GHCziInternalziInt, I16zh_con_info)+INFO_TBL(GHCziInternalziInt, I32zh_con_info)+INFO_TBL(GHCziInternalziInt, I64zh_con_info)+INFO_TBL(GHCziInternalziWord, W8zh_con_info)+INFO_TBL(GHCziInternalziWord, W16zh_con_info)+INFO_TBL(GHCziInternalziWord, W32zh_con_info)+INFO_TBL(GHCziInternalziWord, W64zh_con_info)+INFO_TBL(GHCziInternalziStable, StablePtr_con_info)+CLOSURE(GHCziInternalziStackziCloneStack, StackSnapshot_closure)+CLOSURE(GHCziInternalziExceptionziType, divZZeroException_closure)+CLOSURE(GHCziInternalziExceptionziType, underflowException_closure)+CLOSURE(GHCziInternalziExceptionziType, overflowException_closure)+PRIM_INFO_TBL(GHCziCString, unpackCStringzh_info)+PRIM_INFO_TBL(GHCziCString, unpackCStringUtf8zh_info)+#if defined(wasm32_HOST_ARCH) && defined(__PIC__)+CLOSURE(GHCziInternalziWasmziPrimziImports, raiseJSException_closure)+INFO_TBL(GHCziInternalziWasmziPrimziTypes, JSVal_con_info)+CLOSURE(GHCziInternalziWasmziPrimziConcziInternal, threadDelay_closure)+#endif
src/GHC/Internal/Exception/Backtrace.hs view
@@ -3,16 +3,7 @@ {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} -module GHC.Internal.Exception.Backtrace-    ( -- * Backtrace mechanisms-      BacktraceMechanism(..)-    , getBacktraceMechanismState-    , setBacktraceMechanismState-      -- * Collecting backtraces-    , Backtraces-    , displayBacktraces-    , collectBacktraces-    ) where+module GHC.Internal.Exception.Backtrace where  import GHC.Internal.Base import GHC.Internal.Data.OldList
src/GHC/Internal/Wasm/Prim.hs view
@@ -1,21 +1,21 @@ {-# LANGUAGE NoImplicitPrelude #-}  module GHC.Internal.Wasm.Prim (-  -- User-facing JSVal type and freeJSVal+  -- * User-facing 'JSVal' and related utilities   JSVal (..),   freeJSVal,+  mkWeakJSVal, -  -- The JSString type and conversion from/to Haskell String+  -- * 'JSString' and conversion from/to Haskell 'String'   JSString (..),   fromJSString,   toJSString, -  -- Exception types related to JSFFI+  -- * Exception types related to JSFFI   JSException (..),   WouldBlockException (..),-  PromisePendingException (..), -  -- Is JSFFI used in the current wasm module?+  -- * Is JSFFI used in the current wasm module?   isJSFFIUsed ) where 
src/GHC/Internal/Wasm/Prim/Exports.hs view
@@ -34,6 +34,7 @@ import GHC.Internal.Exception.Type import GHC.Internal.Exts import GHC.Internal.IO+import GHC.Internal.IORef import GHC.Internal.Int import GHC.Internal.Stable import GHC.Internal.TopHandler (flushStdHandles)@@ -43,11 +44,15 @@ mkJSCallback :: (StablePtr a -> IO JSVal) -> a -> IO JSVal mkJSCallback adjustor f = do   sp@(StablePtr sp#) <- newStablePtr f-  JSVal v w _ <- adjustor sp-  let r = JSVal v w sp#-  js_callback_register r sp-  pure r+  v@(JSVal p) <- adjustor sp+  IO $ \s0 -> case stg_setJSVALsp p sp# s0 of+    (# s1 #) -> (# s1, () #)+  js_callback_register v sp+  pure v +foreign import prim "stg_setJSVALsp"+  stg_setJSVALsp :: JSVal# -> StablePtr# a -> State# RealWorld -> (# State# RealWorld #)+ foreign import javascript unsafe "__ghc_wasm_jsffi_finalization_registry.register($1, $2, $1)"   js_callback_register :: JSVal -> StablePtr a -> IO () @@ -61,15 +66,26 @@         let tmp@(JSString tmp_v) = toJSString $ displayException err         js_promiseReject p tmp         freeJSVal tmp_v-  IO $ \s0 -> case fork# (unIO $ catch (res p =<< m) topHandler *> flushStdHandles) s0 of-    (# s1, _ #) -> case stg_scheduler_loop# s1 of-      (# s2, _ #) -> (# s2, p #)+  post_action_ref <- newIORef $ pure ()+  IO $ \s0 -> case fork# (unIO $ catch (res p =<< m) topHandler *> flushStdHandles *> join (readIORef post_action_ref)) s0 of+    (# s1, tso# #) -> case mkWeakNoFinalizer# tso# () s1 of+      (# s2, w# #) -> case makeStablePtr# w# s2 of+        (# s3, sp# #) -> case unIO (writeIORef post_action_ref $ js_promiseDelThrowTo p *> freeStablePtr (StablePtr $ unsafeCoerce# sp#)) s3 of+          (# s4, _ #) -> case unIO (js_promiseAddThrowTo p $ StablePtr $ unsafeCoerce# sp#) s4 of+            (# s5, _ #) -> case stg_scheduler_loop# s5 of+              (# s6, _ #) -> (# s6, p #)  runNonIO :: (JSVal -> a -> IO ()) -> a -> IO JSVal runNonIO res a = runIO res $ pure a  foreign import javascript unsafe "let res, rej; const p = new Promise((resolve, reject) => { res = resolve; rej = reject; }); p.resolve = res; p.reject = rej; return p;"   js_promiseWithResolvers :: IO JSVal++foreign import javascript unsafe "$1.throwTo = (err) => __exports.rts_promiseThrowTo($2, err);"+  js_promiseAddThrowTo :: JSVal -> StablePtr Any -> IO ()++foreign import javascript unsafe "$1.throwTo = () => {};"+  js_promiseDelThrowTo :: JSVal -> IO ()  foreign import prim "stg_scheduler_loopzh"   stg_scheduler_loop# :: State# RealWorld -> (# State# RealWorld, () #)
src/GHC/Internal/Wasm/Prim/Flag.hs view
@@ -7,4 +7,8 @@  import GHC.Internal.Base +-- | If the current wasm module has any JSFFI functionality linked in,+-- this would be 'True' at runtime and 'False' otherwise. If this is+-- 'False', the wasm module would be a self-contained wasm32-wasi+-- module that can be run by non-web runtimes as well. foreign import ccall unsafe "rts_JSFFI_used" isJSFFIUsed :: Bool
src/GHC/Internal/Wasm/Prim/Imports.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE UnliftedFFITypes #-}  module GHC.Internal.Wasm.Prim.Imports (+  raiseJSException,   stg_blockPromise,   stg_messagePromiseUnit,   stg_messagePromiseJSVal,@@ -67,23 +68,19 @@ thread in the future has been set up, we can drop the Promise eagerly, then arrange the current thread to block. -Blocking is done by calling stg_jsffi_block: it pushes a-stg_jsffi_block frame and suspends the thread. The payload of-stg_jsffi_block frame is a single pointer field that holds the return-value. When the Promise is resolved with the result, the RTS fetches-the TSO indexed by the stable pointer passed earlier, checks for the-top stack frame to see if it's still a stg_jsffi_block frame (could be-stripped by an async exception), fills in the boxed result and-restarts execution. In case of a Promise rejection, the closure being-filled is generated via raiseJSException.+Blocking is done by readMVar. stg_blockPromise allocates an empty MVar+and pins it under a stable pointer, then finally blocks by readMVar.+The stable pointer is captured in the promise.then callback. When the+Promise is settled in the future, the promise.then callback writes the+result (or exception) to the MVar and then resumes Haskell execution.  -} -stg_blockPromise :: JSVal -> (JSVal -> StablePtr Any -> IO ()) -> r-stg_blockPromise p msg_p = unsafeDupablePerformIO $ IO $ \s0 ->-  case stg_jsffi_check (unsafeCoerce# $ toException WouldBlockException) s0 of-    (# s1 #) -> case myThreadId# s1 of-      (# s2, tso #) -> case makeStablePtr# tso s2 of+stg_blockPromise :: String -> JSVal -> (JSVal -> StablePtr Any -> IO ()) -> r+stg_blockPromise err_msg p msg_p = unsafeDupablePerformIO $ IO $ \s0 ->+  case stg_jsffi_check (unsafeCoerce# $ toException $ WouldBlockException err_msg) s0 of+    (# s1 #) -> case newMVar# s1 of+      (# s2, mv# #) -> case makeStablePtr# mv# s2 of         (# s3, sp #) ->           case unIO (msg_p p $ StablePtr $ unsafeCoerce# sp) s3 of             -- Since we eagerly free the Promise here, we must return@@ -98,20 +95,10 @@             --    and prevents dmdanal from being naughty             (# s4, _ #) -> case unIO (freeJSVal p) s4 of               (# s5, _ #) ->-                -- raiseJSException_closure is used by the RTS in case-                -- the Promise is rejected, and it is likely a CAF. So-                -- we need to keep it alive when we block waiting for-                -- the Promise to resolve or reject, and also mark it-                -- as OPAQUE just to be sure.-                keepAlive# raiseJSException s5 $-                  stg_jsffi_block $-                    throw PromisePendingException+                readMVar# mv# s5  foreign import prim "stg_jsffi_check"   stg_jsffi_check :: Any -> State# RealWorld -> (# State# RealWorld #)--foreign import prim "stg_jsffi_block"-  stg_jsffi_block :: Any -> State# RealWorld -> (# State# RealWorld, r #)  foreign import javascript unsafe "$1.then(() => __exports.rts_promiseResolveUnit($2), err => __exports.rts_promiseReject($2, err))"   stg_messagePromiseUnit :: JSVal -> StablePtr Any -> IO ()
src/GHC/Internal/Wasm/Prim/Types.hs view
@@ -1,19 +1,21 @@ {-# LANGUAGE GHC2021 #-}+{-# LANGUAGE GHCForeignImportPrim #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE UnliftedFFITypes #-} {-# LANGUAGE UnliftedNewtypes #-}  module GHC.Internal.Wasm.Prim.Types (   JSVal# (..),   JSVal (..),   freeJSVal,+  mkWeakJSVal,   JSString (..),   fromJSString,   toJSString,   JSException (..),-  WouldBlockException (..),-  PromisePendingException (..)+  WouldBlockException (..) ) where  import GHC.Internal.Base@@ -25,7 +27,7 @@ import GHC.Internal.IO.Encoding import GHC.Internal.Num import GHC.Internal.Show-import GHC.Internal.Stable+import GHC.Internal.Weak  {- @@ -36,70 +38,150 @@ only contain bit patterns, not opaque references of the host JavaScript heap. As long as we have two heaps that coexist in this way, the best we can do is representing JavaScript references as-unique ids in the Haskell heap.+ids in the Haskell heap. -In JavaScript, we have a JSValManager which exposes some interfaces as-wasm imports. The JSValManager is in charge of allocating unique ids-and managing the mapping from ids to the actual JavaScript values. In-fact we can implement the entire JSValManager in wasm, using a wasm-table with externref elements to hold the JavaScript values and a-special allocator to manage free slots in the table. That'll take more-work to implement though, with one more caveat: browsers typically-limit max wasm table size to 10000000 which may not be large enough-for some use cases. We can workaround the table size restriction by-managing a pool or tree of wasm tables, but at this point we really-should ditch the idea of doing everything in wasm just because we can.+First, we have the unlifted JSVal# type, defined in jsval.cmm with the+following memory layout: -Next, we have the unlifted JSVal# type, defined in jsval.cmm and-contains one non-pointer word which is the id allocated by-JSValManager. On top of JSVal#, we have the user-facing lifted JSVal-type, which carries the JSVal#, as well as a weak pointer and a stable-pointer.++--------------+-----+----+----------++|stg_JSVAL_info|Weak#|Int#|StablePtr#|++--------------+-----+----+----------+ -The weak pointer is used to garbage collect JSVals. Its key is the-JSVal# closure, and it has a C finalizer that tells the JSValManager-to drop the mapping when the JSVal# closure is collected. Since we-want to provide freeJSVal to allow eager freeing of JSVals, we need to-carry it as a field of JSVal.+The first non-pointer Int# field is a 32-bit id allocated and+returned by the JSValManager on the JavaScript side. The JSValManager+maintains a Map from ids to actual JavaScript values. This field is+immutable throughout a JSVal# closure's lifetime and is unique for+each JSVal# ever created. -The stable pointer field is NULL for normal JSVals created via foreign-import results or foreign export arguments. But for JSFFI dynamic-exports that wraps a Haskell function closure as a JavaScript callback-and returns that callback's JSVal, it is a stable pointer that pins-that Haskell function closure. If this JSVal is garbage collected,-then we can only rely on a JavaScript FinalizerRegistry to free the-stable pointer in the future, but if we eagerly free the callback with-freeJSVal, then we can eagerly free this stable pointer as well.+The Weak# poiner sets the JSVal# closure as key and has a C finalizer+that drops the mapping in JSValManager. When the JSVal# closure is+garbage collected, the finalizer is invoked, but it can also be+eagerly invoked by freeJSVal, that's why we carry the Weak# in JSVal#+as a pointer field. -The lifted JSVal type is meant to be an abstract type. Its creation-and consumption is mainly handled by the RTS API functions rts_mkJSVal-and rts_getJSVal, which are used in C stub files generated when-desugaring JSFFI foreign imports/exports.+Normally, one JSVal# manage one kind of resource: the JavaScript value+retained in JSValManager. However, in case of JSFFI exports where we+convert Haskell functions to JavaScript callbacks, the JSVal# manages+not only the callback on the JavaScript side, but also a stable+pointer that pins the exported function on the Haskell side. That+StablePtr# is recorded in the JSVal# closure. +Even if the JSVal# closure is garbage collected, we don't know if the+JavaScript side still retains the callback somewhere other than+JSValManager, so the stable pointer will continue to pin the Haskell+function closure. We do a best effort cleanup on the JavaScript side+by using a FinalizationRegistry: if the JSVal# is automatically+collected, the callback is dropped in JSValManager and also not used+elsewhere, the FinalizationRegistry calls into the RTS to drop the+stable pointer as well.++However, JSVal# can be eagerly freed by freeJSVal. It'll deregister+the callback in the FinalizationRegistry, finalize the Weak# pointer+and also free the stable pointer. In order to make freeJSVal+idempotent, we must not free the stable pointer twice; therefore the+StablePtr# field is mutable and will be overwritten with NULL upon+first freeJSVal invocation; it's also NULL upon creation by+rts_mkJSVal and later overwritten with the StablePtr# upon the+callback creation.++On top of JSVal#, we have the user-facing lifted JSVal type, which+wraps the JSVal#. The lifted JSVal type is meant to be an abstract+type. Its creation and consumption is mainly handled by the RTS API+functions rts_mkJSVal and rts_getJSVal, which are used in C stub files+generated when desugaring JSFFI foreign imports/exports.+ -}  newtype JSVal#   = JSVal# (Any :: UnliftedType) +-- | A 'JSVal' is a first-class Haskell value on the Haskell heap that+-- represents a JavaScript value. You can use 'JSVal' or its @newtype@+-- as a supported argument or result type in JSFFI import & export+-- declarations, in addition to those lifted FFI types like 'Int' or+-- 'Ptr' that's already supported by C FFI. It is garbage collected by+-- the GHC RTS:+--+-- * There can be different 'JSVal's that point to the same JavaScript+--   value. As long as there's at least one 'JSVal' still alive on the+--   Haskell heap, that JavaScript value will still be alive on the+--   JavaScript heap.+-- * If there's no longer any live 'JSVal' that points to the+--   JavaScript value, after Haskell garbage collection, the+--   JavaScript runtime will be able to eventually garbage collect+--   that JavaScript value as well.+--+-- There's a special kind of 'JSVal' that represents a JavaScript+-- callback exported from a Haskell function like this:+--+-- > foreign import javascript "wrapper"+-- >   exportFibAsAsyncJSCallback :: (Int -> Int) -> IO JSVal+--+-- Such a 'JSVal' manages an additional kind of resource: the exported+-- Haskell function closure. Even if it is automatically garbage+-- collected, the Haskell function closure would still be retained+-- since the JavaScript callback might be retained elsewhere. We do a+-- best-effort collection here using JavaScript+-- [@FinalizationRegistry@](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry),+-- so the Haskell function closure might be eventually dropped if the+-- JavaScript callback is garbage collected.+--+-- Note that even the @FinalizationRegistry@ logic can't break cyclic+-- references between the Haskell/JavaScript heap: when an exported+-- Haskell function closure retains a 'JSVal' that represents a+-- JavaScript callback. Though this can be solved by explicit+-- 'freeJSVal' calls. data JSVal-  = forall a . JSVal JSVal# (Weak# JSVal#) (StablePtr# a)+  = JSVal JSVal# +-- | 'freeJSVal' eagerly frees a 'JSVal' in the runtime. It drops the+-- retained JavaScript value on the JavaScript side, and in case of a+-- 'JSVal' that represents a callback, also drops the retained Haskell+-- function closure. Once a 'JSVal' is freed by 'freeJSVal', later+-- attempts to pass it to the JavaScript side would result in runtime+-- crashes, so you should only call 'freeJSVal' when you're confident+-- that 'JSVal' won't be used again (and in case of callbacks, that+-- callback won't be invoked again).+--+-- 'freeJSVal' is idempotent: it's safe to call it more than once on+-- the same 'JSVal', subsequent invocations are no-ops. You are+-- strongly recommended to call 'freeJSVal' on short-lived+-- intermediate 'JSVal' values for timely release of resources! freeJSVal :: JSVal -> IO ()-freeJSVal v@(JSVal _ w sp) = do-  case sp `eqStablePtr#` unsafeCoerce# nullAddr# of-    0# -> do-      js_callback_unregister v-      freeStablePtr $ StablePtr sp-    _ -> pure ()-  IO $ \s0 -> case finalizeWeak# w s0 of+freeJSVal v@(JSVal p) = do+  js_callback_unregister v+  IO $ \s0 -> case stg_freeJSVal# p s0 of     (# s1, _, _ #) -> (# s1, () #) -foreign import javascript unsafe "if (!__ghc_wasm_jsffi_finalization_registry.unregister($1)) { throw new WebAssembly.RuntimeError('js_callback_unregister'); }"+-- | 'mkWeakJSVal' allows you to create a 'Weak' pointer that observes+-- the liveliness of a 'JSVal' closure on the Haskell heap and+-- optionally attach a finalizer.+--+-- Note that this liveliness is not affected by 'freeJSVal': even if+-- 'freeJSVal' is called, the 'JSVal' might still be alive on the+-- Haskell heap as a dangling reference and 'deRefWeak' might still be+-- able to retrieve the 'JSVal' before it is garbage collected.+mkWeakJSVal :: JSVal -> Maybe (IO ()) -> IO (Weak JSVal)+mkWeakJSVal v@(JSVal p) (Just (IO fin)) = IO $ \s0 ->+  case mkWeak# p v fin s0 of+    (# s1, w #) -> (# s1, Weak w #)+mkWeakJSVal v@(JSVal p) Nothing = IO $ \s0 ->+  case mkWeakNoFinalizer# p v s0 of+    (# s1, w #) -> (# s1, Weak w #)++foreign import prim "stg_freeJSVAL"+  stg_freeJSVal# :: JSVal# -> State# RealWorld -> (# State# RealWorld, Int#, State# RealWorld -> (# State# RealWorld, b #) #)++foreign import javascript unsafe "try { __ghc_wasm_jsffi_finalization_registry.unregister($1); } catch {}"   js_callback_unregister :: JSVal -> IO () +-- | A 'JSString' represents a JavaScript string. newtype JSString   = JSString JSVal +-- | Converts a 'JSString' to a Haskell 'String'. Conversion is done+-- eagerly once the resulting 'String' is forced, and the argument+-- 'JSString' may be explicitly freed if no longer used. fromJSString :: JSString -> String fromJSString s = unsafeDupablePerformIO $ do   l <- js_stringLength s@@ -114,15 +196,25 @@ foreign import javascript unsafe "(new TextEncoder()).encodeInto($1, new Uint8Array(__exports.memory.buffer, $2, $3)).written"   js_encodeInto :: JSString -> Ptr a -> Int -> IO Int +-- | Converts a Haskell 'String' to a 'JSString'. toJSString :: String -> JSString toJSString s = unsafeDupablePerformIO $ withCStringLen utf8 s $ \(buf, len) -> js_toJSString buf len  foreign import javascript unsafe "(new TextDecoder('utf-8', {fatal: true})).decode(new Uint8Array(__exports.memory.buffer, $1, $2))"   js_toJSString :: Ptr a -> Int -> IO JSString +-- | A 'JSException' represents a JavaScript exception. It is likely+-- but not guaranteed to be an instance of the @Error@ class. When you+-- call an async JSFFI import and the result @Promise@ rejected, the+-- rejection value will be wrapped in a 'JSException' and re-thrown in+-- Haskell once you force the result. newtype JSException   = JSException JSVal +-- | If the+-- [@error.stack@](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack)+-- property is present, it will be used to render the 'Show' instance+-- output so you can see the JavaScript stack trace. instance Show JSException where   showsPrec p e =     showParen (p >= 11) $ showString "JSException " . showsPrec 11 (jsErrorString e)@@ -139,14 +231,26 @@  instance Exception JSException -data WouldBlockException-  = WouldBlockException+-- | An async JSFFI import returns a thunk that represents a pending+-- JavaScript @Promise@:+--+-- > foreign import javascript "(await fetch($1)).text()"+-- >   js_fetch :: JSString -> IO JSString+--+-- Forcing that thunk blocks the current Haskell thread until the+-- @Promise@ is fulfilled, but that cannot happen if the Haskell+-- thread is a bound thread created by a JSFFI sync export or a C FFI+-- export! Those Haskell computations are meant to return+-- synchronously, but JavaScript asynchronocity is contagious and+-- there's no escape hatch like @unsafeAwaitPromise@.+--+-- In such cases, a 'WouldBlockException' exception would be thrown.+-- The 'WouldBlockException' is attached with a diagnostic message+-- generated at compile-time (currently just the JSFFI source snippet+-- of the corresponding async import) to help debugging the+-- exception's cause.+newtype WouldBlockException+  = WouldBlockException String   deriving (Show)  instance Exception WouldBlockException--data PromisePendingException-  = PromisePendingException-  deriving (Show)--instance Exception PromisePendingException