Documentation and renaming
authorJoachim Breitner <mail@joachim-breitner.de>
Mon, 12 Mar 2012 16:42:54 +0000 (16:42 +0000)
committerJoachim Breitner <mail@joachim-breitner.de>
Mon, 12 Mar 2012 16:42:54 +0000 (16:42 +0000)
Demo.hs
ghc-heap-view.cabal
src/GHC/HeapView.hs

diff --git a/Demo.hs b/Demo.hs
index 49d448b..041eecd 100644 (file)
--- a/Demo.hs
+++ b/Demo.hs
@@ -49,7 +49,7 @@ main = do
     getClosureData x >>= print
     IndClosure {indirectee = target} <- getClosureData x
     putStrLn $ "The thunk was replaced by an indirection. If we look at the target, " ++ show target ++ ", we see that it is a newly created cons-cell referencing the original location of x:"
-    getHValueClosureData target >>= print
+    getBoxedClosureData target >>= print
     performGC
     putStrLn $ "After running the garbage collector (performGC), we find that the address of x is now " ++ show (asBox x) ++ " and that the self-reference is without indirections:"
     getClosureData x >>= print
@@ -59,7 +59,7 @@ recurse :: Int -> Box -> IO ()
 recurse m = go 0
   where go i b = if i >= m then return () else do
             putStrLn $ ind ++ show b
-            c <- getHValueClosureData b
+            c <- getBoxedClosureData b
             putStrLn $ ind ++ show c
             mapM_ (go (succ i)) (allPtrs c)
           where
index a2ad00b..d468801 100644 (file)
@@ -3,7 +3,7 @@ Version:             0.1
 Synopsis:            Extract the heap representation of Haskell values and thunks
 Description:
   This library provides functions to introspect the Haskell heap, for example
-  to investigate sharing and lazy eavaluation.
+  to investigate sharing and lazy evaluation.
   .
   It has been inspired by (and taken code from) the vacuum package and the GHCi
   debugger, but also allows to investiage thunks and other closures. 
@@ -11,6 +11,7 @@ License:             BSD3
 License-file:        LICENSE
 Author:              Joachim Breitner
 Maintainer:          Joachim Breitner <mail@joachim-breitner.de>
+Copyright:           2012 Joachim Breitner
 Category:            Debug, GHC
 Build-type:          Simple
 Cabal-version:       >=1.2
