summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2018-06-18 17:18:10 +0100
committerSimon Marlow <marlowsd@gmail.com>2018-07-16 15:33:19 +0100
commit71f6b18ba365da9ee4795f6cbce6ec9f1bfe95e8 (patch)
tree5c827256559249740703e47359ab8bfe43173560
parent8b6a9e5575fc848dc03b50b415aa57447654662f (diff)
downloadhaskell-71f6b18ba365da9ee4795f6cbce6ec9f1bfe95e8.tar.gz
Fix space leaks
Summary: All these were detected by -fghci-leak-check when GHC was compiled *without* optimisation (e.g. using the "quick" build flavour). Unfortunately I don't know of a good way to keep this working. I'd like to just disable the -fghci-leak-check flag when the compiler is built without optimisation, but it doesn't look like we have an easy way to do that. And even if we could, it would be fragile anyway, Test Plan: `cd testsuite/tests/ghci; make` Reviewers: bgamari, hvr, erikd, tdammers Subscribers: tdammers, rwbarton, thomie, carter GHC Trac Issues: #15246 Differential Revision: https://phabricator.haskell.org/D4872
-rw-r--r--compiler/ghci/Linker.hs33
-rw-r--r--compiler/iface/IfaceEnv.hs7
-rw-r--r--compiler/main/DriverPipeline.hs4
-rw-r--r--compiler/main/HscTypes.hs6
-rw-r--r--compiler/typecheck/TcRnMonad.hs9
-rw-r--r--compiler/utils/IOEnv.hs2
-rw-r--r--ghc/GHCi/UI.hs7
-rw-r--r--testsuite/tests/perf/compiler/all.T9
8 files changed, 44 insertions, 33 deletions
diff --git a/compiler/ghci/Linker.hs b/compiler/ghci/Linker.hs
index 8d0338a9dd..2af03ddde8 100644
--- a/compiler/ghci/Linker.hs
+++ b/compiler/ghci/Linker.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE CPP, NondecreasingIndentation, TupleSections, RecordWildCards #-}
+{-# LANGUAGE BangPatterns #-}
{-# OPTIONS_GHC -fno-cse #-}
-- -fno-cse is needed for GLOBAL_VAR's to behave properly
@@ -169,10 +170,10 @@ extendLoadedPkgs pkgs =
extendLinkEnv :: [(Name,ForeignHValue)] -> IO ()
extendLinkEnv new_bindings =
- modifyPLS_ $ \pls -> do
- let ce = closure_env pls
- let new_ce = extendClosureEnv ce new_bindings
- return pls{ closure_env = new_ce }
+ modifyPLS_ $ \pls@PersistentLinkerState{..} -> do
+ let new_ce = extendClosureEnv closure_env new_bindings
+ return $! pls{ closure_env = new_ce }
+ -- strictness is important for not retaining old copies of the pls
deleteFromLinkEnv :: [Name] -> IO ()
deleteFromLinkEnv to_remove =
@@ -1095,15 +1096,19 @@ unload_wkr :: HscEnv
-- Does the core unload business
-- (the wrapper blocks exceptions and deals with the PLS get and put)
-unload_wkr hsc_env keep_linkables pls = do
+unload_wkr hsc_env keep_linkables pls@PersistentLinkerState{..} = do
+ -- NB. careful strictness here to avoid keeping the old PLS when
+ -- we're unloading some code. -fghci-leak-check with the tests in
+ -- testsuite/ghci can detect space leaks here.
+
let (objs_to_keep, bcos_to_keep) = partition isObjectLinkable keep_linkables
discard keep l = not (linkableInSet l keep)
(objs_to_unload, remaining_objs_loaded) =
- partition (discard objs_to_keep) (objs_loaded pls)
+ partition (discard objs_to_keep) objs_loaded
(bcos_to_unload, remaining_bcos_loaded) =
- partition (discard bcos_to_keep) (bcos_loaded pls)
+ partition (discard bcos_to_keep) bcos_loaded
mapM_ unloadObjs objs_to_unload
mapM_ unloadObjs bcos_to_unload
@@ -1114,7 +1119,7 @@ unload_wkr hsc_env keep_linkables pls = do
filter (not . null . linkableObjs) bcos_to_unload))) $
purgeLookupSymbolCache hsc_env
- let bcos_retained = mkModuleSet $ map linkableModule remaining_bcos_loaded
+ let !bcos_retained = mkModuleSet $ map linkableModule remaining_bcos_loaded
-- Note that we want to remove all *local*
-- (i.e. non-isExternal) names too (these are the
@@ -1122,13 +1127,13 @@ unload_wkr hsc_env keep_linkables pls = do
keep_name (n,_) = isExternalName n &&
nameModule n `elemModuleSet` bcos_retained
- itbl_env' = filterNameEnv keep_name (itbl_env pls)
- closure_env' = filterNameEnv keep_name (closure_env pls)
+ itbl_env' = filterNameEnv keep_name itbl_env
+ closure_env' = filterNameEnv keep_name closure_env
- new_pls = pls { itbl_env = itbl_env',
- closure_env = closure_env',
- bcos_loaded = remaining_bcos_loaded,
- objs_loaded = remaining_objs_loaded }
+ !new_pls = pls { itbl_env = itbl_env',
+ closure_env = closure_env',
+ bcos_loaded = remaining_bcos_loaded,
+ objs_loaded = remaining_objs_loaded }
return new_pls
where
diff --git a/compiler/iface/IfaceEnv.hs b/compiler/iface/IfaceEnv.hs
index 00bcaa77f1..864c09ce2e 100644
--- a/compiler/iface/IfaceEnv.hs
+++ b/compiler/iface/IfaceEnv.hs
@@ -1,6 +1,6 @@
-- (c) The University of Glasgow 2002-2006
-{-# LANGUAGE CPP, RankNTypes #-}
+{-# LANGUAGE CPP, RankNTypes, BangPatterns #-}
module IfaceEnv (
newGlobalBinder, newInteractiveBinder,
@@ -129,7 +129,8 @@ newtype NameCacheUpdater
mkNameCacheUpdater :: TcRnIf a b NameCacheUpdater
mkNameCacheUpdater = do { hsc_env <- getTopEnv
- ; return (NCU (updNameCache hsc_env)) }
+ ; let !ncRef = hsc_NC hsc_env
+ ; return (NCU (updNameCache ncRef)) }
updNameCacheTc :: Module -> OccName -> (NameCache -> (NameCache, c))
-> TcRnIf a b c
@@ -151,7 +152,7 @@ updNameCacheIO hsc_env mod occ upd_fn = do {
-- This did happen, with tycon_mod in TcIface.tcIfaceAlt (DataAlt..)
mod `seq` occ `seq` return ()
- ; updNameCache hsc_env upd_fn }
+ ; updNameCache (hsc_NC hsc_env) upd_fn }
{-
diff --git a/compiler/main/DriverPipeline.hs b/compiler/main/DriverPipeline.hs
index 92e3455521..94a0a31887 100644
--- a/compiler/main/DriverPipeline.hs
+++ b/compiler/main/DriverPipeline.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NamedFieldPuns, NondecreasingIndentation #-}
+{-# LANGUAGE CPP, NamedFieldPuns, NondecreasingIndentation, BangPatterns #-}
{-# OPTIONS_GHC -fno-cse #-}
-- -fno-cse is needed for GLOBAL_VAR's to behave properly
@@ -263,7 +263,7 @@ compileOne' m_tc_result mHscMessage
-- imports a _stub.h file that we created here.
current_dir = takeDirectory basename
old_paths = includePaths dflags1
- prevailing_dflags = hsc_dflags hsc_env0
+ !prevailing_dflags = hsc_dflags hsc_env0
dflags =
dflags1 { includePaths = addQuoteInclude old_paths [current_dir]
, log_action = log_action prevailing_dflags }
diff --git a/compiler/main/HscTypes.hs b/compiler/main/HscTypes.hs
index 0ef1487312..0c375f074c 100644
--- a/compiler/main/HscTypes.hs
+++ b/compiler/main/HscTypes.hs
@@ -2620,11 +2620,11 @@ interface file); so we give it 'noSrcLoc' then. Later, when we find
its binding site, we fix it up.
-}
-updNameCache :: HscEnv
+updNameCache :: IORef NameCache
-> (NameCache -> (NameCache, c)) -- The updating function
-> IO c
-updNameCache hsc_env upd_fn
- = atomicModifyIORef' (hsc_NC hsc_env) upd_fn
+updNameCache ncRef upd_fn
+ = atomicModifyIORef' ncRef upd_fn
mkSOName :: Platform -> FilePath -> FilePath
mkSOName platform root
diff --git a/compiler/typecheck/TcRnMonad.hs b/compiler/typecheck/TcRnMonad.hs
index 26f549b3fc..4382467100 100644
--- a/compiler/typecheck/TcRnMonad.hs
+++ b/compiler/typecheck/TcRnMonad.hs
@@ -5,7 +5,8 @@
Functions for working with the typechecker environment (setters, getters...).
-}
-{-# LANGUAGE CPP, ExplicitForAll, FlexibleInstances #-}
+{-# LANGUAGE CPP, ExplicitForAll, FlexibleInstances, BangPatterns #-}
+{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module TcRnMonad(
@@ -432,7 +433,7 @@ updTopEnv upd = updEnv (\ env@(Env { env_top = top }) ->
env { env_top = upd top })
getGblEnv :: TcRnIf gbl lcl gbl
-getGblEnv = do { env <- getEnv; return (env_gbl env) }
+getGblEnv = do { Env{..} <- getEnv; return env_gbl }
updGblEnv :: (gbl -> gbl) -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a
updGblEnv upd = updEnv (\ env@(Env { env_gbl = gbl }) ->
@@ -442,7 +443,7 @@ setGblEnv :: gbl -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a
setGblEnv gbl_env = updEnv (\ env -> env { env_gbl = gbl_env })
getLclEnv :: TcRnIf gbl lcl lcl
-getLclEnv = do { env <- getEnv; return (env_lcl env) }
+getLclEnv = do { Env{..} <- getEnv; return env_lcl }
updLclEnv :: (lcl -> lcl) -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a
updLclEnv upd = updEnv (\ env@(Env { env_lcl = lcl }) ->
@@ -1762,7 +1763,7 @@ initIfaceTcRn :: IfG a -> TcRn a
initIfaceTcRn thing_inside
= do { tcg_env <- getGblEnv
; dflags <- getDynFlags
- ; let mod = tcg_semantic_mod tcg_env
+ ; let !mod = tcg_semantic_mod tcg_env
-- When we are instantiating a signature, we DEFINITELY
-- do not want to knot tie.
is_instantiate = unitIdIsDefinite (thisPackage dflags) &&
diff --git a/compiler/utils/IOEnv.hs b/compiler/utils/IOEnv.hs
index b9210702fa..4640b2b7c2 100644
--- a/compiler/utils/IOEnv.hs
+++ b/compiler/utils/IOEnv.hs
@@ -106,7 +106,7 @@ instance ExceptionMonad (IOEnv a) where
instance ContainsDynFlags env => HasDynFlags (IOEnv env) where
getDynFlags = do env <- getEnv
- return $ extractDynFlags env
+ return $! extractDynFlags env
instance ContainsModule env => HasModule (IOEnv env) where
getModule = do env <- getEnv
diff --git a/ghc/GHCi/UI.hs b/ghc/GHCi/UI.hs
index 15cfcf3362..bcb6d6e38c 100644
--- a/ghc/GHCi/UI.hs
+++ b/ghc/GHCi/UI.hs
@@ -1688,7 +1688,8 @@ loadModule' files = do
-- Grab references to the currently loaded modules so that we can
-- see if they leak.
- leak_indicators <- if gopt Opt_GhciLeakCheck (hsc_dflags hsc_env)
+ let !dflags = hsc_dflags hsc_env
+ leak_indicators <- if gopt Opt_GhciLeakCheck dflags
then liftIO $ getLeakIndicators hsc_env
else return (panic "no leak indicators")
@@ -1700,8 +1701,8 @@ loadModule' files = do
GHC.setTargets targets
success <- doLoadAndCollectInfo False LoadAllTargets
- when (gopt Opt_GhciLeakCheck (hsc_dflags hsc_env)) $
- liftIO $ checkLeakIndicators (hsc_dflags hsc_env) leak_indicators
+ when (gopt Opt_GhciLeakCheck dflags) $
+ liftIO $ checkLeakIndicators dflags leak_indicators
return success
-- | @:add@ command
diff --git a/testsuite/tests/perf/compiler/all.T b/testsuite/tests/perf/compiler/all.T
index 6632231999..eed616b7e9 100644
--- a/testsuite/tests/perf/compiler/all.T
+++ b/testsuite/tests/perf/compiler/all.T
@@ -39,7 +39,7 @@ test('T1969',
# 2013-11-13 17 (x86/Windows, 64bit machine)
# 2015-07-11 21 (x86/Linux, 64bit machine) use +RTS -G1
# 2016-04-06 30 (x86/Linux, 64bit machine)
- (wordsize(64), 78, 20)]),
+ (wordsize(64), 73, 20)]),
# 28 (amd64/Linux)
# 34 (amd64/Linux)
# 2012-09-20 23 (amd64/Linux)
@@ -56,6 +56,7 @@ test('T1969',
# 2017-02-17 83 (amd64/Linux) Type-indexed Typeable
# 2017-03-31 61 (amd64/Linux) Fix memory leak in simplifier
# 2018-01-25 78 (amd64/Linux) Use CoreExpr for EvTerm
+ # 2018-07-10 73 (amd64/Linux) Fix space leaks
compiler_stats_num_field('max_bytes_used',
[(platform('i386-unknown-mingw32'), 5719436, 20),
# 2010-05-17 5717704 (x86/Windows)
@@ -73,7 +74,7 @@ test('T1969',
# 2017-03-24 9261052 (x86/Linux, 64-bit machine)
# 2017-04-06 9418680 (x86/Linux, 64-bit machine)
- (wordsize(64), 22311600, 15)]),
+ (wordsize(64), 19738608, 15)]),
# 2014-09-10 10463640, 10 # post-AMP-update (somewhat stabelish)
# looks like the peak is around ~10M, but we're
# unlikely to GC exactly on the peak.
@@ -90,6 +91,7 @@ test('T1969',
# 2017-03-31 16679176 Fix memory leak in simplifier
# 2017-08-25 19199872 Refactor the Mighty Simplifier
# 2018-02-19 22311600 (amd64/Linux) Unknown
+ # 2018-07-10 19738608 (amd64/Linux) Fix space leaks
compiler_stats_num_field('bytes allocated',
[(platform('i386-unknown-mingw32'), 301784492, 5),
@@ -108,7 +110,7 @@ test('T1969',
# 2015-07-11 288699104 (x86/Linux, 64-bit machine) use +RTS -G1
# 2016-04-06 344730660 (x86/Linux, 64-bit machine)
# 2017-03-24 324586096 (x86/Linux, 64-bit machine)
- (wordsize(64), 659863176, 5)]),
+ (wordsize(64), 670839456, 5)]),
# 2009-11-17 434845560 (amd64/Linux)
# 2009-12-08 459776680 (amd64/Linux)
# 2010-05-17 519377728 (amd64/Linux)
@@ -132,6 +134,7 @@ test('T1969',
# 2017-02-17 831733376 (x86_64/Linux) Type-indexed Typeable
# 2017-02-25 695354904 (x86_64/Linux) Early inlining patch
# 2017-04-21 659863176 (x86_64/Linux) Unknown
+ # 2018-07-10 670839456 (x86_64/Linux) Unknown (just updating)
only_ways(['normal']),
extra_hc_opts('-dcore-lint -static'),