summaryrefslogtreecommitdiff
path: root/compiler/GHC/Driver/Main.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Driver/Main.hs')
-rw-r--r--compiler/GHC/Driver/Main.hs148
1 files changed, 119 insertions, 29 deletions
diff --git a/compiler/GHC/Driver/Main.hs b/compiler/GHC/Driver/Main.hs
index e97fb5a4c6..3c6bacdf6a 100644
--- a/compiler/GHC/Driver/Main.hs
+++ b/compiler/GHC/Driver/Main.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE NondecreasingIndentation #-}
+{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -fprof-auto-top #-}
@@ -88,6 +89,7 @@ module GHC.Driver.Main
, ioMsgMaybe
, showModuleIndex
, hscAddSptEntries
+ , writeInterfaceOnlyMode
) where
import GHC.Prelude
@@ -218,6 +220,7 @@ import GHC.Data.Bag
import GHC.Data.StringBuffer
import qualified GHC.Data.Stream as Stream
import GHC.Data.Stream (Stream)
+import qualified GHC.SysTools
import Data.Data hiding (Fixity, TyCon)
import Data.Maybe ( fromJust )
@@ -544,7 +547,7 @@ hsc_typecheck keep_rn mod_summary mb_rdr_module = do
Nothing -> hscParse' mod_summary
tc_result0 <- tcRnModule' mod_summary keep_rn' hpm
if hsc_src == HsigFile
- then do (iface, _, _) <- liftIO $ hscSimpleIface hsc_env tc_result0 Nothing
+ then do (iface, _, _) <- liftIO $ hscSimpleIface hsc_env tc_result0 mod_summary Nothing
ioMsgMaybe $ hoistTcRnMessage $
tcRnMergeSignatures hsc_env hpm tc_result0 iface
else return tc_result0
@@ -680,15 +683,17 @@ This is the only thing that isn't caught by the type-system.
type Messager = HscEnv -> (Int,Int) -> RecompileRequired -> ModuleGraphNode -> IO ()
-- | Do the recompilation avoidance checks for both one-shot and --make modes
+-- This function is the *only* place in the compiler where we decide whether to
+-- recompile a module or not!
hscRecompStatus :: Maybe Messager
-> HscEnv
-> ModSummary
- -> SourceModified
-> Maybe ModIface
+ -> Maybe Linkable
-> (Int,Int)
-> IO HscRecompStatus
hscRecompStatus
- mHscMessage hsc_env mod_summary source_modified mb_old_iface mod_index
+ mHscMessage hsc_env mod_summary mb_old_iface old_linkable mod_index
= do
let
msg what = case mHscMessage of
@@ -696,24 +701,86 @@ hscRecompStatus
Just hscMessage -> hscMessage hsc_env mod_index what (ModuleNode (extendModSummaryNoDeps mod_summary))
Nothing -> return ()
- (recomp_reqd, mb_checked_iface)
- <- {-# SCC "checkOldIface" #-}
- liftIO $ checkOldIface hsc_env mod_summary
- source_modified mb_old_iface
-
+ -- First check to see if the interface file agrees with the
+ -- source file.
+ (recomp_iface_reqd, mb_checked_iface)
+ <- {-# SCC "checkOldIface" #-}
+ liftIO $ checkOldIface hsc_env mod_summary mb_old_iface
+ -- Check to see whether the expected build products already exist.
+ -- If they don't exists then we trigger recompilation.
+ let lcl_dflags = ms_hspp_opts mod_summary
+ (recomp_obj_reqd, mb_linkable) <-
+ case () of
+ -- No need for a linkable, we're good to go
+ _ | writeInterfaceOnlyMode lcl_dflags -> return (UpToDate, Nothing)
+ -- Interpreter can use either already loaded bytecode or loaded object code
+ | not (backendProducesObject (backend lcl_dflags)) -> do
+ res <- liftIO $ checkByteCode old_linkable
+ case res of
+ (_, Just{}) -> return res
+ _ -> liftIO $ checkObjects lcl_dflags old_linkable mod_summary
+ -- Need object files for making object files
+ | backendProducesObject (backend lcl_dflags) -> liftIO $ checkObjects lcl_dflags old_linkable mod_summary
+ | otherwise -> pprPanic "hscRecompStatus" (text $ show $ backend lcl_dflags)
+ let recomp_reqd = recomp_iface_reqd `mappend` recomp_obj_reqd
-- save the interface that comes back from checkOldIface.
-- In one-shot mode we don't have the old iface until this
-- point, when checkOldIface reads it from the disk.
let mb_old_hash = fmap (mi_iface_hash . mi_final_exts) mb_checked_iface
-
msg recomp_reqd
case mb_checked_iface of
- Just iface | not (recompileRequired recomp_reqd) -> do
- -- We didn't need to do any typechecking; the old interface
- -- file on disk was good enough.
- return $ HscUpToDate iface
+ Just iface | not (recompileRequired recomp_reqd) ->
+ return $ HscUpToDate iface mb_linkable
+ _ ->
+ return $ HscRecompNeeded mb_old_hash
+
+-- | Check that the .o files produced by compilation are already up-to-date
+-- or not.
+checkObjects :: DynFlags -> Maybe Linkable -> ModSummary -> IO (RecompileRequired, Maybe Linkable)
+checkObjects dflags mb_old_linkable summary = do
+ dt_state <- dynamicTooState dflags
+ let
+ this_mod = ms_mod summary
+ mb_obj_date = ms_obj_date summary
+ mb_dyn_obj_date = ms_dyn_obj_date summary
+ mb_if_date = ms_iface_date summary
+ obj_fn = ml_obj_file (ms_location summary)
+ -- dynamic-too *also* produces the dyn_o_file, so have to check
+ -- that's there, and if it's not, regenerate both .o and
+ -- .dyn_o
+ checkDynamicObj k = case dt_state of
+ DT_OK -> case (>=) <$> mb_dyn_obj_date <*> mb_if_date of
+ Just True -> k
+ _ -> return (RecompBecause "Missing dynamic object", Nothing)
+ -- Not in dynamic-too mode
+ _ -> k
+
+ checkDynamicObj $
+ case (,) <$> mb_obj_date <*> mb_if_date of
+ Just (obj_date, if_date)
+ | obj_date >= if_date ->
+ case mb_old_linkable of
+ Just old_linkable
+ | isObjectLinkable old_linkable, linkableTime old_linkable == obj_date
+ -> return $ (UpToDate, Just old_linkable)
+ _ -> (UpToDate,) . Just <$> findObjectLinkable this_mod obj_fn obj_date
+ _ -> return (RecompBecause "Missing object file", Nothing)
+
+-- | Check to see if we can reuse the old linkable, by this point we will
+-- have just checked that the old interface matches up with the source hash, so
+-- no need to check that again here
+checkByteCode :: Maybe Linkable -> IO (RecompileRequired, Maybe Linkable)
+checkByteCode mb_old_linkable =
+ case mb_old_linkable of
+ Just old_linkable
+ | not (isObjectLinkable old_linkable)
+ -> return $ (UpToDate, Just old_linkable)
+ _ -> return $ (RecompBecause "Missing bytecode", Nothing)
+
+--------------------------------------------------------------
+-- Compilers
+--------------------------------------------------------------
- _ -> return $ HscRecompNeeded mb_old_hash
-- Knot tying! See Note [Knot-tying typecheckIface]
-- See Note [ModDetails and --make mode]
@@ -828,7 +895,7 @@ hscDesugarAndSimplify summary (FrontendTypecheck tc_result) tc_warnings mb_old_h
{-# SCC "GHC.Driver.Main.mkPartialIface" #-}
-- This `force` saves 2M residency in test T10370
-- See Note [Avoiding space leaks in toIface*] for details.
- force (mkPartialIface hsc_env details simplified_guts)
+ force (mkPartialIface hsc_env details summary simplified_guts)
return HscRecomp { hscs_guts = cg_guts,
hscs_mod_location = ms_location summary,
@@ -840,7 +907,7 @@ hscDesugarAndSimplify summary (FrontendTypecheck tc_result) tc_warnings mb_old_h
-- and generate a simple interface.
_ -> do
(iface, mb_old_iface_hash, _details) <- liftIO $
- hscSimpleIface hsc_env tc_result mb_old_hash
+ hscSimpleIface hsc_env tc_result summary mb_old_hash
liftIO $ hscMaybeWriteIface logger dflags True iface mb_old_iface_hash (ms_location summary)
@@ -960,6 +1027,22 @@ hscMaybeWriteIface logger dflags is_simple iface old_iface mod_location = do
DT_Failed | not (dynamicNow dflags) -> write_iface dflags iface
_ -> return ()
+ when (gopt Opt_WriteHie dflags) $ do
+ -- This is slightly hacky. A hie file is considered to be up to date
+ -- if its modification time on disk is greater than or equal to that
+ -- of the .hi file (since we should always write a .hi file if we are
+ -- writing a .hie file). However, with the way this code is
+ -- structured at the moment, the .hie file is often written before
+ -- the .hi file; by touching the file here, we ensure that it is
+ -- correctly considered up-to-date.
+ --
+ -- The file should exist by the time we get here, but we check for
+ -- existence just in case, so that we don't accidentally create empty
+ -- .hie files.
+ let hie_file = ml_hie_file mod_location
+ whenM (doesFileExist hie_file) $
+ GHC.SysTools.touch logger dflags "Touching hie file" hie_file
+
--------------------------------------------------------------
-- NoRecomp handlers
--------------------------------------------------------------
@@ -1435,7 +1518,7 @@ hscSimplify' plugins ds_result = do
hsc_env <- getHscEnv
hsc_env_with_plugins <- if null plugins -- fast path
then return hsc_env
- else liftIO $ initializePlugins $ hsc_env
+ else liftIO $ flip initializePlugins (Just $ mg_mnwib ds_result) $ hsc_env
{ hsc_dflags = foldr addPluginModuleName (hsc_dflags hsc_env) plugins
}
{-# SCC "Core2Core" #-}
@@ -1449,22 +1532,24 @@ hscSimplify' plugins ds_result = do
-- generates interface files. See Note [simpleTidyPgm - mkBootModDetailsTc]
hscSimpleIface :: HscEnv
-> TcGblEnv
+ -> ModSummary
-> Maybe Fingerprint
-> IO (ModIface, Maybe Fingerprint, ModDetails)
-hscSimpleIface hsc_env tc_result mb_old_iface
- = runHsc hsc_env $ hscSimpleIface' tc_result mb_old_iface
+hscSimpleIface hsc_env tc_result summary mb_old_iface
+ = runHsc hsc_env $ hscSimpleIface' tc_result summary mb_old_iface
hscSimpleIface' :: TcGblEnv
+ -> ModSummary
-> Maybe Fingerprint
-> Hsc (ModIface, Maybe Fingerprint, ModDetails)
-hscSimpleIface' tc_result mb_old_iface = do
+hscSimpleIface' tc_result summary mb_old_iface = do
hsc_env <- getHscEnv
details <- liftIO $ mkBootModDetailsTc hsc_env tc_result
safe_mode <- hscGetSafeMode tc_result
new_iface
<- {-# SCC "MkFinalIface" #-}
liftIO $
- mkIfaceTc hsc_env safe_mode details tc_result
+ mkIfaceTc hsc_env safe_mode details summary tc_result
-- And the answer is ...
liftIO $ dumpIfaceStats hsc_env
return (new_iface, mb_old_iface, details)
@@ -1821,7 +1906,7 @@ hscParsedStmt hsc_env stmt = runInteractiveHsc hsc_env $ do
-- for linking, else we try to link 'main' and can't find it.
-- Whereas the linker already knows to ignore 'interactive'
let src_span = srcLocSpan interactiveSrcLoc
- hval <- liftIO $ hscCompileCoreExpr hsc_env src_span ds_expr
+ hval <- liftIO $ hscCompileCoreExpr hsc_env (src_span, Nothing) ds_expr
return $ Just (ids, hval, fix_env)
@@ -1910,10 +1995,10 @@ hscParsedDecls hsc_env decls = runInteractiveHsc hsc_env $ do
stg_binds data_tycons mod_breaks
let src_span = srcLocSpan interactiveSrcLoc
- liftIO $ loadDecls interp hsc_env src_span cbc
+ liftIO $ loadDecls interp hsc_env (src_span, Nothing) cbc
{- Load static pointer table entries -}
- liftIO $ hscAddSptEntries hsc_env (cg_spt_entries tidy_cg)
+ liftIO $ hscAddSptEntries hsc_env Nothing (cg_spt_entries tidy_cg)
let tcs = filterOut isImplicitTyCon (mg_tcs simpl_mg)
patsyns = mg_patsyns simpl_mg
@@ -1938,12 +2023,12 @@ hscParsedDecls hsc_env decls = runInteractiveHsc hsc_env $ do
-- | Load the given static-pointer table entries into the interpreter.
-- See Note [Grand plan for static forms] in "GHC.Iface.Tidy.StaticPtrTable".
-hscAddSptEntries :: HscEnv -> [SptEntry] -> IO ()
-hscAddSptEntries hsc_env entries = do
+hscAddSptEntries :: HscEnv -> Maybe ModuleNameWithIsBoot -> [SptEntry] -> IO ()
+hscAddSptEntries hsc_env mnwib entries = do
let interp = hscInterp hsc_env
let add_spt_entry :: SptEntry -> IO ()
add_spt_entry (SptEntry i fpr) = do
- val <- loadName interp hsc_env (idName i)
+ val <- loadName interp hsc_env mnwib (idName i)
addSptEntry interp fpr val
mapM_ add_spt_entry entries
@@ -2054,13 +2139,13 @@ hscParseThingWithLocation source linenumber parser str = do
%* *
%********************************************************************* -}
-hscCompileCoreExpr :: HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue
+hscCompileCoreExpr :: HscEnv -> (SrcSpan, Maybe ModuleNameWithIsBoot) -> CoreExpr -> IO ForeignHValue
hscCompileCoreExpr hsc_env loc expr =
case hscCompileCoreExprHook (hsc_hooks hsc_env) of
Nothing -> hscCompileCoreExpr' hsc_env loc expr
Just h -> h hsc_env loc expr
-hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue
+hscCompileCoreExpr' :: HscEnv -> (SrcSpan, Maybe ModuleNameWithIsBoot) -> CoreExpr -> IO ForeignHValue
hscCompileCoreExpr' hsc_env srcspan ds_expr
= do { {- Simplify it -}
-- Question: should we call SimpleOpt.simpleOptExpr here instead?
@@ -2130,3 +2215,8 @@ showModuleIndex (i,n) = text "[" <> pad <> int i <> text " of " <> int n <> text
-- compute the length of x > 0 in base 10
len x = ceiling (logBase 10 (fromIntegral x+1) :: Float)
pad = text (replicate (len n - len i) ' ') -- TODO: use GHC.Utils.Ppr.RStr
+
+writeInterfaceOnlyMode :: DynFlags -> Bool
+writeInterfaceOnlyMode dflags =
+ gopt Opt_WriteInterface dflags &&
+ NoBackend == backend dflags