From ea2ea2d58c6d3b8b80becfe89f5ca23ee82235de Mon Sep 17 00:00:00 2001
From: Ben Gamari <ben@smart-cactus.org>
Date: Tue, 19 Nov 2024 14:53:54 -0500
Subject: [PATCH] ghci: Don't rely on Uniques in BRK_FUN

This is a partial backport of the treatment given to modules names in
!10448, removing the dependence of BRK_FUN on the representation of
`Unique`.
---
 compiler/GHC/ByteCode/Asm.hs         |  7 +++----
 compiler/GHC/ByteCode/Instr.hs       | 10 +++-------
 compiler/GHC/ByteCode/Types.hs       |  6 +++++-
 compiler/GHC/HsToCore/Breakpoints.hs | 12 +++++++-----
 compiler/GHC/Runtime/Eval.hs         | 10 ++++------
 compiler/GHC/Runtime/Interpreter.hs  | 11 +++++++----
 compiler/GHC/StgToByteCode.hs        | 14 ++++++++------
 libraries/ghci/GHCi/Message.hs       | 15 ++++++++++++++-
 libraries/ghci/GHCi/Run.hs           | 12 +++++++++---
 rts/Interpreter.c                    |  8 ++++----
 10 files changed, 64 insertions(+), 41 deletions(-)

diff --git a/compiler/GHC/ByteCode/Asm.hs b/compiler/GHC/ByteCode/Asm.hs
index fab5cd40558..5d6842d88df 100644
--- a/compiler/GHC/ByteCode/Asm.hs
+++ b/compiler/GHC/ByteCode/Asm.hs
@@ -27,7 +27,6 @@ import GHC.Runtime.Heap.Layout ( fromStgWord, StgWord )
 import GHC.Types.Name
 import GHC.Types.Name.Set
 import GHC.Types.Literal
-import GHC.Types.Unique
 import GHC.Types.Unique.DSet
 
 import GHC.Utils.Outputable
@@ -518,11 +517,11 @@ assembleI platform i = case i of
   CCALL off m_addr i       -> do np <- addr m_addr
                                  emit bci_CCALL [wOp off, Op np, SmallOp i]
   PRIMCALL                 -> emit bci_PRIMCALL []
-  BRK_FUN index uniq cc    -> do p1 <- ptr BCOPtrBreakArray
-                                 q <- int (getKey uniq)
+  BRK_FUN index mod cc     -> do p1 <- ptr BCOPtrBreakArray
+                                 m <- addr mod
                                  np <- addr cc
                                  emit bci_BRK_FUN [Op p1, SmallOp index,
-                                                   Op q, Op np]
+                                                   Op m, Op np]
 
   where
     literal (LitLabel fs (Just sz) _)
diff --git a/compiler/GHC/ByteCode/Instr.hs b/compiler/GHC/ByteCode/Instr.hs
index a1ad9da5e9d..c9089e7eb5e 100644
--- a/compiler/GHC/ByteCode/Instr.hs
+++ b/compiler/GHC/ByteCode/Instr.hs
@@ -19,7 +19,6 @@ import GHCi.FFI (C_ffi_cif)
 import GHC.StgToCmm.Layout     ( ArgRep(..) )
 import GHC.Utils.Outputable
 import GHC.Types.Name
-import GHC.Types.Unique
 import GHC.Types.Literal
 import GHC.Core.DataCon
 import GHC.Builtin.PrimOps
@@ -31,6 +30,7 @@ import Data.Word
 import GHC.Stack.CCS (CostCentre)
 
 import GHC.Stg.Syntax
+import Language.Haskell.Syntax.Module.Name (ModuleName)
 
 -- ----------------------------------------------------------------------------
 -- Bytecode instructions
@@ -205,7 +205,7 @@ data BCInstr
                    -- Note [unboxed tuple bytecodes and tuple_BCO] in GHC.StgToByteCode
 
    -- Breakpoints
-   | BRK_FUN         !Word16 Unique (RemotePtr CostCentre)
+   | BRK_FUN         !Word16 (RemotePtr ModuleName) (RemotePtr CostCentre)
 
 -- -----------------------------------------------------------------------------
 -- Printing bytecode instructions
@@ -356,11 +356,7 @@ instance Outputable BCInstr where
    ppr ENTER                 = text "ENTER"
    ppr (RETURN pk)           = text "RETURN  " <+> ppr pk
    ppr (RETURN_TUPLE)        = text "RETURN_TUPLE"
