Rodrigo Mesquita pushed to branch wip/romes/step-out-11 at Glasgow Haskell Compiler / GHC
Commits:
-
01d3154e
by Wen Kokke at 2025-07-10T17:06:36+01:00
-
ac259c48
by Wen Kokke at 2025-07-10T17:06:38+01:00
-
2b4db9ba
by Pi Delport at 2025-07-11T16:40:52-04:00
-
b56d108c
by Rodrigo Mesquita at 2025-07-16T10:32:32+01:00
-
bd2949c6
by Rodrigo Mesquita at 2025-07-16T10:32:47+01:00
-
d19e3e4a
by Rodrigo Mesquita at 2025-07-16T10:32:50+01:00
-
4da0a66b
by Rodrigo Mesquita at 2025-07-17T09:44:05+01:00
-
d1439072
by Rodrigo Mesquita at 2025-07-17T09:44:06+01:00
-
9e37cf61
by Ben Gamari at 2025-07-17T09:44:06+01:00
-
eab05af0
by Rodrigo Mesquita at 2025-07-17T09:44:06+01:00
-
2692e656
by Rodrigo Mesquita at 2025-07-18T18:28:49+01:00
-
02e468b0
by Rodrigo Mesquita at 2025-07-18T18:29:12+01:00
28 changed files:
- cabal.project-reinstall
- 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/CoreToIface.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Runtime/Debugger/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- compiler/Setup.hs
- compiler/ghc.cabal.in
- docs/users_guide/eventlog-formats.rst
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Monad.hs
- libraries/ghc-boot/Setup.hs
- libraries/ghc-boot/ghc-boot.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Base.hs
- libraries/ghci/GHCi/Debugger.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- rts/Disassembler.c
- rts/Exception.cmm
- rts/Interpreter.c
- testsuite/tests/ghci.debugger/scripts/all.T
Changes:
| ... | ... | @@ -59,6 +59,7 @@ constraints: ghc +internal-interpreter +dynamic-system-linke, |
| 59 | 59 | ghc-bin +internal-interpreter +threaded,
|
| 60 | 60 | ghci +internal-interpreter,
|
| 61 | 61 | haddock +in-ghc-tree,
|
| 62 | + haddock-api +in-ghc-tree,
|
|
| 62 | 63 | any.array installed,
|
| 63 | 64 | any.base installed,
|
| 64 | 65 | any.deepseq installed,
|
| ... | ... | @@ -69,6 +70,9 @@ constraints: ghc +internal-interpreter +dynamic-system-linke, |
| 69 | 70 | any.template-haskell installed
|
| 70 | 71 | |
| 71 | 72 | |
| 73 | +package *
|
|
| 74 | + happy-options: --strict
|
|
| 75 | + |
|
| 72 | 76 | benchmarks: False
|
| 73 | 77 | tests: False
|
| 74 | 78 | allow-boot-library-installs: True
|
| ... | ... | @@ -841,24 +841,18 @@ assembleI platform i = case i of |
| 841 | 841 | W8 -> emit_ bci_OP_INDEX_ADDR_08 []
|
| 842 | 842 | _ -> unsupported_width
|
| 843 | 843 | |
| 844 | - BRK_FUN (InternalBreakpointId tick_mod tickx info_mod infox) -> do
|
|
| 844 | + BRK_FUN ibi@(InternalBreakpointId info_mod infox) byteOff -> do
|
|
| 845 | + p1 <- ptr $ BCOPtrBreakArray info_mod
|
|
| 845 | 846 | let -- cast that checks that round-tripping through Word16 doesn't change the value
|
| 846 | 847 | toW16 x = let r = fromIntegral x :: Word16
|
| 847 | 848 | in if fromIntegral r == x
|
| 848 | 849 | then r
|
| 849 | 850 | 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 | - ]
|
|
| 851 | + info_addr <- lit1 $ BCONPtrFS $ moduleNameFS $ moduleName info_mod
|
|
| 852 | + info_unitid_addr <- lit1 $ BCONPtrFS $ unitIdFS $ moduleUnitId info_mod
|
|
| 853 | + np <- lit1 $ BCONPtrCostCentre ibi
|
|
| 854 | + emit_ bci_BRK_FUN [ Op p1, Op info_addr, Op info_unitid_addr
|
|
| 855 | + , SmallOp (toW16 infox), SmallOp (toW16 byteOff), Op np ]
|
|
| 862 | 856 | |
| 863 | 857 | BRK_ALTS active -> emit_ bci_BRK_ALTS [SmallOp (if active then 1 else 0)]
|
| 864 | 858 |
| 1 | 1 | {-# LANGUAGE RecordWildCards #-}
|
| 2 | +{-# LANGUAGE DerivingStrategies #-}
|
|
| 2 | 3 | |
| 3 | 4 | -- | Breakpoint information constructed during ByteCode generation.
|
| 4 | 5 | --
|
| ... | ... | @@ -7,23 +8,24 @@ |
| 7 | 8 | -- 'InternalModBreaks', and is uniquely identified at runtime by an
|
| 8 | 9 | -- 'InternalBreakpointId'.
|
| 9 | 10 | --
|
| 10 | --- See Note [Breakpoint identifiers]
|
|
| 11 | +-- See Note [ModBreaks vs InternalModBreaks] and Note [Breakpoint identifiers]
|
|
| 11 | 12 | module GHC.ByteCode.Breakpoints
|
| 12 | 13 | ( -- * Internal Mod Breaks
|
| 13 | 14 | InternalModBreaks(..), CgBreakInfo(..)
|
| 14 | - , mkInternalModBreaks
|
|
| 15 | + , mkInternalModBreaks, imodBreaks_module
|
|
| 15 | 16 | |
| 16 | 17 | -- ** Internal breakpoint identifier
|
| 17 | 18 | , InternalBreakpointId(..), BreakInfoIndex
|
| 19 | + , InternalBreakLoc(..)
|
|
| 18 | 20 | |
| 19 | 21 | -- * Operations
|
| 20 | - , toBreakpointId
|
|
| 21 | 22 | |
| 22 | 23 | -- ** Internal-level operations
|
| 23 | - , getInternalBreak, addInternalBreak
|
|
| 24 | + , getInternalBreak
|
|
| 24 | 25 | |
| 25 | 26 | -- ** Source-level information operations
|
| 26 | 27 | , getBreakLoc, getBreakVars, getBreakDecls, getBreakCCS
|
| 28 | + , getBreakSourceId, getBreakSourceMod
|
|
| 27 | 29 | |
| 28 | 30 | -- * Utils
|
| 29 | 31 | , seqInternalModBreaks
|
| ... | ... | @@ -47,6 +49,31 @@ import GHC.Utils.Panic |
| 47 | 49 | import Data.Array
|
| 48 | 50 | |
| 49 | 51 | {-
|
| 52 | +Note [ModBreaks vs InternalModBreaks]
|
|
| 53 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 54 | +'ModBreaks' and 'BreakpointId's must not to be confused with
|
|
| 55 | +'InternalModBreaks' and 'InternalBreakId's.
|
|
| 56 | + |
|
| 57 | +'ModBreaks' is constructed once during HsToCore from the information attached
|
|
| 58 | +to source-level breakpoint ticks and is never changed afterwards. A 'ModBreaks'
|
|
| 59 | +can be queried using 'BreakpointId's, which uniquely identifies a breakpoint
|
|
| 60 | +within the list of breakpoint information for a given module's 'ModBreaks'.
|
|
| 61 | + |
|
| 62 | +'InternalModBreaks' are constructed during bytecode generation and are indexed
|
|
| 63 | +by a 'InternalBreakpointId'. They contain all the information relevant to a
|
|
| 64 | +breakpoint for code generation that can be accessed during runtime execution
|
|
| 65 | +(such as a 'BreakArray' for triggering breakpoints). 'InternalBreakpointId's
|
|
| 66 | +are used at runtime to trigger and inspect breakpoints -- a 'BRK_FUN'
|
|
| 67 | +instruction receives 'InternalBreakpointId' as an argument.
|
|
| 68 | + |
|
| 69 | +We keep a mapping from 'InternalModBreaks' to a 'BreakpointId', which can then be used
|
|
| 70 | +to get source-level information about a breakpoint via the corresponding 'ModBreaks'.
|
|
| 71 | + |
|
| 72 | +Notably, 'InternalModBreaks' can contain entries for so-called internal
|
|
| 73 | +breakpoints, which do not necessarily have a source-level location attached to
|
|
| 74 | +it (i.e. do not have a matching entry in 'ModBreaks'). We may leverage this to
|
|
| 75 | +introduce breakpoints during code generation for features such as stepping-out.
|
|
| 76 | + |
|
| 50 | 77 | Note [Breakpoint identifiers]
|
| 51 | 78 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 52 | 79 | Before optimization a breakpoint is identified uniquely with a tick module
|
| ... | ... | @@ -64,6 +91,10 @@ So every breakpoint occurrence gets assigned a module-unique *info index* and |
| 64 | 91 | we store it alongside the occurrence module (*info module*) in the
|
| 65 | 92 | 'InternalBreakpointId' datatype. This is the index that we use at runtime to
|
| 66 | 93 | identify a breakpoint.
|
| 94 | + |
|
| 95 | +When the internal breakpoint has a matching tick-level breakpoint we can fetch
|
|
| 96 | +the related tick-level information by first looking up a mapping
|
|
| 97 | +@'InternalBreakpointId' -> 'BreakpointId'@ in @'CgBreakInfo'@.
|
|
| 67 | 98 | -}
|
| 68 | 99 | |
| 69 | 100 | --------------------------------------------------------------------------------
|
| ... | ... | @@ -78,19 +109,11 @@ type BreakInfoIndex = Int |
| 78 | 109 | -- Indexes into the structures in the @'InternalModBreaks'@ produced during ByteCode generation.
|
| 79 | 110 | -- See Note [Breakpoint identifiers]
|
| 80 | 111 | 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
|
|
| 112 | + { ibi_info_mod :: !Module -- ^ Breakpoint tick module
|
|
| 84 | 113 | , ibi_info_index :: !BreakInfoIndex -- ^ Breakpoint tick index
|
| 85 | 114 | }
|
| 86 | 115 | deriving (Eq, Ord)
|
| 87 | 116 | |
| 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 | 117 | --------------------------------------------------------------------------------
|
| 95 | 118 | -- * Internal Mod Breaks
|
| 96 | 119 | --------------------------------------------------------------------------------
|
| ... | ... | @@ -107,18 +130,34 @@ data InternalModBreaks = InternalModBreaks |
| 107 | 130 | -- 'InternalBreakpointId'.
|
| 108 | 131 | |
| 109 | 132 | , 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.
|
|
| 133 | + -- ^ Store the ModBreaks for this module
|
|
| 134 | + --
|
|
| 135 | + -- Recall Note [Breakpoint identifiers]: for some module A, an
|
|
| 136 | + -- *occurrence* of a breakpoint in A may have been inlined from some
|
|
| 137 | + -- breakpoint *defined* in module B.
|
|
| 138 | + --
|
|
| 139 | + -- This 'ModBreaks' contains information regarding all the breakpoints
|
|
| 140 | + -- defined in the module this 'InternalModBreaks' corresponds to. It
|
|
| 141 | + -- /does not/ necessarily have information regarding all the breakpoint
|
|
| 142 | + -- occurrences registered in 'imodBreaks_breakInfo'. Some of those
|
|
| 143 | + -- occurrences may refer breakpoints inlined from other modules.
|
|
| 113 | 144 | }
|
| 114 | 145 | |
| 115 | --- | Construct an 'InternalModBreaks'
|
|
| 146 | +-- | Construct an 'InternalModBreaks'.
|
|
| 147 | +--
|
|
| 148 | +-- INVARIANT: The given 'ModBreaks' correspond to the same module as this
|
|
| 149 | +-- 'InternalModBreaks' module (the first argument) and its breakpoint infos
|
|
| 150 | +-- (the @IntMap CgBreakInfo@ argument)
|
|
| 116 | 151 | mkInternalModBreaks :: Module -> IntMap CgBreakInfo -> ModBreaks -> InternalModBreaks
|
| 117 | 152 | mkInternalModBreaks mod im mbs =
|
| 118 | 153 | assertPpr (mod == modBreaks_module mbs)
|
| 119 | 154 | (text "Constructing InternalModBreaks with the ModBreaks of a different module!") $
|
| 120 | 155 | InternalModBreaks im mbs
|
| 121 | 156 | |
| 157 | +-- | Get the module to which these 'InternalModBreaks' correspond
|
|
| 158 | +imodBreaks_module :: InternalModBreaks -> Module
|
|
| 159 | +imodBreaks_module = modBreaks_module . imodBreaks_modBreaks
|
|
| 160 | + |
|
| 122 | 161 | -- | Information about a breakpoint that we know at code-generation time
|
| 123 | 162 | -- In order to be used, this needs to be hydrated relative to the current HscEnv by
|
| 124 | 163 | -- 'hydrateCgBreakInfo'. Everything here can be fully forced and that's critical for
|
| ... | ... | @@ -128,20 +167,32 @@ data CgBreakInfo |
| 128 | 167 | { cgb_tyvars :: ![IfaceTvBndr] -- ^ Type variables in scope at the breakpoint
|
| 129 | 168 | , cgb_vars :: ![Maybe (IfaceIdBndr, Word)]
|
| 130 | 169 | , cgb_resty :: !IfaceType
|
| 170 | + , cgb_tick_id :: !(Either InternalBreakLoc BreakpointId)
|
|
| 171 | + -- ^ This field records the original breakpoint tick identifier for this
|
|
| 172 | + -- internal breakpoint info. It is used to convert a breakpoint
|
|
| 173 | + -- *occurrence* index ('InternalBreakpointId') into a *definition* index
|
|
| 174 | + -- ('BreakpointId').
|
|
| 175 | + --
|
|
| 176 | + -- The modules of breakpoint occurrence and breakpoint definition are not
|
|
| 177 | + -- necessarily the same: See Note [Breakpoint identifiers].
|
|
| 178 | + --
|
|
| 179 | + -- If there is no original tick identifier (that is, the breakpoint was
|
|
| 180 | + -- created during code generation), instead refer directly to the SrcSpan
|
|
| 181 | + -- we want to use for it. See Note [Internal Breakpoint Locations]
|
|
| 131 | 182 | }
|
| 132 | 183 | -- See Note [Syncing breakpoint info] in GHC.Runtime.Eval
|
| 133 | 184 | |
| 185 | +-- | Breakpoints created during code generation don't have a source-level tick
|
|
| 186 | +-- location. Instead, we come up with one ourselves.
|
|
| 187 | +-- See Note [Internal Breakpoint Locations]
|
|
| 188 | +newtype InternalBreakLoc = InternalBreakLoc SrcSpan
|
|
| 189 | + deriving newtype (Eq, Show, NFData, Outputable)
|
|
| 190 | + |
|
| 134 | 191 | -- | Get an internal breakpoint info by 'InternalBreakpointId'
|
| 135 | 192 | 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)}
|
|
| 193 | +getInternalBreak (InternalBreakpointId mod ix) imbs =
|
|
| 194 | + assert_modules_match mod (imodBreaks_module imbs) $
|
|
| 195 | + imodBreaks_breakInfo imbs IM.! ix
|
|
| 145 | 196 | |
| 146 | 197 | -- | Assert that the module in the 'InternalBreakpointId' and in
|
| 147 | 198 | -- 'InternalModBreaks' match.
|
| ... | ... | @@ -155,27 +206,70 @@ assert_modules_match ibi_mod imbs_mod = |
| 155 | 206 | -- Tick-level Breakpoint information
|
| 156 | 207 | --------------------------------------------------------------------------------
|
| 157 | 208 | |
| 209 | +-- | Get the source module and tick index for this breakpoint
|
|
| 210 | +-- (as opposed to the module where this breakpoint occurs, which is in 'InternalBreakpointId')
|
|
| 211 | +getBreakSourceId :: InternalBreakpointId -> InternalModBreaks -> Either InternalBreakLoc BreakpointId
|
|
| 212 | +getBreakSourceId (InternalBreakpointId ibi_mod ibi_ix) imbs =
|
|
| 213 | + assert_modules_match ibi_mod (imodBreaks_module imbs) $
|
|
| 214 | + let cgb = imodBreaks_breakInfo imbs IM.! ibi_ix
|
|
| 215 | + in cgb_tick_id cgb
|
|
| 216 | + |
|
| 217 | +-- | Get the source module for this breakpoint (where the breakpoint is defined)
|
|
| 218 | +getBreakSourceMod :: InternalBreakpointId -> InternalModBreaks -> Module
|
|
| 219 | +getBreakSourceMod (InternalBreakpointId ibi_mod ibi_ix) imbs =
|
|
| 220 | + assert_modules_match ibi_mod (imodBreaks_module imbs) $
|
|
| 221 | + let cgb = imodBreaks_breakInfo imbs IM.! ibi_ix
|
|
| 222 | + in case cgb_tick_id cgb of
|
|
| 223 | + Left InternalBreakLoc{} -> imodBreaks_module imbs
|
|
| 224 | + Right BreakpointId{bi_tick_mod} -> bi_tick_mod
|
|
| 225 | + |
|
| 158 | 226 | -- | Get the source span for this breakpoint
|
| 159 | -getBreakLoc :: InternalBreakpointId -> InternalModBreaks -> SrcSpan
|
|
| 160 | -getBreakLoc = getBreakXXX modBreaks_locs
|
|
| 227 | +getBreakLoc :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO SrcSpan
|
|
| 228 | +getBreakLoc = getBreakXXX modBreaks_locs (\(InternalBreakLoc x) -> x)
|
|
| 161 | 229 | |
| 162 | 230 | -- | Get the vars for this breakpoint
|
| 163 | -getBreakVars :: InternalBreakpointId -> InternalModBreaks -> [OccName]
|
|
| 164 | -getBreakVars = getBreakXXX modBreaks_vars
|
|
| 231 | +getBreakVars :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO [OccName]
|
|
| 232 | +getBreakVars = getBreakXXX modBreaks_vars (const [])
|
|
| 165 | 233 | |
| 166 | 234 | -- | Get the decls for this breakpoint
|
| 167 | -getBreakDecls :: InternalBreakpointId -> InternalModBreaks -> [String]
|
|
| 168 | -getBreakDecls = getBreakXXX modBreaks_decls
|
|
| 235 | +getBreakDecls :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO [String]
|
|
| 236 | +getBreakDecls = getBreakXXX modBreaks_decls (const [])
|
|
| 169 | 237 | |
| 170 | 238 | -- | Get the decls for this breakpoint
|
| 171 | -getBreakCCS :: InternalBreakpointId -> InternalModBreaks -> (String, String)
|
|
| 172 | -getBreakCCS = getBreakXXX modBreaks_ccs
|
|
| 239 | +getBreakCCS :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO (Maybe (String, String))
|
|
| 240 | +getBreakCCS = getBreakXXX (fmap Just . modBreaks_ccs) (const Nothing)
|
|
| 173 | 241 | |
| 174 | 242 | -- | 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
|
|
| 243 | +--
|
|
| 244 | +-- Recall Note [Breakpoint identifiers]: the internal breakpoint module (the
|
|
| 245 | +-- *occurrence* module) doesn't necessarily match the module where the
|
|
| 246 | +-- tick breakpoint was defined with the relevant 'ModBreaks'.
|
|
| 247 | +--
|
|
| 248 | +-- When the tick module is the same as the internal module, we use the stored
|
|
| 249 | +-- 'ModBreaks'. When the tick module is different, we need to look up the
|
|
| 250 | +-- 'ModBreaks' in the HUG for that other module.
|
|
| 251 | +--
|
|
| 252 | +-- When there is no tick module (the breakpoint was generated at codegen), use
|
|
| 253 | +-- the function on internal mod breaks.
|
|
| 254 | +--
|
|
| 255 | +-- To avoid cyclic dependencies, we instead receive a function that looks up
|
|
| 256 | +-- the 'ModBreaks' given a 'Module'
|
|
| 257 | +getBreakXXX :: (ModBreaks -> Array BreakTickIndex a) -> (InternalBreakLoc -> a) -> (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO a
|
|
| 258 | +getBreakXXX view viewInternal lookupModule (InternalBreakpointId ibi_mod ibi_ix) imbs =
|
|
| 259 | + assert_modules_match ibi_mod (imodBreaks_module imbs) $ do
|
|
| 260 | + let cgb = imodBreaks_breakInfo imbs IM.! ibi_ix
|
|
| 261 | + case cgb_tick_id cgb of
|
|
| 262 | + Right BreakpointId{bi_tick_mod, bi_tick_index}
|
|
| 263 | + | bi_tick_mod == ibi_mod
|
|
| 264 | + -> do
|
|
| 265 | + let these_mbs = imodBreaks_modBreaks imbs
|
|
| 266 | + return $ view these_mbs ! bi_tick_index
|
|
| 267 | + | otherwise
|
|
| 268 | + -> do
|
|
| 269 | + other_mbs <- lookupModule bi_tick_mod
|
|
| 270 | + return $ view other_mbs ! bi_tick_index
|
|
| 271 | + Left l ->
|
|
| 272 | + return $ viewInternal l
|
|
| 179 | 273 | |
| 180 | 274 | --------------------------------------------------------------------------------
|
| 181 | 275 | -- Instances
|
| ... | ... | @@ -190,7 +284,8 @@ seqInternalModBreaks InternalModBreaks{..} = |
| 190 | 284 | seqCgBreakInfo CgBreakInfo{..} =
|
| 191 | 285 | rnf cgb_tyvars `seq`
|
| 192 | 286 | rnf cgb_vars `seq`
|
| 193 | - rnf cgb_resty
|
|
| 287 | + rnf cgb_resty `seq`
|
|
| 288 | + rnf cgb_tick_id
|
|
| 194 | 289 | |
| 195 | 290 | instance Outputable InternalBreakpointId where
|
| 196 | 291 | ppr InternalBreakpointId{..} =
|
| ... | ... | @@ -203,4 +298,5 @@ instance NFData InternalBreakpointId where |
| 203 | 298 | instance Outputable CgBreakInfo where
|
| 204 | 299 | ppr info = text "CgBreakInfo" <+>
|
| 205 | 300 | parens (ppr (cgb_vars info) <+>
|
| 206 | - ppr (cgb_resty info)) |
|
| 301 | + ppr (cgb_resty info) <+>
|
|
| 302 | + ppr (cgb_tick_id info)) |
| ... | ... | @@ -258,7 +258,7 @@ data BCInstr |
| 258 | 258 | -- Note [unboxed tuple bytecodes and tuple_BCO] in GHC.StgToByteCode
|
| 259 | 259 | |
| 260 | 260 | -- Breakpoints
|
| 261 | - | BRK_FUN !InternalBreakpointId
|
|
| 261 | + | BRK_FUN !InternalBreakpointId !ByteOff
|
|
| 262 | 262 | |
| 263 | 263 | -- An internal breakpoint for triggering a break on any case alternative
|
| 264 | 264 | -- See Note [Debugger: BRK_ALTS]
|
| ... | ... | @@ -454,10 +454,10 @@ instance Outputable BCInstr where |
| 454 | 454 | ppr ENTER = text "ENTER"
|
| 455 | 455 | ppr (RETURN pk) = text "RETURN " <+> ppr pk
|
| 456 | 456 | ppr (RETURN_TUPLE) = text "RETURN_TUPLE"
|
| 457 | - ppr (BRK_FUN (InternalBreakpointId tick_mod tickx info_mod infox))
|
|
| 457 | + ppr (BRK_FUN (InternalBreakpointId info_mod infox) bo)
|
|
| 458 | 458 | = text "BRK_FUN" <+> text "<breakarray>"
|
| 459 | - <+> ppr tick_mod <+> ppr tickx
|
|
| 460 | 459 | <+> ppr info_mod <+> ppr infox
|
| 460 | + <+> ppr bo
|
|
| 461 | 461 | <+> text "<cc>"
|
| 462 | 462 | ppr (BRK_ALTS active) = text "BRK_ALTS" <+> ppr active
|
| 463 | 463 | #if MIN_VERSION_rts(1,0,3)
|
| ... | ... | @@ -98,9 +98,9 @@ lookupLiteral interp pkgs_loaded le lb ptr = case ptr of |
| 98 | 98 | BCONPtrFFIInfo (FFIInfo {..}) -> do
|
| 99 | 99 | RemotePtr p <- interpCmd interp $ PrepFFI ffiInfoArgs ffiInfoRet
|
| 100 | 100 | pure $ fromIntegral p
|
| 101 | - BCONPtrCostCentre BreakpointId{..}
|
|
| 101 | + BCONPtrCostCentre InternalBreakpointId{..}
|
|
| 102 | 102 | | interpreterProfiled interp -> do
|
| 103 | - case expectJust (lookupModuleEnv (ccs_env lb) bi_tick_mod) ! bi_tick_index of
|
|
| 103 | + case expectJust (lookupModuleEnv (ccs_env lb) ibi_info_mod) ! ibi_info_index of
|
|
| 104 | 104 | RemotePtr p -> pure $ fromIntegral p
|
| 105 | 105 | | otherwise ->
|
| 106 | 106 | case toRemotePtr nullPtr of
|
| ... | ... | @@ -285,7 +285,7 @@ data BCONPtr |
| 285 | 285 | -- | A libffi ffi_cif function prototype.
|
| 286 | 286 | | BCONPtrFFIInfo !FFIInfo
|
| 287 | 287 | -- | A 'CostCentre' remote pointer array's respective 'BreakpointId'
|
| 288 | - | BCONPtrCostCentre !BreakpointId
|
|
| 288 | + | BCONPtrCostCentre !InternalBreakpointId
|
|
| 289 | 289 | |
| 290 | 290 | instance NFData BCONPtr where
|
| 291 | 291 | rnf x = x `seq` ()
|
| ... | ... | @@ -44,16 +44,12 @@ module GHC.CoreToIface |
| 44 | 44 | -- * Other stuff
|
| 45 | 45 | , toIfaceLFInfo
|
| 46 | 46 | , toIfaceBooleanFormula
|
| 47 | - -- * CgBreakInfo
|
|
| 48 | - , dehydrateCgBreakInfo
|
|
| 49 | 47 | ) where
|
| 50 | 48 | |
| 51 | 49 | import GHC.Prelude
|
| 52 | 50 | |
| 53 | 51 | import GHC.StgToCmm.Types
|
| 54 | 52 | |
| 55 | -import GHC.ByteCode.Types
|
|
| 56 | - |
|
| 57 | 53 | import GHC.Core
|
| 58 | 54 | import GHC.Core.TyCon hiding ( pprPromotionQuote )
|
| 59 | 55 | import GHC.Core.Coercion.Axiom
|
| ... | ... | @@ -702,15 +698,6 @@ toIfaceLFInfo nm lfi = case lfi of |
| 702 | 698 | LFLetNoEscape ->
|
| 703 | 699 | panic "toIfaceLFInfo: LFLetNoEscape"
|
| 704 | 700 | |
| 705 | --- Dehydrating CgBreakInfo
|
|
| 706 | - |
|
| 707 | -dehydrateCgBreakInfo :: [TyVar] -> [Maybe (Id, Word)] -> Type -> CgBreakInfo
|
|
| 708 | -dehydrateCgBreakInfo ty_vars idOffSets tick_ty =
|
|
| 709 | - CgBreakInfo
|
|
| 710 | - { cgb_tyvars = map toIfaceTvBndr ty_vars
|
|
| 711 | - , cgb_vars = map (fmap (\(i, offset) -> (toIfaceIdBndr i, offset))) idOffSets
|
|
| 712 | - , cgb_resty = toIfaceType tick_ty
|
|
| 713 | - }
|
|
| 714 | 701 | |
| 715 | 702 | {- Note [Inlining and hs-boot files]
|
| 716 | 703 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | -- 'InternalModBreaks' and 'InternalBreakId's. The latter are constructed
|
| 13 | 13 | -- during bytecode generation and can be found in 'GHC.ByteCode.Breakpoints'.
|
| 14 | 14 | --
|
| 15 | --- See Note [Breakpoint identifiers]
|
|
| 15 | +-- See Note [ModBreaks vs InternalModBreaks] and Note [Breakpoint identifiers]
|
|
| 16 | 16 | module GHC.HsToCore.Breakpoints
|
| 17 | 17 | ( -- * ModBreaks
|
| 18 | 18 | mkModBreaks, ModBreaks(..)
|
| ... | ... | @@ -58,6 +58,7 @@ import GHCi.RemoteTypes |
| 58 | 58 | import GHC.Iface.Load
|
| 59 | 59 | import GHCi.Message (ConInfoTable(..), LoadedDLL)
|
| 60 | 60 | |
| 61 | +import GHC.ByteCode.Breakpoints
|
|
| 61 | 62 | import GHC.ByteCode.Linker
|
| 62 | 63 | import GHC.ByteCode.Asm
|
| 63 | 64 | import GHC.ByteCode.Types
|
| ... | ... | @@ -124,7 +125,9 @@ import GHC.Utils.Exception |
| 124 | 125 | import GHC.Unit.Home.Graph (lookupHug, unitEnv_foldWithKey)
|
| 125 | 126 | import GHC.Driver.Downsweep
|
| 126 | 127 | import qualified GHC.Runtime.Interpreter as GHCi
|
| 127 | -import Data.Array.Base (numElements)
|
|
| 128 | +import qualified Data.IntMap.Strict as IM
|
|
| 129 | +import qualified Data.Map.Strict as M
|
|
| 130 | +import Foreign.Ptr (nullPtr)
|
|
| 128 | 131 | |
| 129 | 132 | -- Note [Linkers and loaders]
|
| 130 | 133 | -- ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1666,10 +1669,10 @@ allocateBreakArrays :: |
| 1666 | 1669 | IO (ModuleEnv (ForeignRef BreakArray))
|
| 1667 | 1670 | allocateBreakArrays interp =
|
| 1668 | 1671 | foldlM
|
| 1669 | - ( \be0 InternalModBreaks{imodBreaks_modBreaks=ModBreaks {..}} -> do
|
|
| 1672 | + ( \be0 InternalModBreaks{imodBreaks_breakInfo, imodBreaks_modBreaks=ModBreaks {..}} -> do
|
|
| 1670 | 1673 | -- If no BreakArray is assigned to this module yet, create one
|
| 1671 | 1674 | if not $ elemModuleEnv modBreaks_module be0 then do
|
| 1672 | - let count = numElements modBreaks_locs
|
|
| 1675 | + let count = 1 + (maybe 0 fst $ IM.lookupMax imodBreaks_breakInfo)
|
|
| 1673 | 1676 | breakArray <- GHCi.newBreakArray interp count
|
| 1674 | 1677 | evaluate $ extendModuleEnv be0 modBreaks_module breakArray
|
| 1675 | 1678 | else
|
| ... | ... | @@ -1679,29 +1682,53 @@ allocateBreakArrays interp = |
| 1679 | 1682 | -- | Given a list of 'InternalModBreaks' collected from a list
|
| 1680 | 1683 | -- of 'CompiledByteCode', allocate the 'CostCentre' arrays when profiling is
|
| 1681 | 1684 | -- enabled.
|
| 1685 | +--
|
|
| 1686 | +-- Note that the resulting arrays are indexed by 'BreakInfoIndex' (internal
|
|
| 1687 | +-- breakpoint index), not by tick index
|
|
| 1682 | 1688 | allocateCCS ::
|
| 1683 | 1689 | Interp ->
|
| 1684 | - ModuleEnv (Array BreakTickIndex (RemotePtr CostCentre)) ->
|
|
| 1690 | + ModuleEnv (Array BreakInfoIndex (RemotePtr CostCentre)) ->
|
|
| 1685 | 1691 | [InternalModBreaks] ->
|
| 1686 | - IO (ModuleEnv (Array BreakTickIndex (RemotePtr CostCentre)))
|
|
| 1692 | + IO (ModuleEnv (Array BreakInfoIndex (RemotePtr CostCentre)))
|
|
| 1687 | 1693 | allocateCCS interp ce mbss
|
| 1688 | - | interpreterProfiled interp =
|
|
| 1689 | - foldlM
|
|
| 1690 | - ( \ce0 InternalModBreaks{imodBreaks_modBreaks=ModBreaks {..}} -> do
|
|
| 1691 | - ccs <-
|
|
| 1694 | + | interpreterProfiled interp = do
|
|
| 1695 | + -- 1. Create a mapping from source BreakpointId to CostCentre ptr
|
|
| 1696 | + ccss <- M.unions <$> mapM
|
|
| 1697 | + ( \InternalModBreaks{imodBreaks_modBreaks=ModBreaks{..}} -> do
|
|
| 1698 | + ccs <- {- one ccs ptr per tick index -}
|
|
| 1692 | 1699 | mkCostCentres
|
| 1693 | 1700 | interp
|
| 1694 | 1701 | (moduleNameString $ moduleName modBreaks_module)
|
| 1695 | 1702 | (elems modBreaks_ccs)
|
| 1696 | - if not $ elemModuleEnv modBreaks_module ce0 then do
|
|
| 1697 | - evaluate $
|
|
| 1698 | - extendModuleEnv ce0 modBreaks_module $
|
|
| 1699 | - listArray
|
|
| 1700 | - (0, length ccs - 1)
|
|
| 1701 | - ccs
|
|
| 1703 | + return $ M.fromList $
|
|
| 1704 | + zipWith (\el ix -> (BreakpointId modBreaks_module ix, el)) ccs [0..]
|
|
| 1705 | + )
|
|
| 1706 | + mbss
|
|
| 1707 | + -- 2. Create an array with one element for every InternalBreakpointId,
|
|
| 1708 | + -- where every element has the CCS for the corresponding BreakpointId
|
|
| 1709 | + foldlM
|
|
| 1710 | + (\ce0 InternalModBreaks{imodBreaks_breakInfo, imodBreaks_modBreaks=ModBreaks{..}} -> do
|
|
| 1711 | + if not $ elemModuleEnv modBreaks_module ce then do
|
|
| 1712 | + let count = 1 + (maybe 0 fst $ IM.lookupMax imodBreaks_breakInfo)
|
|
| 1713 | + let ccs = IM.map
|
|
| 1714 | + (\info ->
|
|
| 1715 | + case cgb_tick_id info of
|
|
| 1716 | + Right bi -> fromMaybe (toRemotePtr nullPtr)
|
|
| 1717 | + (M.lookup bi ccss)
|
|
| 1718 | + Left InternalBreakLoc{} -> toRemotePtr nullPtr
|
|
| 1719 | + )
|
|
| 1720 | + imodBreaks_breakInfo
|
|
| 1721 | + assertPpr (count == length ccs)
|
|
| 1722 | + (text "expected CgBreakInfo map to have one entry per valid ix") $
|
|
| 1723 | + evaluate $
|
|
| 1724 | + extendModuleEnv ce0 modBreaks_module $
|
|
| 1725 | + listArray
|
|
| 1726 | + (0, count)
|
|
| 1727 | + (IM.elems ccs)
|
|
| 1702 | 1728 | else
|
| 1703 | 1729 | return ce0
|
| 1704 | 1730 | )
|
| 1705 | 1731 | ce
|
| 1706 | 1732 | mbss
|
| 1733 | + |
|
| 1707 | 1734 | | otherwise = pure ce |
| ... | ... | @@ -31,6 +31,9 @@ import GHC.Unit.Module.ModSummary |
| 31 | 31 | import GHC.Utils.Outputable
|
| 32 | 32 | import GHC.Utils.Panic
|
| 33 | 33 | import qualified GHC.Data.Strict as Strict
|
| 34 | +import qualified Data.IntMap.Strict as IntMap
|
|
| 35 | +import qualified GHC.Unit.Home.Graph as HUG
|
|
| 36 | +import qualified GHC.Unit.Home.PackageTable as HPT
|
|
| 34 | 37 | |
| 35 | 38 | --------------------------------------------------------------------------------
|
| 36 | 39 | -- Finding Module breakpoints
|
| ... | ... | @@ -213,6 +216,50 @@ getModBreak m = do |
| 213 | 216 | mod_info <- fromMaybe (panic "getModBreak") <$> getModuleInfo m
|
| 214 | 217 | pure $ imodBreaks_modBreaks <$> modInfoModBreaks mod_info
|
| 215 | 218 | |
| 219 | +--------------------------------------------------------------------------------
|
|
| 220 | +-- Mapping source-level BreakpointIds to IBI occurrences
|
|
| 221 | +-- (See Note [Breakpoint identifiers])
|
|
| 222 | +--------------------------------------------------------------------------------
|
|
| 223 | + |
|
| 224 | +-- | A source-level breakpoint may have been inlined into many occurrences, now
|
|
| 225 | +-- referred by 'InternalBreakpointId'. When a breakpoint is set on a certain
|
|
| 226 | +-- source breakpoint, it means all *ocurrences* of that breakpoint across
|
|
| 227 | +-- modules should be stopped at -- hence we keep a trie from BreakpointId to
|
|
| 228 | +-- the list of internal break ids using it.
|
|
| 229 | +-- See also Note [Breakpoint identifiers]
|
|
| 230 | +type BreakpointOccurrences = ModuleEnv (IntMap.IntMap [InternalBreakpointId])
|
|
| 231 | + |
|
| 232 | +-- | Lookup all InternalBreakpointIds matching the given BreakpointId
|
|
| 233 | +-- Nothing if BreakpointId not in map
|
|
| 234 | +lookupBreakpointOccurrences :: BreakpointOccurrences -> BreakpointId -> Maybe [InternalBreakpointId]
|
|
| 235 | +lookupBreakpointOccurrences bmp (BreakpointId md tick) =
|
|
| 236 | + lookupModuleEnv bmp md >>= IntMap.lookup tick
|
|
| 237 | + |
|
| 238 | +-- | Construct a mapping from Source 'BreakpointId's to 'InternalBreakpointId's from the given list of 'ModInfo's
|
|
| 239 | +mkBreakpointOccurrences :: forall m. GhcMonad m => m BreakpointOccurrences
|
|
| 240 | +mkBreakpointOccurrences = do
|
|
| 241 | + hug <- hsc_HUG <$> getSession
|
|
| 242 | + liftIO $ foldr go (pure emptyModuleEnv) hug
|
|
| 243 | + where
|
|
| 244 | + go :: HUG.HomeUnitEnv -> IO BreakpointOccurrences -> IO BreakpointOccurrences
|
|
| 245 | + go hue mbmp = do
|
|
| 246 | + bmp <- mbmp
|
|
| 247 | + ibrkss <- HPT.concatHpt (\hmi -> maybeToList (getModBreaks hmi))
|
|
| 248 | + (HUG.homeUnitEnv_hpt hue)
|
|
| 249 | + return $ foldr addBreakToMap bmp ibrkss
|
|
| 250 | + |
|
| 251 | + addBreakToMap :: InternalModBreaks -> BreakpointOccurrences -> BreakpointOccurrences
|
|
| 252 | + addBreakToMap ibrks bmp0 = do
|
|
| 253 | + let imod = modBreaks_module $ imodBreaks_modBreaks ibrks
|
|
| 254 | + IntMap.foldrWithKey (\info_ix cgi bmp -> do
|
|
| 255 | + let ibi = InternalBreakpointId imod info_ix
|
|
| 256 | + case cgb_tick_id cgi of
|
|
| 257 | + Right (BreakpointId tick_mod tick_ix)
|
|
| 258 | + -> extendModuleEnvWith (IntMap.unionWith (S.<>)) bmp tick_mod (IntMap.singleton tick_ix [ibi])
|
|
| 259 | + Left _
|
|
| 260 | + -> bmp
|
|
| 261 | + ) bmp0 (imodBreaks_breakInfo ibrks)
|
|
| 262 | + |
|
| 216 | 263 | --------------------------------------------------------------------------------
|
| 217 | 264 | -- Getting current breakpoint information
|
| 218 | 265 | --------------------------------------------------------------------------------
|
| ... | ... | @@ -235,9 +282,15 @@ getCurrentBreakSpan = do |
| 235 | 282 | getCurrentBreakModule :: GhcMonad m => m (Maybe Module)
|
| 236 | 283 | getCurrentBreakModule = do
|
| 237 | 284 | resumes <- getResumeContext
|
| 238 | - return $ case resumes of
|
|
| 239 | - [] -> Nothing
|
|
| 285 | + hug <- hsc_HUG <$> getSession
|
|
| 286 | + liftIO $ case resumes of
|
|
| 287 | + [] -> pure Nothing
|
|
| 240 | 288 | (r:_) -> case resumeHistoryIx r of
|
| 241 | - 0 -> ibi_tick_mod <$> resumeBreakpointId r
|
|
| 242 | - ix -> Just $ getHistoryModule $ resumeHistory r !! (ix-1)
|
|
| 289 | + 0 -> case resumeBreakpointId r of
|
|
| 290 | + Nothing -> pure Nothing
|
|
| 291 | + Just ibi -> do
|
|
| 292 | + brks <- readIModBreaks hug ibi
|
|
| 293 | + return $ Just $ getBreakSourceMod ibi brks
|
|
| 294 | + ix ->
|
|
| 295 | + Just <$> getHistoryModule hug (resumeHistory r !! (ix-1))
|
|
| 243 | 296 |
| ... | ... | @@ -18,7 +18,7 @@ module GHC.Runtime.Eval ( |
| 18 | 18 | abandon, abandonAll,
|
| 19 | 19 | getResumeContext,
|
| 20 | 20 | getHistorySpan,
|
| 21 | - getModBreaks, readModBreaks,
|
|
| 21 | + getModBreaks, readIModBreaks, readIModModBreaks,
|
|
| 22 | 22 | getHistoryModule,
|
| 23 | 23 | setupBreakpoint,
|
| 24 | 24 | back, forward,
|
| ... | ... | @@ -147,14 +147,17 @@ getResumeContext = withSession (return . ic_resume . hsc_IC) |
| 147 | 147 | mkHistory :: HUG.HomeUnitGraph -> ForeignHValue -> InternalBreakpointId -> IO History
|
| 148 | 148 | mkHistory hug hval ibi = History hval ibi <$> findEnclosingDecls hug ibi
|
| 149 | 149 | |
| 150 | -getHistoryModule :: History -> Module
|
|
| 151 | -getHistoryModule = ibi_tick_mod . historyBreakpointId
|
|
| 150 | +getHistoryModule :: HUG.HomeUnitGraph -> History -> IO Module
|
|
| 151 | +getHistoryModule hug hist = do
|
|
| 152 | + let ibi = historyBreakpointId hist
|
|
| 153 | + brks <- readIModBreaks hug ibi
|
|
| 154 | + return $ getBreakSourceMod ibi brks
|
|
| 152 | 155 | |
| 153 | 156 | getHistorySpan :: HUG.HomeUnitGraph -> History -> IO SrcSpan
|
| 154 | 157 | getHistorySpan hug hist = do
|
| 155 | 158 | let ibi = historyBreakpointId hist
|
| 156 | - brks <- readModBreaks hug (ibi_tick_mod ibi)
|
|
| 157 | - return $ getBreakLoc ibi brks
|
|
| 159 | + brks <- readIModBreaks hug ibi
|
|
| 160 | + getBreakLoc (readIModModBreaks hug) ibi brks
|
|
| 158 | 161 | |
| 159 | 162 | {- | Finds the enclosing top level function name -}
|
| 160 | 163 | -- ToDo: a better way to do this would be to keep hold of the decl_path computed
|
| ... | ... | @@ -162,8 +165,8 @@ getHistorySpan hug hist = do |
| 162 | 165 | -- for each tick.
|
| 163 | 166 | findEnclosingDecls :: HUG.HomeUnitGraph -> InternalBreakpointId -> IO [String]
|
| 164 | 167 | findEnclosingDecls hug ibi = do
|
| 165 | - brks <- readModBreaks hug (ibi_tick_mod ibi)
|
|
| 166 | - return $ getBreakDecls ibi brks
|
|
| 168 | + brks <- readIModBreaks hug ibi
|
|
| 169 | + getBreakDecls (readIModModBreaks hug) ibi brks
|
|
| 167 | 170 | |
| 168 | 171 | -- | Update fixity environment in the current interactive context.
|
| 169 | 172 | updateFixityEnv :: GhcMonad m => FixityEnv -> m ()
|
| ... | ... | @@ -350,15 +353,14 @@ handleRunStatus step expr bindings final_ids status history0 = do |
| 350 | 353 | EvalBreak apStack_ref (Just eval_break) resume_ctxt ccs -> do
|
| 351 | 354 | let ibi = evalBreakpointToId eval_break
|
| 352 | 355 | let hug = hsc_HUG hsc_env
|
| 353 | - tick_brks <- liftIO $ readModBreaks hug (ibi_tick_mod ibi)
|
|
| 354 | - let
|
|
| 355 | - span = getBreakLoc ibi tick_brks
|
|
| 356 | - decl = intercalate "." $ getBreakDecls ibi tick_brks
|
|
| 356 | + info_brks <- liftIO $ readIModBreaks hug ibi
|
|
| 357 | + span <- liftIO $ getBreakLoc (readIModModBreaks hug) ibi info_brks
|
|
| 358 | + decl <- liftIO $ intercalate "." <$> getBreakDecls (readIModModBreaks hug) ibi info_brks
|
|
| 357 | 359 | |
| 358 | 360 | -- Was this breakpoint explicitly enabled (ie. in @BreakArray@)?
|
| 359 | 361 | bactive <- liftIO $ do
|
| 360 | - breakArray <- getBreakArray interp (toBreakpointId ibi) tick_brks
|
|
| 361 | - breakpointStatus interp breakArray (ibi_tick_index ibi)
|
|
| 362 | + breakArray <- getBreakArray interp ibi info_brks
|
|
| 363 | + breakpointStatus interp breakArray (ibi_info_index ibi)
|
|
| 362 | 364 | |
| 363 | 365 | apStack_fhv <- liftIO $ mkFinalizedHValue interp apStack_ref
|
| 364 | 366 | resume_ctxt_fhv <- liftIO $ mkFinalizedHValue interp resume_ctxt
|
| ... | ... | @@ -446,7 +448,7 @@ resumeExec step mbCnt |
| 446 | 448 | -- When the user specified a break ignore count, set it
|
| 447 | 449 | -- in the interpreter
|
| 448 | 450 | case (mb_brkpt, mbCnt) of
|
| 449 | - (Just brkpt, Just cnt) -> setupBreakpoint interp (toBreakpointId brkpt) cnt
|
|
| 451 | + (Just brkpt, Just cnt) -> setupBreakpoint interp brkpt cnt
|
|
| 450 | 452 | _ -> return ()
|
| 451 | 453 | |
| 452 | 454 | let eval_opts = initEvalOpts dflags (enableGhcStepMode step)
|
| ... | ... | @@ -462,17 +464,18 @@ resumeExec step mbCnt |
| 462 | 464 | | otherwise -> pure prevHistoryLst
|
| 463 | 465 | handleRunStatus step expr bindings final_ids status =<< hist'
|
| 464 | 466 | |
| 465 | -setupBreakpoint :: GhcMonad m => Interp -> BreakpointId -> Int -> m () -- #19157
|
|
| 466 | -setupBreakpoint interp bi cnt = do
|
|
| 467 | +setupBreakpoint :: GhcMonad m => Interp -> InternalBreakpointId -> Int -> m () -- #19157
|
|
| 468 | +setupBreakpoint interp ibi cnt = do
|
|
| 467 | 469 | hug <- hsc_HUG <$> getSession
|
| 468 | - modBreaks <- liftIO $ readModBreaks hug (bi_tick_mod bi)
|
|
| 469 | - breakArray <- liftIO $ getBreakArray interp bi modBreaks
|
|
| 470 | - liftIO $ GHCi.storeBreakpoint interp breakArray (bi_tick_index bi) cnt
|
|
| 470 | + liftIO $ do
|
|
| 471 | + modBreaks <- readIModBreaks hug ibi
|
|
| 472 | + breakArray <- getBreakArray interp ibi modBreaks
|
|
| 473 | + GHCi.storeBreakpoint interp breakArray (ibi_info_index ibi) cnt
|
|
| 471 | 474 | |
| 472 | -getBreakArray :: Interp -> BreakpointId -> InternalModBreaks -> IO (ForeignRef BreakArray)
|
|
| 473 | -getBreakArray interp BreakpointId{bi_tick_mod} imbs = do
|
|
| 475 | +getBreakArray :: Interp -> InternalBreakpointId -> InternalModBreaks -> IO (ForeignRef BreakArray)
|
|
| 476 | +getBreakArray interp InternalBreakpointId{ibi_info_mod} imbs = do
|
|
| 474 | 477 | breaks0 <- linked_breaks . fromMaybe (panic "Loader not initialised") <$> getLoaderState interp
|
| 475 | - case lookupModuleEnv (breakarray_env breaks0) bi_tick_mod of
|
|
| 478 | + case lookupModuleEnv (breakarray_env breaks0) ibi_info_mod of
|
|
| 476 | 479 | Just ba -> return ba
|
| 477 | 480 | Nothing -> do
|
| 478 | 481 | modifyLoaderState interp $ \ld_st -> do
|
| ... | ... | @@ -483,13 +486,12 @@ getBreakArray interp BreakpointId{bi_tick_mod} imbs = do |
| 483 | 486 | ba_env <- allocateBreakArrays interp (breakarray_env lb) [imbs]
|
| 484 | 487 | |
| 485 | 488 | let ld_st' = ld_st { linked_breaks = lb{breakarray_env = ba_env} }
|
| 486 | - let ba = expectJust {- just computed -} $ lookupModuleEnv ba_env bi_tick_mod
|
|
| 489 | + let ba = expectJust {- just computed -} $ lookupModuleEnv ba_env ibi_info_mod
|
|
| 487 | 490 | |
| 488 | 491 | return
|
| 489 | 492 | ( ld_st'
|
| 490 | 493 | , ba
|
| 491 | 494 | )
|
| 492 | - |
|
| 493 | 495 | back :: GhcMonad m => Int -> m ([Name], Int, SrcSpan)
|
| 494 | 496 | back n = moveHist (+n)
|
| 495 | 497 | |
| ... | ... | @@ -517,8 +519,9 @@ moveHist fn = do |
| 517 | 519 | span <- case mb_info of
|
| 518 | 520 | Nothing -> return $ mkGeneralSrcSpan (fsLit "<unknown>")
|
| 519 | 521 | Just ibi -> liftIO $ do
|
| 520 | - brks <- readModBreaks (hsc_HUG hsc_env) (ibi_tick_mod ibi)
|
|
| 521 | - return $ getBreakLoc ibi brks
|
|
| 522 | + let hug = hsc_HUG hsc_env
|
|
| 523 | + brks <- readIModBreaks hug ibi
|
|
| 524 | + getBreakLoc (readIModModBreaks hug) ibi brks
|
|
| 522 | 525 | (hsc_env1, names) <-
|
| 523 | 526 | liftIO $ bindLocalsAtBreakpoint hsc_env apStack span mb_info
|
| 524 | 527 | let ic = hsc_IC hsc_env1
|
| ... | ... | @@ -579,11 +582,10 @@ bindLocalsAtBreakpoint hsc_env apStack span Nothing = do |
| 579 | 582 | -- of the breakpoint and the free variables of the expression.
|
| 580 | 583 | bindLocalsAtBreakpoint hsc_env apStack_fhv span (Just ibi) = do
|
| 581 | 584 | let hug = hsc_HUG hsc_env
|
| 582 | - info_brks <- readModBreaks hug (ibi_info_mod ibi)
|
|
| 583 | - tick_brks <- readModBreaks hug (ibi_tick_mod ibi)
|
|
| 584 | - let info = getInternalBreak ibi (info_brks)
|
|
| 585 | + info_brks <- readIModBreaks hug ibi
|
|
| 586 | + let info = getInternalBreak ibi info_brks
|
|
| 585 | 587 | interp = hscInterp hsc_env
|
| 586 | - occs = getBreakVars ibi tick_brks
|
|
| 588 | + occs <- getBreakVars (readIModModBreaks hug) ibi info_brks
|
|
| 587 | 589 | |
| 588 | 590 | -- Rehydrate to understand the breakpoint info relative to the current environment.
|
| 589 | 591 | -- This design is critical to preventing leaks (#22530)
|
| ... | ... | @@ -27,7 +27,9 @@ module GHC.Runtime.Interpreter |
| 27 | 27 | , getClosure
|
| 28 | 28 | , whereFrom
|
| 29 | 29 | , getModBreaks
|
| 30 | - , readModBreaks
|
|
| 30 | + , readIModBreaks
|
|
| 31 | + , readIModBreaksMaybe
|
|
| 32 | + , readIModModBreaks
|
|
| 31 | 33 | , seqHValue
|
| 32 | 34 | , evalBreakpointToId
|
| 33 | 35 | |
| ... | ... | @@ -92,7 +94,6 @@ import GHC.Utils.Fingerprint |
| 92 | 94 | |
| 93 | 95 | import GHC.Unit.Module
|
| 94 | 96 | import GHC.Unit.Home.ModInfo
|
| 95 | -import GHC.Unit.Home.Graph (lookupHugByModule)
|
|
| 96 | 97 | import GHC.Unit.Env
|
| 97 | 98 | |
| 98 | 99 | #if defined(HAVE_INTERNAL_INTERPRETER)
|
| ... | ... | @@ -411,15 +412,10 @@ evalBreakpointToId :: EvalBreakpoint -> InternalBreakpointId |
| 411 | 412 | evalBreakpointToId eval_break =
|
| 412 | 413 | let
|
| 413 | 414 | mkUnitId u = fsToUnit $ mkFastStringShortByteString u
|
| 414 | - |
|
| 415 | 415 | toModule u n = mkModule (mkUnitId u) (mkModuleName n)
|
| 416 | - tickl = toModule (eb_tick_mod_unit eval_break) (eb_tick_mod eval_break)
|
|
| 417 | - infol = toModule (eb_info_mod_unit eval_break) (eb_info_mod eval_break)
|
|
| 418 | 416 | in
|
| 419 | 417 | InternalBreakpointId
|
| 420 | - { ibi_tick_mod = tickl
|
|
| 421 | - , ibi_tick_index = eb_tick_index eval_break
|
|
| 422 | - , ibi_info_mod = infol
|
|
| 418 | + { ibi_info_mod = toModule (eb_info_mod_unit eval_break) (eb_info_mod eval_break)
|
|
| 423 | 419 | , ibi_info_index = eb_info_index eval_break
|
| 424 | 420 | }
|
| 425 | 421 | |
| ... | ... | @@ -440,17 +436,18 @@ handleSeqHValueStatus interp unit_env eval_status = |
| 440 | 436 | -- Reason: Setting of flags in libraries/ghci/GHCi/Run.hs:evalOptsSeq
|
| 441 | 437 | |
| 442 | 438 | Just break -> do
|
| 443 | - let bi = evalBreakpointToId break
|
|
| 439 | + let ibi = evalBreakpointToId break
|
|
| 440 | + hug = ue_home_unit_graph unit_env
|
|
| 444 | 441 | |
| 445 | 442 | -- Just case: Stopped at a breakpoint, extract SrcSpan information
|
| 446 | 443 | -- from the breakpoint.
|
| 447 | - mb_modbreaks <- getModBreaks . expectJust <$>
|
|
| 448 | - lookupHugByModule (ibi_tick_mod bi) (ue_home_unit_graph unit_env)
|
|
| 444 | + mb_modbreaks <- readIModBreaksMaybe hug (ibi_info_mod ibi)
|
|
| 449 | 445 | case mb_modbreaks of
|
| 450 | 446 | -- Nothing case - should not occur! We should have the appropriate
|
| 451 | 447 | -- breakpoint information
|
| 452 | 448 | Nothing -> nothing_case
|
| 453 | - Just modbreaks -> put $ brackets . ppr $ getBreakLoc bi modbreaks
|
|
| 449 | + Just modbreaks -> put . brackets . ppr =<<
|
|
| 450 | + getBreakLoc (readIModModBreaks hug) ibi modbreaks
|
|
| 454 | 451 | |
| 455 | 452 | -- resume the seq (:force) processing in the iserv process
|
| 456 | 453 | withForeignRef resume_ctxt_fhv $ \hval -> do
|
| ... | ... | @@ -745,10 +742,18 @@ getModBreaks hmi |
| 745 | 742 | | otherwise
|
| 746 | 743 | = Nothing -- probably object code
|
| 747 | 744 | |
| 748 | --- | Read the 'InternalModBreaks' and 'ModBreaks' of the given home 'Module'
|
|
| 749 | --- from the 'HomeUnitGraph'.
|
|
| 750 | -readModBreaks :: HomeUnitGraph -> Module -> IO InternalModBreaks
|
|
| 751 | -readModBreaks hug modl = expectJust . getModBreaks . expectJust <$> HUG.lookupHugByModule modl hug
|
|
| 745 | +-- | Read the 'InternalModBreaks' of the given home 'Module' (via
|
|
| 746 | +-- 'InternalBreakpointId') from the 'HomeUnitGraph'.
|
|
| 747 | +readIModBreaks :: HomeUnitGraph -> InternalBreakpointId -> IO InternalModBreaks
|
|
| 748 | +readIModBreaks hug ibi = expectJust <$> readIModBreaksMaybe hug (ibi_info_mod ibi)
|
|
| 749 | + |
|
| 750 | +-- | Read the 'InternalModBreaks' of the given home 'Module' from the 'HomeUnitGraph'.
|
|
| 751 | +readIModBreaksMaybe :: HomeUnitGraph -> Module -> IO (Maybe InternalModBreaks)
|
|
| 752 | +readIModBreaksMaybe hug mod = getModBreaks . expectJust <$> HUG.lookupHugByModule mod hug
|
|
| 753 | + |
|
| 754 | +-- | Read the 'ModBreaks' from the given module's 'InternalModBreaks'
|
|
| 755 | +readIModModBreaks :: HUG.HomeUnitGraph -> Module -> IO ModBreaks
|
|
| 756 | +readIModModBreaks hug mod = imodBreaks_modBreaks . expectJust <$> readIModBreaksMaybe hug mod
|
|
| 752 | 757 | |
| 753 | 758 | -- -----------------------------------------------------------------------------
|
| 754 | 759 | -- Misc utils
|
| ... | ... | @@ -31,7 +31,6 @@ import GHC.Cmm.Utils |
| 31 | 31 | import GHC.Platform
|
| 32 | 32 | import GHC.Platform.Profile
|
| 33 | 33 | |
| 34 | -import GHC.Runtime.Interpreter
|
|
| 35 | 34 | import GHCi.FFI
|
| 36 | 35 | import GHC.Types.Basic
|
| 37 | 36 | import GHC.Utils.Outputable
|
| ... | ... | @@ -64,6 +63,7 @@ import GHC.StgToCmm.Closure ( NonVoid(..), fromNonVoid, idPrimRepU, |
| 64 | 63 | assertNonVoidIds, assertNonVoidStgArgs )
|
| 65 | 64 | import GHC.StgToCmm.Layout
|
| 66 | 65 | import GHC.Runtime.Heap.Layout hiding (WordOff, ByteOff, wordsToBytes)
|
| 66 | +import GHC.Runtime.Interpreter ( interpreterProfiled, readIModModBreaks )
|
|
| 67 | 67 | import GHC.Data.Bitmap
|
| 68 | 68 | import GHC.Data.FlatBag as FlatBag
|
| 69 | 69 | import GHC.Data.OrdList
|
| ... | ... | @@ -79,7 +79,6 @@ import Control.Monad |
| 79 | 79 | import Data.Char
|
| 80 | 80 | |
| 81 | 81 | import GHC.Unit.Module
|
| 82 | -import qualified GHC.Unit.Home.Graph as HUG
|
|
| 83 | 82 | |
| 84 | 83 | import Data.Coerce (coerce)
|
| 85 | 84 | #if MIN_VERSION_rts(1,0,3)
|
| ... | ... | @@ -100,6 +99,7 @@ import GHC.CoreToIface |
| 100 | 99 | import Control.Monad.IO.Class
|
| 101 | 100 | import Control.Monad.Trans.Reader (ReaderT(..))
|
| 102 | 101 | import Control.Monad.Trans.State (StateT(..))
|
| 102 | +import Data.Array ((!))
|
|
| 103 | 103 | |
| 104 | 104 | -- -----------------------------------------------------------------------------
|
| 105 | 105 | -- Generating byte code for a complete module
|
| ... | ... | @@ -394,65 +394,32 @@ schemeR_wrk fvs nm original_body (args, body) |
| 394 | 394 | -- | Introduce break instructions for ticked expressions.
|
| 395 | 395 | -- If no breakpoint information is available, the instruction is omitted.
|
| 396 | 396 | schemeER_wrk :: StackDepth -> BCEnv -> CgStgExpr -> BcM BCInstrList
|
| 397 | -schemeER_wrk d p (StgTick (Breakpoint tick_ty (BreakpointId tick_mod tick_no) fvs) rhs) = do
|
|
| 398 | - code <- schemeE d 0 p rhs
|
|
| 399 | - hsc_env <- getHscEnv
|
|
| 400 | - current_mod <- getCurrentModule
|
|
| 401 | - mb_current_mod_breaks <- getCurrentModBreaks
|
|
| 402 | - case mb_current_mod_breaks of
|
|
| 403 | - -- if we're not generating ModBreaks for this module for some reason, we
|
|
| 404 | - -- can't store breakpoint occurrence information.
|
|
| 405 | - Nothing -> pure code
|
|
| 406 | - Just current_mod_breaks -> break_info hsc_env tick_mod current_mod mb_current_mod_breaks >>= \case
|
|
| 407 | - Nothing -> pure code
|
|
| 408 | - Just ModBreaks{modBreaks_module = tick_mod} -> do
|
|
| 409 | - platform <- profilePlatform <$> getProfile
|
|
| 410 | - let idOffSets = getVarOffSets platform d p fvs
|
|
| 411 | - ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
|
|
| 412 | - toWord :: Maybe (Id, WordOff) -> Maybe (Id, Word)
|
|
| 413 | - toWord = fmap (\(i, wo) -> (i, fromIntegral wo))
|
|
| 414 | - breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty
|
|
| 415 | - |
|
| 416 | - let info_mod = modBreaks_module current_mod_breaks
|
|
| 417 | - infox <- newBreakInfo breakInfo
|
|
| 397 | +schemeER_wrk d p (StgTick bp@(Breakpoint tick_ty tick_id fvs) rhs) = do
|
|
| 398 | + platform <- profilePlatform <$> getProfile
|
|
| 399 | + |
|
| 400 | + code <- case rhs of
|
|
| 401 | + -- When we find a tick surrounding a case expression we introduce a new BRK_FUN
|
|
| 402 | + -- instruction at the start of the case *continuation*, in addition to the
|
|
| 403 | + -- usual BRK_FUN surrounding the StgCase)
|
|
| 404 | + -- See Note [TODO]
|
|
| 405 | + StgCase scrut bndr _ alts
|
|
| 406 | + -> doCase d 0 p (Just bp) scrut bndr alts
|
|
| 407 | + _ -> schemeE d 0 p rhs
|
|
| 408 | + |
|
| 409 | + let idOffSets = getVarOffSets platform d p fvs
|
|
| 410 | + ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
|
|
| 411 | + toWord :: Maybe (Id, WordOff) -> Maybe (Id, Word)
|
|
| 412 | + toWord = fmap (\(i, wo) -> (i, fromIntegral wo))
|
|
| 413 | + breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty (Right tick_id)
|
|
| 414 | + |
|
| 415 | + mibi <- newBreakInfo breakInfo
|
|
| 416 | + |
|
| 417 | + return $ case mibi of
|
|
| 418 | + Nothing -> code
|
|
| 419 | + Just ibi -> BRK_FUN ibi 0 `consOL` code
|
|
| 418 | 420 | |
| 419 | - let breakInstr = BRK_FUN (InternalBreakpointId tick_mod tick_no info_mod infox)
|
|
| 420 | - return $ breakInstr `consOL` code
|
|
| 421 | 421 | schemeER_wrk d p rhs = schemeE d 0 p rhs
|
| 422 | 422 | |
| 423 | --- | Determine the GHCi-allocated 'BreakArray' and module pointer for the module
|
|
| 424 | --- from which the breakpoint originates.
|
|
| 425 | --- These are stored in 'ModBreaks' as remote pointers in order to allow the BCOs
|
|
| 426 | --- to refer to pointers in GHCi's address space.
|
|
| 427 | --- They are initialized in 'GHC.HsToCore.Breakpoints.mkModBreaks', called by
|
|
| 428 | --- 'GHC.HsToCore.deSugar'.
|
|
| 429 | ---
|
|
| 430 | --- Breakpoints might be disabled because we're in TH, because
|
|
| 431 | --- @-fno-break-points@ was specified, or because a module was reloaded without
|
|
| 432 | --- reinitializing 'ModBreaks'.
|
|
| 433 | ---
|
|
| 434 | --- If the module stored in the breakpoint is the currently processed module, use
|
|
| 435 | --- the 'ModBreaks' from the state.
|
|
| 436 | --- If that is 'Nothing', consider breakpoints to be disabled and skip the
|
|
| 437 | --- instruction.
|
|
| 438 | ---
|
|
| 439 | --- If the breakpoint is inlined from another module, look it up in the HUG (home unit graph).
|
|
| 440 | --- If the module doesn't exist there, or if the 'ModBreaks' value is
|
|
| 441 | --- uninitialized, skip the instruction (i.e. return Nothing).
|
|
| 442 | -break_info ::
|
|
| 443 | - HscEnv ->
|
|
| 444 | - Module ->
|
|
| 445 | - Module ->
|
|
| 446 | - Maybe ModBreaks ->
|
|
| 447 | - BcM (Maybe ModBreaks)
|
|
| 448 | -break_info hsc_env mod current_mod current_mod_breaks
|
|
| 449 | - | mod == current_mod
|
|
| 450 | - = pure current_mod_breaks
|
|
| 451 | - | otherwise
|
|
| 452 | - = liftIO (HUG.lookupHugByModule mod (hsc_HUG hsc_env)) >>= \case
|
|
| 453 | - Just hp -> pure $ imodBreaks_modBreaks <$> getModBreaks hp
|
|
| 454 | - Nothing -> pure Nothing
|
|
| 455 | - |
|
| 456 | 423 | getVarOffSets :: Platform -> StackDepth -> BCEnv -> [Id] -> [Maybe (Id, WordOff)]
|
| 457 | 424 | getVarOffSets platform depth env = map getOffSet
|
| 458 | 425 | where
|
| ... | ... | @@ -652,7 +619,7 @@ schemeE d s p (StgTick _ rhs) = schemeE d s p rhs |
| 652 | 619 | schemeE d s p (StgCase scrut _ _ []) = schemeE d s p scrut
|
| 653 | 620 | |
| 654 | 621 | schemeE d s p (StgCase scrut bndr _ alts)
|
| 655 | - = doCase d s p scrut bndr alts
|
|
| 622 | + = doCase d s p Nothing scrut bndr alts
|
|
| 656 | 623 | |
| 657 | 624 | |
| 658 | 625 | {-
|
| ... | ... | @@ -1144,11 +1111,15 @@ doCase |
| 1144 | 1111 | :: StackDepth
|
| 1145 | 1112 | -> Sequel
|
| 1146 | 1113 | -> BCEnv
|
| 1114 | + -> Maybe StgTickish
|
|
| 1115 | + -- ^ The breakpoint surrounding the full case expression, if any (only
|
|
| 1116 | + -- source-level cases get breakpoint ticks, and those are the only we care
|
|
| 1117 | + -- about). See Note [TODO]
|
|
| 1147 | 1118 | -> CgStgExpr
|
| 1148 | 1119 | -> Id
|
| 1149 | 1120 | -> [CgStgAlt]
|
| 1150 | 1121 | -> BcM BCInstrList
|
| 1151 | -doCase d s p scrut bndr alts
|
|
| 1122 | +doCase d s p m_bid scrut bndr alts
|
|
| 1152 | 1123 | = do
|
| 1153 | 1124 | profile <- getProfile
|
| 1154 | 1125 | hsc_env <- getHscEnv
|
| ... | ... | @@ -1209,12 +1180,12 @@ doCase d s p scrut bndr alts |
| 1209 | 1180 | |
| 1210 | 1181 | -- depth of stack after the return value has been pushed
|
| 1211 | 1182 | d_bndr =
|
| 1212 | - d + ret_frame_size_b + bndr_size
|
|
| 1183 | + d + bndr_size
|
|
| 1213 | 1184 | |
| 1214 | 1185 | -- depth of stack after the extra info table for an unlifted return
|
| 1215 | 1186 | -- has been pushed, if any. This is the stack depth at the
|
| 1216 | 1187 | -- continuation.
|
| 1217 | - d_alts = d + ret_frame_size_b + bndr_size + unlifted_itbl_size_b
|
|
| 1188 | + d_alts = d + bndr_size + unlifted_itbl_size_b
|
|
| 1218 | 1189 | |
| 1219 | 1190 | -- Env in which to compile the alts, not including
|
| 1220 | 1191 | -- any vars bound by the alts themselves
|
| ... | ... | @@ -1365,11 +1336,28 @@ doCase d s p scrut bndr alts |
| 1365 | 1336 | let alt_final1
|
| 1366 | 1337 | | ubx_tuple_frame = SLIDE 0 2 `consOL` alt_final0
|
| 1367 | 1338 | | otherwise = alt_final0
|
| 1368 | - alt_final
|
|
| 1369 | - | gopt Opt_InsertBreakpoints (hsc_dflags hsc_env)
|
|
| 1370 | - -- See Note [Debugger: BRK_ALTS]
|
|
| 1371 | - = BRK_ALTS False `consOL` alt_final1
|
|
| 1372 | - | otherwise = alt_final1
|
|
| 1339 | + |
|
| 1340 | + alt_final <- case m_bid of
|
|
| 1341 | + Just (Breakpoint tick_ty tick_id fvs)
|
|
| 1342 | + | gopt Opt_InsertBreakpoints (hsc_dflags hsc_env)
|
|
| 1343 | + -- Construct an internal breakpoint to put at the start of this case
|
|
| 1344 | + -- continuation BCO.
|
|
| 1345 | + -- See Note [TODO]
|
|
| 1346 | + -> do
|
|
| 1347 | + internal_tick_loc <- makeCaseInternalBreakLoc tick_id
|
|
| 1348 | + |
|
| 1349 | + -- same fvs available in the case expression are available in the case continuation
|
|
| 1350 | + let idOffSets = getVarOffSets platform d p fvs
|
|
| 1351 | + ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
|
|
| 1352 | + toWord :: Maybe (Id, WordOff) -> Maybe (Id, Word)
|
|
| 1353 | + toWord = fmap (\(i, wo) -> (i, fromIntegral wo))
|
|
| 1354 | + breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty (Left internal_tick_loc)
|
|
| 1355 | + |
|
| 1356 | + mibi <- newBreakInfo breakInfo
|
|
| 1357 | + return $ case mibi of
|
|
| 1358 | + Nothing -> alt_final1
|
|
| 1359 | + Just ibi -> {- BRK_FUN ibi (d_alts - d) `consOL` -} alt_final1
|
|
| 1360 | + _ -> pure alt_final1
|
|
| 1373 | 1361 | |
| 1374 | 1362 | add_bco_name <- shouldAddBcoName
|
| 1375 | 1363 | let
|
| ... | ... | @@ -1389,6 +1377,24 @@ doCase d s p scrut bndr alts |
| 1389 | 1377 | _ -> panic "schemeE(StgCase).push_alts"
|
| 1390 | 1378 | in return (PUSH_ALTS alt_bco scrut_rep `consOL` scrut_code)
|
| 1391 | 1379 | |
| 1380 | +makeCaseInternalBreakLoc :: BreakpointId -> BcM InternalBreakLoc
|
|
| 1381 | +makeCaseInternalBreakLoc bid = do
|
|
| 1382 | + hug <- hsc_HUG <$> getHscEnv
|
|
| 1383 | + curr_mod <- getCurrentModule
|
|
| 1384 | + mb_mod_brks <- getCurrentModBreaks
|
|
| 1385 | + |
|
| 1386 | + -- TODO: Subtract the scrutinee loc from the case loc to get continuation loc
|
|
| 1387 | + InternalBreakLoc <$> case bid of
|
|
| 1388 | + BreakpointId{bi_tick_mod, bi_tick_index}
|
|
| 1389 | + | bi_tick_mod == curr_mod
|
|
| 1390 | + , Just these_mbs <- mb_mod_brks
|
|
| 1391 | + -> do
|
|
| 1392 | + return $ modBreaks_locs these_mbs ! bi_tick_index
|
|
| 1393 | + | otherwise
|
|
| 1394 | + -> do
|
|
| 1395 | + other_mbs <- liftIO $ readIModModBreaks hug bi_tick_mod
|
|
| 1396 | + return $ modBreaks_locs other_mbs ! bi_tick_index
|
|
| 1397 | + |
|
| 1392 | 1398 | {-
|
| 1393 | 1399 | Note [Debugger: BRK_ALTS]
|
| 1394 | 1400 | ~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1756,6 +1762,10 @@ tupleBCO platform args_info args = |
| 1756 | 1762 | with using a fake name here. We will need to change this if we want
|
| 1757 | 1763 | to save some memory by sharing the BCO between places that have
|
| 1758 | 1764 | the same tuple shape
|
| 1765 | + |
|
| 1766 | + ROMES:TODO: This seems like it would have a pretty good impact.
|
|
| 1767 | + Looking at examples like UnboxedTuple.hs shows many occurrences of the
|
|
| 1768 | + same tuple_BCO
|
|
| 1759 | 1769 | -}
|
| 1760 | 1770 | invented_name = mkSystemVarName (mkPseudoUniqueE 0) (fsLit "tuple")
|
| 1761 | 1771 | |
| ... | ... | @@ -2705,14 +2715,19 @@ getLabelsBc n = BcM $ \_ st -> |
| 2705 | 2715 | let ctr = nextlabel st
|
| 2706 | 2716 | in return (coerce [ctr .. ctr+n-1], st{nextlabel = ctr+n})
|
| 2707 | 2717 | |
| 2708 | -newBreakInfo :: CgBreakInfo -> BcM Int
|
|
| 2709 | -newBreakInfo info = BcM $ \_ st ->
|
|
| 2710 | - let ix = breakInfoIdx st
|
|
| 2711 | - st' = st
|
|
| 2712 | - { breakInfo = IntMap.insert ix info (breakInfo st)
|
|
| 2713 | - , breakInfoIdx = ix + 1
|
|
| 2714 | - }
|
|
| 2715 | - in return (ix, st')
|
|
| 2718 | +newBreakInfo :: CgBreakInfo -> BcM (Maybe InternalBreakpointId)
|
|
| 2719 | +newBreakInfo info = BcM $ \env st -> do
|
|
| 2720 | + -- if we're not generating ModBreaks for this module for some reason, we
|
|
| 2721 | + -- can't store breakpoint occurrence information.
|
|
| 2722 | + case modBreaks env of
|
|
| 2723 | + Nothing -> pure (Nothing, st)
|
|
| 2724 | + Just modBreaks -> do
|
|
| 2725 | + let ix = breakInfoIdx st
|
|
| 2726 | + st' = st
|
|
| 2727 | + { breakInfo = IntMap.insert ix info (breakInfo st)
|
|
| 2728 | + , breakInfoIdx = ix + 1
|
|
| 2729 | + }
|
|
| 2730 | + return (Just $ InternalBreakpointId (modBreaks_module modBreaks) ix, st')
|
|
| 2716 | 2731 | |
| 2717 | 2732 | getCurrentModule :: BcM Module
|
| 2718 | 2733 | getCurrentModule = BcM $ \env st -> return (bcm_module env, st)
|
| ... | ... | @@ -2722,3 +2737,14 @@ getCurrentModBreaks = BcM $ \env st -> return (modBreaks env, st) |
| 2722 | 2737 | |
| 2723 | 2738 | tickFS :: FastString
|
| 2724 | 2739 | tickFS = fsLit "ticked"
|
| 2740 | + |
|
| 2741 | +-- Dehydrating CgBreakInfo
|
|
| 2742 | + |
|
| 2743 | +dehydrateCgBreakInfo :: [TyVar] -> [Maybe (Id, Word)] -> Type -> Either InternalBreakLoc BreakpointId -> CgBreakInfo
|
|
| 2744 | +dehydrateCgBreakInfo ty_vars idOffSets tick_ty bid =
|
|
| 2745 | + CgBreakInfo
|
|
| 2746 | + { cgb_tyvars = map toIfaceTvBndr ty_vars
|
|
| 2747 | + , cgb_vars = map (fmap (\(i, offset) -> (toIfaceIdBndr i, offset))) idOffSets
|
|
| 2748 | + , cgb_resty = toIfaceType tick_ty
|
|
| 2749 | + , cgb_tick_id = bid
|
|
| 2750 | + } |
| 1 | 1 | {-# LANGUAGE NamedFieldPuns #-}
|
| 2 | +{-# LANGUAGE CPP #-}
|
|
| 2 | 3 | module Main where
|
| 3 | 4 | |
| 4 | 5 | import Distribution.Simple
|
| ... | ... | @@ -12,6 +13,8 @@ import Distribution.Simple.Program |
| 12 | 13 | import Distribution.Simple.Utils
|
| 13 | 14 | import Distribution.Simple.Setup
|
| 14 | 15 | import Distribution.Simple.PackageIndex
|
| 16 | +import qualified Distribution.Simple.LocalBuildInfo as LBI
|
|
| 17 | + |
|
| 15 | 18 | |
| 16 | 19 | import System.IO
|
| 17 | 20 | import System.Process
|
| ... | ... | @@ -59,8 +62,9 @@ primopIncls = |
| 59 | 62 | ghcAutogen :: Verbosity -> LocalBuildInfo -> IO ()
|
| 60 | 63 | ghcAutogen verbosity lbi@LocalBuildInfo{pkgDescrFile,withPrograms,componentNameMap,installedPkgs}
|
| 61 | 64 | = do
|
| 65 | + let i = LBI.interpretSymbolicPathLBI lbi
|
|
| 62 | 66 | -- Get compiler/ root directory from the cabal file
|
| 63 | - let Just compilerRoot = takeDirectory <$> pkgDescrFile
|
|
| 67 | + let Just compilerRoot = takeDirectory . i <$> pkgDescrFile
|
|
| 64 | 68 | |
| 65 | 69 | -- Require the necessary programs
|
| 66 | 70 | (gcc ,withPrograms) <- requireProgram normal gccProgram withPrograms
|
| ... | ... | @@ -80,15 +84,19 @@ ghcAutogen verbosity lbi@LocalBuildInfo{pkgDescrFile,withPrograms,componentNameM |
| 80 | 84 | -- Call genprimopcode to generate *.hs-incl
|
| 81 | 85 | forM_ primopIncls $ \(file,command) -> do
|
| 82 | 86 | contents <- readProcess "genprimopcode" [command] primopsStr
|
| 83 | - rewriteFileEx verbosity (buildDir lbi </> file) contents
|
|
| 87 | + rewriteFileEx verbosity (i (buildDir lbi) </> file) contents
|
|
| 84 | 88 | |
| 85 | 89 | -- Write GHC.Platform.Constants
|
| 86 | - let platformConstantsPath = autogenPackageModulesDir lbi </> "GHC/Platform/Constants.hs"
|
|
| 90 | + let platformConstantsPath = i (autogenPackageModulesDir lbi) </> "GHC/Platform/Constants.hs"
|
|
| 87 | 91 | targetOS = case lookup "target os" settings of
|
| 88 | 92 | Nothing -> error "no target os in settings"
|
| 89 | 93 | Just os -> os
|
| 90 | 94 | createDirectoryIfMissingVerbose verbosity True (takeDirectory platformConstantsPath)
|
| 95 | +#if MIN_VERSION_Cabal(3,14,0)
|
|
| 96 | + withTempFile "Constants_tmp.hs" $ \tmp h -> do
|
|
| 97 | +#else
|
|
| 91 | 98 | withTempFile (takeDirectory platformConstantsPath) "Constants_tmp.hs" $ \tmp h -> do
|
| 99 | +#endif
|
|
| 92 | 100 | hClose h
|
| 93 | 101 | callProcess "deriveConstants" ["--gen-haskell-type","-o",tmp,"--target-os",targetOS]
|
| 94 | 102 | renameFile tmp platformConstantsPath
|
| ... | ... | @@ -103,7 +111,7 @@ ghcAutogen verbosity lbi@LocalBuildInfo{pkgDescrFile,withPrograms,componentNameM |
| 103 | 111 | _ -> error "Couldn't find unique ghc-internal library when building ghc"
|
| 104 | 112 | |
| 105 | 113 | -- Write GHC.Settings.Config
|
| 106 | - configHsPath = autogenPackageModulesDir lbi </> "GHC/Settings/Config.hs"
|
|
| 114 | + configHsPath = i (autogenPackageModulesDir lbi) </> "GHC/Settings/Config.hs"
|
|
| 107 | 115 | configHs = generateConfigHs cProjectUnitId cGhcInternalUnitId settings
|
| 108 | 116 | createDirectoryIfMissingVerbose verbosity True (takeDirectory configHsPath)
|
| 109 | 117 | rewriteFileEx verbosity configHsPath configHs
|
| ... | ... | @@ -50,7 +50,7 @@ extra-source-files: |
| 50 | 50 | |
| 51 | 51 | |
| 52 | 52 | custom-setup
|
| 53 | - setup-depends: base >= 3 && < 5, Cabal >= 1.6 && <3.14, directory, process, filepath, containers
|
|
| 53 | + setup-depends: base >= 3 && < 5, Cabal >= 1.6 && <3.16, directory, process, filepath, containers
|
|
| 54 | 54 | |
| 55 | 55 | Flag internal-interpreter
|
| 56 | 56 | Description: Build with internal interpreter support.
|
| ... | ... | @@ -779,9 +779,9 @@ the total time spent profiling. |
| 779 | 779 | Cost-centre break-down
|
| 780 | 780 | ^^^^^^^^^^^^^^^^^^^^^^
|
| 781 | 781 | |
| 782 | -A variable-length packet encoding a heap profile sample broken down by,
|
|
| 783 | - * cost-centre (:rts-flag:`-hc`)
|
|
| 784 | - |
|
| 782 | +A variable-length packet encoding a heap profile sample.
|
|
| 783 | +This event is only emitted when the heap profile type is set to :rts-flag:`-hc` or :rts-flag:`-hb`.
|
|
| 784 | +Otherwise, a :event-type:`HEAP_PROF_SAMPLE_STRING` event is emitted instead.
|
|
| 785 | 785 | |
| 786 | 786 | .. event-type:: HEAP_PROF_SAMPLE_COST_CENTRE
|
| 787 | 787 | |
| ... | ... | @@ -796,11 +796,19 @@ A variable-length packet encoding a heap profile sample broken down by, |
| 796 | 796 | String break-down
|
| 797 | 797 | ^^^^^^^^^^^^^^^^^
|
| 798 | 798 | |
| 799 | -A variable-length event encoding a heap sample broken down by,
|
|
| 799 | +A variable-length event encoding a heap sample.
|
|
| 800 | +The content of the sample label varies depending on the heap profile type:
|
|
| 801 | + |
|
| 802 | + * :rts-flag:`-hT` The sample label contains a closure type, e.g., ``"ghc-bignum:GHC.Num.Integer.IS"``.
|
|
| 803 | + * :rts-flag:`-hm` The sample label contains a module name, e.g., ``"GHC.Num.Integer"``.
|
|
| 804 | + * :rts-flag:`-hd` The sample label contains a closure description, e.g., ``"IS"``.
|
|
| 805 | + * :rts-flag:`-hy` The sample label contains a type description, e.g., ``"Integer"``.
|
|
| 806 | + * :rts-flag:`-he` The sample label contains a stringified era, e.g., ``"1"``.
|
|
| 807 | + * :rts-flag:`-hr` The sample label contains a retainer set description, e.g., ``"(184)$stoIntegralSized1"``.
|
|
| 808 | + * :rts-flag:`-hi` The sample label contains a stringified pointer, e.g., ``"0x1008b7588"``,
|
|
| 809 | + which can be matched to an info table description emitted by the :event-type:`IPE` event.
|
|
| 800 | 810 | |
| 801 | - * type description (:rts-flag:`-hy`)
|
|
| 802 | - * closure description (:rts-flag:`-hd`)
|
|
| 803 | - * module (:rts-flag:`-hm`)
|
|
| 811 | +If the heap profile type is set to :rts-flag:`-hc` or :rts-flag:`-hb`, a :event-type:`HEAP_PROF_SAMPLE_COST_CENTRE` event is emitted instead.
|
|
| 804 | 812 | |
| 805 | 813 | .. event-type:: HEAP_PROF_SAMPLE_STRING
|
| 806 | 814 | |
| ... | ... | @@ -808,7 +816,7 @@ A variable-length event encoding a heap sample broken down by, |
| 808 | 816 | :length: variable
|
| 809 | 817 | :field Word8: profile ID
|
| 810 | 818 | :field Word64: heap residency in bytes
|
| 811 | - :field String: type or closure description, or module name
|
|
| 819 | + :field String: sample label
|
|
| 812 | 820 | |
| 813 | 821 | .. _time-profiler-events:
|
| 814 | 822 |
| ... | ... | @@ -45,7 +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 | +import GHC.ByteCode.Breakpoints (imodBreaks_modBreaks, InternalBreakpointId(..), getBreakSourceId, getBreakSourceMod)
|
|
| 49 | 49 | import GHC.Runtime.Interpreter
|
| 50 | 50 | import GHCi.RemoteTypes
|
| 51 | 51 | import GHCi.BreakArray( breakOn, breakOff )
|
| ... | ... | @@ -68,7 +68,7 @@ import GHC ( LoadHowMuch(..), Target(..), TargetId(..), |
| 68 | 68 | Resume, SingleStep, Ghc,
|
| 69 | 69 | GetDocsFailure(..), pushLogHookM,
|
| 70 | 70 | getModuleGraph, handleSourceError,
|
| 71 | - InternalBreakpointId(..) )
|
|
| 71 | + BreakpointId(..) )
|
|
| 72 | 72 | import GHC.Driver.Main (hscParseModuleWithLocation, hscParseStmtWithLocation)
|
| 73 | 73 | import GHC.Hs.ImpExp
|
| 74 | 74 | import GHC.Hs
|
| ... | ... | @@ -546,6 +546,7 @@ interactiveUI config srcs maybe_exprs = do |
| 546 | 546 | break_ctr = 0,
|
| 547 | 547 | breaks = IntMap.empty,
|
| 548 | 548 | tickarrays = emptyModuleEnv,
|
| 549 | + internalBreaks = emptyModuleEnv,
|
|
| 549 | 550 | ghci_commands = availableCommands config,
|
| 550 | 551 | ghci_macros = [],
|
| 551 | 552 | last_command = Nothing,
|
| ... | ... | @@ -1616,13 +1617,15 @@ toBreakIdAndLocation :: GhciMonad m |
| 1616 | 1617 | toBreakIdAndLocation Nothing = return Nothing
|
| 1617 | 1618 | toBreakIdAndLocation (Just inf) = do
|
| 1618 | 1619 | st <- getGHCiState
|
| 1620 | + hug <- hsc_HUG <$> GHC.getSession
|
|
| 1621 | + brks <- liftIO $ readIModBreaks hug inf
|
|
| 1622 | + let bi = getBreakSourceId inf brks
|
|
| 1619 | 1623 | return $ listToMaybe [ id_loc | id_loc@(_,loc) <- IntMap.assocs (breaks st),
|
| 1620 | - breakModule loc == ibi_tick_mod inf,
|
|
| 1621 | - breakTick loc == ibi_tick_index inf ]
|
|
| 1624 | + Right (breakId loc) == bi ]
|
|
| 1622 | 1625 | |
| 1623 | 1626 | printStoppedAtBreakInfo :: GHC.GhcMonad m => Resume -> [Name] -> m ()
|
| 1624 | 1627 | printStoppedAtBreakInfo res names = do
|
| 1625 | - printForUser $ pprStopped res
|
|
| 1628 | + printForUser =<< pprStopped res
|
|
| 1626 | 1629 | -- printTypeOfNames session names
|
| 1627 | 1630 | let namesSorted = sortBy compareNames names
|
| 1628 | 1631 | tythings <- catMaybes `liftM` mapM GHC.lookupName namesSorted
|
| ... | ... | @@ -3804,22 +3807,32 @@ showBkptTable = do |
| 3804 | 3807 | showContext :: GHC.GhcMonad m => m ()
|
| 3805 | 3808 | showContext = do
|
| 3806 | 3809 | resumes <- GHC.getResumeContext
|
| 3807 | - printForUser $ vcat (map pp_resume (reverse resumes))
|
|
| 3810 | + docs <- mapM pp_resume (reverse resumes)
|
|
| 3811 | + printForUser $ vcat docs
|
|
| 3808 | 3812 | where
|
| 3809 | - pp_resume res =
|
|
| 3810 | - text "--> " <> text (GHC.resumeStmt res)
|
|
| 3811 | - $$ nest 2 (pprStopped res)
|
|
| 3812 | - |
|
| 3813 | -pprStopped :: GHC.Resume -> SDoc
|
|
| 3814 | -pprStopped res =
|
|
| 3815 | - text "Stopped in"
|
|
| 3816 | - <+> ((case mb_mod_name of
|
|
| 3817 | - Nothing -> empty
|
|
| 3818 | - Just mod_name -> ftext (moduleNameFS mod_name) <> char '.')
|
|
| 3819 | - <> text (GHC.resumeDecl res))
|
|
| 3820 | - <> char ',' <+> ppr (GHC.resumeSpan res)
|
|
| 3821 | - where
|
|
| 3822 | - mb_mod_name = moduleName <$> ibi_tick_mod <$> GHC.resumeBreakpointId res
|
|
| 3813 | + pp_resume res = do
|
|
| 3814 | + stopped <- pprStopped res
|
|
| 3815 | + return $
|
|
| 3816 | + text "--> " <> text (GHC.resumeStmt res)
|
|
| 3817 | + $$ nest 2 stopped
|
|
| 3818 | + |
|
| 3819 | +pprStopped :: GHC.GhcMonad m => GHC.Resume -> m SDoc
|
|
| 3820 | +pprStopped res = do
|
|
| 3821 | + let mibi = GHC.resumeBreakpointId res
|
|
| 3822 | + mb_mod_name <- case mibi of
|
|
| 3823 | + Nothing -> pure Nothing
|
|
| 3824 | + Just ibi -> do
|
|
| 3825 | + hug <- hsc_HUG <$> GHC.getSession
|
|
| 3826 | + brks <- liftIO $ readIModBreaks hug ibi
|
|
| 3827 | + return $ Just $ moduleName $
|
|
| 3828 | + getBreakSourceMod ibi brks
|
|
| 3829 | + return $
|
|
| 3830 | + text "Stopped in"
|
|
| 3831 | + <+> ((case mb_mod_name of
|
|
| 3832 | + Nothing -> empty
|
|
| 3833 | + Just mod_name -> ftext (moduleNameFS mod_name) <> char '.')
|
|
| 3834 | + <> text (GHC.resumeDecl res))
|
|
| 3835 | + <> char ',' <+> ppr (GHC.resumeSpan res)
|
|
| 3823 | 3836 | |
| 3824 | 3837 | showUnits :: GHC.GhcMonad m => m ()
|
| 3825 | 3838 | showUnits = mapNonInteractiveHomeUnitsM $ \dflags -> do
|
| ... | ... | @@ -4373,12 +4386,8 @@ ignoreCmd argLine = withSandboxOnly ":ignore" $ do |
| 4373 | 4386 | result <- ignoreSwitch (words argLine)
|
| 4374 | 4387 | case result of
|
| 4375 | 4388 | Left sdoc -> printForUser sdoc
|
| 4376 | - Right (loc, count) -> do
|
|
| 4377 | - let bi = GHC.BreakpointId
|
|
| 4378 | - { bi_tick_mod = breakModule loc
|
|
| 4379 | - , bi_tick_index = breakTick loc
|
|
| 4380 | - }
|
|
| 4381 | - setupBreakpoint bi count
|
|
| 4389 | + Right (loc, count) -> do
|
|
| 4390 | + setupBreakpoint (breakId loc) count
|
|
| 4382 | 4391 | |
| 4383 | 4392 | ignoreSwitch :: GhciMonad m => [String] -> m (Either SDoc (BreakLocation, Int))
|
| 4384 | 4393 | ignoreSwitch [break, count] = do
|
| ... | ... | @@ -4395,10 +4404,13 @@ getIgnoreCount str = |
| 4395 | 4404 | where
|
| 4396 | 4405 | sdocIgnore = text "Ignore count" <+> quotes (text str)
|
| 4397 | 4406 | |
| 4398 | -setupBreakpoint :: GhciMonad m => GHC.BreakpointId -> Int -> m()
|
|
| 4399 | -setupBreakpoint loc count = do
|
|
| 4407 | +setupBreakpoint :: GhciMonad m => GHC.BreakpointId -> Int -> m ()
|
|
| 4408 | +setupBreakpoint bi count = do
|
|
| 4400 | 4409 | hsc_env <- GHC.getSession
|
| 4401 | - GHC.setupBreakpoint (hscInterp hsc_env) loc count
|
|
| 4410 | + -- Trigger all internal breaks that match this source break id
|
|
| 4411 | + internal_break_ids <- getInternalBreaksOf bi
|
|
| 4412 | + forM_ internal_break_ids $ \ibi -> do
|
|
| 4413 | + GHC.setupBreakpoint (hscInterp hsc_env) ibi count
|
|
| 4402 | 4414 | |
| 4403 | 4415 | backCmd :: GhciMonad m => String -> m ()
|
| 4404 | 4416 | backCmd arg
|
| ... | ... | @@ -4489,20 +4501,20 @@ findBreakAndSet md lookupTickTree = do |
| 4489 | 4501 | some -> mapM_ breakAt some
|
| 4490 | 4502 | where
|
| 4491 | 4503 | breakAt (tick, pan) = do
|
| 4492 | - setBreakFlag md tick True
|
|
| 4493 | - (alreadySet, nm) <-
|
|
| 4494 | - recordBreak $ BreakLocation
|
|
| 4495 | - { breakModule = md
|
|
| 4496 | - , breakLoc = RealSrcSpan pan Strict.Nothing
|
|
| 4497 | - , breakTick = tick
|
|
| 4498 | - , onBreakCmd = ""
|
|
| 4499 | - , breakEnabled = True
|
|
| 4500 | - }
|
|
| 4501 | - printForUser $
|
|
| 4502 | - text "Breakpoint " <> ppr nm <>
|
|
| 4503 | - if alreadySet
|
|
| 4504 | - then text " was already set at " <> ppr pan
|
|
| 4505 | - else text " activated at " <> ppr pan
|
|
| 4504 | + let bi = BreakpointId md tick
|
|
| 4505 | + setBreakFlag bi True
|
|
| 4506 | + (alreadySet, nm) <-
|
|
| 4507 | + recordBreak $ BreakLocation
|
|
| 4508 | + { breakLoc = RealSrcSpan pan Strict.Nothing
|
|
| 4509 | + , breakId = bi
|
|
| 4510 | + , onBreakCmd = ""
|
|
| 4511 | + , breakEnabled = True
|
|
| 4512 | + }
|
|
| 4513 | + printForUser $
|
|
| 4514 | + text "Breakpoint " <> ppr nm <>
|
|
| 4515 | + if alreadySet
|
|
| 4516 | + then text " was already set at " <> ppr pan
|
|
| 4517 | + else text " activated at " <> ppr pan
|
|
| 4506 | 4518 | |
| 4507 | 4519 | -- For now, use ANSI bold on terminals that we know support it.
|
| 4508 | 4520 | -- Otherwise, we add a line of carets under the active expression instead.
|
| ... | ... | @@ -4749,14 +4761,32 @@ turnBreakOnOff :: GhciMonad m => Bool -> BreakLocation -> m BreakLocation |
| 4749 | 4761 | turnBreakOnOff onOff loc
|
| 4750 | 4762 | | onOff == breakEnabled loc = return loc
|
| 4751 | 4763 | | otherwise = do
|
| 4752 | - setBreakFlag (breakModule loc) (breakTick loc) onOff
|
|
| 4764 | + setBreakFlag (breakId loc) onOff
|
|
| 4753 | 4765 | return loc { breakEnabled = onOff }
|
| 4754 | 4766 | |
| 4755 | -setBreakFlag :: GhciMonad m => Module -> Int -> Bool ->m ()
|
|
| 4756 | -setBreakFlag md ix enaDisa = do
|
|
| 4767 | +setBreakFlag :: GhciMonad m => GHC.BreakpointId -> Bool -> m ()
|
|
| 4768 | +setBreakFlag (BreakpointId md ix) enaDisa = do
|
|
| 4757 | 4769 | let enaDisaToCount True = breakOn
|
| 4758 | 4770 | enaDisaToCount False = breakOff
|
| 4759 | - setupBreakpoint (GHC.BreakpointId md ix) $ enaDisaToCount enaDisa
|
|
| 4771 | + setupBreakpoint (BreakpointId md ix) $ enaDisaToCount enaDisa
|
|
| 4772 | + |
|
| 4773 | +-- --------------------------------------------------------------------------
|
|
| 4774 | +-- Find matching Internal Breakpoints
|
|
| 4775 | + |
|
| 4776 | +-- | Find all the internal breakpoints that use the given source-level breakpoint id
|
|
| 4777 | +getInternalBreaksOf :: GhciMonad m => BreakpointId -> m [InternalBreakpointId]
|
|
| 4778 | +getInternalBreaksOf bi = do
|
|
| 4779 | + st <- getGHCiState
|
|
| 4780 | + let ibrks = internalBreaks st
|
|
| 4781 | + case lookupBreakpointOccurrences ibrks bi of
|
|
| 4782 | + Just bs -> return bs
|
|
| 4783 | + Nothing -> do
|
|
| 4784 | + -- Refresh the internal breakpoints map
|
|
| 4785 | + bs <- mkBreakpointOccurrences
|
|
| 4786 | + setGHCiState st{internalBreaks = bs}
|
|
| 4787 | + return $
|
|
| 4788 | + fromMaybe [] {- still not found after refresh -} $
|
|
| 4789 | + lookupBreakpointOccurrences bs bi
|
|
| 4760 | 4790 | |
| 4761 | 4791 | -- ---------------------------------------------------------------------------
|
| 4762 | 4792 | -- User code exception handling
|
| ... | ... | @@ -100,6 +100,14 @@ data GHCiState = GHCiState |
| 100 | 100 | -- ^ 'tickarrays' caches the 'TickArray' for loaded modules,
|
| 101 | 101 | -- so that we don't rebuild it each time the user sets
|
| 102 | 102 | -- a breakpoint.
|
| 103 | + |
|
| 104 | + internalBreaks :: BreakpointOccurrences,
|
|
| 105 | + -- ^ Keep a mapping from the source-level 'BreakpointId' to the
|
|
| 106 | + -- occurrences of that breakpoint across modules.
|
|
| 107 | + -- When we want to stop at a source 'BreakpointId', we essentially
|
|
| 108 | + -- trigger a breakpoint for all 'InternalBreakpointId's matching
|
|
| 109 | + -- the same source-id.
|
|
| 110 | + |
|
| 103 | 111 | ghci_commands :: [Command],
|
| 104 | 112 | -- ^ available ghci commands
|
| 105 | 113 | ghci_macros :: [Command],
|
| ... | ... | @@ -238,16 +246,15 @@ data LocalConfigBehaviour |
| 238 | 246 | |
| 239 | 247 | data BreakLocation
|
| 240 | 248 | = BreakLocation
|
| 241 | - { breakModule :: !GHC.Module
|
|
| 242 | - , breakLoc :: !SrcSpan
|
|
| 243 | - , breakTick :: {-# UNPACK #-} !Int
|
|
| 249 | + { breakLoc :: !SrcSpan
|
|
| 250 | + , breakId :: !GHC.BreakpointId
|
|
| 251 | + -- ^ The 'BreakpointId' uniquely identifies a source-level breakpoint
|
|
| 244 | 252 | , breakEnabled:: !Bool
|
| 245 | 253 | , onBreakCmd :: String
|
| 246 | 254 | }
|
| 247 | 255 | |
| 248 | 256 | instance Eq BreakLocation where
|
| 249 | - loc1 == loc2 = breakModule loc1 == breakModule loc2 &&
|
|
| 250 | - breakTick loc1 == breakTick loc2
|
|
| 257 | + loc1 == loc2 = breakId loc1 == breakId loc2
|
|
| 251 | 258 | |
| 252 | 259 | prettyLocations :: IntMap.IntMap BreakLocation -> SDoc
|
| 253 | 260 | prettyLocations locs =
|
| ... | ... | @@ -256,7 +263,7 @@ prettyLocations locs = |
| 256 | 263 | False -> vcat $ map (\(i, loc) -> brackets (int i) <+> ppr loc) $ IntMap.toAscList locs
|
| 257 | 264 | |
| 258 | 265 | instance Outputable BreakLocation where
|
| 259 | - ppr loc = (ppr $ breakModule loc) <+> ppr (breakLoc loc) <+> pprEnaDisa <+>
|
|
| 266 | + ppr loc = (ppr $ GHC.bi_tick_mod $ breakId loc) <+> ppr (breakLoc loc) <+> pprEnaDisa <+>
|
|
| 260 | 267 | if null (onBreakCmd loc)
|
| 261 | 268 | then empty
|
| 262 | 269 | else doubleQuotes (text (onBreakCmd loc))
|
| ... | ... | @@ -10,6 +10,7 @@ import Distribution.Verbosity |
| 10 | 10 | import Distribution.Simple.Program
|
| 11 | 11 | import Distribution.Simple.Utils
|
| 12 | 12 | import Distribution.Simple.Setup
|
| 13 | +import qualified Distribution.Simple.LocalBuildInfo as LBI
|
|
| 13 | 14 | |
| 14 | 15 | import System.IO
|
| 15 | 16 | import System.Directory
|
| ... | ... | @@ -32,12 +33,13 @@ main = defaultMainWithHooks ghcHooks |
| 32 | 33 | ghcAutogen :: Verbosity -> LocalBuildInfo -> IO ()
|
| 33 | 34 | ghcAutogen verbosity lbi@LocalBuildInfo{..} = do
|
| 34 | 35 | -- Get compiler/ root directory from the cabal file
|
| 35 | - let Just compilerRoot = takeDirectory <$> pkgDescrFile
|
|
| 36 | + let Just compilerRoot = takeDirectory . i <$> pkgDescrFile
|
|
| 36 | 37 | |
| 37 | - let platformHostFile = "GHC/Platform/Host.hs"
|
|
| 38 | - platformHostPath = autogenPackageModulesDir lbi </> platformHostFile
|
|
| 38 | + i = LBI.interpretSymbolicPathLBI lbi
|
|
| 39 | + platformHostFile = "GHC/Platform/Host.hs"
|
|
| 40 | + platformHostPath = i (autogenPackageModulesDir lbi) </> platformHostFile
|
|
| 39 | 41 | ghcVersionFile = "GHC/Version.hs"
|
| 40 | - ghcVersionPath = autogenPackageModulesDir lbi </> ghcVersionFile
|
|
| 42 | + ghcVersionPath = i (autogenPackageModulesDir lbi) </> ghcVersionFile
|
|
| 41 | 43 | |
| 42 | 44 | -- Get compiler settings
|
| 43 | 45 | settings <- lookupEnv "HADRIAN_SETTINGS" >>= \case
|
| ... | ... | @@ -28,7 +28,7 @@ build-type: Custom |
| 28 | 28 | extra-source-files: changelog.md
|
| 29 | 29 | |
| 30 | 30 | custom-setup
|
| 31 | - setup-depends: base >= 3 && < 5, Cabal >= 1.6 && <3.14, directory, filepath
|
|
| 31 | + setup-depends: base >= 3 && < 5, Cabal >= 1.6 && <3.16, directory, filepath
|
|
| 32 | 32 | |
| 33 | 33 | source-repository head
|
| 34 | 34 | type: git
|
| ... | ... | @@ -1047,7 +1047,7 @@ class Functor f where |
| 1047 | 1047 | -- * sequence computations and combine their results ('<*>' and 'liftA2').
|
| 1048 | 1048 | --
|
| 1049 | 1049 | -- A minimal complete definition must include implementations of 'pure'
|
| 1050 | +-- and one of either '<*>' or 'liftA2'. If it defines both, then they must behave
|
|
| 1050 | 1051 | -- the same as their default definitions:
|
| 1051 | 1052 | --
|
| 1052 | 1053 | -- @('<*>') = 'liftA2' 'id'@
|
| ... | ... | @@ -65,10 +65,7 @@ foreign import ccall "&rts_stop_on_exception" exceptionFlag :: Ptr CInt |
| 65 | 65 | --------------------------------------------------------------------------------
|
| 66 | 66 | |
| 67 | 67 | type BreakpointCallback
|
| 68 | - = Addr# -- pointer to the breakpoint tick module name
|
|
| 69 | - -> Addr# -- pointer to the breakpoint tick module unit id
|
|
| 70 | - -> Int# -- breakpoint tick index
|
|
| 71 | - -> Addr# -- pointer to the breakpoint info module name
|
|
| 68 | + = Addr# -- pointer to the breakpoint info module name
|
|
| 72 | 69 | -> Addr# -- pointer to the breakpoint info module unit id
|
| 73 | 70 | -> Int# -- breakpoint info index
|
| 74 | 71 | -> Bool -- exception?
|
| ... | ... | @@ -418,10 +418,7 @@ data EvalStatus_ a b |
| 418 | 418 | instance Binary a => Binary (EvalStatus_ a b)
|
| 419 | 419 | |
| 420 | 420 | data EvalBreakpoint = EvalBreakpoint
|
| 421 | - { eb_tick_mod :: String -- ^ Breakpoint tick module
|
|
| 422 | - , eb_tick_mod_unit :: BS.ShortByteString -- ^ Breakpoint tick module unit id
|
|
| 423 | - , eb_tick_index :: Int -- ^ Breakpoint tick index
|
|
| 424 | - , eb_info_mod :: String -- ^ Breakpoint info module
|
|
| 421 | + { eb_info_mod :: String -- ^ Breakpoint info module
|
|
| 425 | 422 | , eb_info_mod_unit :: BS.ShortByteString -- ^ Breakpoint tick module unit id
|
| 426 | 423 | , eb_info_index :: Int -- ^ Breakpoint info index
|
| 427 | 424 | }
|
| ... | ... | @@ -345,7 +345,7 @@ withBreakAction opts breakMVar statusMVar mtid act |
| 345 | 345 | -- as soon as it is hit, or in resetBreakAction below.
|
| 346 | 346 | |
| 347 | 347 | onBreak :: BreakpointCallback
|
| 348 | - onBreak tick_mod# tick_mod_uid# tickx# info_mod# info_mod_uid# infox# is_exception apStack = do
|
|
| 348 | + onBreak info_mod# info_mod_uid# infox# is_exception apStack = do
|
|
| 349 | 349 | tid <- myThreadId
|
| 350 | 350 | let resume = ResumeContext
|
| 351 | 351 | { resumeBreakMVar = breakMVar
|
| ... | ... | @@ -358,11 +358,9 @@ withBreakAction opts breakMVar statusMVar mtid act |
| 358 | 358 | if is_exception
|
| 359 | 359 | then pure Nothing
|
| 360 | 360 | else do
|
| 361 | - tick_mod <- peekCString (Ptr tick_mod#)
|
|
| 362 | - tick_mod_uid <- BS.packCString (Ptr tick_mod_uid#)
|
|
| 363 | 361 | info_mod <- peekCString (Ptr info_mod#)
|
| 364 | 362 | info_mod_uid <- BS.packCString (Ptr info_mod_uid#)
|
| 365 | - pure (Just (EvalBreakpoint tick_mod tick_mod_uid (I# tickx#) info_mod info_mod_uid (I# infox#)))
|
|
| 363 | + pure (Just (EvalBreakpoint info_mod info_mod_uid (I# infox#)))
|
|
| 366 | 364 | putMVar statusMVar $ EvalBreak apStack_r breakpoint resume_r ccs
|
| 367 | 365 | takeMVar breakMVar
|
| 368 | 366 | |
| ... | ... | @@ -409,8 +407,8 @@ noBreakStablePtr :: StablePtr BreakpointCallback |
| 409 | 407 | noBreakStablePtr = unsafePerformIO $ newStablePtr noBreakAction
|
| 410 | 408 | |
| 411 | 409 | noBreakAction :: BreakpointCallback
|
| 412 | -noBreakAction _ _ _ _ _ _ False _ = putStrLn "*** Ignoring breakpoint"
|
|
| 413 | -noBreakAction _ _ _ _ _ _ True _ = return () -- exception: just continue
|
|
| 410 | +noBreakAction _ _ _ False _ = putStrLn "*** Ignoring breakpoint"
|
|
| 411 | +noBreakAction _ _ _ True _ = return () -- exception: just continue
|
|
| 414 | 412 | |
| 415 | 413 | -- Malloc and copy the bytes. We don't have any way to monitor the
|
| 416 | 414 | -- lifetime of this memory, so it just leaks.
|
| ... | ... | @@ -84,16 +84,25 @@ disInstr ( StgBCO *bco, int pc ) |
| 84 | 84 | |
| 85 | 85 | |
| 86 | 86 | switch (instr & 0xff) {
|
| 87 | - case bci_BRK_FUN:
|
|
| 88 | - debugBelch ("BRK_FUN " ); printPtr( ptrs[instrs[pc]] );
|
|
| 89 | - debugBelch (" %d ", instrs[pc+1]); printPtr( ptrs[instrs[pc+2]] );
|
|
| 90 | - CostCentre* cc = (CostCentre*)literals[instrs[pc+5]];
|
|
| 87 | + case bci_BRK_FUN: {
|
|
| 88 | + W_ p1, info_mod, info_unit_id, info_wix, byte_off, np;
|
|
| 89 | + p1 = BCO_GET_LARGE_ARG;
|
|
| 90 | + info_mod = BCO_GET_LARGE_ARG;
|
|
| 91 | + info_unit_id = BCO_GET_LARGE_ARG;
|
|
| 92 | + info_wix = BCO_NEXT;
|
|
| 93 | + byte_off = BCO_NEXT;
|
|
| 94 | + np = BCO_GET_LARGE_ARG;
|
|
| 95 | + debugBelch ("BRK_FUN " ); printPtr( ptrs[p1] );
|
|
| 96 | + debugBelch(" %" FMT_Word, literals[info_mod] );
|
|
| 97 | + debugBelch(" %" FMT_Word, literals[info_unit_id] );
|
|
| 98 | + debugBelch(" %" FMT_Word, info_wix );
|
|
| 99 | + debugBelch(" %" FMT_Word, byte_off );
|
|
| 100 | + CostCentre* cc = (CostCentre*)literals[np];
|
|
| 91 | 101 | if (cc) {
|
| 92 | 102 | debugBelch(" %s", cc->label);
|
| 93 | 103 | }
|
| 94 | 104 | debugBelch("\n");
|
| 95 | - pc += 6;
|
|
| 96 | - break;
|
|
| 105 | + break; }
|
|
| 97 | 106 | case bci_BRK_ALTS:
|
| 98 | 107 | debugBelch ("BRK_ALTS %d\n", BCO_NEXT);
|
| 99 | 108 | break;
|
| ... | ... | @@ -535,23 +535,17 @@ retry_pop_stack: |
| 535 | 535 | // be per-thread.
|
| 536 | 536 | CInt[rts_stop_on_exception] = 0;
|
| 537 | 537 | ("ptr" ioAction) = ccall deRefStablePtr (W_[rts_breakpoint_io_action] "ptr");
|
| 538 | - Sp = Sp - WDS(17);
|
|
| 539 | - Sp(16) = exception;
|
|
| 540 | - Sp(15) = stg_raise_ret_info;
|
|
| 541 | - Sp(14) = exception;
|
|
| 542 | - Sp(13) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception
|
|
| 543 | - Sp(12) = stg_ap_ppv_info;
|
|
| 544 | - Sp(11) = 0;
|
|
| 545 | - Sp(10) = stg_ap_n_info;
|
|
| 546 | - Sp(9) = 0;
|
|
| 547 | - Sp(8) = stg_ap_n_info;
|
|
| 548 | - Sp(7) = 0;
|
|
| 549 | - Sp(6) = stg_ap_n_info;
|
|
| 550 | - Sp(5) = 0;
|
|
| 551 | - Sp(4) = stg_ap_n_info;
|
|
| 552 | - Sp(3) = 0;
|
|
| 553 | - Sp(2) = stg_ap_n_info;
|
|
| 554 | - Sp(1) = 0;
|
|
| 538 | + Sp = Sp - WDS(11);
|
|
| 539 | + Sp(10) = exception;
|
|
| 540 | + Sp(9) = stg_raise_ret_info;
|
|
| 541 | + Sp(8) = exception;
|
|
| 542 | + Sp(7) = ghczminternal_GHCziInternalziTypes_True_closure; // True <=> an exception
|
|
| 543 | + Sp(6) = stg_ap_ppv_info;
|
|
| 544 | + Sp(5) = 0;
|
|
| 545 | + Sp(4) = stg_ap_n_info;
|
|
| 546 | + Sp(3) = 0;
|
|
| 547 | + Sp(2) = stg_ap_n_info;
|
|
| 548 | + Sp(1) = 0;
|
|
| 555 | 549 | R1 = ioAction;
|
| 556 | 550 | jump RET_LBL(stg_ap_n) [R1];
|
| 557 | 551 | }
|
| ... | ... | @@ -207,6 +207,19 @@ See also Note [Width of parameters] for some more motivation. |
| 207 | 207 | // Perhaps confusingly this still reads a full word, merely the offset is in bytes.
|
| 208 | 208 | #define ReadSpB(n) (*((StgWord*) SafeSpBP(n)))
|
| 209 | 209 | |
| 210 | +/*
|
|
| 211 | + * SLIDE "n" words "by" words
|
|
| 212 | + * a_1 ... a_n, b_1 ... b_by, k
|
|
| 213 | + * =>
|
|
| 214 | + * a_1 ... a_n, k
|
|
| 215 | + */
|
|
| 216 | +#define SpSlide(n, by) \
|
|
| 217 | + while(n-- > 0) { \
|
|
| 218 | + SpW(n+by) = ReadSpW(n); \
|
|
| 219 | + } \
|
|
| 220 | + Sp_addW(by); \
|
|
| 221 | + |
|
| 222 | + |
|
| 210 | 223 | /* Note [PUSH_L underflow]
|
| 211 | 224 | ~~~~~~~~~~~~~~~~~~~~~~~
|
| 212 | 225 | BCOs can be nested, resulting in nested BCO stack frames where the inner most
|
| ... | ... | @@ -284,6 +297,19 @@ allocate_NONUPD (Capability *cap, int n_words) |
| 284 | 297 | return allocate(cap, stg_max(sizeofW(StgHeader)+MIN_PAYLOAD_SIZE, n_words));
|
| 285 | 298 | }
|
| 286 | 299 | |
| 300 | +STATIC_INLINE int
|
|
| 301 | +is_ctoi_nontuple_frame(const StgClosure* frame) {
|
|
| 302 | + const StgInfoTable* info = frame->header.info;
|
|
| 303 | + return (
|
|
| 304 | + (W_)info == (W_)&stg_ctoi_R1p_info ||
|
|
| 305 | + (W_)info == (W_)&stg_ctoi_R1n_info ||
|
|
| 306 | + (W_)info == (W_)&stg_ctoi_F1_info ||
|
|
| 307 | + (W_)info == (W_)&stg_ctoi_D1_info ||
|
|
| 308 | + (W_)info == (W_)&stg_ctoi_L1_info ||
|
|
| 309 | + (W_)info == (W_)&stg_ctoi_V_info
|
|
| 310 | + );
|
|
| 311 | +}
|
|
| 312 | + |
|
| 287 | 313 | int rts_stop_on_exception = 0;
|
| 288 | 314 | |
| 289 | 315 | /* ---------------------------------------------------------------------------
|
| ... | ... | @@ -473,6 +499,72 @@ void interp_shutdown( void ){ |
| 473 | 499 | |
| 474 | 500 | #endif
|
| 475 | 501 | |
| 502 | +const StgPtr ctoi_tuple_infos[] = {
|
|
| 503 | + (StgPtr) &stg_ctoi_t0_info,
|
|
| 504 | + (StgPtr) &stg_ctoi_t1_info,
|
|
| 505 | + (StgPtr) &stg_ctoi_t2_info,
|
|
| 506 | + (StgPtr) &stg_ctoi_t3_info,
|
|
| 507 | + (StgPtr) &stg_ctoi_t4_info,
|
|
| 508 | + (StgPtr) &stg_ctoi_t5_info,
|
|
| 509 | + (StgPtr) &stg_ctoi_t6_info,
|
|
| 510 | + (StgPtr) &stg_ctoi_t7_info,
|
|
| 511 | + (StgPtr) &stg_ctoi_t8_info,
|
|
| 512 | + (StgPtr) &stg_ctoi_t9_info,
|
|
| 513 | + (StgPtr) &stg_ctoi_t10_info,
|
|
| 514 | + (StgPtr) &stg_ctoi_t11_info,
|
|
| 515 | + (StgPtr) &stg_ctoi_t12_info,
|
|
| 516 | + (StgPtr) &stg_ctoi_t13_info,
|
|
| 517 | + (StgPtr) &stg_ctoi_t14_info,
|
|
| 518 | + (StgPtr) &stg_ctoi_t15_info,
|
|
| 519 | + (StgPtr) &stg_ctoi_t16_info,
|
|
| 520 | + (StgPtr) &stg_ctoi_t17_info,
|
|
| 521 | + (StgPtr) &stg_ctoi_t18_info,
|
|
| 522 | + (StgPtr) &stg_ctoi_t19_info,
|
|
| 523 | + (StgPtr) &stg_ctoi_t20_info,
|
|
| 524 | + (StgPtr) &stg_ctoi_t21_info,
|
|
| 525 | + (StgPtr) &stg_ctoi_t22_info,
|
|
| 526 | + (StgPtr) &stg_ctoi_t23_info,
|
|
| 527 | + (StgPtr) &stg_ctoi_t24_info,
|
|
| 528 | + (StgPtr) &stg_ctoi_t25_info,
|
|
| 529 | + (StgPtr) &stg_ctoi_t26_info,
|
|
| 530 | + (StgPtr) &stg_ctoi_t27_info,
|
|
| 531 | + (StgPtr) &stg_ctoi_t28_info,
|
|
| 532 | + (StgPtr) &stg_ctoi_t29_info,
|
|
| 533 | + (StgPtr) &stg_ctoi_t30_info,
|
|
| 534 | + (StgPtr) &stg_ctoi_t31_info,
|
|
| 535 | + (StgPtr) &stg_ctoi_t32_info,
|
|
| 536 | + (StgPtr) &stg_ctoi_t33_info,
|
|
| 537 | + (StgPtr) &stg_ctoi_t34_info,
|
|
| 538 | + (StgPtr) &stg_ctoi_t35_info,
|
|
| 539 | + (StgPtr) &stg_ctoi_t36_info,
|
|
| 540 | + (StgPtr) &stg_ctoi_t37_info,
|
|
| 541 | + (StgPtr) &stg_ctoi_t38_info,
|
|
| 542 | + (StgPtr) &stg_ctoi_t39_info,
|
|
| 543 | + (StgPtr) &stg_ctoi_t40_info,
|
|
| 544 | + (StgPtr) &stg_ctoi_t41_info,
|
|
| 545 | + (StgPtr) &stg_ctoi_t42_info,
|
|
| 546 | + (StgPtr) &stg_ctoi_t43_info,
|
|
| 547 | + (StgPtr) &stg_ctoi_t44_info,
|
|
| 548 | + (StgPtr) &stg_ctoi_t45_info,
|
|
| 549 | + (StgPtr) &stg_ctoi_t46_info,
|
|
| 550 | + (StgPtr) &stg_ctoi_t47_info,
|
|
| 551 | + (StgPtr) &stg_ctoi_t48_info,
|
|
| 552 | + (StgPtr) &stg_ctoi_t49_info,
|
|
| 553 | + (StgPtr) &stg_ctoi_t50_info,
|
|
| 554 | + (StgPtr) &stg_ctoi_t51_info,
|
|
| 555 | + (StgPtr) &stg_ctoi_t52_info,
|
|
| 556 | + (StgPtr) &stg_ctoi_t53_info,
|
|
| 557 | + (StgPtr) &stg_ctoi_t54_info,
|
|
| 558 | + (StgPtr) &stg_ctoi_t55_info,
|
|
| 559 | + (StgPtr) &stg_ctoi_t56_info,
|
|
| 560 | + (StgPtr) &stg_ctoi_t57_info,
|
|
| 561 | + (StgPtr) &stg_ctoi_t58_info,
|
|
| 562 | + (StgPtr) &stg_ctoi_t59_info,
|
|
| 563 | + (StgPtr) &stg_ctoi_t60_info,
|
|
| 564 | + (StgPtr) &stg_ctoi_t61_info,
|
|
| 565 | + (StgPtr) &stg_ctoi_t62_info,
|
|
| 566 | +};
|
|
| 567 | + |
|
| 476 | 568 | #if defined(PROFILING)
|
| 477 | 569 | |
| 478 | 570 | //
|
| ... | ... | @@ -619,8 +711,6 @@ interpretBCO (Capability* cap) |
| 619 | 711 | */
|
| 620 | 712 | if (cap->r.rCurrentTSO->flags & TSO_STOP_AFTER_RETURN) {
|
| 621 | 713 | |
| 622 | - StgBCO* bco;
|
|
| 623 | - StgWord16* bco_instrs;
|
|
| 624 | 714 | StgHalfWord type;
|
| 625 | 715 | |
| 626 | 716 | /* Store the entry Sp; traverse the stack modifying Sp (using Sp macros);
|
| ... | ... | @@ -640,28 +730,34 @@ interpretBCO (Capability* cap) |
| 640 | 730 | ASSERT(type == RET_BCO || type == STOP_FRAME);
|
| 641 | 731 | if (type == RET_BCO) {
|
| 642 | 732 | |
| 643 | - bco = (StgBCO*)(SpW(1)); // BCO is first arg of a RET_BCO
|
|
| 733 | + StgBCO* bco = (StgBCO*)(SpW(1)); // BCO is first arg of a RET_BCO
|
|
| 644 | 734 | ASSERT(get_itbl((StgClosure*)bco)->type == BCO);
|
| 645 | - bco_instrs = (StgWord16*)(bco->instrs->payload);
|
|
| 735 | + |
|
| 736 | + StgWord16* instrs = (StgWord16*)(bco->instrs->payload);
|
|
| 737 | + StgWord16 bci = instrs[0];
|
|
| 646 | 738 | |
| 647 | 739 | /* A breakpoint instruction (BRK_FUN or BRK_ALTS) is always the first
|
| 648 | 740 | * instruction in a BCO */
|
| 649 | - if ((bco_instrs[0] & 0xFF) == bci_BRK_FUN) {
|
|
| 650 | - int brk_array, tick_index;
|
|
| 651 | - StgArrBytes *breakPoints;
|
|
| 652 | - StgPtr* ptrs;
|
|
| 741 | + if ((bci & 0xFF) == bci_BRK_FUN) {
|
|
| 742 | + // Define rest of variables used by BCO_* Macros
|
|
| 743 | + int bciPtr = 0;
|
|
| 653 | 744 | |
| 654 | - ptrs = (StgPtr*)(&bco->ptrs->payload[0]);
|
|
| 655 | - brk_array = bco_instrs[1];
|
|
| 656 | - tick_index = bco_instrs[6];
|
|
| 745 | + W_ arg1_brk_array, arg4_info_index;
|
|
| 746 | + arg1_brk_array = BCO_GET_LARGE_ARG;
|
|
| 747 | + /* info_mod_name = */ BCO_GET_LARGE_ARG;
|
|
| 748 | + /* info_mod_id = */ BCO_GET_LARGE_ARG;
|
|
| 749 | + arg4_info_index = BCO_NEXT;
|
|
| 750 | + /* byte_off = BCO_NEXT; */
|
|
| 751 | + |
|
| 752 | + StgPtr* ptrs = (StgPtr*)(&bco->ptrs->payload[0]);
|
|
| 753 | + StgArrBytes* breakPoints = (StgArrBytes *) BCO_PTR(arg1_brk_array);
|
|
| 657 | 754 | |
| 658 | - breakPoints = (StgArrBytes *) BCO_PTR(brk_array);
|
|
| 659 | 755 | // ACTIVATE the breakpoint by tick index
|
| 660 | - ((StgInt*)breakPoints->payload)[tick_index] = 0;
|
|
| 756 | + ((StgInt*)breakPoints->payload)[arg4_info_index] = 0;
|
|
| 661 | 757 | }
|
| 662 | - else if ((bco_instrs[0] & 0xFF) == bci_BRK_ALTS) {
|
|
| 758 | + else if ((bci & 0xFF) == bci_BRK_ALTS) {
|
|
| 663 | 759 | // ACTIVATE BRK_ALTS by setting its only argument to ON
|
| 664 | - bco_instrs[1] = 1;
|
|
| 760 | + instrs[1] = 1;
|
|
| 665 | 761 | }
|
| 666 | 762 | // else: if there is no BRK instruction perhaps we should keep
|
| 667 | 763 | // traversing; that said, the continuation should always have a BRK
|
| ... | ... | @@ -776,7 +872,6 @@ eval_obj: |
| 776 | 872 | debugBelch("\n\n");
|
| 777 | 873 | );
|
| 778 | 874 | |
| 779 | -// IF_DEBUG(sanity,checkStackChunk(Sp, cap->r.rCurrentTSO->stack+cap->r.rCurrentTSO->stack_size));
|
|
| 780 | 875 | IF_DEBUG(sanity,checkStackFrame(Sp));
|
| 781 | 876 | |
| 782 | 877 | switch ( get_itbl(obj)->type ) {
|
| ... | ... | @@ -1018,11 +1113,36 @@ do_return_pointer: |
| 1018 | 1113 | // Returning to an interpreted continuation: put the object on
|
| 1019 | 1114 | // the stack, and start executing the BCO.
|
| 1020 | 1115 | INTERP_TICK(it_retto_BCO);
|
| 1021 | - Sp_subW(1);
|
|
| 1022 | - SpW(0) = (W_)tagged_obj;
|
|
| 1023 | - obj = (StgClosure*)ReadSpW(2);
|
|
| 1116 | + obj = (StgClosure*)ReadSpW(1);
|
|
| 1024 | 1117 | ASSERT(get_itbl(obj)->type == BCO);
|
| 1025 | - goto run_BCO_return_pointer;
|
|
| 1118 | + |
|
| 1119 | + // Heap check
|
|
| 1120 | + if (doYouWantToGC(cap)) {
|
|
| 1121 | + Sp_subW(2);
|
|
| 1122 | + SpW(1) = (W_)tagged_obj;
|
|
| 1123 | + SpW(0) = (W_)&stg_ret_p_info;
|
|
| 1124 | + RETURN_TO_SCHEDULER(ThreadInterpret, HeapOverflow);
|
|
| 1125 | + }
|
|
| 1126 | + else {
|
|
| 1127 | + |
|
| 1128 | + // Stack checks aren't necessary at return points, the stack use
|
|
| 1129 | + // is aggregated into the enclosing function entry point.
|
|
| 1130 | + |
|
| 1131 | + // Make sure to drop the RET_BCO frame header,
|
|
| 1132 | + // but not its arguments (which are expected at the top when running the BCO).
|
|
| 1133 | + // NOTE: Always a return_pointer (ie not a tuple ctoi frame!)
|
|
| 1134 | + |
|
| 1135 | + // Make sure stack is headed by a ctoi nontuple frame then drop it.
|
|
| 1136 | + // The arguments to the BCO continuation stay on top of the stack
|
|
| 1137 | + ASSERT(is_ctoi_nontuple_frame(Sp));
|
|
| 1138 | + Sp_addW(2);
|
|
| 1139 | + |
|
| 1140 | + // Plus the return value on top of the args
|
|
| 1141 | + Sp_subW(1);
|
|
| 1142 | + SpW(0) = (W_)tagged_obj;
|
|
| 1143 | + }
|
|
| 1144 | + |
|
| 1145 | + goto run_BCO;
|
|
| 1026 | 1146 | |
| 1027 | 1147 | default:
|
| 1028 | 1148 | do_return_unrecognised:
|
| ... | ... | @@ -1091,8 +1211,9 @@ do_return_nonpointer: |
| 1091 | 1211 | |
| 1092 | 1212 | // get the offset of the header of the next stack frame
|
| 1093 | 1213 | offset = stack_frame_sizeW((StgClosure *)Sp);
|
| 1214 | + StgClosure* next_frame = (StgClosure*)(SafeSpWP(offset));
|
|
| 1094 | 1215 | |
| 1095 | - switch (get_itbl((StgClosure*)(SafeSpWP(offset)))->type) {
|
|
| 1216 | + switch (get_itbl(next_frame)->type) {
|
|
| 1096 | 1217 | |
| 1097 | 1218 | case RET_BCO:
|
| 1098 | 1219 | // Returning to an interpreted continuation: pop the return frame
|
| ... | ... | @@ -1100,8 +1221,72 @@ do_return_nonpointer: |
| 1100 | 1221 | // executing the BCO.
|
| 1101 | 1222 | INTERP_TICK(it_retto_BCO);
|
| 1102 | 1223 | obj = (StgClosure*)ReadSpW(offset+1);
|
| 1224 | + |
|
| 1103 | 1225 | ASSERT(get_itbl(obj)->type == BCO);
|
| 1104 | - goto run_BCO_return_nonpointer;
|
|
| 1226 | + |
|
| 1227 | + // Heap check
|
|
| 1228 | + if (doYouWantToGC(cap)) {
|
|
| 1229 | + RETURN_TO_SCHEDULER(ThreadInterpret, HeapOverflow);
|
|
| 1230 | + }
|
|
| 1231 | + else {
|
|
| 1232 | + // Stack checks aren't necessary at return points, the stack use
|
|
| 1233 | + // is aggregated into the enclosing function entry point.
|
|
| 1234 | + |
|
| 1235 | +#if defined(PROFILING)
|
|
| 1236 | + /*
|
|
| 1237 | + Restore the current cost centre stack if a tuple is being returned.
|
|
| 1238 | + |
|
| 1239 | + When a "simple" unlifted value is returned, the cccs is restored with
|
|
| 1240 | + an stg_restore_cccs frame on the stack, for example:
|
|
| 1241 | + |
|
| 1242 | + ...
|
|
| 1243 | + stg_ctoi_D1
|
|
| 1244 | + <CCCS>
|
|
| 1245 | + stg_restore_cccs
|
|
| 1246 | + |
|
| 1247 | + But stg_restore_cccs cannot deal with tuples, which may have more
|
|
| 1248 | + things on the stack. Therefore we store the CCCS inside the
|
|
| 1249 | + stg_ctoi_t frame.
|
|
| 1250 | + |
|
| 1251 | + If we have a tuple being returned, the stack looks like this:
|
|
| 1252 | + |
|
| 1253 | + ...
|
|
| 1254 | + <CCCS> <- to restore, Sp offset <next frame + 4 words>
|
|
| 1255 | + tuple_BCO
|
|
| 1256 | + tuple_info
|
|
| 1257 | + cont_BCO
|
|
| 1258 | + stg_ctoi_t <- next frame
|
|
| 1259 | + tuple_data_1
|
|
| 1260 | + ...
|
|
| 1261 | + tuple_data_n
|
|
| 1262 | + tuple_info
|
|
| 1263 | + tuple_BCO
|
|
| 1264 | + stg_ret_t <- Sp
|
|
| 1265 | + */
|
|
| 1266 | + |
|
| 1267 | + if(SpW(0) == (W_)&stg_ret_t_info) {
|
|
| 1268 | + cap->r.rCCCS = (CostCentreStack*)ReadSpW(stack_frame_sizeW((StgClosure *)Sp) + 4);
|
|
| 1269 | + }
|
|
| 1270 | +#endif
|
|
| 1271 | + /* Drop the RET_BCO header (next_frame),
|
|
| 1272 | + * but not its arguments (which are expected at the top when running the BCO)
|
|
| 1273 | + */
|
|
| 1274 | + W_ n = offset;
|
|
| 1275 | + W_ by = is_ctoi_nontuple_frame(next_frame)
|
|
| 1276 | + ? 2 // info+bco
|
|
| 1277 | +#if defined(PROFILING)
|
|
| 1278 | + : 5; // or info+bco+tuple_info+tuple_BCO+CCS
|
|
| 1279 | +#else
|
|
| 1280 | + : 4; // or info+bco+tuple_info+tuple_BCO
|
|
| 1281 | +#endif
|
|
| 1282 | + SpSlide(n, by);
|
|
| 1283 | + |
|
| 1284 | + if (SpW(0) != (W_)&stg_ret_t_info) {
|
|
| 1285 | + Sp_addW(1);
|
|
| 1286 | + }
|
|
| 1287 | + |
|
| 1288 | + goto run_BCO;
|
|
| 1289 | + }
|
|
| 1105 | 1290 | |
| 1106 | 1291 | default:
|
| 1107 | 1292 | {
|
| ... | ... | @@ -1268,8 +1453,8 @@ do_apply: |
| 1268 | 1453 | // Ok, we now have a bco (obj), and its arguments are all on the
|
| 1269 | 1454 | // stack. We can start executing the byte codes.
|
| 1270 | 1455 | //
|
| 1271 | - // The stack is in one of two states. First, if this BCO is a
|
|
| 1272 | - // function:
|
|
| 1456 | + // The stack is in one of two states. First, if this BCO is a
|
|
| 1457 | + // function
|
|
| 1273 | 1458 | //
|
| 1274 | 1459 | // | .... |
|
| 1275 | 1460 | // +---------------+
|
| ... | ... | @@ -1286,10 +1471,6 @@ do_apply: |
| 1286 | 1471 | // +---------------+
|
| 1287 | 1472 | // | fv1 |
|
| 1288 | 1473 | // +---------------+
|
| 1289 | - // | BCO |
|
|
| 1290 | - // +---------------+
|
|
| 1291 | - // | stg_ctoi_ret_ |
|
|
| 1292 | - // +---------------+
|
|
| 1293 | 1474 | // | retval |
|
| 1294 | 1475 | // +---------------+
|
| 1295 | 1476 | //
|
| ... | ... | @@ -1307,68 +1488,6 @@ do_apply: |
| 1307 | 1488 | // Sadly we have three different kinds of stack/heap/cswitch check
|
| 1308 | 1489 | // to do:
|
| 1309 | 1490 | |
| 1310 | - |
|
| 1311 | -run_BCO_return_pointer:
|
|
| 1312 | - // Heap check
|
|
| 1313 | - if (doYouWantToGC(cap)) {
|
|
| 1314 | - Sp_subW(1); SpW(0) = (W_)&stg_ret_p_info;
|
|
| 1315 | - RETURN_TO_SCHEDULER(ThreadInterpret, HeapOverflow);
|
|
| 1316 | - }
|
|
| 1317 | - // Stack checks aren't necessary at return points, the stack use
|
|
| 1318 | - // is aggregated into the enclosing function entry point.
|
|
| 1319 | - |
|
| 1320 | - goto run_BCO;
|
|
| 1321 | - |
|
| 1322 | -run_BCO_return_nonpointer:
|
|
| 1323 | - // Heap check
|
|
| 1324 | - if (doYouWantToGC(cap)) {
|
|
| 1325 | - RETURN_TO_SCHEDULER(ThreadInterpret, HeapOverflow);
|
|
| 1326 | - }
|
|
| 1327 | - // Stack checks aren't necessary at return points, the stack use
|
|
| 1328 | - // is aggregated into the enclosing function entry point.
|
|
| 1329 | - |
|
| 1330 | -#if defined(PROFILING)
|
|
| 1331 | - /*
|
|
| 1332 | - Restore the current cost centre stack if a tuple is being returned.
|
|
| 1333 | - |
|
| 1334 | - When a "simple" unlifted value is returned, the cccs is restored with
|
|
| 1335 | - an stg_restore_cccs frame on the stack, for example:
|
|
| 1336 | - |
|
| 1337 | - ...
|
|
| 1338 | - stg_ctoi_D1
|
|
| 1339 | - <CCCS>
|
|
| 1340 | - stg_restore_cccs
|
|
| 1341 | - |
|
| 1342 | - But stg_restore_cccs cannot deal with tuples, which may have more
|
|
| 1343 | - things on the stack. Therefore we store the CCCS inside the
|
|
| 1344 | - stg_ctoi_t frame.
|
|
| 1345 | - |
|
| 1346 | - If we have a tuple being returned, the stack looks like this:
|
|
| 1347 | - |
|
| 1348 | - ...
|
|
| 1349 | - <CCCS> <- to restore, Sp offset <next frame + 4 words>
|
|
| 1350 | - tuple_BCO
|
|
| 1351 | - tuple_info
|
|
| 1352 | - cont_BCO
|
|
| 1353 | - stg_ctoi_t <- next frame
|
|
| 1354 | - tuple_data_1
|
|
| 1355 | - ...
|
|
| 1356 | - tuple_data_n
|
|
| 1357 | - tuple_info
|
|
| 1358 | - tuple_BCO
|
|
| 1359 | - stg_ret_t <- Sp
|
|
| 1360 | - */
|
|
| 1361 | - |
|
| 1362 | - if(SpW(0) == (W_)&stg_ret_t_info) {
|
|
| 1363 | - cap->r.rCCCS = (CostCentreStack*)ReadSpW(stack_frame_sizeW((StgClosure *)Sp) + 4);
|
|
| 1364 | - }
|
|
| 1365 | -#endif
|
|
| 1366 | - |
|
| 1367 | - if (SpW(0) != (W_)&stg_ret_t_info) {
|
|
| 1368 | - Sp_addW(1);
|
|
| 1369 | - }
|
|
| 1370 | - goto run_BCO;
|
|
| 1371 | - |
|
| 1372 | 1491 | run_BCO_fun:
|
| 1373 | 1492 | IF_DEBUG(sanity,
|
| 1374 | 1493 | Sp_subW(2);
|
| ... | ... | @@ -1454,9 +1573,9 @@ run_BCO: |
| 1454 | 1573 | /* check for a breakpoint on the beginning of a let binding */
|
| 1455 | 1574 | case bci_BRK_FUN:
|
| 1456 | 1575 | {
|
| 1457 | - int arg1_brk_array, arg2_tick_mod, arg3_info_mod, arg4_tick_mod_id, arg5_info_mod_id, arg6_tick_index, arg7_info_index;
|
|
| 1576 | + W_ arg1_brk_array, arg2_info_mod_name, arg3_info_mod_id, arg4_info_index, arg5_byte_off;
|
|
| 1458 | 1577 | #if defined(PROFILING)
|
| 1459 | - int arg8_cc;
|
|
| 1578 | + W_ arg6_cc;
|
|
| 1460 | 1579 | #endif
|
| 1461 | 1580 | StgArrBytes *breakPoints;
|
| 1462 | 1581 | int returning_from_break, stop_next_breakpoint;
|
| ... | ... | @@ -1471,14 +1590,12 @@ run_BCO: |
| 1471 | 1590 | int size_words;
|
| 1472 | 1591 | |
| 1473 | 1592 | arg1_brk_array = BCO_GET_LARGE_ARG;
|
| 1474 | - arg2_tick_mod = BCO_GET_LARGE_ARG;
|
|
| 1475 | - arg3_info_mod = BCO_GET_LARGE_ARG;
|
|
| 1476 | - arg4_tick_mod_id = BCO_GET_LARGE_ARG;
|
|
| 1477 | - arg5_info_mod_id = BCO_GET_LARGE_ARG;
|
|
| 1478 | - arg6_tick_index = BCO_NEXT;
|
|
| 1479 | - arg7_info_index = BCO_NEXT;
|
|
| 1593 | + arg2_info_mod_name = BCO_GET_LARGE_ARG;
|
|
| 1594 | + arg3_info_mod_id = BCO_GET_LARGE_ARG;
|
|
| 1595 | + arg4_info_index = BCO_NEXT;
|
|
| 1596 | + arg5_byte_off = BCO_NEXT;
|
|
| 1480 | 1597 | #if defined(PROFILING)
|
| 1481 | - arg8_cc = BCO_GET_LARGE_ARG;
|
|
| 1598 | + arg6_cc = BCO_GET_LARGE_ARG;
|
|
| 1482 | 1599 | #else
|
| 1483 | 1600 | BCO_GET_LARGE_ARG;
|
| 1484 | 1601 | #endif
|
| ... | ... | @@ -1498,7 +1615,7 @@ run_BCO: |
| 1498 | 1615 | |
| 1499 | 1616 | #if defined(PROFILING)
|
| 1500 | 1617 | cap->r.rCCCS = pushCostCentre(cap->r.rCCCS,
|
| 1501 | - (CostCentre*)BCO_LIT(arg8_cc));
|
|
| 1618 | + (CostCentre*)BCO_LIT(arg6_cc));
|
|
| 1502 | 1619 | #endif
|
| 1503 | 1620 | |
| 1504 | 1621 | // if we are returning from a break then skip this section
|
| ... | ... | @@ -1509,11 +1626,11 @@ run_BCO: |
| 1509 | 1626 | |
| 1510 | 1627 | // stop the current thread if either `stop_next_breakpoint` is
|
| 1511 | 1628 | // true OR if the ignore count for this particular breakpoint is zero
|
| 1512 | - StgInt ignore_count = ((StgInt*)breakPoints->payload)[arg6_tick_index];
|
|
| 1629 | + StgInt ignore_count = ((StgInt*)breakPoints->payload)[arg4_info_index];
|
|
| 1513 | 1630 | if (stop_next_breakpoint == false && ignore_count > 0)
|
| 1514 | 1631 | {
|
| 1515 | 1632 | // decrement and write back ignore count
|
| 1516 | - ((StgInt*)breakPoints->payload)[arg6_tick_index] = --ignore_count;
|
|
| 1633 | + ((StgInt*)breakPoints->payload)[arg4_info_index] = --ignore_count;
|
|
| 1517 | 1634 | }
|
| 1518 | 1635 | else if (stop_next_breakpoint == true || ignore_count == 0)
|
| 1519 | 1636 | {
|
| ... | ... | @@ -1538,7 +1655,12 @@ run_BCO: |
| 1538 | 1655 | // copy the contents of the top stack frame into the AP_STACK
|
| 1539 | 1656 | for (i = 2; i < size_words; i++)
|
| 1540 | 1657 | {
|
| 1541 | - new_aps->payload[i] = (StgClosure *)ReadSpW(i-2);
|
|
| 1658 | + // BAD ASSUMPTION: BITMAP Vars are on top of the stack.
|
|
| 1659 | + // THEY ARE NOT FOR PUSH_ALTS:
|
|
| 1660 | + // THE FIRST THING ON THE STACK IS GOING TO BE
|
|
| 1661 | + // ctoi_***
|
|
| 1662 | + //TODO UPDATE DOCUMENTATION EXPLANING ARG5_BYTE_OFF
|
|
| 1663 | + new_aps->payload[i] = (StgClosure *)ReadSpB(((ptrdiff_t)(i-2) * (ptrdiff_t)sizeof(W_)) + arg5_byte_off);
|
|
| 1542 | 1664 | }
|
| 1543 | 1665 | |
| 1544 | 1666 | // No write barrier is needed here as this is a new allocation
|
| ... | ... | @@ -1547,10 +1669,7 @@ run_BCO: |
| 1547 | 1669 | // Arrange the stack to call the breakpoint IO action, and
|
| 1548 | 1670 | // continue execution of this BCO when the IO action returns.
|
| 1549 | 1671 | //
|
| 1550 | - // ioAction :: Addr# -- the breakpoint tick module
|
|
| 1551 | - // -> Addr# -- the breakpoint tick module unit id
|
|
| 1552 | - // -> Int# -- the breakpoint tick index
|
|
| 1553 | - // -> Addr# -- the breakpoint info module
|
|
| 1672 | + // ioAction :: Addr# -- the breakpoint info module
|
|
| 1554 | 1673 | // -> Addr# -- the breakpoint info module unit id
|
| 1555 | 1674 | // -> Int# -- the breakpoint info index
|
| 1556 | 1675 | // -> Bool -- exception?
|
| ... | ... | @@ -1560,23 +1679,17 @@ run_BCO: |
| 1560 | 1679 | ioAction = (StgClosure *) deRefStablePtr (
|
| 1561 | 1680 | rts_breakpoint_io_action);
|
| 1562 | 1681 | |
| 1563 | - Sp_subW(19);
|
|
| 1564 | - SpW(18) = (W_)obj;
|
|
| 1565 | - SpW(17) = (W_)&stg_apply_interp_info;
|
|
| 1566 | - SpW(16) = (W_)new_aps;
|
|
| 1567 | - SpW(15) = (W_)False_closure; // True <=> an exception
|
|
| 1568 | - SpW(14) = (W_)&stg_ap_ppv_info;
|
|
| 1569 | - SpW(13) = (W_)arg7_info_index;
|
|
| 1570 | - SpW(12) = (W_)&stg_ap_n_info;
|
|
| 1571 | - SpW(11) = (W_)BCO_LIT(arg5_info_mod_id);
|
|
| 1572 | - SpW(10) = (W_)&stg_ap_n_info;
|
|
| 1573 | - SpW(9) = (W_)BCO_LIT(arg3_info_mod);
|
|
| 1574 | - SpW(8) = (W_)&stg_ap_n_info;
|
|
| 1575 | - SpW(7) = (W_)arg6_tick_index;
|
|
| 1682 | + Sp_subW(13);
|
|
| 1683 | + SpW(12) = (W_)obj;
|
|
| 1684 | + SpW(11) = (W_)&stg_apply_interp_info;
|
|
| 1685 | + SpW(10) = (W_)new_aps;
|
|
| 1686 | + SpW(9) = (W_)False_closure; // True <=> an exception
|
|
| 1687 | + SpW(8) = (W_)&stg_ap_ppv_info;
|
|
| 1688 | + SpW(7) = (W_)arg4_info_index;
|
|
| 1576 | 1689 | SpW(6) = (W_)&stg_ap_n_info;
|
| 1577 | - SpW(5) = (W_)BCO_LIT(arg4_tick_mod_id);
|
|
| 1690 | + SpW(5) = (W_)BCO_LIT(arg3_info_mod_id);
|
|
| 1578 | 1691 | SpW(4) = (W_)&stg_ap_n_info;
|
| 1579 | - SpW(3) = (W_)BCO_LIT(arg2_tick_mod);
|
|
| 1692 | + SpW(3) = (W_)BCO_LIT(arg2_info_mod_name);
|
|
| 1580 | 1693 | SpW(2) = (W_)&stg_ap_n_info;
|
| 1581 | 1694 | SpW(1) = (W_)ioAction;
|
| 1582 | 1695 | SpW(0) = (W_)&stg_enter_info;
|
| ... | ... | @@ -1742,6 +1855,10 @@ run_BCO: |
| 1742 | 1855 | Sp_subW(2);
|
| 1743 | 1856 | SpW(1) = BCO_PTR(o_bco);
|
| 1744 | 1857 | SpW(0) = (W_)&stg_ctoi_R1p_info;
|
| 1858 | + |
|
| 1859 | + // The o_bco expects its arguments (as per the BCO_BITMAP_SIZE) to
|
|
| 1860 | + // be found on the stack before it.
|
|
| 1861 | + IF_DEBUG(sanity, checkStackChunk(Sp, cap->r.rCurrentTSO->stackobj->stack+cap->r.rCurrentTSO->stackobj->stack_size););
|
|
| 1745 | 1862 | #if defined(PROFILING)
|
| 1746 | 1863 | Sp_subW(2);
|
| 1747 | 1864 | SpW(1) = (W_)cap->r.rCCCS;
|
| ... | ... | @@ -1755,6 +1872,8 @@ run_BCO: |
| 1755 | 1872 | SpW(-2) = (W_)&stg_ctoi_R1n_info;
|
| 1756 | 1873 | SpW(-1) = BCO_PTR(o_bco);
|
| 1757 | 1874 | Sp_subW(2);
|
| 1875 | + |
|
| 1876 | + IF_DEBUG(sanity, checkStackChunk(Sp, cap->r.rCurrentTSO->stackobj->stack+cap->r.rCurrentTSO->stackobj->stack_size););
|
|
| 1758 | 1877 | #if defined(PROFILING)
|
| 1759 | 1878 | Sp_subW(2);
|
| 1760 | 1879 | SpW(1) = (W_)cap->r.rCCCS;
|
| ... | ... | @@ -1768,6 +1887,8 @@ run_BCO: |
| 1768 | 1887 | SpW(-2) = (W_)&stg_ctoi_F1_info;
|
| 1769 | 1888 | SpW(-1) = BCO_PTR(o_bco);
|
| 1770 | 1889 | Sp_subW(2);
|
| 1890 | + |
|
| 1891 | + IF_DEBUG(sanity, checkStackChunk(Sp, cap->r.rCurrentTSO->stackobj->stack+cap->r.rCurrentTSO->stackobj->stack_size););
|
|
| 1771 | 1892 | #if defined(PROFILING)
|
| 1772 | 1893 | Sp_subW(2);
|
| 1773 | 1894 | SpW(1) = (W_)cap->r.rCCCS;
|
| ... | ... | @@ -1781,6 +1902,8 @@ run_BCO: |
| 1781 | 1902 | SpW(-2) = (W_)&stg_ctoi_D1_info;
|
| 1782 | 1903 | SpW(-1) = BCO_PTR(o_bco);
|
| 1783 | 1904 | Sp_subW(2);
|
| 1905 | + |
|
| 1906 | + IF_DEBUG(sanity, checkStackChunk(Sp, cap->r.rCurrentTSO->stackobj->stack+cap->r.rCurrentTSO->stackobj->stack_size););
|
|
| 1784 | 1907 | #if defined(PROFILING)
|
| 1785 | 1908 | Sp_subW(2);
|
| 1786 | 1909 | SpW(1) = (W_)cap->r.rCCCS;
|
| ... | ... | @@ -1794,6 +1917,8 @@ run_BCO: |
| 1794 | 1917 | SpW(-2) = (W_)&stg_ctoi_L1_info;
|
| 1795 | 1918 | SpW(-1) = BCO_PTR(o_bco);
|
| 1796 | 1919 | Sp_subW(2);
|
| 1920 | + |
|
| 1921 | + IF_DEBUG(sanity, checkStackChunk(Sp, cap->r.rCurrentTSO->stackobj->stack+cap->r.rCurrentTSO->stackobj->stack_size););
|
|
| 1797 | 1922 | #if defined(PROFILING)
|
| 1798 | 1923 | Sp_subW(2);
|
| 1799 | 1924 | SpW(1) = (W_)cap->r.rCCCS;
|
| ... | ... | @@ -1807,6 +1932,8 @@ run_BCO: |
| 1807 | 1932 | SpW(-2) = (W_)&stg_ctoi_V_info;
|
| 1808 | 1933 | SpW(-1) = BCO_PTR(o_bco);
|
| 1809 | 1934 | Sp_subW(2);
|
| 1935 | + |
|
| 1936 | + IF_DEBUG(sanity, checkStackChunk(Sp, cap->r.rCurrentTSO->stackobj->stack+cap->r.rCurrentTSO->stackobj->stack_size););
|
|
| 1810 | 1937 | #if defined(PROFILING)
|
| 1811 | 1938 | Sp_subW(2);
|
| 1812 | 1939 | SpW(1) = (W_)cap->r.rCCCS;
|
| ... | ... | @@ -1820,6 +1947,7 @@ run_BCO: |
| 1820 | 1947 | W_ tuple_info = (W_)BCO_LIT(BCO_GET_LARGE_ARG);
|
| 1821 | 1948 | W_ o_tuple_bco = BCO_GET_LARGE_ARG;
|
| 1822 | 1949 | |
| 1950 | + IF_DEBUG(sanity, checkStackChunk(Sp, cap->r.rCurrentTSO->stackobj->stack+cap->r.rCurrentTSO->stackobj->stack_size););
|
|
| 1823 | 1951 | #if defined(PROFILING)
|
| 1824 | 1952 | SpW(-1) = (W_)cap->r.rCCCS;
|
| 1825 | 1953 | Sp_subW(1);
|
| ... | ... | @@ -1828,82 +1956,11 @@ run_BCO: |
| 1828 | 1956 | SpW(-1) = BCO_PTR(o_tuple_bco);
|
| 1829 | 1957 | SpW(-2) = tuple_info;
|
| 1830 | 1958 | SpW(-3) = BCO_PTR(o_bco);
|
| 1831 | - W_ ctoi_t_offset;
|
|
| 1832 | 1959 | int tuple_stack_words = (tuple_info >> 24) & 0xff;
|
| 1833 | - switch(tuple_stack_words) {
|
|
| 1834 | - case 0: ctoi_t_offset = (W_)&stg_ctoi_t0_info; break;
|
|
| 1835 | - case 1: ctoi_t_offset = (W_)&stg_ctoi_t1_info; break;
|
|
| 1836 | - case 2: ctoi_t_offset = (W_)&stg_ctoi_t2_info; break;
|
|
| 1837 | - case 3: ctoi_t_offset = (W_)&stg_ctoi_t3_info; break;
|
|
| 1838 | - case 4: ctoi_t_offset = (W_)&stg_ctoi_t4_info; break;
|
|
| 1839 | - case 5: ctoi_t_offset = (W_)&stg_ctoi_t5_info; break;
|
|
| 1840 | - case 6: ctoi_t_offset = (W_)&stg_ctoi_t6_info; break;
|
|
| 1841 | - case 7: ctoi_t_offset = (W_)&stg_ctoi_t7_info; break;
|
|
| 1842 | - case 8: ctoi_t_offset = (W_)&stg_ctoi_t8_info; break;
|
|
| 1843 | - case 9: ctoi_t_offset = (W_)&stg_ctoi_t9_info; break;
|
|
| 1844 | - |
|
| 1845 | - case 10: ctoi_t_offset = (W_)&stg_ctoi_t10_info; break;
|
|
| 1846 | - case 11: ctoi_t_offset = (W_)&stg_ctoi_t11_info; break;
|
|
| 1847 | - case 12: ctoi_t_offset = (W_)&stg_ctoi_t12_info; break;
|
|
| 1848 | - case 13: ctoi_t_offset = (W_)&stg_ctoi_t13_info; break;
|
|
| 1849 | - case 14: ctoi_t_offset = (W_)&stg_ctoi_t14_info; break;
|
|
| 1850 | - case 15: ctoi_t_offset = (W_)&stg_ctoi_t15_info; break;
|
|
| 1851 | - case 16: ctoi_t_offset = (W_)&stg_ctoi_t16_info; break;
|
|
| 1852 | - case 17: ctoi_t_offset = (W_)&stg_ctoi_t17_info; break;
|
|
| 1853 | - case 18: ctoi_t_offset = (W_)&stg_ctoi_t18_info; break;
|
|
| 1854 | - case 19: ctoi_t_offset = (W_)&stg_ctoi_t19_info; break;
|
|
| 1855 | - |
|
| 1856 | - case 20: ctoi_t_offset = (W_)&stg_ctoi_t20_info; break;
|
|
| 1857 | - case 21: ctoi_t_offset = (W_)&stg_ctoi_t21_info; break;
|
|
| 1858 | - case 22: ctoi_t_offset = (W_)&stg_ctoi_t22_info; break;
|
|
| 1859 | - case 23: ctoi_t_offset = (W_)&stg_ctoi_t23_info; break;
|
|
| 1860 | - case 24: ctoi_t_offset = (W_)&stg_ctoi_t24_info; break;
|
|
| 1861 | - case 25: ctoi_t_offset = (W_)&stg_ctoi_t25_info; break;
|
|
| 1862 | - case 26: ctoi_t_offset = (W_)&stg_ctoi_t26_info; break;
|
|
| 1863 | - case 27: ctoi_t_offset = (W_)&stg_ctoi_t27_info; break;
|
|
| 1864 | - case 28: ctoi_t_offset = (W_)&stg_ctoi_t28_info; break;
|
|
| 1865 | - case 29: ctoi_t_offset = (W_)&stg_ctoi_t29_info; break;
|
|
| 1866 | - |
|
| 1867 | - case 30: ctoi_t_offset = (W_)&stg_ctoi_t30_info; break;
|
|
| 1868 | - case 31: ctoi_t_offset = (W_)&stg_ctoi_t31_info; break;
|
|
| 1869 | - case 32: ctoi_t_offset = (W_)&stg_ctoi_t32_info; break;
|
|
| 1870 | - case 33: ctoi_t_offset = (W_)&stg_ctoi_t33_info; break;
|
|
| 1871 | - case 34: ctoi_t_offset = (W_)&stg_ctoi_t34_info; break;
|
|
| 1872 | - case 35: ctoi_t_offset = (W_)&stg_ctoi_t35_info; break;
|
|
| 1873 | - case 36: ctoi_t_offset = (W_)&stg_ctoi_t36_info; break;
|
|
| 1874 | - case 37: ctoi_t_offset = (W_)&stg_ctoi_t37_info; break;
|
|
| 1875 | - case 38: ctoi_t_offset = (W_)&stg_ctoi_t38_info; break;
|
|
| 1876 | - case 39: ctoi_t_offset = (W_)&stg_ctoi_t39_info; break;
|
|
| 1877 | - |
|
| 1878 | - case 40: ctoi_t_offset = (W_)&stg_ctoi_t40_info; break;
|
|
| 1879 | - case 41: ctoi_t_offset = (W_)&stg_ctoi_t41_info; break;
|
|
| 1880 | - case 42: ctoi_t_offset = (W_)&stg_ctoi_t42_info; break;
|
|
| 1881 | - case 43: ctoi_t_offset = (W_)&stg_ctoi_t43_info; break;
|
|
| 1882 | - case 44: ctoi_t_offset = (W_)&stg_ctoi_t44_info; break;
|
|
| 1883 | - case 45: ctoi_t_offset = (W_)&stg_ctoi_t45_info; break;
|
|
| 1884 | - case 46: ctoi_t_offset = (W_)&stg_ctoi_t46_info; break;
|
|
| 1885 | - case 47: ctoi_t_offset = (W_)&stg_ctoi_t47_info; break;
|
|
| 1886 | - case 48: ctoi_t_offset = (W_)&stg_ctoi_t48_info; break;
|
|
| 1887 | - case 49: ctoi_t_offset = (W_)&stg_ctoi_t49_info; break;
|
|
| 1888 | - |
|
| 1889 | - case 50: ctoi_t_offset = (W_)&stg_ctoi_t50_info; break;
|
|
| 1890 | - case 51: ctoi_t_offset = (W_)&stg_ctoi_t51_info; break;
|
|
| 1891 | - case 52: ctoi_t_offset = (W_)&stg_ctoi_t52_info; break;
|
|
| 1892 | - case 53: ctoi_t_offset = (W_)&stg_ctoi_t53_info; break;
|
|
| 1893 | - case 54: ctoi_t_offset = (W_)&stg_ctoi_t54_info; break;
|
|
| 1894 | - case 55: ctoi_t_offset = (W_)&stg_ctoi_t55_info; break;
|
|
| 1895 | - case 56: ctoi_t_offset = (W_)&stg_ctoi_t56_info; break;
|
|
| 1896 | - case 57: ctoi_t_offset = (W_)&stg_ctoi_t57_info; break;
|
|
| 1897 | - case 58: ctoi_t_offset = (W_)&stg_ctoi_t58_info; break;
|
|
| 1898 | - case 59: ctoi_t_offset = (W_)&stg_ctoi_t59_info; break;
|
|
| 1899 | - |
|
| 1900 | - case 60: ctoi_t_offset = (W_)&stg_ctoi_t60_info; break;
|
|
| 1901 | - case 61: ctoi_t_offset = (W_)&stg_ctoi_t61_info; break;
|
|
| 1902 | - case 62: ctoi_t_offset = (W_)&stg_ctoi_t62_info; break;
|
|
| 1903 | - |
|
| 1904 | - default: barf("unsupported tuple size %d", tuple_stack_words);
|
|
| 1960 | + if (tuple_stack_words > 62) {
|
|
| 1961 | + barf("unsupported tuple size %d", tuple_stack_words);
|
|
| 1905 | 1962 | }
|
| 1906 | - |
|
| 1963 | + W_ ctoi_t_offset = (W_) ctoi_tuple_infos[tuple_stack_words];
|
|
| 1907 | 1964 | SpW(-4) = ctoi_t_offset;
|
| 1908 | 1965 | Sp_subW(4);
|
| 1909 | 1966 | goto nextInsn;
|
| ... | ... | @@ -1996,15 +2053,7 @@ run_BCO: |
| 1996 | 2053 | case bci_SLIDE: {
|
| 1997 | 2054 | W_ n = BCO_GET_LARGE_ARG;
|
| 1998 | 2055 | W_ by = BCO_GET_LARGE_ARG;
|
| 1999 | - /*
|
|
| 2000 | - * a_1 ... a_n, b_1 ... b_by, k
|
|
| 2001 | - * =>
|
|
| 2002 | - * a_1 ... a_n, k
|
|
| 2003 | - */
|
|
| 2004 | - while(n-- > 0) {
|
|
| 2005 | - SpW(n+by) = ReadSpW(n);
|
|
| 2006 | - }
|
|
| 2007 | - Sp_addW(by);
|
|
| 2056 | + SpSlide(n, by);
|
|
| 2008 | 2057 | INTERP_TICK(it_slides);
|
| 2009 | 2058 | goto nextInsn;
|
| 2010 | 2059 | }
|
| ... | ... | @@ -147,7 +147,7 @@ test('T25932', extra_files(['T25932.hs']), ghci_script, ['T25932.script']) |
| 147 | 147 | |
| 148 | 148 | # Step out tests
|
| 149 | 149 | test('T26042b', [extra_hc_opts('-O -fno-unoptimized-core-for-interpreter'), extra_files(['T26042b.hs'])], ghci_script, ['T26042b.script'])
|
| 150 | -test('T26042c', [expect_broken(26042),extra_hc_opts('-O -fno-unoptimized-core-for-interpreter'), extra_files(['T26042c.hs'])], ghci_script, ['T26042c.script'])
|
|
| 150 | +test('T26042c', [extra_hc_opts('-O -fno-unoptimized-core-for-interpreter'), extra_files(['T26042c.hs'])], ghci_script, ['T26042c.script'])
|
|
| 151 | 151 | test('T26042d', [extra_hc_opts('-O -fno-unoptimized-core-for-interpreter'), extra_files(['T26042d.hs'])], ghci_script, ['T26042d.script'])
|
| 152 | 152 | test('T26042e', extra_files(['T26042e.hs']), ghci_script, ['T26042e.script'])
|
| 153 | 153 | test('T26042f1', extra_files(['T26042f.hs', 'T26042f.script']), ghci_script, ['T26042f.script']) # >> is not inlined, so stepout has nowhere to stop
|