Rodrigo Mesquita pushed to branch wip/romes/step-out-11 at Glasgow Haskell Compiler / GHC
Commits:
-
4fcfaae8
by Rodrigo Mesquita at 2025-07-30T11:00:49+01:00
-
8084c422
by Rodrigo Mesquita at 2025-07-30T11:01:03+01:00
21 changed files:
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Breakpoints.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Runtime/Debugger/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/StgToByteCode.hs
- ghc/GHCi/UI.hs
- rts/Disassembler.c
- rts/Interpreter.c
- rts/include/rts/Bytecodes.h
- testsuite/tests/ghci.debugger/scripts/T26042b.stdout
- testsuite/tests/ghci.debugger/scripts/T26042c.script
- testsuite/tests/ghci.debugger/scripts/T26042c.stdout
- + testsuite/tests/ghci.debugger/scripts/T26042d2.hs
- + testsuite/tests/ghci.debugger/scripts/T26042d2.script
- + testsuite/tests/ghci.debugger/scripts/T26042d2.stdout
- testsuite/tests/ghci.debugger/scripts/T26042e.stdout
- testsuite/tests/ghci.debugger/scripts/T26042f2.stdout
- testsuite/tests/ghci.debugger/scripts/T26042g.stdout
- testsuite/tests/ghci.debugger/scripts/all.T
Changes:
| ... | ... | @@ -854,8 +854,6 @@ assembleI platform i = case i of |
| 854 | 854 | emit_ bci_BRK_FUN [ Op p1, Op info_addr, Op info_unitid_addr
|
| 855 | 855 | , SmallOp (toW16 infox), Op np ]
|
| 856 | 856 | |
| 857 | - BRK_ALTS active -> emit_ bci_BRK_ALTS [SmallOp (if active then 1 else 0)]
|
|
| 858 | - |
|
| 859 | 857 | #if MIN_VERSION_rts(1,0,3)
|
| 860 | 858 | BCO_NAME name -> do np <- lit1 (BCONPtrStr name)
|
| 861 | 859 | emit_ bci_BCO_NAME [Op np]
|
| 1 | 1 | {-# LANGUAGE RecordWildCards #-}
|
| 2 | +{-# LANGUAGE DerivingStrategies #-}
|
|
| 2 | 3 | |
| 3 | 4 | -- | Breakpoint information constructed during ByteCode generation.
|
| 4 | 5 | --
|
| ... | ... | @@ -15,6 +16,7 @@ module GHC.ByteCode.Breakpoints |
| 15 | 16 | |
| 16 | 17 | -- ** Internal breakpoint identifier
|
| 17 | 18 | , InternalBreakpointId(..), BreakInfoIndex
|
| 19 | + , InternalBreakLoc(..)
|
|
| 18 | 20 | |
| 19 | 21 | -- * Operations
|
| 20 | 22 | |
| ... | ... | @@ -23,7 +25,7 @@ module GHC.ByteCode.Breakpoints |
| 23 | 25 | |
| 24 | 26 | -- ** Source-level information operations
|
| 25 | 27 | , getBreakLoc, getBreakVars, getBreakDecls, getBreakCCS
|
| 26 | - , getBreakSourceId
|
|
| 28 | + , getBreakSourceId, getBreakSourceMod
|
|
| 27 | 29 | |
| 28 | 30 | -- * Utils
|
| 29 | 31 | , seqInternalModBreaks
|
| ... | ... | @@ -165,7 +167,7 @@ data CgBreakInfo |
| 165 | 167 | { cgb_tyvars :: ![IfaceTvBndr] -- ^ Type variables in scope at the breakpoint
|
| 166 | 168 | , cgb_vars :: ![Maybe (IfaceIdBndr, Word)]
|
| 167 | 169 | , cgb_resty :: !IfaceType
|
| 168 | - , cgb_tick_id :: !BreakpointId
|
|
| 170 | + , cgb_tick_id :: !(Either InternalBreakLoc BreakpointId)
|
|
| 169 | 171 | -- ^ This field records the original breakpoint tick identifier for this
|
| 170 | 172 | -- internal breakpoint info. It is used to convert a breakpoint
|
| 171 | 173 | -- *occurrence* index ('InternalBreakpointId') into a *definition* index
|
| ... | ... | @@ -173,9 +175,18 @@ data CgBreakInfo |
| 173 | 175 | --
|
| 174 | 176 | -- The modules of breakpoint occurrence and breakpoint definition are not
|
| 175 | 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.
|
|
| 176 | 182 | }
|
| 177 | 183 | -- See Note [Syncing breakpoint info] in GHC.Runtime.Eval
|
| 178 | 184 | |
| 185 | +-- | Breakpoints created during code generation don't have a source-level tick
|
|
| 186 | +-- location. Instead, we come up with one ourselves.
|
|
| 187 | +newtype InternalBreakLoc = InternalBreakLoc SrcSpan
|
|
| 188 | + deriving newtype (Eq, Show, NFData, Outputable)
|
|
| 189 | + |
|
| 179 | 190 | -- | Get an internal breakpoint info by 'InternalBreakpointId'
|
| 180 | 191 | getInternalBreak :: InternalBreakpointId -> InternalModBreaks -> CgBreakInfo
|
| 181 | 192 | getInternalBreak (InternalBreakpointId mod ix) imbs =
|
| ... | ... | @@ -196,27 +207,36 @@ assert_modules_match ibi_mod imbs_mod = |
| 196 | 207 | |
| 197 | 208 | -- | Get the source module and tick index for this breakpoint
|
| 198 | 209 | -- (as opposed to the module where this breakpoint occurs, which is in 'InternalBreakpointId')
|
| 199 | -getBreakSourceId :: InternalBreakpointId -> InternalModBreaks -> BreakpointId
|
|
| 210 | +getBreakSourceId :: InternalBreakpointId -> InternalModBreaks -> Either InternalBreakLoc BreakpointId
|
|
| 200 | 211 | getBreakSourceId (InternalBreakpointId ibi_mod ibi_ix) imbs =
|
| 201 | 212 | assert_modules_match ibi_mod (imodBreaks_module imbs) $
|
| 202 | 213 | let cgb = imodBreaks_breakInfo imbs IM.! ibi_ix
|
| 203 | 214 | in cgb_tick_id cgb
|
| 204 | 215 | |
| 216 | +-- | Get the source module for this breakpoint (where the breakpoint is defined)
|
|
| 217 | +getBreakSourceMod :: InternalBreakpointId -> InternalModBreaks -> Module
|
|
| 218 | +getBreakSourceMod (InternalBreakpointId ibi_mod ibi_ix) imbs =
|
|
| 219 | + assert_modules_match ibi_mod (imodBreaks_module imbs) $
|
|
| 220 | + let cgb = imodBreaks_breakInfo imbs IM.! ibi_ix
|
|
| 221 | + in case cgb_tick_id cgb of
|
|
| 222 | + Left InternalBreakLoc{} -> imodBreaks_module imbs
|
|
| 223 | + Right BreakpointId{bi_tick_mod} -> bi_tick_mod
|
|
| 224 | + |
|
| 205 | 225 | -- | Get the source span for this breakpoint
|
| 206 | 226 | getBreakLoc :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO SrcSpan
|
| 207 | -getBreakLoc = getBreakXXX modBreaks_locs
|
|
| 227 | +getBreakLoc = getBreakXXX modBreaks_locs (\(InternalBreakLoc x) -> x)
|
|
| 208 | 228 | |
| 209 | 229 | -- | Get the vars for this breakpoint
|
| 210 | 230 | getBreakVars :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO [OccName]
|
| 211 | -getBreakVars = getBreakXXX modBreaks_vars
|
|
| 231 | +getBreakVars = getBreakXXX modBreaks_vars (const [])
|
|
| 212 | 232 | |
| 213 | 233 | -- | Get the decls for this breakpoint
|
| 214 | 234 | getBreakDecls :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO [String]
|
| 215 | -getBreakDecls = getBreakXXX modBreaks_decls
|
|
| 235 | +getBreakDecls = getBreakXXX modBreaks_decls (const [])
|
|
| 216 | 236 | |
| 217 | 237 | -- | Get the decls for this breakpoint
|
| 218 | -getBreakCCS :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO (String, String)
|
|
| 219 | -getBreakCCS = getBreakXXX modBreaks_ccs
|
|
| 238 | +getBreakCCS :: (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO (Maybe (String, String))
|
|
| 239 | +getBreakCCS = getBreakXXX (fmap Just . modBreaks_ccs) (const Nothing)
|
|
| 220 | 240 | |
| 221 | 241 | -- | Internal utility to access a ModBreaks field at a particular breakpoint index
|
| 222 | 242 | --
|
| ... | ... | @@ -228,14 +248,17 @@ getBreakCCS = getBreakXXX modBreaks_ccs |
| 228 | 248 | -- 'ModBreaks'. When the tick module is different, we need to look up the
|
| 229 | 249 | -- 'ModBreaks' in the HUG for that other module.
|
| 230 | 250 | --
|
| 251 | +-- When there is no tick module (the breakpoint was generated at codegen), use
|
|
| 252 | +-- the function on internal mod breaks.
|
|
| 253 | +--
|
|
| 231 | 254 | -- To avoid cyclic dependencies, we instead receive a function that looks up
|
| 232 | 255 | -- the 'ModBreaks' given a 'Module'
|
| 233 | -getBreakXXX :: (ModBreaks -> Array BreakTickIndex a) -> (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO a
|
|
| 234 | -getBreakXXX view lookupModule (InternalBreakpointId ibi_mod ibi_ix) imbs =
|
|
| 256 | +getBreakXXX :: (ModBreaks -> Array BreakTickIndex a) -> (InternalBreakLoc -> a) -> (Module -> IO ModBreaks) -> InternalBreakpointId -> InternalModBreaks -> IO a
|
|
| 257 | +getBreakXXX view viewInternal lookupModule (InternalBreakpointId ibi_mod ibi_ix) imbs =
|
|
| 235 | 258 | assert_modules_match ibi_mod (imodBreaks_module imbs) $ do
|
| 236 | 259 | let cgb = imodBreaks_breakInfo imbs IM.! ibi_ix
|
| 237 | 260 | case cgb_tick_id cgb of
|
| 238 | - BreakpointId{bi_tick_mod, bi_tick_index}
|
|
| 261 | + Right BreakpointId{bi_tick_mod, bi_tick_index}
|
|
| 239 | 262 | | bi_tick_mod == ibi_mod
|
| 240 | 263 | -> do
|
| 241 | 264 | let these_mbs = imodBreaks_modBreaks imbs
|
| ... | ... | @@ -244,6 +267,8 @@ getBreakXXX view lookupModule (InternalBreakpointId ibi_mod ibi_ix) imbs = |
| 244 | 267 | -> do
|
| 245 | 268 | other_mbs <- lookupModule bi_tick_mod
|
| 246 | 269 | return $ view other_mbs ! bi_tick_index
|
| 270 | + Left l ->
|
|
| 271 | + return $ viewInternal l
|
|
| 247 | 272 | |
| 248 | 273 | --------------------------------------------------------------------------------
|
| 249 | 274 | -- Instances
|
| ... | ... | @@ -260,10 +260,6 @@ data BCInstr |
| 260 | 260 | -- Breakpoints
|
| 261 | 261 | | BRK_FUN !InternalBreakpointId
|
| 262 | 262 | |
| 263 | - -- An internal breakpoint for triggering a break on any case alternative
|
|
| 264 | - -- See Note [Debugger: BRK_ALTS]
|
|
| 265 | - | BRK_ALTS !Bool {- enabled? -}
|
|
| 266 | - |
|
| 267 | 263 | #if MIN_VERSION_rts(1,0,3)
|
| 268 | 264 | -- | A "meta"-instruction for recording the name of a BCO for debugging purposes.
|
| 269 | 265 | -- These are ignored by the interpreter but helpfully printed by the disassmbler.
|
| ... | ... | @@ -458,7 +454,6 @@ instance Outputable BCInstr where |
| 458 | 454 | = text "BRK_FUN" <+> text "<breakarray>"
|
| 459 | 455 | <+> ppr info_mod <+> ppr infox
|
| 460 | 456 | <+> text "<cc>"
|
| 461 | - ppr (BRK_ALTS active) = text "BRK_ALTS" <+> ppr active
|
|
| 462 | 457 | #if MIN_VERSION_rts(1,0,3)
|
| 463 | 458 | ppr (BCO_NAME nm) = text "BCO_NAME" <+> text (show nm)
|
| 464 | 459 | #endif
|
| ... | ... | @@ -584,7 +579,6 @@ bciStackUse OP_INDEX_ADDR{} = 0 |
| 584 | 579 | |
| 585 | 580 | bciStackUse SWIZZLE{} = 0
|
| 586 | 581 | bciStackUse BRK_FUN{} = 0
|
| 587 | -bciStackUse BRK_ALTS{} = 0
|
|
| 588 | 582 | |
| 589 | 583 | -- These insns actually reduce stack use, but we need the high-tide level,
|
| 590 | 584 | -- so can't use this info. Not that it matters much.
|
| ... | ... | @@ -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
|
| ... | ... | @@ -1711,8 +1712,10 @@ allocateCCS interp ce mbss |
| 1711 | 1712 | let count = 1 + (maybe 0 fst $ IM.lookupMax imodBreaks_breakInfo)
|
| 1712 | 1713 | let ccs = IM.map
|
| 1713 | 1714 | (\info ->
|
| 1714 | - fromMaybe (toRemotePtr nullPtr)
|
|
| 1715 | - (M.lookup (cgb_tick_id info) ccss)
|
|
| 1715 | + case cgb_tick_id info of
|
|
| 1716 | + Right bi -> fromMaybe (toRemotePtr nullPtr)
|
|
| 1717 | + (M.lookup bi ccss)
|
|
| 1718 | + Left InternalBreakLoc{} -> toRemotePtr nullPtr
|
|
| 1716 | 1719 | )
|
| 1717 | 1720 | imodBreaks_breakInfo
|
| 1718 | 1721 | assertPpr (count == length ccs)
|
| ... | ... | @@ -253,8 +253,11 @@ mkBreakpointOccurrences = do |
| 253 | 253 | let imod = modBreaks_module $ imodBreaks_modBreaks ibrks
|
| 254 | 254 | IntMap.foldrWithKey (\info_ix cgi bmp -> do
|
| 255 | 255 | let ibi = InternalBreakpointId imod info_ix
|
| 256 | - let BreakpointId tick_mod tick_ix = cgb_tick_id cgi
|
|
| 257 | - extendModuleEnvWith (IntMap.unionWith (S.<>)) bmp tick_mod (IntMap.singleton tick_ix [ibi])
|
|
| 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
|
|
| 258 | 261 | ) bmp0 (imodBreaks_breakInfo ibrks)
|
| 259 | 262 | |
| 260 | 263 | --------------------------------------------------------------------------------
|
| ... | ... | @@ -287,7 +290,7 @@ getCurrentBreakModule = do |
| 287 | 290 | Nothing -> pure Nothing
|
| 288 | 291 | Just ibi -> do
|
| 289 | 292 | brks <- readIModBreaks hug ibi
|
| 290 | - return $ Just $ bi_tick_mod $ getBreakSourceId ibi brks
|
|
| 293 | + return $ Just $ getBreakSourceMod ibi brks
|
|
| 291 | 294 | ix ->
|
| 292 | 295 | Just <$> getHistoryModule hug (resumeHistory r !! (ix-1))
|
| 293 | 296 |
| ... | ... | @@ -151,7 +151,7 @@ getHistoryModule :: HUG.HomeUnitGraph -> History -> IO Module |
| 151 | 151 | getHistoryModule hug hist = do
|
| 152 | 152 | let ibi = historyBreakpointId hist
|
| 153 | 153 | brks <- readIModBreaks hug ibi
|
| 154 | - return $ bi_tick_mod $ getBreakSourceId ibi brks
|
|
| 154 | + return $ getBreakSourceMod ibi brks
|
|
| 155 | 155 | |
| 156 | 156 | getHistorySpan :: HUG.HomeUnitGraph -> History -> IO SrcSpan
|
| 157 | 157 | getHistorySpan hug hist = do
|
| ... | ... | @@ -63,7 +63,7 @@ import GHC.StgToCmm.Closure ( NonVoid(..), fromNonVoid, idPrimRepU, |
| 63 | 63 | assertNonVoidIds, assertNonVoidStgArgs )
|
| 64 | 64 | import GHC.StgToCmm.Layout
|
| 65 | 65 | import GHC.Runtime.Heap.Layout hiding (WordOff, ByteOff, wordsToBytes)
|
| 66 | -import GHC.Runtime.Interpreter ( interpreterProfiled )
|
|
| 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
|
| ... | ... | @@ -99,6 +99,7 @@ import GHC.CoreToIface |
| 99 | 99 | import Control.Monad.IO.Class
|
| 100 | 100 | import Control.Monad.Trans.Reader (ReaderT(..))
|
| 101 | 101 | import Control.Monad.Trans.State (StateT(..))
|
| 102 | +import Data.Array ((!))
|
|
| 102 | 103 | |
| 103 | 104 | -- -----------------------------------------------------------------------------
|
| 104 | 105 | -- Generating byte code for a complete module
|
| ... | ... | @@ -393,26 +394,26 @@ schemeR_wrk fvs nm original_body (args, body) |
| 393 | 394 | -- | Introduce break instructions for ticked expressions.
|
| 394 | 395 | -- If no breakpoint information is available, the instruction is omitted.
|
| 395 | 396 | schemeER_wrk :: StackDepth -> BCEnv -> CgStgExpr -> BcM BCInstrList
|
| 396 | -schemeER_wrk d p (StgTick (Breakpoint tick_ty tick_id fvs) rhs) = do
|
|
| 397 | - code <- schemeE d 0 p rhs
|
|
| 398 | - mb_current_mod_breaks <- getCurrentModBreaks
|
|
| 399 | - case mb_current_mod_breaks of
|
|
| 400 | - -- if we're not generating ModBreaks for this module for some reason, we
|
|
| 401 | - -- can't store breakpoint occurrence information.
|
|
| 402 | - Nothing -> pure code
|
|
| 403 | - Just current_mod_breaks -> do
|
|
| 404 | - platform <- profilePlatform <$> getProfile
|
|
| 405 | - let idOffSets = getVarOffSets platform d p fvs
|
|
| 406 | - ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
|
|
| 407 | - toWord :: Maybe (Id, WordOff) -> Maybe (Id, Word)
|
|
| 408 | - toWord = fmap (\(i, wo) -> (i, fromIntegral wo))
|
|
| 409 | - breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty tick_id
|
|
| 397 | +schemeER_wrk d p (StgTick bp@(Breakpoint tick_ty tick_id fvs) rhs) = do
|
|
| 398 | + platform <- profilePlatform <$> getProfile
|
|
| 399 | + |
|
| 400 | + -- When we find a tick we update the "last breakpoint location".
|
|
| 401 | + -- We use it when constructing step-out BRK_FUNs in doCase
|
|
| 402 | + -- See Note [Stepout breakpoint locations]
|
|
| 403 | + code <- withBreakTick bp $ schemeE d 0 p rhs
|
|
| 404 | + |
|
| 405 | + let idOffSets = getVarOffSets platform d p fvs
|
|
| 406 | + ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
|
|
| 407 | + toWord :: Maybe (Id, WordOff) -> Maybe (Id, Word)
|
|
| 408 | + toWord = fmap (\(i, wo) -> (i, fromIntegral wo))
|
|
| 409 | + breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty (Right tick_id)
|
|
| 410 | 410 | |
| 411 | - let info_mod = modBreaks_module current_mod_breaks
|
|
| 412 | - infox <- newBreakInfo breakInfo
|
|
| 411 | + mibi <- newBreakInfo breakInfo
|
|
| 412 | + |
|
| 413 | + return $ case mibi of
|
|
| 414 | + Nothing -> code
|
|
| 415 | + Just ibi -> BRK_FUN ibi `consOL` code
|
|
| 413 | 416 | |
| 414 | - let breakInstr = BRK_FUN (InternalBreakpointId info_mod infox)
|
|
| 415 | - return $ breakInstr `consOL` code
|
|
| 416 | 417 | schemeER_wrk d p rhs = schemeE d 0 p rhs
|
| 417 | 418 | |
| 418 | 419 | getVarOffSets :: Platform -> StackDepth -> BCEnv -> [Id] -> [Maybe (Id, WordOff)]
|
| ... | ... | @@ -748,12 +749,21 @@ doTailCall init_d s p fn args = do |
| 748 | 749 | |
| 749 | 750 | where
|
| 750 | 751 | do_pushes !d [] reps = do
|
| 751 | - assert (null reps) return ()
|
|
| 752 | - (push_fn, sz) <- pushAtom d p (StgVarArg fn)
|
|
| 753 | 752 | platform <- profilePlatform <$> getProfile
|
| 754 | - assert (sz == wordSize platform) return ()
|
|
| 755 | - let slide = mkSlideB platform (d - init_d + wordSize platform) (init_d - s)
|
|
| 756 | - return (push_fn `appOL` (slide `appOL` unitOL ENTER))
|
|
| 753 | + assert (null reps) return ()
|
|
| 754 | + case lookupBCEnv_maybe fn p of
|
|
| 755 | + Just d_v
|
|
| 756 | + | d - d_v == 0 -- shortcut; the first thing on the stack is what we want to enter,
|
|
| 757 | + , d_v <= init_d -- and it is between init_d and sequel (which would be dropped)
|
|
| 758 | + -> do
|
|
| 759 | + let slide = mkSlideB platform (d - init_d + wordSize platform)
|
|
| 760 | + (init_d - s - wordSize platform)
|
|
| 761 | + return (slide `appOL` unitOL ENTER)
|
|
| 762 | + _ -> do
|
|
| 763 | + (push_fn, sz) <- pushAtom d p (StgVarArg fn)
|
|
| 764 | + assert (sz == wordSize platform) return ()
|
|
| 765 | + let slide = mkSlideB platform (d - init_d + wordSize platform) (init_d - s)
|
|
| 766 | + return (push_fn `appOL` (slide `appOL` unitOL ENTER))
|
|
| 757 | 767 | do_pushes !d args reps = do
|
| 758 | 768 | let (push_apply, n, rest_of_reps) = findPushSeq reps
|
| 759 | 769 | (these_args, rest_of_args) = splitAt n args
|
| ... | ... | @@ -1325,19 +1335,35 @@ doCase d s p scrut bndr alts |
| 1325 | 1335 | | ubx_tuple_frame = SLIDE 0 3 `consOL` alt_final1
|
| 1326 | 1336 | | otherwise = SLIDE 0 1 `consOL` alt_final1
|
| 1327 | 1337 | |
| 1328 | - -- When entering a case continuation BCO, the stack is always headed
|
|
| 1329 | - -- by the stg_ret frame and the stg_ctoi frame that returned to it.
|
|
| 1330 | - -- See Note [Stack layout when entering run_BCO]
|
|
| 1331 | - --
|
|
| 1332 | - -- Right after the breakpoint instruction, a case continuation BCO
|
|
| 1333 | - -- drops the stg_ret and stg_ctoi frame headers (see alt_final1,
|
|
| 1334 | - -- alt_final2), leaving the stack with the scrutinee followed by the
|
|
| 1335 | - -- free variables (with depth==d_bndr)
|
|
| 1336 | - alt_final
|
|
| 1337 | - | gopt Opt_InsertBreakpoints (hsc_dflags hsc_env)
|
|
| 1338 | - -- See Note [Debugger: BRK_ALTS]
|
|
| 1339 | - = BRK_ALTS False `consOL` alt_final2
|
|
| 1340 | - | otherwise = alt_final2
|
|
| 1338 | + -- When entering a case continuation BCO, the stack is always headed
|
|
| 1339 | + -- by the stg_ret frame and the stg_ctoi frame that returned to it.
|
|
| 1340 | + -- See Note [Stack layout when entering run_BCO]
|
|
| 1341 | + --
|
|
| 1342 | + -- Right after the breakpoint instruction, a case continuation BCO
|
|
| 1343 | + -- drops the stg_ret and stg_ctoi frame headers (see alt_final1,
|
|
| 1344 | + -- alt_final2), leaving the stack with the scrutinee followed by the
|
|
| 1345 | + -- free variables (with depth==d_bndr)
|
|
| 1346 | + alt_final <- getLastBreakTick >>= \case
|
|
| 1347 | + Just (Breakpoint tick_ty tick_id fvs)
|
|
| 1348 | + | gopt Opt_InsertBreakpoints (hsc_dflags hsc_env)
|
|
| 1349 | + -- Construct an internal breakpoint to put at the start of this case
|
|
| 1350 | + -- continuation BCO, for step-out.
|
|
| 1351 | + -- See Note [Debugger: Stepout internal break locs]
|
|
| 1352 | + -> do
|
|
| 1353 | + internal_tick_loc <- makeCaseInternalBreakLoc tick_id
|
|
| 1354 | + |
|
| 1355 | + -- same fvs available in the case expression are available in the case continuation
|
|
| 1356 | + let idOffSets = getVarOffSets platform d p fvs
|
|
| 1357 | + ty_vars = tyCoVarsOfTypesWellScoped (tick_ty:map idType fvs)
|
|
| 1358 | + toWord :: Maybe (Id, WordOff) -> Maybe (Id, Word)
|
|
| 1359 | + toWord = fmap (\(i, wo) -> (i, fromIntegral wo))
|
|
| 1360 | + breakInfo = dehydrateCgBreakInfo ty_vars (map toWord idOffSets) tick_ty (Left internal_tick_loc)
|
|
| 1361 | + |
|
| 1362 | + mibi <- newBreakInfo breakInfo
|
|
| 1363 | + return $ case mibi of
|
|
| 1364 | + Nothing -> alt_final2
|
|
| 1365 | + Just ibi -> BRK_FUN ibi `consOL` alt_final2
|
|
| 1366 | + _ -> pure alt_final2
|
|
| 1341 | 1367 | |
| 1342 | 1368 | add_bco_name <- shouldAddBcoName
|
| 1343 | 1369 | let
|
| ... | ... | @@ -1357,72 +1383,122 @@ doCase d s p scrut bndr alts |
| 1357 | 1383 | _ -> panic "schemeE(StgCase).push_alts"
|
| 1358 | 1384 | in return (PUSH_ALTS alt_bco scrut_rep `consOL` scrut_code)
|
| 1359 | 1385 | |
| 1386 | +-- | Come up with an 'InternalBreakLoc' from the location of the given 'BreakpointId'.
|
|
| 1387 | +-- See also Note [Debugger: Stepout internal break locs]
|
|
| 1388 | +makeCaseInternalBreakLoc :: BreakpointId -> BcM InternalBreakLoc
|
|
| 1389 | +makeCaseInternalBreakLoc bid = do
|
|
| 1390 | + hug <- hsc_HUG <$> getHscEnv
|
|
| 1391 | + curr_mod <- getCurrentModule
|
|
| 1392 | + mb_mod_brks <- getCurrentModBreaks
|
|
| 1393 | + |
|
| 1394 | + InternalBreakLoc <$> case bid of
|
|
| 1395 | + BreakpointId{bi_tick_mod, bi_tick_index}
|
|
| 1396 | + | bi_tick_mod == curr_mod
|
|
| 1397 | + , Just these_mbs <- mb_mod_brks
|
|
| 1398 | + -> do
|
|
| 1399 | + return $ modBreaks_locs these_mbs ! bi_tick_index
|
|
| 1400 | + | otherwise
|
|
| 1401 | + -> do
|
|
| 1402 | + other_mbs <- liftIO $ readIModModBreaks hug bi_tick_mod
|
|
| 1403 | + return $ modBreaks_locs other_mbs ! bi_tick_index
|
|
| 1404 | + |
|
| 1360 | 1405 | {-
|
| 1361 | -Note [Debugger: BRK_ALTS]
|
|
| 1362 | -~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1363 | -As described in Note [Debugger: Step-out] in rts/Interpreter.c, to implement
|
|
| 1364 | -the stepping-out debugger feature we traverse the stack at runtime, identify
|
|
| 1365 | -the first continuation BCO, and explicitly enable that BCO's breakpoint thus
|
|
| 1366 | -ensuring that we stop exactly when we return to the continuation.
|
|
| 1367 | - |
|
| 1368 | -However, case continuation BCOs (produced by PUSH_ALTS and which merely compute
|
|
| 1369 | -which case alternative BCO to enter next) contain no user-facing breakpoint
|
|
| 1370 | -ticks (BRK_FUN). While we could in principle add breakpoints in case continuation
|
|
| 1371 | -BCOs, there are a few reasons why this is not an attractive option:
|
|
| 1372 | - |
|
| 1373 | - 1) It's not useful to a user stepping through the program to always have a
|
|
| 1374 | - breakpoint after the scrutinee is evaluated but before the case alternative
|
|
| 1375 | - is selected. The source span associated with such a breakpoint would also be
|
|
| 1376 | - slightly awkward to choose.
|
|
| 1377 | - |
|
| 1378 | - 2) It's not easy to add a breakpoint tick before the case alternatives because in
|
|
| 1379 | - essentially all internal representations they are given as a list of Alts
|
|
| 1380 | - rather than an expression.
|
|
| 1381 | - |
|
| 1382 | -To provide the debugger a way to break in a case continuation
|
|
| 1383 | -despite the BCOs' lack of BRK_FUNs, we introduce an alternative
|
|
| 1384 | -type of breakpoint, represented by the BRK_ALTS instruction,
|
|
| 1385 | -at the start of every case continuation BCO. For instance,
|
|
| 1386 | - |
|
| 1387 | - case x of
|
|
| 1388 | - 0# -> ...
|
|
| 1389 | - _ -> ...
|
|
| 1390 | - |
|
| 1391 | -will produce a continuation of the form (N.B. the below bytecode
|
|
| 1392 | -is simplified):
|
|
| 1393 | - |
|
| 1394 | - PUSH_ALTS P
|
|
| 1395 | - BRK_ALTS 0
|
|
| 1396 | - TESTEQ_I 0 lblA
|
|
| 1397 | - PUSH_BCO
|
|
| 1398 | - BRK_FUN 0
|
|
| 1399 | - -- body of 0# alternative
|
|
| 1400 | - ENTER
|
|
| 1401 | - |
|
| 1402 | - lblA:
|
|
| 1403 | - PUSH_BCO
|
|
| 1404 | - BRK_FUN 1
|
|
| 1405 | - -- body of wildcard alternative
|
|
| 1406 | - ENTER
|
|
| 1407 | - |
|
| 1408 | -When enabled (by its single boolean operand), the BRK_ALTS instruction causes
|
|
| 1409 | -the program to break at the next encountered breakpoint (implemented
|
|
| 1410 | -by setting the TSO's TSO_STOP_NEXT_BREAKPOINT flag). Since the case
|
|
| 1411 | -continuation BCO will ultimately jump to one of the alternatives (each of
|
|
| 1412 | -which having its own BRK_FUN) we are guaranteed to stop in the taken alternative.
|
|
| 1413 | - |
|
| 1414 | -It's important that BRK_ALTS (just like BRK_FUN) is the first instruction of
|
|
| 1415 | -the BCO, since that's where the debugger will look to enable it at runtime.
|
|
| 1416 | - |
|
| 1417 | -KNOWN ISSUES:
|
|
| 1418 | --------------
|
|
| 1419 | -This implementation of BRK_ALTS that modifies the first argument of the
|
|
| 1420 | -bytecode to enable it does not allow multi-threaded debugging because the BCO
|
|
| 1421 | -object is shared across threads and enabling the breakpoint in one will enable
|
|
| 1422 | -it in all other threads too. This will have to change to support multi-threads
|
|
| 1423 | -debugging.
|
|
| 1424 | - |
|
| 1425 | -The progress towards multi-threaded debugging is tracked by #26064
|
|
| 1406 | +Note [Debugger: Stepout internal break locs]
|
|
| 1407 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1408 | +Step-out tells the interpreter to run until the current function
|
|
| 1409 | +returns to where it was called from, and stop there.
|
|
| 1410 | + |
|
| 1411 | +This is achieved by enabling the BRK_FUN found on the first RET_BCO
|
|
| 1412 | +frame on the stack (See [Note Debugger: Step-out]).
|
|
| 1413 | + |
|
| 1414 | +Case continuation BCOs (which select an alternative branch) must
|
|
| 1415 | +therefore be headed by a BRK_FUN. An example:
|
|
| 1416 | + |
|
| 1417 | + f x = case g x of <--- end up here
|
|
| 1418 | + 1 -> ...
|
|
| 1419 | + 2 -> ...
|
|
| 1420 | + |
|
| 1421 | + g y = ... <--- step out from here
|
|
| 1422 | + |
|
| 1423 | +- `g` will return a value to the case continuation BCO in `f`
|
|
| 1424 | +- The case continuation BCO will receive the value returned from g
|
|
| 1425 | +- Match on it and push the alternative continuation for that branch
|
|
| 1426 | +- And then enter that alternative.
|
|
| 1427 | + |
|
| 1428 | +If we step-out of `g`, the first RET_BCO on the stack is the case
|
|
| 1429 | +continuation of `f` -- execution should stop at its start, before
|
|
| 1430 | +selecting an alternative. (One might ask, "why not enable the breakpoint
|
|
| 1431 | +in the alternative instead?", because the alternative continuation is
|
|
| 1432 | +only pushed to the stack *after* it is selected by the case cont. BCO)
|
|
| 1433 | + |
|
| 1434 | +However, the case cont. BCO is not associated with any source-level
|
|
| 1435 | +tick, it is merely the glue code which selects alternatives which do
|
|
| 1436 | +have source level ticks. Therefore, we have to come up at code
|
|
| 1437 | +generation time with a breakpoint location ('InternalBreakLoc') to
|
|
| 1438 | +display to the user when it is stopped there.
|
|
| 1439 | + |
|
| 1440 | +Our solution is to use the last tick seen just before reaching the case
|
|
| 1441 | +continuation. This is robust because a case continuation will thus
|
|
| 1442 | +always have a relevant breakpoint location:
|
|
| 1443 | + |
|
| 1444 | + - The source location will be the last source-relevant expression
|
|
| 1445 | + executed before the continuation is pushed
|
|
| 1446 | + |
|
| 1447 | + - So the source location will point to the thing you've just stepped
|
|
| 1448 | + out of
|
|
| 1449 | + |
|
| 1450 | + - Doing :step-local from there will put you on the selected
|
|
| 1451 | + alternative (which at the source level may also be the e.g. next
|
|
| 1452 | + line in a do-block)
|
|
| 1453 | + |
|
| 1454 | +Examples, using angle brackets (<<...>>) to denote the breakpoint span:
|
|
| 1455 | + |
|
| 1456 | + f x = case <<g x>> {- step in here -} of
|
|
| 1457 | + 1 -> ...
|
|
| 1458 | + 2 -> ...>
|
|
| 1459 | + |
|
| 1460 | + g y = <<...>> <--- step out from here
|
|
| 1461 | + |
|
| 1462 | + ...
|
|
| 1463 | + |
|
| 1464 | + f x = <<case g x of <--- end up here, whole case highlighted
|
|
| 1465 | + 1 -> ...
|
|
| 1466 | + 2 -> ...>>
|
|
| 1467 | + |
|
| 1468 | + doing :step-local ...
|
|
| 1469 | + |
|
| 1470 | + f x = case g x of
|
|
| 1471 | + 1 -> <<...>> <--- stop in the alternative
|
|
| 1472 | + 2 -> ...
|
|
| 1473 | + |
|
| 1474 | +A second example based on T26042d2, where the source is a do-block IO
|
|
| 1475 | +action, optimised to a chain of `case expressions`.
|
|
| 1476 | + |
|
| 1477 | + main = do
|
|
| 1478 | + putStrLn "hello1"
|
|
| 1479 | + <<f>> <--- step-in here
|
|
| 1480 | + putStrLn "hello3"
|
|
| 1481 | + putStrLn "hello4"
|
|
| 1482 | + |
|
| 1483 | + f = do
|
|
| 1484 | + <<putStrLn "hello2.1">> <--- step-out from here
|
|
| 1485 | + putStrLn "hello2.2"
|
|
| 1486 | + |
|
| 1487 | + ...
|
|
| 1488 | + |
|
| 1489 | + main = do
|
|
| 1490 | + putStrLn "hello1"
|
|
| 1491 | + <<f>> <--- end up here again, the previously executed expression
|
|
| 1492 | + putStrLn "hello3"
|
|
| 1493 | + putStrLn "hello4"
|
|
| 1494 | + |
|
| 1495 | + doing step/step-local ...
|
|
| 1496 | + |
|
| 1497 | + main = do
|
|
| 1498 | + putStrLn "hello1"
|
|
| 1499 | + f
|
|
| 1500 | + <<putStrLn "hello3">> <--- straight to the next line
|
|
| 1501 | + putStrLn "hello4"
|
|
| 1426 | 1502 | -}
|
| 1427 | 1503 | |
| 1428 | 1504 | -- -----------------------------------------------------------------------------
|
| ... | ... | @@ -2625,6 +2701,7 @@ data BcM_Env |
| 2625 | 2701 | { bcm_hsc_env :: !HscEnv
|
| 2626 | 2702 | , bcm_module :: !Module -- current module (for breakpoints)
|
| 2627 | 2703 | , modBreaks :: !(Maybe ModBreaks)
|
| 2704 | + , last_bp_tick :: !(Maybe StgTickish)
|
|
| 2628 | 2705 | }
|
| 2629 | 2706 | |
| 2630 | 2707 | data BcM_State
|
| ... | ... | @@ -2643,7 +2720,7 @@ newtype BcM r = BcM (BcM_Env -> BcM_State -> IO (r, BcM_State)) |
| 2643 | 2720 | |
| 2644 | 2721 | runBc :: HscEnv -> Module -> Maybe ModBreaks -> BcM r -> IO (r, BcM_State)
|
| 2645 | 2722 | runBc hsc_env this_mod mbs (BcM m)
|
| 2646 | - = m (BcM_Env hsc_env this_mod mbs) (BcM_State 0 0 IntMap.empty)
|
|
| 2723 | + = m (BcM_Env hsc_env this_mod mbs Nothing) (BcM_State 0 0 IntMap.empty)
|
|
| 2647 | 2724 | |
| 2648 | 2725 | instance HasDynFlags BcM where
|
| 2649 | 2726 | getDynFlags = hsc_dflags <$> getHscEnv
|
| ... | ... | @@ -2673,14 +2750,19 @@ getLabelsBc n = BcM $ \_ st -> |
| 2673 | 2750 | let ctr = nextlabel st
|
| 2674 | 2751 | in return (coerce [ctr .. ctr+n-1], st{nextlabel = ctr+n})
|
| 2675 | 2752 | |
| 2676 | -newBreakInfo :: CgBreakInfo -> BcM Int
|
|
| 2677 | -newBreakInfo info = BcM $ \_ st ->
|
|
| 2678 | - let ix = breakInfoIdx st
|
|
| 2679 | - st' = st
|
|
| 2680 | - { breakInfo = IntMap.insert ix info (breakInfo st)
|
|
| 2681 | - , breakInfoIdx = ix + 1
|
|
| 2682 | - }
|
|
| 2683 | - in return (ix, st')
|
|
| 2753 | +newBreakInfo :: CgBreakInfo -> BcM (Maybe InternalBreakpointId)
|
|
| 2754 | +newBreakInfo info = BcM $ \env st -> do
|
|
| 2755 | + -- if we're not generating ModBreaks for this module for some reason, we
|
|
| 2756 | + -- can't store breakpoint occurrence information.
|
|
| 2757 | + case modBreaks env of
|
|
| 2758 | + Nothing -> pure (Nothing, st)
|
|
| 2759 | + Just modBreaks -> do
|
|
| 2760 | + let ix = breakInfoIdx st
|
|
| 2761 | + st' = st
|
|
| 2762 | + { breakInfo = IntMap.insert ix info (breakInfo st)
|
|
| 2763 | + , breakInfoIdx = ix + 1
|
|
| 2764 | + }
|
|
| 2765 | + return (Just $ InternalBreakpointId (modBreaks_module modBreaks) ix, st')
|
|
| 2684 | 2766 | |
| 2685 | 2767 | getCurrentModule :: BcM Module
|
| 2686 | 2768 | getCurrentModule = BcM $ \env st -> return (bcm_module env, st)
|
| ... | ... | @@ -2688,12 +2770,20 @@ getCurrentModule = BcM $ \env st -> return (bcm_module env, st) |
| 2688 | 2770 | getCurrentModBreaks :: BcM (Maybe ModBreaks)
|
| 2689 | 2771 | getCurrentModBreaks = BcM $ \env st -> return (modBreaks env, st)
|
| 2690 | 2772 | |
| 2773 | +withBreakTick :: StgTickish -> BcM a -> BcM a
|
|
| 2774 | +withBreakTick bp (BcM act) = BcM $ \env st ->
|
|
| 2775 | + act env{last_bp_tick=Just bp} st
|
|
| 2776 | + |
|
| 2777 | +getLastBreakTick :: BcM (Maybe StgTickish)
|
|
| 2778 | +getLastBreakTick = BcM $ \env st ->
|
|
| 2779 | + pure (last_bp_tick env, st)
|
|
| 2780 | + |
|
| 2691 | 2781 | tickFS :: FastString
|
| 2692 | 2782 | tickFS = fsLit "ticked"
|
| 2693 | 2783 | |
| 2694 | 2784 | -- Dehydrating CgBreakInfo
|
| 2695 | 2785 | |
| 2696 | -dehydrateCgBreakInfo :: [TyVar] -> [Maybe (Id, Word)] -> Type -> BreakpointId -> CgBreakInfo
|
|
| 2786 | +dehydrateCgBreakInfo :: [TyVar] -> [Maybe (Id, Word)] -> Type -> Either InternalBreakLoc BreakpointId -> CgBreakInfo
|
|
| 2697 | 2787 | dehydrateCgBreakInfo ty_vars idOffSets tick_ty bid =
|
| 2698 | 2788 | CgBreakInfo
|
| 2699 | 2789 | { cgb_tyvars = map toIfaceTvBndr ty_vars
|
| ... | ... | @@ -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, InternalBreakpointId(..), getBreakSourceId)
|
|
| 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 )
|
| ... | ... | @@ -1621,7 +1621,7 @@ toBreakIdAndLocation (Just inf) = do |
| 1621 | 1621 | brks <- liftIO $ readIModBreaks hug inf
|
| 1622 | 1622 | let bi = getBreakSourceId inf brks
|
| 1623 | 1623 | return $ listToMaybe [ id_loc | id_loc@(_,loc) <- IntMap.assocs (breaks st),
|
| 1624 | - breakId loc == bi ]
|
|
| 1624 | + Right (breakId loc) == bi ]
|
|
| 1625 | 1625 | |
| 1626 | 1626 | printStoppedAtBreakInfo :: GHC.GhcMonad m => Resume -> [Name] -> m ()
|
| 1627 | 1627 | printStoppedAtBreakInfo res names = do
|
| ... | ... | @@ -3825,7 +3825,7 @@ pprStopped res = do |
| 3825 | 3825 | hug <- hsc_HUG <$> GHC.getSession
|
| 3826 | 3826 | brks <- liftIO $ readIModBreaks hug ibi
|
| 3827 | 3827 | return $ Just $ moduleName $
|
| 3828 | - bi_tick_mod $ getBreakSourceId ibi brks
|
|
| 3828 | + getBreakSourceMod ibi brks
|
|
| 3829 | 3829 | return $
|
| 3830 | 3830 | text "Stopped in"
|
| 3831 | 3831 | <+> ((case mb_mod_name of
|
| ... | ... | @@ -101,9 +101,6 @@ disInstr ( StgBCO *bco, int pc ) |
| 101 | 101 | }
|
| 102 | 102 | debugBelch("\n");
|
| 103 | 103 | break; }
|
| 104 | - case bci_BRK_ALTS:
|
|
| 105 | - debugBelch ("BRK_ALTS %d\n", BCO_NEXT);
|
|
| 106 | - break;
|
|
| 107 | 104 | case bci_SWIZZLE: {
|
| 108 | 105 | W_ stkoff = BCO_GET_LARGE_ARG;
|
| 109 | 106 | StgInt by = BCO_GET_LARGE_ARG;
|
| ... | ... | @@ -370,16 +370,11 @@ to the continuation. |
| 370 | 370 | To achieve this, when the flag is set as the interpreter is re-entered:
|
| 371 | 371 | (1) Traverse the stack until a RET_BCO frame is found or we otherwise hit the
|
| 372 | 372 | bottom (STOP_FRAME).
|
| 373 | - (2) Look for a breakpoint instruction heading the BCO instructions (a
|
|
| 373 | + (2) Look for a BRK_FUN instruction heading the BCO instructions (a
|
|
| 374 | 374 | breakpoint, when present, is always the first instruction in a BCO)
|
| 375 | 375 | |
| 376 | - (2a) For PUSH_ALT BCOs, the breakpoint instruction will be BRK_ALTS
|
|
| 377 | - (as explained in Note [Debugger: BRK_ALTS]) and it can be enabled by
|
|
| 378 | - setting its first operand to 1.
|
|
| 379 | - |
|
| 380 | - (2b) Otherwise, the instruction will be BRK_FUN and the breakpoint can be
|
|
| 381 | - enabled by setting the associated BreakArray at the associated tick
|
|
| 382 | - index to 0.
|
|
| 376 | + The breakpoint can be enabled by setting the associated BreakArray at the
|
|
| 377 | + associated internal breakpoint index to 0.
|
|
| 383 | 378 | |
| 384 | 379 | By simply enabling the breakpoint heading the continuation we can ensure that
|
| 385 | 380 | when it is returned to we will stop there without additional work -- it
|
| ... | ... | @@ -740,8 +735,8 @@ interpretBCO (Capability* cap) |
| 740 | 735 | int bciPtr = 0;
|
| 741 | 736 | StgWord16 bci = BCO_NEXT;
|
| 742 | 737 | |
| 743 | - /* A breakpoint instruction (BRK_FUN or BRK_ALTS) is always the first
|
|
| 744 | - * instruction in a BCO */
|
|
| 738 | + /* A breakpoint instruction (BRK_FUN) can only be the first instruction
|
|
| 739 | + * in a BCO */
|
|
| 745 | 740 | if ((bci & 0xFF) == bci_BRK_FUN) {
|
| 746 | 741 | |
| 747 | 742 | W_ arg1_brk_array, arg4_info_index;
|
| ... | ... | @@ -756,10 +751,6 @@ interpretBCO (Capability* cap) |
| 756 | 751 | // ACTIVATE the breakpoint by tick index
|
| 757 | 752 | ((StgInt*)breakPoints->payload)[arg4_info_index] = 0;
|
| 758 | 753 | }
|
| 759 | - else if ((bci & 0xFF) == bci_BRK_ALTS) {
|
|
| 760 | - // ACTIVATE BRK_ALTS by setting its only argument to ON
|
|
| 761 | - instrs[1] = 1;
|
|
| 762 | - }
|
|
| 763 | 754 | // else: if there is no BRK instruction perhaps we should keep
|
| 764 | 755 | // traversing; that said, the continuation should always have a BRK
|
| 765 | 756 | }
|
| ... | ... | @@ -1804,17 +1795,6 @@ run_BCO: |
| 1804 | 1795 | goto nextInsn;
|
| 1805 | 1796 | }
|
| 1806 | 1797 | |
| 1807 | - /* See Note [Debugger: BRK_ALTS] */
|
|
| 1808 | - case bci_BRK_ALTS:
|
|
| 1809 | - {
|
|
| 1810 | - StgWord16 active = BCO_NEXT;
|
|
| 1811 | - if (active) {
|
|
| 1812 | - cap->r.rCurrentTSO->flags |= TSO_STOP_NEXT_BREAKPOINT;
|
|
| 1813 | - }
|
|
| 1814 | - |
|
| 1815 | - goto nextInsn;
|
|
| 1816 | - }
|
|
| 1817 | - |
|
| 1818 | 1798 | case bci_STKCHECK: {
|
| 1819 | 1799 | // Explicit stack check at the beginning of a function
|
| 1820 | 1800 | // *only* (stack checks in case alternatives are
|
| ... | ... | @@ -214,8 +214,6 @@ |
| 214 | 214 | #define bci_OP_INDEX_ADDR_32 242
|
| 215 | 215 | #define bci_OP_INDEX_ADDR_64 243
|
| 216 | 216 | |
| 217 | -#define bci_BRK_ALTS 244
|
|
| 218 | - |
|
| 219 | 217 | |
| 220 | 218 | /* If you need to go past 255 then you will run into the flags */
|
| 221 | 219 |
| ... | ... | @@ -8,35 +8,32 @@ _result :: |
| 8 | 8 | 10 foo True i = return i
|
| 9 | 9 | ^^^^^^^^
|
| 10 | 10 | 11 foo False _ = do
|
| 11 | -Stopped in Main.bar, T26042b.hs:21:3-10
|
|
| 11 | +Stopped in Main., T26042b.hs:20:3-17
|
|
| 12 | 12 | _result ::
|
| 13 | 13 | GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
| 14 | 14 | -> (# GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld,
|
| 15 | 15 | Int #) = _
|
| 16 | -y :: Int = _
|
|
| 16 | +19 let t = z * 2
|
|
| 17 | 17 | 20 y <- foo True t
|
| 18 | + ^^^^^^^^^^^^^^^
|
|
| 18 | 19 | 21 return y
|
| 19 | - ^^^^^^^^
|
|
| 20 | -22
|
|
| 21 | -Stopped in Main.foo, T26042b.hs:15:3-10
|
|
| 20 | +Stopped in Main., T26042b.hs:14:3-18
|
|
| 22 | 21 | _result ::
|
| 23 | 22 | GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
| 24 | 23 | -> (# GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld,
|
| 25 | 24 | Int #) = _
|
| 26 | -n :: Int = _
|
|
| 25 | +13 y = 4
|
|
| 27 | 26 | 14 n <- bar (x + y)
|
| 27 | + ^^^^^^^^^^^^^^^^
|
|
| 28 | 28 | 15 return n
|
| 29 | - ^^^^^^^^
|
|
| 30 | -16
|
|
| 31 | -Stopped in Main.main, T26042b.hs:6:3-9
|
|
| 29 | +Stopped in Main., T26042b.hs:5:3-26
|
|
| 32 | 30 | _result ::
|
| 33 | 31 | GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
| 34 | 32 | -> (# GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld,
|
| 35 | 33 | () #) = _
|
| 36 | -a :: Int = _
|
|
| 34 | +4 main = do
|
|
| 37 | 35 | 5 a <- foo False undefined
|
| 36 | + ^^^^^^^^^^^^^^^^^^^^^^^^
|
|
| 38 | 37 | 6 print a
|
| 39 | - ^^^^^^^
|
|
| 40 | -7 print a
|
|
| 41 | 38 | 14
|
| 42 | 39 | 14 |
| ... | ... | @@ -14,15 +14,7 @@ main |
| 14 | 14 | -- we go straight to `main`.
|
| 15 | 15 | :stepout
|
| 16 | 16 | :list
|
| 17 | --- stepping out from here will stop in the thunk (TODO: WHY?)
|
|
| 18 | -:stepout
|
|
| 19 | -:list
|
|
| 20 | - |
|
| 21 | --- bring us back to main from the thunk (why were we stopped there?...)
|
|
| 22 | -:stepout
|
|
| 23 | -:list
|
|
| 24 | - |
|
| 25 | --- and finally out
|
|
| 17 | +-- stepping out from here will exit main
|
|
| 26 | 18 | :stepout
|
| 27 | 19 | |
| 28 | 20 | -- this test is also run with optimisation to make sure the IO bindings inline and we can stop at them |
| ... | ... | @@ -8,17 +8,14 @@ _result :: |
| 8 | 8 | 10 foo True i = return i
|
| 9 | 9 | ^^^^^^^^
|
| 10 | 10 | 11 foo False _ = do
|
| 11 | -Stopped in Main.main, T26042c.hs:6:3-9
|
|
| 11 | +Stopped in Main., T26042c.hs:5:3-26
|
|
| 12 | 12 | _result ::
|
| 13 | 13 | GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
| 14 | 14 | -> (# GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld,
|
| 15 | 15 | () #) = _
|
| 16 | -a :: Int = _
|
|
| 16 | +4 main = do
|
|
| 17 | 17 | 5 a <- foo False undefined
|
| 18 | + ^^^^^^^^^^^^^^^^^^^^^^^^
|
|
| 18 | 19 | 6 print a
|
| 19 | - ^^^^^^^
|
|
| 20 | -7 print a
|
|
| 21 | 20 | 14
|
| 22 | 21 | 14 |
| 23 | -not stopped at a breakpoint
|
|
| 24 | -not stopped at a breakpoint |
| 1 | + |
|
| 2 | +module Main where
|
|
| 3 | + |
|
| 4 | +main = do
|
|
| 5 | + putStrLn "hello1"
|
|
| 6 | + f
|
|
| 7 | + putStrLn "hello3"
|
|
| 8 | + putStrLn "hello4"
|
|
| 9 | + |
|
| 10 | +f = do
|
|
| 11 | + putStrLn "hello2.1"
|
|
| 12 | + putStrLn "hello2.2"
|
|
| 13 | +{-# NOINLINE f #-} |
| 1 | +:load T26042d2.hs
|
|
| 2 | + |
|
| 3 | +:break 11
|
|
| 4 | +main
|
|
| 5 | +:list
|
|
| 6 | +:stepout
|
|
| 7 | +:list
|
|
| 8 | +:stepout
|
|
| 9 | + |
|
| 10 | +-- should exit! we compile this test case with -O1 to make sure the monad >> are inlined
|
|
| 11 | +-- and thus the test relies on the filtering behavior based on SrcSpans for stepout
|
|
| 12 | + |
| 1 | +Breakpoint 0 activated at T26042d2.hs:11:3-21
|
|
| 2 | +hello1
|
|
| 3 | +Stopped in Main.f, T26042d2.hs:11:3-21
|
|
| 4 | +_result ::
|
|
| 5 | + GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
|
| 6 | + -> (# GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld,
|
|
| 7 | + () #) = _
|
|
| 8 | +10 f = do
|
|
| 9 | +11 putStrLn "hello2.1"
|
|
| 10 | + ^^^^^^^^^^^^^^^^^^^
|
|
| 11 | +12 putStrLn "hello2.2"
|
|
| 12 | +hello2.1
|
|
| 13 | +hello2.2
|
|
| 14 | +Stopped in Main., T26042d2.hs:6:3
|
|
| 15 | +_result ::
|
|
| 16 | + GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld
|
|
| 17 | + -> (# GHC.Internal.Prim.State# GHC.Internal.Prim.RealWorld,
|
|
| 18 | + () #) = _
|
|
| 19 | +5 putStrLn "hello1"
|
|
| 20 | +6 f
|
|
| 21 | + ^
|
|
| 22 | +7 putStrLn "hello3"
|
|
| 23 | +hello3
|
|
| 24 | +hello4 |
| ... | ... | @@ -7,14 +7,12 @@ y :: [a1] -> Int = _ |
| 7 | 7 | 11 let !z = y x
|
| 8 | 8 | ^^^^^^^^^^^^
|
| 9 | 9 | 12 let !t = y ['b']
|
| 10 | -Stopped in T7.main, T26042e.hs:19:3-11
|
|
| 10 | +Stopped in T7., T26042e.hs:18:3-17
|
|
| 11 | 11 | _result :: IO () = _
|
| 12 | -x :: Int = _
|
|
| 13 | -y :: Int = _
|
|
| 12 | +17 main = do
|
|
| 14 | 13 | 18 let !(x, y) = a
|
| 14 | + ^^^^^^^^^^^^^^^
|
|
| 15 | 15 | 19 print '1'
|
| 16 | - ^^^^^^^^^
|
|
| 17 | -20 print '2'
|
|
| 18 | 16 | '1'
|
| 19 | 17 | '2'
|
| 20 | 18 | '3'
|
| ... | ... | @@ -8,18 +8,16 @@ x :: Int = 450 |
| 8 | 8 | 21 pure (x + 3)
|
| 9 | 9 | ^^
|
| 10 | 10 | 22 {-# OPAQUE t #-}
|
| 11 | -Stopped in T8.g, T26042f.hs:15:3-17
|
|
| 11 | +Stopped in T8., T26042f.hs:14:3-14
|
|
| 12 | 12 | _result :: Identity Int = _
|
| 13 | -a :: Int = 453
|
|
| 13 | +13 g x = do
|
|
| 14 | 14 | 14 a <- t (x*2)
|
| 15 | + ^^^^^^^^^^^^
|
|
| 15 | 16 | 15 n <- pure (a+a)
|
| 16 | - ^^^^^^^^^^^^^^^
|
|
| 17 | -16 return (n+n)
|
|
| 18 | -Stopped in T8.f, T26042f.hs:9:3-17
|
|
| 17 | +Stopped in T8., T26042f.hs:8:3-14
|
|
| 19 | 18 | _result :: Identity Int = _
|
| 20 | -b :: Int = 1812
|
|
| 19 | +7 f x = do
|
|
| 21 | 20 | 8 b <- g (x*x)
|
| 21 | + ^^^^^^^^^^^^
|
|
| 22 | 22 | 9 y <- pure (b+b)
|
| 23 | - ^^^^^^^^^^^^^^^
|
|
| 24 | -10 return (y+y)
|
|
| 25 | 23 | 7248 |
| ... | ... | @@ -6,10 +6,13 @@ x :: Int = 14 |
| 6 | 6 | 11 succ x = (-) (x - 2) (x + 1)
|
| 7 | 7 | ^^^^^^^^^^^^^^^^^^^
|
| 8 | 8 | 12
|
| 9 | -Stopped in T9.top, T26042g.hs:8:10-21
|
|
| 9 | +Stopped in T9., T26042g.hs:(6,3)-(8,21)
|
|
| 10 | 10 | _result :: Int = _
|
| 11 | +5 top = do
|
|
| 12 | + vv
|
|
| 13 | +6 case succ 14 of
|
|
| 11 | 14 | 7 5 -> 5
|
| 12 | 15 | 8 _ -> 6 + other 55
|
| 13 | - ^^^^^^^^^^^^
|
|
| 16 | + ^^
|
|
| 14 | 17 | 9
|
| 15 | 18 | 171 |
| ... | ... | @@ -147,8 +147,9 @@ 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 | +test('T26042d2', [extra_hc_opts('-O -fno-unoptimized-core-for-interpreter'), extra_files(['T26042d2.hs'])], ghci_script, ['T26042d2.script'])
|
|
| 152 | 153 | test('T26042e', extra_files(['T26042e.hs']), ghci_script, ['T26042e.script'])
|
| 153 | 154 | test('T26042f1', extra_files(['T26042f.hs', 'T26042f.script']), ghci_script, ['T26042f.script']) # >> is not inlined, so stepout has nowhere to stop
|
| 154 | 155 | test('T26042f2', [extra_hc_opts('-O -fno-unoptimized-core-for-interpreter'), extra_files(['T26042f.hs', 'T26042f.script'])], ghci_script, ['T26042f.script'])
|