Rodrigo Mesquita pushed to branch wip/romes/step-out-9 at Glasgow Haskell Compiler / GHC
Commits:
-
06651a24
by Rodrigo Mesquita at 2025-07-02T17:24:52+01:00
-
c3f1b718
by Rodrigo Mesquita at 2025-07-02T17:24:52+01:00
-
5178fc25
by Rodrigo Mesquita at 2025-07-02T17:24:52+01:00
26 changed files:
- compiler/GHC.hs
- compiler/GHC/ByteCode/Asm.hs
- + compiler/GHC/ByteCode/Breakpoints.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Core/Ppr.hs
- compiler/GHC/Driver/Session/Inspect.hs
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Debugger/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Eval/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- − compiler/GHC/Types/Breakpoint.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Unit/Module/ModGuts.hs
- compiler/ghc.cabal.in
- ghc/GHCi/UI.hs
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
Changes:
... | ... | @@ -201,7 +201,7 @@ module GHC ( |
201 | 201 | getResumeContext,
|
202 | 202 | GHC.obtainTermFromId, GHC.obtainTermFromVal, reconstructType,
|
203 | 203 | modInfoModBreaks,
|
204 | - ModBreaks(..), BreakIndex,
|
|
204 | + ModBreaks(..), BreakTickIndex,
|
|
205 | 205 | BreakpointId(..), InternalBreakpointId(..),
|
206 | 206 | GHC.Runtime.Eval.back,
|
207 | 207 | GHC.Runtime.Eval.forward,
|
... | ... | @@ -427,7 +427,6 @@ import GHC.Types.Basic |
427 | 427 | import GHC.Types.TyThing
|
428 | 428 | import GHC.Types.Name.Env
|
429 | 429 | import GHC.Types.TypeEnv
|
430 | -import GHC.Types.Breakpoint
|
|
431 | 430 | import GHC.Types.PkgQual
|
432 | 431 | |
433 | 432 | import GHC.Unit
|
... | ... | @@ -109,7 +109,7 @@ assembleBCOs |
109 | 109 | -> FlatBag (ProtoBCO Name)
|
110 | 110 | -> [TyCon]
|
111 | 111 | -> [(Name, ByteString)]
|
112 | - -> Maybe ModBreaks
|
|
112 | + -> Maybe InternalModBreaks
|
|
113 | 113 | -> [SptEntry]
|
114 | 114 | -> IO CompiledByteCode
|
115 | 115 | assembleBCOs profile proto_bcos tycons top_strs modbreaks spt_entries = do
|
... | ... | @@ -841,19 +841,24 @@ assembleI platform i = case i of |
841 | 841 | W8 -> emit_ bci_OP_INDEX_ADDR_08 []
|
842 | 842 | _ -> unsupported_width
|
843 | 843 | |
844 | - BRK_FUN tick_mod tickx info_mod infox ->
|
|
845 | - do p1 <- ptr $ BCOPtrBreakArray tick_mod
|
|
846 | - tick_addr <- lit1 $ BCONPtrFS $ moduleNameFS $ moduleName tick_mod
|
|
847 | - info_addr <- lit1 $ BCONPtrFS $ moduleNameFS $ moduleName info_mod
|
|
848 | - tick_unitid_addr <- lit1 $ BCONPtrFS $ unitIdFS $ moduleUnitId $ tick_mod
|
|
849 | - info_unitid_addr <- lit1 $ BCONPtrFS $ unitIdFS $ moduleUnitId $ info_mod
|
|
850 | - np <- lit1 $ BCONPtrCostCentre tick_mod $ fromIntegral tickx
|
|
851 | - emit_ bci_BRK_FUN [ Op p1
|
|
852 | - , Op tick_addr, Op info_addr
|
|
853 | - , Op tick_unitid_addr, Op info_unitid_addr
|
|
854 | - , SmallOp tickx, SmallOp infox
|
|
855 | - , Op np
|
|
856 | - ]
|
|
844 | + BRK_FUN (InternalBreakpointId tick_mod tickx info_mod infox) -> do
|
|
845 | + let -- cast that checks that round-tripping through Word16 doesn't change the value
|
|
846 | + toW16 x = let r = fromIntegral x :: Word16
|
|
847 | + in if fromIntegral r == x
|
|
848 | + then r
|
|
849 | + else pprPanic "schemeER_wrk: breakpoint tick/info index too large!" (ppr x)
|
|
850 | + p1 <- ptr $ BCOPtrBreakArray tick_mod
|
|
851 | + tick_addr <- lit1 $ BCONPtrFS $ moduleNameFS $ moduleName tick_mod
|
|
852 | + info_addr <- lit1 $ BCONPtrFS $ moduleNameFS $ moduleName info_mod
|
|
853 | + tick_unitid_addr <- lit1 $ BCONPtrFS $ unitIdFS $ moduleUnitId $ tick_mod
|
|
854 | + info_unitid_addr <- lit1 $ BCONPtrFS $ unitIdFS $ moduleUnitId $ info_mod
|
|
855 | + np <- lit1 $ BCONPtrCostCentre (BreakpointId tick_mod tickx)
|
|
856 | + emit_ bci_BRK_FUN [ Op p1
|
|
857 | + , Op tick_addr, Op info_addr
|
|
858 | + , Op tick_unitid_addr, Op info_unitid_addr
|
|
859 | + , SmallOp (toW16 tickx), SmallOp (toW16 infox)
|
|
860 | + , Op np
|
|
861 | + ]
|
|
857 | 862 | |
858 | 863 | BRK_ALTS active -> emit_ bci_BRK_ALTS [SmallOp (if active then 1 else 0)]
|
859 | 864 |
1 | +{-# LANGUAGE RecordWildCards #-}
|
|
2 | + |
|
3 | +-- | Breakpoint information constructed during ByteCode generation.
|
|
4 | +--
|
|
5 | +-- Specifically, code-generation breakpoints are referred to as "internal
|
|
6 | +-- breakpoints", the internal breakpoint data for a module is stored in
|
|
7 | +-- 'InternalModBreaks', and is uniquely identified at runtime by an
|
|
8 | +-- 'InternalBreakpointId'.
|
|
9 | +--
|
|
10 | +-- See Note [Breakpoint identifiers]
|
|
11 | +module GHC.ByteCode.Breakpoints
|
|
12 | + ( -- * Internal Mod Breaks
|
|
13 | + InternalModBreaks(..), CgBreakInfo(..)
|
|
14 | + , mkInternalModBreaks
|
|
15 | + |
|
16 | + -- ** Internal breakpoint identifier
|
|
17 | + , InternalBreakpointId(..), BreakInfoIndex
|
|
18 | + |
|
19 | + -- * Operations
|
|
20 | + , toBreakpointId
|
|
21 | + |
|
22 | + -- ** Internal-level operations
|
|
23 | + , getInternalBreak, addInternalBreak
|
|
24 | + |
|
25 | + -- ** Source-level information operations
|
|
26 | + , getBreakLoc, getBreakVars, getBreakDecls, getBreakCCS
|
|
27 | + |
|
28 | + -- * Utils
|
|
29 | + , seqInternalModBreaks
|
|
30 | + |
|
31 | + )
|
|
32 | + where
|
|
33 | + |
|
34 | +import GHC.Prelude
|
|
35 | +import GHC.Types.SrcLoc
|
|
36 | +import GHC.Types.Name.Occurrence
|
|
37 | +import Control.DeepSeq
|
|
38 | +import Data.IntMap.Strict (IntMap)
|
|
39 | +import qualified Data.IntMap.Strict as IM
|
|
40 | + |
|
41 | +import GHC.HsToCore.Breakpoints
|
|
42 | +import GHC.Iface.Syntax
|
|
43 | + |
|
44 | +import GHC.Unit.Module (Module)
|
|
45 | +import GHC.Utils.Outputable
|
|
46 | +import GHC.Utils.Panic
|
|
47 | +import Data.Array
|
|
48 | + |
|
49 | +{-
|
|
50 | +Note [Breakpoint identifiers]
|
|
51 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
52 | +Before optimization a breakpoint is identified uniquely with a tick module
|
|
53 | +and a tick index. See 'BreakpointId'. A tick module contains an array, indexed
|
|
54 | +with the tick indexes, which indicates breakpoint status.
|
|
55 | + |
|
56 | +When we generate ByteCode, we collect information for every breakpoint at
|
|
57 | +their *occurrence sites* (see CgBreakInfo) and these info
|
|
58 | +are stored in the ModIface of the occurrence module. Because of inlining, we
|
|
59 | +can't reuse the tick index to uniquely identify an occurrence; because of
|
|
60 | +cross-module inlining, we can't assume that the occurrence module is the same
|
|
61 | +as the tick module (#24712).
|
|
62 | + |
|
63 | +So every breakpoint occurrence gets assigned a module-unique *info index* and
|
|
64 | +we store it alongside the occurrence module (*info module*) in the
|
|
65 | +'InternalBreakpointId' datatype. This is the index that we use at runtime to
|
|
66 | +identify a breakpoint.
|
|
67 | +-}
|
|
68 | + |
|
69 | +--------------------------------------------------------------------------------
|
|
70 | +-- * Internal breakpoint identifiers
|
|
71 | +--------------------------------------------------------------------------------
|
|
72 | + |
|
73 | +-- | Internal breakpoint info index
|
|
74 | +type BreakInfoIndex = Int
|
|
75 | + |
|
76 | +-- | Internal breakpoint identifier
|
|
77 | +--
|
|
78 | +-- Indexes into the structures in the @'InternalModBreaks'@ produced during ByteCode generation.
|
|
79 | +-- See Note [Breakpoint identifiers]
|
|
80 | +data InternalBreakpointId = InternalBreakpointId
|
|
81 | + { ibi_tick_mod :: !Module -- ^ Breakpoint tick module
|
|
82 | + , ibi_tick_index :: !Int -- ^ Breakpoint tick index
|
|
83 | + , ibi_info_mod :: !Module -- ^ Breakpoint tick module
|
|
84 | + , ibi_info_index :: !BreakInfoIndex -- ^ Breakpoint tick index
|
|
85 | + }
|
|
86 | + deriving (Eq, Ord)
|
|
87 | + |
|
88 | +toBreakpointId :: InternalBreakpointId -> BreakpointId
|
|
89 | +toBreakpointId ibi = BreakpointId
|
|
90 | + { bi_tick_mod = ibi_tick_mod ibi
|
|
91 | + , bi_tick_index = ibi_tick_index ibi
|
|
92 | + }
|
|
93 | + |
|
94 | +--------------------------------------------------------------------------------
|
|
95 | +-- * Internal Mod Breaks
|
|
96 | +--------------------------------------------------------------------------------
|
|
97 | + |
|
98 | +-- | Internal mod breaks store the runtime-relevant information of breakpoints.
|
|
99 | +--
|
|
100 | +-- Importantly, it maps 'InternalBreakpointId's to 'CgBreakInfo'.
|
|
101 | +--
|
|
102 | +-- 'InternalModBreaks' are constructed during bytecode generation and stored in
|
|
103 | +-- 'CompiledByteCode' afterwards.
|
|
104 | +data InternalModBreaks = InternalModBreaks
|
|
105 | + { imodBreaks_breakInfo :: !(IntMap CgBreakInfo)
|
|
106 | + -- ^ Access code-gen time information about a breakpoint, indexed by
|
|
107 | + -- 'InternalBreakpointId'.
|
|
108 | + |
|
109 | + , imodBreaks_modBreaks :: !ModBreaks
|
|
110 | + -- ^ Store the original ModBreaks for this module, unchanged.
|
|
111 | + -- Allows us to query about source-level breakpoint information using
|
|
112 | + -- an internal breakpoint id.
|
|
113 | + }
|
|
114 | + |
|
115 | +-- | Construct an 'InternalModBreaks'
|
|
116 | +mkInternalModBreaks :: Module -> IntMap CgBreakInfo -> ModBreaks -> InternalModBreaks
|
|
117 | +mkInternalModBreaks mod im mbs =
|
|
118 | + assertPpr (mod == modBreaks_module mbs)
|
|
119 | + (text "Constructing InternalModBreaks with the ModBreaks of a different module!") $
|
|
120 | + InternalModBreaks im mbs
|
|
121 | + |
|
122 | +-- | Information about a breakpoint that we know at code-generation time
|
|
123 | +-- In order to be used, this needs to be hydrated relative to the current HscEnv by
|
|
124 | +-- 'hydrateCgBreakInfo'. Everything here can be fully forced and that's critical for
|
|
125 | +-- preventing space leaks (see #22530)
|
|
126 | +data CgBreakInfo
|
|
127 | + = CgBreakInfo
|
|
128 | + { cgb_tyvars :: ![IfaceTvBndr] -- ^ Type variables in scope at the breakpoint
|
|
129 | + , cgb_vars :: ![Maybe (IfaceIdBndr, Word)]
|
|
130 | + , cgb_resty :: !IfaceType
|
|
131 | + }
|
|
132 | +-- See Note [Syncing breakpoint info] in GHC.Runtime.Eval
|
|
133 | + |
|
134 | +-- | Get an internal breakpoint info by 'InternalBreakpointId'
|
|
135 | +getInternalBreak :: InternalBreakpointId -> InternalModBreaks -> CgBreakInfo
|
|
136 | +getInternalBreak (InternalBreakpointId _ _ info_mod info_ix) imbs =
|
|
137 | + assert_modules_match info_mod (modBreaks_module $ imodBreaks_modBreaks imbs) $
|
|
138 | + imodBreaks_breakInfo imbs IM.! info_ix
|
|
139 | + |
|
140 | +-- | Add a CgBreakInfo to an 'InternalModBreaks' at 'InternalBreakpointId'
|
|
141 | +addInternalBreak :: InternalBreakpointId -> CgBreakInfo -> InternalModBreaks -> InternalModBreaks
|
|
142 | +addInternalBreak (InternalBreakpointId _ _ info_mod info_ix) info imbs =
|
|
143 | + assert_modules_match info_mod (modBreaks_module $ imodBreaks_modBreaks imbs) $
|
|
144 | + imbs{imodBreaks_breakInfo = IM.insert info_ix info (imodBreaks_breakInfo imbs)}
|
|
145 | + |
|
146 | +-- | Assert that the module in the 'InternalBreakpointId' and in
|
|
147 | +-- 'InternalModBreaks' match.
|
|
148 | +assert_modules_match :: Module -> Module -> a -> a
|
|
149 | +assert_modules_match ibi_mod imbs_mod =
|
|
150 | + assertPpr (ibi_mod == imbs_mod)
|
|
151 | + (text "Tried to query the InternalModBreaks of module" <+> ppr imbs_mod
|
|
152 | + <+> text "with an InternalBreakpointId for module" <+> ppr ibi_mod)
|
|
153 | + |
|
154 | +--------------------------------------------------------------------------------
|
|
155 | +-- Tick-level Breakpoint information
|
|
156 | +--------------------------------------------------------------------------------
|
|
157 | + |
|
158 | +-- | Get the source span for this breakpoint
|
|
159 | +getBreakLoc :: InternalBreakpointId -> InternalModBreaks -> SrcSpan
|
|
160 | +getBreakLoc = getBreakXXX modBreaks_locs
|
|
161 | + |
|
162 | +-- | Get the vars for this breakpoint
|
|
163 | +getBreakVars :: InternalBreakpointId -> InternalModBreaks -> [OccName]
|
|
164 | +getBreakVars = getBreakXXX modBreaks_vars
|
|
165 | + |
|
166 | +-- | Get the decls for this breakpoint
|
|
167 | +getBreakDecls :: InternalBreakpointId -> InternalModBreaks -> [String]
|
|
168 | +getBreakDecls = getBreakXXX modBreaks_decls
|
|
169 | + |
|
170 | +-- | Get the decls for this breakpoint
|
|
171 | +getBreakCCS :: InternalBreakpointId -> InternalModBreaks -> (String, String)
|
|
172 | +getBreakCCS = getBreakXXX modBreaks_ccs
|
|
173 | + |
|
174 | +-- | Internal utility to access a ModBreaks field at a particular breakpoint index
|
|
175 | +getBreakXXX :: (ModBreaks -> Array BreakTickIndex a) -> InternalBreakpointId -> InternalModBreaks -> a
|
|
176 | +getBreakXXX view (InternalBreakpointId tick_mod tick_id _ _) imbs =
|
|
177 | + assert_modules_match tick_mod (modBreaks_module $ imodBreaks_modBreaks imbs) $ do
|
|
178 | + view (imodBreaks_modBreaks imbs) ! tick_id
|
|
179 | + |
|
180 | +--------------------------------------------------------------------------------
|
|
181 | +-- Instances
|
|
182 | +--------------------------------------------------------------------------------
|
|
183 | + |
|
184 | +-- | Fully force an 'InternalModBreaks' value
|
|
185 | +seqInternalModBreaks :: InternalModBreaks -> ()
|
|
186 | +seqInternalModBreaks InternalModBreaks{..} =
|
|
187 | + rnf (fmap seqCgBreakInfo imodBreaks_breakInfo)
|
|
188 | + where
|
|
189 | + seqCgBreakInfo :: CgBreakInfo -> ()
|
|
190 | + seqCgBreakInfo CgBreakInfo{..} =
|
|
191 | + rnf cgb_tyvars `seq`
|
|
192 | + rnf cgb_vars `seq`
|
|
193 | + rnf cgb_resty
|
|
194 | + |
|
195 | +instance Outputable InternalBreakpointId where
|
|
196 | + ppr InternalBreakpointId{..} =
|
|
197 | + text "InternalBreakpointId" <+> ppr ibi_info_mod <+> ppr ibi_info_index
|
|
198 | + |
|
199 | +instance NFData InternalBreakpointId where
|
|
200 | + rnf InternalBreakpointId{..} =
|
|
201 | + rnf ibi_info_mod `seq` rnf ibi_info_index
|
|
202 | + |
|
203 | +instance Outputable CgBreakInfo where
|
|
204 | + ppr info = text "CgBreakInfo" <+>
|
|
205 | + parens (ppr (cgb_vars info) <+>
|
|
206 | + ppr (cgb_resty info)) |
... | ... | @@ -17,7 +17,6 @@ import GHC.ByteCode.Types |
17 | 17 | import GHC.Cmm.Type (Width)
|
18 | 18 | import GHC.StgToCmm.Layout ( ArgRep(..) )
|
19 | 19 | import GHC.Utils.Outputable
|
20 | -import GHC.Unit.Module
|
|
21 | 20 | import GHC.Types.Name
|
22 | 21 | import GHC.Types.Literal
|
23 | 22 | import GHC.Types.Unique
|
... | ... | @@ -259,10 +258,7 @@ data BCInstr |
259 | 258 | -- Note [unboxed tuple bytecodes and tuple_BCO] in GHC.StgToByteCode
|
260 | 259 | |
261 | 260 | -- Breakpoints
|
262 | - | BRK_FUN !Module -- breakpoint tick module
|
|
263 | - !Word16 -- breakpoint tick index
|
|
264 | - !Module -- breakpoint info module
|
|
265 | - !Word16 -- breakpoint info index
|
|
261 | + | BRK_FUN !InternalBreakpointId
|
|
266 | 262 | |
267 | 263 | -- An internal breakpoint for triggering a break on any case alternative
|
268 | 264 | -- See Note [Debugger: BRK_ALTS]
|
... | ... | @@ -458,10 +454,10 @@ instance Outputable BCInstr where |
458 | 454 | ppr ENTER = text "ENTER"
|
459 | 455 | ppr (RETURN pk) = text "RETURN " <+> ppr pk
|
460 | 456 | ppr (RETURN_TUPLE) = text "RETURN_TUPLE"
|
461 | - ppr (BRK_FUN _tick_mod tickx _info_mod infox)
|
|
457 | + ppr (BRK_FUN (InternalBreakpointId tick_mod tickx info_mod infox))
|
|
462 | 458 | = text "BRK_FUN" <+> text "<breakarray>"
|
463 | - <+> text "<tick_module>" <+> text "<tick_module_unitid>" <+> ppr tickx
|
|
464 | - <+> text "<info_module>" <+> text "<info_module_unitid>" <+> ppr infox
|
|
459 | + <+> ppr tick_mod <+> ppr tickx
|
|
460 | + <+> ppr info_mod <+> ppr infox
|
|
465 | 461 | <+> text "<cc>"
|
466 | 462 | ppr (BRK_ALTS active) = text "BRK_ALTS" <+> ppr active
|
467 | 463 | #if MIN_VERSION_rts(1,0,3)
|
... | ... | @@ -97,9 +97,9 @@ lookupLiteral interp pkgs_loaded le ptr = case ptr of |
97 | 97 | BCONPtrFFIInfo (FFIInfo {..}) -> do
|
98 | 98 | RemotePtr p <- interpCmd interp $ PrepFFI ffiInfoArgs ffiInfoRet
|
99 | 99 | pure $ fromIntegral p
|
100 | - BCONPtrCostCentre tick_mod tick_no
|
|
101 | - | interpreterProfiled interp ->
|
|
102 | - case expectJust (lookupModuleEnv (ccs_env le) tick_mod) ! tick_no of
|
|
100 | + BCONPtrCostCentre BreakpointId{..}
|
|
101 | + | interpreterProfiled interp -> do
|
|
102 | + case expectJust (lookupModuleEnv (ccs_env le) bi_tick_mod) ! bi_tick_index of
|
|
103 | 103 | RemotePtr p -> pure $ fromIntegral p
|
104 | 104 | | otherwise ->
|
105 | 105 | case toRemotePtr nullPtr of
|
... | ... | @@ -18,10 +18,15 @@ module GHC.ByteCode.Types |
18 | 18 | , UnlinkedBCO(..), BCOPtr(..), BCONPtr(..)
|
19 | 19 | , ItblEnv, ItblPtr(..)
|
20 | 20 | , AddrEnv, AddrPtr(..)
|
21 | - , CgBreakInfo(..)
|
|
22 | - , ModBreaks (..), BreakIndex
|
|
23 | - , CCostCentre
|
|
24 | 21 | , FlatBag, sizeFlatBag, fromSmallArray, elemsFlatBag
|
22 | + |
|
23 | + -- * Mod Breaks
|
|
24 | + , ModBreaks (..), BreakpointId(..), BreakTickIndex
|
|
25 | + |
|
26 | + -- * Internal Mod Breaks
|
|
27 | + , InternalModBreaks(..), CgBreakInfo(..), seqInternalModBreaks
|
|
28 | + -- ** Internal breakpoint identifier
|
|
29 | + , InternalBreakpointId(..), BreakInfoIndex
|
|
25 | 30 | ) where
|
26 | 31 | |
27 | 32 | import GHC.Prelude
|
... | ... | @@ -33,8 +38,8 @@ import GHC.Types.Name.Env |
33 | 38 | import GHC.Utils.Outputable
|
34 | 39 | import GHC.Builtin.PrimOps
|
35 | 40 | import GHC.Types.SptEntry
|
36 | -import GHC.Types.SrcLoc
|
|
37 | -import GHCi.BreakArray
|
|
41 | +import GHC.HsToCore.Breakpoints
|
|
42 | +import GHC.ByteCode.Breakpoints
|
|
38 | 43 | import GHCi.Message
|
39 | 44 | import GHCi.RemoteTypes
|
40 | 45 | import GHCi.FFI
|
... | ... | @@ -42,12 +47,9 @@ import Control.DeepSeq |
42 | 47 | import GHCi.ResolvedBCO ( BCOByteArray(..), mkBCOByteArray )
|
43 | 48 | |
44 | 49 | import Foreign
|
45 | -import Data.Array
|
|
46 | 50 | import Data.ByteString (ByteString)
|
47 | -import Data.IntMap (IntMap)
|
|
48 | 51 | import qualified GHC.Exts.Heap as Heap
|
49 | 52 | import GHC.Cmm.Expr ( GlobalRegSet, emptyRegSet, regSetToList )
|
50 | -import GHC.Iface.Syntax
|
|
51 | 53 | import GHC.Unit.Module
|
52 | 54 | |
53 | 55 | -- -----------------------------------------------------------------------------
|
... | ... | @@ -63,8 +65,12 @@ data CompiledByteCode = CompiledByteCode |
63 | 65 | , bc_strs :: [(Name, ByteString)]
|
64 | 66 | -- ^ top-level strings (heap allocated)
|
65 | 67 | |
66 | - , bc_breaks :: Maybe ModBreaks
|
|
67 | - -- ^ breakpoint info (Nothing if breakpoints are disabled)
|
|
68 | + , bc_breaks :: Maybe InternalModBreaks
|
|
69 | + -- ^ All breakpoint information (no information if breakpoints are disabled).
|
|
70 | + --
|
|
71 | + -- This information is used when loading a bytecode object: we will
|
|
72 | + -- construct the arrays to be used at runtime to trigger breakpoints at load time
|
|
73 | + -- from it (in 'allocateBreakArrays' and 'allocateCCS' in 'GHC.ByteCode.Loader').
|
|
68 | 74 | |
69 | 75 | , bc_spt_entries :: ![SptEntry]
|
70 | 76 | -- ^ Static pointer table entries which should be loaded along with the
|
... | ... | @@ -86,7 +92,9 @@ seqCompiledByteCode CompiledByteCode{..} = |
86 | 92 | rnf bc_bcos `seq`
|
87 | 93 | rnf bc_itbls `seq`
|
88 | 94 | rnf bc_strs `seq`
|
89 | - rnf (fmap seqModBreaks bc_breaks)
|
|
95 | + case bc_breaks of
|
|
96 | + Nothing -> ()
|
|
97 | + Just ibks -> seqInternalModBreaks ibks
|
|
90 | 98 | |
91 | 99 | newtype ByteOff = ByteOff Int
|
92 | 100 | deriving (Enum, Eq, Show, Integral, Num, Ord, Real, Outputable)
|
... | ... | @@ -276,87 +284,15 @@ data BCONPtr |
276 | 284 | | BCONPtrFS !FastString
|
277 | 285 | -- | A libffi ffi_cif function prototype.
|
278 | 286 | | BCONPtrFFIInfo !FFIInfo
|
279 | - -- | A 'CostCentre' remote pointer array's respective 'Module' and index.
|
|
280 | - | BCONPtrCostCentre !Module !BreakIndex
|
|
287 | + -- | A 'CostCentre' remote pointer array's respective 'BreakpointId'
|
|
288 | + | BCONPtrCostCentre !BreakpointId
|
|
281 | 289 | |
282 | 290 | instance NFData BCONPtr where
|
283 | 291 | rnf x = x `seq` ()
|
284 | 292 | |
285 | --- | Information about a breakpoint that we know at code-generation time
|
|
286 | --- In order to be used, this needs to be hydrated relative to the current HscEnv by
|
|
287 | --- 'hydrateCgBreakInfo'. Everything here can be fully forced and that's critical for
|
|
288 | --- preventing space leaks (see #22530)
|
|
289 | -data CgBreakInfo
|
|
290 | - = CgBreakInfo
|
|
291 | - { cgb_tyvars :: ![IfaceTvBndr] -- ^ Type variables in scope at the breakpoint
|
|
292 | - , cgb_vars :: ![Maybe (IfaceIdBndr, Word)]
|
|
293 | - , cgb_resty :: !IfaceType
|
|
294 | - }
|
|
295 | --- See Note [Syncing breakpoint info] in GHC.Runtime.Eval
|
|
296 | - |
|
297 | -seqCgBreakInfo :: CgBreakInfo -> ()
|
|
298 | -seqCgBreakInfo CgBreakInfo{..} =
|
|
299 | - rnf cgb_tyvars `seq`
|
|
300 | - rnf cgb_vars `seq`
|
|
301 | - rnf cgb_resty
|
|
302 | - |
|
303 | 293 | instance Outputable UnlinkedBCO where
|
304 | 294 | ppr (UnlinkedBCO nm _arity _insns _bitmap lits ptrs)
|
305 | 295 | = sep [text "BCO", ppr nm, text "with",
|
306 | 296 | ppr (sizeFlatBag lits), text "lits",
|
307 | 297 | ppr (sizeFlatBag ptrs), text "ptrs" ]
|
308 | 298 | |
309 | -instance Outputable CgBreakInfo where
|
|
310 | - ppr info = text "CgBreakInfo" <+>
|
|
311 | - parens (ppr (cgb_vars info) <+>
|
|
312 | - ppr (cgb_resty info))
|
|
313 | - |
|
314 | --- -----------------------------------------------------------------------------
|
|
315 | --- Breakpoints
|
|
316 | - |
|
317 | --- | Breakpoint index
|
|
318 | -type BreakIndex = Int
|
|
319 | - |
|
320 | --- | C CostCentre type
|
|
321 | -data CCostCentre
|
|
322 | - |
|
323 | --- | All the information about the breakpoints for a module
|
|
324 | -data ModBreaks
|
|
325 | - = ModBreaks
|
|
326 | - { modBreaks_flags :: ForeignRef BreakArray
|
|
327 | - -- ^ The array of flags, one per breakpoint,
|
|
328 | - -- indicating which breakpoints are enabled.
|
|
329 | - , modBreaks_locs :: !(Array BreakIndex SrcSpan)
|
|
330 | - -- ^ An array giving the source span of each breakpoint.
|
|
331 | - , modBreaks_vars :: !(Array BreakIndex [OccName])
|
|
332 | - -- ^ An array giving the names of the free variables at each breakpoint.
|
|
333 | - , modBreaks_decls :: !(Array BreakIndex [String])
|
|
334 | - -- ^ An array giving the names of the declarations enclosing each breakpoint.
|
|
335 | - -- See Note [Field modBreaks_decls]
|
|
336 | - , modBreaks_ccs :: !(Array BreakIndex (String, String))
|
|
337 | - -- ^ Array pointing to cost centre info for each breakpoint;
|
|
338 | - -- actual 'CostCentre' allocation is done at link-time.
|
|
339 | - , modBreaks_breakInfo :: !(IntMap CgBreakInfo)
|
|
340 | - -- ^ info about each breakpoint from the bytecode generator
|
|
341 | - , modBreaks_module :: !Module
|
|
342 | - -- ^ info about the module in which we are setting the breakpoint
|
|
343 | - }
|
|
344 | - |
|
345 | -seqModBreaks :: ModBreaks -> ()
|
|
346 | -seqModBreaks ModBreaks{..} =
|
|
347 | - rnf modBreaks_flags `seq`
|
|
348 | - rnf modBreaks_locs `seq`
|
|
349 | - rnf modBreaks_vars `seq`
|
|
350 | - rnf modBreaks_decls `seq`
|
|
351 | - rnf modBreaks_ccs `seq`
|
|
352 | - rnf (fmap seqCgBreakInfo modBreaks_breakInfo) `seq`
|
|
353 | - rnf modBreaks_module
|
|
354 | - |
|
355 | -{-
|
|
356 | -Note [Field modBreaks_decls]
|
|
357 | -~~~~~~~~~~~~~~~~~~~~~~
|
|
358 | -A value of eg ["foo", "bar", "baz"] in a `modBreaks_decls` field means:
|
|
359 | -The breakpoint is in the function called "baz" that is declared in a `let`
|
|
360 | -or `where` clause of a declaration called "bar", which itself is declared
|
|
361 | -in a `let` or `where` clause of the top-level function called "foo".
|
|
362 | --} |
... | ... | @@ -31,7 +31,6 @@ import GHC.Prelude |
31 | 31 | |
32 | 32 | import GHC.Core
|
33 | 33 | import GHC.Core.Stats (exprStats)
|
34 | -import GHC.Types.Breakpoint
|
|
35 | 34 | import GHC.Types.Fixity (LexicalFixity(..))
|
36 | 35 | import GHC.Types.Literal( pprLiteral )
|
37 | 36 | import GHC.Types.Name( pprInfixName, pprPrefixName )
|
... | ... | @@ -91,7 +91,7 @@ data ModuleInfo = ModuleInfo { |
91 | 91 | minf_instances :: [ClsInst],
|
92 | 92 | minf_iface :: Maybe ModIface,
|
93 | 93 | minf_safe :: SafeHaskellMode,
|
94 | - minf_modBreaks :: Maybe ModBreaks
|
|
94 | + minf_modBreaks :: Maybe InternalModBreaks
|
|
95 | 95 | }
|
96 | 96 | -- We don't want HomeModInfo here, because a ModuleInfo applies
|
97 | 97 | -- to package modules too.
|
... | ... | @@ -196,6 +196,6 @@ modInfoIface = minf_iface |
196 | 196 | modInfoSafe :: ModuleInfo -> SafeHaskellMode
|
197 | 197 | modInfoSafe = minf_safe
|
198 | 198 | |
199 | -modInfoModBreaks :: ModuleInfo -> Maybe ModBreaks
|
|
199 | +modInfoModBreaks :: ModuleInfo -> Maybe InternalModBreaks
|
|
200 | 200 | modInfoModBreaks = minf_modBreaks
|
201 | 201 |
... | ... | @@ -97,8 +97,8 @@ import GHC.Unit.Module.Deps |
97 | 97 | |
98 | 98 | import Data.List (partition)
|
99 | 99 | import Data.IORef
|
100 | -import Data.Traversable (for)
|
|
101 | 100 | import GHC.Iface.Make (mkRecompUsageInfo)
|
101 | +import GHC.Runtime.Interpreter (interpreterProfiled)
|
|
102 | 102 | |
103 | 103 | {-
|
104 | 104 | ************************************************************************
|
... | ... | @@ -162,13 +162,12 @@ deSugar hsc_env |
162 | 162 | mod mod_loc
|
163 | 163 | export_set (typeEnvTyCons type_env) binds
|
164 | 164 | else return (binds, Nothing)
|
165 | - ; modBreaks <- for
|
|
166 | - [ (i, s)
|
|
167 | - | i <- hsc_interp hsc_env
|
|
168 | - , (_, s) <- m_tickInfo
|
|
169 | - , breakpointsAllowed dflags
|
|
170 | - ]
|
|
171 | - $ \(interp, specs) -> mkModBreaks interp mod specs
|
|
165 | + ; let modBreaks
|
|
166 | + | Just (_, specs) <- m_tickInfo
|
|
167 | + , breakpointsAllowed dflags
|
|
168 | + = Just $ mkModBreaks (interpreterProfiled $ hscInterp hsc_env) mod specs
|
|
169 | + | otherwise
|
|
170 | + = Nothing
|
|
172 | 171 | |
173 | 172 | ; ds_hpc_info <- case m_tickInfo of
|
174 | 173 | Just (orig_file2, ticks)
|
1 | 1 | {-# LANGUAGE RecordWildCards #-}
|
2 | 2 | |
3 | +-- | Information attached to Breakpoints generated from Ticks
|
|
4 | +--
|
|
5 | +-- The breakpoint information stored in 'ModBreaks' is generated during
|
|
6 | +-- desugaring from the ticks annotating the source expressions.
|
|
7 | +--
|
|
8 | +-- This information can be queried per-breakpoint using the 'BreakpointId'
|
|
9 | +-- datatype, which indexes tick-level breakpoint information.
|
|
10 | +--
|
|
11 | +-- 'ModBreaks' and 'BreakpointId's are not to be confused with
|
|
12 | +-- 'InternalModBreaks' and 'InternalBreakId's. The latter are constructed
|
|
13 | +-- during bytecode generation and can be found in 'GHC.ByteCode.Breakpoints'.
|
|
14 | +--
|
|
15 | +-- See Note [Breakpoint identifiers]
|
|
3 | 16 | module GHC.HsToCore.Breakpoints
|
4 | - ( mkModBreaks,
|
|
5 | - hydrateModBreaks
|
|
17 | + ( -- * ModBreaks
|
|
18 | + mkModBreaks, ModBreaks(..)
|
|
19 | + |
|
20 | + -- ** Re-exports BreakpointId
|
|
21 | + , BreakpointId(..), BreakTickIndex
|
|
6 | 22 | ) where
|
7 | 23 | |
8 | 24 | import GHC.Prelude
|
9 | - |
|
10 | -import qualified GHC.Runtime.Interpreter as GHCi
|
|
11 | -import GHC.Runtime.Interpreter
|
|
12 | -import GHC.ByteCode.Types
|
|
13 | -import GHC.Unit
|
|
25 | +import Data.Array
|
|
14 | 26 | |
15 | 27 | import GHC.HsToCore.Ticks (Tick (..))
|
16 | - |
|
17 | 28 | import GHC.Data.SizedSeq
|
18 | -import GHC.Utils.Outputable as Outputable
|
|
19 | - |
|
29 | +import GHC.Types.SrcLoc (SrcSpan)
|
|
30 | +import GHC.Types.Name (OccName)
|
|
31 | +import GHC.Types.Tickish (BreakTickIndex, BreakpointId(..))
|
|
32 | +import GHC.Unit.Module (Module)
|
|
33 | +import GHC.Utils.Outputable
|
|
20 | 34 | import Data.List (intersperse)
|
21 | -import Data.Array
|
|
22 | -import Data.Array.Base (numElements)
|
|
23 | -import qualified Data.IntMap as IntMap
|
|
35 | + |
|
36 | +--------------------------------------------------------------------------------
|
|
37 | +-- ModBreaks
|
|
38 | +--------------------------------------------------------------------------------
|
|
39 | + |
|
40 | +-- | All the information about the source-relevant breakpoints for a module
|
|
41 | +--
|
|
42 | +-- This information is constructed once during desugaring (with `mkModBreaks`)
|
|
43 | +-- from breakpoint ticks and fixed/unchanged from there on forward. It could be
|
|
44 | +-- exported as an abstract datatype because it should never be updated after
|
|
45 | +-- construction, only queried.
|
|
46 | +--
|
|
47 | +-- The arrays can be indexed using the int in the corresponding 'BreakpointId'
|
|
48 | +-- (i.e. the 'BreakpointId' whose 'Module' matches the 'Module' corresponding
|
|
49 | +-- to these 'ModBreaks') with the accessors 'modBreaks_locs', 'modBreaks_vars',
|
|
50 | +-- and 'modBreaks_decls'.
|
|
51 | +data ModBreaks
|
|
52 | + = ModBreaks
|
|
53 | + { modBreaks_locs :: !(Array BreakTickIndex SrcSpan)
|
|
54 | + -- ^ An array giving the source span of each breakpoint.
|
|
55 | + , modBreaks_vars :: !(Array BreakTickIndex [OccName])
|
|
56 | + -- ^ An array giving the names of the free variables at each breakpoint.
|
|
57 | + , modBreaks_decls :: !(Array BreakTickIndex [String])
|
|
58 | + -- ^ An array giving the names of the declarations enclosing each breakpoint.
|
|
59 | + -- See Note [Field modBreaks_decls]
|
|
60 | + , modBreaks_ccs :: !(Array BreakTickIndex (String, String))
|
|
61 | + -- ^ Array pointing to cost centre info for each breakpoint;
|
|
62 | + -- actual 'CostCentre' allocation is done at link-time.
|
|
63 | + , modBreaks_module :: !Module
|
|
64 | + -- ^ The module to which this ModBreaks is associated.
|
|
65 | + -- We also cache this here for internal sanity checks.
|
|
66 | + }
|
|
24 | 67 | |
25 | 68 | -- | Initialize memory for breakpoint data that is shared between the bytecode
|
26 | 69 | -- generator and the interpreter.
|
... | ... | @@ -29,38 +72,37 @@ import qualified Data.IntMap as IntMap |
29 | 72 | -- generator needs to encode this information for each expression, the data is
|
30 | 73 | -- allocated remotely in GHCi's address space and passed to the codegen as
|
31 | 74 | -- foreign pointers.
|
32 | -mkModBreaks :: Interp -> Module -> SizedSeq Tick -> IO ModBreaks
|
|
33 | -mkModBreaks interp mod extendedMixEntries
|
|
34 | - = do
|
|
35 | - let count = fromIntegral $ sizeSS extendedMixEntries
|
|
75 | +mkModBreaks :: Bool {-^ Whether the interpreter is profiled and thus if we should include store a CCS array -}
|
|
76 | + -> Module -> SizedSeq Tick -> ModBreaks
|
|
77 | +mkModBreaks interpreterProfiled modl extendedMixEntries
|
|
78 | + = let count = fromIntegral $ sizeSS extendedMixEntries
|
|
36 | 79 | entries = ssElts extendedMixEntries
|
37 | - let
|
|
38 | - locsTicks = listArray (0,count-1) [ tick_loc t | t <- entries ]
|
|
39 | - varsTicks = listArray (0,count-1) [ tick_ids t | t <- entries ]
|
|
40 | - declsTicks = listArray (0,count-1) [ tick_path t | t <- entries ]
|
|
41 | - ccs
|
|
42 | - | interpreterProfiled interp =
|
|
43 | - listArray
|
|
44 | - (0, count - 1)
|
|
45 | - [ ( concat $ intersperse "." $ tick_path t,
|
|
46 | - renderWithContext defaultSDocContext $ ppr $ tick_loc t
|
|
47 | - )
|
|
48 | - | t <- entries
|
|
49 | - ]
|
|
50 | - | otherwise = listArray (0, -1) []
|
|
51 | - hydrateModBreaks interp $
|
|
52 | - ModBreaks
|
|
53 | - { modBreaks_flags = undefined,
|
|
54 | - modBreaks_locs = locsTicks,
|
|
55 | - modBreaks_vars = varsTicks,
|
|
56 | - modBreaks_decls = declsTicks,
|
|
57 | - modBreaks_ccs = ccs,
|
|
58 | - modBreaks_breakInfo = IntMap.empty,
|
|
59 | - modBreaks_module = mod
|
|
60 | - }
|
|
80 | + locsTicks = listArray (0,count-1) [ tick_loc t | t <- entries ]
|
|
81 | + varsTicks = listArray (0,count-1) [ tick_ids t | t <- entries ]
|
|
82 | + declsTicks = listArray (0,count-1) [ tick_path t | t <- entries ]
|
|
83 | + ccs
|
|
84 | + | interpreterProfiled =
|
|
85 | + listArray
|
|
86 | + (0, count - 1)
|
|
87 | + [ ( concat $ intersperse "." $ tick_path t,
|
|
88 | + renderWithContext defaultSDocContext $ ppr $ tick_loc t
|
|
89 | + )
|
|
90 | + | t <- entries
|
|
91 | + ]
|
|
92 | + | otherwise = listArray (0, -1) []
|
|
93 | + in ModBreaks
|
|
94 | + { modBreaks_locs = locsTicks
|
|
95 | + , modBreaks_vars = varsTicks
|
|
96 | + , modBreaks_decls = declsTicks
|
|
97 | + , modBreaks_ccs = ccs
|
|
98 | + , modBreaks_module = modl
|
|
99 | + }
|
|
61 | 100 | |
62 | -hydrateModBreaks :: Interp -> ModBreaks -> IO ModBreaks
|
|
63 | -hydrateModBreaks interp ModBreaks {..} = do
|
|
64 | - let count = numElements modBreaks_locs
|
|
65 | - modBreaks_flags <- GHCi.newBreakArray interp count
|
|
66 | - pure ModBreaks {..} |
|
101 | +{-
|
|
102 | +Note [Field modBreaks_decls]
|
|
103 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
104 | +A value of eg ["foo", "bar", "baz"] in a `modBreaks_decls` field means:
|
|
105 | +The breakpoint is in the function called "baz" that is declared in a `let`
|
|
106 | +or `where` clause of a declaration called "bar", which itself is declared
|
|
107 | +in a `let` or `where` clause of the top-level function called "foo".
|
|
108 | +-} |
... | ... | @@ -34,7 +34,6 @@ import GHC.Driver.Flags (DumpFlag(..)) |
34 | 34 | import GHC.Utils.Outputable as Outputable
|
35 | 35 | import GHC.Utils.Panic
|
36 | 36 | import GHC.Utils.Logger
|
37 | -import GHC.Types.Breakpoint
|
|
38 | 37 | import GHC.Types.SrcLoc
|
39 | 38 | import GHC.Types.Basic
|
40 | 39 | import GHC.Types.Id
|
... | ... | @@ -56,7 +56,6 @@ import GHC.Data.BooleanFormula (pprBooleanFormula, isTrue) |
56 | 56 | |
57 | 57 | import GHC.Builtin.Names ( unrestrictedFunTyConKey, liftedTypeKindTyConKey,
|
58 | 58 | constraintKindTyConKey )
|
59 | -import GHC.Types.Breakpoint
|
|
60 | 59 | import GHC.Types.Unique ( hasKey )
|
61 | 60 | import GHC.Iface.Type
|
62 | 61 | import GHC.Iface.Recomp.Binary
|
... | ... | @@ -75,6 +74,7 @@ import GHC.Types.Avail |
75 | 74 | import GHC.Types.ForeignCall
|
76 | 75 | import GHC.Types.Annotations( AnnPayload, AnnTarget )
|
77 | 76 | import GHC.Types.Basic
|
77 | +import GHC.Types.Tickish
|
|
78 | 78 | import GHC.Unit.Module
|
79 | 79 | import GHC.Unit.Module.Warnings
|
80 | 80 | import GHC.Types.SrcLoc
|
... | ... | @@ -28,6 +28,7 @@ module GHC.Linker.Loader |
28 | 28 | , extendLoadedEnv
|
29 | 29 | , deleteFromLoadedEnv
|
30 | 30 | -- * Internals
|
31 | + , allocateBreakArrays
|
|
31 | 32 | , rmDupLinkables
|
32 | 33 | , modifyLoaderState
|
33 | 34 | , initLinkDepsOpts
|
... | ... | @@ -122,8 +123,8 @@ import System.Win32.Info (getSystemDirectory) |
122 | 123 | import GHC.Utils.Exception
|
123 | 124 | import GHC.Unit.Home.Graph (lookupHug, unitEnv_foldWithKey)
|
124 | 125 | import GHC.Driver.Downsweep
|
125 | - |
|
126 | - |
|
126 | +import qualified GHC.Runtime.Interpreter as GHCi
|
|
127 | +import Data.Array.Base (numElements)
|
|
127 | 128 | |
128 | 129 | -- Note [Linkers and loaders]
|
129 | 130 | -- ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
... | ... | @@ -696,16 +697,8 @@ loadDecls interp hsc_env span linkable = do |
696 | 697 | let le = linker_env pls
|
697 | 698 | le2_itbl_env <- linkITbls interp (itbl_env le) (concat $ map bc_itbls cbcs)
|
698 | 699 | le2_addr_env <- foldlM (\env cbc -> allocateTopStrings interp (bc_strs cbc) env) (addr_env le) cbcs
|
699 | - le2_breakarray_env <-
|
|
700 | - allocateBreakArrays
|
|
701 | - interp
|
|
702 | - (catMaybes $ map bc_breaks cbcs)
|
|
703 | - (breakarray_env le)
|
|
704 | - le2_ccs_env <-
|
|
705 | - allocateCCS
|
|
706 | - interp
|
|
707 | - (catMaybes $ map bc_breaks cbcs)
|
|
708 | - (ccs_env le)
|
|
700 | + le2_breakarray_env <- allocateBreakArrays interp (breakarray_env le) (catMaybes $ map bc_breaks cbcs)
|
|
701 | + le2_ccs_env <- allocateCCS interp (ccs_env le) (catMaybes $ map bc_breaks cbcs)
|
|
709 | 702 | let le2 = le { itbl_env = le2_itbl_env
|
710 | 703 | , addr_env = le2_addr_env
|
711 | 704 | , breakarray_env = le2_breakarray_env
|
... | ... | @@ -933,12 +926,8 @@ dynLinkBCOs interp pls bcos = do |
933 | 926 | le1 = linker_env pls
|
934 | 927 | ie2 <- linkITbls interp (itbl_env le1) (concatMap bc_itbls cbcs)
|
935 | 928 | ae2 <- foldlM (\env cbc -> allocateTopStrings interp (bc_strs cbc) env) (addr_env le1) cbcs
|
936 | - be2 <-
|
|
937 | - allocateBreakArrays
|
|
938 | - interp
|
|
939 | - (catMaybes $ map bc_breaks cbcs)
|
|
940 | - (breakarray_env le1)
|
|
941 | - ce2 <- allocateCCS interp (catMaybes $ map bc_breaks cbcs) (ccs_env le1)
|
|
929 | + be2 <- allocateBreakArrays interp (breakarray_env le1) (catMaybes $ map bc_breaks cbcs)
|
|
930 | + ce2 <- allocateCCS interp (ccs_env le1) (catMaybes $ map bc_breaks cbcs)
|
|
942 | 931 | let le2 = le1 { itbl_env = ie2, addr_env = ae2, breakarray_env = be2, ccs_env = ce2 }
|
943 | 932 | |
944 | 933 | names_and_refs <- linkSomeBCOs interp (pkgs_loaded pls) le2 cbcs
|
... | ... | @@ -1656,44 +1645,51 @@ allocateTopStrings interp topStrings prev_env = do |
1656 | 1645 | where
|
1657 | 1646 | mk_entry nm ptr = (nm, (nm, AddrPtr ptr))
|
1658 | 1647 | |
1659 | --- | Given a list of 'ModBreaks' collected from a list of
|
|
1660 | --- 'CompiledByteCode', allocate the 'BreakArray'.
|
|
1648 | +-- | Given a list of 'InternalModBreaks' collected from a list of
|
|
1649 | +-- 'CompiledByteCode', allocate the 'BreakArray' used to trigger breakpoints.
|
|
1661 | 1650 | allocateBreakArrays ::
|
1662 | 1651 | Interp ->
|
1663 | - [ModBreaks] ->
|
|
1664 | 1652 | ModuleEnv (ForeignRef BreakArray) ->
|
1653 | + [InternalModBreaks] ->
|
|
1665 | 1654 | IO (ModuleEnv (ForeignRef BreakArray))
|
1666 | -allocateBreakArrays _interp mbs be =
|
|
1655 | +allocateBreakArrays interp =
|
|
1667 | 1656 | foldlM
|
1668 | - ( \be0 ModBreaks {..} ->
|
|
1669 | - evaluate $ extendModuleEnv be0 modBreaks_module modBreaks_flags
|
|
1657 | + ( \be0 InternalModBreaks{imodBreaks_modBreaks=ModBreaks {..}} -> do
|
|
1658 | + -- If no BreakArray is assigned to this module yet, create one
|
|
1659 | + if not $ elemModuleEnv modBreaks_module be0 then do
|
|
1660 | + let count = numElements modBreaks_locs
|
|
1661 | + breakArray <- GHCi.newBreakArray interp count
|
|
1662 | + evaluate $ extendModuleEnv be0 modBreaks_module breakArray
|
|
1663 | + else
|
|
1664 | + return be0
|
|
1670 | 1665 | )
|
1671 | - be
|
|
1672 | - mbs
|
|
1673 | 1666 | |
1674 | --- | Given a list of 'ModBreaks' collected from a list of
|
|
1675 | --- 'CompiledByteCode', allocate the 'CostCentre' arrays when profiling
|
|
1676 | --- is enabled.
|
|
1667 | +-- | Given a list of 'InternalModBreaks' collected from a list
|
|
1668 | +-- of 'CompiledByteCode', allocate the 'CostCentre' arrays when profiling is
|
|
1669 | +-- enabled.
|
|
1677 | 1670 | allocateCCS ::
|
1678 | 1671 | Interp ->
|
1679 | - [ModBreaks] ->
|
|
1680 | - ModuleEnv (Array BreakIndex (RemotePtr CostCentre)) ->
|
|
1681 | - IO (ModuleEnv (Array BreakIndex (RemotePtr CostCentre)))
|
|
1682 | -allocateCCS interp mbs ce
|
|
1672 | + ModuleEnv (Array BreakTickIndex (RemotePtr CostCentre)) ->
|
|
1673 | + [InternalModBreaks] ->
|
|
1674 | + IO (ModuleEnv (Array BreakTickIndex (RemotePtr CostCentre)))
|
|
1675 | +allocateCCS interp ce mbss
|
|
1683 | 1676 | | interpreterProfiled interp =
|
1684 | 1677 | foldlM
|
1685 | - ( \ce0 ModBreaks {..} -> do
|
|
1678 | + ( \ce0 InternalModBreaks{imodBreaks_modBreaks=ModBreaks {..}} -> do
|
|
1686 | 1679 | ccs <-
|
1687 | 1680 | mkCostCentres
|
1688 | 1681 | interp
|
1689 | 1682 | (moduleNameString $ moduleName modBreaks_module)
|
1690 | 1683 | (elems modBreaks_ccs)
|
1691 | - evaluate $
|
|
1692 | - extendModuleEnv ce0 modBreaks_module $
|
|
1693 | - listArray
|
|
1694 | - (0, length ccs - 1)
|
|
1695 | - ccs
|
|
1684 | + if not $ elemModuleEnv modBreaks_module ce0 then do
|
|
1685 | + evaluate $
|
|
1686 | + extendModuleEnv ce0 modBreaks_module $
|
|
1687 | + listArray
|
|
1688 | + (0, length ccs - 1)
|
|
1689 | + ccs
|
|
1690 | + else
|
|
1691 | + return ce0
|
|
1696 | 1692 | )
|
1697 | 1693 | ce
|
1698 | - mbs
|
|
1694 | + mbss
|
|
1699 | 1695 | | otherwise = pure ce |
... | ... | @@ -188,7 +188,7 @@ data LinkerEnv = LinkerEnv |
188 | 188 | , breakarray_env :: !(ModuleEnv (ForeignRef BreakArray))
|
189 | 189 | -- ^ Each 'Module's remote pointer of 'BreakArray'.
|
190 | 190 | |
191 | - , ccs_env :: !(ModuleEnv (Array BreakIndex (RemotePtr CostCentre)))
|
|
191 | + , ccs_env :: !(ModuleEnv (Array BreakTickIndex (RemotePtr CostCentre)))
|
|
192 | 192 | -- ^ Each 'Module's array of remote pointers of 'CostCentre'.
|
193 | 193 | -- Untouched when not profiling.
|
194 | 194 | }
|
... | ... | @@ -16,7 +16,8 @@ import Data.Maybe |
16 | 16 | import qualified Data.List.NonEmpty as NE
|
17 | 17 | import qualified Data.Semigroup as S
|
18 | 18 | |
19 | -import GHC.ByteCode.Types (BreakIndex, ModBreaks(..))
|
|
19 | +import GHC.HsToCore.Breakpoints
|
|
20 | +import GHC.ByteCode.Breakpoints
|
|
20 | 21 | import GHC.Driver.Env
|
21 | 22 | import GHC.Driver.Monad
|
22 | 23 | import GHC.Driver.Session.Inspect
|
... | ... | @@ -24,7 +25,6 @@ import GHC.Runtime.Eval |
24 | 25 | import GHC.Runtime.Eval.Utils
|
25 | 26 | import GHC.Types.Name
|
26 | 27 | import GHC.Types.SrcLoc
|
27 | -import GHC.Types.Breakpoint
|
|
28 | 28 | import GHC.Unit.Module
|
29 | 29 | import GHC.Unit.Module.Graph
|
30 | 30 | import GHC.Unit.Module.ModSummary
|
... | ... | @@ -44,7 +44,7 @@ import qualified GHC.Data.Strict as Strict |
44 | 44 | -- - the leftmost subexpression starting on the specified line, or
|
45 | 45 | -- - the rightmost subexpression enclosing the specified line
|
46 | 46 | --
|
47 | -findBreakByLine :: Int {-^ Line number -} -> TickArray -> Maybe (BreakIndex, RealSrcSpan)
|
|
47 | +findBreakByLine :: Int {-^ Line number -} -> TickArray -> Maybe (BreakTickIndex, RealSrcSpan)
|
|
48 | 48 | findBreakByLine line arr
|
49 | 49 | | not (inRange (bounds arr) line) = Nothing
|
50 | 50 | | otherwise =
|
... | ... | @@ -61,7 +61,7 @@ findBreakByLine line arr |
61 | 61 | where ends_here (_,pan) = srcSpanEndLine pan == line
|
62 | 62 | |
63 | 63 | -- | Find a breakpoint in the 'TickArray' of a module, given a line number and a column coordinate.
|
64 | -findBreakByCoord :: (Int, Int) -> TickArray -> Maybe (BreakIndex, RealSrcSpan)
|
|
64 | +findBreakByCoord :: (Int, Int) -> TickArray -> Maybe (BreakTickIndex, RealSrcSpan)
|
|
65 | 65 | findBreakByCoord (line, col) arr
|
66 | 66 | | not (inRange (bounds arr) line) = Nothing
|
67 | 67 | | otherwise =
|
... | ... | @@ -174,7 +174,7 @@ resolveFunctionBreakpoint inp = do |
174 | 174 | -- for
|
175 | 175 | -- (a) this binder only (it maybe a top-level or a nested declaration)
|
176 | 176 | -- (b) that do not have an enclosing breakpoint
|
177 | -findBreakForBind :: String {-^ Name of bind to break at -} -> ModBreaks -> [(BreakIndex, RealSrcSpan)]
|
|
177 | +findBreakForBind :: String {-^ Name of bind to break at -} -> ModBreaks -> [(BreakTickIndex, RealSrcSpan)]
|
|
178 | 178 | findBreakForBind str_name modbreaks = filter (not . enclosed) ticks
|
179 | 179 | where
|
180 | 180 | ticks = [ (index, span)
|
... | ... | @@ -191,15 +191,15 @@ findBreakForBind str_name modbreaks = filter (not . enclosed) ticks |
191 | 191 | --------------------------------------------------------------------------------
|
192 | 192 | |
193 | 193 | -- | Maps line numbers to the breakpoint ticks existing at that line for a module.
|
194 | -type TickArray = Array Int [(BreakIndex,RealSrcSpan)]
|
|
194 | +type TickArray = Array Int [(BreakTickIndex,RealSrcSpan)]
|
|
195 | 195 | |
196 | 196 | -- | Construct the 'TickArray' for the given module.
|
197 | 197 | makeModuleLineMap :: GhcMonad m => Module -> m (Maybe TickArray)
|
198 | 198 | makeModuleLineMap m = do
|
199 | 199 | mi <- getModuleInfo m
|
200 | - return $ mkTickArray . assocs . modBreaks_locs <$> (modInfoModBreaks =<< mi)
|
|
200 | + return $ mkTickArray . assocs . modBreaks_locs . imodBreaks_modBreaks <$> (modInfoModBreaks =<< mi)
|
|
201 | 201 | where
|
202 | - mkTickArray :: [(BreakIndex, SrcSpan)] -> TickArray
|
|
202 | + mkTickArray :: [(BreakTickIndex, SrcSpan)] -> TickArray
|
|
203 | 203 | mkTickArray ticks
|
204 | 204 | = accumArray (flip (:)) [] (1, max_line)
|
205 | 205 | [ (line, (nm,pan)) | (nm,RealSrcSpan pan _) <- ticks, line <- srcSpanLines pan ]
|
... | ... | @@ -211,7 +211,7 @@ makeModuleLineMap m = do |
211 | 211 | getModBreak :: GhcMonad m => Module -> m (Maybe ModBreaks)
|
212 | 212 | getModBreak m = do
|
213 | 213 | mod_info <- fromMaybe (panic "getModBreak") <$> getModuleInfo m
|
214 | - pure $ modInfoModBreaks mod_info
|
|
214 | + pure $ imodBreaks_modBreaks <$> modInfoModBreaks mod_info
|
|
215 | 215 | |
216 | 216 | --------------------------------------------------------------------------------
|
217 | 217 | -- Getting current breakpoint information
|
... | ... | @@ -64,6 +64,7 @@ import GHCi.RemoteTypes |
64 | 64 | import GHC.ByteCode.Types
|
65 | 65 | |
66 | 66 | import GHC.Linker.Loader as Loader
|
67 | +import GHC.Linker.Types (LinkerEnv(..))
|
|
67 | 68 | |
68 | 69 | import GHC.Hs
|
69 | 70 | |
... | ... | @@ -111,7 +112,6 @@ import GHC.Types.Unique |
111 | 112 | import GHC.Types.Unique.Supply
|
112 | 113 | import GHC.Types.Unique.DSet
|
113 | 114 | import GHC.Types.TyThing
|
114 | -import GHC.Types.Breakpoint
|
|
115 | 115 | import GHC.Types.Unique.Map
|
116 | 116 | |
117 | 117 | import GHC.Types.Avail
|
... | ... | @@ -127,16 +127,16 @@ import GHC.Tc.Utils.Instantiate (instDFunType) |
127 | 127 | import GHC.Tc.Utils.Monad
|
128 | 128 | |
129 | 129 | import GHC.IfaceToCore
|
130 | +import GHC.ByteCode.Breakpoints
|
|
130 | 131 | |
131 | 132 | import Control.Monad
|
132 | -import Data.Array
|
|
133 | 133 | import Data.Dynamic
|
134 | 134 | import Data.IntMap (IntMap)
|
135 | -import qualified Data.IntMap as IntMap
|
|
136 | 135 | import Data.List (find,intercalate)
|
137 | 136 | import Data.List.NonEmpty (NonEmpty)
|
138 | 137 | import Unsafe.Coerce ( unsafeCoerce )
|
139 | 138 | import qualified GHC.Unit.Home.Graph as HUG
|
139 | +import GHCi.BreakArray (BreakArray)
|
|
140 | 140 | |
141 | 141 | -- -----------------------------------------------------------------------------
|
142 | 142 | -- running a statement interactively
|
... | ... | @@ -154,7 +154,7 @@ getHistorySpan :: HUG.HomeUnitGraph -> History -> IO SrcSpan |
154 | 154 | getHistorySpan hug hist = do
|
155 | 155 | let ibi = historyBreakpointId hist
|
156 | 156 | brks <- readModBreaks hug (ibi_tick_mod ibi)
|
157 | - return $ modBreaks_locs brks ! ibi_tick_index ibi
|
|
157 | + return $ getBreakLoc ibi brks
|
|
158 | 158 | |
159 | 159 | {- | Finds the enclosing top level function name -}
|
160 | 160 | -- ToDo: a better way to do this would be to keep hold of the decl_path computed
|
... | ... | @@ -163,7 +163,7 @@ getHistorySpan hug hist = do |
163 | 163 | findEnclosingDecls :: HUG.HomeUnitGraph -> InternalBreakpointId -> IO [String]
|
164 | 164 | findEnclosingDecls hug ibi = do
|
165 | 165 | brks <- readModBreaks hug (ibi_tick_mod ibi)
|
166 | - return $ modBreaks_decls brks ! ibi_tick_index ibi
|
|
166 | + return $ getBreakDecls ibi brks
|
|
167 | 167 | |
168 | 168 | -- | Update fixity environment in the current interactive context.
|
169 | 169 | updateFixityEnv :: GhcMonad m => FixityEnv -> m ()
|
... | ... | @@ -350,13 +350,14 @@ handleRunStatus step expr bindings final_ids status history0 = do |
350 | 350 | EvalBreak apStack_ref (Just eval_break) resume_ctxt ccs -> do
|
351 | 351 | let ibi = evalBreakpointToId eval_break
|
352 | 352 | let hug = hsc_HUG hsc_env
|
353 | - tick_brks <- liftIO $ readModBreaks hug (ibi_tick_mod ibi)
|
|
353 | + tick_brks <- liftIO $ readModBreaks hug (ibi_tick_mod ibi)
|
|
354 | + breakArray <- getBreakArray interp (toBreakpointId ibi) tick_brks
|
|
354 | 355 | let
|
355 | - span = modBreaks_locs tick_brks ! ibi_tick_index ibi
|
|
356 | - decl = intercalate "." $ modBreaks_decls tick_brks ! ibi_tick_index ibi
|
|
356 | + span = getBreakLoc ibi tick_brks
|
|
357 | + decl = intercalate "." $ getBreakDecls ibi tick_brks
|
|
357 | 358 | |
358 | 359 | -- Was this breakpoint explicitly enabled (ie. in @BreakArray@)?
|
359 | - bactive <- liftIO $ breakpointStatus interp (modBreaks_flags tick_brks) (ibi_tick_index ibi)
|
|
360 | + bactive <- liftIO $ breakpointStatus interp breakArray (ibi_tick_index ibi)
|
|
360 | 361 | |
361 | 362 | apStack_fhv <- liftIO $ mkFinalizedHValue interp apStack_ref
|
362 | 363 | resume_ctxt_fhv <- liftIO $ mkFinalizedHValue interp resume_ctxt
|
... | ... | @@ -464,9 +465,24 @@ setupBreakpoint :: GhcMonad m => Interp -> BreakpointId -> Int -> m () -- #191 |
464 | 465 | setupBreakpoint interp bi cnt = do
|
465 | 466 | hug <- hsc_HUG <$> getSession
|
466 | 467 | modBreaks <- liftIO $ readModBreaks hug (bi_tick_mod bi)
|
467 | - let breakarray = modBreaks_flags modBreaks
|
|
468 | - _ <- liftIO $ GHCi.storeBreakpoint interp breakarray (bi_tick_index bi) cnt
|
|
469 | - pure ()
|
|
468 | + breakArray <- getBreakArray interp bi modBreaks
|
|
469 | + liftIO $ GHCi.storeBreakpoint interp breakArray (bi_tick_index bi) cnt
|
|
470 | + |
|
471 | +getBreakArray :: GhcMonad m => Interp -> BreakpointId -> InternalModBreaks -> m (ForeignRef BreakArray)
|
|
472 | +getBreakArray interp BreakpointId{bi_tick_mod} imbs = do
|
|
473 | + |
|
474 | + liftIO $ modifyLoaderState interp $ \ld_st -> do
|
|
475 | + let le = linker_env ld_st
|
|
476 | + |
|
477 | + -- Recall that BreakArrays are allocated only at BCO link time, so if we
|
|
478 | + -- haven't linked the BCOs we intend to break at yet, we allocate the arrays here.
|
|
479 | + ba_env <- allocateBreakArrays interp (breakarray_env le) [imbs]
|
|
480 | + |
|
481 | + return
|
|
482 | + ( ld_st { linker_env = le{breakarray_env = ba_env} }
|
|
483 | + , expectJust {- just computed -} $
|
|
484 | + lookupModuleEnv ba_env bi_tick_mod
|
|
485 | + )
|
|
470 | 486 | |
471 | 487 | back :: GhcMonad m => Int -> m ([Name], Int, SrcSpan)
|
472 | 488 | back n = moveHist (+n)
|
... | ... | @@ -496,7 +512,7 @@ moveHist fn = do |
496 | 512 | Nothing -> return $ mkGeneralSrcSpan (fsLit "<unknown>")
|
497 | 513 | Just ibi -> liftIO $ do
|
498 | 514 | brks <- readModBreaks (hsc_HUG hsc_env) (ibi_tick_mod ibi)
|
499 | - return $ modBreaks_locs brks ! ibi_tick_index ibi
|
|
515 | + return $ getBreakLoc ibi brks
|
|
500 | 516 | (hsc_env1, names) <-
|
501 | 517 | liftIO $ bindLocalsAtBreakpoint hsc_env apStack span mb_info
|
502 | 518 | let ic = hsc_IC hsc_env1
|
... | ... | @@ -559,9 +575,9 @@ bindLocalsAtBreakpoint hsc_env apStack_fhv span (Just ibi) = do |
559 | 575 | let hug = hsc_HUG hsc_env
|
560 | 576 | info_brks <- readModBreaks hug (ibi_info_mod ibi)
|
561 | 577 | tick_brks <- readModBreaks hug (ibi_tick_mod ibi)
|
562 | - let info = expectJust $ IntMap.lookup (ibi_info_index ibi) (modBreaks_breakInfo info_brks)
|
|
578 | + let info = getInternalBreak ibi (info_brks)
|
|
563 | 579 | interp = hscInterp hsc_env
|
564 | - occs = modBreaks_vars tick_brks ! ibi_tick_index ibi
|
|
580 | + occs = getBreakVars ibi tick_brks
|
|
565 | 581 | |
566 | 582 | -- Rehydrate to understand the breakpoint info relative to the current environment.
|
567 | 583 | -- This design is critical to preventing leaks (#22530)
|
... | ... | @@ -17,11 +17,11 @@ import GHC.Prelude |
17 | 17 | |
18 | 18 | import GHCi.RemoteTypes
|
19 | 19 | import GHCi.Message (EvalExpr, ResumeContext)
|
20 | +import GHC.ByteCode.Types (InternalBreakpointId(..))
|
|
20 | 21 | import GHC.Driver.Config (EvalStep(..))
|
21 | 22 | import GHC.Types.Id
|
22 | 23 | import GHC.Types.Name
|
23 | 24 | import GHC.Types.TyThing
|
24 | -import GHC.Types.Breakpoint
|
|
25 | 25 | import GHC.Types.Name.Reader
|
26 | 26 | import GHC.Types.SrcLoc
|
27 | 27 | import GHC.Utils.Exception
|
... | ... | @@ -176,7 +176,7 @@ data Resume = Resume |
176 | 176 | , resumeApStack :: ForeignHValue -- The object from which we can get
|
177 | 177 | -- value of the free variables.
|
178 | 178 | , resumeBreakpointId :: Maybe InternalBreakpointId
|
179 | - -- ^ the breakpoint we stopped at
|
|
179 | + -- ^ the internal breakpoint we stopped at
|
|
180 | 180 | -- (Nothing <=> exception)
|
181 | 181 | , resumeSpan :: SrcSpan -- just a copy of the SrcSpan
|
182 | 182 | -- from the ModBreaks,
|
... | ... | @@ -74,9 +74,9 @@ import GHCi.Message |
74 | 74 | import GHCi.RemoteTypes
|
75 | 75 | import GHCi.ResolvedBCO
|
76 | 76 | import GHCi.BreakArray (BreakArray)
|
77 | -import GHC.Types.Breakpoint
|
|
78 | -import GHC.ByteCode.Types
|
|
77 | +import GHC.ByteCode.Breakpoints
|
|
79 | 78 | |
79 | +import GHC.ByteCode.Types
|
|
80 | 80 | import GHC.Linker.Types
|
81 | 81 | |
82 | 82 | import GHC.Data.Maybe
|
... | ... | @@ -105,7 +105,6 @@ import Control.Monad.IO.Class |
105 | 105 | import Control.Monad.Catch as MC (mask)
|
106 | 106 | import Data.Binary
|
107 | 107 | import Data.ByteString (ByteString)
|
108 | -import Data.Array ((!))
|
|
109 | 108 | import Foreign hiding (void)
|
110 | 109 | import qualified GHC.Exts.Heap as Heap
|
111 | 110 | import GHC.Stack.CCS (CostCentre,CostCentreStack)
|
... | ... | @@ -451,7 +450,7 @@ handleSeqHValueStatus interp unit_env eval_status = |
451 | 450 | -- Nothing case - should not occur! We should have the appropriate
|
452 | 451 | -- breakpoint information
|
453 | 452 | Nothing -> nothing_case
|
454 | - Just modbreaks -> put $ brackets . ppr $ (modBreaks_locs modbreaks) ! ibi_tick_index bi
|
|
453 | + Just modbreaks -> put $ brackets . ppr $ getBreakLoc bi modbreaks
|
|
455 | 454 | |
456 | 455 | -- resume the seq (:force) processing in the iserv process
|
457 | 456 | withForeignRef resume_ctxt_fhv $ \hval -> do
|
... | ... | @@ -737,7 +736,7 @@ wormholeRef interp _r = case interpInstance interp of |
737 | 736 | |
738 | 737 | -- | Get the breakpoint information from the ByteCode object associated to this
|
739 | 738 | -- 'HomeModInfo'.
|
740 | -getModBreaks :: HomeModInfo -> Maybe ModBreaks
|
|
739 | +getModBreaks :: HomeModInfo -> Maybe InternalModBreaks
|
|
741 | 740 | getModBreaks hmi
|
742 | 741 | | Just linkable <- homeModInfoByteCode hmi,
|
743 | 742 | -- The linkable may have 'DotO's as well; only consider BCOs. See #20570.
|
... | ... | @@ -748,7 +747,7 @@ getModBreaks hmi |
748 | 747 | |
749 | 748 | -- | Read the 'InternalModBreaks' and 'ModBreaks' of the given home 'Module'
|
750 | 749 | -- from the 'HomeUnitGraph'.
|
751 | -readModBreaks :: HomeUnitGraph -> Module -> IO ModBreaks
|
|
750 | +readModBreaks :: HomeUnitGraph -> Module -> IO InternalModBreaks
|
|
752 | 751 | readModBreaks hug modl = expectJust . getModBreaks . expectJust <$> HUG.lookupHugByModule modl hug
|
753 | 752 | |
754 | 753 | -- -----------------------------------------------------------------------------
|
... | ... | @@ -34,7 +34,6 @@ import GHC.Platform.Profile |
34 | 34 | import GHC.Runtime.Interpreter
|
35 | 35 | import GHCi.FFI
|
36 | 36 | import GHC.Types.Basic
|
37 | -import GHC.Types.Breakpoint
|
|
38 | 37 | import GHC.Utils.Outputable
|
39 | 38 | import GHC.Types.Name
|
40 | 39 | import GHC.Types.Id
|
... | ... | @@ -71,6 +70,7 @@ import GHC.Data.OrdList |
71 | 70 | import GHC.Data.Maybe
|
72 | 71 | import GHC.Types.Tickish
|
73 | 72 | import GHC.Types.SptEntry
|
73 | +import GHC.ByteCode.Breakpoints
|
|
74 | 74 | |
75 | 75 | import Data.List ( genericReplicate, intersperse
|
76 | 76 | , partition, scanl', sortBy, zip4, zip6 )
|
... | ... | @@ -134,9 +134,9 @@ byteCodeGen hsc_env this_mod binds tycs mb_modBreaks spt_entries |
134 | 134 | "Proto-BCOs" FormatByteCode
|
135 | 135 | (vcat (intersperse (char ' ') (map ppr $ elemsFlatBag proto_bcos)))
|
136 | 136 | |
137 | - let mod_breaks = case modBreaks of
|
|
137 | + let mod_breaks = case mb_modBreaks of
|
|
138 | 138 | Nothing -> Nothing
|
139 | - Just mb -> Just mb{ modBreaks_breakInfo = breakInfo }
|
|
139 | + Just mb -> Just $ mkInternalModBreaks this_mod breakInfo mb
|
|
140 | 140 | cbc <- assembleBCOs profile proto_bcos tycs strings mod_breaks spt_entries
|
141 | 141 | |
142 | 142 | -- Squash space leaks in the CompiledByteCode. This is really
|
... | ... | @@ -405,7 +405,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty (BreakpointId tick_mod tick_no) fv |
405 | 405 | Nothing -> pure code
|
406 | 406 | Just current_mod_breaks -> break_info hsc_env tick_mod current_mod mb_current_mod_breaks >>= \case
|
407 | 407 | Nothing -> pure code
|
408 | - Just ModBreaks {modBreaks_module = tick_mod} -> do
|
|
408 | + Just ModBreaks{modBreaks_module = tick_mod} -> do
|
|
409 | 409 | platform <- profilePlatform <$> getProfile
|
410 | 410 | let idOffSets = getVarOffSets platform d p fvs
|
411 | 411 | ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
|
... | ... | @@ -416,12 +416,7 @@ schemeER_wrk d p (StgTick (Breakpoint tick_ty (BreakpointId tick_mod tick_no) fv |
416 | 416 | let info_mod = modBreaks_module current_mod_breaks
|
417 | 417 | infox <- newBreakInfo breakInfo
|
418 | 418 | |
419 | - let -- cast that checks that round-tripping through Word16 doesn't change the value
|
|
420 | - toW16 x = let r = fromIntegral x :: Word16
|
|
421 | - in if fromIntegral r == x
|
|
422 | - then r
|
|
423 | - else pprPanic "schemeER_wrk: breakpoint tick/info index too large!" (ppr x)
|
|
424 | - breakInstr = BRK_FUN tick_mod (toW16 tick_no) info_mod (toW16 infox)
|
|
419 | + let breakInstr = BRK_FUN (InternalBreakpointId tick_mod tick_no info_mod infox)
|
|
425 | 420 | return $ breakInstr `consOL` code
|
426 | 421 | schemeER_wrk d p rhs = schemeE d 0 p rhs
|
427 | 422 | |
... | ... | @@ -455,7 +450,7 @@ break_info hsc_env mod current_mod current_mod_breaks |
455 | 450 | = pure current_mod_breaks
|
456 | 451 | | otherwise
|
457 | 452 | = liftIO (HUG.lookupHugByModule mod (hsc_HUG hsc_env)) >>= \case
|
458 | - Just hp -> pure $ getModBreaks hp
|
|
453 | + Just hp -> pure $ imodBreaks_modBreaks <$> getModBreaks hp
|
|
459 | 454 | Nothing -> pure Nothing
|
460 | 455 | |
461 | 456 | getVarOffSets :: Platform -> StackDepth -> BCEnv -> [Id] -> [Maybe (Id, WordOff)]
|
... | ... | @@ -2659,20 +2654,19 @@ typeArgReps platform = map (toArgRep platform) . typePrimRep |
2659 | 2654 | -- | Read only environment for generating ByteCode
|
2660 | 2655 | data BcM_Env
|
2661 | 2656 | = BcM_Env
|
2662 | - { bcm_hsc_env :: HscEnv
|
|
2663 | - , bcm_module :: Module -- current module (for breakpoints)
|
|
2657 | + { bcm_hsc_env :: !HscEnv
|
|
2658 | + , bcm_module :: !Module -- current module (for breakpoints)
|
|
2659 | + , modBreaks :: !(Maybe ModBreaks)
|
|
2664 | 2660 | }
|
2665 | 2661 | |
2666 | 2662 | data BcM_State
|
2667 | 2663 | = BcM_State
|
2668 | 2664 | { nextlabel :: !Word32 -- ^ For generating local labels
|
2669 | 2665 | , breakInfoIdx :: !Int -- ^ Next index for breakInfo array
|
2670 | - , modBreaks :: Maybe ModBreaks -- info about breakpoints
|
|
2671 | - |
|
2672 | - , breakInfo :: IntMap CgBreakInfo -- ^ Info at breakpoint occurrence.
|
|
2673 | - -- Indexed with breakpoint *info* index.
|
|
2674 | - -- See Note [Breakpoint identifiers]
|
|
2675 | - -- in GHC.Types.Breakpoint
|
|
2666 | + , breakInfo :: !(IntMap CgBreakInfo)
|
|
2667 | + -- ^ Info at breakpoints occurrences. Indexed with
|
|
2668 | + -- 'InternalBreakpointId'. See Note [Breakpoint identifiers] in
|
|
2669 | + -- GHC.ByteCode.Breakpoints.
|
|
2676 | 2670 | }
|
2677 | 2671 | |
2678 | 2672 | newtype BcM r = BcM (BcM_Env -> BcM_State -> IO (r, BcM_State))
|
... | ... | @@ -2681,7 +2675,7 @@ newtype BcM r = BcM (BcM_Env -> BcM_State -> IO (r, BcM_State)) |
2681 | 2675 | |
2682 | 2676 | runBc :: HscEnv -> Module -> Maybe ModBreaks -> BcM r -> IO (r, BcM_State)
|
2683 | 2677 | runBc hsc_env this_mod mbs (BcM m)
|
2684 | - = m (BcM_Env hsc_env this_mod) (BcM_State 0 0 mbs IntMap.empty)
|
|
2678 | + = m (BcM_Env hsc_env this_mod mbs) (BcM_State 0 0 IntMap.empty)
|
|
2685 | 2679 | |
2686 | 2680 | instance HasDynFlags BcM where
|
2687 | 2681 | getDynFlags = hsc_dflags <$> getHscEnv
|
... | ... | @@ -2724,7 +2718,7 @@ getCurrentModule :: BcM Module |
2724 | 2718 | getCurrentModule = BcM $ \env st -> return (bcm_module env, st)
|
2725 | 2719 | |
2726 | 2720 | getCurrentModBreaks :: BcM (Maybe ModBreaks)
|
2727 | -getCurrentModBreaks = BcM $ \_env st -> return (modBreaks st, st)
|
|
2721 | +getCurrentModBreaks = BcM $ \env st -> return (modBreaks env, st)
|
|
2728 | 2722 | |
2729 | 2723 | tickFS :: FastString
|
2730 | 2724 | tickFS = fsLit "ticked" |
1 | --- | Breakpoint related types
|
|
2 | -module GHC.Types.Breakpoint
|
|
3 | - ( BreakpointId (..)
|
|
4 | - , InternalBreakpointId (..)
|
|
5 | - , toBreakpointId
|
|
6 | - )
|
|
7 | -where
|
|
8 | - |
|
9 | -import GHC.Prelude
|
|
10 | -import GHC.Unit.Module
|
|
11 | -import GHC.Utils.Outputable
|
|
12 | -import Control.DeepSeq
|
|
13 | -import Data.Data (Data)
|
|
14 | - |
|
15 | --- | Breakpoint identifier.
|
|
16 | ---
|
|
17 | --- See Note [Breakpoint identifiers]
|
|
18 | -data BreakpointId = BreakpointId
|
|
19 | - { bi_tick_mod :: !Module -- ^ Breakpoint tick module
|
|
20 | - , bi_tick_index :: !Int -- ^ Breakpoint tick index
|
|
21 | - }
|
|
22 | - deriving (Eq, Ord, Data)
|
|
23 | - |
|
24 | --- | Internal breakpoint identifier
|
|
25 | ---
|
|
26 | --- See Note [Breakpoint identifiers]
|
|
27 | -data InternalBreakpointId = InternalBreakpointId
|
|
28 | - { ibi_tick_mod :: !Module -- ^ Breakpoint tick module
|
|
29 | - , ibi_tick_index :: !Int -- ^ Breakpoint tick index
|
|
30 | - , ibi_info_mod :: !Module -- ^ Breakpoint info module
|
|
31 | - , ibi_info_index :: !Int -- ^ Breakpoint info index
|
|
32 | - }
|
|
33 | - deriving (Eq, Ord)
|
|
34 | - |
|
35 | -toBreakpointId :: InternalBreakpointId -> BreakpointId
|
|
36 | -toBreakpointId ibi = BreakpointId
|
|
37 | - { bi_tick_mod = ibi_tick_mod ibi
|
|
38 | - , bi_tick_index = ibi_tick_index ibi
|
|
39 | - }
|
|
40 | - |
|
41 | - |
|
42 | --- Note [Breakpoint identifiers]
|
|
43 | --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
44 | ---
|
|
45 | --- Before optimization a breakpoint is identified uniquely with a tick module
|
|
46 | --- and a tick index. See BreakpointId. A tick module contains an array, indexed
|
|
47 | --- with the tick indexes, which indicates breakpoint status.
|
|
48 | ---
|
|
49 | --- When we generate ByteCode, we collect information for every breakpoint at
|
|
50 | --- their *occurrence sites* (see CgBreakInfo in GHC.ByteCode.Types) and these info
|
|
51 | --- are stored in the ModIface of the occurrence module. Because of inlining, we
|
|
52 | --- can't reuse the tick index to uniquely identify an occurrence; because of
|
|
53 | --- cross-module inlining, we can't assume that the occurrence module is the same
|
|
54 | --- as the tick module (#24712).
|
|
55 | ---
|
|
56 | --- So every breakpoint occurrence gets assigned a module-unique *info index* and
|
|
57 | --- we store it alongside the occurrence module (*info module*) in the
|
|
58 | --- InternalBreakpointId datatype.
|
|
59 | - |
|
60 | -instance Outputable BreakpointId where
|
|
61 | - ppr BreakpointId{bi_tick_mod, bi_tick_index} =
|
|
62 | - text "BreakpointId" <+> ppr bi_tick_mod <+> ppr bi_tick_index
|
|
63 | - |
|
64 | -instance NFData BreakpointId where
|
|
65 | - rnf BreakpointId{bi_tick_mod, bi_tick_index} =
|
|
66 | - rnf bi_tick_mod `seq` rnf bi_tick_index |
... | ... | @@ -21,17 +21,20 @@ module GHC.Types.Tickish ( |
21 | 21 | isProfTick,
|
22 | 22 | TickishPlacement(..),
|
23 | 23 | tickishPlace,
|
24 | - tickishContains
|
|
24 | + tickishContains,
|
|
25 | + |
|
26 | + -- * Breakpoint tick identifiers
|
|
27 | + BreakpointId(..), BreakTickIndex
|
|
25 | 28 | ) where
|
26 | 29 | |
27 | 30 | import GHC.Prelude
|
28 | 31 | import GHC.Data.FastString
|
32 | +import Control.DeepSeq
|
|
29 | 33 | |
30 | 34 | import GHC.Core.Type
|
31 | 35 | |
32 | 36 | import GHC.Unit.Module
|
33 | 37 | |
34 | -import GHC.Types.Breakpoint
|
|
35 | 38 | import GHC.Types.CostCentre
|
36 | 39 | import GHC.Types.SrcLoc ( RealSrcSpan, containsSpan )
|
37 | 40 | import GHC.Types.Var
|
... | ... | @@ -41,7 +44,7 @@ import GHC.Utils.Panic |
41 | 44 | import Language.Haskell.Syntax.Extension ( NoExtField )
|
42 | 45 | |
43 | 46 | import Data.Data
|
44 | -import GHC.Utils.Outputable (Outputable (ppr), text)
|
|
47 | +import GHC.Utils.Outputable (Outputable (ppr), text, (<+>))
|
|
45 | 48 | |
46 | 49 | {- *********************************************************************
|
47 | 50 | * *
|
... | ... | @@ -171,6 +174,35 @@ deriving instance Eq (GenTickish 'TickishPassCmm) |
171 | 174 | deriving instance Ord (GenTickish 'TickishPassCmm)
|
172 | 175 | deriving instance Data (GenTickish 'TickishPassCmm)
|
173 | 176 | |
177 | +--------------------------------------------------------------------------------
|
|
178 | +-- Tick breakpoint index
|
|
179 | +--------------------------------------------------------------------------------
|
|
180 | + |
|
181 | +-- | Breakpoint tick index
|
|
182 | +-- newtype BreakTickIndex = BreakTickIndex Int
|
|
183 | +-- deriving (Eq, Ord, Data, Ix, NFData, Outputable)
|
|
184 | +type BreakTickIndex = Int
|
|
185 | + |
|
186 | +-- | Breakpoint identifier.
|
|
187 | +--
|
|
188 | +-- Indexes into the structures in the @'ModBreaks'@ created during desugaring
|
|
189 | +-- (after inserting the breakpoint ticks in the expressions).
|
|
190 | +-- See Note [Breakpoint identifiers]
|
|
191 | +data BreakpointId = BreakpointId
|
|
192 | + { bi_tick_mod :: !Module -- ^ Breakpoint tick module
|
|
193 | + , bi_tick_index :: !BreakTickIndex -- ^ Breakpoint tick index
|
|
194 | + }
|
|
195 | + deriving (Eq, Ord, Data)
|
|
196 | + |
|
197 | +instance Outputable BreakpointId where
|
|
198 | + ppr BreakpointId{bi_tick_mod, bi_tick_index} =
|
|
199 | + text "BreakpointId" <+> ppr bi_tick_mod <+> ppr bi_tick_index
|
|
200 | + |
|
201 | +instance NFData BreakpointId where
|
|
202 | + rnf BreakpointId{bi_tick_mod, bi_tick_index} =
|
|
203 | + rnf bi_tick_mod `seq` rnf bi_tick_index
|
|
204 | + |
|
205 | +--------------------------------------------------------------------------------
|
|
174 | 206 | |
175 | 207 | -- | A "counting tick" (where tickishCounts is True) is one that
|
176 | 208 | -- counts evaluations in some way. We cannot discard a counting tick,
|
... | ... | @@ -7,7 +7,7 @@ where |
7 | 7 | |
8 | 8 | import GHC.Prelude
|
9 | 9 | |
10 | -import GHC.ByteCode.Types
|
|
10 | +import GHC.HsToCore.Breakpoints
|
|
11 | 11 | import GHC.ForeignSrcLang
|
12 | 12 | |
13 | 13 | import GHC.Hs
|
... | ... | @@ -223,6 +223,7 @@ Library |
223 | 223 | GHC.Builtin.Uniques
|
224 | 224 | GHC.Builtin.Utils
|
225 | 225 | GHC.ByteCode.Asm
|
226 | + GHC.ByteCode.Breakpoints
|
|
226 | 227 | GHC.ByteCode.InfoTable
|
227 | 228 | GHC.ByteCode.Instr
|
228 | 229 | GHC.ByteCode.Linker
|
... | ... | @@ -892,7 +893,6 @@ Library |
892 | 893 | GHC.Types.Annotations
|
893 | 894 | GHC.Types.Avail
|
894 | 895 | GHC.Types.Basic
|
895 | - GHC.Types.Breakpoint
|
|
896 | 896 | GHC.Types.CompleteMatch
|
897 | 897 | GHC.Types.CostCentre
|
898 | 898 | GHC.Types.CostCentre.State
|
... | ... | @@ -45,6 +45,7 @@ import GHC.Runtime.Eval (mkTopLevEnv) |
45 | 45 | import GHC.Runtime.Eval.Utils
|
46 | 46 | |
47 | 47 | -- The GHC interface
|
48 | +import GHC.ByteCode.Breakpoints (imodBreaks_modBreaks)
|
|
48 | 49 | import GHC.Runtime.Interpreter
|
49 | 50 | import GHCi.RemoteTypes
|
50 | 51 | import GHCi.BreakArray( breakOn, breakOff )
|
... | ... | @@ -66,7 +67,8 @@ import qualified GHC |
66 | 67 | import GHC ( LoadHowMuch(..), Target(..), TargetId(..),
|
67 | 68 | Resume, SingleStep, Ghc,
|
68 | 69 | GetDocsFailure(..), pushLogHookM,
|
69 | - getModuleGraph, handleSourceError )
|
|
70 | + getModuleGraph, handleSourceError,
|
|
71 | + InternalBreakpointId(..) )
|
|
70 | 72 | import GHC.Driver.Main (hscParseModuleWithLocation, hscParseStmtWithLocation)
|
71 | 73 | import GHC.Hs.ImpExp
|
72 | 74 | import GHC.Hs
|
... | ... | @@ -78,7 +80,6 @@ import GHC.Core.TyCo.Ppr |
78 | 80 | import GHC.Types.SafeHaskell ( getSafeMode )
|
79 | 81 | import GHC.Types.SourceError ( SourceError )
|
80 | 82 | import GHC.Types.Name
|
81 | -import GHC.Types.Breakpoint
|
|
82 | 83 | import GHC.Types.Var ( varType )
|
83 | 84 | import GHC.Iface.Syntax ( showToHeader )
|
84 | 85 | import GHC.Builtin.Names
|
... | ... | @@ -4473,7 +4474,7 @@ breakById inp = do |
4473 | 4474 | Left sdoc -> printForUser sdoc
|
4474 | 4475 | Right (mod, mod_info, fun_str) -> do
|
4475 | 4476 | let modBreaks = expectJust (GHC.modInfoModBreaks mod_info)
|
4476 | - findBreakAndSet mod $ \_ -> findBreakForBind fun_str modBreaks
|
|
4477 | + findBreakAndSet mod $ \_ -> findBreakForBind fun_str (imodBreaks_modBreaks modBreaks)
|
|
4477 | 4478 | |
4478 | 4479 | breakSyntax :: a
|
4479 | 4480 | breakSyntax = throwGhcException $ CmdLineError ("Syntax: :break [<mod>.]<func>[.<func>]\n"
|
... | ... | @@ -5,6 +5,7 @@ GHC.Builtin.Types |
5 | 5 | GHC.Builtin.Types.Literals
|
6 | 6 | GHC.Builtin.Types.Prim
|
7 | 7 | GHC.Builtin.Uniques
|
8 | +GHC.ByteCode.Breakpoints
|
|
8 | 9 | GHC.ByteCode.Types
|
9 | 10 | GHC.Cmm.BlockId
|
10 | 11 | GHC.Cmm.CLabel
|
... | ... | @@ -110,6 +111,8 @@ GHC.Hs.Pat |
110 | 111 | GHC.Hs.Specificity
|
111 | 112 | GHC.Hs.Type
|
112 | 113 | GHC.Hs.Utils
|
114 | +GHC.HsToCore.Breakpoints
|
|
115 | +GHC.HsToCore.Ticks
|
|
113 | 116 | GHC.Iface.Errors.Types
|
114 | 117 | GHC.Iface.Ext.Fields
|
115 | 118 | GHC.Iface.Flags
|
... | ... | @@ -150,7 +153,6 @@ GHC.Tc.Zonk.Monad |
150 | 153 | GHC.Types.Annotations
|
151 | 154 | GHC.Types.Avail
|
152 | 155 | GHC.Types.Basic
|
153 | -GHC.Types.Breakpoint
|
|
154 | 156 | GHC.Types.CostCentre
|
155 | 157 | GHC.Types.CostCentre.State
|
156 | 158 | GHC.Types.Cpr
|
... | ... | @@ -5,6 +5,7 @@ GHC.Builtin.Types |
5 | 5 | GHC.Builtin.Types.Literals
|
6 | 6 | GHC.Builtin.Types.Prim
|
7 | 7 | GHC.Builtin.Uniques
|
8 | +GHC.ByteCode.Breakpoints
|
|
8 | 9 | GHC.ByteCode.Types
|
9 | 10 | GHC.Cmm.BlockId
|
10 | 11 | GHC.Cmm.CLabel
|
... | ... | @@ -114,8 +115,10 @@ GHC.Hs.Pat |
114 | 115 | GHC.Hs.Specificity
|
115 | 116 | GHC.Hs.Type
|
116 | 117 | GHC.Hs.Utils
|
118 | +GHC.HsToCore.Breakpoints
|
|
117 | 119 | GHC.HsToCore.Errors.Types
|
118 | 120 | GHC.HsToCore.Pmc.Solver.Types
|
121 | +GHC.HsToCore.Ticks
|
|
119 | 122 | GHC.Iface.Errors.Types
|
120 | 123 | GHC.Iface.Ext.Fields
|
121 | 124 | GHC.Iface.Flags
|
... | ... | @@ -171,7 +174,6 @@ GHC.Tc.Zonk.Monad |
171 | 174 | GHC.Types.Annotations
|
172 | 175 | GHC.Types.Avail
|
173 | 176 | GHC.Types.Basic
|
174 | -GHC.Types.Breakpoint
|
|
175 | 177 | GHC.Types.CompleteMatch
|
176 | 178 | GHC.Types.CostCentre
|
177 | 179 | GHC.Types.CostCentre.State
|