Matthew Pickering pushed to branch wip/gdc-files at Glasgow Haskell Compiler / GHC
Commits:
-
b76e8088
by Matthew Pickering at 2025-08-19T09:37:29+01:00
6 changed files:
- + compiler/GHC/Driver/ByteCode.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Linker/Deps.hs
- compiler/GHC/Linker/Loader.hs
- compiler/ghc.cabal.in
Changes:
1 | +module GHC.Driver.ByteCode where
|
|
2 | + |
|
3 | + |
|
4 | +import GHC.Prelude
|
|
5 | + |
|
6 | +import GHC.Driver.Session
|
|
7 | +import GHC.Driver.CodeOutput
|
|
8 | +import GHC.Driver.Env
|
|
9 | +import GHC.Runtime.Interpreter
|
|
10 | +import GHC.ByteCode.Types
|
|
11 | + |
|
12 | +import GHC.Linker.Types
|
|
13 | +import GHC.Tc.Utils.Monad
|
|
14 | + |
|
15 | +import GHC.Unit
|
|
16 | +import GHC.Types.ForeignStubs
|
|
17 | +import GHC.Data.Maybe
|
|
18 | + |
|
19 | +import Data.List.NonEmpty (NonEmpty ((:|)))
|
|
20 | +import {-# SOURCE #-} GHC.Driver.Pipeline
|
|
21 | +import Data.Time
|
|
22 | + |
|
23 | +import GHC.Platform.Ways
|
|
24 | + |
|
25 | +import GHC.ByteCode.Serialize
|
|
26 | + |
|
27 | +-- | Write foreign sources and foreign stubs to temporary files and compile them.
|
|
28 | +outputAndCompileForeign :: HscEnv -> Module -> ModLocation -> [(ForeignSrcLang, FilePath)] -> ForeignStubs -> IO [FilePath]
|
|
29 | +outputAndCompileForeign hsc_env mod_name location foreign_files foreign_stubs = do
|
|
30 | + let dflags = hsc_dflags hsc_env
|
|
31 | + logger = hsc_logger hsc_env
|
|
32 | + tmpfs = hsc_tmpfs hsc_env
|
|
33 | + (_, has_stub) <- outputForeignStubs logger tmpfs dflags (hsc_units hsc_env) mod_name location foreign_stubs
|
|
34 | + compile_for_interpreter hsc_env $ \ i_env -> do
|
|
35 | + stub_o <- traverse (compileForeign i_env LangC) has_stub
|
|
36 | + foreign_files_o <- traverse (uncurry (compileForeign i_env)) foreign_files
|
|
37 | + pure (maybeToList stub_o ++ foreign_files_o)
|
|
38 | + |
|
39 | +-- | Modify flags such that objects are compiled for the interpreter's way.
|
|
40 | +-- This is necessary when building foreign objects for Template Haskell, since
|
|
41 | +-- those are object code built outside of the pipeline, which means they aren't
|
|
42 | +-- subject to the mechanism in 'enableCodeGenWhen' that requests dynamic build
|
|
43 | +-- outputs for dependencies when the interpreter used for TH is dynamic but the
|
|
44 | +-- main outputs aren't.
|
|
45 | +-- Furthermore, the HPT only stores one set of objects with different names for
|
|
46 | +-- bytecode linking in 'HomeModLinkable', so the usual hack for switching
|
|
47 | +-- between ways in 'get_link_deps' doesn't work.
|
|
48 | +compile_for_interpreter :: HscEnv -> (HscEnv -> IO a) -> IO a
|
|
49 | +compile_for_interpreter hsc_env use =
|
|
50 | + use (hscUpdateFlags update hsc_env)
|
|
51 | + where
|
|
52 | + update dflags = dflags {
|
|
53 | + targetWays_ = adapt_way interpreterDynamic WayDyn $
|
|
54 | + adapt_way interpreterProfiled WayProf $
|
|
55 | + targetWays_ dflags
|
|
56 | + }
|
|
57 | + |
|
58 | + adapt_way want = if want (hscInterp hsc_env) then addWay else removeWay
|
|
59 | + |
|
60 | +-- | Write the foreign sources and foreign stubs of a bytecode object to temporary files and compile them.
|
|
61 | +loadByteCodeObject :: HscEnv -> ModLocation -> ByteCodeObject
|
|
62 | + -> IO (CompiledByteCode, [FilePath])
|
|
63 | +loadByteCodeObject hsc_env location (ByteCodeObject mod cbc foreign_srcs foreign_stubs) = do
|
|
64 | + fos <- outputAndCompileForeign hsc_env mod location foreign_srcs foreign_stubs
|
|
65 | + return (cbc, fos)
|
|
66 | + |
|
67 | +loadByteCodeObjectLinkable :: HscEnv -> UTCTime -> ModLocation -> ByteCodeObject -> IO Linkable
|
|
68 | +loadByteCodeObjectLinkable hsc_env linkable_time location bco = do
|
|
69 | + ~(cbc, fos) <- loadByteCodeObject hsc_env location bco
|
|
70 | + return $! Linkable linkable_time (bco_module bco) (BCOs cbc :| [DotO fo ForeignObject | fo <- fos]) |
|
\ No newline at end of file |
... | ... | @@ -116,6 +116,7 @@ import GHC.Driver.Plugins |
116 | 116 | import GHC.Driver.Session
|
117 | 117 | import GHC.Driver.Backend
|
118 | 118 | import GHC.Driver.Env
|
119 | +import GHC.Driver.ByteCode
|
|
119 | 120 | import GHC.Driver.Env.KnotVars
|
120 | 121 | import GHC.Driver.Errors
|
121 | 122 | import GHC.Driver.Messager
|
... | ... | @@ -290,12 +291,10 @@ import Data.List.NonEmpty (NonEmpty ((:|))) |
290 | 291 | import GHC.Unit.Module.WholeCoreBindings
|
291 | 292 | import GHC.Types.TypeEnv
|
292 | 293 | import System.IO
|
293 | -import {-# SOURCE #-} GHC.Driver.Pipeline
|
|
294 | 294 | import Data.Time
|
295 | 295 | |
296 | 296 | import System.IO.Unsafe ( unsafeInterleaveIO )
|
297 | 297 | import GHC.Iface.Env ( trace_if )
|
298 | -import GHC.Platform.Ways
|
|
299 | 298 | import GHC.Stg.EnforceEpt.TagSig (seqTagSig)
|
300 | 299 | import GHC.StgToCmm.Utils (IPEStats)
|
301 | 300 | import GHC.Types.Unique.FM
|
... | ... | @@ -884,6 +883,11 @@ hscRecompStatus |
884 | 883 | |
885 | 884 | let just_o = justObjects <$> obj_linkable
|
886 | 885 | |
886 | + bytecode_or_object_code
|
|
887 | + | gopt Opt_WriteByteCode lcl_dflags = justBytecode <$> definitely_bc
|
|
888 | + | otherwise = (justBytecode <$> maybe_bc) `choose` just_o
|
|
889 | + |
|
890 | + |
|
887 | 891 | definitely_both_os = case (bc_result, obj_linkable) of
|
888 | 892 | (UpToDateItem bc, UpToDateItem o) -> UpToDateItem (bytecodeAndObjects bc o)
|
889 | 893 | -- If missing object code, just say we need to recompile because of object code.
|
... | ... | @@ -899,8 +903,7 @@ hscRecompStatus |
899 | 903 | -- If not -fwrite-byte-code, then we could use core bindings or object code if that's available.
|
900 | 904 | maybe_bc = bc_in_memory_linkable `choose`
|
901 | 905 | bc_obj_linkable `choose`
|
902 | - bc_core_linkable `choose`
|
|
903 | - obj_linkable
|
|
906 | + bc_core_linkable
|
|
904 | 907 | |
905 | 908 | bc_result = if gopt Opt_WriteByteCode lcl_dflags
|
906 | 909 | -- If the byte-code artifact needs to be produced, then we certainly need bytecode.
|
... | ... | @@ -915,8 +918,8 @@ hscRecompStatus |
915 | 918 | -- pprTraceM "recomp" (ppr just_bc <+> ppr just_o)
|
916 | 919 | -- 2. Decide which of the products we will need
|
917 | 920 | let recomp_linkable_result = case () of
|
918 | - _ | backendCanReuseLoadedCode (backend lcl_dflags) ->
|
|
919 | - justBytecode <$> bc_result
|
|
921 | + _ | backendCanReuseLoadedCode (backend lcl_dflags) -> bytecode_or_object_code
|
|
922 | + |
|
920 | 923 | -- Need object files for making object files
|
921 | 924 | | backendWritesFiles (backend lcl_dflags) ->
|
922 | 925 | if gopt Opt_ByteCodeAndObjectCode lcl_dflags
|
... | ... | @@ -936,13 +939,13 @@ hscRecompStatus |
936 | 939 | |
937 | 940 | -- | Prefer requires both arguments to be up-to-date.
|
938 | 941 | -- but prefers to use the second argument.
|
939 | -prefer :: MaybeValidated Linkable -> MaybeValidated Linkable -> MaybeValidated Linkable
|
|
942 | +prefer :: MaybeValidated a -> MaybeValidated a -> MaybeValidated a
|
|
940 | 943 | prefer (UpToDateItem _) (UpToDateItem l2) = UpToDateItem l2
|
941 | 944 | prefer r1 _ = r1
|
942 | 945 | |
943 | 946 | -- | Disjunction, choose either argument, but prefer the first one.
|
944 | 947 | -- Report the failure of the first argument.
|
945 | -choose :: MaybeValidated Linkable -> MaybeValidated Linkable -> MaybeValidated Linkable
|
|
948 | +choose :: MaybeValidated a -> MaybeValidated a -> MaybeValidated a
|
|
946 | 949 | choose (UpToDateItem l1) _ = UpToDateItem l1
|
947 | 950 | choose _ (UpToDateItem l2) = UpToDateItem l2
|
948 | 951 | choose l1 _ = l1
|
... | ... | @@ -1052,26 +1055,6 @@ initModDetails hsc_env iface = |
1052 | 1055 | -- in make mode, since this HMI will go into the HPT.
|
1053 | 1056 | genModDetails hsc_env iface
|
1054 | 1057 | |
1055 | --- | Modify flags such that objects are compiled for the interpreter's way.
|
|
1056 | --- This is necessary when building foreign objects for Template Haskell, since
|
|
1057 | --- those are object code built outside of the pipeline, which means they aren't
|
|
1058 | --- subject to the mechanism in 'enableCodeGenWhen' that requests dynamic build
|
|
1059 | --- outputs for dependencies when the interpreter used for TH is dynamic but the
|
|
1060 | --- main outputs aren't.
|
|
1061 | --- Furthermore, the HPT only stores one set of objects with different names for
|
|
1062 | --- bytecode linking in 'HomeModLinkable', so the usual hack for switching
|
|
1063 | --- between ways in 'get_link_deps' doesn't work.
|
|
1064 | -compile_for_interpreter :: HscEnv -> (HscEnv -> IO a) -> IO a
|
|
1065 | -compile_for_interpreter hsc_env use =
|
|
1066 | - use (hscUpdateFlags update hsc_env)
|
|
1067 | - where
|
|
1068 | - update dflags = dflags {
|
|
1069 | - targetWays_ = adapt_way interpreterDynamic WayDyn $
|
|
1070 | - adapt_way interpreterProfiled WayProf $
|
|
1071 | - targetWays_ dflags
|
|
1072 | - }
|
|
1073 | - |
|
1074 | - adapt_way want = if want (hscInterp hsc_env) then addWay else removeWay
|
|
1075 | 1058 | |
1076 | 1059 | -- | Assemble 'WholeCoreBindings' if the interface contains Core bindings.
|
1077 | 1060 | iface_core_bindings :: ModIface -> ModLocation -> Maybe WholeCoreBindings
|
... | ... | @@ -2257,30 +2240,6 @@ generateAndWriteByteCodeLinkable hsc_env cgguts mod_location = do |
2257 | 2240 | bco_time <- maybe getCurrentTime pure =<< modificationTimeIfExists (ml_bytecode_file mod_location)
|
2258 | 2241 | loadByteCodeObjectLinkable hsc_env bco_time mod_location bco_object
|
2259 | 2242 | |
2260 | --- | Write foreign sources and foreign stubs to temporary files and compile them.
|
|
2261 | -outputAndCompileForeign :: HscEnv -> Module -> ModLocation -> [(ForeignSrcLang, FilePath)] -> ForeignStubs -> IO [FilePath]
|
|
2262 | -outputAndCompileForeign hsc_env mod_name location foreign_files foreign_stubs = do
|
|
2263 | - let dflags = hsc_dflags hsc_env
|
|
2264 | - logger = hsc_logger hsc_env
|
|
2265 | - tmpfs = hsc_tmpfs hsc_env
|
|
2266 | - (_, has_stub) <- outputForeignStubs logger tmpfs dflags (hsc_units hsc_env) mod_name location foreign_stubs
|
|
2267 | - compile_for_interpreter hsc_env $ \ i_env -> do
|
|
2268 | - stub_o <- traverse (compileForeign i_env LangC) has_stub
|
|
2269 | - foreign_files_o <- traverse (uncurry (compileForeign i_env)) foreign_files
|
|
2270 | - pure (maybeToList stub_o ++ foreign_files_o)
|
|
2271 | - |
|
2272 | --- | Write the foreign sources and foreign stubs of a bytecode object to temporary files and compile them.
|
|
2273 | -loadByteCodeObject :: HscEnv -> ModLocation -> ByteCodeObject
|
|
2274 | - -> IO (CompiledByteCode, [FilePath])
|
|
2275 | -loadByteCodeObject hsc_env location (ByteCodeObject mod cbc foreign_srcs foreign_stubs) = do
|
|
2276 | - fos <- outputAndCompileForeign hsc_env mod location foreign_srcs foreign_stubs
|
|
2277 | - return (cbc, fos)
|
|
2278 | - |
|
2279 | -loadByteCodeObjectLinkable :: HscEnv -> UTCTime -> ModLocation -> ByteCodeObject -> IO Linkable
|
|
2280 | -loadByteCodeObjectLinkable hsc_env linkable_time location bco = do
|
|
2281 | - (cbc, fos) <- loadByteCodeObject hsc_env location bco
|
|
2282 | - return $! Linkable linkable_time (bco_module bco) (BCOs cbc :| [DotO fo ForeignObject | fo <- fos])
|
|
2283 | - |
|
2284 | 2243 | mkByteCodeObject :: HscEnv -> Module -> ModLocation -> CgInteractiveGuts -> IO ByteCodeObject
|
2285 | 2244 | mkByteCodeObject hsc_env mod mod_location cgguts = do
|
2286 | 2245 | bcos <- hscGenerateByteCode hsc_env cgguts mod_location
|
... | ... | @@ -187,7 +187,9 @@ mkObjectUsage pit plugins fc hug th_links_needed th_pkgs_needed = do |
187 | 187 | -- home package ifaces in the PIT.
|
188 | 188 | miface <- lookupIfaceByModule hug pit m
|
189 | 189 | case miface of
|
190 | - Nothing -> pprPanic "mkObjectUsage" (ppr m)
|
|
190 | + -- TODO: MP: This is wrong, a placeholder for now.
|
|
191 | + -- We need to work out what to do for bytecode linkables which are not loaded into HPT
|
|
192 | + Nothing -> return $ UsageHomeModuleInterface (moduleName m) (toUnitId $ moduleUnit m) fingerprint0
|
|
191 | 193 | Just iface ->
|
192 | 194 | return $ UsageHomeModuleInterface (moduleName m) (toUnitId $ moduleUnit m) (mi_iface_hash iface)
|
193 | 195 |
... | ... | @@ -59,7 +59,7 @@ data LinkDepsOpts = LinkDepsOpts |
59 | 59 | , ldWays :: !Ways -- ^ Enabled ways
|
60 | 60 | , ldFinderCache :: !FinderCache
|
61 | 61 | , ldFinderOpts :: !FinderOpts
|
62 | - , ldLoadByteCode :: !(Module -> IO (Maybe Linkable))
|
|
62 | + , ldLoadByteCode :: !(Module -> ModLocation -> IO (Maybe Linkable))
|
|
63 | 63 | , ldGetDependencies :: !([Module] -> IO ([Module], UniqDSet UnitId))
|
64 | 64 | }
|
65 | 65 | |
... | ... | @@ -161,8 +161,15 @@ get_link_deps opts pls maybe_normal_osuf span mods = do |
161 | 161 | case ue_homeUnit unit_env of
|
162 | 162 | Nothing -> no_obj mod
|
163 | 163 | Just home_unit -> do
|
164 | - from_bc <- ldLoadByteCode opts mod
|
|
165 | - maybe (fallback_no_bytecode home_unit mod) pure from_bc
|
|
164 | + |
|
165 | + let fc = ldFinderCache opts
|
|
166 | + let fopts = ldFinderOpts opts
|
|
167 | + mb_stuff <- findHomeModule fc fopts home_unit (moduleName mod)
|
|
168 | + case mb_stuff of
|
|
169 | + Found loc _ -> do
|
|
170 | + from_bc <- ldLoadByteCode opts mod loc
|
|
171 | + maybe (fallback_no_bytecode home_unit mod) pure from_bc
|
|
172 | + _ -> fallback_no_bytecode home_unit mod
|
|
166 | 173 | where
|
167 | 174 | |
168 | 175 | fallback_no_bytecode home_unit mod = do
|
... | ... | @@ -39,6 +39,7 @@ where |
39 | 39 | import GHC.Prelude
|
40 | 40 | |
41 | 41 | import GHC.Settings
|
42 | +import GHC.Utils.Misc
|
|
42 | 43 | |
43 | 44 | import GHC.Platform
|
44 | 45 | import GHC.Platform.Ways
|
... | ... | @@ -48,6 +49,7 @@ import GHC.Driver.Phases |
48 | 49 | import GHC.Driver.Env
|
49 | 50 | import GHC.Driver.Session
|
50 | 51 | import GHC.Driver.Ppr
|
52 | +import GHC.Driver.ByteCode
|
|
51 | 53 | import GHC.Driver.Config.Diagnostic
|
52 | 54 | import GHC.Driver.Config.Finder
|
53 | 55 | |
... | ... | @@ -129,6 +131,7 @@ import qualified GHC.Runtime.Interpreter as GHCi |
129 | 131 | import qualified Data.IntMap.Strict as IM
|
130 | 132 | import qualified Data.Map.Strict as M
|
131 | 133 | import Foreign.Ptr (nullPtr)
|
134 | +import GHC.ByteCode.Serialize
|
|
132 | 135 | |
133 | 136 | -- Note [Linkers and loaders]
|
134 | 137 | -- ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
... | ... | @@ -628,7 +631,14 @@ initLinkDepsOpts hsc_env = opts |
628 | 631 | }
|
629 | 632 | dflags = hsc_dflags hsc_env
|
630 | 633 | |
631 | - ldLoadByteCode mod = do
|
|
634 | + ldLoadByteCode mod locn = do
|
|
635 | + bco <- findBytecodeLinkableMaybe hsc_env mod locn
|
|
636 | + case bco of
|
|
637 | + Nothing -> findWholeCoreBindings hsc_env mod
|
|
638 | + Just bco -> return (Just bco)
|
|
639 | + |
|
640 | +findWholeCoreBindings :: HscEnv -> Module -> IO (Maybe Linkable)
|
|
641 | +findWholeCoreBindings hsc_env mod = do
|
|
632 | 642 | _ <- initIfaceLoad hsc_env $
|
633 | 643 | loadInterface (text "get_reachable_nodes" <+> parens (ppr mod))
|
634 | 644 | mod ImportBySystem
|
... | ... | @@ -636,6 +646,16 @@ initLinkDepsOpts hsc_env = opts |
636 | 646 | sequence (lookupModuleEnv eps_iface_bytecode mod)
|
637 | 647 | |
638 | 648 | |
649 | +findBytecodeLinkableMaybe :: HscEnv -> Module -> ModLocation -> IO (Maybe Linkable)
|
|
650 | +findBytecodeLinkableMaybe hsc_env _mod locn = do
|
|
651 | + let bytecode_fn = ml_bytecode_file locn
|
|
652 | + maybe_bytecode_time <- modificationTimeIfExists bytecode_fn
|
|
653 | + case maybe_bytecode_time of
|
|
654 | + Nothing -> return Nothing
|
|
655 | + Just bytecode_time -> do
|
|
656 | + bco <- readBinByteCode hsc_env bytecode_fn
|
|
657 | + Just <$> loadByteCodeObjectLinkable hsc_env bytecode_time locn bco
|
|
658 | + |
|
639 | 659 | get_reachable_nodes :: HscEnv -> [Module] -> IO ([Module], UniqDSet UnitId)
|
640 | 660 | get_reachable_nodes hsc_env mods
|
641 | 661 |
... | ... | @@ -490,6 +490,7 @@ Library |
490 | 490 | GHC.Driver.Backend.Internal
|
491 | 491 | GHC.Driver.Backpack
|
492 | 492 | GHC.Driver.Backpack.Syntax
|
493 | + GHC.Driver.ByteCode
|
|
493 | 494 | GHC.Driver.CmdLine
|
494 | 495 | GHC.Driver.CodeOutput
|
495 | 496 | GHC.Driver.Config
|