packages feed

ghc-lib-parser-0.20201101: compiler/GHC/Runtime/Linker/Types.hs

-----------------------------------------------------------------------------
--
-- 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)