Hannes Siebenhandl pushed to branch wip/fendor/linkable-usage at Glasgow Haskell Compiler / GHC
Commits:
23 changed files:
- compiler/GHC/ByteCode/Serialize.hs
- compiler/GHC/Driver/Hooks.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Driver/Pipeline.hs
- compiler/GHC/Driver/Plugins.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Iface/Recomp.hs
- compiler/GHC/Iface/Recomp/Types.hs
- compiler/GHC/Linker/ByteCode.hs
- compiler/GHC/Linker/Deps.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Loader.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Unit/Home/ModInfo.hs
- compiler/GHC/Unit/Module/Deps.hs
- compiler/GHC/Unit/Module/Status.hs
- compiler/GHC/Utils/Binary.hs
- ghc/GHCi/Leak.hs
- + testsuite/tests/bytecode/TLinkable/Makefile
- + testsuite/tests/bytecode/TLinkable/all.T
- + testsuite/tests/bytecode/TLinkable/genSplices
Changes:
| ... | ... | @@ -14,6 +14,7 @@ module GHC.ByteCode.Serialize |
| 14 | 14 | , InterpreterLibraryContents(..)
|
| 15 | 15 | , writeBytecodeLib
|
| 16 | 16 | , readBytecodeLib
|
| 17 | + , fingerprintModuleByteCodeContents
|
|
| 17 | 18 | , decodeOnDiskModuleByteCode
|
| 18 | 19 | , decodeOnDiskBytecodeLib
|
| 19 | 20 | )
|
| ... | ... | @@ -48,6 +49,7 @@ import GHC.Utils.Logger |
| 48 | 49 | import GHC.Linker.Types
|
| 49 | 50 | import System.IO.Unsafe (unsafeInterleaveIO)
|
| 50 | 51 | import GHC.Utils.Outputable
|
| 52 | +import GHC.Utils.Fingerprint (Fingerprint, fingerprintByteString)
|
|
| 51 | 53 | |
| 52 | 54 | {- Note [Overview of persistent bytecode]
|
| 53 | 55 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -94,6 +96,7 @@ See Note [Recompilation avoidance with bytecode objects] |
| 94 | 96 | -- contained by 'ModuleByteCode' are stored in-memory rather than as file paths to
|
| 95 | 97 | -- temporary files.
|
| 96 | 98 | data OnDiskModuleByteCode = OnDiskModuleByteCode { odgbc_module :: Module
|
| 99 | + , odgbc_hash :: Fingerprint
|
|
| 97 | 100 | , odgbc_compiled_byte_code :: CompiledByteCode
|
| 98 | 101 | , odgbc_foreign :: [ByteString] -- ^ Contents of object files
|
| 99 | 102 | }
|
| ... | ... | @@ -154,7 +157,6 @@ instance Binary OnDiskBytecodeLib where |
| 154 | 157 | put_ bh bytecodeLibForeign
|
| 155 | 158 | |
| 156 | 159 | |
| 157 | - |
|
| 158 | 160 | writeBytecodeLib :: BytecodeLib -> FilePath -> IO ()
|
| 159 | 161 | writeBytecodeLib lib path = do
|
| 160 | 162 | odbco <- encodeBytecodeLib lib
|
| ... | ... | @@ -174,12 +176,14 @@ readBytecodeLib hsc_env path = do |
| 174 | 176 | instance Binary OnDiskModuleByteCode where
|
| 175 | 177 | get bh = do
|
| 176 | 178 | odgbc_module <- get bh
|
| 179 | + odgbc_hash <- get bh
|
|
| 177 | 180 | odgbc_compiled_byte_code <- get bh
|
| 178 | 181 | odgbc_foreign <- get bh
|
| 179 | 182 | pure OnDiskModuleByteCode {..}
|
| 180 | 183 | |
| 181 | 184 | put_ bh OnDiskModuleByteCode {..} = do
|
| 182 | 185 | put_ bh odgbc_module
|
| 186 | + put_ bh odgbc_hash
|
|
| 183 | 187 | put_ bh odgbc_compiled_byte_code
|
| 184 | 188 | put_ bh odgbc_foreign
|
| 185 | 189 | |
| ... | ... | @@ -197,7 +201,8 @@ decodeOnDiskModuleByteCode hsc_env odbco = do |
| 197 | 201 | pure $ ModuleByteCode {
|
| 198 | 202 | gbc_module = odgbc_module odbco,
|
| 199 | 203 | gbc_compiled_byte_code = odgbc_compiled_byte_code odbco,
|
| 200 | - gbc_foreign_files = foreign_files
|
|
| 204 | + gbc_foreign_files = foreign_files,
|
|
| 205 | + gbc_hash = odgbc_hash odbco
|
|
| 201 | 206 | }
|
| 202 | 207 | |
| 203 | 208 | decodeOnDiskBytecodeLib :: HscEnv -> OnDiskBytecodeLib -> IO BytecodeLib
|
| ... | ... | @@ -256,7 +261,8 @@ encodeOnDiskModuleByteCode bco = do |
| 256 | 261 | pure $ OnDiskModuleByteCode {
|
| 257 | 262 | odgbc_module = gbc_module bco,
|
| 258 | 263 | odgbc_compiled_byte_code = gbc_compiled_byte_code bco,
|
| 259 | - odgbc_foreign = foreign_contents
|
|
| 264 | + odgbc_foreign = foreign_contents,
|
|
| 265 | + odgbc_hash = gbc_hash bco
|
|
| 260 | 266 | }
|
| 261 | 267 | |
| 262 | 268 | -- | Read a 'ModuleByteCode' from a file.
|
| ... | ... | @@ -281,6 +287,15 @@ writeBinByteCode f cbc = do |
| 281 | 287 | putWithUserData QuietBinIFace NormalCompression bh odbco
|
| 282 | 288 | writeBinMem bh f
|
| 283 | 289 | |
| 290 | +fingerprintModuleByteCodeContents :: Module -> CompiledByteCode -> [FilePath] -> IO Fingerprint
|
|
| 291 | +fingerprintModuleByteCodeContents modl cbc foreign_files = do
|
|
| 292 | + bh' <- openBinMem (1024 * 1024)
|
|
| 293 | + bh <- addBinNameWriter bh'
|
|
| 294 | + foreign_contents <- readObjectFiles foreign_files
|
|
| 295 | + putWithUserData QuietBinIFace NormalCompression bh
|
|
| 296 | + (modl, cbc, foreign_contents)
|
|
| 297 | + withBinBuffer bh (pure . fingerprintByteString)
|
|
| 298 | + |
|
| 284 | 299 | instance Binary CompiledByteCode where
|
| 285 | 300 | get bh = do
|
| 286 | 301 | bc_bcos <- get bh
|
| ... | ... | @@ -137,7 +137,7 @@ data Hooks = Hooks |
| 137 | 137 | , tcForeignExportsHook :: !(Maybe ([LForeignDecl GhcRn]
|
| 138 | 138 | -> TcM (LHsBinds GhcTc, [LForeignDecl GhcTc], Bag GlobalRdrElt)))
|
| 139 | 139 | , hscFrontendHook :: !(Maybe (ModSummary -> Hsc FrontendResult))
|
| 140 | - , hscCompileCoreExprHook :: !(Maybe (HscEnv -> SrcSpan -> CoreExpr -> IO (ForeignHValue, [Linkable], PkgsLoaded)))
|
|
| 140 | + , hscCompileCoreExprHook :: !(Maybe (HscEnv -> SrcSpan -> CoreExpr -> IO (ForeignHValue, [LinkableWithUsage], PkgsLoaded)))
|
|
| 141 | 141 | , ghcPrimIfaceHook :: !(Maybe ModIface)
|
| 142 | 142 | , runPhaseHook :: !(Maybe PhaseHook)
|
| 143 | 143 | , runMetaHook :: !(Maybe (MetaHook TcM))
|
| ... | ... | @@ -145,7 +145,7 @@ data Hooks = Hooks |
| 145 | 145 | -> HomePackageTable -> IO SuccessFlag))
|
| 146 | 146 | , runRnSpliceHook :: !(Maybe (HsUntypedSplice GhcRn -> RnM (HsUntypedSplice GhcRn)))
|
| 147 | 147 | , getValueSafelyHook :: !(Maybe (HscEnv -> Name -> Type
|
| 148 | - -> IO (Either Type (HValue, [Linkable], PkgsLoaded))))
|
|
| 148 | + -> IO (Either Type (HValue, [LinkableWithUsage], PkgsLoaded))))
|
|
| 149 | 149 | , createIservProcessHook :: !(Maybe (CreateProcess -> IO ProcessHandle))
|
| 150 | 150 | , stgToCmmHook :: !(Maybe (StgToCmmConfig -> InfoTableProvMap -> [TyCon] -> CollectedCCs
|
| 151 | 151 | -> [CgStgTopBinding] -> CgStream CmmGroup ModuleLFInfos))
|
| ... | ... | @@ -866,7 +866,7 @@ hscRecompStatus |
| 866 | 866 | | otherwise -> do
|
| 867 | 867 | -- Check the status of all the linkable types we might need.
|
| 868 | 868 | -- 1. The in-memory linkable we had at hand.
|
| 869 | - bc_in_memory_linkable <- checkByteCodeInMemory hsc_env mod_summary (homeMod_bytecode old_linkable)
|
|
| 869 | + bc_in_memory_linkable <- checkByteCodeInMemory hsc_env mod_summary (homeModLinkableByteCode old_linkable)
|
|
| 870 | 870 | -- 2. The bytecode object file
|
| 871 | 871 | bc_obj_linkable <- checkByteCodeFromObject hsc_env mod_summary
|
| 872 | 872 | -- 3. Bytecode from an interface's whole core bindings.
|
| ... | ... | @@ -1098,7 +1098,7 @@ loadIfaceByteCodeLazy :: |
| 1098 | 1098 | ModIface ->
|
| 1099 | 1099 | ModLocation ->
|
| 1100 | 1100 | TypeEnv ->
|
| 1101 | - IO (Maybe Linkable)
|
|
| 1101 | + IO (Maybe (LinkableWith ModuleByteCode))
|
|
| 1102 | 1102 | loadIfaceByteCodeLazy hsc_env iface location type_env =
|
| 1103 | 1103 | case iface_core_bindings iface location of
|
| 1104 | 1104 | Nothing -> return Nothing
|
| ... | ... | @@ -1106,8 +1106,9 @@ loadIfaceByteCodeLazy hsc_env iface location type_env = |
| 1106 | 1106 | Just <$> compile wcb
|
| 1107 | 1107 | where
|
| 1108 | 1108 | compile decls = do
|
| 1109 | - bco <- unsafeInterleaveIO $ compileWholeCoreBindings hsc_env type_env decls
|
|
| 1110 | - linkable $ NE.singleton (DotGBC bco)
|
|
| 1109 | + bco <- unsafeInterleaveIO $ do
|
|
| 1110 | + compileWholeCoreBindings hsc_env type_env decls
|
|
| 1111 | + linkable bco
|
|
| 1111 | 1112 | |
| 1112 | 1113 | linkable parts = do
|
| 1113 | 1114 | if_time <- modificationTimeIfExists (ml_hi_file_ospath location)
|
| ... | ... | @@ -1148,14 +1149,14 @@ initWholeCoreBindings hsc_env iface details (RecompLinkables bc o) = do |
| 1148 | 1149 | where
|
| 1149 | 1150 | type_env = md_types details
|
| 1150 | 1151 | |
| 1151 | - go :: RecompBytecodeLinkable -> IO (Maybe Linkable)
|
|
| 1152 | + go :: RecompBytecodeLinkable -> IO (Maybe (LinkableWith ModuleByteCode))
|
|
| 1152 | 1153 | go (NormalLinkable l) = pure l
|
| 1153 | 1154 | go (WholeCoreBindingsLinkable wcbl) =
|
| 1154 | 1155 | fmap Just $ for wcbl $ \wcb -> do
|
| 1155 | 1156 | add_iface_to_hpt iface details hsc_env
|
| 1156 | - bco <- unsafeInterleaveIO $
|
|
| 1157 | - compileWholeCoreBindings hsc_env type_env wcb
|
|
| 1158 | - pure $ NE.singleton (DotGBC bco)
|
|
| 1157 | + bco <- unsafeInterleaveIO $ do
|
|
| 1158 | + compileWholeCoreBindings hsc_env type_env wcb
|
|
| 1159 | + pure bco
|
|
| 1159 | 1160 | |
| 1160 | 1161 | -- | Hydrate interface Core bindings and compile them to bytecode.
|
| 1161 | 1162 | --
|
| ... | ... | @@ -2232,20 +2233,21 @@ make user's opt into writing the files. |
| 2232 | 2233 | -}
|
| 2233 | 2234 | |
| 2234 | 2235 | -- | Generate a 'ModuleByteCode' and write it to disk if `-fwrite-byte-code` is enabled.
|
| 2235 | -generateAndWriteByteCodeLinkable :: HscEnv -> CgInteractiveGuts -> ModLocation -> IO Linkable
|
|
| 2236 | +generateAndWriteByteCodeLinkable :: HscEnv -> CgInteractiveGuts -> ModLocation -> IO (LinkableWith ModuleByteCode)
|
|
| 2236 | 2237 | generateAndWriteByteCodeLinkable hsc_env cgguts mod_location = do
|
| 2237 | 2238 | bco_object <- generateAndWriteByteCode hsc_env cgguts mod_location
|
| 2238 | 2239 | -- Either, get the same time as the .gbc file if it exists, or just the current time.
|
| 2239 | 2240 | -- It's important the time of the linkable matches the time of the .gbc file for recompilation
|
| 2240 | 2241 | -- checking.
|
| 2241 | 2242 | bco_time <- maybe getCurrentTime pure =<< modificationTimeIfExists (ml_bytecode_file_ospath mod_location)
|
| 2242 | - return $ mkModuleByteCodeLinkable bco_time bco_object
|
|
| 2243 | + return $ mkOnlyModuleByteCodeLinkable bco_time bco_object
|
|
| 2243 | 2244 | |
| 2244 | 2245 | mkModuleByteCode :: HscEnv -> Module -> ModLocation -> CgInteractiveGuts -> IO ModuleByteCode
|
| 2245 | 2246 | mkModuleByteCode hsc_env mod mod_location cgguts = do
|
| 2246 | 2247 | bcos <- hscGenerateByteCode hsc_env cgguts mod_location
|
| 2247 | 2248 | objs <- outputAndCompileForeign hsc_env mod mod_location (cgi_foreign_files cgguts) (cgi_foreign cgguts)
|
| 2248 | - return $! ModuleByteCode mod bcos objs
|
|
| 2249 | + !bcos_hash <- fingerprintModuleByteCodeContents mod bcos objs
|
|
| 2250 | + return $! ModuleByteCode mod bcos objs bcos_hash
|
|
| 2249 | 2251 | |
| 2250 | 2252 | -- | Generate a fresh 'ModuleByteCode' for a given module but do not write it to disk.
|
| 2251 | 2253 | generateFreshByteCodeLinkable :: HscEnv
|
| ... | ... | @@ -2767,13 +2769,13 @@ hscTidy hsc_env guts = do |
| 2767 | 2769 | %* *
|
| 2768 | 2770 | %********************************************************************* -}
|
| 2769 | 2771 | |
| 2770 | -hscCompileCoreExpr :: HscEnv -> SrcSpan -> CoreExpr -> IO (ForeignHValue, [Linkable], PkgsLoaded)
|
|
| 2772 | +hscCompileCoreExpr :: HscEnv -> SrcSpan -> CoreExpr -> IO (ForeignHValue, [LinkableWithUsage], PkgsLoaded)
|
|
| 2771 | 2773 | hscCompileCoreExpr hsc_env loc expr =
|
| 2772 | 2774 | case hscCompileCoreExprHook (hsc_hooks hsc_env) of
|
| 2773 | 2775 | Nothing -> hscCompileCoreExpr' hsc_env loc expr
|
| 2774 | 2776 | Just h -> h hsc_env loc expr
|
| 2775 | 2777 | |
| 2776 | -hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO (ForeignHValue, [Linkable], PkgsLoaded)
|
|
| 2778 | +hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO (ForeignHValue, [LinkableWithUsage], PkgsLoaded)
|
|
| 2777 | 2779 | hscCompileCoreExpr' hsc_env srcspan ds_expr = do
|
| 2778 | 2780 | {- Simplify it -}
|
| 2779 | 2781 | -- Question: should we call SimpleOpt.simpleOptExpr here instead?
|
| ... | ... | @@ -2859,8 +2861,10 @@ hscCompileCoreExpr' hsc_env srcspan ds_expr = do |
| 2859 | 2861 | |
| 2860 | 2862 | {- load it -}
|
| 2861 | 2863 | bco_time <- getCurrentTime
|
| 2864 | + !bco_hash <- fingerprintModuleByteCodeContents this_mod bcos []
|
|
| 2865 | + let mbc = ModuleByteCode this_mod bcos [] bco_hash
|
|
| 2862 | 2866 | (mods_needed, units_needed) <- loadDecls interp hsc_env srcspan $
|
| 2863 | - Linkable bco_time this_mod $ NE.singleton $ DotGBC (ModuleByteCode this_mod bcos [])
|
|
| 2867 | + Linkable bco_time this_mod $ NE.singleton (DotGBC mbc)
|
|
| 2864 | 2868 | -- Get the foreign reference to the name we should have just loaded.
|
| 2865 | 2869 | mhvs <- lookupFromLoadedEnv interp (idName binding_id)
|
| 2866 | 2870 | {- Get the HValue for the root -}
|
| ... | ... | @@ -2876,7 +2880,7 @@ jsCodeGen |
| 2876 | 2880 | -> Module
|
| 2877 | 2881 | -> [(CgStgTopBinding,IdSet)]
|
| 2878 | 2882 | -> Id
|
| 2879 | - -> IO (ForeignHValue, [Linkable], PkgsLoaded)
|
|
| 2883 | + -> IO (ForeignHValue, [LinkableWithUsage], PkgsLoaded)
|
|
| 2880 | 2884 | jsCodeGen hsc_env srcspan i this_mod stg_binds_with_deps binding_id = do
|
| 2881 | 2885 | let logger = hsc_logger hsc_env
|
| 2882 | 2886 | tmpfs = hsc_tmpfs hsc_env
|
| ... | ... | @@ -430,7 +430,7 @@ link' hsc_env batch_attempt_linking mHscMessager hpt |
| 430 | 430 | let obj_files = concatMap linkableObjs linkables
|
| 431 | 431 | in action obj_files
|
| 432 | 432 | linkBytecodeLinkable action =
|
| 433 | - checkLinkablesUpToDate hsc_env mHscMessager home_mods pkg_deps staticLink checkBytecodeLibraryLinkingNeeded homeMod_bytecode $ \linkables ->
|
|
| 433 | + checkLinkablesUpToDate hsc_env mHscMessager home_mods pkg_deps staticLink checkBytecodeLibraryLinkingNeeded homeModLinkableByteCode $ \linkables ->
|
|
| 434 | 434 | let bytecode = concatMap linkableModuleByteCodes linkables
|
| 435 | 435 | in action bytecode
|
| 436 | 436 |
| ... | ... | @@ -342,7 +342,7 @@ data Plugins = Plugins |
| 342 | 342 | -- The purpose of this field is to cache the plugins so they
|
| 343 | 343 | -- don't have to be loaded each time they are needed. See
|
| 344 | 344 | -- 'GHC.Runtime.Loader.initializePlugins'.
|
| 345 | - , loadedPluginDeps :: !([Linkable], PkgsLoaded)
|
|
| 345 | + , loadedPluginDeps :: !([LinkableWithUsage], PkgsLoaded)
|
|
| 346 | 346 | -- ^ The object files required by the loaded plugins
|
| 347 | 347 | -- See Note [Plugin dependencies]
|
| 348 | 348 | }
|
| ... | ... | @@ -7,8 +7,6 @@ module GHC.HsToCore.Usage ( |
| 7 | 7 | |
| 8 | 8 | import GHC.Prelude
|
| 9 | 9 | |
| 10 | -import GHC.Driver.Env
|
|
| 11 | - |
|
| 12 | 10 | import GHC.Tc.Types
|
| 13 | 11 | |
| 14 | 12 | import GHC.Iface.Load
|
| ... | ... | @@ -27,7 +25,6 @@ import GHC.Types.Unique.Set |
| 27 | 25 | |
| 28 | 26 | import GHC.Unit
|
| 29 | 27 | import GHC.Unit.Env
|
| 30 | -import GHC.Unit.External
|
|
| 31 | 28 | import GHC.Unit.Module.Imported
|
| 32 | 29 | import GHC.Unit.Module.ModIface
|
| 33 | 30 | import GHC.Unit.Module.Deps
|
| ... | ... | @@ -35,18 +32,17 @@ import GHC.Unit.Module.Deps |
| 35 | 32 | import GHC.Data.Maybe
|
| 36 | 33 | import GHC.Data.FastString
|
| 37 | 34 | |
| 38 | -import Data.IORef
|
|
| 39 | 35 | import Data.List (sortBy)
|
| 40 | 36 | import Data.Map (Map)
|
| 41 | 37 | import qualified Data.Map as Map
|
| 42 | 38 | import qualified Data.Set as Set
|
| 43 | -import qualified Data.List.NonEmpty as NE
|
|
| 44 | 39 | |
| 45 | 40 | import GHC.Linker.Types
|
| 46 | 41 | import GHC.Unit.Finder
|
| 47 | 42 | import GHC.Types.Unique.DFM
|
| 48 | 43 | import GHC.Driver.Plugins
|
| 49 | 44 | import qualified GHC.Unit.Home.Graph as HUG
|
| 45 | +import qualified Data.List.NonEmpty as NE
|
|
| 50 | 46 | |
| 51 | 47 | {- Note [Module self-dependency]
|
| 52 | 48 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -75,19 +71,17 @@ data UsageConfig = UsageConfig |
| 75 | 71 | |
| 76 | 72 | mkUsageInfo :: UsageConfig -> Plugins -> FinderCache -> UnitEnv
|
| 77 | 73 | -> Module -> ImportedMods -> [ImportUserSpec] -> NameSet
|
| 78 | - -> [FilePath] -> [FilePath] -> [(Module, Fingerprint)] -> [Linkable] -> PkgsLoaded
|
|
| 74 | + -> [FilePath] -> [FilePath] -> [(Module, Fingerprint)] -> [LinkableWithUsage] -> PkgsLoaded
|
|
| 79 | 75 | -> IfG [Usage]
|
| 80 | 76 | mkUsageInfo uc plugins fc unit_env
|
| 81 | 77 | this_mod dir_imp_mods imp_decls used_names
|
| 82 | 78 | dependent_files dependent_dirs merged needed_links needed_pkgs
|
| 83 | 79 | = do
|
| 84 | - eps <- liftIO $ readIORef (euc_eps (ue_eps unit_env))
|
|
| 85 | 80 | file_hashes <- liftIO $ mapM getFileHash dependent_files
|
| 86 | 81 | dirs_hashes <- liftIO $ mapM getDirHash dependent_dirs
|
| 87 | 82 | let hu = ue_unsafeHomeUnit unit_env
|
| 88 | - hug = ue_home_unit_graph unit_env
|
|
| 89 | 83 | -- Dependencies on object files due to TH and plugins
|
| 90 | - object_usages <- liftIO $ mkObjectUsage (eps_PIT eps) plugins fc hug needed_links needed_pkgs
|
|
| 84 | + object_usages <- liftIO $ mkObjectUsage plugins fc needed_links needed_pkgs
|
|
| 91 | 85 | let all_home_ids = HUG.allUnits (ue_home_unit_graph unit_env)
|
| 92 | 86 | mod_usages <- mk_mod_usage_info uc hu all_home_ids this_mod
|
| 93 | 87 | dir_imp_mods imp_decls used_names
|
| ... | ... | @@ -190,31 +184,31 @@ for a module or not. This is similar to how the recompilation checking for the l |
| 190 | 184 | |
| 191 | 185 | -- | Find object files corresponding to the transitive closure of given home
|
| 192 | 186 | -- modules and direct object files for pkg dependencies
|
| 193 | -mkObjectUsage :: PackageIfaceTable -> Plugins -> FinderCache -> HomeUnitGraph-> [Linkable] -> PkgsLoaded -> IO [Usage]
|
|
| 194 | -mkObjectUsage pit plugins fc hug th_links_needed th_pkgs_needed = do
|
|
| 195 | - let ls = ordNubOn linkableModule (th_links_needed ++ plugins_links_needed)
|
|
| 187 | +mkObjectUsage :: Plugins -> FinderCache -> [LinkableWithUsage] -> PkgsLoaded -> IO [Usage]
|
|
| 188 | +mkObjectUsage plugins fc th_links_needed th_pkgs_needed = do
|
|
| 189 | + let ls = th_links_needed ++ plugins_links_needed
|
|
| 196 | 190 | ds = concatMap loaded_pkg_hs_objs $ eltsUDFM (plusUDFM th_pkgs_needed plugin_pkgs_needed) -- TODO possibly record loaded_pkg_non_hs_objs as well
|
| 197 | 191 | (plugins_links_needed, plugin_pkgs_needed) = loadedPluginDeps plugins
|
| 198 | 192 | concat <$> sequence (map linkableToUsage ls ++ map librarySpecToUsage ds)
|
| 199 | 193 | where
|
| 200 | - linkableToUsage (Linkable _ m uls) = mapM (partToUsage m) (NE.toList uls)
|
|
| 201 | - |
|
| 202 | - msg m = moduleNameString (moduleName m) ++ "[TH] changed"
|
|
| 194 | + linkableToUsage :: LinkableWithUsage -> IO [Usage]
|
|
| 195 | + linkableToUsage (Linkable _ _m parts) = traverse partToUsage (NE.toList parts)
|
|
| 196 | + |
|
| 197 | + partToUsage link_usage =
|
|
| 198 | + case link_usage of
|
|
| 199 | + FileLinkableUsage{flu_file, flu_message} -> do
|
|
| 200 | + fing flu_message flu_file
|
|
| 201 | + |
|
| 202 | + ByteCodeLinkableUsage{bclu_module, bclu_hash} ->
|
|
| 203 | + pure $
|
|
| 204 | + UsageHomeModuleBytecode
|
|
| 205 | + { usg_mod_name = moduleName bclu_module
|
|
| 206 | + , usg_unit_id = toUnitId $ moduleUnit bclu_module
|
|
| 207 | + , usg_bytecode_hash = bclu_hash
|
|
| 208 | + }
|
|
| 203 | 209 | |
| 204 | 210 | fing mmsg fn = UsageFile (mkFastString fn) <$> lookupFileCache fc fn <*> pure mmsg
|
| 205 | 211 | |
| 206 | - partToUsage m part =
|
|
| 207 | - case linkablePartPath part of
|
|
| 208 | - Just fn -> fing (Just (msg m)) fn
|
|
| 209 | - Nothing -> do
|
|
| 210 | - -- This should only happen for home package things but oneshot puts
|
|
| 211 | - -- home package ifaces in the PIT.
|
|
| 212 | - miface <- lookupIfaceByModule hug pit m
|
|
| 213 | - case miface of
|
|
| 214 | - Nothing -> pprPanic "linkableToUsage" (ppr m)
|
|
| 215 | - Just iface ->
|
|
| 216 | - return $ UsageHomeModuleInterface (moduleName m) (toUnitId $ moduleUnit m) (mi_iface_hash iface)
|
|
| 217 | - |
|
| 218 | 212 | librarySpecToUsage :: LibrarySpec -> IO [Usage]
|
| 219 | 213 | librarySpecToUsage (Objects os) = traverse (fing Nothing) os
|
| 220 | 214 | librarySpecToUsage (Archive fn) = traverse (fing Nothing) [fn]
|
| ... | ... | @@ -88,6 +88,10 @@ import GHC.Iface.Errors.Ppr |
| 88 | 88 | import Data.Functor
|
| 89 | 89 | import Data.Bifunctor (first)
|
| 90 | 90 | import GHC.Types.PkgQual
|
| 91 | +import GHC.ByteCode.Serialize (ModuleByteCode, gbc_hash)
|
|
| 92 | +import GHC.Unit.Home.Graph (lookupHugByModule)
|
|
| 93 | +import GHC.Unit.Home.ModInfo (HomeModLinkable(..), HomeModInfo (..))
|
|
| 94 | +import GHC.Linker.Types (linkableParts)
|
|
| 91 | 95 | |
| 92 | 96 | {-
|
| 93 | 97 | -----------------------------------------------
|
| ... | ... | @@ -190,6 +194,7 @@ data RecompReason |
| 190 | 194 | | ModuleAdded (ImportLevel, UnitId, ModuleName)
|
| 191 | 195 | | ModuleChangedRaw ModuleName
|
| 192 | 196 | | ModuleChangedIface ModuleName
|
| 197 | + | ModuleChangedBytecode ModuleName
|
|
| 193 | 198 | | FileChanged FilePath
|
| 194 | 199 | | DirChanged FilePath
|
| 195 | 200 | | CustomReason String
|
| ... | ... | @@ -224,7 +229,8 @@ instance Outputable RecompReason where |
| 224 | 229 | SigsMergeChanged -> text "Signatures to merge in changed"
|
| 225 | 230 | ModuleChanged m -> ppr m <+> text "changed"
|
| 226 | 231 | ModuleChangedRaw m -> ppr m <+> text "changed (raw)"
|
| 227 | - ModuleChangedIface m -> ppr m <+> text "changed (interface)"
|
|
| 232 | + ModuleChangedIface m -> ppr m <+> text "changed (bytecode)"
|
|
| 233 | + ModuleChangedBytecode m -> ppr m <+> text "changed (interface)"
|
|
| 228 | 234 | ModuleRemoved (_st, _uid, m) -> ppr m <+> text "removed"
|
| 229 | 235 | ModuleAdded (_st, _uid, m) -> ppr m <+> text "added"
|
| 230 | 236 | FileChanged fp -> text fp <+> text "changed"
|
| ... | ... | @@ -718,6 +724,15 @@ needInterface mod continue |
| 718 | 724 | Nothing -> return $ NeedsRecompile MustCompile
|
| 719 | 725 | Just iface -> liftIO $ continue iface
|
| 720 | 726 | |
| 727 | +needBytecode :: Module -> (ModuleByteCode -> IO RecompileRequired)
|
|
| 728 | + -> IfG RecompileRequired
|
|
| 729 | +needBytecode mod continue
|
|
| 730 | + = do
|
|
| 731 | + mb_recomp <- tryGetBytecode mod
|
|
| 732 | + case mb_recomp of
|
|
| 733 | + Nothing -> return $ NeedsRecompile MustCompile
|
|
| 734 | + Just mbc -> liftIO $ continue mbc
|
|
| 735 | + |
|
| 721 | 736 | tryGetModIface :: String -> Module -> IfG (Maybe ModIface)
|
| 722 | 737 | tryGetModIface doc_msg mod
|
| 723 | 738 | = do -- Load the imported interface if possible
|
| ... | ... | @@ -739,6 +754,27 @@ tryGetModIface doc_msg mod |
| 739 | 754 | -- import and it's been deleted
|
| 740 | 755 | Succeeded iface -> pure $ Just iface
|
| 741 | 756 | |
| 757 | +tryGetBytecode :: Module -> IfG (Maybe ModuleByteCode)
|
|
| 758 | +tryGetBytecode mod
|
|
| 759 | + = do -- Load the imported bytecode if possible
|
|
| 760 | + logger <- getLogger
|
|
| 761 | + liftIO $ trace_hi_diffs logger (text "Checking bytecode hash for module" <+> ppr mod <+> ppr (moduleUnit mod))
|
|
| 762 | + |
|
| 763 | + mb_module_bytecode <- do
|
|
| 764 | + env <- getTopEnv
|
|
| 765 | + liftIO (lookupHugByModule mod (hsc_HUG env)) >>= \ case
|
|
| 766 | + Nothing -> pure Nothing
|
|
| 767 | + Just hmi ->
|
|
| 768 | + case homeMod_bytecode (hm_linkable hmi) of
|
|
| 769 | + Nothing -> pure Nothing
|
|
| 770 | + Just gbc_linkable -> pure $ Just $ linkableParts gbc_linkable
|
|
| 771 | + |
|
| 772 | + case mb_module_bytecode of
|
|
| 773 | + Nothing -> do
|
|
| 774 | + liftIO $ trace_hi_diffs logger (sep [text "Couldn't find bytecode for module", ppr mod])
|
|
| 775 | + return Nothing
|
|
| 776 | + Just module_bytecode -> pure $ Just module_bytecode
|
|
| 777 | + |
|
| 742 | 778 | -- | Given the usage information extracted from the old
|
| 743 | 779 | -- M.hi file for the module being compiled, figure out
|
| 744 | 780 | -- whether M needs to be recompiled.
|
| ... | ... | @@ -760,14 +796,14 @@ checkModUsage _ UsageMergedRequirement{ usg_mod = mod, usg_mod_hash = old_mod_ha |
| 760 | 796 | needInterface mod $ \iface -> do
|
| 761 | 797 | let reason = ModuleChangedRaw (moduleName mod)
|
| 762 | 798 | checkModuleFingerprint logger reason old_mod_hash (mi_mod_hash iface)
|
| 763 | -checkModUsage _ UsageHomeModuleInterface{ usg_mod_name = mod_name
|
|
| 799 | +checkModUsage _ UsageHomeModuleBytecode{ usg_mod_name = mod_name
|
|
| 764 | 800 | , usg_unit_id = uid
|
| 765 | - , usg_iface_hash = old_mod_hash } = do
|
|
| 801 | + , usg_bytecode_hash = old_bytecode_hash } = do
|
|
| 766 | 802 | let mod = mkModule (RealUnit (Definite uid)) mod_name
|
| 767 | 803 | logger <- getLogger
|
| 768 | - needInterface mod $ \iface -> do
|
|
| 769 | - let reason = ModuleChangedIface mod_name
|
|
| 770 | - checkIfaceFingerprint logger reason old_mod_hash (mi_iface_hash iface)
|
|
| 804 | + needBytecode mod $ \cbc -> do
|
|
| 805 | + let reason = ModuleChangedBytecode mod_name
|
|
| 806 | + checkBytecodeFingerprint logger reason old_bytecode_hash (gbc_hash cbc)
|
|
| 771 | 807 | |
| 772 | 808 | checkModUsage _ UsageHomeModule{
|
| 773 | 809 | usg_mod_name = mod_name,
|
| ... | ... | @@ -1032,19 +1068,18 @@ checkModuleFingerprint logger reason old_mod_hash new_mod_hash |
| 1032 | 1068 | = out_of_date_hash logger reason (text " Module fingerprint has changed")
|
| 1033 | 1069 | old_mod_hash new_mod_hash
|
| 1034 | 1070 | |
| 1035 | -checkIfaceFingerprint
|
|
| 1071 | +checkBytecodeFingerprint
|
|
| 1036 | 1072 | :: Logger
|
| 1037 | 1073 | -> RecompReason
|
| 1038 | 1074 | -> Fingerprint
|
| 1039 | 1075 | -> Fingerprint
|
| 1040 | 1076 | -> IO RecompileRequired
|
| 1041 | -checkIfaceFingerprint logger reason old_mod_hash new_mod_hash
|
|
| 1042 | - | new_mod_hash == old_mod_hash
|
|
| 1043 | - = up_to_date logger (text "Iface fingerprint unchanged")
|
|
| 1044 | - |
|
| 1077 | +checkBytecodeFingerprint logger reason old_bytecode_hash new_bytecode_hash
|
|
| 1078 | + | old_bytecode_hash == new_bytecode_hash
|
|
| 1079 | + = up_to_date logger (text "Bytecode fingerprint unchanged")
|
|
| 1045 | 1080 | | otherwise
|
| 1046 | - = out_of_date_hash logger reason (text " Iface fingerprint has changed")
|
|
| 1047 | - old_mod_hash new_mod_hash
|
|
| 1081 | + = out_of_date_hash logger reason (text " Bytecode fingerprint has changed")
|
|
| 1082 | + old_bytecode_hash new_bytecode_hash
|
|
| 1048 | 1083 | |
| 1049 | 1084 | ------------------------
|
| 1050 | 1085 | checkEntityUsage :: Logger
|
| ... | ... | @@ -146,10 +146,10 @@ pprUsage usage@UsageDirectory{} |
| 146 | 146 | ppr (usg_dir_hash usage)]
|
| 147 | 147 | pprUsage usage@UsageMergedRequirement{}
|
| 148 | 148 | = hsep [text "merged", ppr (usg_mod usage), ppr (usg_mod_hash usage)]
|
| 149 | -pprUsage usage@UsageHomeModuleInterface{}
|
|
| 150 | - = hsep [text "implementation", ppr (usg_mod_name usage)
|
|
| 149 | +pprUsage usage@UsageHomeModuleBytecode{}
|
|
| 150 | + = hsep [text "Bytecode", ppr (usg_mod_name usage)
|
|
| 151 | 151 | , ppr (usg_unit_id usage)
|
| 152 | - , ppr (usg_iface_hash usage)]
|
|
| 152 | + , ppr (usg_bytecode_hash usage)]
|
|
| 153 | 153 | |
| 154 | 154 | pprUsageImport :: Outputable mod => mod -> Fingerprint -> IsSafeImport -> SDoc
|
| 155 | 155 | pprUsageImport mod hash safe
|
| ... | ... | @@ -157,4 +157,4 @@ pprUsageImport mod hash safe |
| 157 | 157 | , ppr hash ]
|
| 158 | 158 | where
|
| 159 | 159 | pp_safe | safe = text "safe"
|
| 160 | - | otherwise = text " -/ " |
|
| \ No newline at end of file | ||
| 160 | + | otherwise = text " -/ " |
| ... | ... | @@ -31,7 +31,7 @@ linkBytecodeLib hsc_env gbcs = do |
| 31 | 31 | |
| 32 | 32 | on_disk_bcos <- mapM (readBinByteCode hsc_env) bytecodeObjects
|
| 33 | 33 | |
| 34 | - let (all_cbcs, foreign_stubs) = unzip [ (bs, fs) | ModuleByteCode _m bs fs <- on_disk_bcos ++ gbcs]
|
|
| 34 | + let (all_cbcs, foreign_stubs) = unzip [ (bs, fs) | ModuleByteCode _m bs fs _hash <- on_disk_bcos ++ gbcs]
|
|
| 35 | 35 | |
| 36 | 36 | interpreter_foreign_lib <- mkInterpreterLib hsc_env (concat foreign_stubs ++ objectFiles)
|
| 37 | 37 | |
| ... | ... | @@ -67,4 +67,4 @@ mkInterpreterLib hsc_env files = |
| 67 | 67 | return $ Just (InterpreterSharedObject foreign_stub_lib_path foreign_stub_lib_dir foreign_stub_lib_name)
|
| 68 | 68 | Nothing -> pure Nothing
|
| 69 | 69 | False -> do
|
| 70 | - pure $ Just (InterpreterStaticObjects files) |
|
| \ No newline at end of file | ||
| 70 | + pure $ Just (InterpreterStaticObjects files) |
| ... | ... | @@ -63,7 +63,7 @@ data LinkDepsOpts = LinkDepsOpts |
| 63 | 63 | |
| 64 | 64 | data LinkDeps = LinkDeps
|
| 65 | 65 | { ldNeededLinkables :: [Linkable]
|
| 66 | - , ldAllLinkables :: [Linkable]
|
|
| 66 | + , ldAllLinkables :: [LinkableWithUsage]
|
|
| 67 | 67 | , ldUnits :: [UnitId]
|
| 68 | 68 | , ldNeededUnits :: UniqDSet UnitId
|
| 69 | 69 | }
|
| ... | ... | @@ -126,7 +126,7 @@ get_link_deps opts pls maybe_normal_osuf span mods = do |
| 126 | 126 | |
| 127 | 127 | return $ LinkDeps
|
| 128 | 128 | { ldNeededLinkables = lnks_needed
|
| 129 | - , ldAllLinkables = links_got ++ lnks_needed
|
|
| 129 | + , ldAllLinkables = links_got ++ mkLinkablesUsage lnks_needed
|
|
| 130 | 130 | , ldUnits = pkgs_needed
|
| 131 | 131 | , ldNeededUnits = pkgs_s
|
| 132 | 132 | }
|
| ... | ... | @@ -228,7 +228,7 @@ lookupFromLoadedEnv interp name = do |
| 228 | 228 | -- | Load the module containing the given Name and get its associated 'HValue'.
|
| 229 | 229 | --
|
| 230 | 230 | -- Throws a 'ProgramError' if loading fails or the name cannot be found.
|
| 231 | -loadName :: Interp -> HscEnv -> Name -> IO (ForeignHValue, [Linkable], PkgsLoaded)
|
|
| 231 | +loadName :: Interp -> HscEnv -> Name -> IO (ForeignHValue, [LinkableWithUsage], PkgsLoaded)
|
|
| 232 | 232 | loadName interp hsc_env name = do
|
| 233 | 233 | initLoaderState interp hsc_env
|
| 234 | 234 | modifyLoaderState interp $ \pls0 -> do
|
| ... | ... | @@ -258,7 +258,7 @@ loadDependencies |
| 258 | 258 | -> LoaderState
|
| 259 | 259 | -> SrcSpan
|
| 260 | 260 | -> [Module]
|
| 261 | - -> IO (LoaderState, SuccessFlag, [Linkable], PkgsLoaded) -- ^ returns the set of linkables required
|
|
| 261 | + -> IO (LoaderState, SuccessFlag, [LinkableWithUsage], PkgsLoaded) -- ^ returns the set of linkables required
|
|
| 262 | 262 | -- When called, the loader state must have been initialized (see `initLoaderState`)
|
| 263 | 263 | loadDependencies interp hsc_env pls span needed_mods = do
|
| 264 | 264 | let opts = initLinkDepsOpts hsc_env
|
| ... | ... | @@ -667,6 +667,7 @@ findBytecodeLinkableMaybe hsc_env mod locn = do |
| 667 | 667 | case maybe_bytecode_time of
|
| 668 | 668 | Nothing -> return Nothing
|
| 669 | 669 | Just bytecode_time -> do
|
| 670 | + -- TODO: @fendor This must go
|
|
| 670 | 671 | -- Also load the interface, for reasons to do with recompilation avoidance.
|
| 671 | 672 | -- See Note [Recompilation avoidance with bytecode objects]
|
| 672 | 673 | _ <- initIfaceLoad hsc_env $
|
| ... | ... | @@ -723,7 +724,7 @@ get_reachable_nodes hsc_env mods |
| 723 | 724 | ********************************************************************* -}
|
| 724 | 725 | |
| 725 | 726 | -- | Load the dependencies of a linkable, and then load the linkable itself.
|
| 726 | -loadDecls :: Interp -> HscEnv -> SrcSpan -> Linkable -> IO ([Linkable], PkgsLoaded)
|
|
| 727 | +loadDecls :: Interp -> HscEnv -> SrcSpan -> Linkable -> IO ([LinkableWithUsage], PkgsLoaded)
|
|
| 727 | 728 | loadDecls interp hsc_env span linkable = do
|
| 728 | 729 | -- Initialise the linker (if it's not been done already)
|
| 729 | 730 | initLoaderState interp hsc_env
|
| ... | ... | @@ -823,7 +824,7 @@ loadModuleLinkables interp hsc_env pls keep_spec linkables |
| 823 | 824 | (objs, bcos) = partitionLinkables linkables
|
| 824 | 825 | |
| 825 | 826 | |
| 826 | -linkableInSet :: Linkable -> LinkableSet -> Bool
|
|
| 827 | +linkableInSet :: Linkable -> LinkableSet LinkableWithUsage -> Bool
|
|
| 827 | 828 | linkableInSet l objs_loaded =
|
| 828 | 829 | case lookupModuleEnv objs_loaded (linkableModule l) of
|
| 829 | 830 | Nothing -> False
|
| ... | ... | @@ -952,9 +953,9 @@ dynLoadObjs interp hsc_env pls objs = do |
| 952 | 953 | then addWay WayProf
|
| 953 | 954 | else id
|
| 954 | 955 | |
| 955 | -rmDupLinkables :: LinkableSet -- Already loaded
|
|
| 956 | +rmDupLinkables :: LinkableSet LinkableWithUsage -- Already loaded
|
|
| 956 | 957 | -> [Linkable] -- New linkables
|
| 957 | - -> (LinkableSet, -- New loaded set (including new ones)
|
|
| 958 | + -> (LinkableSet LinkableWithUsage, -- New loaded set (including new ones)
|
|
| 958 | 959 | [Linkable]) -- New linkables (excluding dups)
|
| 959 | 960 | rmDupLinkables already ls
|
| 960 | 961 | = go already [] ls
|
| ... | ... | @@ -962,7 +963,7 @@ rmDupLinkables already ls |
| 962 | 963 | go already extras [] = (already, extras)
|
| 963 | 964 | go already extras (l:ls)
|
| 964 | 965 | | linkableInSet l already = go already extras ls
|
| 965 | - | otherwise = go (extendModuleEnv already (linkableModule l) l) (l:extras) ls
|
|
| 966 | + | otherwise = go (extendModuleEnv already (linkableModule l) (mkLinkableUsage l)) (l:extras) ls
|
|
| 966 | 967 | |
| 967 | 968 | {- **********************************************************************
|
| 968 | 969 | |
| ... | ... | @@ -974,7 +975,7 @@ rmDupLinkables already ls |
| 974 | 975 | dynLinkBCOs :: Interp -> LoaderState -> KeepModuleLinkableDefinitions -> [Linkable] -> IO LoaderState
|
| 975 | 976 | dynLinkBCOs interp pls keep_spec bcos =
|
| 976 | 977 | |
| 977 | - let (bcos_loaded', new_bcos) = rmDupLinkables (bcos_loaded pls) bcos
|
|
| 978 | + let (bcos_loaded', new_bcos) = rmDupLinkables (bcos_loaded pls) bcos -- TODO: @fendor, convert to linkable usage here?
|
|
| 978 | 979 | pls1 = pls { bcos_loaded = bcos_loaded' }
|
| 979 | 980 | |
| 980 | 981 | cbcs :: [CompiledByteCode]
|
| ... | ... | @@ -1109,13 +1110,13 @@ unload_wkr interp pls@LoaderState{..} = do |
| 1109 | 1110 | -- we're unloading some code. -fghci-leak-check with the tests in
|
| 1110 | 1111 | -- testsuite/ghci can detect space leaks here.
|
| 1111 | 1112 | |
| 1112 | - let linkables_to_unload = moduleEnvElts objs_loaded ++ moduleEnvElts bcos_loaded
|
|
| 1113 | + let linkables_to_unload = moduleEnvElts objs_loaded ++ moduleEnvElts bcos_loaded -- TODO: @fendor LinkableUsage here already?
|
|
| 1113 | 1114 | |
| 1114 | 1115 | mapM_ unloadObjs linkables_to_unload
|
| 1115 | 1116 | |
| 1116 | 1117 | -- If we unloaded any object files at all, we need to purge the cache
|
| 1117 | 1118 | -- of lookupSymbol results.
|
| 1118 | - when (not (null (filter (not . null . linkableObjs) linkables_to_unload))) $
|
|
| 1119 | + when (not (null (filter (not . null . linkableUsageObjs) linkables_to_unload))) $
|
|
| 1119 | 1120 | purgeLookupSymbolCache interp
|
| 1120 | 1121 | |
| 1121 | 1122 | let !new_pls = pls { bco_loader_state = modifyHomePackageBytecodeState bco_loader_state $ \_ -> emptyBytecodeState,
|
| ... | ... | @@ -1125,7 +1126,7 @@ unload_wkr interp pls@LoaderState{..} = do |
| 1125 | 1126 | |
| 1126 | 1127 | return new_pls
|
| 1127 | 1128 | where
|
| 1128 | - unloadObjs :: Linkable -> IO ()
|
|
| 1129 | + unloadObjs :: LinkableWithUsage -> IO ()
|
|
| 1129 | 1130 | unloadObjs lnk
|
| 1130 | 1131 | | interpreterDynamic interp = return ()
|
| 1131 | 1132 | -- We don't do any cleanup when linking objects with the
|
| ... | ... | @@ -1133,7 +1134,7 @@ unload_wkr interp pls@LoaderState{..} = do |
| 1133 | 1134 | -- not much benefit.
|
| 1134 | 1135 | |
| 1135 | 1136 | | otherwise
|
| 1136 | - = mapM_ (unloadObj interp) (linkableObjs lnk)
|
|
| 1137 | + = mapM_ (unloadObj interp) (linkableUsageObjs lnk)
|
|
| 1137 | 1138 | -- The components of a BCO linkable may contain
|
| 1138 | 1139 | -- dot-o files (generated from C stubs).
|
| 1139 | 1140 | --
|
| ... | ... | @@ -49,6 +49,7 @@ module GHC.Linker.Types |
| 49 | 49 | , WholeCoreBindingsLinkable
|
| 50 | 50 | , LinkableWith(..)
|
| 51 | 51 | , mkModuleByteCodeLinkable
|
| 52 | + , mkOnlyModuleByteCodeLinkable
|
|
| 52 | 53 | , LinkablePart(..)
|
| 53 | 54 | , LinkableObjectSort (..)
|
| 54 | 55 | , linkableIsNativeCodeOnly
|
| ... | ... | @@ -67,12 +68,17 @@ module GHC.Linker.Types |
| 67 | 68 | , linkableFilterNative
|
| 68 | 69 | , partitionLinkables
|
| 69 | 70 | |
| 71 | + , LinkableWithUsage
|
|
| 72 | + , linkableUsageObjs
|
|
| 73 | + , mkLinkablesUsage
|
|
| 74 | + , mkLinkableUsage
|
|
| 75 | + |
|
| 70 | 76 | , ModuleByteCode(..)
|
| 71 | 77 | )
|
| 72 | 78 | where
|
| 73 | 79 | |
| 74 | 80 | import GHC.Prelude
|
| 75 | -import GHC.Unit ( UnitId, Module )
|
|
| 81 | +import GHC.Unit ( UnitId, Module, moduleNameString, moduleName )
|
|
| 76 | 82 | import GHC.ByteCode.Types
|
| 77 | 83 | import GHCi.BreakArray
|
| 78 | 84 | import GHCi.RemoteTypes
|
| ... | ... | @@ -97,6 +103,10 @@ import Data.List.NonEmpty (NonEmpty, nonEmpty) |
| 97 | 103 | import qualified Data.List.NonEmpty as NE
|
| 98 | 104 | import Control.Applicative ((<|>))
|
| 99 | 105 | import Data.Functor.Identity
|
| 106 | +import GHC.Unit.Module.Deps (LinkableUsage (..), linkableUsageObjectPaths)
|
|
| 107 | +import GHC.Fingerprint (Fingerprint)
|
|
| 108 | +import qualified GHC.Data.OsPath as OsPath
|
|
| 109 | +import qualified GHC.Data.FlatBag as FlatBag
|
|
| 100 | 110 | |
| 101 | 111 | |
| 102 | 112 | {- **********************************************************************
|
| ... | ... | @@ -172,10 +182,10 @@ data LoaderState = LoaderState |
| 172 | 182 | -- ^ Information about bytecode objects we have loaded into the
|
| 173 | 183 | -- interpreter.
|
| 174 | 184 | |
| 175 | - , bcos_loaded :: !LinkableSet
|
|
| 185 | + , bcos_loaded :: !(LinkableSet LinkableWithUsage)
|
|
| 176 | 186 | -- ^ The currently loaded interpreted modules (home package)
|
| 177 | 187 | |
| 178 | - , objs_loaded :: !LinkableSet
|
|
| 188 | + , objs_loaded :: !(LinkableSet LinkableWithUsage)
|
|
| 179 | 189 | -- ^ And the currently-loaded compiled modules (home package)
|
| 180 | 190 | |
| 181 | 191 | , pkgs_loaded :: !PkgsLoaded
|
| ... | ... | @@ -384,15 +394,17 @@ type Linkable = LinkableWith (NonEmpty LinkablePart) |
| 384 | 394 | |
| 385 | 395 | type WholeCoreBindingsLinkable = LinkableWith WholeCoreBindings
|
| 386 | 396 | |
| 387 | -type LinkableSet = ModuleEnv Linkable
|
|
| 397 | +type LinkableWithUsage = LinkableWith (NonEmpty LinkableUsage)
|
|
| 398 | + |
|
| 399 | +type LinkableSet = ModuleEnv
|
|
| 388 | 400 | |
| 389 | -mkLinkableSet :: [Linkable] -> LinkableSet
|
|
| 401 | +mkLinkableSet :: [Linkable] -> LinkableSet Linkable
|
|
| 390 | 402 | mkLinkableSet ls = mkModuleEnv [(linkableModule l, l) | l <- ls]
|
| 391 | 403 | |
| 392 | 404 | -- | Union of LinkableSets.
|
| 393 | 405 | --
|
| 394 | 406 | -- In case of conflict, keep the most recent Linkable (as per linkableTime)
|
| 395 | -unionLinkableSet :: LinkableSet -> LinkableSet -> LinkableSet
|
|
| 407 | +unionLinkableSet :: LinkableSet (LinkableWith a) -> LinkableSet (LinkableWith a) -> LinkableSet (LinkableWith a)
|
|
| 396 | 408 | unionLinkableSet = plusModuleEnv_C go
|
| 397 | 409 | where
|
| 398 | 410 | go l1 l2
|
| ... | ... | @@ -435,8 +447,9 @@ data LinkablePart |
| 435 | 447 | | DotDLL FilePath
|
| 436 | 448 | -- ^ Dynamically linked library file (.so, .dll, .dylib)
|
| 437 | 449 | |
| 438 | - | DotGBC ModuleByteCode
|
|
| 439 | - -- ^ A byte-code object, lives only in memory.
|
|
| 450 | + | DotGBC
|
|
| 451 | + -- ^ A byte-code object, lives only in memory.
|
|
| 452 | + ModuleByteCode
|
|
| 440 | 453 | |
| 441 | 454 | |
| 442 | 455 | -- | The in-memory representation of a bytecode object
|
| ... | ... | @@ -444,14 +457,19 @@ data LinkablePart |
| 444 | 457 | data ModuleByteCode = ModuleByteCode { gbc_module :: Module
|
| 445 | 458 | , gbc_compiled_byte_code :: CompiledByteCode
|
| 446 | 459 | , gbc_foreign_files :: [FilePath] -- ^ Path to object files
|
| 460 | + , gbc_hash :: !Fingerprint
|
|
| 447 | 461 | }
|
| 448 | 462 | |
| 449 | 463 | mkModuleByteCodeLinkable :: UTCTime -> ModuleByteCode -> Linkable
|
| 450 | -mkModuleByteCodeLinkable linkable_time bco =
|
|
| 464 | +mkModuleByteCodeLinkable linkable_time bco = do
|
|
| 451 | 465 | Linkable linkable_time (gbc_module bco) (pure (DotGBC bco))
|
| 452 | 466 | |
| 467 | +mkOnlyModuleByteCodeLinkable :: UTCTime -> ModuleByteCode -> LinkableWith ModuleByteCode
|
|
| 468 | +mkOnlyModuleByteCodeLinkable linkable_time bco = do
|
|
| 469 | + Linkable linkable_time (gbc_module bco) bco
|
|
| 470 | + |
|
| 453 | 471 | instance Outputable ModuleByteCode where
|
| 454 | - ppr (ModuleByteCode mod _cbc _fos) = text "ModuleByteCode" <+> ppr mod
|
|
| 472 | + ppr (ModuleByteCode mod _cbc _fos _) = text "ModuleByteCode" <+> ppr mod
|
|
| 455 | 473 | |
| 456 | 474 | instance Outputable LinkablePart where
|
| 457 | 475 | ppr (DotO path sort) = text "DotO" <+> text path <+> pprSort sort
|
| ... | ... | @@ -544,8 +562,8 @@ linkablePartObjectPaths = \case |
| 544 | 562 | -- Contrary to linkableBCOs, this includes byte-code from LazyBCOs.
|
| 545 | 563 | linkablePartBCOs :: LinkablePart -> [CompiledByteCode]
|
| 546 | 564 | linkablePartBCOs = \case
|
| 547 | - DotGBC bco -> [gbc_compiled_byte_code bco]
|
|
| 548 | - _ -> []
|
|
| 565 | + DotGBC bco -> [gbc_compiled_byte_code bco]
|
|
| 566 | + _ -> []
|
|
| 549 | 567 | |
| 550 | 568 | linkableFilter :: (LinkablePart -> [LinkablePart]) -> Linkable -> Maybe Linkable
|
| 551 | 569 | linkableFilter f linkable = do
|
| ... | ... | @@ -586,6 +604,48 @@ partitionLinkables linkables = |
| 586 | 604 | mapMaybe linkableFilterByteCode linkables
|
| 587 | 605 | )
|
| 588 | 606 | |
| 607 | + |
|
| 608 | +mkLinkableUsage :: Linkable -> LinkableWithUsage
|
|
| 609 | +mkLinkableUsage linkables = do
|
|
| 610 | + linkableUsage linkables
|
|
| 611 | + where
|
|
| 612 | + msg m = moduleNameString (moduleName m) ++ "[TH] changed"
|
|
| 613 | + |
|
| 614 | + linkableUsage lnk@Linkable{linkableParts} =
|
|
| 615 | + setLinkableParts lnk linkableParts
|
|
| 616 | + |
|
| 617 | + mkFileLinkableUsage m fp objs =
|
|
| 618 | + FileLinkableUsage
|
|
| 619 | + { flu_file = fp
|
|
| 620 | + , flu_message = Just $ msg m
|
|
| 621 | + , flu_linkable_objs = FlatBag.fromList (strictGenericLength objs) [ OsPath.unsafeEncodeUtf obj | obj <- objs ]
|
|
| 622 | + }
|
|
| 623 | + |
|
| 624 | + mkByteCodeLinkableUsage m fp objs =
|
|
| 625 | + ByteCodeLinkableUsage
|
|
| 626 | + { bclu_module = m
|
|
| 627 | + , bclu_hash = fp
|
|
| 628 | + , bclu_linkable_objs = FlatBag.fromList (strictGenericLength objs) [ OsPath.unsafeEncodeUtf obj | obj <- objs ]
|
|
| 629 | + }
|
|
| 630 | + |
|
| 631 | + setLinkableParts lnk@(Linkable{linkableModule}) parts =
|
|
| 632 | + lnk
|
|
| 633 | + { linkableParts = fmap (go linkableModule) parts
|
|
| 634 | + }
|
|
| 635 | + |
|
| 636 | + go :: Module -> LinkablePart -> LinkableUsage
|
|
| 637 | + go m lnkPart = case lnkPart of
|
|
| 638 | + DotO fn _ -> mkFileLinkableUsage m fn (linkablePartObjectPaths lnkPart)
|
|
| 639 | + DotA fn -> mkFileLinkableUsage m fn (linkablePartObjectPaths lnkPart)
|
|
| 640 | + DotDLL fn -> mkFileLinkableUsage m fn (linkablePartObjectPaths lnkPart)
|
|
| 641 | + DotGBC mbc -> mkByteCodeLinkableUsage m (gbc_hash mbc) (linkablePartObjectPaths lnkPart)
|
|
| 642 | + |
|
| 643 | +mkLinkablesUsage :: [Linkable] -> [LinkableWithUsage]
|
|
| 644 | +mkLinkablesUsage linkables = map mkLinkableUsage linkables
|
|
| 645 | + |
|
| 646 | +linkableUsageObjs :: LinkableWithUsage -> [FilePath]
|
|
| 647 | +linkableUsageObjs lnkWithUsage = concatMap linkableUsageObjectPaths (linkableParts lnkWithUsage)
|
|
| 648 | + |
|
| 589 | 649 | {- **********************************************************************
|
| 590 | 650 | |
| 591 | 651 | Loading packages
|
| ... | ... | @@ -153,7 +153,7 @@ initializePlugins hsc_env |
| 153 | 153 | ([] , _ ) -> False -- some external plugin added
|
| 154 | 154 | (p:ps,s:ss) -> check_external_plugin p s && check_external_plugins ps ss
|
| 155 | 155 | |
| 156 | -loadPlugins :: HscEnv -> IO ([LoadedPlugin], [Linkable], PkgsLoaded)
|
|
| 156 | +loadPlugins :: HscEnv -> IO ([LoadedPlugin], [LinkableWithUsage], PkgsLoaded)
|
|
| 157 | 157 | loadPlugins hsc_env
|
| 158 | 158 | = do { unless (null to_load) $
|
| 159 | 159 | checkExternalInterpreter hsc_env
|
| ... | ... | @@ -173,7 +173,7 @@ loadPlugins hsc_env |
| 173 | 173 | loadPlugin = loadPlugin' (mkVarOccFS (fsLit "plugin")) pluginTyConName hsc_env
|
| 174 | 174 | |
| 175 | 175 | |
| 176 | -loadFrontendPlugin :: HscEnv -> ModuleName -> IO (FrontendPlugin, [Linkable], PkgsLoaded)
|
|
| 176 | +loadFrontendPlugin :: HscEnv -> ModuleName -> IO (FrontendPlugin, [LinkableWithUsage], PkgsLoaded)
|
|
| 177 | 177 | loadFrontendPlugin hsc_env mod_name = do
|
| 178 | 178 | checkExternalInterpreter hsc_env
|
| 179 | 179 | (plugin, _iface, links, pkgs)
|
| ... | ... | @@ -188,7 +188,7 @@ checkExternalInterpreter hsc_env = case interpInstance <$> hsc_interp hsc_env of |
| 188 | 188 | -> throwIO (InstallationError "Plugins require -fno-external-interpreter")
|
| 189 | 189 | _ -> pure ()
|
| 190 | 190 | |
| 191 | -loadPlugin' :: OccName -> Name -> HscEnv -> ModuleName -> IO (a, ModIface, [Linkable], PkgsLoaded)
|
|
| 191 | +loadPlugin' :: OccName -> Name -> HscEnv -> ModuleName -> IO (a, ModIface, [LinkableWithUsage], PkgsLoaded)
|
|
| 192 | 192 | loadPlugin' occ_name plugin_name hsc_env mod_name
|
| 193 | 193 | = do { let plugin_rdr_name = mkRdrQual mod_name occ_name
|
| 194 | 194 | dflags = hsc_dflags hsc_env
|
| ... | ... | @@ -266,7 +266,7 @@ forceLoadTyCon hsc_env con_name = do |
| 266 | 266 | -- * If the Name does not exist in the module
|
| 267 | 267 | -- * If the link failed
|
| 268 | 268 | |
| 269 | -getValueSafely :: HscEnv -> Name -> Type -> IO (Either Type (a, [Linkable], PkgsLoaded))
|
|
| 269 | +getValueSafely :: HscEnv -> Name -> Type -> IO (Either Type (a, [LinkableWithUsage], PkgsLoaded))
|
|
| 270 | 270 | getValueSafely hsc_env val_name expected_type = do
|
| 271 | 271 | eith_hval <- case getValueSafelyHook hooks of
|
| 272 | 272 | Nothing -> getHValueSafely interp hsc_env val_name expected_type
|
| ... | ... | @@ -281,7 +281,7 @@ getValueSafely hsc_env val_name expected_type = do |
| 281 | 281 | logger = hsc_logger hsc_env
|
| 282 | 282 | hooks = hsc_hooks hsc_env
|
| 283 | 283 | |
| 284 | -getHValueSafely :: Interp -> HscEnv -> Name -> Type -> IO (Either Type (HValue, [Linkable], PkgsLoaded))
|
|
| 284 | +getHValueSafely :: Interp -> HscEnv -> Name -> Type -> IO (Either Type (HValue, [LinkableWithUsage], PkgsLoaded))
|
|
| 285 | 285 | getHValueSafely interp hsc_env val_name expected_type = do
|
| 286 | 286 | forceLoadNameModuleInterface hsc_env (text "contains a name used in an invocation of getHValueSafely") val_name
|
| 287 | 287 | -- Now look up the names for the value and type constructor in the type environment
|
| ... | ... | @@ -563,7 +563,7 @@ data TcGblEnv |
| 563 | 563 | -- is implicit rather than explicit, so we have to zap a
|
| 564 | 564 | -- mutable variable.
|
| 565 | 565 | |
| 566 | - tcg_th_needed_deps :: TcRef ([Linkable], PkgsLoaded),
|
|
| 566 | + tcg_th_needed_deps :: TcRef ([LinkableWithUsage], PkgsLoaded),
|
|
| 567 | 567 | -- ^ The set of runtime dependencies required by this module
|
| 568 | 568 | -- See Note [Object File Dependencies]
|
| 569 | 569 |
| ... | ... | @@ -2266,7 +2266,7 @@ fillCoercionHole (CH { ch_ref = ref, ch_co_var = cv }) co |
| 2266 | 2266 | recordThUse :: TcM ()
|
| 2267 | 2267 | recordThUse = do { env <- getGblEnv; writeTcRef (tcg_th_used env) True }
|
| 2268 | 2268 | |
| 2269 | -recordThNeededRuntimeDeps :: [Linkable] -> PkgsLoaded -> TcM ()
|
|
| 2269 | +recordThNeededRuntimeDeps :: [LinkableWithUsage] -> PkgsLoaded -> TcM ()
|
|
| 2270 | 2270 | recordThNeededRuntimeDeps new_links new_pkgs
|
| 2271 | 2271 | = do { env <- getGblEnv
|
| 2272 | 2272 | ; updTcRef (tcg_th_needed_deps env) $ \(needed_links, needed_pkgs) ->
|
| ... | ... | @@ -3,9 +3,11 @@ |
| 3 | 3 | module GHC.Unit.Home.ModInfo
|
| 4 | 4 | (
|
| 5 | 5 | HomeModInfo (..)
|
| 6 | - , HomeModLinkable (..)
|
|
| 7 | 6 | , homeModInfoObject
|
| 8 | 7 | , homeModInfoByteCode
|
| 8 | + , HomeModLinkable (..)
|
|
| 9 | + , homeModLinkableByteCode
|
|
| 10 | + , homeModLinkableObject
|
|
| 9 | 11 | , emptyHomeModInfoLinkable
|
| 10 | 12 | )
|
| 11 | 13 | where
|
| ... | ... | @@ -15,9 +17,10 @@ import GHC.Prelude |
| 15 | 17 | import GHC.Unit.Module.ModIface
|
| 16 | 18 | import GHC.Unit.Module.ModDetails
|
| 17 | 19 | |
| 18 | -import GHC.Linker.Types ( Linkable )
|
|
| 20 | +import GHC.Linker.Types ( Linkable, LinkableWith, ModuleByteCode, LinkablePart (..) )
|
|
| 19 | 21 | |
| 20 | 22 | import GHC.Utils.Outputable
|
| 23 | +import qualified Data.List.NonEmpty as NE
|
|
| 21 | 24 | |
| 22 | 25 | -- | Information about modules in the package being compiled
|
| 23 | 26 | data HomeModInfo = HomeModInfo
|
| ... | ... | @@ -48,18 +51,24 @@ data HomeModInfo = HomeModInfo |
| 48 | 51 | }
|
| 49 | 52 | |
| 50 | 53 | homeModInfoByteCode :: HomeModInfo -> Maybe Linkable
|
| 51 | -homeModInfoByteCode = homeMod_bytecode . hm_linkable
|
|
| 54 | +homeModInfoByteCode = homeModLinkableByteCode . hm_linkable
|
|
| 52 | 55 | |
| 53 | 56 | homeModInfoObject :: HomeModInfo -> Maybe Linkable
|
| 54 | -homeModInfoObject = homeMod_object . hm_linkable
|
|
| 57 | +homeModInfoObject = homeModLinkableObject . hm_linkable
|
|
| 55 | 58 | |
| 56 | 59 | emptyHomeModInfoLinkable :: HomeModLinkable
|
| 57 | 60 | emptyHomeModInfoLinkable = HomeModLinkable Nothing Nothing
|
| 58 | 61 | |
| 59 | 62 | -- See Note [Home module build products]
|
| 60 | -data HomeModLinkable = HomeModLinkable { homeMod_bytecode :: !(Maybe Linkable)
|
|
| 63 | +data HomeModLinkable = HomeModLinkable { homeMod_bytecode :: !(Maybe (LinkableWith ModuleByteCode))
|
|
| 61 | 64 | , homeMod_object :: !(Maybe Linkable) }
|
| 62 | 65 | |
| 66 | +homeModLinkableByteCode :: HomeModLinkable -> Maybe Linkable
|
|
| 67 | +homeModLinkableByteCode = fmap (fmap (NE.singleton . DotGBC)) . homeMod_bytecode
|
|
| 68 | + |
|
| 69 | +homeModLinkableObject :: HomeModLinkable -> Maybe Linkable
|
|
| 70 | +homeModLinkableObject = homeMod_object
|
|
| 71 | + |
|
| 63 | 72 | instance Outputable HomeModLinkable where
|
| 64 | 73 | ppr (HomeModLinkable l1 l2) = ppr l1 $$ ppr l2
|
| 65 | 74 |
| ... | ... | @@ -22,6 +22,10 @@ module GHC.Unit.Module.Deps |
| 22 | 22 | , ImportAvails (..)
|
| 23 | 23 | , IfaceImportLevel(..)
|
| 24 | 24 | , tcImportLevel
|
| 25 | + , LinkableUsage(..)
|
|
| 26 | + , linkableUsageObjectPaths
|
|
| 27 | + , noLinkableUsage
|
|
| 28 | + , combineLinkableUsage
|
|
| 25 | 29 | )
|
| 26 | 30 | where
|
| 27 | 31 | |
| ... | ... | @@ -49,7 +53,10 @@ import qualified Data.Set as Set |
| 49 | 53 | import Data.Bifunctor
|
| 50 | 54 | import Control.DeepSeq
|
| 51 | 55 | import GHC.Types.Name.Set
|
| 52 | - |
|
| 56 | +import GHC.ByteCode.Types (FlatBag)
|
|
| 57 | +import GHC.Data.OsPath
|
|
| 58 | +import qualified Data.Foldable as Foldable
|
|
| 59 | +import qualified GHC.Data.OsPath as OsPath
|
|
| 53 | 60 | |
| 54 | 61 | |
| 55 | 62 | -- | Dependency information about ALL modules and packages below this one
|
| ... | ... | @@ -372,12 +379,12 @@ data Usage |
| 372 | 379 | -- we won't spot it here. If you do want to spot that, the caller
|
| 373 | 380 | -- should recursively add them to their useage.
|
| 374 | 381 | }
|
| 375 | - | UsageHomeModuleInterface {
|
|
| 382 | + | UsageHomeModuleBytecode {
|
|
| 376 | 383 | usg_mod_name :: ModuleName
|
| 377 | 384 | -- ^ Name of the module
|
| 378 | 385 | , usg_unit_id :: UnitId
|
| 379 | 386 | -- ^ UnitId of the HomeUnit the module is from
|
| 380 | - , usg_iface_hash :: Fingerprint
|
|
| 387 | + , usg_bytecode_hash :: Fingerprint
|
|
| 381 | 388 | -- ^ The *interface* hash of the module, not the ABI hash.
|
| 382 | 389 | -- This changes when anything about the interface (and hence the
|
| 383 | 390 | -- module) has changed.
|
| ... | ... | @@ -412,7 +419,7 @@ instance NFData Usage where |
| 412 | 419 | rnf (UsageFile file hash label) = rnf file `seq` rnf hash `seq` rnf label `seq` ()
|
| 413 | 420 | rnf (UsageDirectory dir hash label) = rnf dir `seq` rnf hash `seq` rnf label `seq` ()
|
| 414 | 421 | rnf (UsageMergedRequirement mod hash) = rnf mod `seq` rnf hash `seq` ()
|
| 415 | - rnf (UsageHomeModuleInterface mod uid hash) = rnf mod `seq` rnf uid `seq` rnf hash `seq` ()
|
|
| 422 | + rnf (UsageHomeModuleBytecode mod uid hash) = rnf mod `seq` rnf uid `seq` rnf hash `seq` ()
|
|
| 416 | 423 | |
| 417 | 424 | instance Binary Usage where
|
| 418 | 425 | put_ bh usg@UsagePackageModule{} = do
|
| ... | ... | @@ -441,11 +448,11 @@ instance Binary Usage where |
| 441 | 448 | put_ bh (usg_mod usg)
|
| 442 | 449 | put_ bh (usg_mod_hash usg)
|
| 443 | 450 | |
| 444 | - put_ bh usg@UsageHomeModuleInterface{} = do
|
|
| 451 | + put_ bh usg@UsageHomeModuleBytecode{} = do
|
|
| 445 | 452 | putByte bh 4
|
| 446 | 453 | put_ bh (usg_mod_name usg)
|
| 447 | 454 | put_ bh (usg_unit_id usg)
|
| 448 | - put_ bh (usg_iface_hash usg)
|
|
| 455 | + put_ bh (usg_bytecode_hash usg)
|
|
| 449 | 456 | |
| 450 | 457 | put_ bh usg@UsageDirectory{} = do
|
| 451 | 458 | putByte bh 5
|
| ... | ... | @@ -483,7 +490,7 @@ instance Binary Usage where |
| 483 | 490 | mod <- get bh
|
| 484 | 491 | uid <- get bh
|
| 485 | 492 | hash <- get bh
|
| 486 | - return UsageHomeModuleInterface { usg_mod_name = mod, usg_unit_id = uid, usg_iface_hash = hash }
|
|
| 493 | + return UsageHomeModuleBytecode { usg_mod_name = mod, usg_unit_id = uid, usg_bytecode_hash = hash }
|
|
| 487 | 494 | 5 -> do
|
| 488 | 495 | dp <- get bh
|
| 489 | 496 | hash <- get bh
|
| ... | ... | @@ -695,3 +702,38 @@ data ImportAvails |
| 695 | 702 | -- ^ Family instance modules below us in the import tree (and maybe
|
| 696 | 703 | -- including us for imported modules)
|
| 697 | 704 | }
|
| 705 | + |
|
| 706 | +data LinkableUsage
|
|
| 707 | + = FileLinkableUsage
|
|
| 708 | + { flu_file :: !FilePath
|
|
| 709 | + , flu_message :: !(Maybe String)
|
|
| 710 | + , flu_linkable_objs :: !(FlatBag OsPath)
|
|
| 711 | + }
|
|
| 712 | + | ByteCodeLinkableUsage
|
|
| 713 | + { bclu_module :: !Module
|
|
| 714 | + , bclu_hash :: !Fingerprint
|
|
| 715 | + , bclu_linkable_objs :: !(FlatBag OsPath)
|
|
| 716 | + }
|
|
| 717 | + |
|
| 718 | +instance Outputable LinkableUsage where
|
|
| 719 | + ppr = \ case
|
|
| 720 | + FileLinkableUsage fp mmsg _objs ->
|
|
| 721 | + text "FileLinkableUsage" <+> text fp <> maybe empty (\ msg -> text " " <> text msg) mmsg
|
|
| 722 | + ByteCodeLinkableUsage modl hash _objs ->
|
|
| 723 | + text "ByteCodeLinkableUsage" <+> ppr modl <+> ppr hash
|
|
| 724 | + |
|
| 725 | + |
|
| 726 | +linkableUsageObjectPaths :: LinkableUsage -> [FilePath]
|
|
| 727 | +linkableUsageObjectPaths lnkUsage =
|
|
| 728 | + map OsPath.unsafeDecodeUtf . Foldable.toList $ linkableUsageObjectOsPaths lnkUsage
|
|
| 729 | + |
|
| 730 | +linkableUsageObjectOsPaths :: LinkableUsage -> FlatBag OsPath
|
|
| 731 | +linkableUsageObjectOsPaths lnkUsage = case lnkUsage of
|
|
| 732 | + FileLinkableUsage{flu_linkable_objs} -> flu_linkable_objs
|
|
| 733 | + ByteCodeLinkableUsage{bclu_linkable_objs} -> bclu_linkable_objs
|
|
| 734 | + |
|
| 735 | +noLinkableUsage :: [LinkableUsage]
|
|
| 736 | +noLinkableUsage = []
|
|
| 737 | + |
|
| 738 | +combineLinkableUsage :: [LinkableUsage] -> [LinkableUsage] -> [LinkableUsage]
|
|
| 739 | +combineLinkableUsage a b = a ++ b |
| ... | ... | @@ -18,7 +18,7 @@ import GHC.Unit.Home.ModInfo |
| 18 | 18 | import GHC.Unit.Module.ModGuts
|
| 19 | 19 | import GHC.Unit.Module.ModIface
|
| 20 | 20 | |
| 21 | -import GHC.Linker.Types ( Linkable, WholeCoreBindingsLinkable, linkableIsNativeCodeOnly )
|
|
| 21 | +import GHC.Linker.Types ( Linkable, WholeCoreBindingsLinkable, linkableIsNativeCodeOnly, ModuleByteCode, LinkableWith, linkableBCOs, linkableModuleByteCodes )
|
|
| 22 | 22 | |
| 23 | 23 | import GHC.Utils.Fingerprint
|
| 24 | 24 | import GHC.Utils.Outputable
|
| ... | ... | @@ -59,7 +59,7 @@ data RecompLinkables = RecompLinkables { recompLinkables_bytecode :: !RecompByte |
| 59 | 59 | , recompLinkables_object :: !(Maybe Linkable) }
|
| 60 | 60 | |
| 61 | 61 | data RecompBytecodeLinkable
|
| 62 | - = NormalLinkable !(Maybe Linkable)
|
|
| 62 | + = NormalLinkable !(Maybe (LinkableWith ModuleByteCode))
|
|
| 63 | 63 | | WholeCoreBindingsLinkable !WholeCoreBindingsLinkable
|
| 64 | 64 | |
| 65 | 65 | instance Outputable HscRecompStatus where
|
| ... | ... | @@ -87,7 +87,8 @@ justBytecode :: Either Linkable WholeCoreBindingsLinkable -> RecompLinkables |
| 87 | 87 | justBytecode = \case
|
| 88 | 88 | Left lm ->
|
| 89 | 89 | assertPpr (not (linkableIsNativeCodeOnly lm)) (ppr lm)
|
| 90 | - $ emptyRecompLinkables { recompLinkables_bytecode = NormalLinkable (Just lm) }
|
|
| 90 | + $ assertPpr (length (linkableBCOs lm) == 1) (text "Expected 1 DotGBC linkable" $$ ppr lm )
|
|
| 91 | + $ emptyRecompLinkables { recompLinkables_bytecode = NormalLinkable (Just (head (linkableModuleByteCodes lm) <$ lm)) }
|
|
| 91 | 92 | Right lm -> emptyRecompLinkables { recompLinkables_bytecode = WholeCoreBindingsLinkable lm }
|
| 92 | 93 | |
| 93 | 94 | justObjects :: Linkable -> RecompLinkables
|
| ... | ... | @@ -99,7 +100,8 @@ bytecodeAndObjects :: Either Linkable WholeCoreBindingsLinkable -> Linkable -> R |
| 99 | 100 | bytecodeAndObjects either_bc o = case either_bc of
|
| 100 | 101 | Left bc ->
|
| 101 | 102 | assertPpr (not (linkableIsNativeCodeOnly bc) && linkableIsNativeCodeOnly o) (ppr bc $$ ppr o)
|
| 102 | - $ RecompLinkables (NormalLinkable (Just bc)) (Just o)
|
|
| 103 | + $ assertPpr (length (linkableBCOs bc) == 1) (text "Expected 1 DotGBC linkable" $$ ppr bc )
|
|
| 104 | + $ RecompLinkables (NormalLinkable (Just (head (linkableModuleByteCodes bc) <$ bc))) (Just o)
|
|
| 103 | 105 | Right bc ->
|
| 104 | 106 | assertPpr (linkableIsNativeCodeOnly o) (ppr o)
|
| 105 | 107 | $ RecompLinkables (WholeCoreBindingsLinkable bc) (Just o) |
| ... | ... | @@ -37,6 +37,7 @@ module GHC.Utils.Binary |
| 37 | 37 | tellBinWriter,
|
| 38 | 38 | castBin,
|
| 39 | 39 | withBinBuffer,
|
| 40 | + withReadBinBuffer,
|
|
| 40 | 41 | freezeWriteHandle,
|
| 41 | 42 | shrinkBinBuffer,
|
| 42 | 43 | thawReadHandle,
|
| ... | ... | @@ -348,6 +349,12 @@ withBinBuffer (WriteBinMem _ ix_r _ arr_r) action = do |
| 348 | 349 | arr <- readIORef arr_r
|
| 349 | 350 | action $ BS.fromForeignPtr arr 0 ix
|
| 350 | 351 | |
| 352 | +-- | Get access to the underlying buffer.
|
|
| 353 | +withReadBinBuffer :: ReadBinHandle -> (ByteString -> IO a) -> IO a
|
|
| 354 | +withReadBinBuffer (ReadBinMem _ ix_r _ arr) action = do
|
|
| 355 | + ix <- readFastMutInt ix_r
|
|
| 356 | + action $ BS.fromForeignPtr arr 0 ix
|
|
| 357 | + |
|
| 351 | 358 | unsafeUnpackBinBuffer :: ByteString -> IO ReadBinHandle
|
| 352 | 359 | unsafeUnpackBinBuffer (BS.BS arr len) = do
|
| 353 | 360 | ix_r <- newFastMutInt 0
|
| ... | ... | @@ -52,8 +52,11 @@ getLeakIndicators hsc_env = |
| 52 | 52 | return $ LeakModIndicators{..}
|
| 53 | 53 | where
|
| 54 | 54 | mkWeakLinkables :: HomeModLinkable -> IO [Maybe (Weak Linkable)]
|
| 55 | - mkWeakLinkables (HomeModLinkable mbc mo) =
|
|
| 56 | - mapM (\ln -> traverse (flip mkWeakPtr Nothing <=< evaluate) ln) [mbc, mo]
|
|
| 55 | + mkWeakLinkables hml =
|
|
| 56 | + mapM (\ln -> traverse (flip mkWeakPtr Nothing <=< evaluate) ln)
|
|
| 57 | + [ homeModLinkableByteCode hml
|
|
| 58 | + , homeModLinkableObject hml
|
|
| 59 | + ]
|
|
| 57 | 60 | |
| 58 | 61 | -- | Look at the LeakIndicators collected by an earlier call to
|
| 59 | 62 | -- `getLeakIndicators`, and print messasges if any of them are still
|
| 1 | +TOP=../../..
|
|
| 2 | +include $(TOP)/mk/boilerplate.mk
|
|
| 3 | +include $(TOP)/mk/test.mk
|
|
| 4 | + |
|
| 5 | +.PHONY: TLinkable_Prep
|
|
| 6 | +TLinkable_Prep:
|
|
| 7 | + ./genSplices
|
|
| 8 | + '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -fprefer-byte-code -v0 TLinkable.hs
|
|
| 9 | + |
|
| 10 | +.PHONY: TLinkable2Pre
|
|
| 11 | +TLinkable2Pre:
|
|
| 12 | + ./genSplices
|
|
| 13 | + '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -fprefer-byte-code -fwrite-byte-code -v0 THMain.hs
|
|
| 14 | + |
|
| 15 | +.PHONY: TLinkable2
|
|
| 16 | +TLinkable2:
|
|
| 17 | + '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) -c -fprefer-byte-code -fwrite-byte-code -v0 THMain.hs |
| 1 | +# Test ideas
|
|
| 2 | +# Bytecode libraries
|
|
| 3 | +# Depend on that bytecode, look at the bytecode library tests to make sure this ends up in the EPS
|
|
| 4 | + |
|
| 5 | +# test('TLinkable',
|
|
| 6 | +# [ collect_compiler_stats('bytes allocated',2),
|
|
| 7 | +# pre_cmd('$MAKE -s --no-print-directory TLinkablePre'),
|
|
| 8 | +# extra_files(['genSplices']),
|
|
| 9 | +# ],
|
|
| 10 | +# makefile_test,
|
|
| 11 | +# ['TLinkable'])
|
|
| 12 | + |
|
| 13 | +# A performance test for calculating link dependencies in -c mode.
|
|
| 14 | +test('TLinkable',
|
|
| 15 | + [ collect_compiler_stats('bytes allocated',2),
|
|
| 16 | + pre_cmd('$MAKE -s --no-print-directory TLinkable_Prep'),
|
|
| 17 | + extra_files(['genSplices']),
|
|
| 18 | + compile_timeout_multiplier(5),
|
|
| 19 | + when(arch('wasm32'), fragile(25336)),
|
|
| 20 | + ],
|
|
| 21 | + compile,
|
|
| 22 | + ['-fforce-recomp ' + config.ghc_th_way_flags]) |
| 1 | +#!/bin/bash
|
|
| 2 | + |
|
| 3 | +# Generate NMOD Haskell modules, each with NDEF NOINLINE functions
|
|
| 4 | +# Usage: ./genSplices <NMOD> <NDEF>
|
|
| 5 | + |
|
| 6 | +NMOD=${1:-20} # Default 20 modules
|
|
| 7 | +NDEF=${2:-50} # Default 50 functions per module
|
|
| 8 | + |
|
| 9 | +# Generate the modules
|
|
| 10 | +for ((i=1; i<=NMOD; i++)); do
|
|
| 11 | + module_name="Module$(printf "%03d" $i)"
|
|
| 12 | + file_path="${module_name}.hs"
|
|
| 13 | + |
|
| 14 | + cat > "$file_path" << EOF
|
|
| 15 | +module ${module_name} where
|
|
| 16 | + |
|
| 17 | +EOF
|
|
| 18 | + |
|
| 19 | + for ((j=1; j<=NDEF; j++)); do
|
|
| 20 | + func_name="func$(printf "%03d" $j)"
|
|
| 21 | + cat >> "$file_path" << EOF
|
|
| 22 | +{-# NOINLINE ${func_name} #-}
|
|
| 23 | +${func_name} :: Int -> Int
|
|
| 24 | +${func_name} x = x + ${j}
|
|
| 25 | + |
|
| 26 | +EOF
|
|
| 27 | + done
|
|
| 28 | +done
|
|
| 29 | + |
|
| 30 | +# Generate imports section
|
|
| 31 | +imports=""
|
|
| 32 | +for ((i=1; i<=NMOD; i++)); do
|
|
| 33 | + imports="${imports}import Module$(printf "%03d" $i)
|
|
| 34 | +"
|
|
| 35 | +done
|
|
| 36 | + |
|
| 37 | +# Generate the hard-coded TH expression
|
|
| 38 | +# Build: Module001.func001 1 + Module001.func002 2 + ... + Module{NMOD}.func{NDEF} {NMOD*NDEF}
|
|
| 39 | +expression=""
|
|
| 40 | +count=1
|
|
| 41 | +for ((i=1; i<=NMOD; i++)); do
|
|
| 42 | + mod_name="Module$(printf "%03d" $i)"
|
|
| 43 | + for ((j=1; j<=NDEF; j++)); do
|
|
| 44 | + func_name="func$(printf "%03d" $j)"
|
|
| 45 | + if [ $count -gt 1 ]; then
|
|
| 46 | + expression="${expression} + "
|
|
| 47 | + fi
|
|
| 48 | + expression="${expression}${mod_name}.${func_name} ${count}"
|
|
| 49 | + ((count++))
|
|
| 50 | + done
|
|
| 51 | +done
|
|
| 52 | + |
|
| 53 | +# Generate the TH splice file
|
|
| 54 | +cat > TLinkable.hs << EOF
|
|
| 55 | +{-# LANGUAGE TemplateHaskell #-}
|
|
| 56 | + |
|
| 57 | +module TLinkable where
|
|
| 58 | +import Language.Haskell.TH.Syntax (Lift(..))
|
|
| 59 | + |
|
| 60 | +-- Import all generated modules
|
|
| 61 | +${imports}
|
|
| 62 | +-- Hard-coded splice that references ALL functions from ALL modules
|
|
| 63 | +result :: Int
|
|
| 64 | +result = \$(lift \$ ${expression})
|
|
| 65 | + |
|
| 66 | +main :: IO ()
|
|
| 67 | +main = do
|
|
| 68 | + putStrLn \$ "Result: " ++ show result
|
|
| 69 | +EOF |