summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Pickering <matthewtpickering@gmail.com>2021-10-14 13:13:12 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-10-20 14:05:23 -0400
commit949d739893a94eb5bdd1c632543ab7eccca08277 (patch)
tree5e2e7765957492472d582d39afcd100847b65105
parentd73131b9315abf39fc2d307b1c59bf8edd1e43ac (diff)
downloadhaskell-949d739893a94eb5bdd1c632543ab7eccca08277.tar.gz
Add note about heap invariants [skip ci]
At the moment the note just covers three important invariants but now there is a place to add more to if we think of them.
-rw-r--r--compiler/GHC/Driver/Make.hs30
-rw-r--r--compiler/GHC/Iface/Load.hs1
2 files changed, 31 insertions, 0 deletions
diff --git a/compiler/GHC/Driver/Make.hs b/compiler/GHC/Driver/Make.hs
index ba611db424..e58c2a435a 100644
--- a/compiler/GHC/Driver/Make.hs
+++ b/compiler/GHC/Driver/Make.hs
@@ -732,6 +732,7 @@ guessOutputFile = modifySession $ \env ->
-- space at the end of the upsweep, because the topmost ModDetails of the
-- old HPT holds on to the entire type environment from the previous
-- compilation.
+-- Note [GHC Heap Invariants]
pruneCache :: [HomeModInfo]
-> [ModSummary]
-> [HomeModInfo]
@@ -1251,6 +1252,7 @@ typecheckLoop hsc_env hmis = do
let new_hsc_env = hscUpdateHPT (const new_hpt) hsc_env
-- Crucial, crucial: initIfaceLoad clears the if_rec_types field.
-- See [KnotVars invariants]
+ -- Note [GHC Heap Invariants]
mds <- initIfaceLoad new_hsc_env $
mapM (typecheckIface . hm_iface) hmis
let new_mods = [ (mn,hmi{ hm_details = details })
@@ -2456,3 +2458,31 @@ data MakeAction = forall a . MakeAction (RunMakeM a) (MVar (Maybe a))
waitMakeAction :: MakeAction -> IO ()
waitMakeAction (MakeAction _ mvar) = () <$ readMVar mvar
+
+{- Note [GHC Heap Invariants]
+
+This note is a general place to explain some of the heap invariants which should
+hold for a program compiled with --make mode. These invariants are all things
+which can be checked easily using ghc-debug.
+
+1. No HomeModInfo are reachable via the EPS.
+ Why? Interfaces are lazily loaded into the EPS and the lazy thunk retains
+ a reference to the entire HscEnv, if we are not careful the HscEnv will
+ contain the HomePackageTable at the time the interface was loaded and
+ it will never be released.
+ Where? dontLeakTheHPT in GHC.Iface.Load
+
+2. No KnotVars are live at the end of upsweep (#20491)
+ Why? KnotVars contains an old stale reference to the TypeEnv for modules
+ which participate in a loop. At the end of a loop all the KnotVars references
+ should be removed by the call to typecheckLoop.
+ Where? typecheckLoop in GHC.Driver.Make.
+
+3. Immediately after a reload, no ModDetails are live.
+ Why? During the upsweep all old ModDetails are replaced with a new ModDetails
+ generated from a ModIface. If we don't clear the ModDetails before the
+ reload takes place then memory usage during the reload is twice as much
+ as it should be as we retain a copy of the ModDetails for too long.
+ Where? pruneCache in GHC.Driver.Make
+
+-}
diff --git a/compiler/GHC/Iface/Load.hs b/compiler/GHC/Iface/Load.hs
index 77db1f22c6..13fd3c1a3e 100644
--- a/compiler/GHC/Iface/Load.hs
+++ b/compiler/GHC/Iface/Load.hs
@@ -629,6 +629,7 @@ We know that none of the interfaces below here can refer to
home-package modules however, so it's safe for the HPT to be empty.
-}
+-- Note [GHC Heap Invariants]
dontLeakTheHPT :: IfL a -> IfL a
dontLeakTheHPT thing_inside = do
env <- getTopEnv