Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
e9de9e0b
by Sylvain Henry at 2025-05-23T15:12:34-04:00
8 changed files:
- compiler/GHC.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/Runtime/Debugger/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- ghc/GHCi/UI.hs
Changes:
| ... | ... | @@ -1307,7 +1307,7 @@ typecheckModule pmod = do |
| 1307 | 1307 | minf_instances = fixSafeInstances safe $ instEnvElts $ md_insts details,
|
| 1308 | 1308 | minf_iface = Nothing,
|
| 1309 | 1309 | minf_safe = safe,
|
| 1310 | - minf_modBreaks = emptyModBreaks
|
|
| 1310 | + minf_modBreaks = Nothing
|
|
| 1311 | 1311 | }}
|
| 1312 | 1312 | |
| 1313 | 1313 | -- | Desugar a typechecked module.
|
| ... | ... | @@ -1461,7 +1461,7 @@ data ModuleInfo = ModuleInfo { |
| 1461 | 1461 | minf_instances :: [ClsInst],
|
| 1462 | 1462 | minf_iface :: Maybe ModIface,
|
| 1463 | 1463 | minf_safe :: SafeHaskellMode,
|
| 1464 | - minf_modBreaks :: ModBreaks
|
|
| 1464 | + minf_modBreaks :: Maybe ModBreaks
|
|
| 1465 | 1465 | }
|
| 1466 | 1466 | -- We don't want HomeModInfo here, because a ModuleInfo applies
|
| 1467 | 1467 | -- to package modules too.
|
| ... | ... | @@ -1490,7 +1490,7 @@ getPackageModuleInfo hsc_env mdl |
| 1490 | 1490 | minf_instances = error "getModuleInfo: instances for package module unimplemented",
|
| 1491 | 1491 | minf_iface = Just iface,
|
| 1492 | 1492 | minf_safe = getSafeMode $ mi_trust iface,
|
| 1493 | - minf_modBreaks = emptyModBreaks
|
|
| 1493 | + minf_modBreaks = Nothing
|
|
| 1494 | 1494 | }))
|
| 1495 | 1495 | |
| 1496 | 1496 | availsToGlobalRdrEnv :: HasDebugCallStack => HscEnv -> Module -> [AvailInfo] -> IfGlobalRdrEnv
|
| ... | ... | @@ -1567,7 +1567,7 @@ modInfoIface = minf_iface |
| 1567 | 1567 | modInfoSafe :: ModuleInfo -> SafeHaskellMode
|
| 1568 | 1568 | modInfoSafe = minf_safe
|
| 1569 | 1569 | |
| 1570 | -modInfoModBreaks :: ModuleInfo -> ModBreaks
|
|
| 1570 | +modInfoModBreaks :: ModuleInfo -> Maybe ModBreaks
|
|
| 1571 | 1571 | modInfoModBreaks = minf_modBreaks
|
| 1572 | 1572 | |
| 1573 | 1573 | isDictonaryId :: Id -> Bool
|
| ... | ... | @@ -19,7 +19,7 @@ module GHC.ByteCode.Types |
| 19 | 19 | , ItblEnv, ItblPtr(..)
|
| 20 | 20 | , AddrEnv, AddrPtr(..)
|
| 21 | 21 | , CgBreakInfo(..)
|
| 22 | - , ModBreaks (..), BreakIndex, emptyModBreaks
|
|
| 22 | + , ModBreaks (..), BreakIndex
|
|
| 23 | 23 | , CCostCentre
|
| 24 | 24 | , FlatBag, sizeFlatBag, fromSmallArray, elemsFlatBag
|
| 25 | 25 | ) where
|
| ... | ... | @@ -45,12 +45,11 @@ import Foreign |
| 45 | 45 | import Data.Array
|
| 46 | 46 | import Data.ByteString (ByteString)
|
| 47 | 47 | import Data.IntMap (IntMap)
|
| 48 | -import qualified Data.IntMap as IntMap
|
|
| 49 | 48 | import qualified GHC.Exts.Heap as Heap
|
| 50 | 49 | import GHC.Stack.CCS
|
| 51 | 50 | import GHC.Cmm.Expr ( GlobalRegSet, emptyRegSet, regSetToList )
|
| 52 | 51 | import GHC.Iface.Syntax
|
| 53 | -import Language.Haskell.Syntax.Module.Name (ModuleName, mkModuleNameFS)
|
|
| 52 | +import Language.Haskell.Syntax.Module.Name (ModuleName)
|
|
| 54 | 53 | import GHC.Unit.Types (UnitId(..))
|
| 55 | 54 | |
| 56 | 55 | -- -----------------------------------------------------------------------------
|
| ... | ... | @@ -250,7 +249,7 @@ data CCostCentre |
| 250 | 249 | -- | All the information about the breakpoints for a module
|
| 251 | 250 | data ModBreaks
|
| 252 | 251 | = ModBreaks
|
| 253 | - { modBreaks_flags :: ForeignRef BreakArray
|
|
| 252 | + { modBreaks_flags :: !(ForeignRef BreakArray)
|
|
| 254 | 253 | -- ^ The array of flags, one per breakpoint,
|
| 255 | 254 | -- indicating which breakpoints are enabled.
|
| 256 | 255 | , modBreaks_locs :: !(Array BreakIndex SrcSpan)
|
| ... | ... | @@ -281,20 +280,6 @@ seqModBreaks ModBreaks{..} = |
| 281 | 280 | rnf modBreaks_module `seq`
|
| 282 | 281 | rnf modBreaks_module_unitid
|
| 283 | 282 | |
| 284 | --- | Construct an empty ModBreaks
|
|
| 285 | -emptyModBreaks :: ModBreaks
|
|
| 286 | -emptyModBreaks = ModBreaks
|
|
| 287 | - { modBreaks_flags = error "ModBreaks.modBreaks_array not initialised"
|
|
| 288 | - -- ToDo: can we avoid this?
|
|
| 289 | - , modBreaks_locs = array (0,-1) []
|
|
| 290 | - , modBreaks_vars = array (0,-1) []
|
|
| 291 | - , modBreaks_decls = array (0,-1) []
|
|
| 292 | - , modBreaks_ccs = array (0,-1) []
|
|
| 293 | - , modBreaks_breakInfo = IntMap.empty
|
|
| 294 | - , modBreaks_module = mkModuleNameFS nilFS
|
|
| 295 | - , modBreaks_module_unitid = UnitId nilFS
|
|
| 296 | - }
|
|
| 297 | - |
|
| 298 | 283 | {-
|
| 299 | 284 | Note [Field modBreaks_decls]
|
| 300 | 285 | ~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -18,6 +18,7 @@ import GHC.Utils.Outputable as Outputable |
| 18 | 18 | |
| 19 | 19 | import Data.List (intersperse)
|
| 20 | 20 | import Data.Array
|
| 21 | +import qualified Data.IntMap as IntMap
|
|
| 21 | 22 | |
| 22 | 23 | -- | Initialize memory for breakpoint data that is shared between the bytecode
|
| 23 | 24 | -- generator and the interpreter.
|
| ... | ... | @@ -38,15 +39,16 @@ mkModBreaks interp mod extendedMixEntries |
| 38 | 39 | locsTicks = listArray (0,count-1) [ tick_loc t | t <- entries ]
|
| 39 | 40 | varsTicks = listArray (0,count-1) [ tick_ids t | t <- entries ]
|
| 40 | 41 | declsTicks = listArray (0,count-1) [ tick_path t | t <- entries ]
|
| 41 | - return $ emptyModBreaks
|
|
| 42 | - { modBreaks_flags = breakArray
|
|
| 43 | - , modBreaks_locs = locsTicks
|
|
| 44 | - , modBreaks_vars = varsTicks
|
|
| 45 | - , modBreaks_decls = declsTicks
|
|
| 46 | - , modBreaks_ccs = ccs
|
|
| 47 | - , modBreaks_module = moduleName mod
|
|
| 48 | - , modBreaks_module_unitid = toUnitId $ moduleUnit mod
|
|
| 49 | - }
|
|
| 42 | + return $ ModBreaks
|
|
| 43 | + { modBreaks_flags = breakArray
|
|
| 44 | + , modBreaks_locs = locsTicks
|
|
| 45 | + , modBreaks_vars = varsTicks
|
|
| 46 | + , modBreaks_decls = declsTicks
|
|
| 47 | + , modBreaks_ccs = ccs
|
|
| 48 | + , modBreaks_breakInfo = IntMap.empty
|
|
| 49 | + , modBreaks_module = moduleName mod
|
|
| 50 | + , modBreaks_module_unitid = toUnitId $ moduleUnit mod
|
|
| 51 | + }
|
|
| 50 | 52 | |
| 51 | 53 | mkCCSArray
|
| 52 | 54 | :: Interp -> Module -> Int -> [Tick]
|
| ... | ... | @@ -145,15 +145,17 @@ resolveFunctionBreakpoint inp = do |
| 145 | 145 | validateBP _ "" (Just _) = pure $ Just $ text "Function name is missing"
|
| 146 | 146 | validateBP _ fun_str (Just modl) = do
|
| 147 | 147 | isInterpr <- GHC.moduleIsInterpreted modl
|
| 148 | - (_, decls) <- getModBreak modl
|
|
| 149 | 148 | mb_err_msg <- case isInterpr of
|
| 150 | - False -> pure $ Just $ text "Module" <+> quotes (ppr modl)
|
|
| 151 | - <+> text "is not interpreted"
|
|
| 152 | - True -> case fun_str `elem` (intercalate "." <$> elems decls) of
|
|
| 153 | - False -> pure $ Just $
|
|
| 154 | - text "No breakpoint found for" <+> quotes (text fun_str)
|
|
| 155 | - <+> text "in module" <+> quotes (ppr modl)
|
|
| 156 | - True -> pure Nothing
|
|
| 149 | + False -> pure $ Just $ text "Module" <+> quotes (ppr modl) <+> text "is not interpreted"
|
|
| 150 | + True -> do
|
|
| 151 | + mb_modbreaks <- getModBreak modl
|
|
| 152 | + let found = case mb_modbreaks of
|
|
| 153 | + Nothing -> False
|
|
| 154 | + Just mb -> fun_str `elem` (intercalate "." <$> elems (GHC.modBreaks_decls mb))
|
|
| 155 | + if found
|
|
| 156 | + then pure Nothing
|
|
| 157 | + else pure $ Just $ text "No breakpoint found for" <+> quotes (text fun_str)
|
|
| 158 | + <+> text "in module" <+> quotes (ppr modl)
|
|
| 157 | 159 | pure mb_err_msg
|
| 158 | 160 | |
| 159 | 161 | -- | The aim of this function is to find the breakpoints for all the RHSs of
|
| ... | ... | @@ -184,8 +186,7 @@ type TickArray = Array Int [(GHC.BreakIndex,RealSrcSpan)] |
| 184 | 186 | makeModuleLineMap :: GhcMonad m => Module -> m (Maybe TickArray)
|
| 185 | 187 | makeModuleLineMap m = do
|
| 186 | 188 | mi <- GHC.getModuleInfo m
|
| 187 | - return $
|
|
| 188 | - mkTickArray . assocs . GHC.modBreaks_locs . GHC.modInfoModBreaks <$> mi
|
|
| 189 | + return $ mkTickArray . assocs . GHC.modBreaks_locs <$> (GHC.modInfoModBreaks =<< mi)
|
|
| 189 | 190 | where
|
| 190 | 191 | mkTickArray :: [(BreakIndex, SrcSpan)] -> TickArray
|
| 191 | 192 | mkTickArray ticks
|
| ... | ... | @@ -195,15 +196,12 @@ makeModuleLineMap m = do |
| 195 | 196 | max_line = foldr max 0 [ GHC.srcSpanEndLine sp | (_, RealSrcSpan sp _) <- ticks ]
|
| 196 | 197 | srcSpanLines pan = [ GHC.srcSpanStartLine pan .. GHC.srcSpanEndLine pan ]
|
| 197 | 198 | |
| 198 | --- | Get the 'modBreaks_locs' and 'modBreaks_decls' of the given 'Module'
|
|
| 199 | +-- | Get the 'ModBreaks' of the given 'Module' when available
|
|
| 199 | 200 | getModBreak :: GHC.GhcMonad m
|
| 200 | - => Module -> m (Array Int SrcSpan, Array Int [String])
|
|
| 201 | + => Module -> m (Maybe ModBreaks)
|
|
| 201 | 202 | getModBreak m = do
|
| 202 | 203 | mod_info <- fromMaybe (panic "getModBreak") <$> GHC.getModuleInfo m
|
| 203 | - let modBreaks = GHC.modInfoModBreaks mod_info
|
|
| 204 | - let ticks = GHC.modBreaks_locs modBreaks
|
|
| 205 | - let decls = GHC.modBreaks_decls modBreaks
|
|
| 206 | - return (ticks, decls)
|
|
| 204 | + pure $ GHC.modInfoModBreaks mod_info
|
|
| 207 | 205 | |
| 208 | 206 | --------------------------------------------------------------------------------
|
| 209 | 207 | -- Getting current breakpoint information
|
| ... | ... | @@ -522,9 +522,8 @@ result_fs = fsLit "_result" |
| 522 | 522 | |
| 523 | 523 | -- | Read the 'ModBreaks' of the given home 'Module' from the 'HomeUnitGraph'.
|
| 524 | 524 | readModBreaks :: HscEnv -> Module -> IO ModBreaks
|
| 525 | -readModBreaks hsc_env mod =
|
|
| 526 | - getModBreaks . expectJust <$>
|
|
| 527 | - HUG.lookupHugByModule mod (hsc_HUG hsc_env)
|
|
| 525 | +readModBreaks hsc_env mod = expectJust . getModBreaks . expectJust <$> HUG.lookupHugByModule mod (hsc_HUG hsc_env)
|
|
| 526 | + |
|
| 528 | 527 | |
| 529 | 528 | bindLocalsAtBreakpoint
|
| 530 | 529 | :: HscEnv
|
| ... | ... | @@ -435,22 +435,24 @@ handleSeqHValueStatus interp unit_env eval_status = |
| 435 | 435 | resume_ctxt_fhv <- liftIO $ mkFinalizedHValue interp resume_ctxt
|
| 436 | 436 | |
| 437 | 437 | let put x = putStrLn ("*** Ignoring breakpoint " ++ (showSDocUnsafe x))
|
| 438 | + let nothing_case = put $ brackets . ppr $ mkGeneralSrcSpan (fsLit "<unknown>")
|
|
| 438 | 439 | case maybe_break of
|
| 439 | - Nothing ->
|
|
| 440 | + Nothing -> nothing_case
|
|
| 440 | 441 | -- Nothing case - should not occur!
|
| 441 | 442 | -- Reason: Setting of flags in libraries/ghci/GHCi/Run.hs:evalOptsSeq
|
| 442 | - put $ brackets . ppr $
|
|
| 443 | - mkGeneralSrcSpan (fsLit "<unknown>")
|
|
| 444 | 443 | |
| 445 | 444 | Just break -> do
|
| 446 | 445 | let bi = evalBreakpointToId break
|
| 447 | 446 | |
| 448 | 447 | -- Just case: Stopped at a breakpoint, extract SrcSpan information
|
| 449 | 448 | -- from the breakpoint.
|
| 450 | - breaks_tick <- getModBreaks . expectJust <$>
|
|
| 449 | + mb_modbreaks <- getModBreaks . expectJust <$>
|
|
| 451 | 450 | lookupHugByModule (ibi_tick_mod bi) (ue_home_unit_graph unit_env)
|
| 452 | - put $ brackets . ppr $
|
|
| 453 | - (modBreaks_locs breaks_tick) ! ibi_tick_index bi
|
|
| 451 | + case mb_modbreaks of
|
|
| 452 | + -- Nothing case - should not occur! We should have the appropriate
|
|
| 453 | + -- breakpoint information
|
|
| 454 | + Nothing -> nothing_case
|
|
| 455 | + Just modbreaks -> put $ brackets . ppr $ (modBreaks_locs modbreaks) ! ibi_tick_index bi
|
|
| 454 | 456 | |
| 455 | 457 | -- resume the seq (:force) processing in the iserv process
|
| 456 | 458 | withForeignRef resume_ctxt_fhv $ \hval -> do
|
| ... | ... | @@ -737,14 +739,14 @@ fromEvalResult :: EvalResult a -> IO a |
| 737 | 739 | fromEvalResult (EvalException e) = throwIO (fromSerializableException e)
|
| 738 | 740 | fromEvalResult (EvalSuccess a) = return a
|
| 739 | 741 | |
| 740 | -getModBreaks :: HomeModInfo -> ModBreaks
|
|
| 742 | +getModBreaks :: HomeModInfo -> Maybe ModBreaks
|
|
| 741 | 743 | getModBreaks hmi
|
| 742 | 744 | | Just linkable <- homeModInfoByteCode hmi,
|
| 743 | 745 | -- The linkable may have 'DotO's as well; only consider BCOs. See #20570.
|
| 744 | 746 | [cbc] <- linkableBCOs linkable
|
| 745 | - = fromMaybe emptyModBreaks (bc_breaks cbc)
|
|
| 747 | + = bc_breaks cbc
|
|
| 746 | 748 | | otherwise
|
| 747 | - = emptyModBreaks -- probably object code
|
|
| 749 | + = Nothing -- probably object code
|
|
| 748 | 750 | |
| 749 | 751 | -- | Interpreter uses Profiling way
|
| 750 | 752 | interpreterProfiled :: Interp -> Bool
|
| ... | ... | @@ -439,8 +439,8 @@ schemeER_wrk d p rhs = schemeE d 0 p rhs |
| 439 | 439 | --
|
| 440 | 440 | -- If the breakpoint is inlined from another module, look it up in the home
|
| 441 | 441 | -- package table.
|
| 442 | --- If the module doesn't exist there, or its module pointer is null (which means
|
|
| 443 | --- that the 'ModBreaks' value is uninitialized), skip the instruction.
|
|
| 442 | +-- If the module doesn't exist there, or if the 'ModBreaks' value is
|
|
| 443 | +-- uninitialized, skip the instruction (i.e. return Nothing).
|
|
| 444 | 444 | break_info ::
|
| 445 | 445 | HscEnv ->
|
| 446 | 446 | Module ->
|
| ... | ... | @@ -449,18 +449,11 @@ break_info :: |
| 449 | 449 | BcM (Maybe ModBreaks)
|
| 450 | 450 | break_info hsc_env mod current_mod current_mod_breaks
|
| 451 | 451 | | mod == current_mod
|
| 452 | - = pure $ check_mod_ptr =<< current_mod_breaks
|
|
| 452 | + = pure current_mod_breaks
|
|
| 453 | 453 | | otherwise
|
| 454 | 454 | = ioToBc (lookupHpt (hsc_HPT hsc_env) (moduleName mod)) >>= \case
|
| 455 | - Just hp -> pure $ check_mod_ptr (getModBreaks hp)
|
|
| 455 | + Just hp -> pure $ getModBreaks hp
|
|
| 456 | 456 | Nothing -> pure Nothing
|
| 457 | - where
|
|
| 458 | - check_mod_ptr mb
|
|
| 459 | - | mod_ptr <- modBreaks_module mb
|
|
| 460 | - , not $ nullFS $ moduleNameFS mod_ptr
|
|
| 461 | - = Just mb
|
|
| 462 | - | otherwise
|
|
| 463 | - = Nothing
|
|
| 464 | 457 | |
| 465 | 458 | getVarOffSets :: Platform -> StackDepth -> BCEnv -> [Id] -> [Maybe (Id, WordOff)]
|
| 466 | 459 | getVarOffSets platform depth env = map getOffSet
|
| ... | ... | @@ -3629,8 +3629,10 @@ completeBreakpoint = wrapCompleter spaces $ \w -> do -- #3000 |
| 3629 | 3629 | -- Return all possible bids for a given Module
|
| 3630 | 3630 | bidsByModule :: GhciMonad m => [ModuleName] -> Module -> m [String]
|
| 3631 | 3631 | bidsByModule nonquals mod = do
|
| 3632 | - (_, decls) <- getModBreak mod
|
|
| 3633 | - let bids = nub $ declPath <$> elems decls
|
|
| 3632 | + mb_decls <- fmap GHC.modBreaks_decls <$> getModBreak mod
|
|
| 3633 | + let bids = case mb_decls of
|
|
| 3634 | + Just decls -> nub $ declPath <$> elems decls
|
|
| 3635 | + Nothing -> []
|
|
| 3634 | 3636 | pure $ case (moduleName mod) `elem` nonquals of
|
| 3635 | 3637 | True -> bids
|
| 3636 | 3638 | False -> (combineModIdent (showModule mod)) <$> bids
|
| ... | ... | @@ -3656,11 +3658,14 @@ completeBreakpoint = wrapCompleter spaces $ \w -> do -- #3000 |
| 3656 | 3658 | -- declarations. See Note [Field modBreaks_decls] in GHC.ByteCode.Types
|
| 3657 | 3659 | addNestedDecls :: GhciMonad m => (String, Module) -> m [String]
|
| 3658 | 3660 | addNestedDecls (ident, mod) = do
|
| 3659 | - (_, decls) <- getModBreak mod
|
|
| 3660 | - let (mod_str, topLvl, _) = splitIdent ident
|
|
| 3661 | - ident_decls = [ elm | elm@(el : _) <- elems decls, el == topLvl ]
|
|
| 3662 | - bids = nub $ declPath <$> ident_decls
|
|
| 3663 | - pure $ map (combineModIdent mod_str) bids
|
|
| 3661 | + mb_decls <- fmap GHC.modBreaks_decls <$> getModBreak mod
|
|
| 3662 | + case mb_decls of
|
|
| 3663 | + Nothing -> pure []
|
|
| 3664 | + Just decls -> do
|
|
| 3665 | + let (mod_str, topLvl, _) = splitIdent ident
|
|
| 3666 | + ident_decls = [ elm | elm@(el : _) <- elems decls, el == topLvl ]
|
|
| 3667 | + bids = nub $ declPath <$> ident_decls
|
|
| 3668 | + pure $ map (combineModIdent mod_str) bids
|
|
| 3664 | 3669 | |
| 3665 | 3670 | completeModule = wrapIdentCompleterMod $ \w -> do
|
| 3666 | 3671 | hsc_env <- GHC.getSession
|
| ... | ... | @@ -4066,7 +4071,7 @@ breakById inp = do |
| 4066 | 4071 | case mb_error of
|
| 4067 | 4072 | Left sdoc -> printForUser sdoc
|
| 4068 | 4073 | Right (mod, mod_info, fun_str) -> do
|
| 4069 | - let modBreaks = GHC.modInfoModBreaks mod_info
|
|
| 4074 | + let modBreaks = expectJust (GHC.modInfoModBreaks mod_info)
|
|
| 4070 | 4075 | findBreakAndSet mod $ \_ -> findBreakForBind fun_str modBreaks
|
| 4071 | 4076 | |
| 4072 | 4077 | breakSyntax :: a
|