Cheng Shao pushed to branch wip/batch-loaddll at Glasgow Haskell Compiler / GHC

Commits:

15 changed files:

Changes:

  • compiler/GHC/Driver/Plugins.hs
    ... ... @@ -421,7 +421,7 @@ loadExternalPlugins ps = do
    421 421
     loadExternalPluginLib :: FilePath -> IO ()
    
    422 422
     loadExternalPluginLib path = do
    
    423 423
       -- load library
    
    424
    -  loadDLL path >>= \case
    
    424
    +  loadDLLs [path] >>= \case
    
    425 425
         Left errmsg -> pprPanic "loadExternalPluginLib"
    
    426 426
                          (vcat [ text "Can't load plugin library"
    
    427 427
                                , text "  Library path: " <> text path
    

  • compiler/GHC/Iface/Ext/Binary.hs
    ... ... @@ -17,7 +17,6 @@ where
    17 17
     
    
    18 18
     import GHC.Prelude
    
    19 19
     
    
    20
    -import GHC.Builtin.Utils
    
    21 20
     import GHC.Settings.Utils         ( maybeRead )
    
    22 21
     import GHC.Settings.Config        ( cProjectVersion )
    
    23 22
     import GHC.Utils.Binary
    
    ... ... @@ -28,10 +27,8 @@ import GHC.Iface.Binary ( putAllTables )
    28 27
     import GHC.Types.Name
    
    29 28
     import GHC.Types.Name.Cache
    
    30 29
     import GHC.Types.SrcLoc as SrcLoc
    
    31
    -import GHC.Types.Unique
    
    32 30
     import GHC.Types.Unique.FM
    
    33 31
     import qualified GHC.Utils.Binary as Binary
    
    34
    -import GHC.Utils.Outputable
    
    35 32
     import GHC.Utils.Panic
    
    36 33
     
    
    37 34
     import qualified Data.Array        as A
    
    ... ... @@ -290,6 +287,9 @@ fromHieName nc hie_name = do
    290 287
       case hie_name of
    
    291 288
         ExternalName mod occ span -> updateNameCache nc mod occ $ \cache -> do
    
    292 289
           case lookupOrigNameCache cache mod occ of
    
    290
    +        -- Note that this may be a wired-in name (provided that the NameCache
    
    291
    +        -- was initialized with known-key names, which is always the case if you
    
    292
    +        -- use `newNameCache`).
    
    293 293
             Just name -> pure (cache, name)
    
    294 294
             Nothing   -> do
    
    295 295
               uniq <- takeUniqFromNameCache nc
    
    ... ... @@ -302,11 +302,6 @@ fromHieName nc hie_name = do
    302 302
           -- don't update the NameCache for local names
    
    303 303
           pure $ mkInternalName uniq occ span
    
    304 304
     
    
    305
    -    KnownKeyName u -> case lookupKnownKeyName u of
    
    306
    -      Nothing -> pprPanic "fromHieName:unknown known-key unique"
    
    307
    -                          (ppr u)
    
    308
    -      Just n -> pure n
    
    309
    -
    
    310 305
     -- ** Reading and writing `HieName`'s
    
    311 306
     
    
    312 307
     putHieName :: WriteBinHandle -> HieName -> IO ()
    
    ... ... @@ -316,9 +311,6 @@ putHieName bh (ExternalName mod occ span) = do
    316 311
     putHieName bh (LocalName occName span) = do
    
    317 312
       putByte bh 1
    
    318 313
       put_ bh (occName, BinSrcSpan span)
    
    319
    -putHieName bh (KnownKeyName uniq) = do
    
    320
    -  putByte bh 2
    
    321
    -  put_ bh $ unpkUnique uniq
    
    322 314
     
    
    323 315
     getHieName :: ReadBinHandle -> IO HieName
    
    324 316
     getHieName bh = do
    
    ... ... @@ -330,7 +322,4 @@ getHieName bh = do
    330 322
         1 -> do
    
    331 323
           (occ, span) <- get bh
    
    332 324
           return $ LocalName occ $ unBinSrcSpan span
    
    333
    -    2 -> do
    
    334
    -      (c,i) <- get bh
    
    335
    -      return $ KnownKeyName $ mkUnique c i
    
    336 325
         _ -> panic "GHC.Iface.Ext.Binary.getHieName: invalid tag"

  • compiler/GHC/Iface/Ext/Types.hs
    ... ... @@ -19,14 +19,12 @@ import GHC.Prelude
    19 19
     import GHC.Settings.Config
    
    20 20
     import GHC.Utils.Binary
    
    21 21
     import GHC.Data.FastString
    
    22
    -import GHC.Builtin.Utils
    
    23 22
     import GHC.Iface.Type
    
    24 23
     import GHC.Unit.Module            ( ModuleName, Module )
    
    25 24
     import GHC.Types.Name
    
    26 25
     import GHC.Utils.Outputable hiding ( (<>) )
    
    27 26
     import GHC.Types.SrcLoc
    
    28 27
     import GHC.Types.Avail
    
    29
    -import GHC.Types.Unique
    
    30 28
     import qualified GHC.Utils.Outputable as O ( (<>) )
    
    31 29
     import GHC.Utils.Panic
    
    32 30
     import GHC.Core.ConLike           ( ConLike(..) )
    
    ... ... @@ -766,7 +764,6 @@ instance Binary TyVarScope where
    766 764
     data HieName
    
    767 765
       = ExternalName !Module !OccName !SrcSpan
    
    768 766
       | LocalName !OccName !SrcSpan
    
    769
    -  | KnownKeyName !Unique
    
    770 767
       deriving (Eq)
    
    771 768
     
    
    772 769
     instance Ord HieName where
    
    ... ... @@ -774,34 +771,28 @@ instance Ord HieName where
    774 771
         -- TODO (int-index): Perhaps use RealSrcSpan in HieName?
    
    775 772
       compare (LocalName a b) (LocalName c d) = compare a c S.<> leftmost_smallest b d
    
    776 773
         -- TODO (int-index): Perhaps use RealSrcSpan in HieName?
    
    777
    -  compare (KnownKeyName a) (KnownKeyName b) = nonDetCmpUnique a b
    
    778
    -    -- Not actually non deterministic as it is a KnownKey
    
    779 774
       compare ExternalName{} _ = LT
    
    780 775
       compare LocalName{} ExternalName{} = GT
    
    781
    -  compare LocalName{} _ = LT
    
    782
    -  compare KnownKeyName{} _ = GT
    
    783 776
     
    
    784 777
     instance Outputable HieName where
    
    785 778
       ppr (ExternalName m n sp) = text "ExternalName" <+> ppr m <+> ppr n <+> ppr sp
    
    786 779
       ppr (LocalName n sp) = text "LocalName" <+> ppr n <+> ppr sp
    
    787
    -  ppr (KnownKeyName u) = text "KnownKeyName" <+> ppr u
    
    788 780
     
    
    789 781
     hieNameOcc :: HieName -> OccName
    
    790 782
     hieNameOcc (ExternalName _ occ _) = occ
    
    791 783
     hieNameOcc (LocalName occ _) = occ
    
    792
    -hieNameOcc (KnownKeyName u) =
    
    793
    -  case lookupKnownKeyName u of
    
    794
    -    Just n -> nameOccName n
    
    795
    -    Nothing -> pprPanic "hieNameOcc:unknown known-key unique"
    
    796
    -                        (ppr u)
    
    797 784
     
    
    798 785
     toHieName :: Name -> HieName
    
    799
    -toHieName name
    
    800
    -  | isKnownKeyName name = KnownKeyName (nameUnique name)
    
    801
    -  | isExternalName name = ExternalName (nameModule name)
    
    802
    -                                       (nameOccName name)
    
    803
    -                                       (removeBufSpan $ nameSrcSpan name)
    
    804
    -  | otherwise = LocalName (nameOccName name) (removeBufSpan $ nameSrcSpan name)
    
    786
    +toHieName name =
    
    787
    +  case nameModule_maybe name of
    
    788
    +    Nothing -> LocalName occName span
    
    789
    +    Just m -> ExternalName m occName span
    
    790
    +  where
    
    791
    +    occName :: OccName
    
    792
    +    occName = nameOccName name
    
    793
    +
    
    794
    +    span :: SrcSpan
    
    795
    +    span = removeBufSpan $ nameSrcSpan name
    
    805 796
     
    
    806 797
     
    
    807 798
     {- Note [Capture Entity Information]
    

  • compiler/GHC/Iface/Tidy/StaticPtrTable.hs
    ... ... @@ -17,18 +17,18 @@
    17 17
     -- > static void hs_hpc_init_Main(void) {
    
    18 18
     -- >
    
    19 19
     -- >   static StgWord64 k0[2] = {16252233372134256ULL,7370534374096082ULL};
    
    20
    --- >   extern StgPtr Main_r2wb_closure;
    
    20
    +-- >   extern StgClosure Main_r2wb_closure;
    
    21 21
     -- >   hs_spt_insert(k0, &Main_r2wb_closure);
    
    22 22
     -- >
    
    23 23
     -- >   static StgWord64 k1[2] = {12545634534567898ULL,5409674567544151ULL};
    
    24
    --- >   extern StgPtr Main_r2wc_closure;
    
    24
    +-- >   extern StgClosure Main_r2wc_closure;
    
    25 25
     -- >   hs_spt_insert(k1, &Main_r2wc_closure);
    
    26 26
     -- >
    
    27 27
     -- > }
    
    28 28
     --
    
    29 29
     -- where the constants are fingerprints produced from the static forms.
    
    30 30
     --
    
    31
    --- The linker must find the definitions matching the @extern StgPtr <name>@
    
    31
    +-- The linker must find the definitions matching the @extern StgClosure <name>@
    
    32 32
     -- declarations. For this to work, the identifiers of static pointers need to be
    
    33 33
     -- exported. This is done in 'GHC.Core.Opt.SetLevels.newLvlVar'.
    
    34 34
     --
    
    ... ... @@ -263,7 +263,7 @@ sptModuleInitCode platform this_mod entries
    263 263
             -- CLabel. Regardless, MayHaveCafRefs/NoCafRefs wouldn't make
    
    264 264
             -- any difference here, they would pretty-print to the same
    
    265 265
             -- foreign stub content.
    
    266
    -        $$ text "extern StgPtr "
    
    266
    +        $$ text "extern StgClosure "
    
    267 267
                <> (pprCLabel platform $ mkClosureLabel n MayHaveCafRefs) <> semi
    
    268 268
             $$ text "hs_spt_insert" <> parens
    
    269 269
                  (hcat $ punctuate comma
    

  • compiler/GHC/Linker/Loader.hs
    1 1
     {-# LANGUAGE CPP #-}
    
    2 2
     {-# LANGUAGE RecordWildCards #-}
    
    3 3
     {-# LANGUAGE LambdaCase #-}
    
    4
    +{-# LANGUAGE ViewPatterns #-}
    
    4 5
     
    
    5 6
     --
    
    6 7
     --  (c) The University of Glasgow 2002-2006
    
    ... ... @@ -103,6 +104,7 @@ import Data.Array
    103 104
     import Data.ByteString (ByteString)
    
    104 105
     import qualified Data.Set as Set
    
    105 106
     import Data.Char (isSpace)
    
    107
    +import Data.Foldable (for_)
    
    106 108
     import qualified Data.Foldable as Foldable
    
    107 109
     import Data.IORef
    
    108 110
     import Data.List (intercalate, isPrefixOf, nub, partition)
    
    ... ... @@ -534,7 +536,7 @@ preloadLib interp hsc_env lib_paths framework_paths pls lib_spec = do
    534 536
           return pls
    
    535 537
     
    
    536 538
         DLL dll_unadorned -> do
    
    537
    -      maybe_errstr <- loadDLL interp (platformSOName platform dll_unadorned)
    
    539
    +      maybe_errstr <- loadDLLs interp [platformSOName platform dll_unadorned]
    
    538 540
           case maybe_errstr of
    
    539 541
              Right _ -> maybePutStrLn logger "done"
    
    540 542
              Left mm | platformOS platform /= OSDarwin ->
    
    ... ... @@ -544,14 +546,14 @@ preloadLib interp hsc_env lib_paths framework_paths pls lib_spec = do
    544 546
                -- since (apparently) some things install that way - see
    
    545 547
                -- ticket #8770.
    
    546 548
                let libfile = ("lib" ++ dll_unadorned) <.> "so"
    
    547
    -           err2 <- loadDLL interp libfile
    
    549
    +           err2 <- loadDLLs interp [libfile]
    
    548 550
                case err2 of
    
    549 551
                  Right _ -> maybePutStrLn logger "done"
    
    550 552
                  Left _  -> preloadFailed mm lib_paths lib_spec
    
    551 553
           return pls
    
    552 554
     
    
    553 555
         DLLPath dll_path -> do
    
    554
    -      do maybe_errstr <- loadDLL interp dll_path
    
    556
    +      do maybe_errstr <- loadDLLs interp [dll_path]
    
    555 557
              case maybe_errstr of
    
    556 558
                 Right _ -> maybePutStrLn logger "done"
    
    557 559
                 Left mm -> preloadFailed mm lib_paths lib_spec
    
    ... ... @@ -891,7 +893,7 @@ dynLoadObjs interp hsc_env pls@LoaderState{..} objs = do
    891 893
     
    
    892 894
         -- if we got this far, extend the lifetime of the library file
    
    893 895
         changeTempFilesLifetime tmpfs TFL_GhcSession [soFile]
    
    894
    -    m <- loadDLL interp soFile
    
    896
    +    m <- loadDLLs interp [soFile]
    
    895 897
         case m of
    
    896 898
           Right _ -> return $! pls { temp_sos = (libPath, libName) : temp_sos }
    
    897 899
           Left err -> linkFail msg (text err)
    
    ... ... @@ -1128,51 +1130,76 @@ loadPackages interp hsc_env new_pkgs = do
    1128 1130
     
    
    1129 1131
     loadPackages' :: Interp -> HscEnv -> [UnitId] -> LoaderState -> IO LoaderState
    
    1130 1132
     loadPackages' interp hsc_env new_pks pls = do
    
    1131
    -    pkgs' <- link (pkgs_loaded pls) new_pks
    
    1132
    -    return $! pls { pkgs_loaded = pkgs'
    
    1133
    -                  }
    
    1133
    +  (reverse -> pkgs_info_list, pkgs_almost_loaded) <-
    
    1134
    +    downsweep
    
    1135
    +      ([], pkgs_loaded pls)
    
    1136
    +      new_pks
    
    1137
    +  loaded_pkgs_info_list <- loadPackage interp hsc_env pkgs_info_list
    
    1138
    +  evaluate $
    
    1139
    +    pls
    
    1140
    +      { pkgs_loaded =
    
    1141
    +          foldl'
    
    1142
    +            ( \pkgs (new_pkg_info, (loaded_pkg_hs_objs, loaded_pkg_non_hs_objs, loaded_pkg_hs_dlls)) ->
    
    1143
    +                adjustUDFM
    
    1144
    +                  ( \old_pkg_info ->
    
    1145
    +                      old_pkg_info
    
    1146
    +                        { loaded_pkg_hs_objs,
    
    1147
    +                          loaded_pkg_non_hs_objs,
    
    1148
    +                          loaded_pkg_hs_dlls
    
    1149
    +                        }
    
    1150
    +                  )
    
    1151
    +                  pkgs
    
    1152
    +                  (Packages.unitId new_pkg_info)
    
    1153
    +            )
    
    1154
    +            pkgs_almost_loaded
    
    1155
    +            (zip pkgs_info_list loaded_pkgs_info_list)
    
    1156
    +      }
    
    1134 1157
       where
    
    1135
    -     link :: PkgsLoaded -> [UnitId] -> IO PkgsLoaded
    
    1136
    -     link pkgs new_pkgs =
    
    1137
    -         foldM link_one pkgs new_pkgs
    
    1138
    -
    
    1139
    -     link_one pkgs new_pkg
    
    1140
    -        | new_pkg `elemUDFM` pkgs   -- Already linked
    
    1141
    -        = return pkgs
    
    1142
    -
    
    1143
    -        | Just pkg_cfg <- lookupUnitId (hsc_units hsc_env) new_pkg
    
    1144
    -        = do { let deps = unitDepends pkg_cfg
    
    1145
    -               -- Link dependents first
    
    1146
    -             ; pkgs' <- link pkgs deps
    
    1147
    -                -- Now link the package itself
    
    1148
    -             ; (hs_cls, extra_cls, loaded_dlls) <- loadPackage interp hsc_env pkg_cfg
    
    1149
    -             ; let trans_deps = unionManyUniqDSets [ addOneToUniqDSet (loaded_pkg_trans_deps loaded_pkg_info) dep_pkg
    
    1150
    -                                                   | dep_pkg <- deps
    
    1151
    -                                                   , Just loaded_pkg_info <- pure (lookupUDFM pkgs' dep_pkg)
    
    1152
    -                                                   ]
    
    1153
    -             ; return (addToUDFM pkgs' new_pkg (LoadedPkgInfo new_pkg hs_cls extra_cls loaded_dlls trans_deps)) }
    
    1154
    -
    
    1155
    -        | otherwise
    
    1156
    -        = throwGhcExceptionIO (CmdLineError ("unknown package: " ++ unpackFS (unitIdFS new_pkg)))
    
    1157
    -
    
    1158
    -
    
    1159
    -loadPackage :: Interp -> HscEnv -> UnitInfo -> IO ([LibrarySpec], [LibrarySpec], [RemotePtr LoadedDLL])
    
    1160
    -loadPackage interp hsc_env pkg
    
    1158
    +    downsweep = foldlM downsweep_one
    
    1159
    +
    
    1160
    +    downsweep_one (pkgs_info_list, pkgs) new_pkg
    
    1161
    +      | new_pkg `elemUDFM` pkgs = pure (pkgs_info_list, pkgs)
    
    1162
    +      | Just new_pkg_info <- lookupUnitId (hsc_units hsc_env) new_pkg = do
    
    1163
    +          let new_pkg_deps = unitDepends new_pkg_info
    
    1164
    +          (pkgs_info_list', pkgs') <- downsweep (pkgs_info_list, pkgs) new_pkg_deps
    
    1165
    +          let new_pkg_trans_deps =
    
    1166
    +                unionManyUniqDSets
    
    1167
    +                  [ addOneToUniqDSet (loaded_pkg_trans_deps loaded_pkg_info) dep_pkg
    
    1168
    +                  | dep_pkg <- new_pkg_deps,
    
    1169
    +                    loaded_pkg_info <- maybeToList $ pkgs' `lookupUDFM` dep_pkg
    
    1170
    +                  ]
    
    1171
    +          pure
    
    1172
    +            ( new_pkg_info : pkgs_info_list',
    
    1173
    +              addToUDFM pkgs' new_pkg $
    
    1174
    +                LoadedPkgInfo
    
    1175
    +                  { loaded_pkg_uid = new_pkg,
    
    1176
    +                    loaded_pkg_hs_objs = [],
    
    1177
    +                    loaded_pkg_non_hs_objs = [],
    
    1178
    +                    loaded_pkg_hs_dlls = [],
    
    1179
    +                    loaded_pkg_trans_deps = new_pkg_trans_deps
    
    1180
    +                  }
    
    1181
    +            )
    
    1182
    +      | otherwise =
    
    1183
    +          throwGhcExceptionIO
    
    1184
    +            (CmdLineError ("unknown package: " ++ unpackFS (unitIdFS new_pkg)))
    
    1185
    +
    
    1186
    +loadPackage :: Interp -> HscEnv -> [UnitInfo] -> IO [([LibrarySpec], [LibrarySpec], [RemotePtr LoadedDLL])]
    
    1187
    +loadPackage interp hsc_env pkgs
    
    1161 1188
        = do
    
    1162 1189
             let dflags    = hsc_dflags hsc_env
    
    1163 1190
             let logger    = hsc_logger hsc_env
    
    1164 1191
                 platform  = targetPlatform dflags
    
    1165 1192
                 is_dyn    = interpreterDynamic interp
    
    1166
    -            dirs | is_dyn    = map ST.unpack $ Packages.unitLibraryDynDirs pkg
    
    1167
    -                 | otherwise = map ST.unpack $ Packages.unitLibraryDirs pkg
    
    1193
    +            dirs | is_dyn    = [map ST.unpack $ Packages.unitLibraryDynDirs pkg | pkg <- pkgs]
    
    1194
    +                 | otherwise = [map ST.unpack $ Packages.unitLibraryDirs pkg | pkg <- pkgs]
    
    1168 1195
     
    
    1169
    -        let hs_libs   = map ST.unpack $ Packages.unitLibraries pkg
    
    1196
    +        let hs_libs   = [map ST.unpack $ Packages.unitLibraries pkg | pkg <- pkgs]
    
    1170 1197
                 -- The FFI GHCi import lib isn't needed as
    
    1171 1198
                 -- GHC.Linker.Loader + rts/Linker.c link the
    
    1172 1199
                 -- interpreted references to FFI to the compiled FFI.
    
    1173 1200
                 -- We therefore filter it out so that we don't get
    
    1174 1201
                 -- duplicate symbol errors.
    
    1175
    -            hs_libs'  =  filter ("HSffi" /=) hs_libs
    
    1202
    +            hs_libs'  =  filter ("HSffi" /=) <$> hs_libs
    
    1176 1203
     
    
    1177 1204
             -- Because of slight differences between the GHC dynamic linker and
    
    1178 1205
             -- the native system linker some packages have to link with a
    
    ... ... @@ -1181,51 +1208,54 @@ loadPackage interp hsc_env pkg
    1181 1208
             -- libs do not exactly match the .so/.dll equivalents. So if the
    
    1182 1209
             -- package file provides an "extra-ghci-libraries" field then we use
    
    1183 1210
             -- that instead of the "extra-libraries" field.
    
    1184
    -            extdeplibs = map ST.unpack (if null (Packages.unitExtDepLibsGhc pkg)
    
    1211
    +            extdeplibs = [map ST.unpack (if null (Packages.unitExtDepLibsGhc pkg)
    
    1185 1212
                                           then Packages.unitExtDepLibsSys pkg
    
    1186
    -                                      else Packages.unitExtDepLibsGhc pkg)
    
    1187
    -            linkerlibs = [ lib | '-':'l':lib <- (map ST.unpack $ Packages.unitLinkerOptions pkg) ]
    
    1188
    -            extra_libs = extdeplibs ++ linkerlibs
    
    1213
    +                                      else Packages.unitExtDepLibsGhc pkg) | pkg <- pkgs]
    
    1214
    +            linkerlibs = [[ lib | '-':'l':lib <- (map ST.unpack $ Packages.unitLinkerOptions pkg) ] | pkg <- pkgs]
    
    1215
    +            extra_libs = zipWith (++) extdeplibs linkerlibs
    
    1189 1216
     
    
    1190 1217
             -- See Note [Fork/Exec Windows]
    
    1191 1218
             gcc_paths <- getGCCPaths logger dflags (platformOS platform)
    
    1192
    -        dirs_env <- addEnvPaths "LIBRARY_PATH" dirs
    
    1219
    +        dirs_env <- traverse (addEnvPaths "LIBRARY_PATH") dirs
    
    1193 1220
     
    
    1194 1221
             hs_classifieds
    
    1195
    -           <- mapM (locateLib interp hsc_env True  dirs_env gcc_paths) hs_libs'
    
    1222
    +           <- sequenceA [mapM (locateLib interp hsc_env True  dirs_env_ gcc_paths) hs_libs'_ | (dirs_env_, hs_libs'_) <- zip dirs_env hs_libs' ]
    
    1196 1223
             extra_classifieds
    
    1197
    -           <- mapM (locateLib interp hsc_env False dirs_env gcc_paths) extra_libs
    
    1198
    -        let classifieds = hs_classifieds ++ extra_classifieds
    
    1224
    +           <- sequenceA [mapM (locateLib interp hsc_env False dirs_env_ gcc_paths) extra_libs_ | (dirs_env_, extra_libs_) <- zip dirs_env extra_libs]
    
    1225
    +        let classifieds = zipWith (++) hs_classifieds extra_classifieds
    
    1199 1226
     
    
    1200 1227
             -- Complication: all the .so's must be loaded before any of the .o's.
    
    1201
    -        let known_hs_dlls    = [ dll | DLLPath dll <- hs_classifieds ]
    
    1202
    -            known_extra_dlls = [ dll | DLLPath dll <- extra_classifieds ]
    
    1203
    -            known_dlls       = known_hs_dlls ++ known_extra_dlls
    
    1228
    +        let known_hs_dlls    = [[ dll | DLLPath dll <- hs_classifieds_ ] | hs_classifieds_ <- hs_classifieds]
    
    1229
    +            known_extra_dlls = [ dll | extra_classifieds_ <- extra_classifieds, DLLPath dll <- extra_classifieds_ ]
    
    1230
    +            known_dlls       = concat known_hs_dlls ++ known_extra_dlls
    
    1204 1231
     #if defined(CAN_LOAD_DLL)
    
    1205
    -            dlls       = [ dll  | DLL dll        <- classifieds ]
    
    1232
    +            dlls       = [ dll  | classifieds_ <- classifieds, DLL dll      <- classifieds_ ]
    
    1206 1233
     #endif
    
    1207
    -            objs       = [ obj  | Objects objs    <- classifieds
    
    1208
    -                                , obj <- objs ]
    
    1209
    -            archs      = [ arch | Archive arch   <- classifieds ]
    
    1234
    +            objs       = [ obj  | classifieds_ <- classifieds, Objects objs <- classifieds_
    
    1235
    +                                , obj <- objs]
    
    1236
    +            archs      = [ arch | classifieds_ <- classifieds, Archive arch <- classifieds_ ]
    
    1210 1237
     
    
    1211 1238
             -- Add directories to library search paths
    
    1212 1239
             let dll_paths  = map takeDirectory known_dlls
    
    1213
    -            all_paths  = nub $ map normalise $ dll_paths ++ dirs
    
    1240
    +            all_paths  = nub $ map normalise $ dll_paths ++ concat dirs
    
    1214 1241
             all_paths_env <- addEnvPaths "LD_LIBRARY_PATH" all_paths
    
    1215 1242
             pathCache <- mapM (addLibrarySearchPath interp) all_paths_env
    
    1216 1243
     
    
    1217 1244
             maybePutSDoc logger
    
    1218
    -            (text "Loading unit " <> pprUnitInfoForUser pkg <> text " ... ")
    
    1245
    +            (text "Loading units " <> vcat (map pprUnitInfoForUser pkgs) <> text " ... ")
    
    1219 1246
     
    
    1220 1247
     #if defined(CAN_LOAD_DLL)
    
    1221
    -        loadFrameworks interp platform pkg
    
    1248
    +        for_ pkgs $ loadFrameworks interp platform
    
    1222 1249
             -- See Note [Crash early load_dyn and locateLib]
    
    1223 1250
             -- Crash early if can't load any of `known_dlls`
    
    1224
    -        mapM_ (load_dyn interp hsc_env True) known_extra_dlls
    
    1225
    -        loaded_dlls <- mapMaybeM (load_dyn interp hsc_env True) known_hs_dlls
    
    1251
    +        _ <- load_dyn interp hsc_env True known_extra_dlls
    
    1252
    +        let regroup :: [[a]] -> [b] -> [[b]]
    
    1253
    +            regroup [] _ = []
    
    1254
    +            regroup (l:ls) xs = xs0: regroup ls xs1 where (xs0, xs1) = splitAt (length l) xs
    
    1255
    +        loaded_dlls <- regroup known_hs_dlls <$> load_dyn interp hsc_env True (concat known_hs_dlls)
    
    1226 1256
             -- For remaining `dlls` crash early only when there is surely
    
    1227 1257
             -- no package's DLL around ... (not is_dyn)
    
    1228
    -        mapM_ (load_dyn interp hsc_env (not is_dyn) . platformSOName platform) dlls
    
    1258
    +        _ <- load_dyn interp hsc_env (not is_dyn) $ map (platformSOName platform) dlls
    
    1229 1259
     #else
    
    1230 1260
             let loaded_dlls = []
    
    1231 1261
     #endif
    
    ... ... @@ -1247,9 +1277,9 @@ loadPackage interp hsc_env pkg
    1247 1277
             if succeeded ok
    
    1248 1278
                then do
    
    1249 1279
                  maybePutStrLn logger "done."
    
    1250
    -             return (hs_classifieds, extra_classifieds, loaded_dlls)
    
    1251
    -           else let errmsg = text "unable to load unit `"
    
    1252
    -                             <> pprUnitInfoForUser pkg <> text "'"
    
    1280
    +             pure $ zip3 hs_classifieds extra_classifieds loaded_dlls
    
    1281
    +           else let errmsg = text "unable to load units `"
    
    1282
    +                             <> vcat (map pprUnitInfoForUser pkgs) <> text "'"
    
    1253 1283
                      in throwGhcExceptionIO (InstallationError (showSDoc dflags errmsg))
    
    1254 1284
     
    
    1255 1285
     {-
    
    ... ... @@ -1299,12 +1329,12 @@ restriction very easily.
    1299 1329
     -- we have already searched the filesystem; the strings passed to load_dyn
    
    1300 1330
     -- can be passed directly to loadDLL.  They are either fully-qualified
    
    1301 1331
     -- ("/usr/lib/libfoo.so"), or unqualified ("libfoo.so").  In the latter case,
    
    1302
    --- loadDLL is going to search the system paths to find the library.
    
    1303
    -load_dyn :: Interp -> HscEnv -> Bool -> FilePath -> IO (Maybe (RemotePtr LoadedDLL))
    
    1304
    -load_dyn interp hsc_env crash_early dll = do
    
    1305
    -  r <- loadDLL interp dll
    
    1332
    +-- loadDLLs is going to search the system paths to find the library.
    
    1333
    +load_dyn :: Interp -> HscEnv -> Bool -> [FilePath] -> IO [RemotePtr LoadedDLL]
    
    1334
    +load_dyn interp hsc_env crash_early dlls = do
    
    1335
    +  r <- loadDLLs interp dlls
    
    1306 1336
       case r of
    
    1307
    -    Right loaded_dll -> pure (Just loaded_dll)
    
    1337
    +    Right loaded_dlls -> pure loaded_dlls
    
    1308 1338
         Left err ->
    
    1309 1339
           if crash_early
    
    1310 1340
             then cmdLineErrorIO err
    
    ... ... @@ -1313,7 +1343,7 @@ load_dyn interp hsc_env crash_early dll = do
    1313 1343
                 $ reportDiagnostic logger
    
    1314 1344
                     neverQualify diag_opts
    
    1315 1345
                       noSrcSpan (WarningWithFlag Opt_WarnMissedExtraSharedLib) $ withPprStyle defaultUserStyle (note err)
    
    1316
    -          pure Nothing
    
    1346
    +          pure []
    
    1317 1347
       where
    
    1318 1348
         diag_opts = initDiagOpts (hsc_dflags hsc_env)
    
    1319 1349
         logger = hsc_logger hsc_env
    
    ... ... @@ -1369,7 +1399,7 @@ locateLib interp hsc_env is_hs lib_dirs gcc_dirs lib0
    1369 1399
         --   then  look in library-dirs and inplace GCC for a static library (libfoo.a)
    
    1370 1400
         --   then  try "gcc --print-file-name" to search gcc's search path
    
    1371 1401
         --       for a dynamic library (#5289)
    
    1372
    -    --   otherwise, assume loadDLL can find it
    
    1402
    +    --   otherwise, assume loadDLLs can find it
    
    1373 1403
         --
    
    1374 1404
         --   The logic is a bit complicated, but the rationale behind it is that
    
    1375 1405
         --   loading a shared library for us is O(1) while loading an archive is
    

  • compiler/GHC/Linker/MacOS.hs
    ... ... @@ -162,7 +162,7 @@ loadFramework interp extraPaths rootname
    162 162
          -- sorry for the hardcoded paths, I hope they won't change anytime soon:
    
    163 163
          defaultFrameworkPaths = ["/Library/Frameworks", "/System/Library/Frameworks"]
    
    164 164
     
    
    165
    -     -- Try to call loadDLL for each candidate path.
    
    165
    +     -- Try to call loadDLLs for each candidate path.
    
    166 166
          --
    
    167 167
          -- See Note [macOS Big Sur dynamic libraries]
    
    168 168
          findLoadDLL [] errs =
    
    ... ... @@ -170,7 +170,7 @@ loadFramework interp extraPaths rootname
    170 170
            -- has no built-in paths for frameworks: give up
    
    171 171
            return $ Just errs
    
    172 172
          findLoadDLL (p:ps) errs =
    
    173
    -       do { dll <- loadDLL interp (p </> fwk_file)
    
    173
    +       do { dll <- loadDLLs interp [p </> fwk_file]
    
    174 174
               ; case dll of
    
    175 175
                   Right _  -> return Nothing
    
    176 176
                   Left err -> findLoadDLL ps ((p ++ ": " ++ err):errs)
    

  • compiler/GHC/Linker/Types.hs
    ... ... @@ -494,7 +494,7 @@ data LibrarySpec
    494 494
        | DLL String         -- "Unadorned" name of a .DLL/.so
    
    495 495
                             --  e.g.    On unix     "qt"  denotes "libqt.so"
    
    496 496
                             --          On Windows  "burble"  denotes "burble.DLL" or "libburble.dll"
    
    497
    -                        --  loadDLL is platform-specific and adds the lib/.so/.DLL
    
    497
    +                        --  loadDLLs is platform-specific and adds the lib/.so/.DLL
    
    498 498
                             --  suffixes platform-dependently
    
    499 499
     
    
    500 500
        | DLLPath FilePath   -- Absolute or relative pathname to a dynamic library
    

  • compiler/GHC/Runtime/Interpreter.hs
    ... ... @@ -38,7 +38,7 @@ module GHC.Runtime.Interpreter
    38 38
       , lookupSymbol
    
    39 39
       , lookupSymbolInDLL
    
    40 40
       , lookupClosure
    
    41
    -  , loadDLL
    
    41
    +  , loadDLLs
    
    42 42
       , loadArchive
    
    43 43
       , loadObj
    
    44 44
       , unloadObj
    
    ... ... @@ -559,13 +559,13 @@ withSymbolCache interp str determine_addr = do
    559 559
     purgeLookupSymbolCache :: Interp -> IO ()
    
    560 560
     purgeLookupSymbolCache interp = purgeInterpSymbolCache (interpSymbolCache interp)
    
    561 561
     
    
    562
    --- | loadDLL loads a dynamic library using the OS's native linker
    
    562
    +-- | 'loadDLLs' loads dynamic libraries using the OS's native linker
    
    563 563
     -- (i.e. dlopen() on Unix, LoadLibrary() on Windows).  It takes either
    
    564
    --- an absolute pathname to the file, or a relative filename
    
    565
    --- (e.g. "libfoo.so" or "foo.dll").  In the latter case, loadDLL
    
    566
    --- searches the standard locations for the appropriate library.
    
    567
    -loadDLL :: Interp -> String -> IO (Either String (RemotePtr LoadedDLL))
    
    564
    +-- absolute pathnames to the files, or relative filenames
    
    565
    +-- (e.g. "libfoo.so" or "foo.dll").  In the latter case, 'loadDLLs'
    
    566
    +-- searches the standard locations for the appropriate libraries.
    
    567
    +loadDLLs :: Interp -> [String] -> IO (Either String [RemotePtr LoadedDLL])
    
    568
    +loadDLLs interp strs = interpCmd interp (LoadDLLs strs)
    
    568 569
     
    
    569 570
     loadArchive :: Interp -> String -> IO ()
    
    570 571
     loadArchive interp path = do
    
    ... ... @@ -761,4 +761,3 @@ readIModModBreaks hug mod = imodBreaks_modBreaks . expectJust <$> readIModBreaks
    761 761
     fromEvalResult :: EvalResult a -> IO a
    
    762 762
     fromEvalResult (EvalException e) = throwIO (fromSerializableException e)
    
    763 763
     fromEvalResult (EvalSuccess a) = return a
    764
    -

  • compiler/GHC/Types/Name/Cache.hs
    ... ... @@ -101,9 +101,14 @@ OrigNameCache at all? Good question; after all,
    101 101
       3) Loading of interface files encodes names via Uniques, as detailed in
    
    102 102
          Note [Symbol table representation of names] in GHC.Iface.Binary
    
    103 103
     
    
    104
    -It turns out that we end up looking up built-in syntax in the cache when we
    
    105
    -generate Haddock documentation. E.g. if we don't find tuple data constructors
    
    106
    -there, hyperlinks won't work as expected. Test case: haddockHtmlTest (Bug923.hs)
    
    104
    +
    
    105
    +However note that:
    
    106
    +  1) It turns out that we end up looking up built-in syntax in the cache when
    
    107
    +     we generate Haddock documentation. E.g. if we don't find tuple data
    
    108
    +     constructors there, hyperlinks won't work as expected. Test case:
    
    109
    +     haddockHtmlTest (Bug923.hs)
    
    110
    +  2) HIE de-serialization relies on wired-in names, including built-in syntax,
    
    111
    +     being present in the OrigNameCache.
    
    107 112
     -}
    
    108 113
     
    
    109 114
     -- | The NameCache makes sure that there is just one Unique assigned for
    

  • libraries/ghci/GHCi/Message.hs
    ... ... @@ -84,7 +84,7 @@ data Message a where
    84 84
       LookupSymbol :: String -> Message (Maybe (RemotePtr ()))
    
    85 85
       LookupSymbolInDLL :: RemotePtr LoadedDLL -> String -> Message (Maybe (RemotePtr ()))
    
    86 86
       LookupClosure :: String -> Message (Maybe HValueRef)
    
    87
    -  LoadDLL :: String -> Message (Either String (RemotePtr LoadedDLL))
    
    87
    +  LoadDLLs :: [String] -> Message (Either String [RemotePtr LoadedDLL])
    
    88 88
       LoadArchive :: String -> Message () -- error?
    
    89 89
       LoadObj :: String -> Message () -- error?
    
    90 90
       UnloadObj :: String -> Message () -- error?
    
    ... ... @@ -441,7 +441,7 @@ data BreakModule
    441 441
     -- that type isn't available here.
    
    442 442
     data BreakUnitId
    
    443 443
     
    
    444
    --- | A dummy type that tags pointers returned by 'LoadDLL'.
    
    444
    +-- | A dummy type that tags pointers returned by 'LoadDLLs'.
    
    445 445
     data LoadedDLL
    
    446 446
     
    
    447 447
     -- SomeException can't be serialized because it contains dynamic
    
    ... ... @@ -555,7 +555,7 @@ getMessage = do
    555 555
           1  -> Msg <$> return InitLinker
    
    556 556
           2  -> Msg <$> LookupSymbol <$> get
    
    557 557
           3  -> Msg <$> LookupClosure <$> get
    
    558
    -      4  -> Msg <$> LoadDLL <$> get
    
    558
    +      4  -> Msg <$> LoadDLLs <$> get
    
    559 559
           5  -> Msg <$> LoadArchive <$> get
    
    560 560
           6  -> Msg <$> LoadObj <$> get
    
    561 561
           7  -> Msg <$> UnloadObj <$> get
    
    ... ... @@ -601,7 +601,7 @@ putMessage m = case m of
    601 601
       InitLinker                  -> putWord8 1
    
    602 602
       LookupSymbol str            -> putWord8 2  >> put str
    
    603 603
       LookupClosure str           -> putWord8 3  >> put str
    
    604
    -  LoadDLL str                 -> putWord8 4  >> put str
    
    604
    +  LoadDLLs strs               -> putWord8 4  >> put strs
    
    605 605
       LoadArchive str             -> putWord8 5  >> put str
    
    606 606
       LoadObj str                 -> putWord8 6  >> put str
    
    607 607
       UnloadObj str               -> putWord8 7  >> put str
    

  • libraries/ghci/GHCi/ObjLink.hs
    ... ... @@ -12,7 +12,7 @@
    12 12
     -- dynamic linker.
    
    13 13
     module GHCi.ObjLink
    
    14 14
       ( initObjLinker, ShouldRetainCAFs(..)
    
    15
    -  , loadDLL
    
    15
    +  , loadDLLs
    
    16 16
       , loadArchive
    
    17 17
       , loadObj
    
    18 18
       , unloadObj
    
    ... ... @@ -43,6 +43,10 @@ import Control.Exception (catch, evaluate)
    43 43
     import GHC.Wasm.Prim
    
    44 44
     #endif
    
    45 45
     
    
    46
    +#if defined(wasm32_HOST_ARCH)
    
    47
    +import Data.List (intercalate)
    
    48
    +#endif
    
    49
    +
    
    46 50
     -- ---------------------------------------------------------------------------
    
    47 51
     -- RTS Linker Interface
    
    48 52
     -- ---------------------------------------------------------------------------
    
    ... ... @@ -67,20 +71,25 @@ data ShouldRetainCAFs
    67 71
     initObjLinker :: ShouldRetainCAFs -> IO ()
    
    68 72
     initObjLinker _ = pure ()
    
    69 73
     
    
    70
    -loadDLL :: String -> IO (Either String (Ptr LoadedDLL))
    
    71
    -loadDLL f =
    
    74
    +-- Batch load multiple DLLs at once via dyld to enable a single
    
    75
    +-- dependency resolution and more parallel compilation. We pass a
    
    76
    +-- NUL-delimited JSString to avoid array marshalling on wasm.
    
    77
    +loadDLLs :: [String] -> IO (Either String [Ptr LoadedDLL])
    
    78
    +loadDLLs fs =
    
    72 79
       m `catch` \(err :: JSException) ->
    
    73
    -    pure $ Left $ "loadDLL failed for " <> f <> ": " <> show err
    
    80
    +    pure $ Left $ "loadDLLs failed: " <> show err
    
    74 81
       where
    
    82
    +    packed :: JSString
    
    83
    +    packed = toJSString (intercalate ['\0'] fs)
    
    75 84
         m = do
    
    76
    -      evaluate =<< js_loadDLL (toJSString f)
    
    77
    -      pure $ Right nullPtr
    
    85
    +      evaluate =<< js_loadDLLs packed
    
    86
    +      pure $ Right (replicate (length fs) nullPtr)
    
    78 87
     
    
    79 88
     -- See Note [Variable passing in JSFFI] for where
    
    80 89
     -- __ghc_wasm_jsffi_dyld comes from
    
    81 90
     
    
    82
    -foreign import javascript safe "__ghc_wasm_jsffi_dyld.loadDLL($1)"
    
    83
    -  js_loadDLL :: JSString -> IO ()
    
    91
    +foreign import javascript safe "__ghc_wasm_jsffi_dyld.loadDLLs($1)"
    
    92
    +  js_loadDLLs :: JSString -> IO ()
    
    84 93
     
    
    85 94
     loadArchive :: String -> IO ()
    
    86 95
     loadArchive f = throwIO $ ErrorCall $ "loadArchive: unsupported on wasm for " <> f
    
    ... ... @@ -241,6 +250,16 @@ resolveObjs = do
    241 250
        r <- c_resolveObjs
    
    242 251
        return (r /= 0)
    
    243 252
     
    
    253
    +loadDLLs :: [String] -> IO (Either String [Ptr LoadedDLL])
    
    254
    +loadDLLs = go []
    
    255
    +  where
    
    256
    +    go acc [] = pure (Right (reverse acc))
    
    257
    +    go acc (p:ps) = do
    
    258
    +      r <- loadDLL p
    
    259
    +      case r of
    
    260
    +        Left err -> pure (Left err)
    
    261
    +        Right h  -> go (h:acc) ps
    
    262
    +
    
    244 263
     -- ---------------------------------------------------------------------------
    
    245 264
     -- Foreign declarations to RTS entry points which does the real work;
    
    246 265
     -- ---------------------------------------------------------------------------
    

  • libraries/ghci/GHCi/Run.hs
    ... ... @@ -57,7 +57,7 @@ run m = case m of
    57 57
     #if defined(javascript_HOST_ARCH)
    
    58 58
       LoadObj p                   -> withCString p loadJS
    
    59 59
       InitLinker                  -> notSupportedJS m
    
    60
    -  LoadDLL {}                  -> notSupportedJS m
    
    60
    +  LoadDLLs {}                 -> notSupportedJS m
    
    61 61
       LoadArchive {}              -> notSupportedJS m
    
    62 62
       UnloadObj {}                -> notSupportedJS m
    
    63 63
       AddLibrarySearchPath {}     -> notSupportedJS m
    
    ... ... @@ -69,7 +69,7 @@ run m = case m of
    69 69
       LookupClosure str           -> lookupJSClosure str
    
    70 70
     #else
    
    71 71
       InitLinker -> initObjLinker RetainCAFs
    
    72
    -  LoadDLL str -> fmap toRemotePtr <$> loadDLL str
    
    72
    +  LoadDLLs strs -> fmap (map toRemotePtr) <$> loadDLLs strs
    
    73 73
       LoadArchive str -> loadArchive str
    
    74 74
       LoadObj str -> loadObj str
    
    75 75
       UnloadObj str -> unloadObj str
    

  • testsuite/tests/rts/linker/T2615.hs
    ... ... @@ -4,7 +4,7 @@ library_name = "libfoo_script_T2615.so" -- this is really a linker script
    4 4
     
    
    5 5
     main = do
    
    6 6
       initObjLinker RetainCAFs
    
    7
    -  result <- loadDLL library_name
    
    7
    +  result <- loadDLLs [library_name]
    
    8 8
       case result of
    
    9 9
         Right _ -> putStrLn (library_name ++ " loaded successfully")
    
    10 10
         Left x  -> putStrLn ("error: " ++ x)

  • utils/haddock/haddock-api/src/Haddock/InterfaceFile.hs
    ... ... @@ -229,10 +229,7 @@ writeInterfaceFile filename iface = do
    229 229
       return ()
    
    230 230
     
    
    231 231
     freshNameCache :: IO NameCache
    
    232
    -freshNameCache =
    
    233
    -  initNameCache
    
    234
    -    'a' -- ??
    
    235
    -    []
    
    232
    +freshNameCache = newNameCache
    
    236 233
     
    
    237 234
     -- | Read a Haddock (@.haddock@) interface file. Return either an
    
    238 235
     -- 'InterfaceFile' or an error message.
    

  • utils/jsffi/dyld.mjs
    ... ... @@ -9,7 +9,7 @@
    9 9
     //    iserv (GHCi.Server.defaultServer). This part only runs in
    
    10 10
     //    nodejs.
    
    11 11
     // 2. Dynamic linker: provide RTS linker interfaces like
    
    12
    -//    loadDLL/lookupSymbol etc which are imported by wasm iserv. This
    
    12
    +//    loadDLLs/lookupSymbol etc which are imported by wasm iserv. This
    
    13 13
     //    part can run in browsers as well.
    
    14 14
     //
    
    15 15
     // When GHC starts external interpreter for the wasm target, it starts
    
    ... ... @@ -50,7 +50,7 @@
    50 50
     //
    
    51 51
     // *** What works right now and what doesn't work yet?
    
    52 52
     //
    
    53
    -// loadDLL & bytecode interpreter work. Template Haskell & ghci work.
    
    53
    +// loadDLLs & bytecode interpreter work. Template Haskell & ghci work.
    
    54 54
     // Profiled dynamic code works. Compiled code and bytecode can all be
    
    55 55
     // loaded, though the side effects are constrained to what's supported
    
    56 56
     // by wasi preview1: we map the full host filesystem into wasm cause
    
    ... ... @@ -801,17 +801,17 @@ class DyLD {
    801 801
         return this.#rpc.findSystemLibrary(f);
    
    802 802
       }
    
    803 803
     
    
    804
    -  // When we do loadDLL, we first perform "downsweep" which return a
    
    804
    +  // When we do loadDLLs, we first perform "downsweep" which return a
    
    805 805
       // toposorted array of dependencies up to itself, then sequentially
    
    806 806
       // load the downsweep result.
    
    807 807
       //
    
    808 808
       // The rationale of a separate downsweep phase, instead of a simple
    
    809
    -  // recursive loadDLL function is: V8 delegates async
    
    809
    +  // recursive loadDLLs function is: V8 delegates async
    
    810 810
       // WebAssembly.compile to a background worker thread pool. To
    
    811 811
       // maintain consistent internal linker state, we *must* load each so
    
    812 812
       // file sequentially, but it's okay to kick off compilation asap,
    
    813 813
       // store the Promise in downsweep result and await for the actual
    
    814
    -  // WebAssembly.Module in loadDLL logic. This way we can harness some
    
    814
    +  // WebAssembly.Module in loadDLLs logic. This way we can harness some
    
    815 815
       // background parallelism.
    
    816 816
       async #downsweep(p) {
    
    817 817
         const toks = p.split("/");
    
    ... ... @@ -852,8 +852,26 @@ class DyLD {
    852 852
         return acc;
    
    853 853
       }
    
    854 854
     
    
    855
    -  // The real stuff
    
    856
    -  async loadDLL(p) {
    
    855
    +  // Batch load multiple DLLs in one go.
    
    856
    +  // Accepts a NUL-delimited string of paths to avoid array marshalling.
    
    857
    +  // Each path can be absolute or a soname; dependency resolution is
    
    858
    +  // performed across the full set to enable maximal parallel compile
    
    859
    +  // while maintaining sequential instantiation order.
    
    860
    +  async loadDLLs(packed) {
    
    861
    +    // Normalize input to an array of strings. When called from Haskell
    
    862
    +    // we pass a single JSString containing NUL-separated paths.
    
    863
    +    const paths = (typeof packed === "string"
    
    864
    +      ? (packed.length === 0 ? [] : packed.split("\0"))
    
    865
    +      : [packed] // tolerate an accidental single path object
    
    866
    +    ).filter((s) => s.length > 0);
    
    867
    +
    
    868
    +    // Compute a single downsweep plan for the whole batch.
    
    869
    +    // Note: #downsweep mutates #loadedSos to break cycles and dedup.
    
    870
    +    const plan = [];
    
    871
    +    for (const p of paths) {
    
    872
    +      plan.push(...(await this.#downsweep(p)));
    
    873
    +    }
    
    874
    +
    
    857 875
         for (const {
    
    858 876
           memSize,
    
    859 877
           memP2Align,
    
    ... ... @@ -861,7 +879,7 @@ class DyLD {
    861 879
           tableP2Align,
    
    862 880
           modp,
    
    863 881
           soname,
    
    864
    -    } of await this.#downsweep(p)) {
    
    882
    +    } of plan) {
    
    865 883
           const import_obj = {
    
    866 884
             wasi_snapshot_preview1: this.#wasi.wasiImport,
    
    867 885
             env: {
    
    ... ... @@ -1138,7 +1156,7 @@ export async function main({ rpc, libdir, ghciSoPath, args }) {
    1138 1156
           rpc,
    
    1139 1157
         });
    
    1140 1158
         await dyld.addLibrarySearchPath(libdir);
    
    1141
    -    await dyld.loadDLL(ghciSoPath);
    
    1159
    +    await dyld.loadDLLs(ghciSoPath);
    
    1142 1160
     
    
    1143 1161
         const reader = rpc.readStream.getReader();
    
    1144 1162
         const writer = rpc.writeStream.getWriter();