packages feed

vacuum 0.0.93 → 0.0.94

raw patch · 8 files changed

+803/−633 lines, 8 filesdep −Cabaldep −ghcdep −ghc-pathsPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: Cabal, ghc, ghc-paths

API changes (from Hackage documentation)

- GHC.Vacuum: instance Functor (S s)
- GHC.Vacuum: instance Monad (S s)
- GHC.Vacuum.ClosureType: N_CLOSURE_TYPES :: ClosureType
- GHC.Vacuum.ClosureType: closureType :: a -> IO ClosureType
- GHC.Vacuum.GHC.Internal: CabalModule :: CabalPkgId -> CabalPkgVersion -> CabalModuleId -> CabalModule
- GHC.Vacuum.GHC.Internal: CabalPkg :: CabalPkgId -> CabalPkgVersion -> [CabalModuleId] -> CabalPkg
- GHC.Vacuum.GHC.Internal: GhcApiCfg :: FilePath -> [CabalPkg] -> [DynFlag] -> [DynFlag] -> GhcApiCfg
- GHC.Vacuum.GHC.Internal: cabalModuleModuleId :: CabalModule -> CabalModuleId
- GHC.Vacuum.GHC.Internal: cabalModulePkgId :: CabalModule -> CabalPkgId
- GHC.Vacuum.GHC.Internal: cabalModulePkgVersion :: CabalModule -> CabalPkgVersion
- GHC.Vacuum.GHC.Internal: cabalPkgModules :: CabalPkg -> [CabalModuleId]
- GHC.Vacuum.GHC.Internal: cabalPkgPkg :: CabalPkg -> CabalPkgId
- GHC.Vacuum.GHC.Internal: cabalPkgToModules :: CabalPkg -> [Module]
- GHC.Vacuum.GHC.Internal: cabalPkgVersion :: CabalPkg -> CabalPkgVersion
- GHC.Vacuum.GHC.Internal: collectCabalModules :: [CabalModule] -> [CabalPkg]
- GHC.Vacuum.GHC.Internal: data CabalModule
- GHC.Vacuum.GHC.Internal: data CabalPkg
- GHC.Vacuum.GHC.Internal: data GhcApiCfg
- GHC.Vacuum.GHC.Internal: dataConInfoPtrToNames :: Ptr () -> IO (String, String, String)
- GHC.Vacuum.GHC.Internal: defaultEnv :: IO HscEnv
- GHC.Vacuum.GHC.Internal: defaultGhcApiConfig :: GhcApiCfg
- GHC.Vacuum.GHC.Internal: dynFlagsOff :: [DynFlag] -> (DynFlags -> DynFlags)
- GHC.Vacuum.GHC.Internal: dynFlagsOn :: [DynFlag] -> (DynFlags -> DynFlags)
- GHC.Vacuum.GHC.Internal: ghcApiDynFlagsOff :: GhcApiCfg -> [DynFlag]
- GHC.Vacuum.GHC.Internal: ghcApiDynFlagsOn :: GhcApiCfg -> [DynFlag]
- GHC.Vacuum.GHC.Internal: ghcApiImports :: GhcApiCfg -> [CabalPkg]
- GHC.Vacuum.GHC.Internal: ghcApiLibDir :: GhcApiCfg -> FilePath
- GHC.Vacuum.GHC.Internal: instance Eq CabalModule
- GHC.Vacuum.GHC.Internal: instance Eq CabalPkg
- GHC.Vacuum.GHC.Internal: instance Eq GhcApiCfg
- GHC.Vacuum.GHC.Internal: instance Ord CabalModule
- GHC.Vacuum.GHC.Internal: instance Ord CabalPkg
- GHC.Vacuum.GHC.Internal: instance Ord DynFlag
- GHC.Vacuum.GHC.Internal: instance Ord GhcApiCfg
- GHC.Vacuum.GHC.Internal: instance Read CabalModule
- GHC.Vacuum.GHC.Internal: instance Read CabalPkg
- GHC.Vacuum.GHC.Internal: instance Read DynFlag
- GHC.Vacuum.GHC.Internal: instance Read GhcApiCfg
- GHC.Vacuum.GHC.Internal: instance Show CabalModule
- GHC.Vacuum.GHC.Internal: instance Show CabalPkg
- GHC.Vacuum.GHC.Internal: instance Show GhcApiCfg
- GHC.Vacuum.GHC.Internal: myRunGhc :: HscEnv -> Ghc a -> IO a
- GHC.Vacuum.GHC.Internal: newEnv :: GhcApiCfg -> Maybe DynFlags -> IO HscEnv
- GHC.Vacuum.GHC.Internal: preludeCM :: CabalModule
- GHC.Vacuum.GHC.Internal: type CabalModuleId = String
- GHC.Vacuum.GHC.Internal: type CabalPkgId = String
- GHC.Vacuum.GHC.Internal: type CabalPkgVersion = [Int]
- GHC.Vacuum.GHC.Internal: withGhcApiCfg :: GhcApiCfg -> (FilePath -> DynFlags -> [Module] -> o) -> (DynFlags -> o)
+ GHC.Vacuum: closureType :: a -> IO ClosureType
+ GHC.Vacuum: dumpLazy :: a -> IO (IntMap HNode)
+ GHC.Vacuum: getInfoPtr :: a -> Ptr StgInfoTable
+ GHC.Vacuum: getInfoTab :: a -> IO InfoTab
+ GHC.Vacuum: peekInfoTab :: Ptr StgInfoTable -> IO InfoTab
+ GHC.Vacuum: type HValue = Any
+ GHC.Vacuum: vacuumLazy :: a -> IntMap HNode
+ GHC.Vacuum.ClosureType: SE_BLACKHOLE :: ClosureType
+ GHC.Vacuum.ClosureType: SE_CAF_BLACKHOLE :: ClosureType
+ GHC.Vacuum.Internal: S :: (forall o. (a -> s -> IO o) -> s -> IO o) -> S s a
+ GHC.Vacuum.Internal: StgInfoTable :: HalfWord -> HalfWord -> HalfWord -> HalfWord -> [ItblCode] -> StgInfoTable
+ GHC.Vacuum.Internal: code :: StgInfoTable -> [ItblCode]
+ GHC.Vacuum.Internal: data StgInfoTable
+ GHC.Vacuum.Internal: dataConInfoPtrToNames :: Ptr () -> IO (String, String, String)
+ GHC.Vacuum.Internal: get :: S s s
+ GHC.Vacuum.Internal: gets :: (s -> a) -> S s a
+ GHC.Vacuum.Internal: ghciTablesNextToCode :: Bool
+ GHC.Vacuum.Internal: hALF_WORD_SIZE :: Int
+ GHC.Vacuum.Internal: instance Functor (S s)
+ GHC.Vacuum.Internal: instance Monad (S s)
+ GHC.Vacuum.Internal: instance MonadFix (S s)
+ GHC.Vacuum.Internal: instance Storable StgInfoTable
+ GHC.Vacuum.Internal: io :: IO a -> S s a
+ GHC.Vacuum.Internal: modify :: (s -> s) -> S s ()
+ GHC.Vacuum.Internal: newtype S s a
+ GHC.Vacuum.Internal: nptrs :: StgInfoTable -> HalfWord
+ GHC.Vacuum.Internal: ptrs :: StgInfoTable -> HalfWord
+ GHC.Vacuum.Internal: runS :: S s a -> s -> IO (a, s)
+ GHC.Vacuum.Internal: set :: s -> S s ()
+ GHC.Vacuum.Internal: srtlen :: StgInfoTable -> HalfWord
+ GHC.Vacuum.Internal: tipe :: StgInfoTable -> HalfWord
+ GHC.Vacuum.Internal: type HValue = Any
+ GHC.Vacuum.Internal: type HalfWord = Word16
+ GHC.Vacuum.Internal: type ItblCode = Word8
+ GHC.Vacuum.Internal: unS :: S s a -> forall o. (a -> s -> IO o) -> s -> IO o
+ GHC.Vacuum.Internal: wORD_SIZE :: Int

Files

