summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/main/DriverPipeline.hs123
-rw-r--r--compiler/main/HscMain.hs49
-rw-r--r--compiler/main/HscTypes.hs18
-rw-r--r--compiler/main/PipelineMonad.hs21
4 files changed, 114 insertions, 97 deletions
diff --git a/compiler/main/DriverPipeline.hs b/compiler/main/DriverPipeline.hs
index 18f22d6d78..4d418b99fe 100644
--- a/compiler/main/DriverPipeline.hs
+++ b/compiler/main/DriverPipeline.hs
@@ -66,6 +66,7 @@ import FileCleanup
import Ar
import Bag ( unitBag )
import FastString ( mkFastString )
+import MkIface ( mkFullIface )
import Exception
import System.Directory
@@ -76,7 +77,6 @@ import Data.List ( isInfixOf, intercalate )
import Data.Maybe
import Data.Version
import Data.Either ( partitionEithers )
-import Data.IORef
import Data.Time ( UTCTime )
@@ -98,15 +98,18 @@ preprocess :: HscEnv
preprocess hsc_env input_fn mb_input_buf mb_phase =
handleSourceError (\err -> return (Left (srcErrorMessages err))) $
ghandle handler $
- fmap Right $
- ASSERT2(isJust mb_phase || isHaskellSrcFilename input_fn, text input_fn)
- runPipeline anyHsc hsc_env (input_fn, mb_input_buf, fmap RealPhase mb_phase)
+ fmap Right $ do
+ MASSERT2(isJust mb_phase || isHaskellSrcFilename input_fn, text input_fn)
+ (dflags, fp, mb_iface) <- runPipeline anyHsc hsc_env (input_fn, mb_input_buf, fmap RealPhase mb_phase)
Nothing
-- We keep the processed file for the whole session to save on
-- duplicated work in ghci.
(Temporary TFL_GhcSession)
Nothing{-no ModLocation-}
[]{-no foreign objects-}
+ -- We stop before Hsc phase so we shouldn't generate an interface
+ MASSERT(isNothing mb_iface)
+ return (dflags, fp)
where
srcspan = srcLocSpan $ mkSrcLoc (mkFastString input_fn) 1 1
handler (ProgramError msg) = return $ Left $ unitBag $
@@ -157,7 +160,7 @@ compileOne' m_tc_result mHscMessage
debugTraceMsg dflags1 2 (text "compile: input file" <+> text input_fnpp)
-- Run the pipeline up to codeGen (so everything up to, but not including, STG)
- (status, hmi_details) <- hscIncrementalCompile
+ (status, hmi_details, plugin_dflags) <- hscIncrementalCompile
always_do_basic_recompilation_check
m_tc_result mHscMessage
hsc_env summary source_modified mb_old_iface (mod_index, nmods)
@@ -170,6 +173,10 @@ compileOne' m_tc_result mHscMessage
addFilesToClean flags TFL_GhcSession $
[ml_obj_file $ ms_location summary]
+ -- Use an HscEnv with DynFlags updated with the plugin info (returned from
+ -- hscIncrementalCompile)
+ let hsc_env' = hsc_env{ hsc_dflags = plugin_dflags }
+
case (status, hsc_lang) of
(HscUpToDate iface, _) ->
-- TODO recomp014 triggers this assert. What's going on?!
@@ -199,7 +206,7 @@ compileOne' m_tc_result mHscMessage
-- #10660: Use the pipeline instead of calling
-- compileEmptyStub directly, so -dynamic-too gets
-- handled properly
- _ <- runPipeline StopLn hsc_env
+ _ <- runPipeline StopLn hsc_env'
(output_fn,
Nothing,
Just (HscOut src_flavour
@@ -211,21 +218,22 @@ compileOne' m_tc_result mHscMessage
o_time <- getModificationUTCTime object_filename
let !linkable = LM o_time this_mod [DotO object_filename]
return $! HomeModInfo iface hmi_details (Just linkable)
- (HscRecomp cgguts summary iface_gen, HscInterpreted) -> do
- -- In interpreted mode the regular codeGen backend is not run
- -- so we generate a interface without codeGen info.
- (iface, no_change) <- iface_gen
- -- If we interpret the code, then we can write the interface file here.
- liftIO $ hscMaybeWriteIface dflags iface no_change
- (ms_location summary)
-
- (hasStub, comp_bc, spt_entries) <-
- hscInteractive hsc_env cgguts summary
+ (HscRecomp { hscs_guts = cgguts,
+ hscs_summary = summary,
+ hscs_partial_iface = partial_iface,
+ hscs_old_iface_hash = mb_old_iface_hash,
+ hscs_iface_dflags = iface_dflags }, HscInterpreted) -> do
+ -- In interpreted mode the regular codeGen backend is not run so we
+ -- generate a interface without codeGen info.
+ final_iface <- mkFullIface hsc_env'{hsc_dflags=iface_dflags} partial_iface
+ liftIO $ hscMaybeWriteIface dflags final_iface mb_old_iface_hash (ms_location summary)
+
+ (hasStub, comp_bc, spt_entries) <- hscInteractive hsc_env' cgguts summary
stub_o <- case hasStub of
Nothing -> return []
Just stub_c -> do
- stub_o <- compileStub hsc_env stub_c
+ stub_o <- compileStub hsc_env' stub_c
return [DotO stub_o]
let hs_unlinked = [BCOs comp_bc spt_entries]
@@ -238,32 +246,20 @@ compileOne' m_tc_result mHscMessage
-- be out of date.
let !linkable = LM unlinked_time (ms_mod summary)
(hs_unlinked ++ stub_o)
- return $! HomeModInfo iface hmi_details (Just linkable)
- (HscRecomp cgguts summary iface_gen, _) -> do
+ return $! HomeModInfo final_iface hmi_details (Just linkable)
+ (HscRecomp{}, _) -> do
output_fn <- getOutputFilename next_phase
(Temporary TFL_CurrentModule)
basename dflags next_phase (Just location)
-- We're in --make mode: finish the compilation pipeline.
-
- -- We use this IORef the get out the iface from the otherwise
- -- opaque pipeline once it's created. Otherwise we would have
- -- to thread it through runPipeline.
- if_ref <- newIORef Nothing :: IO (IORef (Maybe ModIface))
- let iface_gen' = do
- res@(iface, _no_change) <- iface_gen
- writeIORef if_ref $ Just iface
- return res
-
- _ <- runPipeline StopLn hsc_env
+ (_, _, Just iface) <- runPipeline StopLn hsc_env'
(output_fn,
Nothing,
- Just (HscOut src_flavour mod_name
- (HscRecomp cgguts summary iface_gen')))
+ Just (HscOut src_flavour mod_name status))
(Just basename)
Persistent
(Just location)
[]
- iface <- (expectJust "Iface callback") <$> readIORef if_ref
-- The object filename comes from the ModLocation
o_time <- getModificationUTCTime object_filename
let !linkable = LM o_time this_mod [DotO object_filename]
@@ -354,7 +350,7 @@ compileForeign hsc_env lang stub_c = do
LangObjcxx -> Cobjcxx
LangAsm -> As True -- allow CPP
RawObject -> panic "compileForeign: should be unreachable"
- (_, stub_o) <- runPipeline StopLn hsc_env
+ (_, stub_o, _) <- runPipeline StopLn hsc_env
(stub_c, Nothing, Just (RealPhase phase))
Nothing (Temporary TFL_GhcSession)
Nothing{-no ModLocation-}
@@ -563,7 +559,7 @@ compileFile hsc_env stop_phase (src, mb_phase) = do
-- -o foo applies to the file we are compiling now
| otherwise = Persistent
- ( _, out_file) <- runPipeline stop_phase hsc_env
+ ( _, out_file, _) <- runPipeline stop_phase hsc_env
(src, Nothing, fmap RealPhase mb_phase)
Nothing
output
@@ -606,7 +602,8 @@ runPipeline
-> PipelineOutput -- ^ Output filename
-> Maybe ModLocation -- ^ A ModLocation, if this is a Haskell module
-> [FilePath] -- ^ foreign objects
- -> IO (DynFlags, FilePath) -- ^ (final flags, output filename)
+ -> IO (DynFlags, FilePath, Maybe ModIface)
+ -- ^ (final flags, output filename, interface)
runPipeline stop_phase hsc_env0 (input_fn, mb_input_buf, mb_phase)
mb_basename output maybe_loc foreign_os
@@ -700,20 +697,21 @@ runPipeline'
-> FilePath -- ^ Input filename
-> Maybe ModLocation -- ^ A ModLocation, if this is a Haskell module
-> [FilePath] -- ^ foreign objects, if we have one
- -> IO (DynFlags, FilePath) -- ^ (final flags, output filename)
+ -> IO (DynFlags, FilePath, Maybe ModIface)
+ -- ^ (final flags, output filename, interface)
runPipeline' start_phase hsc_env env input_fn
maybe_loc foreign_os
= do
-- Execute the pipeline...
- let state = PipeState{ hsc_env, maybe_loc, foreign_os = foreign_os }
-
- evalP (pipeLoop start_phase input_fn) env state
+ let state = PipeState{ hsc_env, maybe_loc, foreign_os = foreign_os, iface = Nothing }
+ (pipe_state, fp) <- evalP (pipeLoop start_phase input_fn) env state
+ return (pipeStateDynFlags pipe_state, fp, pipeStateModIface pipe_state)
-- ---------------------------------------------------------------------------
-- outer pipeline loop
-- | pipeLoop runs phases until we reach the stop phase
-pipeLoop :: PhasePlus -> FilePath -> CompPipeline (DynFlags, FilePath)
+pipeLoop :: PhasePlus -> FilePath -> CompPipeline FilePath
pipeLoop phase input_fn = do
env <- getPipeEnv
dflags <- getDynFlags
@@ -729,7 +727,7 @@ pipeLoop phase input_fn = do
-- further compilation stages can tell what the original filename was.
case output_spec env of
Temporary _ ->
- return (dflags, input_fn)
+ return input_fn
output ->
do pst <- getPipeState
final_fn <- liftIO $ getOutputFilename
@@ -739,7 +737,7 @@ pipeLoop phase input_fn = do
let msg = ("Copying `" ++ input_fn ++"' to `" ++ final_fn ++ "'")
line_prag = Just ("{-# LINE 1 \"" ++ src_filename env ++ "\" #-}\n")
liftIO $ copyWithHeader dflags msg line_prag input_fn final_fn
- return (dflags, final_fn)
+ return final_fn
| not (realPhase `happensBefore'` stopPhase)
@@ -1136,9 +1134,13 @@ runPhase (RealPhase (Hsc src_flavour)) input_fn dflags0
-- run the compiler!
let msg hsc_env _ what _ = oneShotMsg hsc_env what
- (result, _) <- liftIO $ hscIncrementalCompile True Nothing (Just msg) hsc_env'
+ (result, _mod_details, plugin_dflags) <-
+ liftIO $ hscIncrementalCompile True Nothing (Just msg) hsc_env'
mod_summary source_unchanged Nothing (1,1)
+ -- In the rest of the pipeline use the dflags with plugin info
+ setDynFlags plugin_dflags
+
return (HscOut src_flavour mod_name result,
panic "HscOut doesn't have an input filename")
@@ -1173,7 +1175,11 @@ runPhase (HscOut src_flavour mod_name result) _ dflags = do
basename = dropExtension input_fn
liftIO $ compileEmptyStub dflags hsc_env' basename location mod_name
return (RealPhase StopLn, o_file)
- HscRecomp cgguts mod_summary iface_gen
+ HscRecomp { hscs_guts = cgguts,
+ hscs_summary = mod_summary,
+ hscs_partial_iface = partial_iface,
+ hscs_old_iface_hash = mb_old_iface_hash,
+ hscs_iface_dflags = iface_dflags }
-> do output_fn <- phaseOutputFilename next_phase
PipeState{hsc_env=hsc_env'} <- getPipeState
@@ -1181,12 +1187,12 @@ runPhase (HscOut src_flavour mod_name result) _ dflags = do
(outputFilename, mStub, foreign_files) <- liftIO $
hscGenHardCode hsc_env' cgguts mod_summary output_fn
-
- (iface, no_change) <- liftIO iface_gen
+ final_iface <- liftIO (mkFullIface hsc_env'{hsc_dflags=iface_dflags} partial_iface)
+ setIface final_iface
-- See Note [Writing interface files]
let if_dflags = dflags `gopt_unset` Opt_BuildDynamicToo
- liftIO $ hscMaybeWriteIface if_dflags iface no_change
+ liftIO $ hscMaybeWriteIface if_dflags final_iface mb_old_iface_hash
(ms_location mod_summary)
stub_o <- liftIO (mapM (compileStub hsc_env') mStub)
@@ -1200,25 +1206,18 @@ runPhase (HscOut src_flavour mod_name result) _ dflags = do
-- Cmm phase
runPhase (RealPhase CmmCpp) input_fn dflags
- = do
- output_fn <- phaseOutputFilename Cmm
+ = do output_fn <- phaseOutputFilename Cmm
liftIO $ doCpp dflags False{-not raw-}
input_fn output_fn
return (RealPhase Cmm, output_fn)
runPhase (RealPhase Cmm) input_fn dflags
- = do
- let hsc_lang = hscTarget dflags
-
- let next_phase = hscPostBackendPhase HsSrcFile hsc_lang
-
- output_fn <- phaseOutputFilename next_phase
-
- PipeState{hsc_env} <- getPipeState
-
- liftIO $ hscCompileCmmFile hsc_env input_fn output_fn
-
- return (RealPhase next_phase, output_fn)
+ = do let hsc_lang = hscTarget dflags
+ let next_phase = hscPostBackendPhase HsSrcFile hsc_lang
+ output_fn <- phaseOutputFilename next_phase
+ PipeState{hsc_env} <- getPipeState
+ liftIO $ hscCompileCmmFile hsc_env input_fn output_fn
+ return (RealPhase next_phase, output_fn)
-----------------------------------------------------------------------------
-- Cc phase
diff --git a/compiler/main/HscMain.hs b/compiler/main/HscMain.hs
index 9ed2710ee8..16f50f11e9 100644
--- a/compiler/main/HscMain.hs
+++ b/compiler/main/HscMain.hs
@@ -727,7 +727,7 @@ hscIncrementalCompile :: Bool
-> SourceModified
-> Maybe ModIface
-> (Int,Int)
- -> IO (HscStatus, ModDetails)
+ -> IO (HscStatus, ModDetails, DynFlags)
hscIncrementalCompile always_do_basic_recompilation_check m_tc_result
mHscMessage hsc_env' mod_summary source_modified mb_old_iface mod_index
= do
@@ -768,13 +768,14 @@ hscIncrementalCompile always_do_basic_recompilation_check m_tc_result
-- in make mode, since this HMI will go into the HPT.
details <- genModDetails hsc_env' iface
return details
- return (HscUpToDate iface, details)
+ return (HscUpToDate iface, details, dflags)
-- We finished type checking. (mb_old_hash is the hash of
-- the interface that existed on disk; it's possible we had
-- to retypecheck but the resulting interface is exactly
-- the same.)
- Right (FrontendTypecheck tc_result, mb_old_hash) ->
- finish mod_summary tc_result mb_old_hash
+ Right (FrontendTypecheck tc_result, mb_old_hash) -> do
+ (status, mb_old_hash) <- finish mod_summary tc_result mb_old_hash
+ return (status, mb_old_hash, dflags)
-- Runs the post-typechecking frontend (desugar and simplify). We want to
-- generate most of the interface as late as possible. This gets us up-to-date
@@ -801,10 +802,10 @@ finish summary tc_result mb_old_hash = do
ms_mod summary /= gHC_PRIM && hsc_src == HsSrcFile
mk_simple_iface :: Hsc (HscStatus, ModDetails)
mk_simple_iface = do
- (iface, no_change, details) <- liftIO $
+ (iface, mb_old_iface_hash, details) <- liftIO $
hscSimpleIface hsc_env tc_result mb_old_hash
- liftIO $ hscMaybeWriteIface dflags iface no_change (ms_location summary)
+ liftIO $ hscMaybeWriteIface dflags iface mb_old_iface_hash (ms_location summary)
let hsc_status =
case (target, hsc_src) of
@@ -838,19 +839,12 @@ finish summary tc_result mb_old_hash = do
-- See Note [Avoiding space leaks in toIface*] for details.
force (mkPartialIface hsc_env details desugared_guts)
- let iface_gen :: IO (ModIface, Bool)
- iface_gen = do
- -- Build a fully instantiated ModIface.
- -- This has to happen *after* code gen so that the back-end
- -- info has been set.
- -- This captures hsc_env, but it seems we keep it alive in other
- -- ways as well so we don't bother extracting only the relevant parts.
- dumpIfaceStats hsc_env
- final_iface <- mkFullIface hsc_env partial_iface
- let no_change = mb_old_hash == Just (mi_iface_hash (mi_final_exts final_iface))
- return (final_iface, no_change)
-
- return ( HscRecomp cg_guts summary iface_gen, details )
+ return ( HscRecomp { hscs_guts = cg_guts,
+ hscs_summary = summary,
+ hscs_partial_iface = partial_iface,
+ hscs_old_iface_hash = mb_old_hash,
+ hscs_iface_dflags = dflags },
+ details )
else mk_simple_iface
@@ -868,15 +862,17 @@ hscMaybeWriteIface, but only once per compilation (twice with dynamic-too).
In this case we create the interface file inside RunPhase using the interface
generator contained inside the HscRecomp status.
-}
-hscMaybeWriteIface :: DynFlags -> ModIface -> Bool -> ModLocation -> IO ()
-hscMaybeWriteIface dflags iface no_change location =
+hscMaybeWriteIface :: DynFlags -> ModIface -> Maybe Fingerprint -> ModLocation -> IO ()
+hscMaybeWriteIface dflags iface old_iface location = do
let force_write_interface = gopt Opt_WriteInterface dflags
write_interface = case hscTarget dflags of
HscNothing -> False
HscInterpreted -> False
_ -> True
- in when (write_interface || force_write_interface) $
- hscWriteIface dflags iface no_change location
+ no_change = old_iface == Just (mi_iface_hash (mi_final_exts iface))
+
+ when (write_interface || force_write_interface) $
+ hscWriteIface dflags iface no_change location
--------------------------------------------------------------
-- NoRecomp handlers
@@ -1341,13 +1337,13 @@ hscSimplify' plugins ds_result = do
hscSimpleIface :: HscEnv
-> TcGblEnv
-> Maybe Fingerprint
- -> IO (ModIface, Bool, ModDetails)
+ -> IO (ModIface, Maybe Fingerprint, ModDetails)
hscSimpleIface hsc_env tc_result mb_old_iface
= runHsc hsc_env $ hscSimpleIface' tc_result mb_old_iface
hscSimpleIface' :: TcGblEnv
-> Maybe Fingerprint
- -> Hsc (ModIface, Bool, ModDetails)
+ -> Hsc (ModIface, Maybe Fingerprint, ModDetails)
hscSimpleIface' tc_result mb_old_iface = do
hsc_env <- getHscEnv
details <- liftIO $ mkBootModDetailsTc hsc_env tc_result
@@ -1356,10 +1352,9 @@ hscSimpleIface' tc_result mb_old_iface = do
<- {-# SCC "MkFinalIface" #-}
liftIO $
mkIfaceTc hsc_env safe_mode details tc_result
- let no_change = mb_old_iface == Just (mi_iface_hash (mi_final_exts new_iface))
-- And the answer is ...
liftIO $ dumpIfaceStats hsc_env
- return (new_iface, no_change, details)
+ return (new_iface, mb_old_iface, details)
--------------------------------------------------------------
-- BackEnd combinators
diff --git a/compiler/main/HscTypes.hs b/compiler/main/HscTypes.hs
index 4b251af436..ca321d6405 100644
--- a/compiler/main/HscTypes.hs
+++ b/compiler/main/HscTypes.hs
@@ -242,11 +242,21 @@ data HscStatus
-- | Recompile this module.
| HscRecomp
{ hscs_guts :: CgGuts
- -- ^ Information for the code generator.
+ -- ^ Information for the code generator.
, hscs_summary :: ModSummary
- -- ^ Module info
- , hscs_iface_gen :: IO (ModIface, Bool)
- -- ^ Action to generate iface after codegen.
+ -- ^ Module info
+ , hscs_partial_iface :: !PartialModIface
+ -- ^ Partial interface
+ , hscs_old_iface_hash :: !(Maybe Fingerprint)
+ -- ^ Old interface hash for this compilation, if an old interface file
+ -- exists. Pass to `hscMaybeWriteIface` when writing the interface to
+ -- avoid updating the existing interface when the interface isn't
+ -- changed.
+ , hscs_iface_dflags :: !DynFlags
+ -- ^ Generate final iface using this DynFlags.
+ -- FIXME (osa): I don't understand why this is necessary, but I spent
+ -- almost two days trying to figure this out and I couldn't .. perhaps
+ -- someone who understands this code better will remove this later.
}
-- Should HscStatus contain the HomeModInfo?
-- All places where we return a status we also return a HomeModInfo.
diff --git a/compiler/main/PipelineMonad.hs b/compiler/main/PipelineMonad.hs
index d152d04530..bdda19ceac 100644
--- a/compiler/main/PipelineMonad.hs
+++ b/compiler/main/PipelineMonad.hs
@@ -7,7 +7,8 @@ module PipelineMonad (
CompPipeline(..), evalP
, PhasePlus(..)
, PipeEnv(..), PipeState(..), PipelineOutput(..)
- , getPipeEnv, getPipeState, setDynFlags, setModLocation, setForeignOs
+ , getPipeEnv, getPipeState, setDynFlags, setModLocation, setForeignOs, setIface
+ , pipeStateDynFlags, pipeStateModIface
) where
import GhcPrelude
@@ -25,8 +26,8 @@ import Control.Monad
newtype CompPipeline a = P { unP :: PipeEnv -> PipeState -> IO (PipeState, a) }
deriving (Functor)
-evalP :: CompPipeline a -> PipeEnv -> PipeState -> IO a
-evalP f env st = liftM snd $ unP f env st
+evalP :: CompPipeline a -> PipeEnv -> PipeState -> IO (PipeState, a)
+evalP (P f) env st = f env st
instance Applicative CompPipeline where
pure a = P $ \_env state -> return (state, a)
@@ -67,12 +68,21 @@ data PipeState = PipeState {
maybe_loc :: Maybe ModLocation,
-- ^ the ModLocation. This is discovered during compilation,
-- in the Hsc phase where we read the module header.
- foreign_os :: [FilePath]
+ foreign_os :: [FilePath],
-- ^ additional object files resulting from compiling foreign
-- code. They come from two sources: foreign stubs, and
-- add{C,Cxx,Objc,Objcxx}File from template haskell
+ iface :: Maybe ModIface
+ -- ^ Interface generated by HscOut phase. Only available after the
+ -- phase runs.
}
+pipeStateDynFlags :: PipeState -> DynFlags
+pipeStateDynFlags = hsc_dflags . hsc_env
+
+pipeStateModIface :: PipeState -> Maybe ModIface
+pipeStateModIface = iface
+
data PipelineOutput
= Temporary TempFileLifetime
-- ^ Output should be to a temporary file: we're going to
@@ -107,3 +117,6 @@ setModLocation loc = P $ \_env state ->
setForeignOs :: [FilePath] -> CompPipeline ()
setForeignOs os = P $ \_env state ->
return (state{ foreign_os = os }, ())
+
+setIface :: ModIface -> CompPipeline ()
+setIface iface = P $ \_env state -> return (state{ iface = Just iface }, ())