----------------------------------------------------------------------------- -- -- Types for the Dynamic Linker -- -- (c) The University of Glasgow 2019 -- ----------------------------------------------------------------------------- module GHC.Runtime.Linker.Types ( DynLinker(..) , PersistentLinkerState(..) , Linkable(..) , Unlinked(..) , SptEntry(..) , isObjectLinkable , linkableObjs , isObject , nameOfObject , isInterpretable , byteCodeOfObject ) where import GHC.Prelude import Data.Time ( UTCTime ) import Control.Concurrent.MVar ( MVar ) import GHC.Unit ( UnitId, Module ) import GHC.ByteCode.Types ( ItblEnv, CompiledByteCode ) import GHC.Fingerprint.Type ( Fingerprint ) import GHCi.RemoteTypes ( ForeignHValue ) import GHC.Types.Var ( Id ) import GHC.Types.Name.Env ( NameEnv ) import GHC.Types.Name ( Name ) import GHC.Utils.Outputable import GHC.Utils.Panic type ClosureEnv = NameEnv (Name, ForeignHValue) newtype DynLinker = DynLinker { dl_mpls :: MVar (Maybe PersistentLinkerState) } data PersistentLinkerState = PersistentLinkerState { -- Current global mapping from Names to their true values closure_env :: ClosureEnv, -- The current global mapping from RdrNames of DataCons to -- info table addresses. -- When a new Unlinked is linked into the running image, or an existing -- module in the image is replaced, the itbl_env must be updated -- appropriately. itbl_env :: !ItblEnv, -- The currently loaded interpreted modules (home package) bcos_loaded :: ![Linkable], -- And the currently-loaded compiled modules (home package) objs_loaded :: ![Linkable], -- The currently-loaded packages; always object code -- Held, as usual, in dependency order; though I am not sure if -- that is really important pkgs_loaded :: ![UnitId], -- we need to remember the name of previous temporary DLL/.so -- libraries so we can link them (see #10322) temp_sos :: ![(FilePath, String)] } -- | Information we can use to dynamically link modules into the compiler data Linkable = LM { linkableTime :: UTCTime, -- ^ Time at which this linkable was built -- (i.e. when the bytecodes were produced, -- or the mod date on the files) linkableModule :: Module, -- ^ The linkable module itself linkableUnlinked :: [Unlinked] -- ^ Those files and chunks of code we have yet to link. -- -- INVARIANT: A valid linkable always has at least one 'Unlinked' item. -- If this list is empty, the Linkable represents a fake linkable, which -- is generated with no backend is used to avoid recompiling modules. -- -- ToDo: Do items get removed from this list when they get linked? } instance Outputable Linkable where ppr (LM when_made mod unlinkeds) = (text "LinkableM" <+> parens (text (show when_made)) <+> ppr mod) $$ nest 3 (ppr unlinkeds) -- | Objects which have yet to be linked by the compiler data Unlinked = DotO FilePath -- ^ An object file (.o) | DotA FilePath -- ^ Static archive file (.a) | DotDLL FilePath -- ^ Dynamically linked library file (.so, .dll, .dylib) | BCOs CompiledByteCode [SptEntry] -- ^ A byte-code object, lives only in memory. Also -- carries some static pointer table entries which -- should be loaded along with the BCOs. -- See Note [Grant plan for static forms] in -- "GHC.Iface.Tidy.StaticPtrTable". instance Outputable Unlinked where ppr (DotO path) = text "DotO" <+> text path ppr (DotA path) = text "DotA" <+> text path ppr (DotDLL path) = text "DotDLL" <+> text path ppr (BCOs bcos spt) = text "BCOs" <+> ppr bcos <+> ppr spt -- | An entry to be inserted into a module's static pointer table. -- See Note [Grand plan for static forms] in "GHC.Iface.Tidy.StaticPtrTable". data SptEntry = SptEntry Id Fingerprint instance Outputable SptEntry where ppr (SptEntry id fpr) = ppr id <> colon <+> ppr fpr isObjectLinkable :: Linkable -> Bool isObjectLinkable l = not (null unlinked) && all isObject unlinked where unlinked = linkableUnlinked l -- A linkable with no Unlinked's is treated as a BCO. We can -- generate a linkable with no Unlinked's as a result of -- compiling a module in NoBackend mode, and this choice -- happens to work well with checkStability in module GHC. linkableObjs :: Linkable -> [FilePath] linkableObjs l = [ f | DotO f <- linkableUnlinked l ] ------------------------------------------- -- | Is this an actual file on disk we can link in somehow? isObject :: Unlinked -> Bool isObject (DotO _) = True isObject (DotA _) = True isObject (DotDLL _) = True isObject _ = False -- | Is this a bytecode linkable with no file on disk? isInterpretable :: Unlinked -> Bool isInterpretable = not . isObject -- | Retrieve the filename of the linkable if possible. Panic if it is a byte-code object nameOfObject :: Unlinked -> FilePath nameOfObject (DotO fn) = fn nameOfObject (DotA fn) = fn nameOfObject (DotDLL fn) = fn nameOfObject other = pprPanic "nameOfObject" (ppr other) -- | Retrieve the compiled byte-code if possible. Panic if it is a file-based linkable byteCodeOfObject :: Unlinked -> CompiledByteCode byteCodeOfObject (BCOs bc _) = bc byteCodeOfObject other = pprPanic "byteCodeOfObject" (ppr other)