-   ppr (BRK_FUN index uniq _cc) = text "BRK_FUN" <+> ppr index <+> mb_uniq <+> text "<cc>"
-     where mb_uniq = sdocOption sdocSuppressUniques $ \case
-             True  -> text "<uniq>"
-             False -> ppr uniq
-
+   ppr (BRK_FUN index _mod_name _cc) = text "BRK_FUN" <+> ppr index <+> text "<module>" <+> text "<cc>"
 
 
 -- -----------------------------------------------------------------------------
diff --git a/compiler/GHC/ByteCode/Types.hs b/compiler/GHC/ByteCode/Types.hs
index c555fb329e9..254e754f8cd 100644
--- a/compiler/GHC/ByteCode/Types.hs
+++ b/compiler/GHC/ByteCode/Types.hs
@@ -44,6 +44,7 @@ import qualified GHC.Exts.Heap as Heap
 import GHC.Stack.CCS
 import GHC.Cmm.Expr ( GlobalRegSet, emptyRegSet, regSetToList )
 import GHC.Iface.Syntax
+import Language.Haskell.Syntax.Module.Name (ModuleName)
 
 -- -----------------------------------------------------------------------------
 -- Compiled Byte Code
@@ -242,6 +243,7 @@ data ModBreaks
         -- ^ Array pointing to cost centre for each breakpoint
    , modBreaks_breakInfo :: IntMap CgBreakInfo
         -- ^ info about each breakpoint from the bytecode generator
+   , modBreaks_module :: RemotePtr ModuleName
    }
 
 seqModBreaks :: ModBreaks -> ()
@@ -251,7 +253,8 @@ seqModBreaks ModBreaks{..} =
   rnf modBreaks_vars `seq`
   rnf modBreaks_decls `seq`
   rnf modBreaks_ccs `seq`
-  rnf (fmap seqCgBreakInfo modBreaks_breakInfo)
+  rnf (fmap seqCgBreakInfo modBreaks_breakInfo) `seq`
+  rnf modBreaks_module
 
 -- | Construct an empty ModBreaks
 emptyModBreaks :: ModBreaks
@@ -263,6 +266,7 @@ emptyModBreaks = ModBreaks
    , modBreaks_decls = array (0,-1) []
    , modBreaks_ccs = array (0,-1) []
    , modBreaks_breakInfo = IntMap.empty
