diff options
author | Simon Marlow <marlowsd@gmail.com> | 2015-11-07 09:39:05 +0000 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2015-11-07 09:39:05 +0000 |
commit | ce1f1607ed7f8fedd2f63c8610cafefd59baaf32 (patch) | |
tree | 718641160c3d93a2ca974deec1e228cb09e1a97e /compiler | |
parent | a58eeb7febd67c93dab82de7049ef1dcdecd34e9 (diff) | |
download | haskell-ce1f1607ed7f8fedd2f63c8610cafefd59baaf32.tar.gz |
Make GHCi & TH work when the compiler is built with -prof
Summary:
Amazingly, there were zero changes to the byte code generator and very
few changes to the interpreter - mainly because we've used good
abstractions that hide the differences between profiling and
non-profiling. So that bit was pleasantly straightforward, but there
were a pile of other wibbles to get the whole test suite through.
Note that a compiler built with -prof is now like one built with
-dynamic, in that to use TH you have to build the code the same way.
For dynamic, we automatically enable -dynamic-too when TH is required,
but we don't have anything equivalent for profiling, so you have to
explicitly use -prof when building code that uses TH with a profiled
compiler. For this reason Cabal won't work with TH. We don't expect
to ship a profiled compiler, so I think that's OK.
Test Plan: validate with GhcProfiled=YES in validate.mk
Reviewers: goldfire, bgamari, rwbarton, austin, hvr, erikd, ezyang
Reviewed By: ezyang
Subscribers: thomie
Differential Revision: https://phabricator.haskell.org/D1407
GHC Trac Issues: #4837, #545
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/cmm/CmmInfo.hs | 4 | ||||
-rw-r--r-- | compiler/codeGen/StgCmmProf.hs | 13 | ||||
-rw-r--r-- | compiler/ghci/ByteCodeItbls.hs | 18 | ||||
-rw-r--r-- | compiler/ghci/Linker.hs | 74 | ||||
-rw-r--r-- | compiler/ghci/RtClosureInspect.hs | 15 | ||||
-rw-r--r-- | compiler/main/DynFlags.hs | 21 | ||||
-rw-r--r-- | compiler/main/HscMain.hs | 5 |
7 files changed, 88 insertions, 62 deletions
diff --git a/compiler/cmm/CmmInfo.hs b/compiler/cmm/CmmInfo.hs index ce8b9f8b6b..723f7fc4cc 100644 --- a/compiler/cmm/CmmInfo.hs +++ b/compiler/cmm/CmmInfo.hs @@ -26,6 +26,7 @@ module CmmInfo ( maxStdInfoTableSizeW, maxRetInfoTableSizeW, stdInfoTableSizeB, + conInfoTableSizeB, stdSrtBitmapOffset, stdClosureTypeOffset, stdPtrsOffset, stdNonPtrsOffset, @@ -551,3 +552,6 @@ stdClosureTypeOffset dflags = stdInfoTableSizeB dflags - wORD_SIZE dflags stdPtrsOffset, stdNonPtrsOffset :: DynFlags -> ByteOff stdPtrsOffset dflags = stdInfoTableSizeB dflags - 2 * wORD_SIZE dflags stdNonPtrsOffset dflags = stdInfoTableSizeB dflags - 2 * wORD_SIZE dflags + hALF_WORD_SIZE dflags + +conInfoTableSizeB :: DynFlags -> Int +conInfoTableSizeB dflags = stdInfoTableSizeB dflags + wORD_SIZE dflags diff --git a/compiler/codeGen/StgCmmProf.hs b/compiler/codeGen/StgCmmProf.hs index a7384c725b..efad805120 100644 --- a/compiler/codeGen/StgCmmProf.hs +++ b/compiler/codeGen/StgCmmProf.hs @@ -321,14 +321,15 @@ dynLdvInit dflags = -- (era << LDV_SHIFT) | LDV_STATE_CREATE -- Initialise the LDV word of a new closure -- ldvRecordCreate :: CmmExpr -> FCode () -ldvRecordCreate closure = do dflags <- getDynFlags - emit $ mkStore (ldvWord dflags closure) (dynLdvInit dflags) +ldvRecordCreate closure = do + dflags <- getDynFlags + emit $ mkStore (ldvWord dflags closure) (dynLdvInit dflags) -- --- Called when a closure is entered, marks the closure as having been "used". --- The closure is not an 'inherently used' one. --- The closure is not IND or IND_OLDGEN because neither is considered for LDV --- profiling. +-- | Called when a closure is entered, marks the closure as having +-- been "used". The closure is not an "inherently used" one. The +-- closure is not @IND@ or @IND_OLDGEN@ because neither is considered +-- for LDV profiling. -- ldvEnterClosure :: ClosureInfo -> CmmReg -> FCode () ldvEnterClosure closure_info node_reg = do diff --git a/compiler/ghci/ByteCodeItbls.hs b/compiler/ghci/ByteCodeItbls.hs index a01fcd89b9..01420f5e34 100644 --- a/compiler/ghci/ByteCodeItbls.hs +++ b/compiler/ghci/ByteCodeItbls.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE CPP, MagicHash #-} +{-# LANGUAGE CPP, MagicHash, ScopedTypeVariables #-} {-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-} -- -- (c) The University of Glasgow 2002-2006 @@ -20,6 +20,7 @@ import DataCon ( DataCon, dataConRepArgTys, dataConIdentity ) import TyCon ( TyCon, tyConFamilySize, isDataTyCon, tyConDataCons ) import Type ( flattenRepType, repType, typePrimRep ) import StgCmmLayout ( mkVirtHeapOffsets ) +import CmmInfo ( conInfoTableSizeB, profInfoTableSizeW ) import Util import Control.Monad @@ -43,10 +44,6 @@ itblCode dflags (ItblPtr ptr) | ghciTablesNextToCode = castPtr ptr `plusPtr` conInfoTableSizeB dflags | otherwise = castPtr ptr --- XXX bogus -conInfoTableSizeB :: DynFlags -> Int -conInfoTableSizeB dflags = 3 * wORD_SIZE dflags - type ItblEnv = NameEnv (Name, ItblPtr) -- We need the Name in the range so we know which -- elements to filter out when unloading a module @@ -258,8 +255,10 @@ foreign import ccall "&stg_interp_constr_entry" -- Ultra-minimalist version specially for constructors #if SIZEOF_VOID_P == 8 type HalfWord = Word32 +type FullWord = Word64 #else type HalfWord = Word16 +type FullWord = Word32 #endif data StgConInfoTable = StgConInfoTable { @@ -311,6 +310,8 @@ sizeOfItbl dflags itbl Right xs -> sizeOf (head xs) * length xs else 0 ] + + if rtsIsProfiled then profInfoTableSizeW * wORD_SIZE dflags + else 0 pokeItbl :: DynFlags -> Ptr StgInfoTable -> StgInfoTable -> IO () pokeItbl _ a0 itbl @@ -319,6 +320,9 @@ pokeItbl _ a0 itbl case entry itbl of Nothing -> return () Just e -> store e + when rtsIsProfiled $ do + store (0 :: FullWord) + store (0 :: FullWord) store (ptrs itbl) store (nptrs itbl) store (tipe itbl) @@ -335,6 +339,10 @@ peekItbl dflags a0 entry' <- if ghciTablesNextToCode then return Nothing else liftM Just load + when rtsIsProfiled $ do + (_ :: Ptr FullWord) <- advance + (_ :: Ptr FullWord) <- advance + return () ptrs' <- load nptrs' <- load tipe' <- load diff --git a/compiler/ghci/Linker.hs b/compiler/ghci/Linker.hs index f62998ce86..9fa89fec5e 100644 --- a/compiler/ghci/Linker.hs +++ b/compiler/ghci/Linker.hs @@ -504,24 +504,20 @@ dieWith dflags span msg = throwGhcExceptionIO (ProgramError (showSDoc dflags (mk checkNonStdWay :: DynFlags -> SrcSpan -> IO (Maybe FilePath) -checkNonStdWay dflags srcspan = - if interpWays == haskellWays - then return Nothing - -- see #3604: object files compiled for way "dyn" need to link to the - -- dynamic packages, so we can't load them into a statically-linked GHCi. - -- we have to treat "dyn" in the same way as "prof". - -- - -- In the future when GHCi is dynamically linked we should be able to relax - -- this, but they we may have to make it possible to load either ordinary - -- .o files or -dynamic .o files into GHCi (currently that's not possible - -- because the dynamic objects contain refs to e.g. __stginit_base_Prelude_dyn - -- whereas we have __stginit_base_Prelude_. - else if objectSuf dflags == normalObjectSuffix && not (null haskellWays) - then failNonStd dflags srcspan - else return $ Just $ if dynamicGhc - then "dyn_o" - else "o" - where haskellWays = filter (not . wayRTSOnly) (ways dflags) +checkNonStdWay dflags srcspan + | interpWays == haskellWays = return Nothing + -- Only if we are compiling with the same ways as GHC is built + -- with, can we dynamically load those object files. (see #3604) + + | objectSuf dflags == normalObjectSuffix && not (null haskellWays) + = failNonStd dflags srcspan + + | otherwise = return (Just (interpTag ++ "o")) + where + haskellWays = filter (not . wayRTSOnly) (ways dflags) + interpTag = case mkBuildTag interpWays of + "" -> "" + tag -> tag ++ "_" normalObjectSuffix :: String normalObjectSuffix = phaseInputExt StopLn @@ -529,11 +525,13 @@ normalObjectSuffix = phaseInputExt StopLn failNonStd :: DynFlags -> SrcSpan -> IO (Maybe FilePath) failNonStd dflags srcspan = dieWith dflags srcspan $ ptext (sLit "Dynamic linking required, but this is a non-standard build (eg. prof).") $$ - ptext (sLit "You need to build the program twice: once the") <+> ghciWay <+> ptext (sLit "way, and then") $$ + ptext (sLit "You need to build the program twice: once") <+> + ghciWay <> ptext (sLit ", and then") $$ ptext (sLit "in the desired way using -osuf to set the object file suffix.") - where ghciWay = if dynamicGhc - then ptext (sLit "dynamic") - else ptext (sLit "normal") + where ghciWay + | dynamicGhc = ptext (sLit "with -dynamic") + | rtsIsProfiled = ptext (sLit "with -prof") + | otherwise = ptext (sLit "the normal way") getLinkDeps :: HscEnv -> HomePackageTable -> PersistentLinkerState @@ -663,7 +661,7 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods ok <- doesFileExist new_file if (not ok) then dieWith dflags span $ - ptext (sLit "cannot find normal object file ") + ptext (sLit "cannot find object file ") <> quotes (text new_file) $$ while_linking_expr else return (DotO new_file) adjust_ul _ (DotA fp) = panic ("adjust_ul DotA " ++ show fp) @@ -1199,22 +1197,34 @@ locateLib dflags is_hs dirs lib -- for a dynamic library (#5289) -- otherwise, assume loadDLL can find it -- - = findDll `orElse` findArchive `orElse` tryGcc `orElse` tryGccPrefixed `orElse` assumeDll - - | not dynamicGhc - -- When the GHC package was not compiled as dynamic library - -- (=DYNAMIC not set), we search for .o libraries or, if they - -- don't exist, .a libraries. - = findObject `orElse` findArchive `orElse` assumeDll + = findDll `orElse` + findArchive `orElse` + tryGcc `orElse` + tryGccPrefixed `orElse` + assumeDll - | otherwise + | dynamicGhc -- When the GHC package was compiled as dynamic library (=DYNAMIC set), -- we search for .so libraries first. = findHSDll `orElse` findDynObject `orElse` assumeDll + + | rtsIsProfiled + -- When the GHC package is profiled, only a libHSfoo_p.a archive will do. + = findArchive `orElse` + assumeDll + + | otherwise + -- HSfoo.o is the best, but only works for the normal way + -- libHSfoo.a is the backup option. + = findObject `orElse` + findArchive `orElse` + assumeDll + where obj_file = lib <.> "o" dyn_obj_file = lib <.> "dyn_o" - arch_file = "lib" ++ lib <.> "a" + arch_file = "lib" ++ lib ++ lib_tag <.> "a" + lib_tag = if is_hs && rtsIsProfiled then "_p" else "" hs_dyn_lib_name = lib ++ '-':programName dflags ++ projectVersion dflags hs_dyn_lib_file = mkHsSOName platform hs_dyn_lib_name diff --git a/compiler/ghci/RtClosureInspect.hs b/compiler/ghci/RtClosureInspect.hs index b95d05322f..6853fbbaea 100644 --- a/compiler/ghci/RtClosureInspect.hs +++ b/compiler/ghci/RtClosureInspect.hs @@ -175,17 +175,17 @@ getClosureData :: DynFlags -> a -> IO Closure getClosureData dflags a = case unpackClosure# a of (# iptr, ptrs, nptrs #) -> do - let iptr' - | ghciTablesNextToCode = - Ptr iptr + let iptr0 = Ptr iptr + let iptr1 + | ghciTablesNextToCode = iptr0 | otherwise = -- the info pointer we get back from unpackClosure# -- is to the beginning of the standard info table, -- but the Storable instance for info tables takes -- into account the extra entry pointer when -- !ghciTablesNextToCode, so we must adjust here: - Ptr iptr `plusPtr` negate (wORD_SIZE dflags) - itbl <- peekItbl dflags iptr' + iptr0 `plusPtr` negate (wORD_SIZE dflags) + itbl <- peekItbl dflags iptr1 let tipe = readCType (BCI.tipe itbl) elems = fromIntegral (BCI.ptrs itbl) ptrsList = Array 0 (elems - 1) elems ptrs @@ -193,7 +193,7 @@ getClosureData dflags a = | I# i <- [0.. fromIntegral (BCI.nptrs itbl)-1] ] ASSERT(elems >= 0) return () ptrsList `seq` - return (Closure tipe (Ptr iptr) itbl ptrsList nptrs_data) + return (Closure tipe iptr0 itbl ptrsList nptrs_data) readCType :: Integral a => a -> ClosureType readCType i @@ -774,7 +774,8 @@ cvObtainTerm hsc_env max_depth force old_ty hval = runTR hsc_env $ do return (Term my_ty (Right dc) a subTerms) -- The otherwise case: can be a Thunk,AP,PAP,etc. - tipe_clos -> + tipe_clos -> do + traceTR (text "Unknown closure:" <+> ppr tipe_clos) return (Suspension tipe_clos my_ty a Nothing) -- insert NewtypeWraps around newtypes diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs index fb6265cdfb..b8705603c7 100644 --- a/compiler/main/DynFlags.hs +++ b/compiler/main/DynFlags.hs @@ -172,10 +172,8 @@ import SrcLoc import BasicTypes ( IntWithInf, treatZeroAsInf ) import FastString import Outputable -#ifdef GHCI import Foreign.C ( CInt(..) ) import System.IO.Unsafe ( unsafeDupablePerformIO ) -#endif import {-# SOURCE #-} ErrUtils ( Severity(..), MsgDoc, mkLocMessage ) import System.IO.Unsafe ( unsafePerformIO ) @@ -1580,9 +1578,10 @@ defaultWays settings = if pc_DYNAMIC_BY_DEFAULT (sPlatformConstants settings) else [] interpWays :: [Way] -interpWays = if dynamicGhc - then [WayDyn] - else [] +interpWays + | dynamicGhc = [WayDyn] + | rtsIsProfiled = [WayProf] + | otherwise = [] -------------------------------------------------------------------------- @@ -3493,14 +3492,12 @@ glasgowExtsFlags = [ , Opt_UnicodeSyntax , Opt_UnliftedFFITypes ] -#ifdef GHCI -- Consult the RTS to find whether GHC itself has been built profiled -- If so, you can't use Template Haskell foreign import ccall unsafe "rts_isProfiled" rtsIsProfiledIO :: IO CInt rtsIsProfiled :: Bool rtsIsProfiled = unsafeDupablePerformIO rtsIsProfiledIO /= 0 -#endif #ifdef GHCI -- Consult the RTS to find whether GHC itself has been built with @@ -4126,6 +4123,8 @@ compilerInfo dflags then "YES" else "NO"), ("GHC Dynamic", if dynamicGhc then "YES" else "NO"), + ("GHC Profiled", if rtsIsProfiled + then "YES" else "NO"), ("Leading underscore", cLeadingUnderscore), ("Debug on", show debugIsOn), ("LibDir", topDir dflags), @@ -4217,6 +4216,14 @@ makeDynFlagsConsistent dflags "Enabling -fPIC as it is always on for this platform" | Left err <- checkOptLevel (optLevel dflags) dflags = loop (updOptLevel 0 dflags) err + + | LinkInMemory <- ghcLink dflags + , rtsIsProfiled + , isObjectTarget (hscTarget dflags) + , WayProf `notElem` ways dflags + = loop dflags{ways = WayProf : ways dflags} + "Enabling -prof, because -fobject-code is enabled and GHCi is profiled" + | otherwise = (dflags, []) where loc = mkGeneralSrcSpan (fsLit "when making flags consistent") loop updated_dflags warning diff --git a/compiler/main/HscMain.hs b/compiler/main/HscMain.hs index 95cb5f222f..53c6f626e5 100644 --- a/compiler/main/HscMain.hs +++ b/compiler/main/HscMain.hs @@ -1787,11 +1787,6 @@ hscCompileCoreExpr hsc_env = hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO HValue hscCompileCoreExpr' hsc_env srcspan ds_expr - | rtsIsProfiled - = throwIO (InstallationError "You can't call hscCompileCoreExpr in a profiled compiler") - -- Otherwise you get a seg-fault when you run it - - | otherwise = do { let dflags = hsc_dflags hsc_env {- Simplify it -} |