summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2022-06-01 00:04:26 +0000
committerJohn Ericson <John.Ericson@Obsidian.Systems>2022-06-02 15:42:59 +0000
commit6520da955ec003b3f7ba931e81df4c4f9873f185 (patch)
tree4530a1a0be48fffa1eb648be988aca57c5bb91d2
parentd550d9079d6518938a2e41622b1c3ebf1fb24f59 (diff)
downloadhaskell-6520da955ec003b3f7ba931e81df4c4f9873f185.tar.gz
Split out `GHC.HsToCore.{Breakpoints,Coverage}` and use `SizedSeq`
As proposed in https://gitlab.haskell.org/ghc/ghc/-/merge_requests/7508#note_432877 and https://gitlab.haskell.org/ghc/ghc/-/merge_requests/7508#note_434676, `GHC.HsToCore.Ticks` is about ticks, breakpoints are separate and backend-specific (only for the bytecode interpreter), and mix entry writing is just for HPC. With this split we separate out those interpreter- and HPC-specific its, and keep the main `GHC.HsToCore.Ticks` agnostic. Also, instead of passing the reversed list and count around, we use `SizedSeq` which abstracts over the algorithm. This is much nicer to avoid noise and prevents bugs. (The bugs are not just hypothetical! I missed up the reverses on an earlier draft of this commit.)
-rw-r--r--compiler/GHC/HsToCore.hs30
-rw-r--r--compiler/GHC/HsToCore/Breakpoints.hs54
-rw-r--r--compiler/GHC/HsToCore/Coverage.hs139
-rw-r--r--compiler/GHC/HsToCore/Ticks.hs228
-rw-r--r--compiler/ghc.cabal.in2
-rw-r--r--rts/Hpc.c2
6 files changed, 266 insertions, 189 deletions
diff --git a/compiler/GHC/HsToCore.hs b/compiler/GHC/HsToCore.hs
index 772c242a12..706bb0613a 100644
--- a/compiler/GHC/HsToCore.hs
+++ b/compiler/GHC/HsToCore.hs
@@ -1,4 +1,4 @@
-
+{-# LANGUAGE MonadComprehensions #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
@@ -34,6 +34,8 @@ import GHC.HsToCore.Expr
import GHC.HsToCore.Binds
import GHC.HsToCore.Foreign.Decl
import GHC.HsToCore.Ticks
+import GHC.HsToCore.Breakpoints
+import GHC.HsToCore.Coverage
import GHC.HsToCore.Docs
import GHC.Tc.Types
@@ -62,6 +64,7 @@ import GHC.Builtin.Types
import GHC.Data.FastString
import GHC.Data.Maybe ( expectJust )
import GHC.Data.OrdList
+import GHC.Data.SizedSeq ( sizeSS )
import GHC.Utils.Error
import GHC.Utils.Outputable
@@ -92,6 +95,7 @@ import GHC.Unit.Module.Deps
import Data.List (partition)
import Data.IORef
+import Data.Traversable (for)
{-
************************************************************************
@@ -147,19 +151,35 @@ deSugar hsc_env
do { -- Desugar the program
; let export_set = availsToNameSet exports
bcknd = backend dflags
- hpcInfo = emptyHpcInfo other_hpc_info
- ; (binds_cvr, ds_hpc_info, modBreaks)
+ ; (binds_cvr, m_tickInfo)
<- if not (isHsBootOrSig hsc_src)
then addTicksToBinds
(TicksConfig
{ ticksConfig_logger = hsc_logger hsc_env
, ticksConfig_dynFlags = hsc_dflags hsc_env
- , ticksConfig_mInterp = hsc_interp hsc_env
})
mod mod_loc
export_set (typeEnvTyCons type_env) binds
- else return (binds, hpcInfo, Nothing)
+ else return (binds, Nothing)
+ ; modBreaks <- for
+ [ (i, s)
+ | i <- hsc_interp hsc_env
+ , (_, s) <- m_tickInfo
+ , backendWantsBreakpointTicks (backend dflags)
+ ]
+ $ \(interp, specs) -> mkModBreaks interp mod specs
+
+ ; ds_hpc_info <- case m_tickInfo of
+ Just (orig_file2, ticks)
+ | gopt Opt_Hpc $ hsc_dflags hsc_env
+ -> do
+ hashNo <- if gopt Opt_Hpc $ hsc_dflags hsc_env
+ then writeMixEntries (hpcDir dflags) mod ticks orig_file2
+ else return 0 -- dummy hash when none are written
+ pure $ HpcInfo (fromIntegral $ sizeSS ticks) hashNo
+ _ -> pure $ emptyHpcInfo other_hpc_info
+
; (msgs, mb_res) <- initDs hsc_env tcg_env $
do { ds_ev_binds <- dsEvBinds ev_binds
; core_prs <- dsTopLHsBinds binds_cvr
diff --git a/compiler/GHC/HsToCore/Breakpoints.hs b/compiler/GHC/HsToCore/Breakpoints.hs
new file mode 100644
index 0000000000..98d302efe8
--- /dev/null
+++ b/compiler/GHC/HsToCore/Breakpoints.hs
@@ -0,0 +1,54 @@
+module GHC.HsToCore.Breakpoints
+ ( mkModBreaks
+ ) where
+
+import GHC.Prelude
+
+import qualified GHC.Runtime.Interpreter as GHCi
+import GHC.Runtime.Interpreter.Types
+import GHCi.RemoteTypes
+import GHC.ByteCode.Types
+import GHC.Stack.CCS
+import GHC.Unit
+
+import GHC.HsToCore.Ticks (Tick (..))
+
+import GHC.Data.SizedSeq
+import GHC.Utils.Outputable as Outputable
+
+import Data.List (intersperse)
+import Data.Array
+
+mkModBreaks :: Interp -> Module -> SizedSeq Tick -> IO ModBreaks
+mkModBreaks interp mod extendedMixEntries
+ = do
+ let count = fromIntegral $ sizeSS extendedMixEntries
+ entries = ssElts extendedMixEntries
+
+ breakArray <- GHCi.newBreakArray interp (length entries)
+ ccs <- mkCCSArray interp mod count entries
+ 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
+ }
+
+mkCCSArray
+ :: Interp -> Module -> Int -> [Tick]
+ -> IO (Array BreakIndex (RemotePtr GHC.Stack.CCS.CostCentre))
+mkCCSArray interp modul count entries
+ | GHCi.interpreterProfiled interp = do
+ let module_str = moduleNameString (moduleName modul)
+ costcentres <- GHCi.mkCostCentres interp module_str (map mk_one entries)
+ return (listArray (0,count-1) costcentres)
+ | otherwise = return (listArray (0,-1) [])
+ where
+ mk_one t = (name, src)
+ where name = concat $ intersperse "." $ tick_path t
+ src = renderWithContext defaultSDocContext $ ppr $ tick_loc t
diff --git a/compiler/GHC/HsToCore/Coverage.hs b/compiler/GHC/HsToCore/Coverage.hs
new file mode 100644
index 0000000000..cec5a581de
--- /dev/null
+++ b/compiler/GHC/HsToCore/Coverage.hs
@@ -0,0 +1,139 @@
+{-
+(c) Galois, 2006
+(c) University of Glasgow, 2007
+-}
+
+module GHC.HsToCore.Coverage
+ ( writeMixEntries
+ , hpcInitCode
+ ) where
+
+import GHC.Prelude as Prelude
+
+import GHC.Unit
+
+import GHC.HsToCore.Ticks
+
+import GHC.Platform
+
+import GHC.Data.FastString
+import GHC.Data.SizedSeq
+
+import GHC.Cmm.CLabel
+
+import GHC.Utils.Misc
+import GHC.Utils.Panic
+import GHC.Utils.Outputable
+import GHC.Types.ForeignStubs
+import GHC.Types.HpcInfo
+import GHC.Types.SrcLoc
+
+import Control.Monad
+import Data.Time
+import System.Directory
+
+import Trace.Hpc.Mix
+import Trace.Hpc.Util
+
+import qualified Data.ByteString as BS
+
+writeMixEntries
+ :: FilePath -> Module -> SizedSeq Tick -> FilePath -> IO Int
+writeMixEntries hpc_dir mod extendedMixEntries filename
+ = do
+ let count = fromIntegral $ sizeSS extendedMixEntries
+ entries = ssElts extendedMixEntries
+
+ mod_name = moduleNameString (moduleName mod)
+
+ hpc_mod_dir
+ | moduleUnit mod == mainUnit = hpc_dir
+ | otherwise = hpc_dir ++ "/" ++ unitString (moduleUnit mod)
+
+ tabStop = 8 -- <tab> counts as a normal char in GHC's
+ -- location ranges.
+
+ createDirectoryIfMissing True hpc_mod_dir
+ modTime <- getModificationUTCTime filename
+ let entries' = [ (hpcPos, tick_label t)
+ | t <- entries, hpcPos <- [mkHpcPos $ tick_loc t] ]
+ when (entries' `lengthIsNot` count) $
+ panic "the number of .mix entries are inconsistent"
+ let hashNo = mixHash filename modTime tabStop entries'
+ mixCreate hpc_mod_dir mod_name
+ $ Mix filename modTime (toHash hashNo) tabStop entries'
+ return hashNo
+
+mkHpcPos :: SrcSpan -> HpcPos
+mkHpcPos pos@(RealSrcSpan s _)
+ | isGoodSrcSpan' pos = toHpcPos (srcSpanStartLine s,
+ srcSpanStartCol s,
+ srcSpanEndLine s,
+ srcSpanEndCol s - 1)
+ -- the end column of a SrcSpan is one
+ -- greater than the last column of the
+ -- span (see SrcLoc), whereas HPC
+ -- expects to the column range to be
+ -- inclusive, hence we subtract one above.
+mkHpcPos _ = panic "bad source span; expected such spans to be filtered out"
+
+-- For the hash value, we hash everything: the file name,
+-- the timestamp of the original source file, the tab stop,
+-- and the mix entries. We cheat, and hash the show'd string.
+-- This hash only has to be hashed at Mix creation time,
+-- and is for sanity checking only.
+mixHash :: FilePath -> UTCTime -> Int -> [MixEntry] -> Int
+mixHash file tm tabstop entries = fromIntegral $ hashString
+ (show $ Mix file tm 0 tabstop entries)
+
+{-
+************************************************************************
+* *
+* initialisation
+* *
+************************************************************************
+-}
+
+{- | Create HPC initialization C code for a module
+
+Each module compiled with -fhpc declares an initialisation function of
+the form `hpc_init_<module>()`, which is emitted into the _stub.c file
+and annotated with __attribute__((constructor)) so that it gets
+executed at startup time.
+
+The function's purpose is to call hs_hpc_module to register this
+module with the RTS, and it looks something like this:
+
+> static void hpc_init_Main(void) __attribute__((constructor));
+> static void hpc_init_Main(void)
+> {
+> extern StgWord64 _hpc_tickboxes_Main_hpc[];
+> hs_hpc_module("Main",8,1150288664,_hpc_tickboxes_Main_hpc);
+> }
+-}
+hpcInitCode :: Platform -> Module -> HpcInfo -> CStub
+hpcInitCode _ _ (NoHpcInfo {}) = mempty
+hpcInitCode platform this_mod (HpcInfo tickCount hashNo)
+ = initializerCStub platform fn_name decls body
+ where
+ fn_name = mkInitializerStubLabel this_mod "hpc"
+ decls = text "extern StgWord64 " <> tickboxes <> text "[]" <> semi
+ body = text "hs_hpc_module" <>
+ parens (hcat (punctuate comma [
+ doubleQuotes full_name_str,
+ int tickCount, -- really StgWord32
+ int hashNo, -- really StgWord32
+ tickboxes
+ ])) <> semi
+
+ tickboxes = pprCLabel platform CStyle (mkHpcTicksLabel $ this_mod)
+
+ module_name = hcat (map (text.charToC) $ BS.unpack $
+ bytesFS (moduleNameFS (moduleName this_mod)))
+ package_name = hcat (map (text.charToC) $ BS.unpack $
+ bytesFS (unitFS (moduleUnit this_mod)))
+ full_name_str
+ | moduleUnit this_mod == mainUnit
+ = module_name
+ | otherwise
+ = package_name <> char '/' <> module_name
diff --git a/compiler/GHC/HsToCore/Ticks.hs b/compiler/GHC/HsToCore/Ticks.hs
index cedd1d0439..f78ed14e1e 100644
--- a/compiler/GHC/HsToCore/Ticks.hs
+++ b/compiler/GHC/HsToCore/Ticks.hs
@@ -1,5 +1,4 @@
{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE MonadComprehensions #-}
{-# LANGUAGE NondecreasingIndentation #-}
{-# LANGUAGE TypeFamilies #-}
@@ -12,8 +11,9 @@
module GHC.HsToCore.Ticks
( TicksConfig (..)
+ , Tick (..)
, addTicksToBinds
- , hpcInitCode
+ , isGoodSrcSpan'
) where
import GHC.Prelude as Prelude
@@ -21,13 +21,8 @@ import GHC.Prelude as Prelude
import GHC.Driver.Session
import GHC.Driver.Backend
-import qualified GHC.Runtime.Interpreter as GHCi
-import GHCi.RemoteTypes
-import GHC.ByteCode.Types
-import GHC.Stack.CCS
import GHC.Hs
import GHC.Unit
-import GHC.Cmm.CLabel
import GHC.Core.Type
import GHC.Core.TyCon
@@ -35,40 +30,27 @@ import GHC.Core.TyCon
import GHC.Data.Maybe
import GHC.Data.FastString
import GHC.Data.Bag
+import GHC.Data.SizedSeq
-import GHC.Platform
-
-import GHC.Runtime.Interpreter.Types
-
-import GHC.Utils.Misc
import GHC.Utils.Outputable as Outputable
import GHC.Utils.Panic
import GHC.Utils.Monad
import GHC.Utils.Logger
-
import GHC.Types.SrcLoc
import GHC.Types.Basic
import GHC.Types.Id
import GHC.Types.Var.Set
import GHC.Types.Name.Set hiding (FreeVars)
import GHC.Types.Name
-import GHC.Types.HpcInfo
import GHC.Types.CostCentre
import GHC.Types.CostCentre.State
-import GHC.Types.ForeignStubs
import GHC.Types.Tickish
import Control.Monad
import Data.List (isSuffixOf, intersperse)
-import Data.Array
-import Data.Time
-import Data.Traversable (for)
-import System.Directory
import Trace.Hpc.Mix
-import Trace.Hpc.Util
-import qualified Data.ByteString as BS
import Data.Set (Set)
import qualified Data.Set as Set
@@ -87,10 +69,16 @@ data TicksConfig = TicksConfig
-- FIXME: replace this with the specific fields of DynFlags we care about.
, ticksConfig_dynFlags :: DynFlags
+ }
- , ticksConfig_mInterp :: Maybe Interp
+data Tick = Tick
+ { tick_loc :: SrcSpan -- ^ Tick source span
+ , tick_path :: [String] -- ^ Path to the declaration
+ , tick_ids :: [OccName] -- ^ Identifiers being bound
+ , tick_label :: BoxLabel -- ^ Label for the tick counter
}
+
addTicksToBinds
:: TicksConfig
-> Module
@@ -100,12 +88,11 @@ addTicksToBinds
-- hasn't set it), so we have to work from this set.
-> [TyCon] -- ^ Type constructors in this module
-> LHsBinds GhcTc
- -> IO (LHsBinds GhcTc, HpcInfo, Maybe ModBreaks)
+ -> IO (LHsBinds GhcTc, Maybe (FilePath, SizedSeq Tick))
addTicksToBinds (TicksConfig
{ ticksConfig_logger = logger
, ticksConfig_dynFlags = dflags
- , ticksConfig_mInterp = m_interp
})
mod mod_loc exports tyCons binds
| let passes = coveragePasses dflags
@@ -134,27 +121,16 @@ addTicksToBinds (TicksConfig
(binds',_,st') = unTM (addTickLHsBinds binds) env st
in (binds', st')
- initState = TT { tickBoxCount = 0
- , mixEntries = []
- , ccIndices = newCostCentreState
- }
-
- (binds1,st) = foldr tickPass (binds, initState) passes
+ (binds1,st) = foldr tickPass (binds, initTTState) passes
- let tickCount = tickBoxCount st
- entries = reverse $ mixEntries st
- modBreaks <- for [i | i <- m_interp, breakpointsEnabled dflags] $
- \interp -> mkModBreaks interp mod tickCount entries
- hashNo <- if gopt Opt_Hpc dflags
- then writeMixEntries (hpcDir dflags) mod tickCount entries orig_file2
- else return 0 -- dummy hash when none are written
+ extendedMixEntries = ticks st
putDumpFileMaybe logger Opt_D_dump_ticked "HPC" FormatHaskell
(pprLHsBinds binds1)
- return (binds1, HpcInfo tickCount hashNo, modBreaks)
+ return (binds1, Just (orig_file2, extendedMixEntries))
- | otherwise = return (binds, emptyHpcInfo False, Nothing)
+ | otherwise = return (binds, Nothing)
guessSourceFile :: LHsBinds GhcTc -> FilePath -> FilePath
guessSourceFile binds orig_file =
@@ -169,64 +145,6 @@ guessSourceFile binds orig_file =
_ -> orig_file
-mkModBreaks :: Interp -> Module -> Int -> [MixEntry_] -> IO ModBreaks
-mkModBreaks interp mod count entries
- = do
- breakArray <- GHCi.newBreakArray interp (length entries)
- ccs <- mkCCSArray interp mod count entries
- let
- locsTicks = listArray (0,count-1) [ span | (span,_,_,_) <- entries ]
- varsTicks = listArray (0,count-1) [ vars | (_,_,vars,_) <- entries ]
- declsTicks = listArray (0,count-1) [ decls | (_,decls,_,_) <- entries ]
- return $ emptyModBreaks
- { modBreaks_flags = breakArray
- , modBreaks_locs = locsTicks
- , modBreaks_vars = varsTicks
- , modBreaks_decls = declsTicks
- , modBreaks_ccs = ccs
- }
-
-mkCCSArray
- :: Interp -> Module -> Int -> [MixEntry_]
- -> IO (Array BreakIndex (RemotePtr GHC.Stack.CCS.CostCentre))
-mkCCSArray interp modul count entries
- | GHCi.interpreterProfiled interp = do
- let module_str = moduleNameString (moduleName modul)
- costcentres <- GHCi.mkCostCentres interp module_str (map mk_one entries)
- return (listArray (0,count-1) costcentres)
- | otherwise = return (listArray (0,-1) [])
- where
- mk_one (srcspan, decl_path, _, _) = (name, src)
- where name = concat (intersperse "." decl_path)
- src = renderWithContext defaultSDocContext (ppr srcspan)
-
-
-writeMixEntries
- :: FilePath -> Module -> Int -> [MixEntry_] -> FilePath -> IO Int
-writeMixEntries hpc_dir mod count entries filename
- = do
- let
- mod_name = moduleNameString (moduleName mod)
-
- hpc_mod_dir
- | moduleUnit mod == mainUnit = hpc_dir
- | otherwise = hpc_dir ++ "/" ++ unitString (moduleUnit mod)
-
- tabStop = 8 -- <tab> counts as a normal char in GHC's
- -- location ranges.
-
- createDirectoryIfMissing True hpc_mod_dir
- modTime <- getModificationUTCTime filename
- let entries' = [ (hpcPos, box)
- | (span,_,_,box) <- entries, hpcPos <- [mkHpcPos span] ]
- when (entries' `lengthIsNot` count) $
- panic "the number of .mix entries are inconsistent"
- let hashNo = mixHash filename modTime tabStop entries'
- mixCreate hpc_mod_dir mod_name
- $ Mix filename modTime (toHash hashNo) tabStop entries'
- return hashNo
-
-
-- -----------------------------------------------------------------------------
-- TickDensity
@@ -1038,17 +956,20 @@ addTickArithSeqInfo (FromThenTo e1 e2 e3) =
(addTickLHsExpr e2)
(addTickLHsExpr e3)
-data TickTransState = TT { tickBoxCount:: !Int
- , mixEntries :: [MixEntry_]
+data TickTransState = TT { ticks :: !(SizedSeq Tick)
, ccIndices :: !CostCentreState
}
-addMixEntry :: MixEntry_ -> TM Int
+initTTState :: TickTransState
+initTTState = TT { ticks = emptySS
+ , ccIndices = newCostCentreState
+ }
+
+addMixEntry :: Tick -> TM Int
addMixEntry ent = do
- c <- tickBoxCount <$> getState
+ c <- fromIntegral . sizeSS . ticks <$> getState
setState $ \st ->
- st { tickBoxCount = c + 1
- , mixEntries = ent : mixEntries st
+ st { ticks = addToSS (ticks st) ent
}
return c
@@ -1250,7 +1171,12 @@ mkTickish boxLabel countEntries topOnly pos fvs decl_path = do
-- * the simplifier might try to substitute a literal for
-- the Id, and we can't handle that.
- me = (pos, decl_path, map (nameOccName.idName) ids, boxLabel)
+ me = Tick
+ { tick_loc = pos
+ , tick_path = decl_path
+ , tick_ids = map (nameOccName.idName) ids
+ , tick_label = boxLabel
+ }
cc_name | topOnly = head decl_path
| otherwise = concat (intersperse "." decl_path)
@@ -1290,27 +1216,26 @@ mkBinTickBoxHpc :: (Bool -> BoxLabel) -> SrcSpan -> LHsExpr GhcTc
mkBinTickBoxHpc boxLabel pos e = do
env <- getEnv
binTick <- HsBinTick
- <$> addMixEntry (pos,declPath env, [],boxLabel True)
- <*> addMixEntry (pos,declPath env, [],boxLabel False)
+ <$> addMixEntry (Tick { tick_loc = pos
+ , tick_path = declPath env
+ , tick_ids = []
+ , tick_label = boxLabel True
+ })
+ <*> addMixEntry (Tick { tick_loc = pos
+ , tick_path = declPath env
+ , tick_ids = []
+ , tick_label = boxLabel False
+ })
<*> pure e
tick <- HpcTick (this_mod env)
- <$> addMixEntry (pos,declPath env, [],ExpBox False)
+ <$> addMixEntry (Tick { tick_loc = pos
+ , tick_path = declPath env
+ , tick_ids = []
+ , tick_label = ExpBox False
+ })
let pos' = noAnnSrcSpan pos
return $ L pos' $ XExpr $ HsTick tick (L pos' (XExpr binTick))
-mkHpcPos :: SrcSpan -> HpcPos
-mkHpcPos pos@(RealSrcSpan s _)
- | isGoodSrcSpan' pos = toHpcPos (srcSpanStartLine s,
- srcSpanStartCol s,
- srcSpanEndLine s,
- srcSpanEndCol s - 1)
- -- the end column of a SrcSpan is one
- -- greater than the last column of the
- -- span (see SrcLoc), whereas HPC
- -- expects to the column range to be
- -- inclusive, hence we subtract one above.
-mkHpcPos _ = panic "bad source span; expected such spans to be filtered out"
-
hpcSrcSpan :: SrcSpan
hpcSrcSpan = mkGeneralSrcSpan (fsLit "Haskell Program Coverage internals")
@@ -1320,66 +1245,3 @@ matchesOneOfMany lmatches = sum (map matchCount lmatches) > 1
matchCount :: LMatch GhcTc body -> Int
matchCount (L _ (Match { m_grhss = GRHSs _ grhss _ }))
= length grhss
-
-type MixEntry_ = (SrcSpan, [String], [OccName], BoxLabel)
-
--- For the hash value, we hash everything: the file name,
--- the timestamp of the original source file, the tab stop,
--- and the mix entries. We cheat, and hash the show'd string.
--- This hash only has to be hashed at Mix creation time,
--- and is for sanity checking only.
-mixHash :: FilePath -> UTCTime -> Int -> [MixEntry] -> Int
-mixHash file tm tabstop entries = fromIntegral $ hashString
- (show $ Mix file tm 0 tabstop entries)
-
-{-
-************************************************************************
-* *
-* initialisation
-* *
-************************************************************************
--}
-
-{- | Create HPC initialization C code for a module
-
-Each module compiled with -fhpc declares an initialisation function of
-the form `hpc_init_<module>()`, which is emitted into the _stub.c file
-and annotated with __attribute__((constructor)) so that it gets
-executed at startup time.
-
-The function's purpose is to call hs_hpc_module to register this
-module with the RTS, and it looks something like this:
-
-> static void hpc_init_Main(void) __attribute__((constructor));
-> static void hpc_init_Main(void)
-> {
-> extern StgWord64 _hpc_tickboxes_Main_hpc[];
-> hs_hpc_module("Main",8,1150288664,_hpc_tickboxes_Main_hpc);
-> }
--}
-hpcInitCode :: Platform -> Module -> HpcInfo -> CStub
-hpcInitCode _ _ (NoHpcInfo {}) = mempty
-hpcInitCode platform this_mod (HpcInfo tickCount hashNo)
- = initializerCStub platform fn_name decls body
- where
- fn_name = mkInitializerStubLabel this_mod "hpc"
- decls = text "extern StgWord64 " <> tickboxes <> text "[]" <> semi
- body = text "hs_hpc_module" <>
- parens (hcat (punctuate comma [
- doubleQuotes full_name_str,
- int tickCount, -- really StgWord32
- int hashNo, -- really StgWord32
- tickboxes
- ])) <> semi
-
- tickboxes = pprCLabel platform CStyle (mkHpcTicksLabel $ this_mod)
-
- module_name = hcat (map (text.charToC) $ BS.unpack $
- bytesFS (moduleNameFS (moduleName this_mod)))
- package_name = hcat (map (text.charToC) $ BS.unpack $
- bytesFS (unitFS (moduleUnit this_mod)))
- full_name_str
- | moduleUnit this_mod == mainUnit
- = module_name
- | otherwise
- = package_name <> char '/' <> module_name
diff --git a/compiler/ghc.cabal.in b/compiler/ghc.cabal.in
index afb7618e1e..d7ca0b84c0 100644
--- a/compiler/ghc.cabal.in
+++ b/compiler/ghc.cabal.in
@@ -453,6 +453,8 @@ Library
GHC.HsToCore
GHC.HsToCore.Arrows
GHC.HsToCore.Binds
+ GHC.HsToCore.Breakpoints
+ GHC.HsToCore.Coverage
GHC.HsToCore.Docs
GHC.HsToCore.Errors.Ppr
GHC.HsToCore.Errors.Types
diff --git a/rts/Hpc.c b/rts/Hpc.c
index 55e0fa355a..edbad500c0 100644
--- a/rts/Hpc.c
+++ b/rts/Hpc.c
@@ -241,7 +241,7 @@ startupHpc(void)
/*
* Called on a per-module basis, by a constructor function compiled
- * with each module (see GHC.HsToCore.Ticks.hpcInitCode), declaring
+ * with each module (see GHC.HsToCore.Coverage.hpcInitCode), declaring
* where the tix boxes are stored in memory. This memory can be uninitized,
* because we will initialize it with either the contents of the tix
* file, or all zeros.