ghc-9.14.1: GHC/Runtime/Interpreter/Types/SymbolCache.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE RecordWildCards #-}
-- | The SymbolCache is used to cache lookups for specific symbols when using
-- the interpreter.
module GHC.Runtime.Interpreter.Types.SymbolCache (
InterpSymbolCache(..)
, mkInterpSymbolCache
, lookupInterpSymbolCache
, updateInterpSymbolCache
, purgeInterpSymbolCache
, InterpSymbol(..)
, SuffixOrInterpreted(..)
, interpSymbolName
, interpSymbolSuffix
, eliminateInterpSymbol
, interpretedInterpSymbol
) where
import GHC.Prelude
import GHC.Types.Unique.FM
import GHC.Types.Name
import GHC.Data.FastString
import Foreign
import Control.Concurrent
import GHC.Utils.Outputable
import GHC.TypeLits
-- The symbols records the suffix which each cache deals with.
newtype SymbolCache (s :: Symbol) = SymbolCache { _getSymbolCache :: UniqFM Name (Ptr ()) }
-- Each cache is keyed by Name, there is one cache for each type of symbol we will
-- potentially lookup. The caches are keyed by 'Name' so that it is not necessary to consult
-- a complicated `FastString` each time.
data InterpSymbolCache = InterpSymbolCache {
interpClosureCache :: MVar (SymbolCache "closure")
, interpConInfoCache :: MVar (SymbolCache "con_info")
, interpStaticInfoCache :: MVar (SymbolCache "static_info")
, interpBytesCache :: MVar (SymbolCache "bytes")
, interpFaststringCache :: MVar (UniqFM FastString (Ptr ()))
}
data SuffixOrInterpreted = Suffix Symbol | Interpreted
data InterpSymbol (s :: SuffixOrInterpreted) where
IClosureSymbol :: Name -> InterpSymbol (Suffix "closure")
IConInfoSymbol :: Name -> InterpSymbol (Suffix "con_info")
IStaticInfoSymbol :: Name -> InterpSymbol (Suffix "static_info")
IBytesSymbol :: Name -> InterpSymbol (Suffix "bytes")
IFaststringSymbol :: FastString -> InterpSymbol Interpreted
instance Outputable (InterpSymbol s) where
ppr s = eliminateInterpSymbol s
(\(IFaststringSymbol s) -> text "interpreted:" <> ppr s)
(\s -> text (interpSymbolSuffix s) <> colon <> ppr (interpSymbolName s))
eliminateInterpSymbol :: InterpSymbol s -> (InterpSymbol Interpreted -> r)
-> (forall x . InterpSymbol (Suffix x) -> r)
-> r
eliminateInterpSymbol s k1 k2 =
case s of
IFaststringSymbol {} -> k1 s
IBytesSymbol {} -> k2 s
IStaticInfoSymbol {} -> k2 s
IConInfoSymbol {} -> k2 s
IClosureSymbol {} -> k2 s
interpSymbolName :: InterpSymbol (Suffix s) -> Name
interpSymbolName (IClosureSymbol n) = n
interpSymbolName (IConInfoSymbol n) = n
interpSymbolName (IStaticInfoSymbol n) = n
interpSymbolName (IBytesSymbol n) = n
interpretedInterpSymbol :: InterpSymbol Interpreted -> FastString
interpretedInterpSymbol (IFaststringSymbol s) = s
interpSymbolSuffix :: InterpSymbol (Suffix s) -> String
interpSymbolSuffix (IClosureSymbol {}) = "closure"
interpSymbolSuffix (IConInfoSymbol {}) = "con_info"
interpSymbolSuffix (IStaticInfoSymbol {}) = "static_info"
interpSymbolSuffix (IBytesSymbol {}) = "bytes"
emptySymbolCache :: SymbolCache s
emptySymbolCache = SymbolCache emptyUFM
lookupSymbolCache :: InterpSymbol (Suffix s) -> SymbolCache s -> Maybe (Ptr ())
lookupSymbolCache s (SymbolCache cache) = lookupUFM cache (interpSymbolName s)
insertSymbolCache :: InterpSymbol (Suffix s) -> Ptr () -> SymbolCache s -> SymbolCache s
insertSymbolCache s v (SymbolCache cache) = SymbolCache (addToUFM cache (interpSymbolName s) v)
lookupInterpSymbolCache :: InterpSymbol s -> InterpSymbolCache -> IO (Maybe (Ptr ()))
lookupInterpSymbolCache = withInterpSymbolCache
(\(IFaststringSymbol f) mvar_var -> (\cache -> lookupUFM cache f) <$> readMVar mvar_var)
(\s mvar_var -> lookupSymbolCache s <$> readMVar mvar_var)
updateInterpSymbolCache :: InterpSymbol s
-> InterpSymbolCache -> Ptr () -> IO ()
updateInterpSymbolCache = withInterpSymbolCache
(\(IFaststringSymbol f) mvar_var v -> modifyMVar_ mvar_var (\cache -> pure $ addToUFM cache f v))
(\s mvar_var v -> modifyMVar_ mvar_var (\cache -> pure $ insertSymbolCache s v cache))
withInterpSymbolCache ::
(InterpSymbol Interpreted -> MVar (UniqFM FastString (Ptr ())) -> r)
-> (forall x . InterpSymbol (Suffix x) -> MVar (SymbolCache x) -> r)
-> InterpSymbol s
-> InterpSymbolCache
-> r
withInterpSymbolCache k1 k2 key InterpSymbolCache{..} =
case key of
IClosureSymbol {} -> k2 key interpClosureCache
IConInfoSymbol {} -> k2 key interpConInfoCache
IStaticInfoSymbol {} -> k2 key interpStaticInfoCache
IBytesSymbol {} -> k2 key interpBytesCache
IFaststringSymbol {} -> k1 key interpFaststringCache
-- | Clear all symbol caches.
purgeInterpSymbolCache :: InterpSymbolCache -> IO ()
purgeInterpSymbolCache (InterpSymbolCache a b c d e) = do
modifyMVar_ a (\_ -> do
modifyMVar_ b (\_ -> do
modifyMVar_ c (\_ -> do
modifyMVar_ d (\_ -> do
modifyMVar_ e (\_ -> pure emptyUFM)
pure emptySymbolCache)
pure emptySymbolCache)
pure emptySymbolCache)
pure emptySymbolCache)
mkInterpSymbolCache :: IO InterpSymbolCache
mkInterpSymbolCache = do
InterpSymbolCache <$> newMVar emptySymbolCache
<*> newMVar emptySymbolCache
<*> newMVar emptySymbolCache
<*> newMVar emptySymbolCache
<*> newMVar emptyUFM