Advertisement
Guest User

Untitled

a guest
May 22nd, 2015
219
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.32 KB | None | 0 0
  1. module MarkSweep where
  2.  
  3. import Data.Array.IO
  4. import Data.Word
  5. import Data.Bits
  6. import Data.Bits.Lens
  7. import Data.Foldable (traverse_)
  8. import Control.Lens
  9. import Control.Monad
  10.  
  11. ------------------------------------------------------------------------
  12. -- Heaps
  13. ------------------------------------------------------------------------
  14.  
  15. {- Heap layout: contiguous sequence of objects
  16. - Object layout:
  17. - bit 0: mark bit
  18. - bit 1: allocated bit
  19. - bit 31-2: size (maximum allocation is therefore 2^30-1
  20. - -}
  21.  
  22. newtype Heap = Heap (IOUArray Int Word32)
  23.  
  24. readHeap ::
  25. Heap {- ^ heap -} ->
  26. Int {- ^ read address -} ->
  27. IO HeapElem
  28. readHeap (Heap a) i = fmap HeapElem (readArray a i)
  29.  
  30. writeHeap ::
  31. Heap {- ^ heap -} ->
  32. Int {- ^ write address -} ->
  33. HeapElem {- ^ new value -} ->
  34. IO ()
  35. writeHeap (Heap a) i (HeapElem e) = writeArray a i e
  36.  
  37. -- | Determine range of valid indexes in a heap
  38. heapBounds :: Heap -> IO (Int,Int)
  39. heapBounds (Heap a) = getBounds a
  40.  
  41. -- | Construct an empty heap with a single free block
  42. -- of the given size
  43. initialHeap :: Int -> IO Heap
  44. initialHeap sz =
  45. do heap <- fmap Heap (newArray (0,sz-1) 0)
  46. writeHeap heap 0 (mkFreeBlock sz)
  47. return heap
  48.  
  49. -- | Attempt to allocate a new block in the heap of the given size.
  50. allocate ::
  51. Heap {- ^ heap -} ->
  52. Int {- ^ allocation size -} ->
  53. IO Int {- ^ index of allocation -}
  54. allocate heap sz =
  55. do b <- heapBounds heap
  56. next b 0
  57. where
  58. next :: (Int,Int) -> Int -> IO Int
  59. next b i
  60. | inRange b i = attemptAllocation b i =<< readHeap heap i
  61. | otherwise = fail "virtual heap exhausted"
  62.  
  63. attemptAllocation b i e
  64. | e^.allocated || esz < sz = next b (i + e^.elemSize)
  65.  
  66. | otherwise =
  67. do -- mark unused portion of this block as free
  68. when (sz < esz)
  69. (writeHeap heap (i+sz) (mkFreeBlock (esz-sz)))
  70.  
  71. let e' = set allocated True
  72. $ mkFreeBlock sz
  73.  
  74. writeHeap heap i e'
  75.  
  76. return i
  77. where
  78. esz = e^.elemSize
  79.  
  80. -- | Walk through heap from beginning to end
  81. -- combining subsequent free blocks.
  82. coalesceHeap :: Heap -> IO ()
  83. coalesceHeap h =
  84. do (lo,hi) <- heapBounds h
  85.  
  86. let next i =
  87. when (i <= hi) $
  88. do e <- readHeap h i
  89. let i' = i + view elemSize e
  90.  
  91. if view allocated e || i' >= hi then next i'
  92.  
  93. else do e' <- readHeap h i'
  94. if view allocated e'
  95. then next (i' + view elemSize e')
  96.  
  97. else do writeHeap h i (mkFreeBlock (view elemSize e + view elemSize e'))
  98. next i -- retry
  99.  
  100. next lo
  101.  
  102.  
  103. describeHeap :: Heap -> IO ()
  104. describeHeap h =
  105. do (lo,hi) <- heapBounds h
  106.  
  107. let next i =
  108. when (i <= hi) $
  109. do e <- readHeap h i
  110. print (i,view allocated e, view marked e, view elemSize e)
  111. next (i + view elemSize e)
  112.  
  113. next lo
  114.  
  115. ------------------------------------------------------------------------
  116. -- Heap elements
  117. ------------------------------------------------------------------------
  118.  
  119. newtype HeapElem = HeapElem { heapElemRep :: Word32 }
  120.  
  121. _HeapElem :: Iso' HeapElem Word32
  122. _HeapElem = iso heapElemRep HeapElem
  123.  
  124. mkFreeBlock :: Int -> HeapElem
  125. mkFreeBlock sz
  126. | 0 <= sz && sz < 2^30-1 = HeapElem (fromIntegral sz `shiftL` 2)
  127. | otherwise = error "mkFreeBlock: size out of range"
  128.  
  129. marked :: Lens' HeapElem Bool
  130. marked = _HeapElem . bitAt 0
  131.  
  132. allocated :: Lens' HeapElem Bool
  133. allocated = _HeapElem . bitAt 1
  134.  
  135. elemSize :: Lens' HeapElem Int
  136. elemSize = _HeapElem
  137. . lens (\s -> fromIntegral (shiftR s 2))
  138. (\s b -> shiftL (fromIntegral b) 2 .|. (0x3 .&. s))
  139.  
  140. ------------------------------------------------------------------------
  141. -- Object layouts
  142. ------------------------------------------------------------------------
  143.  
  144. data ObjectType = SumType | ProductType
  145.  
  146. data ObjectDescription = ObjectDescription
  147. { objectType :: ObjectType
  148. , objectFields :: [FieldType]
  149. }
  150.  
  151. data FieldType
  152. = IntField
  153. | ObjectField ObjectDescription
  154.  
  155. allocateSum ::
  156. Heap ->
  157. Int {- ^ alternative tag -} ->
  158. Word32 {- ^ value of alternative -} ->
  159. IO Int {- ^ pointer to allocated and initialized block -}
  160. allocateSum h alt v =
  161. do p <- allocate h 3
  162. writeHeap h (p+1) (HeapElem (fromIntegral alt))
  163. writeHeap h (p+2) (HeapElem v)
  164. return p
  165.  
  166. allocateProduct ::
  167. Heap ->
  168. [Word32] {- ^ list of fields in product -} ->
  169. IO Int {- ^ pointer to allocated and initialized block -}
  170. allocateProduct h vs =
  171. do p <- allocate h (1+length vs)
  172. zipWithM_ (\i e -> writeHeap h i (HeapElem e))
  173. [p+1, p+2..]
  174. vs
  175. return p
  176.  
  177. ------------------------------------------------------------------------
  178. -- Sample object descriptions
  179. ------------------------------------------------------------------------
  180.  
  181. intObject :: ObjectDescription
  182. intObject = ObjectDescription
  183. { objectType = ProductType
  184. , objectFields = [IntField]
  185. }
  186.  
  187. mkInt ::
  188. Heap {- ^ allocation heap -} ->
  189. Int {- ^ int value -} ->
  190. IO Int {- ^ returns pointer to boxed int value -}
  191. mkInt h v = allocateProduct h [fromIntegral v]
  192.  
  193. pairObject :: ObjectDescription -> ObjectDescription -> ObjectDescription
  194. pairObject a b = ObjectDescription
  195. { objectType = ProductType
  196. , objectFields = [ObjectField a, ObjectField b]
  197. }
  198.  
  199. mkPair ::
  200. Heap ->
  201. Int {- ^ fst pointer -} ->
  202. Int {- ^ snd pointer -} ->
  203. IO Int
  204. mkPair h x1 x2 = allocateProduct h [fromIntegral x1, fromIntegral x2]
  205.  
  206. unitObject :: ObjectDescription
  207. unitObject = ObjectDescription
  208. { objectType = ProductType
  209. , objectFields = []
  210. }
  211.  
  212. mkUnit :: Heap -> IO Int
  213. mkUnit h = allocateProduct h []
  214.  
  215. maybeObject :: ObjectDescription -> ObjectDescription
  216. maybeObject a = ObjectDescription
  217. { objectType = SumType
  218. , objectFields = [ObjectField unitObject, ObjectField a]
  219. }
  220.  
  221. mkNothing :: Heap -> IO Int
  222. mkNothing h =
  223. do p <- mkUnit h
  224. allocateSum h 0 (fromIntegral p)
  225.  
  226. mkJust :: Heap -> Int -> IO Int
  227. mkJust h v = allocateSum h 1 (fromIntegral v)
  228.  
  229. listObject :: ObjectDescription -> ObjectDescription
  230. listObject a = maybeObject (pairObject a (listObject a))
  231.  
  232. mkNil :: Heap -> IO Int
  233. mkNil = mkNothing
  234.  
  235. mkCons ::
  236. Heap ->
  237. Int {- ^ pointer to head of list -} ->
  238. Int {- ^ pointer to tail of list -} ->
  239. IO Int {- ^ pointer to list -}
  240. mkCons h x xs =
  241. do p <- mkPair h x xs
  242. allocateSum h 1 (fromIntegral p)
  243.  
  244. ------------------------------------------------------------------------
  245. -- Mark and sweep GC
  246. ------------------------------------------------------------------------
  247.  
  248. mark ::
  249. Heap {- ^ heap to mark -} ->
  250. ObjectDescription {- ^ description of the object at the address -} ->
  251. Int {- ^ address to start marking -} ->
  252. IO ()
  253. mark h obj i =
  254. do e <- readHeap h i
  255. writeHeap h i (set marked True e)
  256.  
  257. case objectType obj of
  258. SumType -> markSum h (objectFields obj) (i+1)
  259. ProductType -> markProduct h (objectFields obj) (i+1)
  260.  
  261. markSum ::
  262. Heap {- ^ heap to mark -} ->
  263. [FieldType] {- ^ description of the possible field types -} ->
  264. Int {- ^ address of sum type index -} ->
  265. IO ()
  266. markSum h alts i =
  267. do altNum <- fmap (views _HeapElem fromIntegral) (readHeap h i)
  268. case preview (ix altNum) alts of
  269. Nothing -> fail ("Invalid sum type at " ++ show i)
  270. Just alt -> markField h alt (i+1)
  271.  
  272. markProduct ::
  273. Heap {- ^ heap to mark -} ->
  274. [FieldType] {- ^ description of the sequentially stored fields -} ->
  275. Int {- ^ address of the first field -} ->
  276. IO ()
  277. markProduct h fields i = zipWithM_ (markField h) fields [i,i+1..]
  278.  
  279. markField ::
  280. Heap {- ^ heap to mark -} ->
  281. FieldType {- ^ description of this field -} ->
  282. Int {- ^ address of this field -} ->
  283. IO ()
  284. markField _ IntField _ = return ()
  285. markField h (ObjectField obj) i =
  286. do e <- readHeap h i
  287. let i' = views _HeapElem fromIntegral e
  288. mark h obj i'
  289.  
  290. -- | Walk through heap from beginning to end deallocating any
  291. -- unmarked but allocated region.
  292. sweep :: Heap -> IO ()
  293. sweep h =
  294. do (lo,hi) <- heapBounds h
  295.  
  296. let next i = when (i <= hi) $
  297. do e <- readHeap h i
  298.  
  299. if view allocated e
  300.  
  301. then if view marked e
  302. then do writeHeap h i (set marked False e)
  303. next (i + view elemSize e)
  304.  
  305. else do writeHeap h i (set allocated False e)
  306. next i
  307.  
  308. else next (i + view elemSize e)
  309.  
  310. next lo
  311.  
  312. collectGarbage ::
  313. Heap {- ^ heap to gc -} ->
  314. [(ObjectDescription,Int)] {- ^ live root types and addresses -} ->
  315. IO ()
  316. collectGarbage h roots =
  317. do traverse_ (\(obj,i) -> mark h obj i) roots
  318. sweep h
  319. coalesceHeap h
  320.  
  321. ------------------------------------------------------------------------
  322. -- Test case
  323. ------------------------------------------------------------------------
  324.  
  325.  
  326. demo :: IO ()
  327. demo = do
  328.  
  329. h <- initialHeap 100
  330.  
  331. one <- mkInt h 1
  332. two <- mkInt h 2
  333.  
  334. _three <- mkInt h 3
  335.  
  336. nil <- mkNil h
  337. x3 <- mkCons h one nil
  338. x2 <- mkCons h two x3
  339. x1 <- mkCons h one x2
  340.  
  341. collectGarbage h [(listObject intObject, x1)]
  342. putStrLn "After GC"
  343. describeHeap h
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement