Zubin pushed to branch wip/linkable-hashes at Glasgow Haskell Compiler / GHC

Commits:

15 changed files:

Changes:

  • compiler/GHC/ByteCode/Serialize.hs
    ... ... @@ -6,7 +6,7 @@
    6 6
     {- | This module implements the serialization of bytecode objects to and from disk.
    
    7 7
     -}
    
    8 8
     module GHC.ByteCode.Serialize
    
    9
    -  ( writeBinByteCode, readBinByteCode, readOnDiskModuleByteCode
    
    9
    +  ( writeBinByteCode, readBinByteCode, readBinByteCodeHash, readOnDiskModuleByteCode
    
    10 10
       , ModuleByteCode(..)
    
    11 11
       , BytecodeLibX(..)
    
    12 12
       , BytecodeLib
    
    ... ... @@ -15,6 +15,7 @@ module GHC.ByteCode.Serialize
    15 15
       , InterpreterLibraryContents(..)
    
    16 16
       , writeBytecodeLib
    
    17 17
       , readBytecodeLib
    
    18
    +  , readBytecodeLibInputsHash
    
    18 19
       , mkModuleByteCode
    
    19 20
       , fingerprintModuleByteCodeContents
    
    20 21
       , decodeOnDiskModuleByteCode
    
    ... ... @@ -84,6 +85,7 @@ The ticket where bytecode objects were dicussed is #26298
    84 85
     See Note [-fwrite-byte-code is not the default]
    
    85 86
     See Note [Recompilation avoidance with bytecode objects]
    
    86 87
     See Note [Persistent bytecode file headers]
    
    88
    +See Note [Hash of bytecode libs]
    
    87 89
     
    
    88 90
     Note [Persistent bytecode file headers]
    
    89 91
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    ... ... @@ -96,15 +98,28 @@ To make these failures explicit, we write a file-kind-specific magic word and
    96 98
     the current `hiVersion` ahead of the binary payload. Readers validate this
    
    97 99
     header before setting up the normal `Name`/`FastString` deserialisation
    
    98 100
     machinery. This follows the same approach as normal interface files.
    
    101
    +
    
    102
    +Note [Hash of bytecode libs]
    
    103
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    104
    +A bytecode library records the combined hash of its constituents, so
    
    105
    +that relinking can be skipped when they haven't changed.
    
    106
    +
    
    107
    +We can't hash the library file itself: we would have to build the
    
    108
    +library to know which hash to expect. So we compare the inputs.
    
    109
    +
    
    110
    +The hash is written right after the file header. The constituent hashes
    
    111
    +are sorted before they are combined, so the order of the modules
    
    112
    +doesn't matter.
    
    99 113
     -}
    
    100 114
     
    
    101
    -writeBytecodeLib :: BytecodeLib -> FilePath -> IO ()
    
    102
    -writeBytecodeLib lib path = do
    
    115
    +writeBytecodeLib :: Fingerprint -> BytecodeLib -> FilePath -> IO ()
    
    116
    +writeBytecodeLib inputs_hash lib path = do
    
    103 117
       odbco <- encodeBytecodeLib lib
    
    104 118
       createDirectoryIfMissing True (takeDirectory path)
    
    105 119
       bh' <- openBinMem initBinMemSize
    
    106 120
       bh <- addBinNameWriter bh'
    
    107 121
       writePersistentBytecodeHeader BytecodeLibraryFile bh
    
    122
    +  put_ bh inputs_hash
    
    108 123
       putWithUserData QuietBinIFace NormalCompression bh odbco
    
    109 124
       writeBinMem bh path
    
    110 125
     
    
    ... ... @@ -112,10 +127,18 @@ readBytecodeLib :: HscEnv -> FilePath -> IO OnDiskBytecodeLib
    112 127
     readBytecodeLib hsc_env path = do
    
    113 128
       bh' <- readBinMem path
    
    114 129
       readPersistentBytecodeHeader BytecodeLibraryFile path bh'
    
    130
    +  _inputs_hash <- get bh' :: IO Fingerprint
    
    115 131
       bh <- addBinNameReader (hsc_NC hsc_env) bh'
    
    116 132
       res <- getWithUserData (hsc_NC hsc_env) bh
    
    117 133
       pure res
    
    118 134
     
    
    135
    +-- See Note [Hash of bytecode libs]
    
    136
    +readBytecodeLibInputsHash :: FilePath -> IO Fingerprint
    
    137
    +readBytecodeLibInputsHash path = do
    
    138
    +  bh <- readBinMem path
    
    139
    +  readPersistentBytecodeHeader BytecodeLibraryFile path bh
    
    140
    +  get bh
    
    141
    +
    
    119 142
     -- | Convert an 'OnDiskModuleByteCode' to an 'ModuleByteCode'.
    
    120 143
     -- 'OnDiskModuleByteCode' is the representation which we read from a file,
    
    121 144
     -- the 'ModuleByteCode' is the representation which is manipulated by program logic.
    
    ... ... @@ -200,6 +223,10 @@ readBinByteCode hsc_env f = do
    200 223
       odbco <- readOnDiskModuleByteCode hsc_env f
    
    201 224
       decodeOnDiskModuleByteCode hsc_env odbco
    
    202 225
     
    
    226
    +-- | Read only the hash from the start of a bytecode file
    
    227
    +readBinByteCodeHash :: HscEnv -> FilePath -> IO Fingerprint
    
    228
    +readBinByteCodeHash hsc_env f = odgbc_hash <$> readOnDiskModuleByteCode hsc_env f
    
    229
    +
    
    203 230
     readOnDiskModuleByteCode :: HscEnv -> FilePath -> IO OnDiskModuleByteCode
    
    204 231
     readOnDiskModuleByteCode hsc_env f = do
    
    205 232
       bh' <- readBinMem f
    

  • compiler/GHC/Driver/Main/Compile.hs
    ... ... @@ -132,7 +132,6 @@ import GHC.Data.OsPath (unsafeEncodeUtf)
    132 132
     import qualified GHC.Data.Stream as Stream
    
    133 133
     
    
    134 134
     
    
    135
    -import Data.Traversable (for)
    
    136 135
     import Control.Monad
    
    137 136
     import Data.IORef
    
    138 137
     import System.Directory
    
    ... ... @@ -141,7 +140,6 @@ import Data.Map (Map)
    141 140
     import qualified Data.Set as S
    
    142 141
     import GHC.Unit.Module.WholeCoreBindings
    
    143 142
     import GHC.Types.TypeEnv
    
    144
    -import Data.Time
    
    145 143
     
    
    146 144
     import System.IO.Unsafe ( unsafeInterleaveIO )
    
    147 145
     import GHC.Iface.Env ( trace_if )
    
    ... ... @@ -218,12 +216,7 @@ loadIfaceByteCode hsc_env iface location type_env =
    218 216
       where
    
    219 217
         compile decls = do
    
    220 218
           bco <- compileWholeCoreBindings hsc_env type_env decls
    
    221
    -      linkable $ pure $ DotGBC bco
    
    222
    -
    
    223
    -    linkable parts = do
    
    224
    -      if_time <- modificationTimeIfExists (ml_hi_file_ospath location)
    
    225
    -      time <- maybe getCurrentTime pure if_time
    
    226
    -      return $! Linkable time (mi_module iface) parts
    
    219
    +      return $! Linkable (gbc_hash bco) (mi_module iface) (pure (DotGBC bco))
    
    227 220
     
    
    228 221
     loadIfaceByteCodeLazy ::
    
    229 222
       HscEnv ->
    
    ... ... @@ -240,12 +233,7 @@ loadIfaceByteCodeLazy hsc_env iface location type_env =
    240 233
         compile decls = do
    
    241 234
           bco <- unsafeInterleaveIO $ do
    
    242 235
               compileWholeCoreBindings hsc_env type_env decls
    
    243
    -      linkable bco
    
    244
    -
    
    245
    -    linkable parts = do
    
    246
    -      if_time <- modificationTimeIfExists (ml_hi_file_ospath location)
    
    247
    -      time <- maybe getCurrentTime pure if_time
    
    248
    -      return $!Linkable time (mi_module iface) parts
    
    236
    +      return $! Linkable (gbc_hash bco) (mi_module iface) bco
    
    249 237
     
    
    250 238
     -- | If the 'Linkable' contains Core bindings loaded from an interface, replace
    
    251 239
     -- them with a lazy IO thunk that compiles them to bytecode and foreign objects,
    
    ... ... @@ -283,12 +271,13 @@ initWholeCoreBindings hsc_env iface details (RecompLinkables bc o) = do
    283 271
     
    
    284 272
         go :: RecompBytecodeLinkable -> IO (Maybe (LinkableWith ModuleByteCode))
    
    285 273
         go (NormalLinkable l) = pure l
    
    286
    -    go (WholeCoreBindingsLinkable wcbl) =
    
    287
    -      fmap Just $ for wcbl $ \wcb -> do
    
    288
    -        add_iface_to_hpt iface details hsc_env
    
    289
    -        bco <- unsafeInterleaveIO $ do
    
    290
    -            compileWholeCoreBindings hsc_env type_env wcb
    
    291
    -        pure bco
    
    274
    +    go (WholeCoreBindingsLinkable wcbl) = do
    
    275
    +      add_iface_to_hpt iface details hsc_env
    
    276
    +      bco <- unsafeInterleaveIO $ do
    
    277
    +          compileWholeCoreBindings hsc_env type_env (linkableParts wcbl)
    
    278
    +      -- We need to fill in the hash over here, replacing the panic
    
    279
    +      -- because WholeCoreBindingsLinkable doesn't have a hash.
    
    280
    +      pure $ Just $ Linkable (gbc_hash bco) (linkableModule wcbl) bco
    
    292 281
     
    
    293 282
     -- | Hydrate interface Core bindings and compile them to bytecode.
    
    294 283
     --
    
    ... ... @@ -842,11 +831,7 @@ make user's opt into writing the files.
    842 831
     generateAndWriteByteCodeLinkable :: HscEnv -> CgInteractiveGuts -> ModLocation -> IO (LinkableWith ModuleByteCode)
    
    843 832
     generateAndWriteByteCodeLinkable hsc_env cgguts mod_location = do
    
    844 833
       bco_object <- generateAndWriteByteCode hsc_env cgguts mod_location
    
    845
    -  -- Either, get the same time as the .gbc file if it exists, or just the current time.
    
    846
    -  -- It's important the time of the linkable matches the time of the .gbc file for recompilation
    
    847
    -  -- checking.
    
    848
    -  bco_time <- maybe getCurrentTime pure =<< modificationTimeIfExists (ml_bytecode_file_ospath mod_location)
    
    849
    -  return $ mkOnlyModuleByteCodeLinkable bco_time bco_object
    
    834
    +  return $ mkOnlyModuleByteCodeLinkable bco_object
    
    850 835
     
    
    851 836
     mkModuleByteCode :: HscEnv -> Module -> ModLocation -> CgInteractiveGuts -> IO ModuleByteCode
    
    852 837
     mkModuleByteCode hsc_env mod mod_location cgguts = do
    
    ... ... @@ -861,9 +846,8 @@ generateFreshByteCodeLinkable :: HscEnv
    861 846
       -> ModLocation
    
    862 847
       -> IO Linkable
    
    863 848
     generateFreshByteCodeLinkable hsc_env mod_name cgguts mod_location = do
    
    864
    -  bco_time <- getCurrentTime
    
    865 849
       bco_object <- mkModuleByteCode hsc_env (mkHomeModule (hsc_home_unit hsc_env) mod_name) mod_location cgguts
    
    866
    -  return $ mkModuleByteCodeLinkable bco_time bco_object
    
    850
    +  return $ mkModuleByteCodeLinkable bco_object
    
    867 851
     ------------------------------
    
    868 852
     
    
    869 853
     hscCompileCmmFile :: HscEnv -> FilePath -> FilePath -> FilePath -> IO (Maybe FilePath)
    

  • compiler/GHC/Driver/Main/Passes.hs
    ... ... @@ -153,7 +153,7 @@ import GHC.Types.Unique.Set
    153 153
     import GHC.Types.Var.Env       ( mkEmptyTidyEnv )
    
    154 154
     import GHC.Types.Var.Set
    
    155 155
     
    
    156
    -import GHC.Utils.Fingerprint ( Fingerprint )
    
    156
    +import GHC.Utils.Fingerprint ( Fingerprint, getFileHash )
    
    157 157
     import GHC.Utils.Panic
    
    158 158
     import GHC.Utils.Error
    
    159 159
     import GHC.Utils.Outputable
    
    ... ... @@ -168,8 +168,8 @@ import GHC.Data.Maybe
    168 168
     import qualified GHC.Data.Strict as Strict
    
    169 169
     
    
    170 170
     import qualified Data.Array as A
    
    171
    -import Data.List ( nub, isPrefixOf, partition )
    
    172 171
     import qualified Data.List.NonEmpty as NE
    
    172
    +import Data.List ( nub, isPrefixOf, partition )
    
    173 173
     import Control.Monad
    
    174 174
     import Data.IORef
    
    175 175
     import System.FilePath as FilePath
    
    ... ... @@ -180,7 +180,6 @@ import Data.Set (Set)
    180 180
     import Control.DeepSeq (force)
    
    181 181
     import Control.Exception as E (mask_, finally)
    
    182 182
     import Data.List.NonEmpty (NonEmpty ((:|)))
    
    183
    -import Data.Time
    
    184 183
     
    
    185 184
     import System.IO.Unsafe ( unsafeInterleaveIO )
    
    186 185
     import GHC.Iface.Env ( trace_if )
    
    ... ... @@ -707,15 +706,24 @@ checkObjects dflags mb_old_linkable summary = do
    707 706
           -- Not in dynamic-too mode
    
    708 707
           else k
    
    709 708
     
    
    709
    +  -- We check by date first, even though we have the hash
    
    710
    +  -- If a compilation is interupted after writing the .hi
    
    711
    +  -- but before writing the .o, then we catch this through
    
    712
    +  -- modtimes.
    
    713
    +  -- If the object file is newer than the .hi file, and the
    
    714
    +  -- .hi file is up to date, we also assume the object file
    
    715
    +  -- is up to date.
    
    710 716
       checkDynamicObj $
    
    711 717
         case (,) <$> mb_obj_date <*> mb_if_date of
    
    712 718
           Just (obj_date, if_date)
    
    713
    -        | obj_date >= if_date ->
    
    719
    +        | obj_date >= if_date -> do
    
    720
    +            disk_hash <- getFileHash obj_fn
    
    714 721
                 case mb_old_linkable of
    
    715 722
                   Just old_linkable
    
    716
    -                | linkableIsNativeCodeOnly old_linkable, linkableTime old_linkable == obj_date
    
    723
    +                | linkableIsNativeCodeOnly old_linkable
    
    724
    +                , linkableHash old_linkable == disk_hash
    
    717 725
                     -> return $ UpToDateItem old_linkable
    
    718
    -              _ -> UpToDateItem <$> findObjectLinkable this_mod obj_fn obj_date
    
    726
    +              _ -> return $ UpToDateItem (findObjectLinkable this_mod obj_fn disk_hash)
    
    719 727
           _ -> return $ outOfDateItemBecause MissingObjectFile Nothing
    
    720 728
     
    
    721 729
     -- | Check to see if we can reuse the old linkable, by this point we will
    
    ... ... @@ -724,15 +732,22 @@ checkObjects dflags mb_old_linkable summary = do
    724 732
     checkByteCodeInMemory :: HscEnv -> ModSummary -> Maybe (LinkableWith ModuleByteCode) -> IO (MaybeValidated (LinkableWith ModuleByteCode))
    
    725 733
     checkByteCodeInMemory hsc_env mod_sum mb_old_linkable =
    
    726 734
       case mb_old_linkable of
    
    727
    -    Just old_linkable
    
    735
    +    Just old_linkable -> do
    
    728 736
           -- If `-fwrite-byte-code` is enabled, then check that the .gbc file is
    
    729 737
           -- up-to-date with the linkable we have in our hand.
    
    730 738
           -- If ms_bytecode_date is Nothing, then the .gbc file does not exist yet.
    
    731
    -      -- Otherwise, check that the date matches the linkable date exactly.
    
    732
    -      | if gopt Opt_WriteByteCode (hsc_dflags hsc_env)
    
    733
    -          then maybe False (linkableTime old_linkable ==) (ms_bytecode_date mod_sum)
    
    734
    -          else True
    
    735
    -      -> return $ (UpToDateItem old_linkable)
    
    739
    +      -- Otherwise, check that the hash matches the disk.
    
    740
    +      ok <- if gopt Opt_WriteByteCode (hsc_dflags hsc_env)
    
    741
    +              then case ms_bytecode_date mod_sum of
    
    742
    +                     Nothing -> pure False
    
    743
    +                     Just _ -> do
    
    744
    +                       disk_hash <- ByteCode.readBinByteCodeHash hsc_env
    
    745
    +                                      (ml_bytecode_file (ms_location mod_sum))
    
    746
    +                       pure (disk_hash == linkableHash old_linkable)
    
    747
    +              else pure True
    
    748
    +      if ok
    
    749
    +        then return (UpToDateItem old_linkable)
    
    750
    +        else return $ outOfDateItemBecause MissingBytecode Nothing
    
    736 751
         _ -> return $ outOfDateItemBecause MissingBytecode Nothing
    
    737 752
     
    
    738 753
     -- | Load bytecode from a ".gbc" object file if it exists and is up-to-date
    
    ... ... @@ -749,7 +764,7 @@ checkByteCodeFromObject hsc_env mod_sum = do
    749 764
               -- that the one we have on disk would be suitable as well.
    
    750 765
               linkable <- unsafeInterleaveIO $ do
    
    751 766
                 bco <- ByteCode.readBinByteCode hsc_env obj_fn
    
    752
    -            return $ mkOnlyModuleByteCodeLinkable obj_date bco
    
    767
    +            return $ mkOnlyModuleByteCodeLinkable bco
    
    753 768
               return $ UpToDateItem linkable
    
    754 769
         _ -> return $ outOfDateItemBecause MissingBytecode Nothing
    
    755 770
     
    
    ... ... @@ -759,9 +774,11 @@ checkByteCodeFromIfaceCoreBindings :: HscEnv -> ModIface -> ModSummary -> IO (Ma
    759 774
     checkByteCodeFromIfaceCoreBindings _hsc_env iface mod_sum = do
    
    760 775
         let
    
    761 776
           this_mod   = ms_mod mod_sum
    
    762
    -      if_date    = fromJust $ ms_iface_date mod_sum
    
    777
    +      -- This hash isn't used, initWholeCoreBindings will replace it
    
    778
    +      -- with a real linkable with bytecode that has a hash.
    
    779
    +      wcb_hash   = panic "linkableHash: WholeCoreBindingsLinkable"
    
    763 780
         case iface_core_bindings iface (ms_location mod_sum) of
    
    764
    -      Just fi -> return $ UpToDateItem (Linkable if_date this_mod fi)
    
    781
    +      Just fi -> return $ UpToDateItem (Linkable wcb_hash this_mod fi)
    
    765 782
           _ -> return $ outOfDateItemBecause MissingBytecode Nothing
    
    766 783
     
    
    767 784
     
    
    ... ... @@ -1621,10 +1638,9 @@ hscCompileCoreExpr' hsc_env srcspan ds_expr = do
    1621 1638
                     Strict.Nothing -- no hpc info
    
    1622 1639
     
    
    1623 1640
           {- load it -}
    
    1624
    -      bco_time <- getCurrentTime
    
    1625 1641
           mbc <- ByteCode.mkModuleByteCode this_mod bcos []
    
    1626 1642
           (mods_needed, units_needed) <- loadDecls interp hsc_env srcspan $
    
    1627
    -        Linkable bco_time this_mod $ NE.singleton (DotGBC mbc)
    
    1643
    +        mkModuleByteCodeLinkable mbc
    
    1628 1644
           -- Get the foreign reference to the name we should have just loaded.
    
    1629 1645
           mhvs <- lookupFromLoadedEnv interp (idName binding_id)
    
    1630 1646
           {- Get the HValue for the root -}
    
    ... ... @@ -1683,7 +1699,7 @@ jsCodeGen hsc_env srcspan i this_mod stg_binds_with_deps binding_id = do
    1683 1699
         -- state independently to load new objects here.
    
    1684 1700
     
    
    1685 1701
         let objs = mapMaybe linkableFilterNative (ldNeededLinkables deps)
    
    1686
    -        (objs_loaded', _new_objs) = rmDupLinkables (objs_loaded pls) objs
    
    1702
    +        (objs_loaded', _new_objs) = rmDupLinkables Nothing (objs_loaded pls) objs
    
    1687 1703
     
    
    1688 1704
         -- Compute LoadedPkgInfo metadata for recompilation avoidance.
    
    1689 1705
         -- We don't call loadPackages' because the JS interpreter doesn't load
    

  • compiler/GHC/Driver/Pipeline.hs
    ... ... @@ -126,9 +126,11 @@ import qualified Control.Monad.Catch as MC (handle, mask, onException)
    126 126
     import Data.Maybe
    
    127 127
     import qualified Data.Set as Set
    
    128 128
     import qualified Data.List.NonEmpty as NE
    
    129
    +import Data.List (sort)
    
    129 130
     import Data.List.NonEmpty (NonEmpty(..))
    
    130 131
     
    
    131
    -import Data.Time ( getCurrentTime )
    
    132
    +import GHC.Utils.Fingerprint ( fingerprintFingerprints, getFileHash )
    
    133
    +import GHC.ByteCode.Serialize ( readBytecodeLibInputsHash )
    
    132 134
     import GHC.Tc.Utils.Monad (shutdownTcMPluginsIO, FrontendResult (..), tcg_plugins)
    
    133 135
     
    
    134 136
     
    
    ... ... @@ -547,11 +549,13 @@ checkBytecodeLibraryLinkingNeeded _logger dflags unit_env linkables _pkg_deps =
    547 549
       e_bytecode_lib_time <- modificationTimeIfExists exe_file_os
    
    548 550
       case e_bytecode_lib_time of
    
    549 551
         Nothing  -> return $ NeedsRecompile MustCompile
    
    550
    -    Just t -> do
    
    551
    -        let bytecode_times =  map linkableTime linkables
    
    552
    -        if any (t <) bytecode_times
    
    553
    -            then return $ needsRecompileBecause ObjectsChanged
    
    554
    -            else return UpToDate
    
    552
    +    Just _ -> do
    
    553
    +        -- See Note [Hash of bytecode libs] in GHC.ByteCode.Serialize
    
    554
    +        e_recorded <- tryIO (readBytecodeLibInputsHash exe_file)
    
    555
    +        let current = fingerprintFingerprints (sort (map linkableHash linkables))
    
    556
    +        case e_recorded of
    
    557
    +          Right recorded | recorded == current -> return UpToDate
    
    558
    +          _ -> return $ needsRecompileBecause ObjectsChanged
    
    555 559
     
    
    556 560
     checkNativeLibraryLinkingNeeded :: Bool -> Logger -> DynFlags -> UnitEnv -> [Linkable] -> [UnitId] -> IO RecompileRequired
    
    557 561
     checkNativeLibraryLinkingNeeded staticLink _ dflags unit_env linkables pkg_deps = do
    
    ... ... @@ -576,8 +580,9 @@ checkNativeLibraryLinkingNeeded staticLink _ dflags unit_env linkables pkg_deps
    576 580
         Just t -> do
    
    577 581
             -- first check object files and extra_ld_inputs
    
    578 582
             let extra_ld_inputs = [ f | FileOption _ f <- ldInputs dflags ]
    
    579
    -        (errs,extra_times) <- partitionWithM (tryIO . getModificationUTCTime) extra_ld_inputs
    
    580
    -        let obj_times =  map linkableTime linkables ++ extra_times
    
    583
    +            obj_files = concatMap linkableFiles linkables
    
    584
    +        (errs,obj_times) <- partitionWithM (tryIO . getModificationUTCTime)
    
    585
    +                              (obj_files ++ extra_ld_inputs)
    
    581 586
             if not (null errs) || any (t <) obj_times
    
    582 587
                 then return $ needsRecompileBecause ObjectsChanged
    
    583 588
                 else do
    
    ... ... @@ -936,9 +941,9 @@ hscGenBackendPipeline pipe_env hsc_env mod_sum result = do
    936 941
           -- No object file produced, bytecode or NoBackend
    
    937 942
           Nothing -> return mlinkable
    
    938 943
           Just o_fp -> do
    
    939
    -        part_time <- liftIO getCurrentTime
    
    940 944
             final_object <- use (T_MergeForeign pipe_env hsc_env o_fp fos)
    
    941
    -        let !linkable = Linkable part_time (ms_mod mod_sum) (NE.singleton (DotO final_object ModuleObject))
    
    945
    +        !obj_hash <- liftIO $ getFileHash final_object
    
    946
    +        let !linkable = Linkable obj_hash (ms_mod mod_sum) (NE.singleton (DotO final_object ModuleObject))
    
    942 947
             -- Add the object linkable to the potential bytecode linkable which was generated in HscBackend.
    
    943 948
             return (mlinkable { homeMod_object = Just linkable })
    
    944 949
     
    

  • compiler/GHC/Linker/ByteCode.hs
    ... ... @@ -8,7 +8,8 @@ import GHC.Utils.Error
    8 8
     import GHC.Driver.Env
    
    9 9
     import GHC.Utils.Outputable
    
    10 10
     import GHC.Linker.Loader
    
    11
    -import Data.List (partition)
    
    11
    +import Data.List (partition, sort)
    
    12
    +import GHC.Utils.Fingerprint (fingerprintFingerprints)
    
    12 13
     import GHC.Driver.Phases (isBytecodeFilename)
    
    13 14
     import GHC.Runtime.Interpreter (interpreterDynamic)
    
    14 15
     import Data.Maybe
    
    ... ... @@ -40,8 +41,10 @@ linkBytecodeLib hsc_env gbcs = do
    40 41
         bytecodeLibFiles = all_cbcs,
    
    41 42
         bytecodeLibForeign = interpreter_foreign_lib
    
    42 43
       }
    
    44
    +  let inputs_hash = fingerprintFingerprints
    
    45
    +        (sort [ gbc_hash m | m <- on_disk_bcos ++ gbcs ])
    
    43 46
       let output_fn = fromMaybe "a.out" (outputFile dflags)
    
    44
    -  writeBytecodeLib bytecodeLib' output_fn
    
    47
    +  writeBytecodeLib inputs_hash bytecodeLib' output_fn
    
    45 48
       return ()
    
    46 49
     
    
    47 50
     
    

  • compiler/GHC/Linker/Deps.hs
    ... ... @@ -41,11 +41,10 @@ import qualified GHC.Unit.Home.Graph as HUG
    41 41
     import GHC.Data.Maybe
    
    42 42
     
    
    43 43
     import Control.Applicative
    
    44
    +import Control.Monad (forM_, unless)
    
    44 45
     
    
    45
    -import Data.List (isSuffixOf)
    
    46
    +import System.Directory (doesFileExist)
    
    46 47
     
    
    47
    -import System.FilePath
    
    48
    -import System.Directory
    
    49 48
     
    
    50 49
     data LinkDepsOpts = LinkDepsOpts
    
    51 50
       { ldObjSuffix   :: !String                        -- ^ Suffix of .o files
    
    ... ... @@ -87,18 +86,18 @@ getLinkDeps opts interp pls span mods = do
    87 86
           -- the "normal" way, i.e. no non-std ways like profiling or ticky-ticky.
    
    88 87
           -- So here we check the build tag: if we're building a non-standard way
    
    89 88
           -- then we need to find & link object files built the "normal" way.
    
    90
    -      maybe_normal_osuf <- checkNonStdWay opts interp span
    
    89
    +      checkNonStdWay opts interp span
    
    91 90
     
    
    92
    -      get_link_deps opts pls maybe_normal_osuf span mods
    
    91
    +      get_link_deps opts interp pls span mods
    
    93 92
     
    
    94 93
     get_link_deps
    
    95 94
       :: LinkDepsOpts
    
    95
    +  -> Interp
    
    96 96
       -> LoaderState
    
    97
    -  -> Maybe FilePath  -- replace object suffixes?
    
    98 97
       -> SrcSpan
    
    99 98
       -> [Module]
    
    100 99
       -> IO LinkDeps
    
    101
    -get_link_deps opts pls maybe_normal_osuf span mods = do
    
    100
    +get_link_deps opts interp pls span mods = do
    
    102 101
     
    
    103 102
           -- Three step process:
    
    104 103
     
    
    ... ... @@ -122,9 +121,9 @@ get_link_deps opts pls maybe_normal_osuf span mods = do
    122 121
             -- 3.  For each dependent module, find its linkable
    
    123 122
             --     This will either be in the HPT or (in the case of one-shot
    
    124 123
             --     compilation) we may need to use maybe_getFileLinkable
    
    125
    -      lnks_needed <- mapM (get_linkable (ldObjSuffix opts)) mods_needed
    
    124
    +      lnks_needed <- mapM get_linkable mods_needed
    
    126 125
           let
    
    127
    -        lnks_needed_usages = mkLinkablesUsage lnks_needed
    
    126
    +        lnks_needed_usages = mkLinkablesUsage (interpObjSuffix interp) lnks_needed
    
    128 127
             new_link_deps lnks = LinkDeps
    
    129 128
               { ldNeededLinkables = lnks_needed
    
    130 129
               , ldAllLinkables    = lnks
    
    ... ... @@ -156,9 +155,12 @@ get_link_deps opts pls maybe_normal_osuf span mods = do
    156 155
             then homeModInfoByteCode hmi <|> homeModInfoObject hmi
    
    157 156
             else homeModInfoObject hmi   <|> homeModInfoByteCode hmi
    
    158 157
     
    
    159
    -    get_linkable osuf mod      -- A home-package module
    
    158
    +    get_linkable mod      -- A home-package module
    
    160 159
           = HUG.lookupHugByModule mod (ue_home_unit_graph unit_env) >>= \case
    
    161
    -          Just mod_info -> adjust_linkable (expectJust (homeModLinkable mod_info))
    
    160
    +          Just mod_info -> do
    
    161
    +            let lnk = expectJust (homeModLinkable mod_info)
    
    162
    +            validate_objects lnk
    
    163
    +            pure lnk
    
    162 164
               Nothing -> do
    
    163 165
                -- It's not in the HPT because we are in one shot mode,
    
    164 166
                -- so use the Finder to get a ModLocation...
    
    ... ... @@ -185,30 +187,23 @@ get_link_deps opts pls maybe_normal_osuf span mods = do
    185 187
                       mb_lnk <- findObjectLinkableMaybe mod loc
    
    186 188
                       case mb_lnk of
    
    187 189
                         Nothing  -> no_obj mod
    
    188
    -                    Just lnk -> adjust_linkable lnk
    
    190
    +                    Just lnk -> validate_objects lnk >> pure lnk
    
    189 191
                     _ -> no_obj (moduleName mod)
    
    190 192
     
    
    191
    -            adjust_linkable lnk
    
    192
    -                | Just new_osuf <- maybe_normal_osuf = do
    
    193
    -                        new_parts <- mapM (adjust_part new_osuf)
    
    194
    -                                        (linkableParts lnk)
    
    195
    -                        return lnk{ linkableParts=new_parts }
    
    196
    -                | otherwise =
    
    197
    -                        return lnk
    
    198
    -
    
    199
    -            adjust_part new_osuf part = case part of
    
    200
    -              DotO file ModuleObject -> do
    
    201
    -                massert (osuf `isSuffixOf` file)
    
    202
    -                let file_base = fromJust (stripExtension osuf file)
    
    203
    -                    new_file = file_base <.> new_osuf
    
    204
    -                ok <- doesFileExist new_file
    
    205
    -                if (not ok)
    
    206
    -                   then dieWith opts span $
    
    207
    -                          text "cannot find object file "
    
    208
    -                                <> quotes (text new_file) $$ while_linking_expr
    
    209
    -                   else return (DotO new_file ModuleObject)
    
    210
    -              DotO file ForeignObject -> pure (DotO file ForeignObject)
    
    211
    -              DotGBC {}  -> pure part
    
    193
    +            -- The loader loads the interpreter's object variant of each
    
    194
    +            -- module object. Check it exists here, where we can say which
    
    195
    +            -- module and expression needed it.
    
    196
    +            validate_objects lnk
    
    197
    +              | Just suffixes <- interpObjSuffix interp =
    
    198
    +                  forM_ (linkableParts lnk) $ \part -> case part of
    
    199
    +                    DotO f ModuleObject -> do
    
    200
    +                      let f' = swapObjSuffix suffixes f
    
    201
    +                      ok <- doesFileExist f'
    
    202
    +                      unless ok $ dieWith opts span $
    
    203
    +                        text "cannot find object file" <+> quotes (text f') $$
    
    204
    +                        while_linking_expr
    
    205
    +                    _ -> pure ()
    
    206
    +              | otherwise = pure ()
    
    212 207
     
    
    213 208
     
    
    214 209
     {-
    
    ... ... @@ -241,19 +236,11 @@ dieWith opts span msg = throwProgramError opts (mkLocMessage MCFatal span msg)
    241 236
     throwProgramError :: LinkDepsOpts -> SDoc -> IO a
    
    242 237
     throwProgramError opts doc = throwGhcExceptionIO (ProgramError (renderWithContext (ldPprOpts opts) doc))
    
    243 238
     
    
    244
    -checkNonStdWay :: LinkDepsOpts -> Interp -> SrcSpan -> IO (Maybe FilePath)
    
    239
    +checkNonStdWay :: LinkDepsOpts -> Interp -> SrcSpan -> IO ()
    
    245 240
     checkNonStdWay _opts interp _srcspan
    
    246
    -  -- On some targets (e.g. wasm) the RTS linker only supports loading
    
    247
    -  -- dynamic code, in which case we need to ensure the .dyn_o object
    
    248
    -  -- is picked (instead of .o which is also present because of
    
    249
    -  -- -dynamic-too)
    
    250
    -  | ldForceDyn _opts = do
    
    251
    -      let target_ways = fullWays $ ldWays _opts
    
    252
    -      pure $ if target_ways `hasWay` WayDyn
    
    253
    -        then Nothing
    
    254
    -        else Just $ waysTag (WayDyn `addWay` target_ways) ++ "_o"
    
    255
    -
    
    256
    -  | ExternalInterp {} <- interpInstance interp = return Nothing
    
    241
    +  | ldForceDyn _opts = return ()
    
    242
    +
    
    243
    +  | ExternalInterp {} <- interpInstance interp = return ()
    
    257 244
         -- with -fexternal-interpreter we load the .o files, whatever way
    
    258 245
         -- they were built.  If they were built for a non-std way, then
    
    259 246
         -- we will use the appropriate variant of the iserv binary to load them.
    
    ... ... @@ -262,26 +249,23 @@ checkNonStdWay _opts interp _srcspan
    262 249
     -- complain that they are redundant.
    
    263 250
     #if defined(HAVE_INTERNAL_INTERPRETER)
    
    264 251
     checkNonStdWay opts _interp srcspan
    
    265
    -  | hostFullWays == targetFullWays = return Nothing
    
    252
    +  | hostFullWays == targetFullWays = return ()
    
    266 253
         -- Only if we are compiling with the same ways as GHC is built
    
    267 254
         -- with, can we dynamically load those object files. (see #3604)
    
    268 255
     
    
    269 256
       | ldObjSuffix opts == normalObjectSuffix && not (null targetFullWays)
    
    270 257
       = failNonStd opts srcspan
    
    271 258
     
    
    272
    -  | otherwise = return (Just (hostWayTag ++ "o"))
    
    259
    +  | otherwise = return ()
    
    273 260
       where
    
    274 261
         targetFullWays = fullWays (ldWays opts)
    
    275
    -    hostWayTag = case waysTag hostFullWays of
    
    276
    -                  "" -> ""
    
    277
    -                  tag -> tag ++ "_"
    
    278 262
     
    
    279 263
         normalObjectSuffix :: String
    
    280 264
         normalObjectSuffix = "o"
    
    281 265
     
    
    282 266
     data Way' = Normal | Prof | Dyn | ProfDyn
    
    283 267
     
    
    284
    -failNonStd :: LinkDepsOpts -> SrcSpan -> IO (Maybe FilePath)
    
    268
    +failNonStd :: LinkDepsOpts -> SrcSpan -> IO ()
    
    285 269
     failNonStd opts srcspan = dieWith opts srcspan $
    
    286 270
       text "Cannot load" <+> pprWay' compWay <+>
    
    287 271
          text "objects when GHC is built" <+> pprWay' ghciWay $$
    

  • compiler/GHC/Linker/Loader.hs
    ... ... @@ -44,7 +44,6 @@ where
    44 44
     import GHC.Prelude
    
    45 45
     
    
    46 46
     import GHC.Settings
    
    47
    -import GHC.Utils.Misc
    
    48 47
     
    
    49 48
     import GHC.Platform
    
    50 49
     import GHC.Platform.Ways
    
    ... ... @@ -673,14 +672,13 @@ findWholeCoreBindings hsc_env mod = do
    673 672
     
    
    674 673
     findBytecodeLinkableMaybe :: HscEnv -> ModLocation -> IO (Maybe Linkable)
    
    675 674
     findBytecodeLinkableMaybe hsc_env locn = do
    
    676
    -  let bytecode_fn    = ml_bytecode_file locn
    
    677
    -      bytecode_fn_os = ml_bytecode_file_ospath locn
    
    678
    -  maybe_bytecode_time <- modificationTimeIfExists bytecode_fn_os
    
    679
    -  case maybe_bytecode_time of
    
    680
    -    Nothing -> return Nothing
    
    681
    -    Just bytecode_time -> do
    
    675
    +  let bytecode_fn = ml_bytecode_file locn
    
    676
    +  exists <- doesFileExist bytecode_fn
    
    677
    +  if not exists
    
    678
    +    then return Nothing
    
    679
    +    else do
    
    682 680
           bco <- readBinByteCode hsc_env bytecode_fn
    
    683
    -      return $ Just $ mkModuleByteCodeLinkable bytecode_time bco
    
    681
    +      return $ Just $ mkModuleByteCodeLinkable bco
    
    684 682
     
    
    685 683
     get_reachable_nodes :: HscEnv -> [Module] -> IO ([Module], UniqDSet UnitId)
    
    686 684
     get_reachable_nodes hsc_env mods
    
    ... ... @@ -834,7 +832,7 @@ linkableInSet :: Linkable -> LinkableSet LinkableUsage -> Bool
    834 832
     linkableInSet l objs_loaded =
    
    835 833
       case lookupModuleEnv objs_loaded (linkableModule l) of
    
    836 834
             Nothing -> False
    
    837
    -        Just m  -> linkableTime l == linkableTime m
    
    835
    +        Just m  -> linkableHash l == linkableHash m
    
    838 836
     
    
    839 837
     
    
    840 838
     {- **********************************************************************
    
    ... ... @@ -854,9 +852,9 @@ loadObjects
    854 852
       -> [Linkable]
    
    855 853
       -> IO (LoaderState, SuccessFlag)
    
    856 854
     loadObjects interp hsc_env pls objs = do
    
    857
    -        let (objs_loaded', new_objs) = rmDupLinkables (objs_loaded pls) objs
    
    855
    +        let (objs_loaded', new_objs) = rmDupLinkables (interpObjSuffix interp) (objs_loaded pls) objs
    
    858 856
                 pls1                     = pls { objs_loaded = objs_loaded' }
    
    859
    -            wanted_objs              = concatMap linkableObjs new_objs
    
    857
    +        wanted_objs <- concat <$> mapM (loadableObjs interp) new_objs
    
    860 858
     
    
    861 859
             if interpreterDynamic interp
    
    862 860
                 then do pls2 <- dynLoadObjs interp hsc_env pls1 wanted_objs
    
    ... ... @@ -875,6 +873,18 @@ loadObjects interp hsc_env pls objs = do
    875 873
                                 return (pls2, Failed)
    
    876 874
     
    
    877 875
     
    
    876
    +loadableObjs :: Interp -> Linkable -> IO [FilePath]
    
    877
    +loadableObjs interp l = concat <$> mapM go (Foldable.toList (linkableParts l))
    
    878
    +  where
    
    879
    +    go (DotO fn ModuleObject)
    
    880
    +      | Just suffixes <- interpObjSuffix interp = do
    
    881
    +          let fn' = swapObjSuffix suffixes fn
    
    882
    +          ok <- doesFileExist fn'
    
    883
    +          if ok
    
    884
    +            then return [fn']
    
    885
    +            else throwGhcExceptionIO (ProgramError ("cannot find object file " ++ fn'))
    
    886
    +    go part = return (linkablePartObjectPaths part)
    
    887
    +
    
    878 888
     -- | Create a shared library containing the given object files
    
    879 889
     mkDynLoadLib :: HscEnv -> (Ways -> Ways) -> [(FilePath, String)] ->[UnitId] -> [FilePath] -> IO (Maybe (FilePath, FilePath, String))
    
    880 890
     mkDynLoadLib      _  _  _ _  []   = return Nothing
    
    ... ... @@ -959,17 +969,18 @@ dynLoadObjs interp hsc_env pls objs = do
    959 969
                             then addWay WayProf
    
    960 970
                             else id
    
    961 971
     
    
    962
    -rmDupLinkables :: LinkableSet LinkableUsage  -- ^ Already loaded
    
    972
    +rmDupLinkables :: Maybe (String, String)
    
    973
    +               -> LinkableSet LinkableUsage  -- ^ Already loaded
    
    963 974
                    -> [Linkable]    -- ^ New linkables
    
    964 975
                    -> (LinkableSet LinkableUsage,  -- New loaded set (including new ones)
    
    965 976
                        [Linkable])  -- New linkables (excluding dups)
    
    966
    -rmDupLinkables already ls
    
    977
    +rmDupLinkables mb_osuf already ls
    
    967 978
       = go already [] ls
    
    968 979
       where
    
    969 980
         go !already extras [] = (already, extras)
    
    970 981
         go !already extras (l:ls)
    
    971 982
             | linkableInSet l already = go already     extras     ls
    
    972
    -        | otherwise               = go (extendModuleEnv already (linkableModule l) $! mkLinkableUsage l) (l:extras) ls
    
    983
    +        | otherwise               = go (extendModuleEnv already (linkableModule l) $! mkLinkableUsage mb_osuf l) (l:extras) ls
    
    973 984
     
    
    974 985
     {- **********************************************************************
    
    975 986
     
    
    ... ... @@ -981,7 +992,7 @@ rmDupLinkables already ls
    981 992
     dynLinkBCOs :: Interp -> LoaderState -> KeepModuleLinkableDefinitions -> [Linkable] -> IO LoaderState
    
    982 993
     dynLinkBCOs interp pls keep_spec bcos =
    
    983 994
     
    
    984
    -        let (bcos_loaded', new_bcos) = rmDupLinkables (bcos_loaded pls) bcos
    
    995
    +        let (bcos_loaded', new_bcos) = rmDupLinkables Nothing (bcos_loaded pls) bcos
    
    985 996
                 pls1                     = pls { bcos_loaded = bcos_loaded' }
    
    986 997
     
    
    987 998
                 cbcs :: [CompiledByteCode]
    

  • compiler/GHC/Linker/Types.hs
    ... ... @@ -36,8 +36,6 @@ module GHC.Linker.Types
    36 36
        , LinkedBreaks(..)
    
    37 37
        , emptyLinkedBreaks
    
    38 38
        , LinkableSet
    
    39
    -   , mkLinkableSet
    
    40
    -   , unionLinkableSet
    
    41 39
        , ObjFile
    
    42 40
        , SptEntry(..)
    
    43 41
        , LibrarySpec(..)
    
    ... ... @@ -58,9 +56,8 @@ module GHC.Linker.Types
    58 56
        , linkableBCOs
    
    59 57
        , linkablePartBCOs
    
    60 58
        , linkableModuleByteCodes
    
    61
    -   , linkableNativeParts
    
    62
    -   , linkablePartitionParts
    
    63 59
        , linkablePartPath
    
    60
    +   , linkablePartObjectPaths
    
    64 61
        , isNativeCode
    
    65 62
        , linkableFilterByteCode
    
    66 63
        , linkableFilterNative
    
    ... ... @@ -70,6 +67,7 @@ module GHC.Linker.Types
    70 67
        , linkableUsageObjs
    
    71 68
        , mkLinkablesUsage
    
    72 69
        , mkLinkableUsage
    
    70
    +   , swapObjSuffix
    
    73 71
     
    
    74 72
        , ModuleByteCode(..)
    
    75 73
        )
    
    ... ... @@ -95,6 +93,7 @@ import GHC.Unit.Module.Deps (LinkablePartUsage (..), linkablePartUsageObjectPath
    95 93
     import GHC.Unit.Module.Env
    
    96 94
     import GHC.Unit.Module.WholeCoreBindings
    
    97 95
     import GHC.Utils.Misc (seqNonEmpty)
    
    96
    +import GHC.Utils.Panic (pprPanic)
    
    98 97
     
    
    99 98
     import GHC.Utils.Outputable
    
    100 99
     
    
    ... ... @@ -102,10 +101,10 @@ import Control.Applicative ((<|>))
    102 101
     import Control.Concurrent.MVar
    
    103 102
     import Data.Array
    
    104 103
     import Data.Functor.Identity
    
    105
    -import Data.Time               ( UTCTime )
    
    106 104
     import Data.Maybe (mapMaybe)
    
    107 105
     import Data.List.NonEmpty (NonEmpty, nonEmpty)
    
    108 106
     import qualified Data.List.NonEmpty as NE
    
    107
    +import System.FilePath (stripExtension, (<.>))
    
    109 108
     
    
    110 109
     {- **********************************************************************
    
    111 110
     
    
    ... ... @@ -376,10 +375,10 @@ instance Outputable LoadedPkgInfo where
    376 375
     
    
    377 376
     -- | Information we can use to dynamically link modules into the compiler
    
    378 377
     data LinkableWith parts = Linkable
    
    379
    -  { linkableTime     :: !UTCTime
    
    380
    -      -- ^ Time at which this linkable was built
    
    381
    -      -- (i.e. when the bytecodes were produced,
    
    382
    -      --       or the mod date on the files)
    
    378
    +  { linkableHash     :: Fingerprint
    
    379
    +      -- ^ The identity of the linkable, derived from the hash of its contents
    
    380
    +      -- Lazy because bytecode is compiled lazily (see loadIfaceByteCodeLazy),
    
    381
    +      -- and inspecting the hash can force compiling the bytecode itself.
    
    383 382
     
    
    384 383
       , linkableModule   :: !Module
    
    385 384
           -- ^ The linkable module itself
    
    ... ... @@ -396,22 +395,12 @@ type LinkableUsage = LinkableWith (NonEmpty LinkablePartUsage)
    396 395
     
    
    397 396
     type LinkableSet = ModuleEnv
    
    398 397
     
    
    399
    -mkLinkableSet :: [Linkable] -> LinkableSet Linkable
    
    400
    -mkLinkableSet ls = mkModuleEnv [(linkableModule l, l) | l <- ls]
    
    401
    -
    
    402
    --- | Union of LinkableSets.
    
    403
    ---
    
    404
    --- In case of conflict, keep the most recent Linkable (as per linkableTime)
    
    405
    -unionLinkableSet :: LinkableSet (LinkableWith a) -> LinkableSet (LinkableWith a) -> LinkableSet (LinkableWith a)
    
    406
    -unionLinkableSet = plusModuleEnv_C go
    
    407
    -  where
    
    408
    -    go l1 l2
    
    409
    -      | linkableTime l1 > linkableTime l2 = l1
    
    410
    -      | otherwise = l2
    
    411 398
     
    
    412 399
     instance Outputable a => Outputable (LinkableWith a) where
    
    413
    -  ppr (Linkable when_made mod parts)
    
    414
    -     = (text "Linkable" <+> parens (text (show when_made)) <+> ppr mod)
    
    400
    +  -- Don't print the hash, forcing it can trigger compilation
    
    401
    +  -- See the comment on 'linkableHash'
    
    402
    +  ppr (Linkable _ mod parts)
    
    403
    +     = (text "Linkable" <+> ppr mod)
    
    415 404
            $$ nest 3 (ppr parts)
    
    416 405
     
    
    417 406
     type ObjFile = FilePath
    
    ... ... @@ -452,13 +441,13 @@ data ModuleByteCode = ModuleByteCode { gbc_module :: Module
    452 441
                                           , gbc_hash :: !Fingerprint
    
    453 442
                                           }
    
    454 443
     
    
    455
    -mkModuleByteCodeLinkable :: UTCTime -> ModuleByteCode -> Linkable
    
    456
    -mkModuleByteCodeLinkable linkable_time bco = do
    
    457
    -  Linkable linkable_time (gbc_module bco) (pure (DotGBC bco))
    
    444
    +mkModuleByteCodeLinkable :: ModuleByteCode -> Linkable
    
    445
    +mkModuleByteCodeLinkable bco =
    
    446
    +  Linkable (gbc_hash bco) (gbc_module bco) (pure (DotGBC bco))
    
    458 447
     
    
    459
    -mkOnlyModuleByteCodeLinkable :: UTCTime -> ModuleByteCode -> LinkableWith ModuleByteCode
    
    460
    -mkOnlyModuleByteCodeLinkable linkable_time bco = do
    
    461
    -  Linkable linkable_time (gbc_module bco) bco
    
    448
    +mkOnlyModuleByteCodeLinkable :: ModuleByteCode -> LinkableWith ModuleByteCode
    
    449
    +mkOnlyModuleByteCodeLinkable bco =
    
    450
    +  Linkable (gbc_hash bco) (gbc_module bco) bco
    
    462 451
     
    
    463 452
     instance Outputable ModuleByteCode where
    
    464 453
       ppr (ModuleByteCode mod _cbc _fos _) = text "ModuleByteCode" <+> ppr mod
    
    ... ... @@ -484,21 +473,13 @@ linkableBCOs l = [ gbc_compiled_byte_code gbc | DotGBC gbc <- NE.toList (linkabl
    484 473
     linkableModuleByteCodes :: Linkable -> [ModuleByteCode]
    
    485 474
     linkableModuleByteCodes l = [ mbc | DotGBC mbc <- NE.toList (linkableParts l) ]
    
    486 475
     
    
    487
    --- | List the native linkable parts (.o) of a linkable
    
    488
    -linkableNativeParts :: Linkable -> [LinkablePart]
    
    489
    -linkableNativeParts l = NE.filter isNativeCode (linkableParts l)
    
    490
    -
    
    491
    --- | Split linkable parts into (native code parts, BCOs parts)
    
    492
    -linkablePartitionParts :: Linkable -> ([LinkablePart],[LinkablePart])
    
    493
    -linkablePartitionParts l = NE.partition isNativeCode (linkableParts l)
    
    494
    -
    
    495 476
     -- | List the native objects (.o) of a linkable
    
    496 477
     linkableObjs :: Linkable -> [FilePath]
    
    497 478
     linkableObjs l = concatMap linkablePartObjectPaths (linkableParts l)
    
    498 479
     
    
    499 480
     -- | List the paths of the native objects (.o)
    
    500 481
     linkableFiles :: Linkable -> [FilePath]
    
    501
    -linkableFiles l = concatMap linkablePartNativePaths (NE.toList (linkableParts l))
    
    482
    +linkableFiles l = mapMaybe linkablePartPath (NE.toList (linkableParts l))
    
    502 483
     
    
    503 484
     -------------------------------------------
    
    504 485
     
    
    ... ... @@ -514,13 +495,6 @@ linkablePartPath = \case
    514 495
       DotO fn _       -> Just fn
    
    515 496
       DotGBC {}       -> Nothing
    
    516 497
     
    
    517
    --- | Return the paths of all object code files (.o) contained in this
    
    518
    --- 'LinkablePart'.
    
    519
    -linkablePartNativePaths :: LinkablePart -> [FilePath]
    
    520
    -linkablePartNativePaths = \case
    
    521
    -  DotO fn _       -> [fn]
    
    522
    -  DotGBC {}       -> []
    
    523
    -
    
    524 498
     -- | Return the paths of all object files (.o) contained in this 'LinkablePart'.
    
    525 499
     linkablePartObjectPaths :: LinkablePart -> [FilePath]
    
    526 500
     linkablePartObjectPaths = \case
    
    ... ... @@ -578,8 +552,13 @@ partitionLinkables linkables =
    578 552
     --
    
    579 553
     -- Each 'LinkablePartUsage' is fully evaluated to avoid retaining any reference
    
    580 554
     -- to the original 'LinkablePart'.
    
    581
    -mkLinkableUsage :: Linkable -> LinkableUsage
    
    582
    -mkLinkableUsage lnk =
    
    555
    +swapObjSuffix :: (String, String) -> FilePath -> FilePath
    
    556
    +swapObjSuffix (from, to) file = case stripExtension from file of
    
    557
    +  Just base -> base <.> to
    
    558
    +  Nothing   -> pprPanic "swapObjSuffix" (text file <+> text from)
    
    559
    +
    
    560
    +mkLinkableUsage :: Maybe (String, String) -> Linkable -> LinkableUsage
    
    561
    +mkLinkableUsage mb_osuf lnk =
    
    583 562
       let
    
    584 563
         linkablesWithUsage = NE.map (go (linkableModule lnk)) (linkableParts lnk)
    
    585 564
         lnkUsage = lnk
    
    ... ... @@ -589,7 +568,9 @@ mkLinkableUsage lnk =
    589 568
               seqNonEmpty linkablesWithUsage linkablesWithUsage
    
    590 569
           }
    
    591 570
       in
    
    592
    -    linkableParts lnkUsage `seq` lnkUsage
    
    571
    +    -- Also force the hash so that we don't retain the actual bytecode
    
    572
    +    -- from a LinkableUsage
    
    573
    +    linkableHash lnkUsage `seq` linkableParts lnkUsage `seq` lnkUsage
    
    593 574
       where
    
    594 575
         mkFileLinkablePartUsage m fp objs =
    
    595 576
           FileLinkablePartUsage
    
    ... ... @@ -609,11 +590,15 @@ mkLinkableUsage lnk =
    609 590
     
    
    610 591
         go :: Module -> LinkablePart -> LinkablePartUsage
    
    611 592
         go m lnkPart = case lnkPart of
    
    593
    +      DotO fn ModuleObject
    
    594
    +        | Just suffixes <- mb_osuf
    
    595
    +        , let fn' = swapObjSuffix suffixes fn
    
    596
    +        -> mkFileLinkablePartUsage m fn' [fn']
    
    612 597
           DotO fn _ -> mkFileLinkablePartUsage m fn (linkablePartObjectPaths lnkPart)
    
    613 598
           DotGBC mbc -> mkByteCodeLinkablePartUsage m (gbc_hash mbc) (linkablePartObjectPaths lnkPart)
    
    614 599
     
    
    615
    -mkLinkablesUsage :: [Linkable] -> [LinkableUsage]
    
    616
    -mkLinkablesUsage linkables = map mkLinkableUsage linkables
    
    600
    +mkLinkablesUsage :: Maybe (String, String) -> [Linkable] -> [LinkableUsage]
    
    601
    +mkLinkablesUsage mb_osuf linkables = map (mkLinkableUsage mb_osuf) linkables
    
    617 602
     
    
    618 603
     linkableUsageObjs :: LinkableUsage -> [FilePath]
    
    619 604
     linkableUsageObjs lnkWithUsage = concatMap linkablePartUsageObjectPaths (linkableParts lnkWithUsage)
    

  • compiler/GHC/Runtime/Interpreter/Init.hs
    ... ... @@ -11,6 +11,7 @@ where
    11 11
     import GHC.Prelude
    
    12 12
     import GHC.Data.FastString.Env
    
    13 13
     import GHC.Driver.DynFlags
    
    14
    +import GHC.Driver.Session (objectSuf)
    
    14 15
     import GHC.Platform
    
    15 16
     import GHC.Platform.Ways
    
    16 17
     import GHC.Settings
    
    ... ... @@ -74,6 +75,23 @@ initInterpreter dflags tmpfs logger platform finder_cache unit_env opts = do
    74 75
     
    
    75 76
       fs_cache <- liftIO $ newMVar emptyFsEnv
    
    76 77
     
    
    78
    +#if defined(HAVE_INTERNAL_INTERPRETER)
    
    79
    +  let host_way_tag = case waysTag hostFullWays of
    
    80
    +        ""  -> ""
    
    81
    +        tag -> tag ++ "_"
    
    82
    +      internal_obj_suffix
    
    83
    +        | hostFullWays == fullWays (interpWays opts) = Nothing
    
    84
    +        | otherwise = Just (objectSuf dflags, host_way_tag ++ "o")
    
    85
    +#endif
    
    86
    +
    
    87
    +#if !defined(wasm32_HOST_ARCH)
    
    88
    +  let target_full_ways = fullWays (interpWays opts)
    
    89
    +      wasm_obj_suffix
    
    90
    +        | target_full_ways `hasWay` WayDyn = Nothing
    
    91
    +        | otherwise =
    
    92
    +            Just (objectSuf dflags, waysTag (WayDyn `addWay` target_full_ways) ++ "_o")
    
    93
    +#endif
    
    94
    +
    
    77 95
       -- see Note [Target code interpreter]
    
    78 96
       if
    
    79 97
     #if !defined(wasm32_HOST_ARCH)
    
    ... ... @@ -103,7 +121,7 @@ initInterpreter dflags tmpfs logger platform finder_cache unit_env opts = do
    103 121
                     , wasmInterpHsSoSuffix = way_tag ++ dynLibSuffix (interpNameVer opts)
    
    104 122
                     , wasmInterpUnitState = ue_homeUnitState unit_env
    
    105 123
                     }
    
    106
    -        pure $ Just $ Interp (ExternalInterp $ ExtWasm $ ExtInterpState cfg s) loader lookup_cache fs_cache
    
    124
    +        pure $ Just $ Interp (ExternalInterp $ ExtWasm $ ExtInterpState cfg s) loader lookup_cache fs_cache wasm_obj_suffix
    
    107 125
     #endif
    
    108 126
     
    
    109 127
         -- JavaScript interpreter
    
    ... ... @@ -122,7 +140,7 @@ initInterpreter dflags tmpfs logger platform finder_cache unit_env opts = do
    122 140
                   , jsInterpFinderOpts  = interpFinderOpts opts
    
    123 141
                   , jsInterpFinderCache = finder_cache
    
    124 142
                   }
    
    125
    -         return (Just (Interp (ExternalInterp (ExtJS (ExtInterpState cfg s))) loader lookup_cache fs_cache))
    
    143
    +         return (Just (Interp (ExternalInterp (ExtJS (ExtInterpState cfg s))) loader lookup_cache fs_cache Nothing))
    
    126 144
     
    
    127 145
         -- external interpreter
    
    128 146
         | interpExternal opts
    
    ... ... @@ -149,7 +167,7 @@ initInterpreter dflags tmpfs logger platform finder_cache unit_env opts = do
    149 167
                }
    
    150 168
             s <- liftIO $ newMVar InterpPending
    
    151 169
             loader <- liftIO Loader.uninitializedLoader
    
    152
    -        return (Just (Interp (ExternalInterp (ExtIServ (ExtInterpState conf s))) loader lookup_cache fs_cache))
    
    170
    +        return (Just (Interp (ExternalInterp (ExtIServ (ExtInterpState conf s))) loader lookup_cache fs_cache Nothing))
    
    153 171
     
    
    154 172
         -- Internal interpreter
    
    155 173
         | otherwise
    
    ... ... @@ -157,7 +175,7 @@ initInterpreter dflags tmpfs logger platform finder_cache unit_env opts = do
    157 175
     #if defined(HAVE_INTERNAL_INTERPRETER)
    
    158 176
          do
    
    159 177
           loader <- liftIO Loader.uninitializedLoader
    
    160
    -      return (Just (Interp InternalInterp loader lookup_cache fs_cache))
    
    178
    +      return (Just (Interp InternalInterp loader lookup_cache fs_cache internal_obj_suffix))
    
    161 179
     #else
    
    162 180
           return Nothing
    
    163 181
     #endif

  • compiler/GHC/Runtime/Interpreter/Types.hs
    ... ... @@ -79,6 +79,10 @@ data Interp = Interp
    79 79
     
    
    80 80
       , interpStringCache :: !(MVar (FastStringEnv (RemotePtr ())))
    
    81 81
           -- ^ MallocStrings cache
    
    82
    +
    
    83
    +  , interpObjSuffix :: !(Maybe (String, String))
    
    84
    +      -- ^ @(from, to)@ object suffixes to swap when the interpreter cannot
    
    85
    +      -- load objects built the target's way
    
    82 86
       }
    
    83 87
     
    
    84 88
     data InterpInstance
    

  • compiler/GHC/Unit/Finder.hs
    ... ... @@ -58,7 +58,6 @@ import GHC.Unit.Finder.Types
    58 58
     
    
    59 59
     import qualified GHC.Data.ShortText as ST
    
    60 60
     
    
    61
    -import GHC.Utils.Misc
    
    62 61
     import GHC.Utils.Outputable as Outputable
    
    63 62
     import GHC.Utils.Panic
    
    64 63
     
    
    ... ... @@ -72,7 +71,6 @@ import GHC.Fingerprint
    72 71
     import Data.IORef
    
    73 72
     import Control.Applicative ((<|>))
    
    74 73
     import Control.Monad
    
    75
    -import Data.Time
    
    76 74
     import qualified Data.Map as M
    
    77 75
     import GHC.Types.Unique.Map
    
    78 76
     import GHC.Driver.Env
    
    ... ... @@ -1004,15 +1002,15 @@ mkStubPaths fopts mod location = do
    1004 1002
     findObjectLinkableMaybe :: Module -> ModLocation -> IO (Maybe Linkable)
    
    1005 1003
     findObjectLinkableMaybe mod locn
    
    1006 1004
        = do let obj_fn = ml_obj_file locn
    
    1007
    -        maybe_obj_time <- modificationTimeIfExists (ml_obj_file_ospath locn)
    
    1008
    -        case maybe_obj_time of
    
    1009
    -          Nothing -> return Nothing
    
    1010
    -          Just obj_time -> liftM Just (findObjectLinkable mod obj_fn obj_time)
    
    1011
    -
    
    1012
    --- Make an object linkable when we know the object file exists, and we know
    
    1013
    --- its modification time.
    
    1014
    -findObjectLinkable :: Module -> FilePath -> UTCTime -> IO Linkable
    
    1015
    -findObjectLinkable mod obj_fn obj_time =
    
    1016
    -  pure (Linkable obj_time mod (NE.singleton (DotO obj_fn ModuleObject)))
    
    1005
    +        exists <- doesFileExist (ml_obj_file_ospath locn)
    
    1006
    +        if not exists
    
    1007
    +          then return Nothing
    
    1008
    +          else do
    
    1009
    +            obj_hash <- getFileHash obj_fn
    
    1010
    +            return (Just (findObjectLinkable mod obj_fn obj_hash))
    
    1011
    +
    
    1012
    +findObjectLinkable :: Module -> FilePath -> Fingerprint -> Linkable
    
    1013
    +findObjectLinkable mod obj_fn obj_hash =
    
    1014
    +  Linkable obj_hash mod (NE.singleton (DotO obj_fn ModuleObject))
    
    1017 1015
       -- We used to look for _stub.o files here, but that was a bug (#706)
    
    1018 1016
       -- Now GHC merges the stub.o into the main .o (#3687)

  • testsuite/tests/driver/recomp023/M.hs
    1
    +module M where
    
    2
    +
    
    3
    +m :: Int
    
    4
    +m = 5

  • testsuite/tests/driver/recomp023/Makefile
    1
    +TOP=../../..
    
    2
    +include $(TOP)/mk/boilerplate.mk
    
    3
    +include $(TOP)/mk/test.mk
    
    4
    +
    
    5
    +clean:
    
    6
    +
    
    7
    +recomp023: clean
    
    8
    +	'$(TEST_HC)' $(TEST_HC_OPTS) --make -bytecodelib -fbyte-code \
    
    9
    +		-fwrite-interface -fwrite-byte-code -this-unit-id=recomp023 \
    
    10
    +		-o recomp023.bytecodelib M.hs
    
    11
    +	'$(TEST_HC)' $(TEST_HC_OPTS) --make -bytecodelib -fbyte-code \
    
    12
    +		-fwrite-interface -fwrite-byte-code -this-unit-id=recomp023 \
    
    13
    +		-o recomp023.bytecodelib M.hs

  • testsuite/tests/driver/recomp023/all.T
    1
    +test('recomp023', [extra_files(['M.hs']), req_bco, normalise_slashes],
    
    2
    +     makefile_test, [])

  • testsuite/tests/driver/recomp023/recomp023.stdout
    1
    +[1 of 2] Compiling M                ( M.hs, M.gbc )
    
    2
    +[2 of 2] Linking recomp023.bytecodelib