Cheng Shao pushed to branch wip/batch-loaddll at Glasgow Haskell Compiler / GHC
Commits:
-
f0a19d74
by fendor at 2025-08-20T19:55:00-04:00
-
ebeb991b
by fendor at 2025-08-20T19:55:00-04:00
-
e368e247
by Rodrigo Mesquita at 2025-08-20T19:55:42-04:00
-
c38e97c7
by Cheng Shao at 2025-08-21T05:21:37+02:00
-
57467d9e
by Cheng Shao at 2025-08-21T05:21:41+02:00
19 changed files:
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/Driver/Plugins.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/MacOS.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- libraries/base/changelog.md
- libraries/base/src/GHC/Exts.hs
- libraries/ghci/GHCi/CreateBCO.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/ObjLink.hs
- libraries/ghci/GHCi/Run.hs
- libraries/ghci/GHCi/TH.hs
- libraries/ghci/ghci.cabal.in
- rts/Disassembler.c
- rts/Interpreter.c
- − testsuite/tests/module/T21752.stderr
- testsuite/tests/rts/linker/T2615.hs
- utils/jsffi/dyld.mjs
Changes:
| ... | ... | @@ -843,16 +843,18 @@ assembleI platform i = case i of |
| 843 | 843 | |
| 844 | 844 | BRK_FUN ibi@(InternalBreakpointId info_mod infox) -> do
|
| 845 | 845 | p1 <- ptr $ BCOPtrBreakArray info_mod
|
| 846 | - let -- cast that checks that round-tripping through Word16 doesn't change the value
|
|
| 847 | - toW16 x = let r = fromIntegral x :: Word16
|
|
| 848 | - in if fromIntegral r == x
|
|
| 846 | + let -- cast that checks that round-tripping through Word32 doesn't change the value
|
|
| 847 | + infoW32 = let r = fromIntegral infox :: Word32
|
|
| 848 | + in if fromIntegral r == infox
|
|
| 849 | 849 | then r
|
| 850 | - else pprPanic "schemeER_wrk: breakpoint tick/info index too large!" (ppr x)
|
|
| 850 | + else pprPanic "schemeER_wrk: breakpoint tick/info index too large!" (ppr infox)
|
|
| 851 | + ix_hi = fromIntegral (infoW32 `shiftR` 16)
|
|
| 852 | + ix_lo = fromIntegral (infoW32 .&. 0xffff)
|
|
| 851 | 853 | info_addr <- lit1 $ BCONPtrFS $ moduleNameFS $ moduleName info_mod
|
| 852 | 854 | info_unitid_addr <- lit1 $ BCONPtrFS $ unitIdFS $ moduleUnitId info_mod
|
| 853 | 855 | np <- lit1 $ BCONPtrCostCentre ibi
|
| 854 | 856 | emit_ bci_BRK_FUN [ Op p1, Op info_addr, Op info_unitid_addr
|
| 855 | - , SmallOp (toW16 infox), Op np ]
|
|
| 857 | + , SmallOp ix_hi, SmallOp ix_lo, Op np ]
|
|
| 856 | 858 | |
| 857 | 859 | BRK_ALTS active -> emit_ bci_BRK_ALTS [SmallOp (if active then 1 else 0)]
|
| 858 | 860 |
| ... | ... | @@ -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
|
| 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
|
| ... | ... | @@ -534,7 +535,7 @@ preloadLib interp hsc_env lib_paths framework_paths pls lib_spec = do |
| 534 | 535 | return pls
|
| 535 | 536 | |
| 536 | 537 | DLL dll_unadorned -> do
|
| 537 | - maybe_errstr <- loadDLL interp (platformSOName platform dll_unadorned)
|
|
| 538 | + maybe_errstr <- loadDLLs interp [platformSOName platform dll_unadorned]
|
|
| 538 | 539 | case maybe_errstr of
|
| 539 | 540 | Right _ -> maybePutStrLn logger "done"
|
| 540 | 541 | Left mm | platformOS platform /= OSDarwin ->
|
| ... | ... | @@ -544,14 +545,14 @@ preloadLib interp hsc_env lib_paths framework_paths pls lib_spec = do |
| 544 | 545 | -- since (apparently) some things install that way - see
|
| 545 | 546 | -- ticket #8770.
|
| 546 | 547 | let libfile = ("lib" ++ dll_unadorned) <.> "so"
|
| 547 | - err2 <- loadDLL interp libfile
|
|
| 548 | + err2 <- loadDLLs interp [libfile]
|
|
| 548 | 549 | case err2 of
|
| 549 | 550 | Right _ -> maybePutStrLn logger "done"
|
| 550 | 551 | Left _ -> preloadFailed mm lib_paths lib_spec
|
| 551 | 552 | return pls
|
| 552 | 553 | |
| 553 | 554 | DLLPath dll_path -> do
|
| 554 | - do maybe_errstr <- loadDLL interp dll_path
|
|
| 555 | + do maybe_errstr <- loadDLLs interp [dll_path]
|
|
| 555 | 556 | case maybe_errstr of
|
| 556 | 557 | Right _ -> maybePutStrLn logger "done"
|
| 557 | 558 | Left mm -> preloadFailed mm lib_paths lib_spec
|
| ... | ... | @@ -891,7 +892,7 @@ dynLoadObjs interp hsc_env pls@LoaderState{..} objs = do |
| 891 | 892 | |
| 892 | 893 | -- if we got this far, extend the lifetime of the library file
|
| 893 | 894 | changeTempFilesLifetime tmpfs TFL_GhcSession [soFile]
|
| 894 | - m <- loadDLL interp soFile
|
|
| 895 | + m <- loadDLLs interp [soFile]
|
|
| 895 | 896 | case m of
|
| 896 | 897 | Right _ -> return $! pls { temp_sos = (libPath, libName) : temp_sos }
|
| 897 | 898 | Left err -> linkFail msg (text err)
|
| ... | ... | @@ -1128,33 +1129,57 @@ loadPackages interp hsc_env new_pkgs = do |
| 1128 | 1129 | |
| 1129 | 1130 | loadPackages' :: Interp -> HscEnv -> [UnitId] -> LoaderState -> IO LoaderState
|
| 1130 | 1131 | loadPackages' interp hsc_env new_pks pls = do
|
| 1131 | - pkgs' <- link (pkgs_loaded pls) new_pks
|
|
| 1132 | - return $! pls { pkgs_loaded = pkgs'
|
|
| 1132 | + (reverse -> pkgs_info_list, pkgs_almost_loaded) <-
|
|
| 1133 | + downsweep
|
|
| 1134 | + ([], pkgs_loaded pls)
|
|
| 1135 | + new_pks
|
|
| 1136 | + let link_one pkgs new_pkg_info = do
|
|
| 1137 | + (hs_cls, extra_cls, loaded_dlls) <-
|
|
| 1138 | + loadPackage
|
|
| 1139 | + interp
|
|
| 1140 | + hsc_env
|
|
| 1141 | + new_pkg_info
|
|
| 1142 | + evaluate $
|
|
| 1143 | + adjustUDFM
|
|
| 1144 | + ( \old_pkg_info ->
|
|
| 1145 | + old_pkg_info
|
|
| 1146 | + { loaded_pkg_hs_objs = hs_cls,
|
|
| 1147 | + loaded_pkg_non_hs_objs = extra_cls,
|
|
| 1148 | + loaded_pkg_hs_dlls = loaded_dlls
|
|
| 1133 | 1149 | }
|
| 1150 | + )
|
|
| 1151 | + pkgs
|
|
| 1152 | + (Packages.unitId new_pkg_info)
|
|
| 1153 | + pkgs_loaded' <- foldlM link_one pkgs_almost_loaded pkgs_info_list
|
|
| 1154 | + evaluate $ pls {pkgs_loaded = pkgs_loaded'}
|
|
| 1134 | 1155 | 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 | - |
|
| 1156 | + downsweep = foldlM downsweep_one
|
|
| 1157 | + |
|
| 1158 | + downsweep_one (pkgs_info_list, pkgs) new_pkg
|
|
| 1159 | + | new_pkg `elemUDFM` pkgs = pure (pkgs_info_list, pkgs)
|
|
| 1160 | + | Just new_pkg_info <- lookupUnitId (hsc_units hsc_env) new_pkg = do
|
|
| 1161 | + let new_pkg_deps = unitDepends new_pkg_info
|
|
| 1162 | + (pkgs_info_list', pkgs') <- downsweep (pkgs_info_list, pkgs) new_pkg_deps
|
|
| 1163 | + let new_pkg_trans_deps =
|
|
| 1164 | + unionManyUniqDSets
|
|
| 1165 | + [ addOneToUniqDSet (loaded_pkg_trans_deps loaded_pkg_info) dep_pkg
|
|
| 1166 | + | dep_pkg <- new_pkg_deps,
|
|
| 1167 | + loaded_pkg_info <- maybeToList $ pkgs' `lookupUDFM` dep_pkg
|
|
| 1168 | + ]
|
|
| 1169 | + pure
|
|
| 1170 | + ( new_pkg_info : pkgs_info_list',
|
|
| 1171 | + addToUDFM pkgs' new_pkg $
|
|
| 1172 | + LoadedPkgInfo
|
|
| 1173 | + { loaded_pkg_uid = new_pkg,
|
|
| 1174 | + loaded_pkg_hs_objs = [],
|
|
| 1175 | + loaded_pkg_non_hs_objs = [],
|
|
| 1176 | + loaded_pkg_hs_dlls = [],
|
|
| 1177 | + loaded_pkg_trans_deps = new_pkg_trans_deps
|
|
| 1178 | + }
|
|
| 1179 | + )
|
|
| 1180 | + | otherwise =
|
|
| 1181 | + throwGhcExceptionIO
|
|
| 1182 | + (CmdLineError ("unknown package: " ++ unpackFS (unitIdFS new_pkg)))
|
|
| 1158 | 1183 | |
| 1159 | 1184 | loadPackage :: Interp -> HscEnv -> UnitInfo -> IO ([LibrarySpec], [LibrarySpec], [RemotePtr LoadedDLL])
|
| 1160 | 1185 | loadPackage interp hsc_env pkg
|
| ... | ... | @@ -1221,11 +1246,11 @@ loadPackage interp hsc_env pkg |
| 1221 | 1246 | loadFrameworks interp platform pkg
|
| 1222 | 1247 | -- See Note [Crash early load_dyn and locateLib]
|
| 1223 | 1248 | -- 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
|
|
| 1249 | + _ <- load_dyn interp hsc_env True known_extra_dlls
|
|
| 1250 | + loaded_dlls <- load_dyn interp hsc_env True known_hs_dlls
|
|
| 1226 | 1251 | -- For remaining `dlls` crash early only when there is surely
|
| 1227 | 1252 | -- no package's DLL around ... (not is_dyn)
|
| 1228 | - mapM_ (load_dyn interp hsc_env (not is_dyn) . platformSOName platform) dlls
|
|
| 1253 | + _ <- load_dyn interp hsc_env (not is_dyn) $ map (platformSOName platform) dlls
|
|
| 1229 | 1254 | #else
|
| 1230 | 1255 | let loaded_dlls = []
|
| 1231 | 1256 | #endif
|
| ... | ... | @@ -1299,12 +1324,12 @@ restriction very easily. |
| 1299 | 1324 | -- we have already searched the filesystem; the strings passed to load_dyn
|
| 1300 | 1325 | -- can be passed directly to loadDLL. They are either fully-qualified
|
| 1301 | 1326 | -- ("/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
|
|
| 1327 | +-- loadDLLs is going to search the system paths to find the library.
|
|
| 1328 | +load_dyn :: Interp -> HscEnv -> Bool -> [FilePath] -> IO [RemotePtr LoadedDLL]
|
|
| 1329 | +load_dyn interp hsc_env crash_early dlls = do
|
|
| 1330 | + r <- loadDLLs interp dlls
|
|
| 1306 | 1331 | case r of
|
| 1307 | - Right loaded_dll -> pure (Just loaded_dll)
|
|
| 1332 | + Right loaded_dlls -> pure loaded_dlls
|
|
| 1308 | 1333 | Left err ->
|
| 1309 | 1334 | if crash_early
|
| 1310 | 1335 | then cmdLineErrorIO err
|
| ... | ... | @@ -1313,7 +1338,7 @@ load_dyn interp hsc_env crash_early dll = do |
| 1313 | 1338 | $ reportDiagnostic logger
|
| 1314 | 1339 | neverQualify diag_opts
|
| 1315 | 1340 | noSrcSpan (WarningWithFlag Opt_WarnMissedExtraSharedLib) $ withPprStyle defaultUserStyle (note err)
|
| 1316 | - pure Nothing
|
|
| 1341 | + pure []
|
|
| 1317 | 1342 | where
|
| 1318 | 1343 | diag_opts = initDiagOpts (hsc_dflags hsc_env)
|
| 1319 | 1344 | logger = hsc_logger hsc_env
|
| ... | ... | @@ -1369,7 +1394,7 @@ locateLib interp hsc_env is_hs lib_dirs gcc_dirs lib0 |
| 1369 | 1394 | -- then look in library-dirs and inplace GCC for a static library (libfoo.a)
|
| 1370 | 1395 | -- then try "gcc --print-file-name" to search gcc's search path
|
| 1371 | 1396 | -- for a dynamic library (#5289)
|
| 1372 | - -- otherwise, assume loadDLL can find it
|
|
| 1397 | + -- otherwise, assume loadDLLs can find it
|
|
| 1373 | 1398 | --
|
| 1374 | 1399 | -- The logic is a bit complicated, but the rationale behind it is that
|
| 1375 | 1400 | -- 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 | - |
| 1 | 1 | # Changelog for [`base` package](http://hackage.haskell.org/package/base)
|
| 2 | 2 | |
| 3 | 3 | ## 4.23.0.0 *TBA*
|
| 4 | + * Remove deprecated, unstable heap representation details from `GHC.Exts` ([CLC proposal #212](https://github.com/haskell/core-libraries-committee/issues/212))
|
|
| 4 | 5 | * Add `Data.List.NonEmpty.mapMaybe`. ([CLC proposal #337](https://github.com/haskell/core-libraries-committee/issues/337))
|
| 5 | 6 | * Fix issues with toRational for types capable to represent infinite and not-a-number values ([CLC proposal #338](https://github.com/haskell/core-libraries-committee/issues/338))
|
| 6 | 7 | * Modify the implementation of `Data.List.sortOn` to use `(>)` instead of `compare`. ([CLC proposal #332](https://github.com/haskell/core-libraries-committee/issues/332))
|
| ... | ... | @@ -26,12 +26,6 @@ module GHC.Exts |
| 26 | 26 | -- ** Legacy interface for arrays of arrays
|
| 27 | 27 | module GHC.Internal.ArrayArray,
|
| 28 | 28 | -- * Primitive operations
|
| 29 | - {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
|
|
| 30 | - Prim.BCO,
|
|
| 31 | - {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
|
|
| 32 | - Prim.mkApUpd0#,
|
|
| 33 | - {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
|
|
| 34 | - Prim.newBCO#,
|
|
| 35 | 29 | module GHC.Prim,
|
| 36 | 30 | module GHC.Prim.Ext,
|
| 37 | 31 | -- ** Running 'RealWorld' state thread
|
| ... | ... | @@ -130,9 +124,6 @@ import GHC.Prim hiding |
| 130 | 124 | , whereFrom#
|
| 131 | 125 | , isByteArrayWeaklyPinned#, isMutableByteArrayWeaklyPinned#
|
| 132 | 126 | |
| 133 | - -- deprecated
|
|
| 134 | - , BCO, mkApUpd0#, newBCO#
|
|
| 135 | - |
|
| 136 | 127 | -- Don't re-export vector FMA instructions
|
| 137 | 128 | , fmaddFloatX4#
|
| 138 | 129 | , fmsubFloatX4#
|
| ... | ... | @@ -255,8 +246,6 @@ import GHC.Prim hiding |
| 255 | 246 | , minWord8X32#
|
| 256 | 247 | , minWord8X64#
|
| 257 | 248 | )
|
| 258 | -import qualified GHC.Prim as Prim
|
|
| 259 | - ( BCO, mkApUpd0#, newBCO# )
|
|
| 260 | 249 | |
| 261 | 250 | import GHC.Prim.Ext
|
| 262 | 251 |
| ... | ... | @@ -6,10 +6,6 @@ |
| 6 | 6 | {-# LANGUAGE UnboxedTuples #-}
|
| 7 | 7 | {-# LANGUAGE RecordWildCards #-}
|
| 8 | 8 | {-# LANGUAGE CPP #-}
|
| 9 | -{-# OPTIONS_GHC -Wno-warnings-deprecations #-}
|
|
| 10 | --- TODO We want to import GHC.Internal.Base (BCO, mkApUpd0#, newBCO#) instead
|
|
| 11 | --- of from GHC.Exts when we can require of the bootstrap compiler to have
|
|
| 12 | --- ghc-internal.
|
|
| 13 | 9 | |
| 14 | 10 | --
|
| 15 | 11 | -- (c) The University of Glasgow 2002-2006
|
| ... | ... | @@ -30,7 +26,8 @@ import Data.Array.Base |
| 30 | 26 | import Foreign hiding (newArray)
|
| 31 | 27 | import Unsafe.Coerce (unsafeCoerce)
|
| 32 | 28 | import GHC.Arr ( Array(..) )
|
| 33 | -import GHC.Exts
|
|
| 29 | +import GHC.Exts hiding ( BCO, mkApUpd0#, newBCO# )
|
|
| 30 | +import GHC.Internal.Base ( BCO, mkApUpd0#, newBCO# )
|
|
| 34 | 31 | import GHC.IO
|
| 35 | 32 | import Control.Exception ( ErrorCall(..) )
|
| 36 | 33 |
| ... | ... | @@ -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
|
| 1 | 1 | {-# LANGUAGE ScopedTypeVariables, StandaloneDeriving, DeriveGeneric,
|
| 2 | 2 | TupleSections, RecordWildCards, InstanceSigs, CPP #-}
|
| 3 | 3 | {-# OPTIONS_GHC -fno-warn-name-shadowing #-}
|
| 4 | -{-# OPTIONS_GHC -Wno-warnings-deprecations #-}
|
|
| 5 | --- TODO We want to import GHC.Internal.Desugar instead of GHC.Desugar when we
|
|
| 6 | --- can require of the bootstrap compiler to have ghc-internal.
|
|
| 7 | 4 | |
| 8 | 5 | -- |
|
| 9 | 6 | -- Running TH splices
|
| ... | ... | @@ -112,7 +109,7 @@ import Data.IORef |
| 112 | 109 | import Data.Map (Map)
|
| 113 | 110 | import qualified Data.Map as M
|
| 114 | 111 | import Data.Maybe
|
| 115 | -import GHC.Desugar (AnnotationWrapper(..))
|
|
| 112 | +import GHC.Internal.Desugar (AnnotationWrapper(..))
|
|
| 116 | 113 | import qualified GHC.Boot.TH.Syntax as TH
|
| 117 | 114 | import Unsafe.Coerce
|
| 118 | 115 |
| ... | ... | @@ -86,11 +86,7 @@ library |
| 86 | 86 | rts,
|
| 87 | 87 | array == 0.5.*,
|
| 88 | 88 | base >= 4.8 && < 4.23,
|
| 89 | - -- ghc-internal == @ProjectVersionForLib@.*
|
|
| 90 | - -- TODO: Use GHC.Internal.Desugar and GHC.Internal.Base from
|
|
| 91 | - -- ghc-internal instead of ignoring the deprecation warning in GHCi.TH
|
|
| 92 | - -- and GHCi.CreateBCO when we require ghc-internal of the bootstrap
|
|
| 93 | - -- compiler
|
|
| 89 | + ghc-internal >= 9.1001.0 && <=@ProjectVersionForLib@.0,
|
|
| 94 | 90 | ghc-prim >= 0.5.0 && < 0.14,
|
| 95 | 91 | binary == 0.8.*,
|
| 96 | 92 | bytestring >= 0.10 && < 0.13,
|
| ... | ... | @@ -89,7 +89,7 @@ disInstr ( StgBCO *bco, int pc ) |
| 89 | 89 | p1 = BCO_GET_LARGE_ARG;
|
| 90 | 90 | info_mod = BCO_GET_LARGE_ARG;
|
| 91 | 91 | info_unit_id = BCO_GET_LARGE_ARG;
|
| 92 | - info_wix = BCO_NEXT;
|
|
| 92 | + info_wix = BCO_READ_NEXT_32;
|
|
| 93 | 93 | np = BCO_GET_LARGE_ARG;
|
| 94 | 94 | debugBelch ("BRK_FUN " ); printPtr( ptrs[p1] );
|
| 95 | 95 | debugBelch("%" FMT_Word, literals[info_mod] );
|
| ... | ... | @@ -720,7 +720,7 @@ interpretBCO (Capability* cap) |
| 720 | 720 | arg1_brk_array = BCO_GET_LARGE_ARG;
|
| 721 | 721 | /* info_mod_name = */ BCO_GET_LARGE_ARG;
|
| 722 | 722 | /* info_mod_id = */ BCO_GET_LARGE_ARG;
|
| 723 | - arg4_info_index = BCO_NEXT;
|
|
| 723 | + arg4_info_index = BCO_READ_NEXT_32;
|
|
| 724 | 724 | |
| 725 | 725 | StgPtr* ptrs = (StgPtr*)(&bco->ptrs->payload[0]);
|
| 726 | 726 | StgArrBytes* breakPoints = (StgArrBytes *) BCO_PTR(arg1_brk_array);
|
| ... | ... | @@ -1542,7 +1542,7 @@ run_BCO: |
| 1542 | 1542 | arg1_brk_array = BCO_GET_LARGE_ARG;
|
| 1543 | 1543 | arg2_info_mod_name = BCO_GET_LARGE_ARG;
|
| 1544 | 1544 | arg3_info_mod_id = BCO_GET_LARGE_ARG;
|
| 1545 | - arg4_info_index = BCO_NEXT;
|
|
| 1545 | + arg4_info_index = BCO_READ_NEXT_32;
|
|
| 1546 | 1546 | #if defined(PROFILING)
|
| 1547 | 1547 | arg5_cc = BCO_GET_LARGE_ARG;
|
| 1548 | 1548 | #else
|
| 1 | -T21752A.hs:4:5: warning: [GHC-68441] [-Wdeprecations (in -Wextended-warnings)]
|
|
| 2 | - In the use of ‘newBCO#’ (imported from GHC.Exts):
|
|
| 3 | - Deprecated: "The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14
|
|
| 4 | - These symbols should be imported from ghc-internal instead if needed."
|
|
| 5 | - |
|
| 6 | -T21752A.hs:4:5: warning: [GHC-68441] [-Wdeprecations (in -Wextended-warnings)]
|
|
| 7 | - In the use of ‘newBCO#’ (imported from GHC.Exts):
|
|
| 8 | - Deprecated: "The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14
|
|
| 9 | - These symbols should be imported from ghc-internal instead if needed."
|
|
| 10 | - |
|
| 11 | -T21752A.hs:4:5: warning: [GHC-68441] [-Wdeprecations (in -Wextended-warnings)]
|
|
| 12 | - In the use of ‘mkApUpd0#’ (imported from GHC.Exts):
|
|
| 13 | - Deprecated: "The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14
|
|
| 14 | - These symbols should be imported from ghc-internal instead if needed."
|
|
| 15 | - |
|
| 16 | -T21752A.hs:4:5: warning: [GHC-68441] [-Wdeprecations (in -Wextended-warnings)]
|
|
| 17 | - In the use of ‘mkApUpd0#’ (imported from GHC.Exts):
|
|
| 18 | - Deprecated: "The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14
|
|
| 19 | - These symbols should be imported from ghc-internal instead if needed."
|
|
| 20 | - |
|
| 21 | -T21752A.hs:4:5: warning: [GHC-68441] [-Wdeprecations (in -Wextended-warnings)]
|
|
| 22 | - In the use of type constructor or class ‘BCO’
|
|
| 23 | - (imported from GHC.Exts):
|
|
| 24 | - Deprecated: "The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14
|
|
| 25 | - These symbols should be imported from ghc-internal instead if needed."
|
|
| 26 | - |
|
| 27 | -T21752A.hs:4:5: warning: [GHC-68441] [-Wdeprecations (in -Wextended-warnings)]
|
|
| 28 | - In the use of type constructor or class ‘BCO’
|
|
| 29 | - (imported from GHC.Exts):
|
|
| 30 | - Deprecated: "The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14
|
|
| 31 | - These symbols should be imported from ghc-internal instead if needed."
|
|
| 32 | - |
| ... | ... | @@ -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) |
| ... | ... | @@ -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();
|