+   , modBreaks_module = toRemotePtr nullPtr
    }
 
 {-
diff --git a/compiler/GHC/HsToCore/Breakpoints.hs b/compiler/GHC/HsToCore/Breakpoints.hs
index bbf88fa5ee5..dc1b2cef04e 100644
--- a/compiler/GHC/HsToCore/Breakpoints.hs
+++ b/compiler/GHC/HsToCore/Breakpoints.hs
@@ -27,16 +27,18 @@ mkModBreaks interp mod extendedMixEntries
 
     breakArray <- GHCi.newBreakArray interp count
     ccs <- mkCCSArray interp mod count entries
+    mod_ptr <- GHCi.newModuleName interp (moduleName mod)
     let
            locsTicks  = listArray (0,count-1) [ tick_loc  t | t <- entries ]
            varsTicks  = listArray (0,count-1) [ tick_ids  t | t <- entries ]
            declsTicks = listArray (0,count-1) [ tick_path t | t <- entries ]
     return $ emptyModBreaks
-                       { modBreaks_flags = breakArray
-                       , modBreaks_locs  = locsTicks
-                       , modBreaks_vars  = varsTicks
-                       , modBreaks_decls = declsTicks
-                       , modBreaks_ccs   = ccs
+                       { modBreaks_flags  = breakArray
+                       , modBreaks_locs   = locsTicks
+                       , modBreaks_vars   = varsTicks
+                       , modBreaks_decls  = declsTicks
+                       , modBreaks_ccs    = ccs
+                       , modBreaks_module = mod_ptr
                        }
 
 mkCCSArray
diff --git a/compiler/GHC/Runtime/Eval.hs b/compiler/GHC/Runtime/Eval.hs
index 427a8797ee2..a0913c0eb59 100644
--- a/compiler/GHC/Runtime/Eval.hs
+++ b/compiler/GHC/Runtime/Eval.hs
@@ -325,15 +325,14 @@ handleRunStatus step expr bindings final_ids status history
   | otherwise              = not_tracing
  where
   tracing
-    | EvalBreak is_exception apStack_ref ix mod_uniq resume_ctxt _ccs <- status
+    | EvalBreak is_exception apStack_ref ix mod_name resume_ctxt _ccs <- status
     , not is_exception
     = do
        hsc_env <- getSession
        let interp = hscInterp hsc_env
        let dflags = hsc_dflags hsc_env
        let hmi = expectJust "handleRunStatus" $
-                   lookupHptDirectly (hsc_HPT hsc_env)
-                                     (mkUniqueGrimily mod_uniq)
+                   lookupHpt (hsc_HPT hsc_env) (mkModuleName mod_name)
            modl = mi_module (hm_iface hmi)
            breaks = getModBreaks hmi
 
@@ -358,15 +357,14 @@ handleRunStatus step expr bindings final_ids status history
 
   not_tracing
     -- Hit a breakpoint
-    | EvalBreak is_exception apStack_ref ix mod_uniq resume_ctxt ccs <- status
+    | EvalBreak is_exception apStack_ref ix mod_name resume_ctxt ccs <- status
     = do
          hsc_env <- getSession
          let interp = hscInterp hsc_env
          resume_ctxt_fhv <- liftIO $ mkFinalizedHValue interp resume_ctxt
          apStack_fhv <- liftIO $ mkFinalizedHValue interp apStack_ref
          let hmi = expectJust "handleRunStatus" $
-                     lookupHptDirectly (hsc_HPT hsc_env)
-                                       (mkUniqueGrimily mod_uniq)
+                     lookupHpt (hsc_HPT hsc_env) (mkModuleName mod_name)
              modl = mi_module (hm_iface hmi)
              bp | is_exception = Nothing
                 | otherwise = Just (BreakInfo modl ix)
diff --git a/compiler/GHC/Runtime/Interpreter.hs b/compiler/GHC/Runtime/Interpreter.hs
index 8ff9fcd36b6..e7711c178a2 100644
--- a/compiler/GHC/Runtime/Interpreter.hs
+++ b/compiler/GHC/Runtime/Interpreter.hs
@@ -25,6 +25,7 @@ module GHC.Runtime.Interpreter
   , mkCostCentres
   , costCentreStackInfo
   , newBreakArray
+  , newModuleName
   , storeBreakpoint
   , breakpointStatus
   , getBreakpointVar
@@ -84,7 +85,6 @@ import GHC.Linker.Types
 import GHC.Data.Maybe
 import GHC.Data.FastString
 
-import GHC.Types.Unique
 import GHC.Types.SrcLoc
 import GHC.Types.Unique.FM
 import GHC.Types.Basic
@@ -381,6 +381,10 @@ newBreakArray interp size = do
   breakArray <- interpCmd interp (NewBreakArray size)
   mkFinalizedHValue interp breakArray
 
+newModuleName :: Interp -> ModuleName -> IO (RemotePtr ModuleName)
+newModuleName interp mod_name =
+  castRemotePtr <$> interpCmd interp (NewBreakModule (moduleNameString mod_name))
+
 storeBreakpoint :: Interp -> ForeignRef BreakArray -> Int -> Int -> IO ()
 storeBreakpoint interp ref ix cnt = do                               -- #19157
   withForeignRef ref $ \breakarray ->
@@ -414,13 +418,12 @@ seqHValue interp unit_env ref =
 handleSeqHValueStatus :: Interp -> UnitEnv -> EvalStatus () -> IO (EvalResult ())
 handleSeqHValueStatus interp unit_env eval_status =
   case eval_status of
-    (EvalBreak is_exception _ ix mod_uniq resume_ctxt _) -> do
+    (EvalBreak is_exception _ ix mod_name resume_ctxt _) -> do
       -- A breakpoint was hit; inform the user and tell them
       -- which breakpoint was hit.
       resume_ctxt_fhv <- liftIO $ mkFinalizedHValue interp resume_ctxt
       let hmi = expectJust "handleRunStatus" $
-                  lookupHptDirectly (ue_hpt unit_env)
-                    (mkUniqueGrimily mod_uniq)
+                  lookupHpt (ue_hpt unit_env) (mkModuleName mod_name)
           modl = mi_module (hm_iface hmi)
           bp | is_exception = Nothing
              | otherwise = Just (BreakInfo modl ix)
diff --git a/compiler/GHC/StgToByteCode.hs b/compiler/GHC/StgToByteCode.hs
index c85f66528ac..d3a91cb511a 100644
--- a/compiler/GHC/StgToByteCode.hs
+++ b/compiler/GHC/StgToByteCode.hs
@@ -53,7 +53,6 @@ import GHC.Types.Var.Set
 import GHC.Builtin.Types.Prim
 import GHC.Core.TyCo.Ppr ( pprType )
 import GHC.Utils.Error
-import GHC.Types.Unique
 import GHC.Builtin.Uniques
 import GHC.Data.FastString
 import GHC.Utils.Panic
@@ -392,7 +391,6 @@ schemeER_wrk :: StackDepth -> BCEnv -> CgStgExpr -> BcM BCInstrList
 schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs) rhs)
   = do  code <- schemeE d 0 p rhs
         cc_arr <- getCCArray
