summaryrefslogtreecommitdiff
path: root/compiler/main/InteractiveEval.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/main/InteractiveEval.hs')
-rw-r--r--compiler/main/InteractiveEval.hs131
1 files changed, 92 insertions, 39 deletions
diff --git a/compiler/main/InteractiveEval.hs b/compiler/main/InteractiveEval.hs
index ff588e1276..44b207a293 100644
--- a/compiler/main/InteractiveEval.hs
+++ b/compiler/main/InteractiveEval.hs
@@ -1,4 +1,5 @@
-{-# LANGUAGE CPP, MagicHash, NondecreasingIndentation, UnboxedTuples #-}
+{-# LANGUAGE CPP, MagicHash, NondecreasingIndentation, UnboxedTuples,
+ RecordWildCards #-}
-- -----------------------------------------------------------------------------
--
@@ -10,8 +11,9 @@
module InteractiveEval (
#ifdef GHCI
- RunResult(..), Status(..), Resume(..), History(..),
- runStmt, runStmtWithLocation, runDecls, runDeclsWithLocation,
+ Status(..), Resume(..), History(..),
+ execStmt, ExecOptions(..), execOptions, ExecResult(..), resumeExec,
+ runDecls, runDeclsWithLocation,
parseImportDecl, SingleStep(..),
resume,
abandon, abandonAll,
@@ -32,7 +34,9 @@ module InteractiveEval (
showModule,
isModuleInterpreted,
compileExpr, dynCompileExpr,
- Term(..), obtainTermFromId, obtainTermFromVal, reconstructType
+ Term(..), obtainTermFromId, obtainTermFromVal, reconstructType,
+ -- * Depcreated API (remove in GHC 7.14)
+ RunResult(..), runStmt, runStmtWithLocation,
#endif
) where
@@ -93,6 +97,7 @@ import Data.Array
import Exception
import Control.Concurrent
import System.IO.Unsafe
+import GHC.Conc ( setAllocationCounter, getAllocationCounter )
-- -----------------------------------------------------------------------------
-- running a statement interactively
@@ -100,15 +105,6 @@ import System.IO.Unsafe
getResumeContext :: GhcMonad m => m [Resume]
getResumeContext = withSession (return . ic_resume . hsc_IC)
-data SingleStep
- = RunToCompletion
- | SingleStep
- | RunAndLogSteps
-
-isStep :: SingleStep -> Bool
-isStep RunToCompletion = False
-isStep _ = True
-
mkHistory :: HscEnv -> HValue -> BreakInfo -> History
mkHistory hsc_env hval bi = let
decls = findEnclosingDecls hsc_env bi
@@ -152,21 +148,30 @@ updateFixityEnv fix_env = do
let ic = hsc_IC hsc_env
setSession $ hsc_env { hsc_IC = ic { ic_fix_env = fix_env } }
--- | Run a statement in the current interactive context. Statement
--- may bind multple values.
-runStmt :: GhcMonad m => String -> SingleStep -> m RunResult
-runStmt = runStmtWithLocation "<interactive>" 1
-
--- | Run a statement in the current interactive context. Passing debug information
--- Statement may bind multple values.
-runStmtWithLocation :: GhcMonad m => String -> Int ->
- String -> SingleStep -> m RunResult
-runStmtWithLocation source linenumber expr step =
- do
+-- -----------------------------------------------------------------------------
+-- execStmt
+
+-- | default ExecOptions
+execOptions :: ExecOptions
+execOptions = ExecOptions
+ { execSingleStep = RunToCompletion
+ , execSourceFile = "<interactive>"
+ , execLineNumber = 1
+ }
+
+-- | Run a statement in the current interactive context.
+execStmt
+ :: GhcMonad m
+ => String -- ^ a statement (bind or expression)
+ -> ExecOptions
+ -> m ExecResult
+execStmt stmt ExecOptions{..} = do
hsc_env <- getSession
- breakMVar <- liftIO $ newEmptyMVar -- wait on this when we hit a breakpoint
- statusMVar <- liftIO $ newEmptyMVar -- wait on this when a computation is running
+ -- wait on this when we hit a breakpoint
+ breakMVar <- liftIO $ newEmptyMVar
+ -- wait on this when a computation is running
+ statusMVar <- liftIO $ newEmptyMVar
-- Turn off -fwarn-unused-local-binds when running a statement, to hide
-- warnings about the implicit bindings we introduce.
@@ -175,28 +180,63 @@ runStmtWithLocation source linenumber expr step =
hsc_env' = hsc_env{ hsc_IC = ic{ ic_dflags = idflags' } }
-- compile to value (IO [HValue]), don't run
- r <- liftIO $ hscStmtWithLocation hsc_env' expr source linenumber
+ r <- liftIO $ hscStmtWithLocation hsc_env' stmt
+ execSourceFile execLineNumber
case r of
-- empty statement / comment
- Nothing -> return (RunOk [])
+ Nothing -> return (ExecComplete (Right []) 0)
Just (tyThings, hval, fix_env) -> do
updateFixityEnv fix_env
status <-
withVirtualCWD $
- withBreakAction (isStep step) idflags' breakMVar statusMVar $ do
- liftIO $ sandboxIO idflags' statusMVar hval
+ withBreakAction (isStep execSingleStep) idflags'
+ breakMVar statusMVar $ do
+ liftIO $ sandboxIO idflags' statusMVar hval
let ic = hsc_IC hsc_env
bindings = (ic_tythings ic, ic_rn_gbl_env ic)
size = ghciHistSize idflags'
- handleRunStatus step expr bindings tyThings
+ handleRunStatus execSingleStep stmt bindings tyThings
breakMVar statusMVar status (emptyHistory size)
+-- | The type returned by the deprecated 'runStmt' and
+-- 'runStmtWithLocation' API
+data RunResult
+ = RunOk [Name] -- ^ names bound by this evaluation
+ | RunException SomeException -- ^ statement raised an exception
+ | RunBreak ThreadId [Name] (Maybe BreakInfo)
+
+-- | Conver the old result type to the new result type
+execResultToRunResult :: ExecResult -> RunResult
+execResultToRunResult r =
+ case r of
+ ExecComplete{ execResult = Left ex } -> RunException ex
+ ExecComplete{ execResult = Right names } -> RunOk names
+ ExecBreak{..} -> RunBreak breakThreadId breakNames breakInfo
+
+-- Remove in GHC 7.14
+{-# DEPRECATED runStmt "use execStmt" #-}
+-- | Run a statement in the current interactive context. Statement
+-- may bind multple values.
+runStmt :: GhcMonad m => String -> SingleStep -> m RunResult
+runStmt stmt step =
+ execResultToRunResult <$> execStmt stmt execOptions { execSingleStep = step }
+
+-- Remove in GHC 7.14
+{-# DEPRECATED runStmtWithLocation "use execStmtWithLocation" #-}
+runStmtWithLocation :: GhcMonad m => String -> Int ->
+ String -> SingleStep -> m RunResult
+runStmtWithLocation source linenumber expr step = do
+ execResultToRunResult <$>
+ execStmt expr execOptions { execSingleStep = step
+ , execSourceFile = source
+ , execLineNumber = linenumber }
+
runDecls :: GhcMonad m => String -> m [Name]
runDecls = runDeclsWithLocation "<interactive>" 1
@@ -243,7 +283,7 @@ emptyHistory size = nilBL size
handleRunStatus :: GhcMonad m
=> SingleStep -> String-> ([TyThing],GlobalRdrEnv) -> [Id]
-> MVar () -> MVar Status -> Status -> BoundedList History
- -> m RunResult
+ -> m ExecResult
handleRunStatus step expr bindings final_ids
breakMVar statusMVar status history
@@ -296,21 +336,21 @@ handleRunStatus step expr bindings final_ids
hsc_env2 = pushResume hsc_env1 resume
modifySession (\_ -> hsc_env2)
- return (RunBreak tid names mb_info)
+ return (ExecBreak tid names mb_info)
-- Completed with an exception
- | Complete (Left e) <- status
- = return (RunException e)
+ | Complete (Left e) alloc <- status
+ = return (ExecComplete (Left e) alloc)
-- Completed successfully
- | Complete (Right hvals) <- status
+ | Complete (Right hvals) allocs <- status
= do hsc_env <- getSession
let final_ic = extendInteractiveContextWithIds (hsc_IC hsc_env) final_ids
final_names = map getName final_ids
liftIO $ Linker.extendLinkEnv (zip final_names hvals)
hsc_env' <- liftIO $ rttiEnvironment hsc_env{hsc_IC=final_ic}
modifySession (\_ -> hsc_env')
- return (RunOk final_names)
+ return (ExecComplete (Right final_names) allocs)
| otherwise
= panic "handleRunStatus" -- The above cases are in fact exhaustive
@@ -351,7 +391,10 @@ foreign import ccall "&rts_breakpoint_io_action"
sandboxIO :: DynFlags -> MVar Status -> IO [HValue] -> IO Status
sandboxIO dflags statusMVar thing =
mask $ \restore -> -- fork starts blocked
- let runIt = liftM Complete $ try (restore $ rethrow dflags thing)
+ let runIt =
+ liftM (uncurry Complete) $
+ measureAlloc $
+ try $ restore $ rethrow dflags $ thing
in if gopt Opt_GhciSandbox dflags
then do tid <- forkIO $ do res <- runIt
putMVar statusMVar res -- empty: can't block
@@ -398,6 +441,13 @@ redirectInterrupts target wait
Nothing -> wait
Just target -> do throwTo target (e :: SomeException); wait
+measureAlloc :: IO a -> IO (a,Word64)
+measureAlloc io = do
+ setAllocationCounter maxBound
+ a <- io
+ allocs <- getAllocationCounter
+ return (a, fromIntegral (maxBound::Int64) - fromIntegral allocs)
+
-- We want to turn ^C into a break when -fbreak-on-exception is on,
-- but it's an async exception and we only break for sync exceptions.
-- Idea: if we catch and re-throw it, then the re-throw will trigger
@@ -460,7 +510,10 @@ noBreakAction False _ _ = putStrLn "*** Ignoring breakpoint"
noBreakAction True _ _ = return () -- exception: just continue
resume :: GhcMonad m => (SrcSpan->Bool) -> SingleStep -> m RunResult
-resume canLogSpan step
+resume canLogSpan step = execResultToRunResult <$> resumeExec canLogSpan step
+
+resumeExec :: GhcMonad m => (SrcSpan->Bool) -> SingleStep -> m ExecResult
+resumeExec canLogSpan step
= do
hsc_env <- getSession
let ic = hsc_IC hsc_env