Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC

Commits:

30 changed files:

Changes:

  • compiler/GHC.hs
    ... ... @@ -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
    

  • compiler/GHC/ByteCode/Types.hs
    ... ... @@ -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
     ~~~~~~~~~~~~~~~~~~~~~~
    

  • compiler/GHC/HsToCore/Breakpoints.hs
    ... ... @@ -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]
    

  • compiler/GHC/Runtime/Debugger/Breakpoints.hs
    ... ... @@ -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
    

  • compiler/GHC/Runtime/Eval.hs
    ... ... @@ -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
    

  • compiler/GHC/Runtime/Interpreter.hs
    ... ... @@ -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
    

  • compiler/GHC/StgToByteCode.hs
    ... ... @@ -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
    

  • ghc/GHCi/UI.hs
    ... ... @@ -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
    

  • libraries/base/changelog.md
    ... ... @@ -22,11 +22,13 @@
    22 22
           * `GHC.TypeNats.Internal`
    
    23 23
           * `GHC.ExecutionStack.Internal`.
    
    24 24
       * Deprecate `GHC.JS.Prim.Internal.Build`, as per [CLC #329](https://github.com/haskell/core-libraries-committee/issues/329)
    
    25
    +  * Expose constructor and field of `Backtraces` from `Control.Exception.Backtrace`, as per [CLC #199](https://github.com/haskell/core-libraries-committee/issues/199#issuecomment-1954662391)
    
    25 26
     
    
    26 27
       * Fix incorrect results of `integerPowMod` when the base is 0 and the exponent is negative, and `integerRecipMod` when the modulus is zero ([#26017](https://gitlab.haskell.org/ghc/ghc/-/issues/26017)).
    
    27 28
     
    
    28 29
     
    
    29
    -## 4.21.0.0 *TBA*
    
    30
    +## 4.21.0.0 *December 2024*
    
    31
    +  * Shipped with GHC 9.12.1
    
    30 32
       * Change `SrcLoc` to be a strict and unboxed (finishing [CLC proposal #55](https://github.com/haskell/core-libraries-committee/issues/55))
    
    31 33
       * Introduce `Data.Bounded` module exporting the `Bounded` typeclass (finishing [CLC proposal #208](https://github.com/haskell/core-libraries-committee/issues/208))
    
    32 34
       * Deprecate export of `Bounded` class from `Data.Enum` ([CLC proposal #208](https://github.com/haskell/core-libraries-committee/issues/208))
    
    ... ... @@ -311,29 +313,29 @@
    311 313
     
    
    312 314
       * Re-export the `IsList` typeclass from the new `GHC.IsList` module.
    
    313 315
     
    
    314
    -  * There's a new special function ``withDict`` in ``GHC.Exts``: ::
    
    316
    +  * There's a new special function `withDict` in `GHC.Exts`: ::
    
    315 317
     
    
    316 318
             withDict :: forall {rr :: RuntimeRep} cls meth (r :: TYPE rr). WithDict cls meth => meth -> (cls => r) -> r
    
    317 319
     
    
    318
    -    where ``cls`` must be a class containing exactly one method, whose type
    
    319
    -    must be ``meth``.
    
    320
    +    where `cls` must be a class containing exactly one method, whose type
    
    321
    +    must be `meth`.
    
    320 322
     
    
    321
    -    This function converts ``meth`` to a type class dictionary.
    
    322
    -    It removes the need for ``unsafeCoerce`` in implementation of reflection
    
    323
    +    This function converts `meth` to a type class dictionary.
    
    324
    +    It removes the need for `unsafeCoerce` in implementation of reflection
    
    323 325
         libraries. It should be used with care, because it can introduce
    
    324 326
         incoherent instances.
    
    325 327
     
    
    326
    -    For example, the ``withTypeable`` function from the
    
    327
    -    ``Type.Reflection`` module can now be defined as: ::
    
    328
    +    For example, the `withTypeable` function from the
    
    329
    +    `Type.Reflection` module can now be defined as: ::
    
    328 330
     
    
    329 331
               withTypeable :: forall k (a :: k) rep (r :: TYPE rep). ()
    
    330 332
                            => TypeRep a -> (Typeable a => r) -> r
    
    331 333
               withTypeable rep k = withDict @(Typeable a) rep k
    
    332 334
     
    
    333 335
         Note that the explicit type application is required, as the call to
    
    334
    -    ``withDict`` would be ambiguous otherwise.
    
    336
    +    `withDict` would be ambiguous otherwise.
    
    335 337
     
    
    336
    -    This replaces the old ``GHC.Exts.magicDict``, which required
    
    338
    +    This replaces the old `GHC.Exts.magicDict`, which required
    
    337 339
         an intermediate data type and was less reliable.
    
    338 340
     
    
    339 341
       * `Data.Word.Word64` and `Data.Int.Int64` are now always represented by
    
    ... ... @@ -351,17 +353,17 @@
    351 353
     
    
    352 354
       * Shipped with GHC 9.2.4
    
    353 355
     
    
    354
    -  * winio: make consoleReadNonBlocking not wait for any events at all.
    
    356
    +  * winio: make `consoleReadNonBlocking` not wait for any events at all.
    
    355 357
     
    
    356
    -  * winio: Add support to console handles to handleToHANDLE
    
    358
    +  * winio: Add support to console handles to `handleToHANDLE`
    
    357 359
     
    
    358 360
     ## 4.16.2.0 *May 2022*
    
    359 361
     
    
    360 362
       * Shipped with GHC 9.2.2
    
    361 363
     
    
    362
    -  * Export GHC.Event.Internal on Windows (#21245)
    
    364
    +  * Export `GHC.Event.Internal` on Windows (#21245)
    
    363 365
     
    
    364
    -  # Documentation Fixes
    
    366
    +  * Documentation Fixes
    
    365 367
     
    
    366 368
     ## 4.16.1.0 *Feb 2022*
    
    367 369
     
    
    ... ... @@ -430,10 +432,17 @@
    430 432
     
    
    431 433
         - Newtypes `And`, `Ior`, `Xor` and `Iff` which wrap their argument,
    
    432 434
           and whose `Semigroup` instances are defined using `(.&.)`, `(.|.)`, `xor`
    
    433
    -      and ```\x y -> complement (x `xor` y)```, respectively.
    
    435
    +      and `\x y -> complement (x `xor` y)`, respectively.
    
    434 436
     
    
    435 437
         - `oneBits :: FiniteBits a => a`, `oneBits = complement zeroBits`.
    
    436 438
     
    
    439
    +  * Various folding operations in `GHC.List` are now implemented via strict
    
    440
    +    folds:
    
    441
    +    - `sum`
    
    442
    +    - `product`
    
    443
    +    - `maximum`
    
    444
    +    - `minimum`
    
    445
    +
    
    437 446
     ## 4.15.0.0 *Feb 2021*
    
    438 447
     
    
    439 448
       * Shipped with GHC 9.0.1
    

  • libraries/base/src/Control/Exception/Backtrace.hs
    ... ... @@ -51,7 +51,7 @@ module Control.Exception.Backtrace
    51 51
         , getBacktraceMechanismState
    
    52 52
         , setBacktraceMechanismState
    
    53 53
           -- * Collecting backtraces
    
    54
    -    , Backtraces
    
    54
    +    , Backtraces(..)
    
    55 55
         , displayBacktraces
    
    56 56
         , collectBacktraces
    
    57 57
         ) where
    

  • libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs
    ... ... @@ -9,7 +9,7 @@ module GHC.Internal.Exception.Backtrace
    9 9
         , getBacktraceMechanismState
    
    10 10
         , setBacktraceMechanismState
    
    11 11
           -- * Collecting backtraces
    
    12
    -    , Backtraces
    
    12
    +    , Backtraces(..)
    
    13 13
         , displayBacktraces
    
    14 14
         , collectBacktraces
    
    15 15
         ) where
    

  • rts/Hash.c
    ... ... @@ -94,13 +94,13 @@ hashWord(const HashTable *table, StgWord key)
    94 94
     }
    
    95 95
     
    
    96 96
     int
    
    97
    -hashStr(const HashTable *table, StgWord w)
    
    97
    +hashBuffer(const HashTable *table, const void *buf, size_t len)
    
    98 98
     {
    
    99
    -    const char *key = (char*) w;
    
    99
    +    const char *key = (char*) buf;
    
    100 100
     #if WORD_SIZE_IN_BITS == 64
    
    101
    -    StgWord h = XXH3_64bits_withSeed (key, strlen(key), 1048583);
    
    101
    +    StgWord h = XXH3_64bits_withSeed (key, len, 1048583);
    
    102 102
     #else
    
    103
    -    StgWord h = XXH32 (key, strlen(key), 1048583);
    
    103
    +    StgWord h = XXH32 (key, len, 1048583);
    
    104 104
     #endif
    
    105 105
     
    
    106 106
         /* Mod the size of the hash table (a power of 2) */
    
    ... ... @@ -114,6 +114,13 @@ hashStr(const HashTable *table, StgWord w)
    114 114
         return bucket;
    
    115 115
     }
    
    116 116
     
    
    117
    +int
    
    118
    +hashStr(const HashTable *table, StgWord w)
    
    119
    +{
    
    120
    +    const char *key = (char*) w;
    
    121
    +    return hashBuffer(table, key, strlen(key));
    
    122
    +}
    
    123
    +
    
    117 124
     STATIC_INLINE int
    
    118 125
     compareWord(StgWord key1, StgWord key2)
    
    119 126
     {
    

  • rts/Hash.h
    ... ... @@ -69,6 +69,10 @@ void * removeStrHashTable ( StrHashTable *table, const char * key,
    69 69
      */
    
    70 70
     typedef int HashFunction(const HashTable *table, StgWord key);
    
    71 71
     typedef int CompareFunction(StgWord key1, StgWord key2);
    
    72
    +
    
    73
    +// Helper for implementing hash functions
    
    74
    +int hashBuffer(const HashTable *table, const void *buf, size_t len);
    
    75
    +
    
    72 76
     int hashWord(const HashTable *table, StgWord key);
    
    73 77
     int hashStr(const HashTable *table, StgWord w);
    
    74 78
     void        insertHashTable_ ( HashTable *table, StgWord key,
    
    ... ... @@ -79,6 +83,7 @@ void * removeHashTable_ ( HashTable *table, StgWord key,
    79 83
                                    const void *data, HashFunction f,
    
    80 84
                                    CompareFunction cmp );
    
    81 85
     
    
    86
    +
    
    82 87
     /* Freeing hash tables
    
    83 88
      */
    
    84 89
     void freeHashTable ( HashTable *table, void (*freeDataFun)(void *) );
    

  • rts/Linker.c
    ... ... @@ -1194,7 +1194,7 @@ void freeObjectCode (ObjectCode *oc)
    1194 1194
             stgFree(oc->sections);
    
    1195 1195
         }
    
    1196 1196
     
    
    1197
    -    freeProddableBlocks(oc);
    
    1197
    +    freeProddableBlocks(&oc->proddables);
    
    1198 1198
         freeSegments(oc);
    
    1199 1199
     
    
    1200 1200
         /* Free symbol_extras.  On x86_64 Windows, symbol_extras are allocated
    
    ... ... @@ -1279,7 +1279,7 @@ mkOc( ObjectType type, pathchar *path, char *image, int imageSize,
    1279 1279
        oc->sections          = NULL;
    
    1280 1280
        oc->n_segments        = 0;
    
    1281 1281
        oc->segments          = NULL;
    
    1282
    -   oc->proddables        = NULL;
    
    1282
    +   initProddableBlockSet(&oc->proddables);
    
    1283 1283
        oc->foreign_exports   = NULL;
    
    1284 1284
     #if defined(NEED_SYMBOL_EXTRAS)
    
    1285 1285
        oc->symbol_extras     = NULL;
    
    ... ... @@ -1834,50 +1834,6 @@ OStatus getObjectLoadStatus (pathchar *path)
    1834 1834
         return r;
    
    1835 1835
     }
    
    1836 1836
     
    
    1837
    -/* -----------------------------------------------------------------------------
    
    1838
    - * Sanity checking.  For each ObjectCode, maintain a list of address ranges
    
    1839
    - * which may be prodded during relocation, and abort if we try and write
    
    1840
    - * outside any of these.
    
    1841
    - */
    
    1842
    -void
    
    1843
    -addProddableBlock ( ObjectCode* oc, void* start, int size )
    
    1844
    -{
    
    1845
    -   ProddableBlock* pb
    
    1846
    -      = stgMallocBytes(sizeof(ProddableBlock), "addProddableBlock");
    
    1847
    -
    
    1848
    -   IF_DEBUG(linker, debugBelch("addProddableBlock: %p %p %d\n", oc, start, size));
    
    1849
    -   ASSERT(size > 0);
    
    1850
    -   pb->start      = start;
    
    1851
    -   pb->size       = size;
    
    1852
    -   pb->next       = oc->proddables;
    
    1853
    -   oc->proddables = pb;
    
    1854
    -}
    
    1855
    -
    
    1856
    -void
    
    1857
    -checkProddableBlock (ObjectCode *oc, void *addr, size_t size )
    
    1858
    -{
    
    1859
    -   ProddableBlock* pb;
    
    1860
    -
    
    1861
    -   for (pb = oc->proddables; pb != NULL; pb = pb->next) {
    
    1862
    -      char* s = (char*)(pb->start);
    
    1863
    -      char* e = s + pb->size;
    
    1864
    -      char* a = (char*)addr;
    
    1865
    -      if (a >= s && (a+size) <= e) return;
    
    1866
    -   }
    
    1867
    -   barf("checkProddableBlock: invalid fixup in runtime linker: %p", addr);
    
    1868
    -}
    
    1869
    -
    
    1870
    -void freeProddableBlocks (ObjectCode *oc)
    
    1871
    -{
    
    1872
    -    ProddableBlock *pb, *next;
    
    1873
    -
    
    1874
    -    for (pb = oc->proddables; pb != NULL; pb = next) {
    
    1875
    -        next = pb->next;
    
    1876
    -        stgFree(pb);
    
    1877
    -    }
    
    1878
    -    oc->proddables = NULL;
    
    1879
    -}
    
    1880
    -
    
    1881 1837
     /* -----------------------------------------------------------------------------
    
    1882 1838
      * Section management.
    
    1883 1839
      */
    

  • rts/LinkerInternals.h
    ... ... @@ -12,6 +12,7 @@
    12 12
     #include "RtsSymbols.h"
    
    13 13
     #include "Hash.h"
    
    14 14
     #include "linker/M32Alloc.h"
    
    15
    +#include "linker/ProddableBlocks.h"
    
    15 16
     
    
    16 17
     #if RTS_LINKER_USE_MMAP
    
    17 18
     #include <sys/mman.h>
    
    ... ... @@ -175,14 +176,6 @@ struct _Section {
    175 176
       struct SectionFormatInfo* info;
    
    176 177
     };
    
    177 178
     
    
    178
    -typedef
    
    179
    -   struct _ProddableBlock {
    
    180
    -      void* start;
    
    181
    -      int   size;
    
    182
    -      struct _ProddableBlock* next;
    
    183
    -   }
    
    184
    -   ProddableBlock;
    
    185
    -
    
    186 179
     typedef struct _Segment {
    
    187 180
         void *start;                /* page aligned start address of a segment */
    
    188 181
         size_t size;                /* page rounded size of a segment */
    
    ... ... @@ -328,7 +321,7 @@ struct _ObjectCode {
    328 321
         /* SANITY CHECK ONLY: a list of the only memory regions which may
    
    329 322
            safely be prodded during relocation.  Any attempt to prod
    
    330 323
            outside one of these is an error in the linker. */
    
    331
    -    ProddableBlock* proddables;
    
    324
    +    ProddableBlockSet proddables;
    
    332 325
     
    
    333 326
     #if defined(NEED_SYMBOL_EXTRAS)
    
    334 327
         SymbolExtra    *symbol_extras;
    
    ... ... @@ -434,10 +427,6 @@ void exitLinker( void );
    434 427
     void freeObjectCode (ObjectCode *oc);
    
    435 428
     SymbolAddr* loadSymbol(SymbolName *lbl, RtsSymbolInfo *pinfo);
    
    436 429
     
    
    437
    -void addProddableBlock ( ObjectCode* oc, void* start, int size );
    
    438
    -void checkProddableBlock (ObjectCode *oc, void *addr, size_t size );
    
    439
    -void freeProddableBlocks (ObjectCode *oc);
    
    440
    -
    
    441 430
     void addSection (Section *s, SectionKind kind, SectionAlloc alloc,
    
    442 431
                      void* start, StgWord size, StgWord mapped_offset,
    
    443 432
                      void* mapped_start, StgWord mapped_size);
    

  • rts/PathUtils.c
    ... ... @@ -13,7 +13,7 @@
    13 13
     #include <wchar.h>
    
    14 14
     #endif
    
    15 15
     
    
    16
    -pathchar* pathdup(pathchar *path)
    
    16
    +pathchar* pathdup(const pathchar *path)
    
    17 17
     {
    
    18 18
         pathchar *ret;
    
    19 19
     #if defined(mingw32_HOST_OS)
    
    ... ... @@ -26,7 +26,7 @@ pathchar* pathdup(pathchar *path)
    26 26
         return ret;
    
    27 27
     }
    
    28 28
     
    
    29
    -pathchar* pathdir(pathchar *path)
    
    29
    +pathchar* pathdir(const pathchar *path)
    
    30 30
     {
    
    31 31
         pathchar *ret;
    
    32 32
     #if defined(mingw32_HOST_OS)
    
    ... ... @@ -40,7 +40,8 @@ pathchar* pathdir(pathchar *path)
    40 40
         stgFree(drive);
    
    41 41
         stgFree(dirName);
    
    42 42
     #else
    
    43
    -    pathchar* dirName = dirname(path);
    
    43
    +    // N.B. cast is safe as we do not modify dirName
    
    44
    +    const pathchar* dirName = dirname((pathchar *) path);
    
    44 45
         size_t memberLen  = pathlen(dirName);
    
    45 46
         ret = stgMallocBytes(pathsize * (memberLen + 2), "pathdir(path)");
    
    46 47
         strcpy(ret, dirName);
    
    ... ... @@ -50,7 +51,7 @@ pathchar* pathdir(pathchar *path)
    50 51
         return ret;
    
    51 52
     }
    
    52 53
     
    
    53
    -pathchar* mkPath(char* path)
    
    54
    +pathchar* mkPath(const char* path)
    
    54 55
     {
    
    55 56
     #if defined(mingw32_HOST_OS)
    
    56 57
         size_t required = mbstowcs(NULL, path, 0);
    
    ... ... @@ -66,7 +67,7 @@ pathchar* mkPath(char* path)
    66 67
     #endif
    
    67 68
     }
    
    68 69
     
    
    69
    -HsBool endsWithPath(pathchar* base, pathchar* str) {
    
    70
    +HsBool endsWithPath(const pathchar* base, const pathchar* str) {
    
    70 71
         int blen = pathlen(base);
    
    71 72
         int slen = pathlen(str);
    
    72 73
         return (blen >= slen) && (0 == pathcmp(base + blen - slen, str));
    

  • rts/PathUtils.h
    ... ... @@ -37,9 +37,9 @@
    37 37
     
    
    38 38
     #include "BeginPrivate.h"
    
    39 39
     
    
    40
    -pathchar* pathdup(pathchar *path);
    
    41
    -pathchar* pathdir(pathchar *path);
    
    42
    -pathchar* mkPath(char* path);
    
    43
    -HsBool endsWithPath(pathchar* base, pathchar* str);
    
    40
    +pathchar* pathdup(const pathchar *path);
    
    41
    +pathchar* pathdir(const pathchar *path);
    
    42
    +pathchar* mkPath(const char* path);
    
    43
    +HsBool endsWithPath(const pathchar* base, const pathchar* str);
    
    44 44
     
    
    45 45
     #include "EndPrivate.h"

  • rts/linker/Elf.c
    ... ... @@ -924,7 +924,7 @@ ocGetNames_ELF ( ObjectCode* oc )
    924 924
               oc->sections[i].info->stubs = NULL;
    
    925 925
     #endif
    
    926 926
     
    
    927
    -          addProddableBlock(oc, start, size);
    
    927
    +          addProddableBlock(&oc->proddables, start, size);
    
    928 928
           } else {
    
    929 929
               addSection(&oc->sections[i], kind, alloc, oc->image+offset, size,
    
    930 930
                          0, 0, 0);
    
    ... ... @@ -1272,7 +1272,7 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
    1272 1272
                     debugBelch("Reloc: P = %p   S = %p   A = %p   type=%d\n",
    
    1273 1273
                                (void*)P, (void*)S, (void*)A, reloc_type ));
    
    1274 1274
     #if defined(DEBUG)
    
    1275
    -       checkProddableBlock ( oc, pP, sizeof(Elf_Word) );
    
    1275
    +       checkProddableBlock ( &oc->proddables, pP, sizeof(Elf_Word) );
    
    1276 1276
     #else
    
    1277 1277
            (void) pP; /* suppress unused varialbe warning in non-debug build */
    
    1278 1278
     #endif
    
    ... ... @@ -1684,7 +1684,7 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC,
    1684 1684
     #if defined(DEBUG)
    
    1685 1685
           IF_DEBUG(linker_verbose,debugBelch("Reloc: P = %p   S = %p   A = %p\n",
    
    1686 1686
                                              (void*)P, (void*)S, (void*)A ));
    
    1687
    -      checkProddableBlock(oc, (void*)P, sizeof(Elf_Word));
    
    1687
    +      checkProddableBlock(&oc->proddables, (void*)P, sizeof(Elf_Word));
    
    1688 1688
     #endif
    
    1689 1689
     
    
    1690 1690
     #if defined(powerpc_HOST_ARCH) || defined(x86_64_HOST_ARCH)
    

  • rts/linker/MachO.c
    ... ... @@ -253,7 +253,7 @@ resolveImports(
    253 253
                 return 0;
    
    254 254
             }
    
    255 255
     
    
    256
    -        checkProddableBlock(oc,
    
    256
    +        checkProddableBlock(&oc->proddables,
    
    257 257
                                 ((void**)(oc->image + sect->offset)) + i,
    
    258 258
                                 sizeof(void *));
    
    259 259
             ((void**)(oc->image + sect->offset))[i] = addr;
    
    ... ... @@ -287,7 +287,7 @@ decodeAddend(ObjectCode * oc, Section * section, MachORelocationInfo * ri) {
    287 287
         /* the instruction. It is 32bit wide */
    
    288 288
         uint32_t * p = (uint32_t*)((uint8_t*)section->start + ri->r_address);
    
    289 289
     
    
    290
    -    checkProddableBlock(oc, (void*)p, 1 << ri->r_length);
    
    290
    +    checkProddableBlock(&oc->proddables, (void*)p, 1 << ri->r_length);
    
    291 291
     
    
    292 292
         switch(ri->r_type) {
    
    293 293
             case ARM64_RELOC_UNSIGNED: {
    
    ... ... @@ -364,7 +364,7 @@ encodeAddend(ObjectCode * oc, Section * section,
    364 364
                  MachORelocationInfo * ri, int64_t addend) {
    
    365 365
         uint32_t * p = (uint32_t*)((uint8_t*)section->start + ri->r_address);
    
    366 366
     
    
    367
    -    checkProddableBlock(oc, (void*)p, 1 << ri->r_length);
    
    367
    +    checkProddableBlock(&oc->proddables, (void*)p, 1 << ri->r_length);
    
    368 368
     
    
    369 369
         switch (ri->r_type) {
    
    370 370
             case ARM64_RELOC_UNSIGNED: {
    
    ... ... @@ -788,7 +788,7 @@ relocateSection(ObjectCode* oc, int curSection)
    788 788
                 default:
    
    789 789
                     barf("Unknown size.");
    
    790 790
             }
    
    791
    -        checkProddableBlock(oc,thingPtr,relocLenBytes);
    
    791
    +        checkProddableBlock(&oc->proddables,thingPtr,relocLenBytes);
    
    792 792
     
    
    793 793
             /*
    
    794 794
              * With SIGNED_N the relocation is not at the end of the
    
    ... ... @@ -1034,9 +1034,9 @@ relocateSection(ObjectCode* oc, int curSection)
    1034 1034
              */
    
    1035 1035
             if (0 == reloc->r_extern) {
    
    1036 1036
                 if (reloc->r_pcrel) {
    
    1037
    -                checkProddableBlock(oc, (void *)((char *)thing + baseValue), 1);
    
    1037
    +                checkProddableBlock(&oc->proddables, (void *)((char *)thing + baseValue), 1);
    
    1038 1038
                 } else {
    
    1039
    -                checkProddableBlock(oc, (void *)thing, 1);
    
    1039
    +                checkProddableBlock(&oc->proddables, (void *)thing, 1);
    
    1040 1040
                 }
    
    1041 1041
             }
    
    1042 1042
     
    
    ... ... @@ -1343,7 +1343,7 @@ ocGetNames_MachO(ObjectCode* oc)
    1343 1343
                     secArray[sec_idx].info->stub_size = 0;
    
    1344 1344
                     secArray[sec_idx].info->stubs = NULL;
    
    1345 1345
     #endif
    
    1346
    -                addProddableBlock(oc, start, section->size);
    
    1346
    +                addProddableBlock(&oc->proddables, start, section->size);
    
    1347 1347
                 }
    
    1348 1348
     
    
    1349 1349
                 curMem = (char*) secMem + section->size;
    

  • rts/linker/PEi386.c
    ... ... @@ -378,7 +378,7 @@ static size_t makeSymbolExtra_PEi386(
    378 378
     #endif
    
    379 379
     
    
    380 380
     static void addDLLHandle(
    
    381
    -    pathchar* dll_name,
    
    381
    +    const pathchar* dll_name,
    
    382 382
         HINSTANCE instance);
    
    383 383
     
    
    384 384
     static bool verifyCOFFHeader(
    
    ... ... @@ -427,8 +427,52 @@ const int default_alignment = 8;
    427 427
        the pointer as a redirect.  Essentially it's a DATA DLL reference.  */
    
    428 428
     const void* __rts_iob_func = (void*)&__acrt_iob_func;
    
    429 429
     
    
    430
    +/*
    
    431
    + * Note [Avoiding repeated DLL loading]
    
    432
    + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    433
    + * As LoadLibraryEx tends to be expensive and addDLL_PEi386 is called on every
    
    434
    + * DLL-imported symbol, we use a hash-map to keep track of which DLLs have
    
    435
    + * already been loaded. This hash-map is keyed on the dll_name passed to
    
    436
    + * addDLL_PEi386 and is mapped to its HINSTANCE. This serves as a quick check
    
    437
    + * to avoid repeated calls to LoadLibraryEx for the identical DLL. See #26009.
    
    438
    + */
    
    439
    +
    
    440
    +typedef struct {
    
    441
    +    HashTable *hash;
    
    442
    +} LoadedDllCache;
    
    443
    +
    
    444
    +LoadedDllCache loaded_dll_cache;
    
    445
    +
    
    446
    +static void initLoadedDllCache(LoadedDllCache *cache) {
    
    447
    +    cache->hash = allocHashTable();
    
    448
    +}
    
    449
    +
    
    450
    +static int hash_path(const HashTable *table, StgWord w)
    
    451
    +{
    
    452
    +    const pathchar *key = (pathchar*) w;
    
    453
    +    return hashBuffer(table, key, sizeof(pathchar) * wcslen(key));
    
    454
    +}
    
    455
    +
    
    456
    +static int compare_path(StgWord key1, StgWord key2)
    
    457
    +{
    
    458
    +    return wcscmp((pathchar*) key1, (pathchar*) key2) == 0;
    
    459
    +}
    
    460
    +
    
    461
    +static void addLoadedDll(LoadedDllCache *cache, const pathchar *dll_name, HINSTANCE instance)
    
    462
    +{
    
    463
    +    insertHashTable_(cache->hash, (StgWord) dll_name, instance, hash_path);
    
    464
    +}
    
    465
    +
    
    466
    +static HINSTANCE isDllLoaded(const LoadedDllCache *cache, const pathchar *dll_name)
    
    467
    +{
    
    468
    +    void *result = lookupHashTable_(cache->hash, (StgWord) dll_name, hash_path, compare_path);
    
    469
    +    return (HINSTANCE) result;
    
    470
    +}
    
    471
    +
    
    430 472
     void initLinker_PEi386(void)
    
    431 473
     {
    
    474
    +    initLoadedDllCache(&loaded_dll_cache);
    
    475
    +
    
    432 476
         if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
    
    433 477
                                    symhash, "__image_base__",
    
    434 478
                                    GetModuleHandleW (NULL), HS_BOOL_TRUE,
    
    ... ... @@ -440,10 +484,11 @@ void initLinker_PEi386(void)
    440 484
         addDLLHandle(WSTR("*.exe"), GetModuleHandle(NULL));
    
    441 485
     #endif
    
    442 486
     
    
    443
    -  /* Register the cleanup routine as an exit handler,  this gives other exit handlers
    
    444
    -     a chance to run which may need linker information.  Exit handlers are ran in
    
    445
    -     reverse registration order so this needs to be before the linker loads anything.  */
    
    446
    -  atexit (exitLinker_PEi386);
    
    487
    +    /* Register the cleanup routine as an exit handler,  this gives other exit handlers
    
    488
    +     * a chance to run which may need linker information.  Exit handlers are ran in
    
    489
    +     * reverse registration order so this needs to be before the linker loads anything.
    
    490
    +     */
    
    491
    +    atexit (exitLinker_PEi386);
    
    447 492
     }
    
    448 493
     
    
    449 494
     void exitLinker_PEi386(void)
    
    ... ... @@ -454,7 +499,7 @@ void exitLinker_PEi386(void)
    454 499
     static OpenedDLL* opened_dlls = NULL;
    
    455 500
     
    
    456 501
     /* Adds a DLL instance to the list of DLLs in which to search for symbols. */
    
    457
    -static void addDLLHandle(pathchar* dll_name, HINSTANCE instance) {
    
    502
    +static void addDLLHandle(const pathchar* dll_name, HINSTANCE instance) {
    
    458 503
     
    
    459 504
         IF_DEBUG(linker, debugBelch("addDLLHandle(%" PATH_FMT ")...\n", dll_name));
    
    460 505
         /* At this point, we actually know what was loaded.
    
    ... ... @@ -796,14 +841,19 @@ uint8_t* getSymShortName ( COFF_HEADER_INFO *info, COFF_symbol* sym )
    796 841
     }
    
    797 842
     
    
    798 843
     const char *
    
    799
    -addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    
    844
    +addDLL_PEi386( const pathchar *dll_name, HINSTANCE *loaded )
    
    800 845
     {
    
    801
    -   /* ------------------- Win32 DLL loader ------------------- */
    
    802
    -
    
    803
    -   pathchar*  buf;
    
    804
    -   HINSTANCE  instance;
    
    805
    -
    
    806
    -   IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
    
    846
    +    /* ------------------- Win32 DLL loader ------------------- */
    
    847
    +    IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
    
    848
    +
    
    849
    +    // See Note [Avoiding repeated DLL loading]
    
    850
    +    HINSTANCE instance = isDllLoaded(&loaded_dll_cache, dll_name);
    
    851
    +    if (instance) {
    
    852
    +        if (loaded) {
    
    853
    +            *loaded = instance;
    
    854
    +        }
    
    855
    +        return NULL;
    
    856
    +    }
    
    807 857
     
    
    808 858
         /* The file name has no suffix (yet) so that we can try
    
    809 859
            both foo.dll and foo.drv
    
    ... ... @@ -816,45 +866,32 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    816 866
             extension. */
    
    817 867
     
    
    818 868
         size_t bufsize = pathlen(dll_name) + 10;
    
    819
    -    buf = stgMallocBytes(bufsize * sizeof(wchar_t), "addDLL");
    
    869
    +    pathchar *buf = stgMallocBytes(bufsize * sizeof(wchar_t), "addDLL");
    
    820 870
     
    
    821 871
         /* These are ordered by probability of success and order we'd like them.  */
    
    822 872
         const wchar_t *formats[] = { L"%ls.DLL", L"%ls.DRV", L"lib%ls.DLL", L"%ls" };
    
    823 873
         const DWORD flags[] = { LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, 0 };
    
    824 874
     
    
    825
    -    int cFormat, cFlag;
    
    826
    -    int flags_start = 1; /* Assume we don't support the new API.  */
    
    827
    -
    
    828
    -    /* Detect if newer API are available, if not, skip the first flags entry.  */
    
    829
    -    if (GetProcAddress((HMODULE)LoadLibraryW(L"Kernel32.DLL"), "AddDllDirectory")) {
    
    830
    -        flags_start = 0;
    
    831
    -    }
    
    832
    -
    
    833 875
         /* Iterate through the possible flags and formats.  */
    
    834
    -    for (cFlag = flags_start; cFlag < 2; cFlag++)
    
    835
    -    {
    
    836
    -        for (cFormat = 0; cFormat < 4; cFormat++)
    
    837
    -        {
    
    876
    +    for (int cFlag = 0; cFlag < 2; cFlag++) {
    
    877
    +        for (int cFormat = 0; cFormat < 4; cFormat++) {
    
    838 878
                 snwprintf(buf, bufsize, formats[cFormat], dll_name);
    
    839 879
                 instance = LoadLibraryExW(buf, NULL, flags[cFlag]);
    
    840 880
                 if (instance == NULL) {
    
    841
    -                if (GetLastError() != ERROR_MOD_NOT_FOUND)
    
    842
    -                {
    
    881
    +                if (GetLastError() != ERROR_MOD_NOT_FOUND) {
    
    843 882
                         goto error;
    
    844 883
                     }
    
    845
    -            }
    
    846
    -            else
    
    847
    -            {
    
    848
    -                break; /* We're done. DLL has been loaded.  */
    
    884
    +            } else {
    
    885
    +                goto loaded; /* We're done. DLL has been loaded.  */
    
    849 886
                 }
    
    850 887
             }
    
    851 888
         }
    
    852 889
     
    
    853
    -    /* Check if we managed to load the DLL.  */
    
    854
    -    if (instance == NULL) {
    
    855
    -        goto error;
    
    856
    -    }
    
    890
    +    // We failed to load
    
    891
    +    goto error;
    
    857 892
     
    
    893
    +loaded:
    
    894
    +    addLoadedDll(&loaded_dll_cache, dll_name, instance);
    
    858 895
         addDLLHandle(buf, instance);
    
    859 896
         if (loaded) {
    
    860 897
             *loaded = instance;
    
    ... ... @@ -1658,7 +1695,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
    1658 1695
           }
    
    1659 1696
     
    
    1660 1697
           addSection(section, kind, SECTION_NOMEM, start, sz, 0, 0, 0);
    
    1661
    -      addProddableBlock(oc, oc->sections[i].start, sz);
    
    1698
    +      addProddableBlock(&oc->proddables, oc->sections[i].start, sz);
    
    1662 1699
        }
    
    1663 1700
     
    
    1664 1701
        /* Copy exported symbols into the ObjectCode. */
    
    ... ... @@ -1690,7 +1727,7 @@ ocGetNames_PEi386 ( ObjectCode* oc )
    1690 1727
                       SECTIONKIND_RWDATA, SECTION_MALLOC,
    
    1691 1728
                       bss, globalBssSize, 0, 0, 0);
    
    1692 1729
            IF_DEBUG(linker_verbose, debugBelch("bss @ %p %" FMT_Word "\n", bss, globalBssSize));
    
    1693
    -       addProddableBlock(oc, bss, globalBssSize);
    
    1730
    +       addProddableBlock(&oc->proddables, bss, globalBssSize);
    
    1694 1731
        } else {
    
    1695 1732
            addSection(&oc->sections[oc->n_sections-1],
    
    1696 1733
                       SECTIONKIND_OTHER, SECTION_NOMEM, NULL, 0, 0, 0, 0);
    
    ... ... @@ -2067,13 +2104,13 @@ ocResolve_PEi386 ( ObjectCode* oc )
    2067 2104
              IF_DEBUG(linker_verbose, debugBelch("S=%zx\n", S));
    
    2068 2105
     
    
    2069 2106
              /* All supported relocations write at least 4 bytes */
    
    2070
    -         checkProddableBlock(oc, pP, 4);
    
    2107
    +         checkProddableBlock(&oc->proddables, pP, 4);
    
    2071 2108
              switch (reloc->Type) {
    
    2072 2109
     #if defined(x86_64_HOST_ARCH)
    
    2073 2110
                 case 1: /* R_X86_64_64 (ELF constant 1) - IMAGE_REL_AMD64_ADDR64 (PE constant 1) */
    
    2074 2111
                    {
    
    2075 2112
                        uint64_t A;
    
    2076
    -                   checkProddableBlock(oc, pP, 8);
    
    2113
    +                   checkProddableBlock(&oc->proddables, pP, 8);
    
    2077 2114
                        A = *(uint64_t*)pP;
    
    2078 2115
                        *(uint64_t *)pP = S + A;
    
    2079 2116
                        break;
    
    ... ... @@ -2114,7 +2151,7 @@ ocResolve_PEi386 ( ObjectCode* oc )
    2114 2151
                    {
    
    2115 2152
                        /* mingw will emit this for a pc-rel 64 relocation */
    
    2116 2153
                        uint64_t A;
    
    2117
    -                   checkProddableBlock(oc, pP, 8);
    
    2154
    +                   checkProddableBlock(&oc->proddables, pP, 8);
    
    2118 2155
                        A = *(uint64_t*)pP;
    
    2119 2156
                        *(uint64_t *)pP = S + A - (intptr_t)pP;
    
    2120 2157
                        break;
    

  • rts/linker/PEi386.h
    ... ... @@ -45,7 +45,7 @@ typedef struct _COFF_HEADER_INFO {
    45 45
     
    
    46 46
     void initLinker_PEi386( void );
    
    47 47
     void exitLinker_PEi386( void );
    
    48
    -const char * addDLL_PEi386( pathchar *dll_name, HINSTANCE *instance  );
    
    48
    +const char * addDLL_PEi386( const pathchar *dll_name, HINSTANCE *instance  );
    
    49 49
     void freePreloadObjectFile_PEi386( ObjectCode *oc );
    
    50 50
     
    
    51 51
     bool checkAndLoadImportLibrary( pathchar* arch_name, char* member_name, FILE* f);
    

  • rts/linker/ProddableBlocks.c
    1
    +/* -----------------------------------------------------------------------------
    
    2
    + *
    
    3
    + * (c) The GHC Team, 2025
    
    4
    + *
    
    5
    + * RTS Object Linker
    
    6
    + *
    
    7
    + * ---------------------------------------------------------------------------*/
    
    8
    +
    
    9
    +
    
    10
    +/*
    
    11
    + * Note [Proddable blocks]
    
    12
    + * ~~~~~~~~~~~~~~~~~~~~~~~
    
    13
    + * For each ObjectCode, we maintain a ProddableBlockSet representing the set of
    
    14
    + * address ranges containing data belonging to the object. This set is
    
    15
    + * represented here as an array of intervals sorted by start address. This
    
    16
    + * allows us to efficiently query and insert via binary search. Array resizing
    
    17
    + * is done according to an exponential growth schedule.
    
    18
    + *
    
    19
    + * While performing relocations we check against this set and and abort if we
    
    20
    + * try and write outside any of these.
    
    21
    + */
    
    22
    +
    
    23
    +#include "Rts.h"
    
    24
    +#include "RtsUtils.h"
    
    25
    +#include "linker/ProddableBlocks.h"
    
    26
    +
    
    27
    +#include <stdlib.h>
    
    28
    +#include <string.h>
    
    29
    +
    
    30
    +typedef struct _ProddableBlock {
    
    31
    +    uintptr_t start;  // inclusive
    
    32
    +    uintptr_t end;    // inclusive
    
    33
    +} ProddableBlock;
    
    34
    +
    
    35
    +void
    
    36
    +initProddableBlockSet ( ProddableBlockSet* set )
    
    37
    +{
    
    38
    +    set->data = NULL;
    
    39
    +    set->capacity = 0;
    
    40
    +    set->size = 0;
    
    41
    +}
    
    42
    +
    
    43
    +void
    
    44
    +freeProddableBlocks (ProddableBlockSet *set)
    
    45
    +{
    
    46
    +    stgFree(set->data);
    
    47
    +    set->data = NULL;
    
    48
    +    set->size = 0;
    
    49
    +    set->capacity = 0;
    
    50
    +}
    
    51
    +
    
    52
    +// Binary search for the first interval with start >= value. Returns index or
    
    53
    +// size if none.
    
    54
    +static size_t
    
    55
    +findLower(const ProddableBlockSet *set, uintptr_t value)
    
    56
    +{
    
    57
    +    size_t l = 0;
    
    58
    +    size_t r = set->size;
    
    59
    +    while (l < r) {
    
    60
    +        size_t mid = l + (r - l) / 2;
    
    61
    +        if (set->data[mid].start < value) {
    
    62
    +            l = mid + 1;
    
    63
    +        } else {
    
    64
    +            r = mid;
    
    65
    +        }
    
    66
    +    }
    
    67
    +    return l;
    
    68
    +}
    
    69
    +
    
    70
    +// Check whether a given value is a member of the set.
    
    71
    +bool
    
    72
    +containsSpan ( const ProddableBlockSet *set, uintptr_t start, uintptr_t end )
    
    73
    +{
    
    74
    +    size_t i = findLower(set, start+1);
    
    75
    +    return i > 0
    
    76
    +      && set->data[i-1].start <= start
    
    77
    +      && end <= set->data[i-1].end;
    
    78
    +}
    
    79
    +
    
    80
    +void
    
    81
    +checkProddableBlock (const ProddableBlockSet *set, void *addr, size_t size )
    
    82
    +{
    
    83
    +    if (! containsSpan(set, (uintptr_t) addr, (uintptr_t) addr+size)) {
    
    84
    +        barf("checkProddableBlock: invalid fixup in runtime linker: %p", addr);
    
    85
    +    }
    
    86
    +}
    
    87
    +
    
    88
    +// Ensure capacity for at least new_capacity intervals
    
    89
    +static void
    
    90
    +ensureCapacity(ProddableBlockSet *set, size_t new_capacity) {
    
    91
    +    if (new_capacity > set->capacity) {
    
    92
    +        size_t cap = set->capacity ? set->capacity * 2 : 4;
    
    93
    +        if (cap < new_capacity) {
    
    94
    +            cap = new_capacity;
    
    95
    +        }
    
    96
    +        ProddableBlock *tmp = stgReallocBytes(set->data, cap * sizeof(ProddableBlock), "addProddableBlock");
    
    97
    +        set->data = tmp;
    
    98
    +        set->capacity = cap;
    
    99
    +    }
    
    100
    +}
    
    101
    +
    
    102
    +void
    
    103
    +addProddableBlock ( ProddableBlockSet* set, void* start_ptr, size_t size )
    
    104
    +{
    
    105
    +    const uintptr_t start = (uintptr_t) start_ptr;
    
    106
    +    const uintptr_t end = (uintptr_t) start + size;
    
    107
    +    size_t i = findLower(set, start);
    
    108
    +
    
    109
    +    // check previous interval if it is overlapping or adjacent
    
    110
    +    if (i > 0 && start <= set->data[i-1].end + 1) {
    
    111
    +        // merge with left interval
    
    112
    +        i--;
    
    113
    +        if (end > set->data[i].end) {
    
    114
    +            set->data[i].end = end;
    
    115
    +        }
    
    116
    +    } else {
    
    117
    +        // insert new interval
    
    118
    +        ensureCapacity(set, set->size + 1);
    
    119
    +        memmove(&set->data[i+1], &set->data[i], sizeof(ProddableBlock) * (set->size - i));
    
    120
    +        set->data[i].start = start;
    
    121
    +        set->data[i].end = end;
    
    122
    +        set->size++;
    
    123
    +    }
    
    124
    +
    
    125
    +    // coalesce overlaps on right
    
    126
    +    size_t j = i;
    
    127
    +    while (j < set->size && set->data[j].start <= set->data[i].end + 1) {
    
    128
    +        set->data[i].end = set->data[j].end;
    
    129
    +        j++;
    
    130
    +    }
    
    131
    +
    
    132
    +    if (j != i) {
    
    133
    +        memmove(&set->data[i+1], &set->data[j], sizeof(ProddableBlock) * (set->size - j));
    
    134
    +        set->size -= j - i - 1;
    
    135
    +    }
    
    136
    +}
    
    137
    +

  • rts/linker/ProddableBlocks.h
    1
    +/* -----------------------------------------------------------------------------
    
    2
    + *
    
    3
    + * (c) The GHC Team, 2025
    
    4
    + *
    
    5
    + * RTS Object Linker
    
    6
    + *
    
    7
    + * ---------------------------------------------------------------------------*/
    
    8
    +
    
    9
    +#pragma once
    
    10
    +
    
    11
    +#include <stdbool.h>
    
    12
    +#include <stddef.h>
    
    13
    +#include <stdint.h>
    
    14
    +
    
    15
    +// An interval set on uintptr_t.
    
    16
    +struct _ProddableBlock;
    
    17
    +
    
    18
    +typedef struct {
    
    19
    +    size_t size;
    
    20
    +    size_t capacity;
    
    21
    +    // sorted list of disjoint (start,end) pairs
    
    22
    +    struct _ProddableBlock *data;
    
    23
    +} ProddableBlockSet;
    
    24
    +
    
    25
    +void initProddableBlockSet ( ProddableBlockSet* set );
    
    26
    +
    
    27
    +// Insert an interval.
    
    28
    +void addProddableBlock ( ProddableBlockSet* set, void* start, size_t size );
    
    29
    +
    
    30
    +// Check that an address belongs to the set.
    
    31
    +void checkProddableBlock (const ProddableBlockSet *set, void *addr, size_t size );
    
    32
    +
    
    33
    +
    
    34
    +// Free a set.
    
    35
    +void freeProddableBlocks (ProddableBlockSet *set);
    
    36
    +
    
    37
    +// For testing.
    
    38
    +bool containsSpan ( const ProddableBlockSet *set, uintptr_t start, uintptr_t end );

  • rts/rts.cabal
    ... ... @@ -491,6 +491,7 @@ library
    491 491
                      linker/MachO.c
    
    492 492
                      linker/macho/plt.c
    
    493 493
                      linker/macho/plt_aarch64.c
    
    494
    +                 linker/ProddableBlocks.c
    
    494 495
                      linker/PEi386.c
    
    495 496
                      linker/SymbolExtras.c
    
    496 497
                      linker/elf_got.c
    

  • testsuite/tests/interface-stability/base-exports.stdout
    ... ... @@ -322,7 +322,7 @@ module Control.Exception.Backtrace where
    322 322
       type BacktraceMechanism :: *
    
    323 323
       data BacktraceMechanism = CostCentreBacktrace | HasCallStackBacktrace | ExecutionBacktrace | IPEBacktrace
    
    324 324
       type Backtraces :: *
    
    325
    -  data Backtraces = ...
    
    325
    +  data Backtraces = Backtraces {btrCostCentre :: GHC.Internal.Maybe.Maybe (GHC.Internal.Ptr.Ptr GHC.Internal.Stack.CCS.CostCentreStack), btrHasCallStack :: GHC.Internal.Maybe.Maybe GHC.Internal.Stack.Types.CallStack, btrExecutionStack :: GHC.Internal.Maybe.Maybe [GHC.Internal.ExecutionStack.Internal.Location], btrIpe :: GHC.Internal.Maybe.Maybe [GHC.Internal.Stack.CloneStack.StackEntry]}
    
    326 326
       collectBacktraces :: (?callStack::GHC.Internal.Stack.Types.CallStack) => GHC.Internal.Types.IO Backtraces
    
    327 327
       displayBacktraces :: Backtraces -> GHC.Internal.Base.String
    
    328 328
       getBacktraceMechanismState :: BacktraceMechanism -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    

  • testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
    ... ... @@ -322,7 +322,7 @@ module Control.Exception.Backtrace where
    322 322
       type BacktraceMechanism :: *
    
    323 323
       data BacktraceMechanism = CostCentreBacktrace | HasCallStackBacktrace | ExecutionBacktrace | IPEBacktrace
    
    324 324
       type Backtraces :: *
    
    325
    -  data Backtraces = ...
    
    325
    +  data Backtraces = Backtraces {btrCostCentre :: GHC.Internal.Maybe.Maybe (GHC.Internal.Ptr.Ptr GHC.Internal.Stack.CCS.CostCentreStack), btrHasCallStack :: GHC.Internal.Maybe.Maybe GHC.Internal.Stack.Types.CallStack, btrExecutionStack :: GHC.Internal.Maybe.Maybe [GHC.Internal.ExecutionStack.Internal.Location], btrIpe :: GHC.Internal.Maybe.Maybe [GHC.Internal.Stack.CloneStack.StackEntry]}
    
    326 326
       collectBacktraces :: (?callStack::GHC.Internal.Stack.Types.CallStack) => GHC.Internal.Types.IO Backtraces
    
    327 327
       displayBacktraces :: Backtraces -> GHC.Internal.Base.String
    
    328 328
       getBacktraceMechanismState :: BacktraceMechanism -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    

  • testsuite/tests/interface-stability/base-exports.stdout-mingw32
    ... ... @@ -322,7 +322,7 @@ module Control.Exception.Backtrace where
    322 322
       type BacktraceMechanism :: *
    
    323 323
       data BacktraceMechanism = CostCentreBacktrace | HasCallStackBacktrace | ExecutionBacktrace | IPEBacktrace
    
    324 324
       type Backtraces :: *
    
    325
    -  data Backtraces = ...
    
    325
    +  data Backtraces = Backtraces {btrCostCentre :: GHC.Internal.Maybe.Maybe (GHC.Internal.Ptr.Ptr GHC.Internal.Stack.CCS.CostCentreStack), btrHasCallStack :: GHC.Internal.Maybe.Maybe GHC.Internal.Stack.Types.CallStack, btrExecutionStack :: GHC.Internal.Maybe.Maybe [GHC.Internal.ExecutionStack.Internal.Location], btrIpe :: GHC.Internal.Maybe.Maybe [GHC.Internal.Stack.CloneStack.StackEntry]}
    
    326 326
       collectBacktraces :: (?callStack::GHC.Internal.Stack.Types.CallStack) => GHC.Internal.Types.IO Backtraces
    
    327 327
       displayBacktraces :: Backtraces -> GHC.Internal.Base.String
    
    328 328
       getBacktraceMechanismState :: BacktraceMechanism -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    

  • testsuite/tests/interface-stability/base-exports.stdout-ws-32
    ... ... @@ -322,7 +322,7 @@ module Control.Exception.Backtrace where
    322 322
       type BacktraceMechanism :: *
    
    323 323
       data BacktraceMechanism = CostCentreBacktrace | HasCallStackBacktrace | ExecutionBacktrace | IPEBacktrace
    
    324 324
       type Backtraces :: *
    
    325
    -  data Backtraces = ...
    
    325
    +  data Backtraces = Backtraces {btrCostCentre :: GHC.Internal.Maybe.Maybe (GHC.Internal.Ptr.Ptr GHC.Internal.Stack.CCS.CostCentreStack), btrHasCallStack :: GHC.Internal.Maybe.Maybe GHC.Internal.Stack.Types.CallStack, btrExecutionStack :: GHC.Internal.Maybe.Maybe [GHC.Internal.ExecutionStack.Internal.Location], btrIpe :: GHC.Internal.Maybe.Maybe [GHC.Internal.Stack.CloneStack.StackEntry]}
    
    326 326
       collectBacktraces :: (?callStack::GHC.Internal.Stack.Types.CallStack) => GHC.Internal.Types.IO Backtraces
    
    327 327
       displayBacktraces :: Backtraces -> GHC.Internal.Base.String
    
    328 328
       getBacktraceMechanismState :: BacktraceMechanism -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    

  • testsuite/tests/rts/TestProddableBlockSet.c
    1
    +#include <assert.h>
    
    2
    +#include <stdbool.h>
    
    3
    +#include <stdint.h>
    
    4
    +#include <stddef.h>
    
    5
    +
    
    6
    +// Excerpted from ProddableBlocks.h
    
    7
    +typedef struct {
    
    8
    +    size_t size;
    
    9
    +    size_t capacity;
    
    10
    +    // sorted list of disjoint (start,end) pairs
    
    11
    +    struct _ProddableBlock *data;
    
    12
    +} ProddableBlockSet;
    
    13
    +
    
    14
    +void initProddableBlockSet ( ProddableBlockSet* set );
    
    15
    +void addProddableBlock ( ProddableBlockSet* set, void* start, size_t size );
    
    16
    +bool containsSpan ( const ProddableBlockSet *set, uintptr_t start, uintptr_t end );
    
    17
    +
    
    18
    +int main () {
    
    19
    +  ProddableBlockSet set;
    
    20
    +  initProddableBlockSet(&set);
    
    21
    +  addProddableBlock(&set, (void*) 0x20, 0x10);
    
    22
    +  addProddableBlock(&set, (void*) 0x30, 0x10);
    
    23
    +  addProddableBlock(&set, (void*) 0x100, 0x10);
    
    24
    +
    
    25
    +  assert( containsSpan(&set, 0x20, 0x30));
    
    26
    +  assert( containsSpan(&set, 0x30, 0x29));
    
    27
    +  assert(!containsSpan(&set, 0x30, 0x49));
    
    28
    +  assert(!containsSpan(&set, 0x60, 0x70));
    
    29
    +  assert(!containsSpan(&set, 0x90, 0x110));
    
    30
    +  assert( containsSpan(&set, 0x100, 0x101));
    
    31
    +  return 0;
    
    32
    +}
    
    33
    +

  • testsuite/tests/rts/all.T
    ... ... @@ -641,3 +641,5 @@ test('T25280', [unless(opsys('linux'),skip),req_process,js_skip], compile_and_ru
    641 641
     # N.B. This will likely issue a warning on stderr but we merely care that the
    
    642 642
     # program doesn't crash.
    
    643 643
     test('T25560', [req_c_rts, ignore_stderr], compile_and_run, [''])
    
    644
    +
    
    645
    +test('TestProddableBlockSet', [req_c_rts], multimod_compile_and_run, ['TestProddableBlockSet.c', '-no-hs-main'])