repos / gcs.git


gcs.git / src / MarkSweep
Evgenii Akentev  ·  2024-09-16

Basic.hs

  1{-# language ImportQualifiedPost, InstanceSigs, DuplicateRecordFields
  2 , LambdaCase, RecordWildCards, NamedFieldPuns, TypeSynonymInstances
  3 , DerivingStrategies, GeneralizedNewtypeDeriving #-}
  4
  5module MarkSweep.Basic where
  6
  7
  8import Data.Array
  9import Control.Monad.State
 10import Control.Monad.Identity
 11import Mutator 
 12
 13instance Mutator GcM where
 14  new :: Value -> GcM ObjectPtr
 15  new v = do
 16    allocate v >>= \case
 17      Right ptr -> pure ptr 
 18      _ -> do
 19        collect
 20        allocate v >>= \case
 21          Right ptr -> pure ptr
 22          Left s -> error s
 23
 24  readFromRoots :: Int -> GcM ObjectPtr
 25  readFromRoots i = do
 26    GCState{roots} <- get
 27    return $ roots ! i
 28 
 29  readFromObject :: ObjectPtr -> GcM Value
 30  readFromObject NullPtr = error "Null pointer"
 31  readFromObject (ObjectPtr i) = do
 32   GCState{heap} <- get
 33   case heap ! i of
 34    Just o -> pure $ val o
 35    Nothing -> error "Incorrect pointer"
 36
 37  readFromField :: Int -> ObjectPtr -> GcM ObjectPtr
 38  readFromField _ NullPtr = error "Null pointer"
 39  readFromField f (ObjectPtr i) = do
 40   GCState{heap} <- get
 41   case heap ! i of
 42    Just o -> pure $ (fields o) ! f
 43    Nothing -> error "Incorrect pointer"
 44
 45  writeToRoots :: Int -> ObjectPtr -> GcM ()
 46  writeToRoots i ptr = do
 47    s@GCState{roots} <- get
 48    put $ s { roots = roots // [(i, ptr)] }
 49
 50  writeToObject :: Value -> ObjectPtr -> GcM ()
 51  writeToObject _ NullPtr = error "Null pointer"
 52  writeToObject v (ObjectPtr i) = do
 53   s@GCState{heap} <- get
 54   case heap ! i of
 55    Nothing -> error "Object is null"
 56    Just obj ->
 57     put $ s { heap = heap // [(i, Just $ obj { val = v })] }
 58
 59  writeToField :: Int -> ObjectPtr -> ObjectPtr -> GcM ()
 60  writeToField _ _ NullPtr = error "Null pointer"
 61  writeToField i ptr (ObjectPtr p) = do
 62    s@GCState{heap} <- get
 63    case heap ! p of 
 64      Nothing -> error "Object is null"
 65      Just obj -> do
 66        put $ s { heap = heap // [(p, Just $ obj { fields = fields obj // [(i, ptr)] })]  }
 67
 68data Object = Object {
 69  val :: Value,
 70  fields :: Array Int ObjectPtr,
 71  marked :: Bool
 72} deriving (Eq, Show)
 73
 74data GCState = GCState {
 75  roots :: Array Int ObjectPtr,
 76  heap :: Heap
 77} deriving (Eq,Show)
 78
 79type Heap = Array Int (Maybe Object)
 80
 81initState :: GCState
 82initState = GCState
 83  { roots = array (1, 8) [(i, NullPtr) | i <- [1..8]]
 84  , heap = array (1, 8) [(i, Nothing) | i <- [1 :: Int ..8]]
 85  }
 86
 87newtype GcM a = GcM { unGcM :: StateT GCState Identity a }
 88  deriving (Functor, Applicative, Monad, MonadState GCState)
 89
 90isMarked :: ObjectPtr -> Heap -> Bool
 91isMarked NullPtr _ = False
 92isMarked (ObjectPtr p) h = Just True == (marked <$> (h ! p))
 93
 94setMarked :: ObjectPtr -> Heap -> Heap
 95setMarked NullPtr h = h
 96setMarked (ObjectPtr p) hs = hs // [(p, (\o -> o { marked = True }) <$> (hs ! p)) ]
 97
 98allocate :: Value -> GcM (Either String ObjectPtr) 
 99allocate v = do
100  s@GCState{heap} <- get
101  case findIndexWithNothing heap of
102    Just p -> do
103      put $ s { heap = heap // [(p, Just $ Object v (array (1,8) [(i, NullPtr) | i <- [1..8]]) False)] }
104      pure $ Right $ ObjectPtr p
105    Nothing -> pure $ Left "Out of memory"
106  where
107      findIndexWithNothing h = foldl step Nothing $ assocs h
108      step _ (i, Nothing) = Just i
109      step acc _ = acc
110
111mark :: [ObjectPtr] -> Heap -> Heap
112mark [] h = h
113mark (ptr:rest) h
114  | (ObjectPtr p) <- ptr
115  , Just obj <- h ! p
116  =
117    let
118      step acc NullPtr = acc
119      step (wl, heap) child
120        | not (isMarked child h) = (child : wl, setMarked child heap)
121      step acc _ = acc
122      
123      (workList, newH) = foldl step ([], h) $ fields obj
124    in mark (workList ++ rest) newH
125  | otherwise = mark rest h
126
127markFromRoots :: GcM ()
128markFromRoots = do
129  GCState{..} <- get
130  let newHeap = foldl step heap roots
131  put $ GCState roots newHeap
132  where
133    step heap ptr
134      | ptr /= NullPtr && not (isMarked ptr heap) =
135        let newH = setMarked ptr heap
136        in mark [ptr] newH
137    step heap _ = heap
138
139collect :: GcM ()
140collect = do
141  markFromRoots
142  sweep
143
144sweep :: GcM ()
145sweep = do
146  s@GCState{heap} <- get
147  put $ s { heap = fmap step heap }
148  where
149    step Nothing = Nothing
150    step (Just o) = if marked o then Just (o { marked = False }) else Nothing
151
152main :: IO ()
153main = do
154  let
155    res = flip runState initState $ unGcM $ do
156        ptr <- new (IntVal 3)
157        ptr2 <- new (IntVal 5) 
158
159        writeToRoots 1 ptr 
160
161        collect
162        return [ptr, ptr2]
163  print res