packages feed

g2-0.2.0.0: src/G2/Execution/Memory.hs

{-# LANGUAGE RankNTypes #-}

module G2.Execution.Memory 
  ( MemConfig (..)
  , emptyMemConfig
  , addSearchNames
  , markAndSweep
  , markAndSweepIgnoringKnownValues
  , markAndSweepPreserving
  ) where

import G2.Language.Syntax
import G2.Language.Support
import G2.Language.Naming
import qualified G2.Language.ExprEnv as E
import G2.Language.Typing

import Data.Foldable
import Data.List
import qualified Data.HashSet as HS
import qualified Data.HashMap.Lazy as HM
import qualified Data.Map as M

import qualified Data.Sequence as S
import Data.Semigroup

type PreservingFunc = forall t . State t -> Bindings -> HS.HashSet Name -> HS.HashSet Name

data MemConfig = MemConfig { search_names :: [Name]
                           , pres_func :: PreservingFunc }
               | PreserveAllMC

instance Semigroup MemConfig where
    (MemConfig { search_names = sn1, pres_func = pf1 }) <> (MemConfig { search_names = sn2, pres_func = pf2 }) =
                MemConfig { search_names = sn1 ++ sn2
                          , pres_func = \s b hs -> pf1 s b hs `HS.union` pf2 s b hs}
    _ <> _ = PreserveAllMC

instance Monoid MemConfig where
    mempty = MemConfig { search_names = [], pres_func = \ _ _ -> id }

    mappend = (<>)

emptyMemConfig :: MemConfig
emptyMemConfig = MemConfig { search_names = [], pres_func = \_ _ a -> a }

markAndSweep :: State t -> Bindings -> (State t, Bindings)
markAndSweep s = markAndSweepPreserving emptyMemConfig s

addSearchNames :: [Name] -> MemConfig -> MemConfig
addSearchNames ns mc@(MemConfig { search_names = ns' }) = mc { search_names = ns ++ ns' }
addSearchNames _ PreserveAllMC = PreserveAllMC

markAndSweepIgnoringKnownValues :: State t -> Bindings -> (State t, Bindings)
markAndSweepIgnoringKnownValues = markAndSweepPreserving' emptyMemConfig

markAndSweepPreserving :: MemConfig -> State t -> Bindings -> (State t, Bindings)
markAndSweepPreserving mc s =
    markAndSweepPreserving' (toList (names (known_values s)) `addSearchNames` mc) s

markAndSweepPreserving' :: MemConfig -> State t -> Bindings -> (State t, Bindings)
markAndSweepPreserving' PreserveAllMC s b = (s, b)
markAndSweepPreserving' mc (state@State { expr_env = eenv
                                        , type_env = tenv
                                        , curr_expr = cexpr
                                        , path_conds = pc
                                        , exec_stack = es
                                        }) (bindings@Bindings { deepseq_walkers = dsw
                                                              , higher_order_inst = inst }) = -- error $ show $ length $ take 20 $ PC.toList path_conds
                               (state', bindings')
  where
    state' = state { expr_env = eenv'
                   , type_env = tenv'
                   }
    bindings' = bindings { deepseq_walkers = dsw'}

    active = activeNames tenv (E.redirsToExprs eenv) HS.empty $ names cexpr <>
                                                                names es <>
                                                                names pc <>
                                                                names (E.symbolicIds eenv) <>
                                                                S.fromList higher_ord_rel <>
                                                                S.fromList (search_names mc)

    active' = HS.union (pres_func mc state bindings active) active

    isActive :: Name -> Bool
    isActive = (flip HS.member) active'

    eenv' = E.filterWithKey (\n _ -> isActive n) eenv
    tenv' = HM.filterWithKey (\n _ -> isActive n) tenv

    dsw' = M.filterWithKey (\n _ -> isActive n) dsw

    higher_ord_eenv = E.filterWithKey (\n _ -> n `HS.member` inst) eenv
    higher_ord = nubBy (.::.) $ argTypesTEnv tenv ++ E.higherOrderExprs higher_ord_eenv
    higher_ord_rel = E.keys $ E.filter (\e -> any (e .::) higher_ord) higher_ord_eenv

activeNames :: TypeEnv -> ExprEnv -> HS.HashSet Name -> S.Seq Name -> HS.HashSet Name
activeNames tenv eenv explored nss
    | n S.:< ns <- S.viewl nss =
        let
            explored' = HS.insert n explored
            tenv_hits = case HM.lookup n tenv of
                Nothing -> S.empty
                Just r -> names r
            eenv_hits = case E.lookup n eenv of
                Nothing -> S.empty
                Just r -> names r
            ns' = tenv_hits <> eenv_hits <> ns
        in
        if HS.member n explored
          then activeNames tenv eenv explored ns
          else activeNames tenv eenv explored' ns'
    | otherwise = explored