Cheng Shao pushed to branch wip/batch-loaddll at Glasgow Haskell Compiler / GHC
Commits:
-
42724462
by Simon Hengel at 2025-08-21T17:52:11-04:00
-
6a43f8ec
by Cheng Shao at 2025-08-21T17:52:52-04:00
-
65384837
by Cheng Shao at 2025-08-22T20:09:08+02:00
-
6bd22d2c
by Cheng Shao at 2025-08-22T20:09:08+02:00
-
1f88562c
by Cheng Shao at 2025-08-22T20:09:08+02:00
15 changed files:
- compiler/GHC/Driver/Plugins.hs
- compiler/GHC/Iface/Ext/Binary.hs
- compiler/GHC/Iface/Ext/Types.hs
- compiler/GHC/Iface/Tidy/StaticPtrTable.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/MacOS.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/Types/Name/Cache.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/ObjLink.hs
- libraries/ghci/GHCi/Run.hs
- testsuite/tests/rts/linker/T2615.hs
- utils/haddock/haddock-api/src/Haddock/InterfaceFile.hs
- utils/jsffi/dyld.mjs
Changes:
... | ... | @@ -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
|
... | ... | @@ -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" |
... | ... | @@ -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]
|
... | ... | @@ -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
|
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
|
... | ... | @@ -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)
|
... | ... | @@ -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
|
... | ... | @@ -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 | - |
... | ... | @@ -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
|
... | ... | @@ -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
|
... | ... | @@ -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 | -- ---------------------------------------------------------------------------
|
... | ... | @@ -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
|
... | ... | @@ -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) |
... | ... | @@ -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.
|
... | ... | @@ -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();
|