-        this_mod <- moduleName <$> getCurrentModule
         platform <- profilePlatform <$> getProfile
         let idOffSets = getVarOffSets platform d p fvs
             ty_vars   = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
@@ -405,8 +403,12 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_no fvs) rhs)
                , interpreterProfiled interp
                = cc_arr ! tick_no
                | otherwise = toRemotePtr nullPtr
-        let breakInstr = BRK_FUN (fromIntegral tick_no) (getUnique this_mod) cc
-        return $ breakInstr `consOL` code
+        mb_mod_name <- getCurrentModuleName
+        case mb_mod_name of
+          Just mod_ptr -> do
+            let breakInstr = BRK_FUN (fromIntegral tick_no) mod_ptr cc
+            return $ breakInstr `consOL` code
+          Nothing -> return code
 schemeER_wrk d p rhs = schemeE d 0 p rhs
 
 getVarOffSets :: Platform -> StackDepth -> BCEnv -> [Id] -> [Maybe (Id, WordOff)]
@@ -2263,8 +2265,8 @@ newBreakInfo :: BreakIndex -> CgBreakInfo -> BcM ()
 newBreakInfo ix info = BcM $ \st ->
   return (st{breakInfo = IntMap.insert ix info (breakInfo st)}, ())
 
-getCurrentModule :: BcM Module
-getCurrentModule = BcM $ \st -> return (st, thisModule st)
+getCurrentModuleName :: BcM (Maybe (RemotePtr ModuleName))
+getCurrentModuleName = BcM $ \st -> return (st, modBreaks_module <$> modBreaks st)
 
 tickFS :: FastString
 tickFS = fsLit "ticked"
diff --git a/libraries/ghci/GHCi/Message.hs b/libraries/ghci/GHCi/Message.hs
index 5e2fb167add..762e4454d8c 100644
--- a/libraries/ghci/GHCi/Message.hs
+++ b/libraries/ghci/GHCi/Message.hs
@@ -22,6 +22,7 @@ module GHCi.Message
   , getMessage, putMessage, getTHMessage, putTHMessage
   , Pipe(..), remoteCall, remoteTHCall, readPipe, writePipe
   , LoadedDLL
+  , BreakModule
   ) where
 
 import Prelude -- See note [Why do we import Prelude here?]
@@ -228,6 +229,12 @@ data Message a where
     :: RemoteRef (ResumeContext ())
     -> Message (EvalStatus ())
 
+  -- | Allocate a string for a breakpoint module name.
+  -- This uses an empty dummy type because @ModuleName@ isn't available here.
+  NewBreakModule
+   :: String
+   -> Message (RemotePtr BreakModule)
+
 deriving instance Show (Message a)
 
 
@@ -382,7 +389,7 @@ data EvalStatus_ a b
   | EvalBreak Bool
        HValueRef{- AP_STACK -}
        Int {- break index -}
-       Int {- uniq of ModuleName -}
+       String {- module name -}
        (RemoteRef (ResumeContext b))
        (RemotePtr CostCentreStack) -- Cost centre stack
   deriving (Generic, Show)
@@ -396,6 +403,10 @@ data EvalResult a
 
 instance Binary a => Binary (EvalResult a)
 
+-- | A dummy type that tags the pointer to a breakpoint's @ModuleName@, because
+-- that type isn't available here.
+data BreakModule
+
 -- | A dummy type that tags pointers returned by 'LoadDLL'.
 data LoadedDLL
 
@@ -526,6 +537,7 @@ getMessage = do
       36 -> Msg <$> (Seq <$> get)
       37 -> Msg <$> return RtsRevertCAFs
       38 -> Msg <$> (ResumeSeq <$> get)
+      39 -> Msg <$> (NewBreakModule <$> get)
       40 -> Msg <$> (LookupSymbolInDLL <$> get <*> get)
       _  -> error $ "Unknown Message code " ++ (show b)
 
@@ -570,6 +582,7 @@ putMessage m = case m of
   Seq a                       -> putWord8 36 >> put a
   RtsRevertCAFs               -> putWord8 37
   ResumeSeq a                 -> putWord8 38 >> put a
+  NewBreakModule name         -> putWord8 39 >> put name
   LookupSymbolInDLL dll str   -> putWord8 40 >> put dll >> put str
 
 -- -----------------------------------------------------------------------------
