diff options
| author | Simon Marlow <marlowsd@gmail.com> | 2018-05-01 16:52:05 +0100 |
|---|---|---|
| committer | Simon Marlow <marlowsd@gmail.com> | 2018-05-17 15:18:20 +0100 |
| commit | f27e4f624fe1270e8027ff0a14f03514f5be31b7 (patch) | |
| tree | eb711910a70958b0ee9bcfca52050b45be10e178 /compiler/iface/LoadIface.hs | |
| parent | 5f15d53a98ad2f26465730d8c3463ccc58f6d94a (diff) | |
| download | haskell-f27e4f624fe1270e8027ff0a14f03514f5be31b7.tar.gz | |
Fix GHCi space leaks (#15111)
Summary:
There were a number of leaks causing previously loaded modules to be
retained after a new `:load`. This fixes enough leaks to get the
tests to pass from D4658.
Test Plan: See new tests in D4658
Reviewers: niteria, bgamari, simonpj, erikd
Subscribers: thomie, carter
GHC Trac Issues: #15111
Differential Revision: https://phabricator.haskell.org/D4659
Diffstat (limited to 'compiler/iface/LoadIface.hs')
| -rw-r--r-- | compiler/iface/LoadIface.hs | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/compiler/iface/LoadIface.hs b/compiler/iface/LoadIface.hs index a380ccf008..8f0e958b48 100644 --- a/compiler/iface/LoadIface.hs +++ b/compiler/iface/LoadIface.hs @@ -6,7 +6,7 @@ Loading interface files -} -{-# LANGUAGE CPP #-} +{-# LANGUAGE CPP, BangPatterns, RecordWildCards, NondecreasingIndentation #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module LoadIface ( -- Importing one thing @@ -443,6 +443,8 @@ loadInterface doc_str mod from in initIfaceLcl (mi_semantic_module iface) loc_doc (mi_boot iface) $ do + dontLeakTheHPT $ do + -- Load the new ModIface into the External Package State -- Even home-package interfaces loaded by loadInterface -- (which only happens in OneShot mode; in Batch/Interactive @@ -514,6 +516,54 @@ loadInterface doc_str mod from ; return (Succeeded final_iface) }}}} + + +-- Note [HPT space leak] (#15111) +-- +-- In IfL, we defer some work until it is demanded using forkM, such +-- as building TyThings from IfaceDecls. These thunks are stored in +-- the ExternalPackageState, and they might never be poked. If we're +-- not careful, these thunks will capture the state of the loaded +-- program when we read an interface file, and retain all that data +-- for ever. +-- +-- Therefore, when loading a package interface file , we use a "clean" +-- version of the HscEnv with all the data about the currently loaded +-- program stripped out. Most of the fields can be panics because +-- we'll never read them, but hsc_HPT needs to be empty because this +-- interface will cause other interfaces to be loaded recursively, and +-- when looking up those interfaces we use the HPT in loadInterface. +-- 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. +-- +dontLeakTheHPT :: IfL a -> IfL a +dontLeakTheHPT thing_inside = do + let + cleanTopEnv HscEnv{..} = + let + -- wrinkle: when we're typechecking in --backpack mode, the + -- instantiation of a signature might reside in the HPT, so + -- this case breaks the assumption that EPS interfaces only + -- refer to other EPS interfaces. We can detect when we're in + -- typechecking-only mode by using hscTarget==HscNothing, and + -- in that case we don't empty the HPT. (admittedly this is + -- a bit of a hack, better suggestions welcome). A number of + -- tests in testsuite/tests/backpack break without this + -- tweak. + !hpt | hscTarget hsc_dflags == HscNothing = hsc_HPT + | otherwise = emptyHomePackageTable + in + HscEnv { hsc_targets = panic "cleanTopEnv: hsc_targets" + , hsc_mod_graph = panic "cleanTopEnv: hsc_mod_graph" + , hsc_IC = panic "cleanTopEnv: hsc_IC" + , hsc_HPT = hpt + , .. } + + updTopEnv cleanTopEnv $ do + !_ <- getTopEnv -- force the updTopEnv + thing_inside + + -- | Returns @True@ if a 'ModIface' comes from an external package. -- In this case, we should NOT load it into the EPS; the entities -- should instead come from the local merged signature interface. |
