1 {-# LANGUAGE MagicHash, BangPatterns #-}
7 import System.Environment
13 args <- map length `fmap` getArgs
15 (l ++ l2 ++ args) `deepseq` return ()
17 let x = l ++ l2 ++ args
19 putStrLn "ghc-heap-view-demo"
21 putStrLn "Here are a four different lists, where the first three are already evaluated."
22 putStrLn "The first one, l, was defined as a top level constant as "
23 putStrLn "> l = [1,2,3]"
24 putStrLn $ "and is now found at " ++ show (asBox l) ++ " (where the /2 is the pointer tag information) and fully evaluated:"
25 getClosureData l >>= printInd
26 putStrLn $ "The second one, l2, is locally defined"
27 putStrLn "> let l2 = 4:l"
28 putStrLn $ "and now found at " ++ show (asBox l2) ++ ". See how the cons-cell references l!"
29 getClosureData l2 >>= printInd
30 putStrLn "And the binding"
31 putStrLn "> args <- map length `fmap` getArgs"
32 putStrLn $ "gives us at " ++ show (asBox args) ++ " a static, but at compile time unknown list:"
33 getClosureData args >>= printInd
34 getClosureData [] >>= printInd
35 putStrLn $ "And now we have, at " ++ show (asBox x) ++ ", the concatenation of them, but unevaluated:"
36 putStrLn "> let x = l ++ l2 ++ args"
37 putStrLn "The thunk keeps a reference to l2 and args, but not l, as that is at a static address, unless you are running this in GHCi:"
38 getClosureData x >>= printInd
41 putStrLn "Now to some more closure types. m and m' locally bound of type the unboxed type Int#, with values 42 resp. 23."
42 putStrLn "> let f = \\x n -> take (I# m + I# x) n ++ args"
43 putStrLn " t = f m' l2"
44 let !(I# m) = length args + 42
45 let !(I# m') = length args + 23
46 let f = \x n -> take (I# m + I# x) n ++ args
48 putStrLn $ "So here is (" ++ show (asBox f) ++ "), referencing its free variables args and 42:"
49 getClosureData f >>= printInd
50 putStrLn "And t is a thunk that applies f (also referenced here) to an unboxed value (23) and l2:"
51 getClosureData t >>= printInd
54 putStrLn "Lastly, here is the standard example for self reference:"
55 putStrLn "> let x = id (:) () x"
57 putStrLn $ "This is what x (" ++ show (asBox x) ++ ") looks like, at least without -O:"
58 getClosureData x >>= printInd
60 putStrLn $ "So it is unevaluated. Let us evaluate it using seq. Now we have, still at " ++ show (asBox x) ++ ":"
61 getClosureData x >>= printInd
62 IndClosure {indirectee = target} <- getClosureData x
63 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:"
64 getBoxedClosureData target >>= printInd
66 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:"
67 getClosureData x >>= printInd
69 printInd :: Show a => a -> IO ()
70 printInd x = putStrLn $ " " ++ show x
72 recurse :: Int -> Box -> IO ()
74 where go i b = if i >= m then return () else do
75 putStrLn $ ind ++ show b
76 c <- getBoxedClosureData b
77 putStrLn $ ind ++ show c
78 mapM_ (go (succ i)) (allPtrs c)
80 ind = concat $ replicate i " "