index 735425a..f788ef6 100644 (file)
@@ -10,7 +10,22 @@ values, i.e. to investigate sharing and lazy evaluation.
 
 {-# LANGUAGE MagicHash, UnboxedTuples, CPP, ForeignFunctionInterface, GHCForeignImportPrim, UnliftedFFITypes, BangPatterns, RecordWildCards #-}
 
-module GHC.HeapView where
+module GHC.HeapView (
+    -- * Heap data types
+    Closure(..),
+    allPtrs,
+    ClosureType(..),
+    StgInfoTable(..),
+    HalfWord,
+    -- * Reading from the heap
+    getClosureData,
+    getBoxedClosureData,
+    getClosureRaw,
+    -- * Boxes
+    Box(..),
+    asBox,
+    )
+    where
 
 import System.IO.Unsafe
 import GHC.Exts
@@ -33,16 +48,17 @@ import Data.Bits
 import Data.Char
 import Control.Monad
 
-newtype HValue = HValue Any
-
--- A Safegard of HValues
-data Box = Box HValue
+-- | An arbitrarily Haskell value in a safe Box. The point is that even
+-- unevaluated thunks can safely be moved around inside the Box, and when
+-- required, e.g. in 'getBoxedClosureData', the function knows how far it has
+-- to evalue the argument.
+data Box = Box Any
 
 type HalfWord = Word32
 
 instance Show Box where
 -- From libraries/base/GHC/Ptr.lhs
-   showsPrec _ (Box (HValue any)) rs =
+   showsPrec _ (Box any) rs =
     -- unsafePerformIO (print "↓" >> pClosure any) `seq`    
     pad_out (showHex addr "") ++ (if tag>0 then "/" ++ show tag else "") ++ rs
      where
@@ -53,17 +69,31 @@ instance Show Box where
        pad_out ls = 
           '0':'x':(replicate (2*wORD_SIZE - length ls) '0') ++ ls
 
+{-|
+  This takes an arbitrary value and puts it into a box. Note that calls like
+
+  > asBox (head list) 
+
+  will put the thunk \"head list\" into the box, /not/ the element at the head
+  of the list. For that, use careful case expressions:
+
+  > case list of x:_ -> asBox x
+-}
 asBox :: a -> Box
 asBox x = Box (unsafeCoerce# x)
 
 {-
- StgInfoTable parsing derived from ByteCodeItbls.lhs
- Removed the code parameter for now
- Replaced Type by an enumeration
- Remove stuff dependent on GHCI_TABLES_NEXT_TO_CODE
  StgInfoTable parsing derived from ByteCodeItbls.lhs
  Removed the code parameter for now
  Replaced Type by an enumeration
  Remove stuff dependent on GHCI_TABLES_NEXT_TO_CODE
  -}
 
-
+{-| This is a somewhat faithful representation of an info table. See
+   <http://hackage.haskell.org/trac/ghc/browser/includes/rts/storage/InfoTables.h>
+   for more details on this data structure. Note that the 'Storable' instance
+   provided here does _not_ support writing.
+ -}
 data StgInfoTable = StgInfoTable {
    ptrs   :: HalfWord,
    nptrs  :: HalfWord,
@@ -127,7 +157,7 @@ store x = do addr <- advance
              lift (poke addr x)
 
 {-
- Embedded StateT, also from ByteCodeItbls
  Embedded StateT, also from ByteCodeItbls
  -}
 
 newtype State s m a = State (s -> m (s, a))
@@ -143,10 +173,14 @@ runState :: (Monad m) => s -> State s m a -> m a
 runState s (State m) = m s >>= return . snd
 
 {-
- Data Type representing Closures
  Data Type representing Closures
  -}
 
 
+{-| A closure type enumeration, in order matching the actual value on the heap.
+   Needs to be synchronized with
+   <http://hackage.haskell.org/trac/ghc/browser/includes/rts/storage/ClosureTypes.h>
+ -}
 data ClosureType =
          INVALID_OBJECT
        | CONSTR
@@ -211,6 +245,10 @@ data ClosureType =
        | WHITEHOLE
  deriving (Show, Eq, Enum, Ord)
 
+{-| This is the main data type of this module, representing a Haskell value on
+  the heap. This reflects
+  <http://hackage.haskell.org/trac/ghc/browser/includes/rts/storage/Closures.h>
+ -}
 data Closure =
     ConsClosure {
         info         :: StgInfoTable 
@@ -285,6 +323,8 @@ data Closure =
     }
  deriving (Show)
 
+-- | For generic code, this function returns all referenced closures. 
+allPtrs :: Closure -> [Box]
 allPtrs (ConsClosure {..}) = ptrArgs
 allPtrs (ThunkClosure {..}) = ptrArgs
 allPtrs (SelectorClosure {..}) = [selectee]
@@ -323,6 +363,11 @@ slurpClosure# a = slurpClosure'# (aToWord# a)
 --pClosure x = do
 --    getClosure x >>= print
 
+-- | This returns the raw representation of the given argument. The second
+-- component of the triple are the words on the heap, and the third component
+-- are those words that are actually pointers. Once back in Haskell word, the
+-- 'Word'  may be outdated after a garbage collector run, but the corresponding
+-- 'Box' will still point to the correct value.
 getClosureRaw :: a -> IO (Ptr StgInfoTable, [Word], [Box])
 getClosureRaw x =
     case slurpClosure# (unsafeCoerce# x) of
@@ -339,13 +384,6 @@ amap' f (Array i0 i _ arr#) = map g [0 .. i - i0]
     where g (I# i#) = case indexArray# arr# i# of
                           (# e #) -> f e
 
-
-
--- #include "../includes/rts/storage/ClosureTypes.h"
-
-getHValueClosureData :: Box -> IO Closure
-getHValueClosureData b@(Box a) = getClosureData a
-
 -- derived from vacuum-1.0.0.2/src/GHC/Vacuum/Internal.hs, which got it from
 -- compiler/ghci/DebuggerUtils.hs
 dataConInfoPtrToNames :: Ptr StgInfoTable -> IO String
@@ -386,6 +424,10 @@ dataConInfoPtrToNames ptr = do
     stdInfoTableSizeB = stdInfoTableSizeW * wORD_SIZE
     
 
+-- | This function returns parsed heap representation of the argument _at this
+-- moment_, even if it is unevaluated or an indirection or other exotic stuff.
+-- Beware when passing something to this function, the same caveats as for
+-- 'asBox' apply.
 getClosureData :: a -> IO Closure
 getClosureData x = do
     (iptr, words, ptrs) <- getClosureRaw x
@@ -441,3 +483,8 @@ getClosureData x = do
 
         --  return $ OtherClosure itbl ptrs words
         x -> error $ "getClosureData: Cannot handle closure type " ++ show x
+
+-- | Like 'getClosureData', but taking a 'Box', so it is easier to work with.
+getBoxedClosureData :: Box -> IO Closure
+getBoxedClosureData b@(Box a) = getClosureData a
+