ddc-core-eval-0.4.1.3: DDC/Core/Eval/Store.hs
-- | Definition of the store.
---
-- This implements the store in terms of the operational semantics of the
-- core language, and isn't intended to be efficient in a practical sense.
-- If we cared about runtime performance we'd want to use an IOArray or
-- some other mutable structure to hold the bindings, instead of a Data.Map.
--
module DDC.Core.Eval.Store
( Store (..)
, Loc (..)
, Rgn (..)
, SBind (..)
-- * Operators
, initial
, locUnit, isUnitOrLocX
, newLoc, newLocs
, newRgn, newRgns
, delRgn
, hasRgn
, setGlobal
, addBind
, allocBind, allocBinds
, lookupBind
, lookupTypeOfLoc
, lookupRegionTypeBind)
where
import DDC.Core.Exp
import DDC.Core.Eval.Name
import DDC.Core.Eval.Compounds
import Control.Monad
import DDC.Core.Pretty hiding (empty)
import Data.Map (Map)
import Data.Set (Set)
import qualified Data.Map as Map
import qualified Data.Set as Set
data Store
= Store
{ -- | Next store location to allocate.
storeNextLoc :: Int
-- | Next region handle to allocate.
, storeNextRgn :: Int
-- | Region handles already allocated.
, storeRegions :: Set Rgn
-- | Regions that are marked as global, and are not
-- deallocated with a stack discipline.
, storeGlobal :: Set Rgn
-- | Map of locations to store bindings,
-- their types,
-- and the handle for the regions they're in.
, storeBinds :: Map Loc (Rgn, Type Name, SBind) }
deriving Show
-- | Store binding.
-- These are naked objects that can be allocated directly into the heap.
data SBind
-- | An algebraic data constructor.
= SObj
{ sbindDataTag :: DaCon Name
, sbindDataArgs :: [Loc] }
-- | Lambda abstraction, used for recursive bindings.
-- The flag indicates whether each binder is level-1 (True) or level-0 (False).
| SLams
{ sbindLamBinds :: [(Bool, Bind Name)]
, sbindLamBody :: Exp () Name }
-- | A thunk, used for lazy evaluation.
| SThunk
{ sbindThunkExp :: Exp () Name }
deriving (Eq, Show)
-- Pretty ---------------------------------------------------------------------
instance Pretty Store where
ppr (Store nextLoc nextRgn regions global binds)
= vcat
[ text "* STORE"
, text " NextLoc: " <> text (show nextLoc)
, text " NextRgn: " <> text (show nextRgn)
, text " Regions: " <> braces (sep $ punctuate comma
$ map ppr $ Set.toList regions)
, text " Global: " <> braces (sep $ punctuate comma
$ map ppr $ Set.toList global)
, text ""
, text " Binds:"
, vcat $ [ text " " <> ppr l <> colon <> ppr r <> text " -> " <> ppr sbind
<> line
<> text " :: " <> ppr t
| (l, (r, t, sbind)) <- Map.toList binds] ]
instance Pretty SBind where
ppr (SObj tag [])
= text "OBJ" <+> ppr tag
ppr (SObj tag svs)
= text "OBJ" <+> ppr tag
<+> (sep $ map ppr svs)
ppr (SLams fbs x)
= text "LAMS" <+> sep (map (parens . ppr) fbs)
<> text "."
<> text (renderPlain $ ppr x)
ppr (SThunk x)
= text "THUNK" <+> text (renderPlain $ ppr x)
-- Constructors ---------------------------------------------------------------
-- | Initial store containing the preallocated regions and bindings.
initial :: Store
initial = Store
{ storeNextLoc = 1
, storeNextRgn = 1
, storeRegions
= Set.fromList [Rgn 0]
, storeGlobal
= Set.fromList [Rgn 0]
, storeBinds
= Map.fromList
[ (Loc 0 tUnit, (Rgn 0, tUnit, SObj dcUnit []))]
}
-- | Location of the static unit object.
locUnit :: Loc
locUnit = Loc 0 tUnit
-- | Check whether an expression is the unit constructor,
-- or its static heap location.
isUnitOrLocX :: Show a => Exp a Name -> Bool
isUnitOrLocX xx
= case xx of
XCon _ DaConUnit -> True
XVar _ (UPrim (NameLoc (Loc 0 _)) _) -> True
_ -> False
-- Locations ------------------------------------------------------------------
-- | Create a new location in the store.
newLoc :: Type Name -> Store -> (Store, Loc)
newLoc t store
= let loc = storeNextLoc store
store' = store { storeNextLoc = loc + 1 }
in (store', Loc loc t)
-- | Create several new locations in the store.
newLocs :: [Type Name] -> Store -> (Store, [Loc])
newLocs ts store
= let n = length ts
lFirst = storeNextLoc store
lLast = lFirst + n
locs = [lFirst .. lLast]
store' = store { storeNextLoc = lLast + 1 }
in (store', [Loc l t | l <- locs | t <- ts])
-- Regions -------------------------------------------------------------------
-- | Create a new region in the store.
newRgn :: Store -> (Store, Rgn)
newRgn store
= let rgn = storeNextRgn store
store' = store { storeNextRgn = rgn + 1
, storeRegions = Set.insert (Rgn rgn) (storeRegions store) }
in (store', Rgn rgn)
-- | Create several new regions in the store
newRgns :: Int -> Store -> (Store, [Rgn])
newRgns 0 store = (store, [])
newRgns count store
= let rgns = map Rgn $ [ storeNextRgn store .. storeNextRgn store + count - 1]
store' = store { storeNextRgn = storeNextRgn store + count
, storeRegions = Set.union (Set.fromList rgns) (storeRegions store) }
in (store', rgns)
-- | Delete a region, removing all its bindings.
delRgn :: Rgn -> Store -> Store
delRgn rgn store
= let binds' = [x | x@(_, (r, _, _)) <- Map.toList $ storeBinds store
, r /= rgn ]
in store { storeBinds = Map.fromList binds'
, storeRegions = Set.delete rgn (storeRegions store)
, storeGlobal = Set.delete rgn (storeGlobal store) }
-- | Check whether a store contains the given region.
hasRgn :: Store -> Rgn -> Bool
hasRgn store rgn
= Set.member rgn (storeRegions store)
-- | Set a region as being global.
setGlobal :: Rgn -> Store -> Store
setGlobal rgn store
= store
{ storeGlobal = Set.insert rgn (storeGlobal store) }
-- Bindings -------------------------------------------------------------------
-- | Add a store binding to the store, at the given location.
addBind :: Loc -> Rgn -> Type Name -> SBind -> Store -> Store
addBind loc rgn t sbind store
= store
{ storeBinds = Map.insert loc (rgn, t, sbind) (storeBinds store) }
-- | Allocate a new binding into the given region,
-- returning the new location.
allocBind :: Rgn -> Type Name -> SBind -> Store -> (Store, Loc)
allocBind rgn t sbind store
= let (store1, loc) = newLoc t store
store2 = addBind loc rgn t sbind store1
in (store2, loc)
-- | Alloc some recursive bindings into the given region,
-- returning the new locations.
allocBinds :: [[Loc] -> (Rgn, Type Name, SBind)] -> [Type Name] -> Store -> (Store, [Loc])
allocBinds mkSBinds ts store
= let (store1, locs) = newLocs ts store
rgnBinds = map (\mk -> mk locs) mkSBinds
store2 = foldr (\(l, (r, t, b)) -> addBind l r t b) store1
$ zip locs rgnBinds
in (store2, locs)
-- | Lookup a the binding for a location.
lookupBind :: Loc -> Store -> Maybe SBind
lookupBind loc store
= liftM (\(_, _, sb) -> sb)
$ Map.lookup loc (storeBinds store)
-- | Lookup the type of a store location.
lookupTypeOfLoc :: Loc -> Store -> Maybe (Type Name)
lookupTypeOfLoc loc store
= case Map.lookup loc (storeBinds store) of
Nothing -> Nothing
Just (_, t, _) -> Just t
-- | Lookup the region handle, type and binding for a location.
lookupRegionTypeBind :: Loc -> Store -> Maybe (Rgn, Type Name, SBind)
lookupRegionTypeBind loc store
= Map.lookup loc (storeBinds store)