PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/compiler/iface/BinIface.hs

http://github.com/ghc/ghc
Haskell | 501 lines | 343 code | 62 blank | 96 comment | 8 complexity | 6c61fb3e4bf43c3a0eeb423d762b8583 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, GPL-3.0
  1. {-# LANGUAGE BinaryLiterals, CPP, ScopedTypeVariables #-}
  2. --
  3. -- (c) The University of Glasgow 2002-2006
  4. --
  5. {-# OPTIONS_GHC -O #-}
  6. -- We always optimise this, otherwise performance of a non-optimised
  7. -- compiler is severely affected
  8. -- | Binary interface file support.
  9. module BinIface (
  10. writeBinIface,
  11. readBinIface,
  12. getSymtabName,
  13. getDictFastString,
  14. CheckHiWay(..),
  15. TraceBinIFaceReading(..)
  16. ) where
  17. #include "HsVersions.h"
  18. import TcRnMonad
  19. import TyCon
  20. import ConLike
  21. import PrelInfo ( knownKeyNames )
  22. import Id ( idName, isDataConWorkId_maybe )
  23. import TysWiredIn
  24. import IfaceEnv
  25. import HscTypes
  26. import BasicTypes
  27. import Module
  28. import Name
  29. import DynFlags
  30. import UniqFM
  31. import UniqSupply
  32. import Panic
  33. import Binary
  34. import SrcLoc
  35. import ErrUtils
  36. import FastMutInt
  37. import Unique
  38. import Outputable
  39. import Platform
  40. import FastString
  41. import Constants
  42. import Util
  43. import DataCon
  44. import Data.Bits
  45. import Data.Char
  46. import Data.List
  47. import Data.Word
  48. import Data.Array
  49. import Data.IORef
  50. import Control.Monad
  51. -- ---------------------------------------------------------------------------
  52. -- Reading and writing binary interface files
  53. --
  54. data CheckHiWay = CheckHiWay | IgnoreHiWay
  55. deriving Eq
  56. data TraceBinIFaceReading = TraceBinIFaceReading | QuietBinIFaceReading
  57. deriving Eq
  58. -- | Read an interface file
  59. readBinIface :: CheckHiWay -> TraceBinIFaceReading -> FilePath
  60. -> TcRnIf a b ModIface
  61. readBinIface checkHiWay traceBinIFaceReading hi_path = do
  62. ncu <- mkNameCacheUpdater
  63. dflags <- getDynFlags
  64. liftIO $ readBinIface_ dflags checkHiWay traceBinIFaceReading hi_path ncu
  65. readBinIface_ :: DynFlags -> CheckHiWay -> TraceBinIFaceReading -> FilePath
  66. -> NameCacheUpdater
  67. -> IO ModIface
  68. readBinIface_ dflags checkHiWay traceBinIFaceReading hi_path ncu = do
  69. let printer :: SDoc -> IO ()
  70. printer = case traceBinIFaceReading of
  71. TraceBinIFaceReading -> \sd ->
  72. log_action dflags
  73. dflags
  74. NoReason
  75. SevOutput
  76. noSrcSpan
  77. defaultDumpStyle
  78. sd
  79. QuietBinIFaceReading -> \_ -> return ()
  80. wantedGot :: Outputable a => String -> a -> a -> IO ()
  81. wantedGot what wanted got =
  82. printer (text what <> text ": " <>
  83. vcat [text "Wanted " <> ppr wanted <> text ",",
  84. text "got " <> ppr got])
  85. errorOnMismatch :: (Eq a, Show a) => String -> a -> a -> IO ()
  86. errorOnMismatch what wanted got =
  87. -- This will be caught by readIface which will emit an error
  88. -- msg containing the iface module name.
  89. when (wanted /= got) $ throwGhcExceptionIO $ ProgramError
  90. (what ++ " (wanted " ++ show wanted
  91. ++ ", got " ++ show got ++ ")")
  92. bh <- Binary.readBinMem hi_path
  93. -- Read the magic number to check that this really is a GHC .hi file
  94. -- (This magic number does not change when we change
  95. -- GHC interface file format)
  96. magic <- get bh
  97. wantedGot "Magic" (binaryInterfaceMagic dflags) magic
  98. errorOnMismatch "magic number mismatch: old/corrupt interface file?"
  99. (binaryInterfaceMagic dflags) magic
  100. -- Note [dummy iface field]
  101. -- read a dummy 32/64 bit value. This field used to hold the
  102. -- dictionary pointer in old interface file formats, but now
  103. -- the dictionary pointer is after the version (where it
  104. -- should be). Also, the serialisation of value of type "Bin
  105. -- a" used to depend on the word size of the machine, now they
  106. -- are always 32 bits.
  107. if wORD_SIZE dflags == 4
  108. then do _ <- Binary.get bh :: IO Word32; return ()
  109. else do _ <- Binary.get bh :: IO Word64; return ()
  110. -- Check the interface file version and ways.
  111. check_ver <- get bh
  112. let our_ver = show hiVersion
  113. wantedGot "Version" our_ver check_ver
  114. errorOnMismatch "mismatched interface file versions" our_ver check_ver
  115. check_way <- get bh
  116. let way_descr = getWayDescr dflags
  117. wantedGot "Way" way_descr check_way
  118. when (checkHiWay == CheckHiWay) $
  119. errorOnMismatch "mismatched interface file ways" way_descr check_way
  120. -- Read the dictionary
  121. -- The next word in the file is a pointer to where the dictionary is
  122. -- (probably at the end of the file)
  123. dict_p <- Binary.get bh
  124. data_p <- tellBin bh -- Remember where we are now
  125. seekBin bh dict_p
  126. dict <- getDictionary bh
  127. seekBin bh data_p -- Back to where we were before
  128. -- Initialise the user-data field of bh
  129. bh <- do
  130. bh <- return $ setUserData bh $ newReadState (error "getSymtabName")
  131. (getDictFastString dict)
  132. symtab_p <- Binary.get bh -- Get the symtab ptr
  133. data_p <- tellBin bh -- Remember where we are now
  134. seekBin bh symtab_p
  135. symtab <- getSymbolTable bh ncu
  136. seekBin bh data_p -- Back to where we were before
  137. -- It is only now that we know how to get a Name
  138. return $ setUserData bh $ newReadState (getSymtabName ncu dict symtab)
  139. (getDictFastString dict)
  140. -- Read the interface file
  141. get bh
  142. -- | Write an interface file
  143. writeBinIface :: DynFlags -> FilePath -> ModIface -> IO ()
  144. writeBinIface dflags hi_path mod_iface = do
  145. bh <- openBinMem initBinMemSize
  146. put_ bh (binaryInterfaceMagic dflags)
  147. -- dummy 32/64-bit field before the version/way for
  148. -- compatibility with older interface file formats.
  149. -- See Note [dummy iface field] above.
  150. if wORD_SIZE dflags == 4
  151. then Binary.put_ bh (0 :: Word32)
  152. else Binary.put_ bh (0 :: Word64)
  153. -- The version and way descriptor go next
  154. put_ bh (show hiVersion)
  155. let way_descr = getWayDescr dflags
  156. put_ bh way_descr
  157. -- Remember where the dictionary pointer will go
  158. dict_p_p <- tellBin bh
  159. -- Placeholder for ptr to dictionary
  160. put_ bh dict_p_p
  161. -- Remember where the symbol table pointer will go
  162. symtab_p_p <- tellBin bh
  163. put_ bh symtab_p_p
  164. -- Make some intial state
  165. symtab_next <- newFastMutInt
  166. writeFastMutInt symtab_next 0
  167. symtab_map <- newIORef emptyUFM
  168. let bin_symtab = BinSymbolTable {
  169. bin_symtab_next = symtab_next,
  170. bin_symtab_map = symtab_map }
  171. dict_next_ref <- newFastMutInt
  172. writeFastMutInt dict_next_ref 0
  173. dict_map_ref <- newIORef emptyUFM
  174. let bin_dict = BinDictionary {
  175. bin_dict_next = dict_next_ref,
  176. bin_dict_map = dict_map_ref }
  177. -- Put the main thing,
  178. bh <- return $ setUserData bh $ newWriteState (putName bin_dict bin_symtab)
  179. (putFastString bin_dict)
  180. put_ bh mod_iface
  181. -- Write the symtab pointer at the fornt of the file
  182. symtab_p <- tellBin bh -- This is where the symtab will start
  183. putAt bh symtab_p_p symtab_p -- Fill in the placeholder
  184. seekBin bh symtab_p -- Seek back to the end of the file
  185. -- Write the symbol table itself
  186. symtab_next <- readFastMutInt symtab_next
  187. symtab_map <- readIORef symtab_map
  188. putSymbolTable bh symtab_next symtab_map
  189. debugTraceMsg dflags 3 (text "writeBinIface:" <+> int symtab_next
  190. <+> text "Names")
  191. -- NB. write the dictionary after the symbol table, because
  192. -- writing the symbol table may create more dictionary entries.
  193. -- Write the dictionary pointer at the fornt of the file
  194. dict_p <- tellBin bh -- This is where the dictionary will start
  195. putAt bh dict_p_p dict_p -- Fill in the placeholder
  196. seekBin bh dict_p -- Seek back to the end of the file
  197. -- Write the dictionary itself
  198. dict_next <- readFastMutInt dict_next_ref
  199. dict_map <- readIORef dict_map_ref
  200. putDictionary bh dict_next dict_map
  201. debugTraceMsg dflags 3 (text "writeBinIface:" <+> int dict_next
  202. <+> text "dict entries")
  203. -- And send the result to the file
  204. writeBinMem bh hi_path
  205. -- | Initial ram buffer to allocate for writing interface files
  206. initBinMemSize :: Int
  207. initBinMemSize = 1024 * 1024
  208. binaryInterfaceMagic :: DynFlags -> Word32
  209. binaryInterfaceMagic dflags
  210. | target32Bit (targetPlatform dflags) = 0x1face
  211. | otherwise = 0x1face64
  212. -- -----------------------------------------------------------------------------
  213. -- The symbol table
  214. --
  215. putSymbolTable :: BinHandle -> Int -> UniqFM (Int,Name) -> IO ()
  216. putSymbolTable bh next_off symtab = do
  217. put_ bh next_off
  218. let names = elems (array (0,next_off-1) (nonDetEltsUFM symtab))
  219. -- It's OK to use nonDetEltsUFM here because the elements have
  220. -- indices that array uses to create order
  221. mapM_ (\n -> serialiseName bh n symtab) names
  222. getSymbolTable :: BinHandle -> NameCacheUpdater -> IO SymbolTable
  223. getSymbolTable bh ncu = do
  224. sz <- get bh
  225. od_names <- sequence (replicate sz (get bh))
  226. updateNameCache ncu $ \namecache ->
  227. let arr = listArray (0,sz-1) names
  228. (namecache', names) =
  229. mapAccumR (fromOnDiskName arr) namecache od_names
  230. in (namecache', arr)
  231. type OnDiskName = (UnitId, ModuleName, OccName)
  232. fromOnDiskName :: Array Int Name -> NameCache -> OnDiskName -> (NameCache, Name)
  233. fromOnDiskName _ nc (pid, mod_name, occ) =
  234. let mod = mkModule pid mod_name
  235. cache = nsNames nc
  236. in case lookupOrigNameCache cache mod occ of
  237. Just name -> (nc, name)
  238. Nothing ->
  239. let (uniq, us) = takeUniqFromSupply (nsUniqs nc)
  240. name = mkExternalName uniq mod occ noSrcSpan
  241. new_cache = extendNameCache cache mod occ name
  242. in ( nc{ nsUniqs = us, nsNames = new_cache }, name )
  243. serialiseName :: BinHandle -> Name -> UniqFM (Int,Name) -> IO ()
  244. serialiseName bh name _ = do
  245. let mod = ASSERT2( isExternalName name, ppr name ) nameModule name
  246. put_ bh (moduleUnitId mod, moduleName mod, nameOccName name)
  247. -- Note [Symbol table representation of names]
  248. -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  249. --
  250. -- An occurrence of a name in an interface file is serialized as a single 32-bit word.
  251. -- The format of this word is:
  252. -- 00xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  253. -- A normal name. x is an index into the symbol table
  254. -- 01xxxxxx xxyyyyyy yyyyyyyy yyyyyyyyyy
  255. -- A known-key name. x is the Unique's Char, y is the int part
  256. -- 100xxyyz zzzzzzzz zzzzzzzz zzzzzzzz
  257. -- A tuple name:
  258. -- x is the tuple sort (00b ==> boxed, 01b ==> unboxed, 10b ==> constraint)
  259. -- y is the thing (00b ==> tycon, 01b ==> datacon, 10b ==> datacon worker)
  260. -- z is the arity
  261. --
  262. -- 10100xxx xxxxxxxx xxxxxxxx xxxxxxxx
  263. -- A sum tycon name:
  264. -- x is the arity
  265. -- 10101xxx xxxxxxxx xxyyyyyy yyyyyyyy
  266. -- A sum datacon name:
  267. -- x is the arity
  268. -- y is the alternative
  269. -- 10110xxx xxxxxxxx xxyyyyyy yyyyyyyy
  270. -- worker
  271. -- 11xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  272. -- An implicit parameter TyCon name. x is an index into the FastString *dictionary*
  273. --
  274. -- Note that we have to have special representation for tuples, sums, and IP
  275. -- TyCons because they form an "infinite" family and hence are not recorded
  276. -- explicitly in wiredInTyThings or basicKnownKeyNames.
  277. knownKeyNamesMap :: UniqFM Name
  278. knownKeyNamesMap = listToUFM_Directly [(nameUnique n, n) | n <- knownKeyNames]
  279. -- See Note [Symbol table representation of names]
  280. putName :: BinDictionary -> BinSymbolTable -> BinHandle -> Name -> IO ()
  281. putName _dict BinSymbolTable{
  282. bin_symtab_map = symtab_map_ref,
  283. bin_symtab_next = symtab_next } bh name
  284. | name `elemUFM` knownKeyNamesMap
  285. , let (c, u) = unpkUnique (nameUnique name) -- INVARIANT: (ord c) fits in 8 bits
  286. = -- ASSERT(u < 2^(22 :: Int))
  287. put_ bh (0x40000000 .|. (fromIntegral (ord c) `shiftL` 22) .|. (fromIntegral u :: Word32))
  288. | otherwise
  289. = case wiredInNameTyThing_maybe name of
  290. Just (ATyCon tc)
  291. | Just sort <- tyConTuple_maybe tc -> putTupleName_ bh tc sort 0
  292. | isUnboxedSumTyCon tc -> putSumTyConName_ bh tc
  293. Just (AConLike (RealDataCon dc))
  294. | let tc = dataConTyCon dc
  295. , Just sort <- tyConTuple_maybe tc -> putTupleName_ bh tc sort 1
  296. | isUnboxedSumCon dc -> putSumDataConName_ bh dc
  297. Just (AnId x)
  298. | Just dc <- isDataConWorkId_maybe x
  299. , let tc = dataConTyCon dc
  300. , Just sort <- tyConTuple_maybe tc -> putTupleName_ bh tc sort 2
  301. Just (AnId x)
  302. | Just dc <- isDataConWorkId_maybe x
  303. , isUnboxedSumCon dc
  304. -> putSumWorkerId_ bh dc
  305. _ -> do
  306. symtab_map <- readIORef symtab_map_ref
  307. case lookupUFM symtab_map name of
  308. Just (off,_) -> put_ bh (fromIntegral off :: Word32)
  309. Nothing -> do
  310. off <- readFastMutInt symtab_next
  311. -- MASSERT(off < 2^(30 :: Int))
  312. writeFastMutInt symtab_next (off+1)
  313. writeIORef symtab_map_ref
  314. $! addToUFM symtab_map name (off,name)
  315. put_ bh (fromIntegral off :: Word32)
  316. putTupleName_ :: BinHandle -> TyCon -> TupleSort -> Word32 -> IO ()
  317. putTupleName_ bh tc tup_sort thing_tag
  318. = ASSERT(arity < 2^(25 :: Int))
  319. put_ bh (0x80000000 .|. (sort_tag `shiftL` 27) .|. (thing_tag `shiftL` 25) .|. arity)
  320. where
  321. (sort_tag, arity) = case tup_sort of
  322. BoxedTuple -> (0, fromIntegral (tyConArity tc))
  323. UnboxedTuple -> (1, fromIntegral (tyConArity tc `div` 2))
  324. -- See Note [Unboxed tuple RuntimeRep vars] in TyCon
  325. ConstraintTuple -> pprPanic "putTupleName:ConstraintTuple" (ppr tc)
  326. putSumTyConName_ :: BinHandle -> TyCon -> IO ()
  327. putSumTyConName_ bh tc
  328. = ASSERT(arity < 2^(27 :: Int))
  329. put_ bh (0xA0000000 .|. arity)
  330. where
  331. arity = (fromIntegral (tyConArity tc) `div` 2) :: Word32
  332. putSumDataConName_ :: BinHandle -> DataCon -> IO ()
  333. putSumDataConName_ bh dc
  334. = ASSERT(arity < 2^(13 :: Int) && alt < 2^(14 :: Int))
  335. put_ bh (0xA8000000 .|. (arity `shiftL` 14) .|. alt)
  336. where
  337. tc = dataConTyCon dc
  338. alt = fromIntegral (dataConTag dc)
  339. arity = (fromIntegral (tyConArity tc) `div` 2) :: Word32
  340. putSumWorkerId_ :: BinHandle -> DataCon -> IO ()
  341. putSumWorkerId_ bh dc
  342. = put_ bh (0xB0000000 .|. (arity `shiftL` 14) .|. alt)
  343. where
  344. tc = dataConTyCon dc
  345. alt = fromIntegral (dataConTag dc)
  346. arity = (fromIntegral (tyConArity tc) `div` 2) :: Word32
  347. -- See Note [Symbol table representation of names]
  348. getSymtabName :: NameCacheUpdater
  349. -> Dictionary -> SymbolTable
  350. -> BinHandle -> IO Name
  351. getSymtabName _ncu _dict symtab bh = do
  352. i :: Word32 <- get bh
  353. case i .&. 0xC0000000 of
  354. 0x00000000 -> return $! symtab ! fromIntegral i
  355. 0x40000000 ->
  356. let
  357. tag = chr (fromIntegral ((i .&. 0x3FC00000) `shiftR` 22))
  358. ix = fromIntegral i .&. 0x003FFFFF
  359. in
  360. return $! case lookupUFM_Directly knownKeyNamesMap (mkUnique tag ix) of
  361. Nothing -> pprPanic "getSymtabName:unknown known-key unique" (ppr i)
  362. Just n -> n
  363. 0x80000000 ->
  364. case i .&. 0x20000000 of
  365. 0x00000000 ->
  366. let
  367. dc = tupleDataCon sort arity
  368. sort = case (i .&. 0x18000000) `shiftR` 27 of
  369. 0 -> Boxed
  370. 1 -> Unboxed
  371. _ -> pprPanic "getSymtabName:unknown tuple sort" (ppr i)
  372. arity = fromIntegral (i .&. 0x01FFFFFF)
  373. in
  374. return $! case ( (i .&. 0x06FFFFFF) `shiftR` 25 ) of
  375. 0 -> tyConName (tupleTyCon sort arity)
  376. 1 -> dataConName dc
  377. 2 -> idName (dataConWorkId dc)
  378. _ -> pprPanic "getSymtabName:unknown tuple thing" (ppr i)
  379. 0x20000000 ->
  380. return $! case ((i .&. 0x18000000) `shiftR` 27) of
  381. 0 -> tyConName $ sumTyCon ( fromIntegral (i .&. 0x7ffffff) )
  382. 1 -> let
  383. alt =
  384. -- first (least significant) 14 bits
  385. fromIntegral (i .&. 0b11111111111111)
  386. arity =
  387. -- next 13 bits
  388. fromIntegral ((i `shiftR` 14) .&. 0b1111111111111)
  389. in
  390. ASSERT( arity >= alt )
  391. dataConName (sumDataCon alt arity)
  392. 2 -> let
  393. alt =
  394. -- first (least significant) 14 bits
  395. fromIntegral (i .&. 0b11111111111111)
  396. arity =
  397. -- next 13 bits
  398. fromIntegral ((i `shiftR` 14) .&. 0b1111111111111)
  399. in
  400. ASSERT( arity >= alt )
  401. idName (dataConWorkId (sumDataCon alt arity))
  402. _ -> pprPanic "getSymtabName:unknown sum sort" (ppr i)
  403. _ -> pprPanic "getSyntabName:unknown `tuple or sum` tag" (ppr i)
  404. _ -> pprPanic "getSymtabName:unknown name tag" (ppr i)
  405. data BinSymbolTable = BinSymbolTable {
  406. bin_symtab_next :: !FastMutInt, -- The next index to use
  407. bin_symtab_map :: !(IORef (UniqFM (Int,Name)))
  408. -- indexed by Name
  409. }
  410. putFastString :: BinDictionary -> BinHandle -> FastString -> IO ()
  411. putFastString dict bh fs = allocateFastString dict fs >>= put_ bh
  412. allocateFastString :: BinDictionary -> FastString -> IO Word32
  413. allocateFastString BinDictionary { bin_dict_next = j_r,
  414. bin_dict_map = out_r} f = do
  415. out <- readIORef out_r
  416. let uniq = getUnique f
  417. case lookupUFM out uniq of
  418. Just (j, _) -> return (fromIntegral j :: Word32)
  419. Nothing -> do
  420. j <- readFastMutInt j_r
  421. writeFastMutInt j_r (j + 1)
  422. writeIORef out_r $! addToUFM out uniq (j, f)
  423. return (fromIntegral j :: Word32)
  424. getDictFastString :: Dictionary -> BinHandle -> IO FastString
  425. getDictFastString dict bh = do
  426. j <- get bh
  427. return $! (dict ! fromIntegral (j :: Word32))
  428. data BinDictionary = BinDictionary {
  429. bin_dict_next :: !FastMutInt, -- The next index to use
  430. bin_dict_map :: !(IORef (UniqFM (Int,FastString)))
  431. -- indexed by FastString
  432. }
  433. getWayDescr :: DynFlags -> String
  434. getWayDescr dflags
  435. | platformUnregisterised (targetPlatform dflags) = 'u':tag
  436. | otherwise = tag
  437. where tag = buildTag dflags
  438. -- if this is an unregisterised build, make sure our interfaces
  439. -- can't be used by a registerised build.