diff options
author | Matthew Pickering <matthewtpickering@gmail.com> | 2021-10-14 13:13:12 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-10-20 14:05:23 -0400 |
commit | 949d739893a94eb5bdd1c632543ab7eccca08277 (patch) | |
tree | 5e2e7765957492472d582d39afcd100847b65105 | |
parent | d73131b9315abf39fc2d307b1c59bf8edd1e43ac (diff) | |
download | haskell-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.hs | 30 | ||||
-rw-r--r-- | compiler/GHC/Iface/Load.hs | 1 |
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 |