diff options
Diffstat (limited to 'compiler/main')
-rw-r--r-- | compiler/main/BreakArray.hs | 83 | ||||
-rw-r--r-- | compiler/main/DynFlags.hs | 11 | ||||
-rw-r--r-- | compiler/main/GHC.hs | 3 | ||||
-rw-r--r-- | compiler/main/HscTypes.hs | 16 | ||||
-rw-r--r-- | compiler/main/InteractiveEval.hs | 34 | ||||
-rw-r--r-- | compiler/main/InteractiveEvalTypes.hs | 13 |
6 files changed, 93 insertions, 67 deletions
diff --git a/compiler/main/BreakArray.hs b/compiler/main/BreakArray.hs index 9b84931390..447490266c 100644 --- a/compiler/main/BreakArray.hs +++ b/compiler/main/BreakArray.hs @@ -2,13 +2,16 @@ ------------------------------------------------------------------------------- -- --- | Break Arrays in the IO monad +-- (c) The University of Glasgow 2007 -- --- Entries in the array are Word sized Conceptually, a zero-indexed IOArray of --- Bools, initially False. They're represented as Words with 0==False, 1==True. --- They're used to determine whether GHCI breakpoints are on or off. +-- | Break Arrays -- --- (c) The University of Glasgow 2007 +-- An array of bytes, indexed by a breakpoint number (breakpointId in Tickish) +-- There is one of these arrays per module. +-- +-- Each byte is +-- 1 if the corresponding breakpoint is enabled +-- 0 otherwise -- ------------------------------------------------------------------------------- @@ -27,10 +30,10 @@ module BreakArray #endif ) where -import DynFlags - #ifdef GHCI import Control.Monad +import Data.Word +import GHC.Word import GHC.Exts import GHC.IO ( IO(..) ) @@ -38,43 +41,43 @@ import System.IO.Unsafe ( unsafeDupablePerformIO ) data BreakArray = BA (MutableByteArray# RealWorld) -breakOff, breakOn :: Word +breakOff, breakOn :: Word8 breakOn = 1 breakOff = 0 -showBreakArray :: DynFlags -> BreakArray -> IO () -showBreakArray dflags array = do - forM_ [0 .. (size dflags array - 1)] $ \i -> do +showBreakArray :: BreakArray -> IO () +showBreakArray array = do + forM_ [0 .. (size array - 1)] $ \i -> do val <- readBreakArray array i putStr $ ' ' : show val putStr "\n" -setBreakOn :: DynFlags -> BreakArray -> Int -> IO Bool -setBreakOn dflags array index - | safeIndex dflags array index = do +setBreakOn :: BreakArray -> Int -> IO Bool +setBreakOn array index + | safeIndex array index = do writeBreakArray array index breakOn return True | otherwise = return False -setBreakOff :: DynFlags -> BreakArray -> Int -> IO Bool -setBreakOff dflags array index - | safeIndex dflags array index = do +setBreakOff :: BreakArray -> Int -> IO Bool +setBreakOff array index + | safeIndex array index = do writeBreakArray array index breakOff return True | otherwise = return False -getBreak :: DynFlags -> BreakArray -> Int -> IO (Maybe Word) -getBreak dflags array index - | safeIndex dflags array index = do +getBreak :: BreakArray -> Int -> IO (Maybe Word8) +getBreak array index + | safeIndex array index = do val <- readBreakArray array index return $ Just val | otherwise = return Nothing -safeIndex :: DynFlags -> BreakArray -> Int -> Bool -safeIndex dflags array index = index < size dflags array && index >= 0 +safeIndex :: BreakArray -> Int -> Bool +safeIndex array index = index < size array && index >= 0 -size :: DynFlags -> BreakArray -> Int -size dflags (BA array) = size `div` wORD_SIZE dflags +size :: BreakArray -> Int +size (BA array) = size where -- We want to keep this operation pure. The mutable byte array -- is never resized so this is safe. @@ -90,30 +93,28 @@ allocBA (I# sz) = IO $ \s1 -> case newByteArray# sz s1 of { (# s2, array #) -> (# s2, BA array #) } -- create a new break array and initialise elements to zero -newBreakArray :: DynFlags -> Int -> IO BreakArray -newBreakArray dflags entries@(I# sz) = do - BA array <- allocBA (entries * wORD_SIZE dflags) +newBreakArray :: Int -> IO BreakArray +newBreakArray entries@(I# sz) = do + BA array <- allocBA entries case breakOff of - W# off -> do -- Todo: there must be a better way to write zero as a Word! - let loop n | isTrue# (n ==# sz) = return () - | otherwise = do - writeBA# array n off - loop (n +# 1#) - loop 0# + W8# off -> do + let loop n | isTrue# (n ==# sz) = return () + | otherwise = do writeBA# array n off; loop (n +# 1#) + loop 0# return $ BA array writeBA# :: MutableByteArray# RealWorld -> Int# -> Word# -> IO () writeBA# array i word = IO $ \s -> - case writeWordArray# array i word s of { s -> (# s, () #) } + case writeWord8Array# array i word s of { s -> (# s, () #) } -writeBreakArray :: BreakArray -> Int -> Word -> IO () -writeBreakArray (BA array) (I# i) (W# word) = writeBA# array i word +writeBreakArray :: BreakArray -> Int -> Word8 -> IO () +writeBreakArray (BA array) (I# i) (W8# word) = writeBA# array i word -readBA# :: MutableByteArray# RealWorld -> Int# -> IO Word +readBA# :: MutableByteArray# RealWorld -> Int# -> IO Word8 readBA# array i = IO $ \s -> - case readWordArray# array i s of { (# s, c #) -> (# s, W# c #) } + case readWord8Array# array i s of { (# s, c #) -> (# s, W8# c #) } -readBreakArray :: BreakArray -> Int -> IO Word +readBreakArray :: BreakArray -> Int -> IO Word8 readBreakArray (BA array) (I# i) = readBA# array i #else /* !GHCI */ @@ -124,8 +125,8 @@ readBreakArray (BA array) (I# i) = readBA# array i -- presumably have a different representation. data BreakArray = Unspecified -newBreakArray :: DynFlags -> Int -> IO BreakArray -newBreakArray _ _ = return Unspecified +newBreakArray :: Int -> IO BreakArray +newBreakArray _ = return Unspecified #endif /* GHCI */ diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs index a23ecfa8d3..556175c0ea 100644 --- a/compiler/main/DynFlags.hs +++ b/compiler/main/DynFlags.hs @@ -81,6 +81,7 @@ module DynFlags ( defaultDynFlags, -- Settings -> DynFlags defaultWays, interpWays, + interpreterProfiled, interpreterDynamic, initDynFlags, -- DynFlags -> IO DynFlags defaultFatalMessager, defaultLogAction, @@ -1522,6 +1523,16 @@ interpWays | rtsIsProfiled = [WayProf] | otherwise = [] +interpreterProfiled :: DynFlags -> Bool +interpreterProfiled dflags + | gopt Opt_ExternalInterpreter dflags = gopt Opt_SccProfilingOn dflags + | otherwise = rtsIsProfiled + +interpreterDynamic :: DynFlags -> Bool +interpreterDynamic dflags + | gopt Opt_ExternalInterpreter dflags = WayDyn `elem` ways dflags + | otherwise = dynamicGhc + -------------------------------------------------------------------------- type FatalMessager = String -> IO () diff --git a/compiler/main/GHC.hs b/compiler/main/GHC.hs index 4bf9a5845f..0ac1331d26 100644 --- a/compiler/main/GHC.hs +++ b/compiler/main/GHC.hs @@ -136,8 +136,7 @@ module GHC ( -- ** The debugger SingleStep(..), - Resume(resumeStmt, resumeBreakInfo, resumeSpan, - resumeHistory, resumeHistoryIx), + Resume(..), History(historyBreakInfo, historyEnclosingDecls), GHC.getHistorySpan, getHistoryModule, abandon, abandonAll, diff --git a/compiler/main/HscTypes.hs b/compiler/main/HscTypes.hs index 3766b57df1..ea921fe79a 100644 --- a/compiler/main/HscTypes.hs +++ b/compiler/main/HscTypes.hs @@ -112,6 +112,7 @@ module HscTypes ( -- * Breakpoints ModBreaks (..), BreakIndex, emptyModBreaks, + CCostCentre, -- * Vectorisation information VectInfo(..), IfaceVectInfo(..), noVectInfo, plusVectInfo, @@ -136,7 +137,7 @@ module HscTypes ( import ByteCodeTypes ( CompiledByteCode ) import InteractiveEvalTypes ( Resume ) import GHCi.Message ( Pipe ) -import GHCi.RemoteTypes ( HValueRef ) +import GHCi.RemoteTypes #endif import HsSyn @@ -191,15 +192,14 @@ import Platform import Util import GHC.Serialized ( Serialized ) +import Foreign import Control.Monad ( guard, liftM, when, ap ) import Control.Concurrent import Data.Array ( Array, array ) import Data.IORef import Data.Time -import Data.Word import Data.Typeable ( Typeable ) import Exception -import Foreign import System.FilePath import System.Process ( ProcessHandle ) @@ -2872,6 +2872,9 @@ byteCodeOfObject other = pprPanic "byteCodeOfObject" (ppr other) -- | Breakpoint index type BreakIndex = Int +-- | C CostCentre type +data CCostCentre + -- | All the information about the breakpoints for a given module data ModBreaks = ModBreaks @@ -2884,6 +2887,10 @@ data ModBreaks -- ^ An array giving the names of the free variables at each breakpoint. , modBreaks_decls :: !(Array BreakIndex [String]) -- ^ An array giving the names of the declarations enclosing each breakpoint. +#ifdef GHCI + , modBreaks_ccs :: !(Array BreakIndex (RemotePtr {- CCostCentre -})) + -- ^ Array pointing to cost centre for each breakpoint +#endif } -- | Construct an empty ModBreaks @@ -2894,4 +2901,7 @@ emptyModBreaks = ModBreaks , modBreaks_locs = array (0,-1) [] , modBreaks_vars = array (0,-1) [] , modBreaks_decls = array (0,-1) [] +#ifdef GHCI + , modBreaks_ccs = array (0,-1) [] +#endif } diff --git a/compiler/main/InteractiveEval.hs b/compiler/main/InteractiveEval.hs index 2f819e4a60..eb23a60f82 100644 --- a/compiler/main/InteractiveEval.hs +++ b/compiler/main/InteractiveEval.hs @@ -94,7 +94,7 @@ import qualified Parser (parseStmt, parseModule, parseDeclaration) import System.Directory import Data.Dynamic import Data.Either -import Data.List (find) +import Data.List (find,intercalate) import StringBuffer (stringToStringBuffer) import Control.Monad import GHC.Exts @@ -293,7 +293,7 @@ handleRunStatus step expr bindings final_ids status history | otherwise = not_tracing where tracing - | EvalBreak is_exception apStack_ref info_ref resume_ctxt <- status + | EvalBreak is_exception apStack_ref info_ref resume_ctxt _ccs <- status , not is_exception = do hsc_env <- getSession @@ -320,7 +320,7 @@ handleRunStatus step expr bindings final_ids status history not_tracing -- Hit a breakpoint - | EvalBreak is_exception apStack_ref info_ref resume_ctxt <- status + | EvalBreak is_exception apStack_ref info_ref resume_ctxt ccs <- status = do hsc_env <- getSession let dflags = hsc_dflags hsc_env @@ -330,7 +330,7 @@ handleRunStatus step expr bindings final_ids status history apStack_fhv <- liftIO $ mkFinalizedHValue hsc_env apStack_ref let mb_info | is_exception = Nothing | otherwise = Just info - (hsc_env1, names, span) <- liftIO $ + (hsc_env1, names, span, decl) <- liftIO $ bindLocalsAtBreakpoint hsc_env apStack_fhv mb_info let resume = Resume @@ -338,6 +338,8 @@ handleRunStatus step expr bindings final_ids status history , resumeBindings = bindings, resumeFinalIds = final_ids , resumeApStack = apStack_fhv, resumeBreakInfo = mb_info , resumeSpan = span, resumeHistory = toListBL history + , resumeDecl = decl + , resumeCCS = ccs , resumeHistoryIx = 0 } hsc_env2 = pushResume hsc_env1 resume @@ -365,8 +367,7 @@ isBreakEnabled :: HscEnv -> BreakInfo -> IO Bool isBreakEnabled hsc_env inf = case lookupUFM (hsc_HPT hsc_env) (moduleName (breakInfo_module inf)) of Just hmi -> do - w <- getBreak (hsc_dflags hsc_env) - (modBreaks_flags (getModBreaks hmi)) + w <- getBreak (modBreaks_flags (getModBreaks hmi)) (breakInfo_number inf) case w of Just n -> return (n /= 0); _other -> return False _ -> @@ -419,13 +420,13 @@ resumeExec canLogSpan step fromListBL 50 hist handleRunStatus step expr bindings final_ids status hist' -back :: GhcMonad m => Int -> m ([Name], Int, SrcSpan) +back :: GhcMonad m => Int -> m ([Name], Int, SrcSpan, String) back n = moveHist (+n) -forward :: GhcMonad m => Int -> m ([Name], Int, SrcSpan) +forward :: GhcMonad m => Int -> m ([Name], Int, SrcSpan, String) forward n = moveHist (subtract n) -moveHist :: GhcMonad m => (Int -> Int) -> m ([Name], Int, SrcSpan) +moveHist :: GhcMonad m => (Int -> Int) -> m ([Name], Int, SrcSpan, String) moveHist fn = do hsc_env <- getSession case ic_resume (hsc_IC hsc_env) of @@ -443,15 +444,15 @@ moveHist fn = do let update_ic apStack mb_info = do - (hsc_env1, names, span) <- liftIO $ bindLocalsAtBreakpoint hsc_env - apStack mb_info + (hsc_env1, names, span, decl) <- + liftIO $ bindLocalsAtBreakpoint hsc_env apStack mb_info let ic = hsc_IC hsc_env1 r' = r { resumeHistoryIx = new_ix } ic' = ic { ic_resume = r':rs } modifySession (\_ -> hsc_env1{ hsc_IC = ic' }) - return (names, new_ix, span) + return (names, new_ix, span, decl) -- careful: we want apStack to be the AP_STACK itself, not a thunk -- around it, hence the cases are carefully constructed below to @@ -474,7 +475,7 @@ bindLocalsAtBreakpoint :: HscEnv -> ForeignHValue -> Maybe BreakInfo - -> IO (HscEnv, [Name], SrcSpan) + -> IO (HscEnv, [Name], SrcSpan, String) -- Nothing case: we stopped when an exception was raised, not at a -- breakpoint. We have no location information or local variables to @@ -482,7 +483,7 @@ bindLocalsAtBreakpoint -- value. bindLocalsAtBreakpoint hsc_env apStack Nothing = do let exn_occ = mkVarOccFS (fsLit "_exception") - span = mkGeneralSrcSpan (fsLit "<exception thrown>") + span = mkGeneralSrcSpan (fsLit "<unknown>") exn_name <- newInteractiveBinder hsc_env exn_occ span let e_fs = fsLit "e" @@ -495,7 +496,7 @@ bindLocalsAtBreakpoint hsc_env apStack Nothing = do -- Linker.extendLinkEnv [(exn_name, apStack)] - return (hsc_env{ hsc_IC = ictxt1 }, [exn_name], span) + return (hsc_env{ hsc_IC = ictxt1 }, [exn_name], span, "<exception thrown>") -- Just case: we stopped at a breakpoint, we have information about the location -- of the breakpoint and the free variables of the expression. @@ -510,6 +511,7 @@ bindLocalsAtBreakpoint hsc_env apStack_fhv (Just info) = do result_ty = breakInfo_resty info occs = modBreaks_vars breaks ! index span = modBreaks_locs breaks ! index + decl = intercalate "." $ modBreaks_decls breaks ! index -- Filter out any unboxed ids; -- we can't bind these at the prompt @@ -556,7 +558,7 @@ bindLocalsAtBreakpoint hsc_env apStack_fhv (Just info) = do Linker.extendLinkEnv (zip names fhvs) when result_ok $ Linker.extendLinkEnv [(result_name, apStack_fhv)] hsc_env1 <- rttiEnvironment hsc_env{ hsc_IC = ictxt1 } - return (hsc_env1, if result_ok then result_name:names else names, span) + return (hsc_env1, if result_ok then result_name:names else names, span, decl) where -- We need a fresh Unique for each Id we bind, because the linker -- state is single-threaded and otherwise we'd spam old bindings diff --git a/compiler/main/InteractiveEvalTypes.hs b/compiler/main/InteractiveEvalTypes.hs index 98090bbaed..4372891bd8 100644 --- a/compiler/main/InteractiveEvalTypes.hs +++ b/compiler/main/InteractiveEvalTypes.hs @@ -17,7 +17,7 @@ module InteractiveEvalTypes ( #ifdef GHCI -import GHCi.RemoteTypes (ForeignHValue) +import GHCi.RemoteTypes import GHCi.Message (EvalExpr) import Id import Name @@ -67,9 +67,13 @@ data Resume resumeBreakInfo :: Maybe BreakInfo, -- the breakpoint we stopped at -- (Nothing <=> exception) - resumeSpan :: SrcSpan, -- just a cache, otherwise it's a pain - -- to fetch the ModDetails & ModBreaks - -- to get this. + resumeSpan :: SrcSpan, -- just a copy of the SrcSpan + -- from the ModBreaks, + -- otherwise it's a pain to + -- fetch the ModDetails & + -- ModBreaks to get this. + resumeDecl :: String, -- ditto + resumeCCS :: RemotePtr {- CostCentreStack -}, resumeHistory :: [History], resumeHistoryIx :: Int -- 0 <==> at the top of the history } @@ -81,4 +85,3 @@ data History historyEnclosingDecls :: [String] -- declarations enclosing the breakpoint } #endif - |