src/GHC/Vacuum.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE BangPatterns #-}  {- | > ghci> toAdjList $ vacuum (fix (0:))@@ -36,8 +37,8 @@    HNodeId   ,HNode(..)   ,emptyHNode-  ,vacuum,dump-  ,vacuumTo,dumpTo+  ,vacuum,vacuumTo,vacuumLazy+  ,dump,dumpTo,dumpLazy   ,toAdjList   ,nameGraph   ,ShowHNode(..)@@ -48,13 +49,19 @@   ,Closure(..)   ,InfoTab(..)   ,getClosure+  ,closureType+  ,getInfoTab+  ,getInfoPtr+  ,peekInfoTab   ,nodePkg,nodeMod   ,nodeName,itabName+  ,HValue ) where+ import Prelude hiding(catch) import GHC.Vacuum.Dot as Dot import GHC.Vacuum.ClosureType-import GHC.Vacuum.GHC as GHC hiding(Closure)+import GHC.Vacuum.Internal as GHC import Data.Char import Data.Word import Data.List@@ -67,7 +74,9 @@ import System.IO.Unsafe import Control.Monad import Data.Bits+import Text.PrettyPrint(Doc,text) import Language.Haskell.Meta.Utils(pretty)+import Control.Applicative import Control.Exception  import Foreign@@ -84,12 +93,23 @@ vacuumTo :: Int -> a -> IntMap HNode vacuumTo n a = unsafePerformIO (dumpTo n a) +-- | Doesn't really work like you'd want it to.+-- Working on this, but there's a slight chance that getting+-- it to work as one would expect isn't possible given the+-- ever-so small hook that GHC gives us (@unpackClosure#@).+-- (Just so that the possibility of impossibility is stated).+vacuumLazy :: a -> IntMap HNode+vacuumLazy a = unsafePerformIO (dumpLazy a)+ dump :: a -> IO (IntMap HNode) dump a = execH (dumpH a)  dumpTo :: Int -> a -> IO (IntMap HNode) dumpTo n a = execH (dumpToH n a) +dumpLazy :: a -> IO (IntMap HNode)+dumpLazy a = execH (dumpLazyH a)+ -----------------------------------------------------------------------------  toAdjList :: IntMap HNode -> [(Int, [Int])]@@ -241,7 +261,7 @@ getClosure a = grab (getClosure_ a) getClosure  getClosure_ :: a -> IO Closure-getClosure_ a = a `seq`+getClosure_ a =   case unpackClosure# a of       (# iptr         ,ptrs@@ -259,32 +279,66 @@                         then []                         else dumpArray (Array 0 (elems - 1) elems ptrs)               lits = [W# (indexWordArray# nptrs i)-                        | I# i <- [0.. fromIntegral (itabLits itab)] ]-          ptrs <- mapM defined ptrs0-          return (Closure ptrs lits itab)+                        | I# i <- [0.. fromIntegral (itabLits itab-1)] ]+          -- ptrs <- mapM defined ptrs0+          return (Closure ptrs0 lits itab) +closureType :: a -> IO ClosureType+closureType a = itabType <$> getInfoTab a++getInfoTab :: a -> IO InfoTab+getInfoTab a =+  case unpackClosure# a of+    (# iptr+      ,_+      ,_ #) -> do+        let iptr' | ghciTablesNextToCode = Ptr iptr+                  | otherwise = Ptr iptr `plusPtr` negate wORD_SIZE+                      -- the info pointer we get back from unpackClosure#+                      -- is to the beginning of the standard info table,+                      -- but the Storable instance for info tables takes+                      -- into account the extra entry pointer when+                      -- !ghciTablesNextToCode, so we must adjust here.+        peekInfoTab iptr'++ peekInfoTab :: Ptr StgInfoTable -> IO InfoTab peekInfoTab p = do   stg <- peek p   let ct = (toEnum . fromIntegral . GHC.tipe) stg   case ct of-    _ | isCon ct -> do (a,b,c) <- dataConInfoPtrToNames (castPtr p)-                       return $ ConInfo-                        {itabPkg    = a-                        ,itabMod    = b-                        ,itabCon    = c-                        ,itabPtrs   = (fromIntegral . GHC.stgItblPtrs) stg-                        ,itabLits   = (fromIntegral . GHC.nptrs) stg-                        ,itabType   = ct-                        ,itabSrtLen = fromIntegral (GHC.srtlen stg)-                        ,itabCode   = fmap fromIntegral (GHC.code stg)}+    _ | hasName stg -> do (a,b,c) <- dataConInfoPtrToNames (castPtr p)+                          return $ ConInfo+                            {itabPkg    = a+                            ,itabMod    = b+                            ,itabCon    = c+                            ,itabPtrs   = (fromIntegral . GHC.ptrs) stg+                            ,itabLits   = (fromIntegral . GHC.nptrs) stg+                            ,itabType   = ct+                            ,itabSrtLen = fromIntegral (GHC.srtlen stg)+                            ,itabCode   = fmap fromIntegral (GHC.code stg)}     _ -> return $ OtherInfo-          {itabPtrs   = (fromIntegral . GHC.stgItblPtrs) stg+          {itabPtrs   = (fromIntegral . GHC.ptrs) stg           ,itabLits   = (fromIntegral . GHC.nptrs) stg           ,itabType   = ct           ,itabSrtLen = fromIntegral (GHC.srtlen stg)           ,itabCode   = fmap fromIntegral (GHC.code stg)} ++-- Check whether this closure is a datacon and sanity check+-- to make sure we didn't read garbage from memory into this+-- StgInfoTable (because if we did, we'll probably segfault+--  during dataConInfoPtrToNames).+hasName :: StgInfoTable -> Bool+hasName stg = let ct = (toEnum . fromIntegral . GHC.tipe) stg :: ClosureType+                  lits = (fromIntegral . GHC.nptrs) stg       :: Int+                  ptrs = (fromIntegral . GHC.ptrs) stg :: Int+              in  isCon ct+                && lits < 1024  -- It seems the ptrs info the ItblEnv+                && ptrs < 1024  -- gotten from ByteCodeItbls are borked+                                -- in some way, *OR* (and more likely)+                                -- there's some caveat i'm not aware of.+ ------------------------------------------------  type H a = S Env a@@ -317,24 +371,32 @@ dumpH :: a -> H () dumpH a = go =<< rootH a   where go :: HValue -> H ()-        go a = a `seq` do+        go a = do           ids <- nodeH a           case ids of             [] -> return ()             _  -> mapM_ go =<< mapM getHVal ids - dumpToH :: Int -> a -> H () dumpToH n _ | n < 1 = return () dumpToH n a = go (n-1) =<< rootH a   where go :: Int -> HValue -> H ()         go 0 _ = return ()-        go n a = a `seq` do+        go n a = do           ids <- nodeH a           case ids of             [] -> return ()             _  -> mapM_ (go (n-1)) =<< mapM getHVal ids +dumpLazyH :: a -> H ()+dumpLazyH !a = go =<< rootH a+  where go :: HValue -> H ()+        go a = do+          ids <- nodeLazyH a+          case ids of+            [] -> return ()+            _  -> mapM_ go =<< mapM getHVal ids+ -- | Needed since i don't know of a way -- to go @a -> HValue@ directly (unsafeCoercing -- directly doesn't work (i tried)).@@ -342,12 +404,12 @@  -- | Turn the root into an @HValue@ to start off. rootH :: a -> H HValue-rootH a = let b = Box a-          in b `seq` do-            c <- io (getClosureData b)-            case dumpArray (GHC.ptrs c) of-              [hval] -> io (defined hval)-              _ -> error "zomg"+rootH a = do+  let b = Box a+  c <- io (getClosure $! b)+  case closPtrs c of+    [hval] -> io (defined hval)+    _ -> error "zomg"  -- | Add this @HValue@ to the graph, then --  add it's successor's not already seen, and@@ -358,27 +420,36 @@ --  unpointed closures cannot be entered, which HValues --  can. nodeH :: HValue -> H [HNodeId]-nodeH a = a `seq` do+nodeH a = do+  clos <- io (getClosure $! a)+  (i, _) <- getId a+  let itab = closITab clos+      ptrs = closPtrs clos+  ptrs' <- case itabType itab of+              t | isCon t -> return (avoid (itabCon itab) ptrs)+                | otherwise -> return ptrs+  ptrs'' <- io (mapM defined ptrs')+  xs <- mapM getId ptrs''+  let news = (fmap fst . fst . partition snd) xs+      n    = HNode (fmap fst xs)+                    (closLits clos)+                    (closITab clos)+  insertG i n+  return news++nodeLazyH :: HValue -> H [HNodeId]+nodeLazyH a = do   clos <- io (getClosure a)   (i, _) <- getId a   let itab = closITab clos       ptrs = closPtrs clos   ptrs' <- case itabType itab of-              t | isCon t -> -- XXX: hackish casing on conname until unpackClosure# is fixed.-                             -- Try to cover a few common cases.-                            case itabCon itab of-                              "J#"    -> return []            -- avoid the ByteArray#-                              "MVar"  -> return []            -- avoid the MVar#-                              "STRef" -> return []            -- avoid the MutVar#-                              "Array" -> return (take 2 ptrs) -- avoid the Array#-                              "MallocPtr" -> return []            -- ForeignPtr-                              "PlainPtr" -> return []             -- ForeignPtr-                              "STRef"     -> return []            -- avoid the MutVar#-                              "PS"        -> return (drop 1 ptrs)-                              "Chunk"     -> return (drop 1 ptrs)-                              _       -> return ptrs+              t | isCon t -> return (avoid (itabCon itab) ptrs)+                  -- IMPORTANT: Following either (or both) of+                  -- the pointer inside a @THUNK@ results in a segfault.+                | isThunk t -> return []                 | otherwise -> return ptrs-  xs <- mapM getId ptrs'+  xs <- mapM getIdLazy ptrs'   let news = (fmap fst . fst . partition snd) xs       n    = HNode (fmap fst xs)                     (closLits clos)@@ -388,6 +459,61 @@  ------------------------------------------------ +-- XXXXXX: USE A TRIE FOR THIS INSTEAD++-- XXX: hackish casing on conname until unpackClosure# is fixed.+-- Try to cover a few common cases.+avoid :: String -> [HValue] -> [HValue]+avoid con = maybe id id (IM.lookup (hash con) criminals)++criminals :: IntMap ([HValue] -> [HValue])+criminals = IM.fromList . fmap (mapfst hash) $+  [("J#",               const [])+  ,("MVar",             const [])+  ,("STRef",            const [])+  ,("Array",            take   2)+  ,("MallocPtr",        const [])+  ,("PlainPtr",         const [])+  ,("PS",               drop   1)+  ,("Chunk",            drop   1)+  ,("FileHandle",       take   1)+  ,("DuplexHandle",     take   1)+  --,("",                 id)+  ]++hash :: String -> Int+hash [] = 0+hash  s = go 0 (fmap ord s)+  where go !h [] = h+        go !h (n:ns) =+          let a = (h `shiftL` 4)+              b = a + n+              c = b .&. 0xf0000000+              !d = case c==0 of+                    False -> let !e = c `shiftR` 24+                              in b `xor` e+                    True  -> b+              !e = complement c+              !f = d `xor` e+          in go f ns++{-+unsigned long+elfhash(const char *s)+{+  unsigned long h=0, g;+  while (*s){+    h = (h << 4) + *s++;+    if((g = h & 0xf0000000))+      h ^= g >> 24;+    h &= ~g;+  }+  return h;+}+-}++------------------------------------------------+ getHVal :: HNodeId -> H HValue getHVal i = (IM.! i) `fmap` gets hvals @@ -414,6 +540,18 @@                    ,hvals= IM.insert i hval vs})       return (i, True) +getIdLazy :: HValue -> H (HNodeId, Bool)+getIdLazy hval = do+  s <- gets seen+  case lookLazy hval s of+    Just i -> return (i, False)+    Nothing -> do+      i <- newId+      vs <- gets hvals+      modify (\e->e{seen=(hval,i):s+                   ,hvals= IM.insert i hval vs})+      return (i, True)+ ------------------------------------------------  look :: HValue -> [(HValue, a)] -> Maybe a@@ -426,6 +564,15 @@ a .==. b = a `seq` b `seq`   (0 /= I# (reallyUnsafePtrEquality# a b)) +lookLazy :: HValue -> [(HValue, a)] -> Maybe a+lookLazy _      [] = Nothing+lookLazy hval ((x,i):xs)+  | hval =.= x = Just i+  | otherwise   = lookLazy hval xs++(=.=) :: HValue -> HValue -> Bool+a =.= b = (0 /= I# (reallyUnsafePtrEquality# a b))+ dumpArray :: Array Int a -> [a] dumpArray a = let (m,n) = bounds a               in fmap (a!) [m..n]@@ -441,6 +588,7 @@  ------------------------------------------------ +{- newtype S s a = S {unS :: forall o. s -> (s -> a -> IO o) -> IO o} instance Functor (S s) where   fmap f (S g) = S (\s k -> g s (\s a -> k s (f a)))@@ -459,10 +607,11 @@ modify f = S (\s k -> k (f s) ()) runS :: S s a -> s -> IO (a, s) runS (S g) s = g s (\s a -> return (a, s))+-}  ------------------------------------------------ -{- RE: the array entering problem:+{-  rts/StgMiscClosures.cmm 
src/GHC/Vacuum/ClosureType.hs view
@@ -1,25 +1,11 @@  module GHC.Vacuum.ClosureType (-   closureType+   isFun,isThunk,isCon   ,ClosureType(..)-  ,isFun,isThunk,isCon ) where -import GHC.Vacuum.GHC as GHC- ------------------------------------------------ --- | Get the @ClosureType@.-closureType :: a -> IO ClosureType-closureType a = a `seq` do-  c <- GHC.getClosureData a-  let itab  = GHC.infoTable c-      tag   = (fromIntegral . GHC.tipe) itab-      ctype = (toEnum . fromIntegral) tag-  return ctype--------------------------------------------------- isFun :: ClosureType -> Bool isFun FUN = True isFun FUN_1_0 = True@@ -98,6 +84,8 @@   | STOP_FRAME   | CAF_BLACKHOLE   | BLACKHOLE+  | SE_BLACKHOLE+  | SE_CAF_BLACKHOLE   | MVAR_CLEAN   | MVAR_DIRTY   | ARR_WORDS@@ -125,83 +113,81 @@   | CATCH_RETRY_FRAME   | CATCH_STM_FRAME   | WHITEHOLE-  | N_CLOSURE_TYPES-  deriving (Eq,Ord,Read,Show)--------------------------------------------------+  deriving(Eq,Ord,Read,Show)  instance Enum ClosureType where-  fromEnum INVALID_OBJECT = 0-  fromEnum CONSTR = 1-  fromEnum CONSTR_1_0 = 2-  fromEnum CONSTR_0_1 = 3-  fromEnum CONSTR_2_0 = 4-  fromEnum CONSTR_1_1 = 5-  fromEnum CONSTR_0_2 = 6-  fromEnum CONSTR_STATIC = 7-  fromEnum CONSTR_NOCAF_STATIC = 8-  fromEnum FUN = 9-  fromEnum FUN_1_0 = 10-  fromEnum FUN_0_1 = 11-  fromEnum FUN_2_0 = 12-  fromEnum FUN_1_1 = 13-  fromEnum FUN_0_2 = 14-  fromEnum FUN_STATIC = 15-  fromEnum THUNK = 16-  fromEnum THUNK_1_0 = 17-  fromEnum THUNK_0_1 = 18-  fromEnum THUNK_2_0 = 19-  fromEnum THUNK_1_1 = 20-  fromEnum THUNK_0_2 = 21-  fromEnum THUNK_STATIC = 22-  fromEnum THUNK_SELECTOR = 23-  fromEnum BCO = 24-  fromEnum AP = 25-  fromEnum PAP = 26-  fromEnum AP_STACK = 27-  fromEnum IND = 28-  fromEnum IND_OLDGEN = 29-  fromEnum IND_PERM = 30-  fromEnum IND_OLDGEN_PERM = 31-  fromEnum IND_STATIC = 32-  fromEnum RET_BCO = 33-  fromEnum RET_SMALL = 34-  fromEnum RET_BIG = 35-  fromEnum RET_DYN = 36-  fromEnum RET_FUN = 37-  fromEnum UPDATE_FRAME = 38-  fromEnum CATCH_FRAME = 39-  fromEnum STOP_FRAME = 40-  fromEnum CAF_BLACKHOLE = 41-  fromEnum BLACKHOLE = 42-  fromEnum MVAR_CLEAN = 43-  fromEnum MVAR_DIRTY = 44-  fromEnum ARR_WORDS = 45-  fromEnum MUT_ARR_PTRS_CLEAN = 46-  fromEnum MUT_ARR_PTRS_DIRTY = 47-  fromEnum MUT_ARR_PTRS_FROZEN0 = 48-  fromEnum MUT_ARR_PTRS_FROZEN = 49-  fromEnum MUT_VAR_CLEAN = 50-  fromEnum MUT_VAR_DIRTY = 51-  fromEnum WEAK = 52-  fromEnum STABLE_NAME = 53-  fromEnum TSO = 54-  fromEnum BLOCKED_FETCH = 55-  fromEnum FETCH_ME = 56-  fromEnum FETCH_ME_BQ = 57-  fromEnum RBH = 58-  fromEnum REMOTE_REF = 59-  fromEnum TVAR_WATCH_QUEUE = 60-  fromEnum INVARIANT_CHECK_QUEUE = 61-  fromEnum ATOMIC_INVARIANT = 62-  fromEnum TVAR = 63-  fromEnum TREC_CHUNK = 64-  fromEnum TREC_HEADER = 65-  fromEnum ATOMICALLY_FRAME = 66-  fromEnum CATCH_RETRY_FRAME = 67-  fromEnum CATCH_STM_FRAME = 68-  fromEnum WHITEHOLE = 69-  fromEnum N_CLOSURE_TYPES = 70+  fromEnum INVALID_OBJECT          = 0+  fromEnum CONSTR                  = 1+  fromEnum CONSTR_1_0              = 2+  fromEnum CONSTR_0_1              = 3+  fromEnum CONSTR_2_0              = 4+  fromEnum CONSTR_1_1              = 5+  fromEnum CONSTR_0_2              = 6+  fromEnum CONSTR_STATIC           = 7+  fromEnum CONSTR_NOCAF_STATIC     = 8+  fromEnum FUN                     = 9+  fromEnum FUN_1_0                 = 10+  fromEnum FUN_0_1                 = 11+  fromEnum FUN_2_0                 = 12+  fromEnum FUN_1_1                 = 13+  fromEnum FUN_0_2                 = 14+  fromEnum FUN_STATIC              = 15+  fromEnum THUNK                   = 16+  fromEnum THUNK_1_0               = 17+  fromEnum THUNK_0_1               = 18+  fromEnum THUNK_2_0               = 19+  fromEnum THUNK_1_1               = 20+  fromEnum THUNK_0_2               = 21+  fromEnum THUNK_STATIC            = 22+  fromEnum THUNK_SELECTOR          = 23+  fromEnum BCO                     = 24+  fromEnum AP                      = 25+  fromEnum PAP                     = 26+  fromEnum AP_STACK                = 27+  fromEnum IND                     = 28+  fromEnum IND_OLDGEN              = 29+  fromEnum IND_PERM                = 30+  fromEnum IND_OLDGEN_PERM         = 31+  fromEnum IND_STATIC              = 32+  fromEnum RET_BCO                 = 33+  fromEnum RET_SMALL               = 34+  fromEnum RET_BIG                 = 35+  fromEnum RET_DYN                 = 36+  fromEnum RET_FUN                 = 37+  fromEnum UPDATE_FRAME            = 38+  fromEnum CATCH_FRAME             = 39+  fromEnum STOP_FRAME              = 40+  fromEnum CAF_BLACKHOLE           = 41+  fromEnum BLACKHOLE               = 42+  fromEnum SE_BLACKHOLE            = 43+  fromEnum SE_CAF_BLACKHOLE        = 44+  fromEnum MVAR_CLEAN              = 45+  fromEnum MVAR_DIRTY              = 46+  fromEnum ARR_WORDS               = 47+  fromEnum MUT_ARR_PTRS_CLEAN      = 48+  fromEnum MUT_ARR_PTRS_DIRTY      = 49+  fromEnum MUT_ARR_PTRS_FROZEN0    = 50+  fromEnum MUT_ARR_PTRS_FROZEN     = 51+  fromEnum MUT_VAR_CLEAN           = 52+  fromEnum MUT_VAR_DIRTY           = 53+  fromEnum WEAK                    = 54+  fromEnum STABLE_NAME             = 55+  fromEnum TSO                     = 56+  fromEnum BLOCKED_FETCH           = 57+  fromEnum FETCH_ME                = 58+  fromEnum FETCH_ME_BQ             = 59+  fromEnum RBH                     = 60+  fromEnum REMOTE_REF              = 62+  fromEnum TVAR_WATCH_QUEUE        = 63+  fromEnum INVARIANT_CHECK_QUEUE   = 64+  fromEnum ATOMIC_INVARIANT        = 65+  fromEnum TVAR                    = 66+  fromEnum TREC_CHUNK              = 67+  fromEnum TREC_HEADER             = 68+  fromEnum ATOMICALLY_FRAME        = 69+  fromEnum CATCH_RETRY_FRAME       = 70+  fromEnum CATCH_STM_FRAME         = 71+  fromEnum WHITEHOLE               = 72   toEnum 0 = INVALID_OBJECT   toEnum 1 = CONSTR   toEnum 2 = CONSTR_1_0@@ -245,34 +231,40 @@   toEnum 40 = STOP_FRAME   toEnum 41 = CAF_BLACKHOLE   toEnum 42 = BLACKHOLE-  toEnum 43 = MVAR_CLEAN-  toEnum 44 = MVAR_DIRTY-  toEnum 45 = ARR_WORDS-  toEnum 46 = MUT_ARR_PTRS_CLEAN-  toEnum 47 = MUT_ARR_PTRS_DIRTY-  toEnum 48 = MUT_ARR_PTRS_FROZEN0-  toEnum 49 = MUT_ARR_PTRS_FROZEN-  toEnum 50 = MUT_VAR_CLEAN-  toEnum 51 = MUT_VAR_DIRTY-  toEnum 52 = WEAK-  toEnum 53 = STABLE_NAME-  toEnum 54 = TSO-  toEnum 55 = BLOCKED_FETCH-  toEnum 56 = FETCH_ME-  toEnum 57 = FETCH_ME_BQ-  toEnum 58 = RBH-  toEnum 59 = REMOTE_REF-  toEnum 60 = TVAR_WATCH_QUEUE-  toEnum 61 = INVARIANT_CHECK_QUEUE-  toEnum 62 = ATOMIC_INVARIANT-  toEnum 63 = TVAR-  toEnum 64 = TREC_CHUNK-  toEnum 65 = TREC_HEADER-  toEnum 66 = ATOMICALLY_FRAME-  toEnum 67 = CATCH_RETRY_FRAME-  toEnum 68 = CATCH_STM_FRAME-  toEnum 69 = WHITEHOLE-  toEnum 70 = N_CLOSURE_TYPES-  toEnum _  = error "toEnum: ClosureType: invalid ClosureType"+  toEnum 43 = SE_BLACKHOLE+  toEnum 44 = SE_CAF_BLACKHOLE+  toEnum 45 = MVAR_CLEAN+  toEnum 46 = MVAR_DIRTY+  toEnum 47 = ARR_WORDS+  toEnum 48 = MUT_ARR_PTRS_CLEAN+  toEnum 49 = MUT_ARR_PTRS_DIRTY+  toEnum 50 = MUT_ARR_PTRS_FROZEN0+  toEnum 51 = MUT_ARR_PTRS_FROZEN+  toEnum 52 = MUT_VAR_CLEAN+  toEnum 53 = MUT_VAR_DIRTY+  toEnum 54 = WEAK+  toEnum 55 = STABLE_NAME+  toEnum 56 = TSO+  toEnum 57 = BLOCKED_FETCH+  toEnum 58 = FETCH_ME+  toEnum 59 = FETCH_ME_BQ+  toEnum 60 = RBH+  toEnum 62 = REMOTE_REF+  toEnum 63 = TVAR_WATCH_QUEUE+  toEnum 64 = INVARIANT_CHECK_QUEUE+  toEnum 65 = ATOMIC_INVARIANT+  toEnum 66 = TVAR+  toEnum 67 = TREC_CHUNK+  toEnum 68 = TREC_HEADER+  toEnum 69 = ATOMICALLY_FRAME+  toEnum 70 = CATCH_RETRY_FRAME+  toEnum 71 = CATCH_STM_FRAME+  toEnum 72 = WHITEHOLE+  toEnum n  = error ("toEnum: ClosureType: invalid ClosureType: " ++ show n) -------------------------------------------------++++++
src/GHC/Vacuum/Dot.hs view
@@ -2,7 +2,7 @@ module GHC.Vacuum.Dot (    graphToDot   ,ppGraph,ppEdge,gStyle-  ,Doc,text,render+--   ,Doc,text,render ) where  import Text.PrettyPrint@@ -18,16 +18,16 @@  gStyle :: String gStyle = unlines-  ["graph [rankdir=LR, splines=true];"-  ,"node [label=\"\\N\", shape=none, fontcolor=blue, fontname=courier];"-  ,"edge [color=black, style=dotted, fontname=courier, arrowname=onormal];"]+  ["  graph [rankdir=LR, splines=true];"+  ,"  node [label=\"\\N\", shape=none, fontcolor=blue, fontname=courier];"+  ,"  edge [color=black, style=dotted, fontname=courier, arrowname=onormal];"]  ppGraph :: [(String, [String])] -> Doc ppGraph xs = (text "digraph g" <+> text "{")               $+$ text gStyle                 $+$ nest indent (vcat . fmap ppEdge $ xs)                     $+$ text "}"-                        where indent = 4+                        where indent = 2  ppEdge :: (String, [String]) -> Doc ppEdge (x,xs) = (dQText x) <+> (text "->")
− src/GHC/Vacuum/GHC.hs
@@ -1,8 +0,0 @@--module GHC.Vacuum.GHC (-   module Internal-  ,module Imports-) where--import GHC.Vacuum.GHC.Imports as Imports-import GHC.Vacuum.GHC.Internal as Internal
− src/GHC/Vacuum/GHC/Imports.hs
@@ -1,97 +0,0 @@---- | Want this module to be as isolated as possible,---  due to the extreme volatility of the GHC-API.--module GHC.Vacuum.GHC.Imports (-   module Constants-  ,module GHC.Ptr-  ,module GHC.Prim-  ,module GHC.Exts-  ,module ByteCodeLink-  ,module BCI-  ,module Rt -- RtClosureInspect-  ,module CgInfoTbls-  ,module SMRep---   ,module GHC-  ,module HscMain-  ,module HscTypes-  ,module DynFlags-  ,module StaticFlags-  ,module SysTools-  ,module Packages---   ,module PackageConfig---   ,module Distribution.Package-  ,module Name-  ,module Module-  ,module IfaceEnv---   ,module TcRnMonad-  ,module Outputable-  ,module FastString---   ,module Util-  ,module Bag-  ,ghciTablesNextToCode-  ,setContext-  ,stgItblPtrs-) where-------------------------------------------------------import Constants--import GHC.Ptr(Ptr(..))-import GHC.Prim-import GHC.Exts(Int(..))--import ByteCodeLink-import ByteCodeItbls as BCI hiding (ptrs)-import qualified ByteCodeItbls as BCI--- import RtClosureInspect hiding (ClosureType)-import RtClosureInspect as Rt hiding (tipe,ClosureType(..),isFun)-import CgInfoTbls hiding (infoTable)-import SMRep hiding (ClosureType(..))--import GHC (setContext)--- import GHC hiding (lookupName,compileExpr,LIE)-import HscMain-import HscTypes-import DynFlags-import StaticFlags-import SysTools (initSysTools)--import Packages--- import PackageConfig-import Distribution.Package (PackageName(..))--import Name-import Module--import IfaceEnv--- import TcRnMonad hiding (Env)--import Outputable(ppr,showSDoc)-import qualified Outputable as O--import FastString-  hiding (uniq)-import Util (ghciTablesNextToCode)-import Bag-  (unitBag-  ,listToBag-  ,emptyBag-  ,isEmptyBag)----------------------------------------------------stgItblPtrs = BCI.ptrs---------------------------------------------------------
− src/GHC/Vacuum/GHC/Internal.hs
@@ -1,335 +0,0 @@---- | Want this module to be as isolated as possible,---  due to the extreme volatility of the GHC-API.--module GHC.Vacuum.GHC.Internal (-   GhcApiCfg(..)-  ,defaultGhcApiConfig-  ,withGhcApiCfg-  ,dynFlagsOn,dynFlagsOff-  ,defaultEnv,newEnv,myRunGhc-  ,CabalPkg(..)-  ,CabalPkgId-  ,CabalPkgVersion-  ,CabalModuleId-  ,CabalModule(..)-  ,cabalModulePkgId-  ,cabalModulePkgVersion-  ,cabalModuleModuleId-  ,preludeCM-  ,collectCabalModules-  ,cabalPkgToModules-  ,dataConInfoPtrToNames-) where--import GHC.Paths(libdir)-import GHC.Vacuum.GHC.Imports as Imports-import Distribution.Package(PackageName(..))--import Data.Char-import Data.Word-import Data.List-import Data.IORef-import Data.Array.IArray-import Control.Monad-import Foreign--import Data.List-import Data.Map(Map)-import Data.Set(Set)-import qualified Data.Set as S-import qualified Data.Map as M-import Data.Monoid(Monoid(..))--------------------------------------------------------------------------------------------------------data GhcApiCfg = GhcApiCfg-  {ghcApiLibDir :: FilePath-  ,ghcApiImports :: [CabalPkg]-  ,ghcApiDynFlagsOn :: [DynFlag]-  ,ghcApiDynFlagsOff :: [DynFlag]}-  deriving(Eq,Ord,Read,Show)--deriving instance Ord DynFlag-deriving instance Read DynFlag--defaultGhcApiConfig :: GhcApiCfg-defaultGhcApiConfig = GhcApiCfg-  {ghcApiLibDir = GHC.Paths.libdir-  ,ghcApiImports-        -- e.g.-      = CabalPkg "base" [] ["Prelude"]-          : collectCabalModules-              [CabalModule "base" [] "Prelude"-              ,CabalModule "base" [] "Prelude"]-  ,ghcApiDynFlagsOn-      = [Opt_TemplateHaskell-        ,Opt_QuasiQuotes-        ,Opt_ViewPatterns-        ,Opt_RankNTypes-        ,Opt_KindSignatures-        ,Opt_UnicodeSyntax-          -- um, i assume this turns it _off_ (?)-        ,Opt_MonomorphismRestriction-        ,Opt_PatternGuards-        ,Opt_ParallelListComp-        ,Opt_ImplicitParams-        ,Opt_BangPatterns]-  ,ghcApiDynFlagsOff-      = [Opt_PrintBindResult-        ,Opt_PrintBindContents-        ,Opt_PrintEvldWithShow]}--withGhcApiCfg :: GhcApiCfg-              -> (FilePath -> DynFlags -> [Module] -> o)-              -> (DynFlags -> o)-withGhcApiCfg (GhcApiCfg-                    libdir-                    imports-                    ons offs) k dflags = k libdir-                                           ((dynFlagsOn ons-                                              . dynFlagsOff offs) dflags)-                                           (concatMap cabalPkgToModules imports)--dynFlagsOn  :: [DynFlag] -> (DynFlags -> DynFlags)-dynFlagsOn = flip (foldl dopt_set)--dynFlagsOff :: [DynFlag] -> (DynFlags -> DynFlags)-dynFlagsOff = flip (foldl dopt_unset)--------------------------------------------------------------------------------------------------------defaultEnv :: IO HscEnv-defaultEnv = newEnv defaultGhcApiConfig-                    (Just defaultDynFlags)--newEnv :: GhcApiCfg -> Maybe DynFlags -> IO HscEnv-newEnv cfg dflagsM-  = let-        initEnv :: HscEnv -> [Module] -> IO HscEnv-        initEnv hsc modules = do-          let dflags = hsc_dflags hsc-          (dflags', preload) <- initPackages-                    (dflags{ghcLink=LinkInMemory})-          let hsc' = hsc{hsc_dflags = dflags'}-          myRunGhc hsc' (setContext [] modules)-          return hsc'--        newEnv' :: Maybe FilePath -> DynFlags -> IO HscEnv-        newEnv' mb_top_dir dflags00 = do-          initStaticOpts-          dflags0 <- initDynFlags dflags00-          dflags  <- initSysTools mb_top_dir dflags0-          hsc <- newHscEnv dflags-          return hsc--    in withGhcApiCfg cfg (\libdir dflags modules ->-           do env <- newEnv' (Just libdir) dflags-              env' <- initEnv env modules-              return env')-          (maybe defaultDynFlags id dflagsM)--myRunGhc :: HscEnv -> Ghc a -> IO a-myRunGhc hsc_env ghc = do-  wref <- newIORef emptyBag-  ref <- newIORef hsc_env-  unGhc ghc (Session ref wref)--------------------------------------------------------------------------------------------------------data CabalPkg = CabalPkg-  {cabalPkgPkg     :: CabalPkgId-  ,cabalPkgVersion :: CabalPkgVersion-  ,cabalPkgModules :: [CabalModuleId]}-  deriving(Eq,Ord,Read,Show)--type CabalPkgId      = String-type CabalPkgVersion = [Int]-type CabalModuleId   = String--data CabalModule = CabalModule-                    CabalPkgId-                    CabalPkgVersion-                    CabalModuleId-  deriving(Eq,Ord,Read,Show)--cabalModulePkgId      :: CabalModule -> CabalPkgId-cabalModulePkgVersion :: CabalModule -> CabalPkgVersion-cabalModuleModuleId   :: CabalModule -> CabalModuleId--cabalModulePkgId      (CabalModule x _ _) = x-cabalModulePkgVersion (CabalModule _ x _) = x-cabalModuleModuleId   (CabalModule _ _ x) = x--preludeCM :: CabalModule-preludeCM = CabalModule "base" [] "Prelude"--collectCabalModules :: [CabalModule] -> [CabalPkg]-collectCabalModules-  = let f &&& g = \x -> (f x, g x)-        keyify = cabalModulePkgId-                  &&& cabalModulePkgVersion-        elemify = S.singleton . cabalModuleModuleId-        toPkg ((pid,v),ms) = CabalPkg pid v (S.toList ms)-        collect (<>) f g = M.toList . flip foldl' mempty-                            (\m a -> M.insertWith' (<>) (f a)-                                                        (g a) m)-    in fmap toPkg . collect S.union keyify elemify--cabalPkgToModules :: CabalPkg -> [Module]-cabalPkgToModules (CabalPkg-                    pid-                    ver-                    mods) = fmap (mkModule-                                    (mkPackageId-                                      (PackageIdentifier-                                        (PackageName pid)-                                        (Version ver [])))-                                    . mkModuleName) mods---------------------------------------------------------------------------------------------------------- * This section is taken from Linker.lhs---- %--- % (c) The University of Glasgow 2005-2006--- %---- | Given a data constructor in the heap, find its Name.---   The info tables for data constructors have a field which records---   the source name of the constructor as a Ptr Word8 (UTF-8 encoded---   string). The format is:------    Package:Module.Name------   We use this string to lookup the interpreter's internal representation of the name---   using the lookupOrig.--dataConInfoPtrToNames :: Ptr () -> IO (String, String, String) -- (Either String Name) -- TcM (Either String Name)-dataConInfoPtrToNames x = do-   readIORef justToInitGhc-   initStaticOpts-   theString <- do -- liftIO $ do-      let ptr = castPtr x :: Ptr StgInfoTable-      conDescAddress <- getConDescAddress ptr-      peekArray0 0 conDescAddress-   let (pkg, mod, occ) = parse theString -       pkgFS = mkFastStringByteList pkg-       modFS = mkFastStringByteList mod-       occFS = mkFastStringByteList occ-       occName = mkOccNameFS dataName occFS-       modName = mkModule (fsToPackageId pkgFS) (mkModuleNameFS modFS)-   return ((packageIdString . modulePackageId) modName-          ,(moduleNameString . moduleName) modName-          ,occNameString occName)---    return (showSDoc $ ppr modName O.<> O.dot O.<> ppr occName)-   -- return (Left$ showSDoc$ ppr modName O.<> O.dot O.<> ppr occName)-    -- `recoverM` (Right `fmap` lookupOrig modName occName)----- | This is needed to make sure that GHC is all initialized with its---  plethora of well-hidden and ill-documented global vars. I'm not---  bothering to NOINLINE it because i like to live dangerously.---  (clearly i'm beligerent at this point).-justToInitGhc :: IORef HscEnv-justToInitGhc = unsafePerformIO (newIORef =<< defaultEnv)---   {- To find the string in the constructor's info table we need to consider-      the layout of info tables relative to the entry code for a closure.--      An info table can be next to the entry code for the closure, or it can-      be separate. The former (faster) is used in registerised versions of ghc,-      and the latter (portable) is for non-registerised versions.--      The diagrams below show where the string is to be found relative to-      the normal info table of the closure.--      1) Code next to table:--         ---------------         |            |   <- pointer to the start of the string-         ---------------         |            |   <- the (start of the) info table structure-         |            |-         |            |-         ---------------         | entry code |-         |    ....    |--         In this case the pointer to the start of the string can be found in-         the memory location _one word before_ the first entry in the normal info-         table.--      2) Code NOT next to table:--                                 ---------------         info table structure -> |     *------------------> ---------------                                 |            |             | entry code |-                                 |            |             |    ....    |-                                 ---------------         ptr to start of str ->  |            |-                                 ----------------         In this case the pointer to the start of the string can be found-         in the memory location: info_table_ptr + info_table_size-   -}--getConDescAddress :: Ptr StgInfoTable -> IO (Ptr Word8)-getConDescAddress ptr-  | ghciTablesNextToCode = do-      offsetToString <- peek (ptr `plusPtr` (negate wORD_SIZE))-      return $ (ptr `plusPtr` stdInfoTableSizeB)-                `plusPtr` (fromIntegral (offsetToString :: StgWord))-  | otherwise = peek . intPtrToPtr-                  . (+ fromIntegral-                        stdInfoTableSizeB)-                    . ptrToIntPtr $ ptr-   -- parsing names is a little bit fiddly because we have a string in the form: -   -- pkg:A.B.C.foo, and we want to split it into three parts: ("pkg", "A.B.C", "foo").-   -- Thus we split at the leftmost colon and the rightmost occurrence of the dot.-   -- It would be easier if the string was in the form pkg:A.B.C:foo, but alas-   -- this is not the conventional way of writing Haskell names. We stick with-   -- convention, even though it makes the parsing code more troublesome.-   -- Warning: this code assumes that the string is well formed. XXXXXXXXXXXXXXXXXXX-parse :: [Word8] -> ([Word8], [Word8], [Word8])-parse input = if not . all (>0) . fmap length $ [pkg,mod,occ]-                then (error . concat)-                        ["getConDescAddress:parse:"-                        ,"(not . all (>0) . fmap le"-                        ,"ngth $ [pkg,mod,occ]"]-                else (pkg, mod, occ)---   = ASSERT (all (>0) (map length [pkg, mod, occ])) (pkg, mod, occ)   -- XXXXXXXXXXXXXXXX-  where-        (pkg, rest1) = break (== fromIntegral (ord ':')) input-        (mod, occ)-            = (concat $ intersperse [dot] $ reverse modWords, occWord)-            where-            (modWords, occWord) = if (length rest1 < 1) --  XXXXXXXXx YUKX-                                    then error "getConDescAddress:parse:length rest1 < 1"-                                    else parseModOcc [] (tail rest1)-        -- ASSERT (length rest1 > 0) (parseModOcc [] (tail rest1))-        dot = fromIntegral (ord '.')-        parseModOcc :: [[Word8]] -> [Word8] -> ([[Word8]], [Word8])-        parseModOcc acc str-            = case break (== dot) str of-                (top, []) -> (acc, top)-                (top, _:bot) -> parseModOcc (top : acc) bot--------------------------------------------------
+ src/GHC/Vacuum/Internal.hs view
@@ -0,0 +1,483 @@+{-# LANGUAGE CPP #-}++module GHC.Vacuum.Internal (+   HValue+  ,HalfWord+  ,ItblCode+  ,StgInfoTable(..)+  ,ghciTablesNextToCode+  ,dataConInfoPtrToNames+  ,wORD_SIZE+  ,hALF_WORD_SIZE+  ,S(..),get,gets,set,io,modify,runS+) where++import Data.Char+import Data.Word+import Data.List+import Data.IORef+import Data.Array.IArray+import Control.Monad+import Control.Monad.Fix+import Foreign++import Data.List+import Data.Map(Map)+import Data.Set(Set)+import qualified Data.Set as S+import qualified Data.Map as M+import Data.Monoid(Monoid(..))++import GHC.Prim+import GHC.Exts++#include "ghcplatform.h"+#include "ghcautoconf.h"+#define GHCI_TABLES_NEXT_TO_CODE+        -- is there somewhere to get this define?++-----------------------------------------------------------------------------++-- * Fabricate what we need to avoid the ghc pkg dep++type HValue = Any++#if SIZEOF_VOID_P == 8+type HalfWord = Word32+#else+type HalfWord = Word16+#endif++-- | From SMRep+type ByteOff = Int++-- | From SMRep+type WordOff = Int++-- | From SMRep+type StgWord = Word++-- hmmmmmm. Is there any way to tell this?+opt_SccProfilingOn = False++-- ghci> wORD_SIZE+-- 8+-- ghci> sizeOf (undefined :: Word)+-- 8+wORD_SIZE :: Int+wORD_SIZE = sizeOf (undefined :: Word)++hALF_WORD_SIZE :: Int+hALF_WORD_SIZE  = wORD_SIZE `div` 2++-- | This is currently always True since+-- i'm not sure how to get at the CPP define+-- \"GHCI_TABLES_NEXT_TO_CODE\" (or equiv) to tell.+ghciTablesNextToCode :: Bool+#ifdef GHCI_TABLES_NEXT_TO_CODE+ghciTablesNextToCode = True+#else+ghciTablesNextToCode = False+#endif++-----------------------------------------------------------------------------++data StgInfoTable = StgInfoTable {+#ifndef GHCI_TABLES_NEXT_TO_CODE+   entry  :: Ptr (),+#endif+   ptrs   :: HalfWord,+   nptrs  :: HalfWord,+   tipe   :: HalfWord,+   srtlen :: HalfWord+#ifdef GHCI_TABLES_NEXT_TO_CODE+ , code   :: [ItblCode]+#endif+  }++instance Storable StgInfoTable where++   sizeOf itbl+      = sum+        [+#ifndef GHCI_TABLES_NEXT_TO_CODE+         fieldSz entry itbl,+#endif+         fieldSz ptrs itbl,+         fieldSz nptrs itbl,+         fieldSz tipe itbl,+         fieldSz srtlen itbl+#ifdef GHCI_TABLES_NEXT_TO_CODE+        ,fieldSz (head.code) itbl * itblCodeLength+#endif+        ]++   alignment itbl+      = SIZEOF_VOID_P++   poke a0 itbl+      = flip evalS (castPtr a0)+      $ do+#ifndef GHCI_TABLES_NEXT_TO_CODE+           store (entry  itbl)+#endif+           store (ptrs   itbl)+           store (nptrs  itbl)+           store (tipe   itbl)+           store (srtlen itbl)+#ifdef GHCI_TABLES_NEXT_TO_CODE+           sequence_ (map store (code itbl))+#endif++   peek a0+      = flip evalS (castPtr a0)+      $ do+#ifndef GHCI_TABLES_NEXT_TO_CODE+           entry  <- load+#endif+           ptrs   <- load+           nptrs  <- load+           tipe   <- load+           srtlen <- load+#ifdef GHCI_TABLES_NEXT_TO_CODE+           code   <- sequence (replicate itblCodeLength load)+#endif+           return+              StgInfoTable {+#ifndef GHCI_TABLES_NEXT_TO_CODE+                 entry  = entry,+#endif+                 ptrs   = ptrs,+                 nptrs  = nptrs,+                 tipe   = tipe,+                 srtlen = srtlen+#ifdef GHCI_TABLES_NEXT_TO_CODE+                ,code   = code+#endif+              }++fieldSz :: (Storable a, Storable b) => (a -> b) -> a -> Int+fieldSz sel x = sizeOf (sel x)++type PtrIO = S (Ptr Word8)++advance :: Storable a => PtrIO (Ptr a)+advance = S adv where+    adv k addr = case castPtr addr of+                  addrCast -> k addrCast+                                (addr `plusPtr`+                                  sizeOfPointee addrCast)++sizeOfPointee :: (Storable a) => Ptr a -> Int+sizeOfPointee addr = sizeOf (typeHack addr)+  where typeHack = undefined  :: Ptr a -> a++store :: Storable a => a -> PtrIO ()+store x = do addr <- advance+             io (poke addr x)++load :: Storable a => PtrIO a+load = do addr <- advance+          io (peek addr)++newtype S s a = S {unS :: forall o. (a -> s -> IO o) -> s -> IO o}+instance Functor (S s) where+  fmap f (S g) = S (\k -> g (k . f))+instance Monad (S s) where+  return a = S (\k -> k a)+  S g >>= f = S (\k -> g (\a -> unS (f a) k))+instance MonadFix (S s) where+  mfix f = S (\k s ->+    uncurry k =<< mfix (\ ~(a,_) ->+    -- the lazy pattern is ESSENTIAL, otherwise <<loop>>+      unS (f a) (\a s -> return (a,s)) s))+get :: S s s+get = S (\k s -> k s s)+gets :: (s -> a) -> S s a+gets f = S (\k s -> k (f s) s)+set :: s -> S s ()+set s = S (\k _ -> k () s)+io :: IO a -> S s a+io m = S (\k s -> flip k s =<< m)+modify :: (s -> s) -> S s ()+modify f = S (\k -> k () . f)+runS :: S s a -> s -> IO (a, s)+runS (S g) = g (\a -> return . (,) a)+evalS :: S s a -> s -> IO a+evalS (S g) = g (\a _ -> return a)+execS :: S s a -> s -> IO s+execS (S g) = g (\_ -> return)++-----------------------------------------------------------------------------++-- VACUUM: All this just to get itblCodeLength.++-- Make code which causes a jump to the given address.  This is the+-- only arch-dependent bit of the itbl story.  The returned list is+-- itblCodeLength elements (bytes) long.++-- For sparc_TARGET_ARCH, i386_TARGET_ARCH, etc.+-- #include "nativeGen/NCG.h"+-- VACUUM: we get *_TARGET_ARCH from ghcplatform.h instead++itblCodeLength :: Int+itblCodeLength = length (mkJumpToAddr undefined)++mkJumpToAddr :: Ptr () -> [ItblCode]++ptrToInt (Ptr a#) = I# (addr2Int# a#)++#if sparc_TARGET_ARCH+-- After some consideration, we'll try this, where+-- 0x55555555 stands in for the address to jump to.+-- According to ghc/includes/MachRegs.h, %g3 is very+-- likely indeed to be baggable.+--+--   0000 07155555              sethi   %hi(0x55555555), %g3+--   0004 8610E155              or      %g3, %lo(0x55555555), %g3+--   0008 81C0C000              jmp     %g3+--   000c 01000000              nop++type ItblCode = Word32+mkJumpToAddr a+   = let w32 = fromIntegral (ptrToInt a)++         hi22, lo10 :: Word32 -> Word32+         lo10 x = x .&. 0x3FF+         hi22 x = (x `shiftR` 10) .&. 0x3FFFF++     in  [ 0x07000000 .|. (hi22 w32),+           0x8610E000 .|. (lo10 w32),+           0x81C0C000,+           0x01000000 ]++#elif powerpc_TARGET_ARCH+-- We'll use r12, for no particular reason.+-- 0xDEADBEEF stands for the adress:+-- 3D80DEAD lis r12,0xDEAD+-- 618CBEEF ori r12,r12,0xBEEF+-- 7D8903A6 mtctr r12+-- 4E800420 bctr++type ItblCode = Word32+mkJumpToAddr a =+    let w32 = fromIntegral (ptrToInt a)+  hi16 x = (x `shiftR` 16) .&. 0xFFFF+  lo16 x = x .&. 0xFFFF+    in  [+  0x3D800000 .|. hi16 w32,+  0x618C0000 .|. lo16 w32,+  0x7D8903A6, 0x4E800420+  ]++#elif i386_TARGET_ARCH+-- Let the address to jump to be 0xWWXXYYZZ.+-- Generate   movl $0xWWXXYYZZ,%eax  ;  jmp *%eax+-- which is+-- B8 ZZ YY XX WW FF E0++type ItblCode = Word8+mkJumpToAddr a+   = let w32 = fromIntegral (ptrToInt a) :: Word32+         insnBytes :: [Word8]+         insnBytes+            = [0xB8, byte0 w32, byte1 w32, +                     byte2 w32, byte3 w32, +               0xFF, 0xE0]+     in+         insnBytes++#elif x86_64_TARGET_ARCH+-- Generates:+--  jmpq *.L1(%rip)+--  .align 8+-- .L1:+--  .quad <addr>+--+-- We need a full 64-bit pointer (we can't assume the info table is+-- allocated in low memory).  Assuming the info pointer is aligned to+-- an 8-byte boundary, the addr will also be aligned.++type ItblCode = Word8+mkJumpToAddr a+   = let w64 = fromIntegral (ptrToInt a) :: Word64+         insnBytes :: [Word8]+         insnBytes+            = [0xff, 0x25, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,+                byte0 w64, byte1 w64, byte2 w64, byte3 w64,+                byte4 w64, byte5 w64, byte6 w64, byte7 w64]+     in+         insnBytes++#elif alpha_TARGET_ARCH+type ItblCode = Word32+mkJumpToAddr a+    = [ 0xc3800000      -- br   at, .+4+      , 0xa79c000c      -- ldq  at, 12(at)+      , 0x6bfc0000      -- jmp  (at)    # with zero hint -- oh well+      , 0x47ff041f      -- nop+      , fromIntegral (w64 .&. 0x0000FFFF)+      , fromIntegral ((w64 `shiftR` 32) .&. 0x0000FFFF) ]+    where w64 = fromIntegral (ptrToInt a) :: Word64++#else+type ItblCode = Word32+mkJumpToAddr a+    = undefined+#endif++byte0, byte1, byte2, byte3, byte4, byte5, byte6, byte7+   :: (Integral w, Bits w) => w -> Word8+byte0 w = fromIntegral w+byte1 w = fromIntegral (w `shiftR` 8)+byte2 w = fromIntegral (w `shiftR` 16)+byte3 w = fromIntegral (w `shiftR` 24)+byte4 w = fromIntegral (w `shiftR` 32)+byte5 w = fromIntegral (w `shiftR` 40)+byte6 w = fromIntegral (w `shiftR` 48)+byte7 w = fromIntegral (w `shiftR` 56)++-----------------------------------------------------------------------------+--+--  Info table offsets+--+-----------------------------------------------------------------------------++stdInfoTableSizeW :: WordOff+-- The size of a standard info table varies with profiling/ticky etc,+-- so we can't get it from Constants+-- It must vary in sync with mkStdInfoTable+stdInfoTableSizeW+  = size_fixed + size_prof+  where+    size_fixed = 2  -- layout, type+    size_prof | opt_SccProfilingOn = 2+              | otherwise    = 0++stdInfoTableSizeB :: ByteOff+stdInfoTableSizeB = stdInfoTableSizeW * wORD_SIZE++stdSrtBitmapOffset :: ByteOff+-- Byte offset of the SRT bitmap half-word which is +-- in the *higher-addressed* part of the type_lit+stdSrtBitmapOffset = stdInfoTableSizeB - hALF_WORD_SIZE++stdClosureTypeOffset :: ByteOff+-- Byte offset of the closure type half-word +stdClosureTypeOffset = stdInfoTableSizeB - wORD_SIZE++stdPtrsOffset, stdNonPtrsOffset :: ByteOff+stdPtrsOffset    = stdInfoTableSizeB - 2*wORD_SIZE+stdNonPtrsOffset = stdInfoTableSizeB - 2*wORD_SIZE + hALF_WORD_SIZE++------------------------------------------------++-- * This section is taken from Linker.lhs++-- %+-- % (c) The University of Glasgow 2005-2006+-- %++-- | Given a data constructor in the heap, find its Name.+--   The info tables for data constructors have a field which records+--   the source name of the constructor as a Ptr Word8 (UTF-8 encoded+--   string). The format is:+--+--    Package:Module.Name+--+--   We use this string to lookup the interpreter's internal representation of the name+--   using the lookupOrig.++b2s :: [Word8] -> String+b2s = fmap (chr . fromIntegral)++dataConInfoPtrToNames :: Ptr () -> IO (String, String, String)+dataConInfoPtrToNames x = do+  let ptr = castPtr x :: Ptr StgInfoTable+  conDescAddress <- getConDescAddress ptr+  theString <- peekArray0 0 conDescAddress+  let (pkg, mod, occ) = parse theString+  return (b2s pkg, b2s mod, b2s occ)++{- To find the string in the constructor's info table we need to consider+  the layout of info tables relative to the entry code for a closure.++  An info table can be next to the entry code for the closure, or it can+  be separate. The former (faster) is used in registerised versions of ghc,+  and the latter (portable) is for non-registerised versions.++  The diagrams below show where the string is to be found relative to+  the normal info table of the closure.++  1) Code next to table:++      --------------+      |            |   <- pointer to the start of the string+      --------------+      |            |   <- the (start of the) info table structure+      |            |+      |            |+      --------------+      | entry code |+      |    ....    |++      In this case the pointer to the start of the string can be found in+      the memory location _one word before_ the first entry in the normal info+      table.++  2) Code NOT next to table:++                              --------------+      info table structure -> |     *------------------> --------------+                              |            |             | entry code |+                              |            |             |    ....    |+                              --------------+      ptr to start of str ->  |            |+                              --------------++      In this case the pointer to the start of the string can be found+      in the memory location: info_table_ptr + info_table_size+-}++getConDescAddress :: Ptr StgInfoTable -> IO (Ptr Word8)+getConDescAddress ptr+  | ghciTablesNextToCode = do+      offsetToString <- peek (ptr `plusPtr` (negate wORD_SIZE))+      return $ (ptr `plusPtr` stdInfoTableSizeB)+                `plusPtr` (fromIntegral (offsetToString :: StgWord))+  | otherwise = peek . intPtrToPtr+                  . (+ fromIntegral+                        stdInfoTableSizeB)+                    . ptrToIntPtr $ ptr+   -- parsing names is a little bit fiddly because we have a string in the form: +   -- pkg:A.B.C.foo, and we want to split it into three parts: ("pkg", "A.B.C", "foo").+   -- Thus we split at the leftmost colon and the rightmost occurrence of the dot.+   -- It would be easier if the string was in the form pkg:A.B.C:foo, but alas+   -- this is not the conventional way of writing Haskell names. We stick with+   -- convention, even though it makes the parsing code more troublesome.+   -- Warning: this code assumes that the string is well formed. XXXXXXXXXXXXXXXXXXX+parse :: [Word8] -> ([Word8], [Word8], [Word8])+parse input = if not . all (>0) . fmap length $ [pkg,mod,occ]+                then (error . concat)+                        ["getConDescAddress:parse:"+                        ,"(not . all (>0) . fmap le"+                        ,"ngth $ [pkg,mod,occ]"]+                else (pkg, mod, occ)+--   = ASSERT (all (>0) (map length [pkg, mod, occ])) (pkg, mod, occ)   -- XXXXXXXXXXXXXXXX+  where+        (pkg, rest1) = break (== fromIntegral (ord ':')) input+        (mod, occ)+            = (concat $ intersperse [dot] $ reverse modWords, occWord)+            where+            (modWords, occWord) = if (length rest1 < 1) --  XXXXXXXXx YUKX+                                    then error "getConDescAddress:parse:length rest1 < 1"+                                    else parseModOcc [] (tail rest1)+        -- ASSERT (length rest1 > 0) (parseModOcc [] (tail rest1))+        dot = fromIntegral (ord '.')+        parseModOcc :: [[Word8]] -> [Word8] -> ([[Word8]], [Word8])+        parseModOcc acc str+            = case break (== dot) str of+                (top, []) -> (acc, top)+                (top, _:bot) -> parseModOcc (top : acc) bot++------------------------------------------------
vacuum.cabal view
@@ -1,40 +1,26 @@ name:               vacuum-version:            0.0.93+version:            0.0.94 cabal-version:      >= 1.6 build-type:         Simple license:            LGPL license-file:       LICENSE-category:           Interpreter, GHC+category:           Debug, GHC author:             Matt Morrow-copyright:          (c) Matt Morrow 2008+copyright:          (c) Matt Morrow 2009 maintainer:         Matt Morrow <morrow@moonpatio.com> homepage:           http://moonpatio.com/vacuum/ stability:          experimental synopsis:           Extract graph representations of ghc heap values.-description:        .--flag ghc-six-ten-one-  description:  ghc-6.10.1-  default:      True+description:        <http://moonpatio.com/vacuum/>  library   hs-source-dirs:   src-  ghc-options:      -O2 -fglasgow-exts-  extensions:+  ghc-options:      -O2 -fglasgow-exts -funbox-strict-fields+  extensions:       CPP, BangPatterns+  includes:         ghcautoconf.h   exposed-modules:  GHC.Vacuum,-                    GHC.Vacuum.ClosureType,                     GHC.Vacuum.Dot,-                    GHC.Vacuum.GHC.Internal-  other-modules:    GHC.Vacuum.GHC,-                    GHC.Vacuum.GHC.Imports--  if flag(ghc-six-ten-one)-    build-depends:    base==4.*, ghc-prim, ghc-paths,-                      ghc == 6.10.1, Cabal == 1.6.0.1,-                      array, containers, array,-                      pretty, haskell-src-meta-  else-    build-depends:    base==4.*, ghc-prim, ghc-paths,-                      ghc == 6.10.2, Cabal == 1.6.0.3,-                      array, containers, array,-                      pretty, haskell-src-meta+                    GHC.Vacuum.ClosureType,+                    GHC.Vacuum.Internal+  build-depends:    base==4.*, ghc-prim, array,+                    containers, pretty, haskell-src-meta