diff --git a/libraries/ghci/GHCi/Run.hs b/libraries/ghci/GHCi/Run.hs
index a5fcd869582..57b4fe00760 100644
--- a/libraries/ghci/GHCi/Run.hs
+++ b/libraries/ghci/GHCi/Run.hs
@@ -96,6 +96,7 @@ run m = case m of
   MkCostCentres mod ccs -> mkCostCentres mod ccs
   CostCentreStackInfo ptr -> ccsToStrings (fromRemotePtr ptr)
   NewBreakArray sz -> mkRemoteRef =<< newBreakArray sz
+  NewBreakModule name -> newModuleName name
   SetupBreakpoint ref ix cnt -> do
     arr <- localRef ref;
     _ <- setupBreakpoint arr ix cnt
@@ -330,7 +331,7 @@ withBreakAction opts breakMVar statusMVar act
         -- as soon as it is hit, or in resetBreakAction below.
 
    onBreak :: BreakpointCallback
-   onBreak ix# uniq# is_exception apStack = do
+   onBreak ix# mod_name# is_exception apStack = do
      tid <- myThreadId
      let resume = ResumeContext
            { resumeBreakMVar = breakMVar
@@ -339,7 +340,8 @@ withBreakAction opts breakMVar statusMVar act
      resume_r <- mkRemoteRef resume
      apStack_r <- mkRemoteRef apStack
      ccs <- toRemotePtr <$> getCCSOf apStack
-     putMVar statusMVar $ EvalBreak is_exception apStack_r (I# ix#) (I# uniq#) resume_r ccs
+     mod_name <- if is_exception then return "<dummy>" else peekCString (Ptr mod_name#)
+     putMVar statusMVar $ EvalBreak is_exception apStack_r (I# ix#) mod_name resume_r ccs
      takeMVar breakMVar
 
    resetBreakAction stablePtr = do
@@ -388,7 +390,7 @@ resetStepFlag = poke stepFlag 0
 
 type BreakpointCallback
      = Int#    -- the breakpoint index
-    -> Int#    -- the module uniq
+    -> Addr#   -- the module name
     -> Bool    -- exception?
     -> HValue  -- the AP_STACK, or exception
     -> IO ()
@@ -435,6 +437,10 @@ foreign import ccall unsafe "mkCostCentre"
 mkCostCentres _ _ = return []
 #endif
 
+newModuleName :: String -> IO (RemotePtr BreakModule)
+newModuleName name =
+  castRemotePtr . toRemotePtr <$> newCString name
+
 getIdValFromApStack :: HValue -> Int -> IO (Maybe HValue)
 getIdValFromApStack apStack (I# stackDepth) = do
    case getApStackVal# apStack stackDepth of
diff --git a/rts/Interpreter.c b/rts/Interpreter.c
index 73fa5f941bd..552e41d94dd 100644
--- a/rts/Interpreter.c
+++ b/rts/Interpreter.c
@@ -1111,7 +1111,7 @@ run_BCO:
         /* check for a breakpoint on the beginning of a let binding */
         case bci_BRK_FUN:
         {
-            int arg1_brk_array, arg2_array_index, arg3_module_uniq;
+            int arg1_brk_array, arg2_array_index, arg3_module_name;
 #if defined(PROFILING)
             int arg4_cc;
 #endif
@@ -1129,7 +1129,7 @@ run_BCO:
 
             arg1_brk_array      = BCO_GET_LARGE_ARG;
             arg2_array_index    = BCO_NEXT;
-            arg3_module_uniq    = BCO_GET_LARGE_ARG;
+            arg3_module_name    = BCO_GET_LARGE_ARG;
 #if defined(PROFILING)
             arg4_cc             = BCO_GET_LARGE_ARG;
 #else
@@ -1194,7 +1194,7 @@ run_BCO:
                   // continue execution of this BCO when the IO action returns.
                   //
                   // ioAction :: Int#        -- the breakpoint index
-                  //          -> Int#        -- the module uniq
+                  //          -> Addr#       -- the module name
                   //          -> Bool        -- exception?
                   //          -> HValue      -- the AP_STACK, or exception
                   //          -> IO ()
@@ -1208,7 +1208,7 @@ run_BCO:
                   SpW(8)  = (W_)new_aps;
                   SpW(7)  = (W_)False_closure;         // True <=> an exception
                   SpW(6)  = (W_)&stg_ap_ppv_info;
-                  SpW(5)  = (W_)BCO_LIT(arg3_module_uniq);
+                  SpW(5)  = (W_)BCO_LIT(arg3_module_name);
                   SpW(4)  = (W_)&stg_ap_n_info;
                   SpW(3)  = (W_)arg2_array_index;
                   SpW(2)  = (W_)&stg_ap_n_info;
-- 
GitLab