Skip to content

Commit 7083e2e

Browse files
committed
hie-compat: Reexport the original version of HieBin
1 parent 5149eef commit 7083e2e

File tree

1 file changed

+2
-365
lines changed

1 file changed

+2
-365
lines changed
+2-365
Original file line numberDiff line numberDiff line change
@@ -1,371 +1,8 @@
11
{-
22
Binary serialization for .hie files.
33
-}
4-
{- HLINT ignore -}
5-
{-# LANGUAGE ScopedTypeVariables #-}
6-
{-# LANGUAGE BangPatterns #-}
74

8-
module Compat.HieBin
9-
( readHieFile
10-
, readHieFileWithVersion
11-
, HieHeader
12-
, writeHieFile
13-
, HieName(..)
14-
, toHieName
15-
, HieFileResult(..)
16-
, hieMagic
17-
, hieNameOcc
18-
, NameCacheUpdater(..)
19-
)
5+
module Compat.HieBin ( module GHC.Iface.Ext.Binary)
206
where
217

22-
import GHC.Settings.Utils ( maybeRead )
23-
import GHC.Settings.Config ( cProjectVersion )
24-
-- import GHC.Prelude
25-
import GHC.Utils.Binary
26-
import GHC.Iface.Binary ( getDictFastString )
27-
import GHC.Data.FastMutInt
28-
import GHC.Data.FastString ( FastString )
29-
import GHC.Types.Name
30-
import GHC.Types.Name.Cache
31-
import GHC.Utils.Outputable
32-
import GHC.Builtin.Utils
33-
import GHC.Types.SrcLoc as SrcLoc
34-
import GHC.Types.Unique.Supply ( takeUniqFromSupply )
35-
import GHC.Types.Unique
36-
import GHC.Types.Unique.FM
37-
import GHC.Iface.Env (NameCacheUpdater(..))
38-
-- import IfaceEnv
39-
40-
import qualified Data.Array as A
41-
import Data.IORef
42-
import Data.ByteString ( ByteString )
43-
import qualified Data.ByteString as BS
44-
import qualified Data.ByteString.Char8 as BSC
45-
import Data.List ( mapAccumR )
46-
import Data.Word ( Word8, Word32 )
47-
import Control.Monad ( replicateM, when )
48-
import System.Directory ( createDirectoryIfMissing )
49-
import System.FilePath ( takeDirectory )
50-
51-
import GHC.Iface.Ext.Types
52-
53-
data HieSymbolTable = HieSymbolTable
54-
{ hie_symtab_next :: !FastMutInt
55-
, hie_symtab_map :: !(IORef (UniqFM Name (Int, HieName)))
56-
}
57-
58-
data HieDictionary = HieDictionary
59-
{ hie_dict_next :: !FastMutInt -- The next index to use
60-
, hie_dict_map :: !(IORef (UniqFM FastString (Int,FastString))) -- indexed by FastString
61-
}
62-
63-
initBinMemSize :: Int
64-
initBinMemSize = 1024*1024
65-
66-
-- | The header for HIE files - Capital ASCII letters \"HIE\".
67-
hieMagic :: [Word8]
68-
hieMagic = [72,73,69]
69-
70-
hieMagicLen :: Int
71-
hieMagicLen = length hieMagic
72-
73-
ghcVersion :: ByteString
74-
ghcVersion = BSC.pack cProjectVersion
75-
76-
putBinLine :: BinHandle -> ByteString -> IO ()
77-
putBinLine bh xs = do
78-
mapM_ (putByte bh) $ BS.unpack xs
79-
putByte bh 10 -- newline char
80-
81-
-- | Write a `HieFile` to the given `FilePath`, with a proper header and
82-
-- symbol tables for `Name`s and `FastString`s
83-
writeHieFile :: FilePath -> HieFile -> IO ()
84-
writeHieFile hie_file_path hiefile = do
85-
bh0 <- openBinMem initBinMemSize
86-
87-
-- Write the header: hieHeader followed by the
88-
-- hieVersion and the GHC version used to generate this file
89-
mapM_ (putByte bh0) hieMagic
90-
putBinLine bh0 $ BSC.pack $ show hieVersion
91-
putBinLine bh0 $ ghcVersion
92-
93-
-- remember where the dictionary pointer will go
94-
dict_p_p <- tellBin bh0
95-
put_ bh0 dict_p_p
96-
97-
-- remember where the symbol table pointer will go
98-
symtab_p_p <- tellBin bh0
99-
put_ bh0 symtab_p_p
100-
101-
-- Make some initial state
102-
symtab_next <- newFastMutInt
103-
writeFastMutInt symtab_next 0
104-
symtab_map <- newIORef emptyUFM :: IO (IORef (UniqFM Name (Int, HieName)))
105-
let hie_symtab = HieSymbolTable {
106-
hie_symtab_next = symtab_next,
107-
hie_symtab_map = symtab_map }
108-
dict_next_ref <- newFastMutInt
109-
writeFastMutInt dict_next_ref 0
110-
dict_map_ref <- newIORef emptyUFM
111-
let hie_dict = HieDictionary {
112-
hie_dict_next = dict_next_ref,
113-
hie_dict_map = dict_map_ref }
114-
115-
-- put the main thing
116-
let bh = setUserData bh0 $ newWriteState (putName hie_symtab)
117-
(putName hie_symtab)
118-
(putFastString hie_dict)
119-
put_ bh hiefile
120-
121-
-- write the symtab pointer at the front of the file
122-
symtab_p <- tellBin bh
123-
putAt bh symtab_p_p symtab_p
124-
seekBin bh symtab_p
125-
126-
-- write the symbol table itself
127-
symtab_next' <- readFastMutInt symtab_next
128-
symtab_map' <- readIORef symtab_map
129-
putSymbolTable bh symtab_next' symtab_map'
130-
131-
-- write the dictionary pointer at the front of the file
132-
dict_p <- tellBin bh
133-
putAt bh dict_p_p dict_p
134-
seekBin bh dict_p
135-
136-
-- write the dictionary itself
137-
dict_next <- readFastMutInt dict_next_ref
138-
dict_map <- readIORef dict_map_ref
139-
putDictionary bh dict_next dict_map
140-
141-
-- and send the result to the file
142-
createDirectoryIfMissing True (takeDirectory hie_file_path)
143-
writeBinMem bh hie_file_path
144-
return ()
145-
146-
data HieFileResult
147-
= HieFileResult
148-
{ hie_file_result_version :: Integer
149-
, hie_file_result_ghc_version :: ByteString
150-
, hie_file_result :: HieFile
151-
}
152-
153-
type HieHeader = (Integer, ByteString)
154-
155-
-- | Read a `HieFile` from a `FilePath`. Can use
156-
-- an existing `NameCache`. Allows you to specify
157-
-- which versions of hieFile to attempt to read.
158-
-- `Left` case returns the failing header versions.
159-
readHieFileWithVersion :: (HieHeader -> Bool) -> NameCacheUpdater -> FilePath -> IO (Either HieHeader HieFileResult)
160-
readHieFileWithVersion readVersion ncu file = do
161-
bh0 <- readBinMem file
162-
163-
(hieVersion, ghcVersion) <- readHieFileHeader file bh0
164-
165-
if readVersion (hieVersion, ghcVersion)
166-
then do
167-
hieFile <- readHieFileContents bh0 ncu
168-
return $ Right (HieFileResult hieVersion ghcVersion hieFile)
169-
else return $ Left (hieVersion, ghcVersion)
170-
171-
172-
-- | Read a `HieFile` from a `FilePath`. Can use
173-
-- an existing `NameCache`.
174-
readHieFile :: NameCacheUpdater -> FilePath -> IO HieFileResult
175-
readHieFile ncu file = do
176-
177-
bh0 <- readBinMem file
178-
179-
(readHieVersion, ghcVersion) <- readHieFileHeader file bh0
180-
181-
-- Check if the versions match
182-
when (readHieVersion /= hieVersion) $
183-
panic $ unwords ["readHieFile: hie file versions don't match for file:"
184-
, file
185-
, "Expected"
186-
, show hieVersion
187-
, "but got", show readHieVersion
188-
]
189-
hieFile <- readHieFileContents bh0 ncu
190-
return $ HieFileResult hieVersion ghcVersion hieFile
191-
192-
readBinLine :: BinHandle -> IO ByteString
193-
readBinLine bh = BS.pack . reverse <$> loop []
194-
where
195-
loop acc = do
196-
char <- get bh :: IO Word8
197-
if char == 10 -- ASCII newline '\n'
198-
then return acc
199-
else loop (char : acc)
200-
201-
readHieFileHeader :: FilePath -> BinHandle -> IO HieHeader
202-
readHieFileHeader file bh0 = do
203-
-- Read the header
204-
magic <- replicateM hieMagicLen (get bh0)
205-
version <- BSC.unpack <$> readBinLine bh0
206-
case maybeRead version of
207-
Nothing ->
208-
panic $ unwords ["readHieFileHeader: hieVersion isn't an Integer:"
209-
, show version
210-
]
211-
Just readHieVersion -> do
212-
ghcVersion <- readBinLine bh0
213-
214-
-- Check if the header is valid
215-
when (magic /= hieMagic) $
216-
panic $ unwords ["readHieFileHeader: headers don't match for file:"
217-
, file
218-
, "Expected"
219-
, show hieMagic
220-
, "but got", show magic
221-
]
222-
return (readHieVersion, ghcVersion)
223-
224-
readHieFileContents :: BinHandle -> NameCacheUpdater -> IO HieFile
225-
readHieFileContents bh0 ncu = do
226-
227-
dict <- get_dictionary bh0
228-
229-
-- read the symbol table so we are capable of reading the actual data
230-
bh1 <- do
231-
let bh1 = setUserData bh0 $ newReadState (error "getSymtabName")
232-
(getDictFastString dict)
233-
symtab <- get_symbol_table bh1
234-
let bh1' = setUserData bh1
235-
$ newReadState (getSymTabName symtab)
236-
(getDictFastString dict)
237-
return bh1'
238-
239-
-- load the actual data
240-
hiefile <- get bh1
241-
return hiefile
242-
where
243-
get_dictionary bin_handle = do
244-
dict_p <- get bin_handle
245-
data_p <- tellBin bin_handle
246-
seekBin bin_handle dict_p
247-
dict <- getDictionary bin_handle
248-
seekBin bin_handle data_p
249-
return dict
250-
251-
get_symbol_table bh1 = do
252-
symtab_p <- get bh1
253-
data_p' <- tellBin bh1
254-
seekBin bh1 symtab_p
255-
symtab <- getSymbolTable bh1 ncu
256-
seekBin bh1 data_p'
257-
return symtab
258-
259-
putFastString :: HieDictionary -> BinHandle -> FastString -> IO ()
260-
putFastString HieDictionary { hie_dict_next = j_r,
261-
hie_dict_map = out_r} bh f
262-
= do
263-
out <- readIORef out_r
264-
let !unique = getUnique f
265-
case lookupUFM_Directly out unique of
266-
Just (j, _) -> put_ bh (fromIntegral j :: Word32)
267-
Nothing -> do
268-
j <- readFastMutInt j_r
269-
put_ bh (fromIntegral j :: Word32)
270-
writeFastMutInt j_r (j + 1)
271-
writeIORef out_r $! addToUFM_Directly out unique (j, f)
272-
273-
putSymbolTable :: BinHandle -> Int -> UniqFM Name (Int,HieName) -> IO ()
274-
putSymbolTable bh next_off symtab = do
275-
put_ bh next_off
276-
let names = A.elems (A.array (0,next_off-1) (nonDetEltsUFM symtab))
277-
mapM_ (putHieName bh) names
278-
279-
getSymbolTable :: BinHandle -> NameCacheUpdater -> IO SymbolTable
280-
getSymbolTable bh ncu = do
281-
sz <- get bh
282-
od_names <- replicateM sz (getHieName bh)
283-
updateNameCache ncu $ \nc ->
284-
let arr = A.listArray (0,sz-1) names
285-
(nc', names) = mapAccumR fromHieName nc od_names
286-
in (nc',arr)
287-
288-
getSymTabName :: SymbolTable -> BinHandle -> IO Name
289-
getSymTabName st bh = do
290-
i :: Word32 <- get bh
291-
return $ st A.! (fromIntegral i)
292-
293-
putName :: HieSymbolTable -> BinHandle -> Name -> IO ()
294-
putName (HieSymbolTable next ref) bh name = do
295-
symmap <- readIORef ref
296-
case lookupUFM symmap name of
297-
Just (off, ExternalName mod occ (UnhelpfulSpan _))
298-
| isGoodSrcSpan (nameSrcSpan name) -> do
299-
let hieName = ExternalName mod occ (nameSrcSpan name)
300-
writeIORef ref $! addToUFM symmap name (off, hieName)
301-
put_ bh (fromIntegral off :: Word32)
302-
Just (off, LocalName _occ span)
303-
| notLocal (toHieName name) || nameSrcSpan name /= span -> do
304-
writeIORef ref $! addToUFM symmap name (off, toHieName name)
305-
put_ bh (fromIntegral off :: Word32)
306-
Just (off, _) -> put_ bh (fromIntegral off :: Word32)
307-
Nothing -> do
308-
off <- readFastMutInt next
309-
writeFastMutInt next (off+1)
310-
writeIORef ref $! addToUFM symmap name (off, toHieName name)
311-
put_ bh (fromIntegral off :: Word32)
312-
313-
where
314-
notLocal :: HieName -> Bool
315-
notLocal LocalName{} = False
316-
notLocal _ = True
317-
318-
319-
-- ** Converting to and from `HieName`'s
320-
321-
fromHieName :: NameCache -> HieName -> (NameCache, Name)
322-
fromHieName nc (ExternalName mod occ span) =
323-
let cache = nsNames nc
324-
in case lookupOrigNameCache cache mod occ of
325-
Just name
326-
| nameSrcSpan name == span -> (nc, name)
327-
| otherwise ->
328-
let name' = setNameLoc name span
329-
new_cache = extendNameCache cache mod occ name'
330-
in ( nc{ nsNames = new_cache }, name' )
331-
Nothing ->
332-
let (uniq, us) = takeUniqFromSupply (nsUniqs nc)
333-
name = mkExternalName uniq mod occ span
334-
new_cache = extendNameCache cache mod occ name
335-
in ( nc{ nsUniqs = us, nsNames = new_cache }, name )
336-
fromHieName nc (LocalName occ span) =
337-
let (uniq, us) = takeUniqFromSupply (nsUniqs nc)
338-
name = mkInternalName uniq occ span
339-
in ( nc{ nsUniqs = us }, name )
340-
fromHieName nc (KnownKeyName u) = case lookupKnownKeyName u of
341-
Nothing -> pprPanic "fromHieName:unknown known-key unique"
342-
(ppr (unpkUnique u))
343-
Just n -> (nc, n)
344-
345-
-- ** Reading and writing `HieName`'s
346-
347-
putHieName :: BinHandle -> HieName -> IO ()
348-
putHieName bh (ExternalName mod occ span) = do
349-
putByte bh 0
350-
put_ bh (mod, occ, span)
351-
putHieName bh (LocalName occName span) = do
352-
putByte bh 1
353-
put_ bh (occName, span)
354-
putHieName bh (KnownKeyName uniq) = do
355-
putByte bh 2
356-
put_ bh $ unpkUnique uniq
357-
358-
getHieName :: BinHandle -> IO HieName
359-
getHieName bh = do
360-
t <- getByte bh
361-
case t of
362-
0 -> do
363-
(modu, occ, span) <- get bh
364-
return $ ExternalName modu occ span
365-
1 -> do
366-
(occ, span) <- get bh
367-
return $ LocalName occ span
368-
2 -> do
369-
(c,i) <- get bh
370-
return $ KnownKeyName $ mkUnique c i
371-
_ -> panic "GHC.Iface.Ext.Binary.getHieName: invalid tag"
8+
import GHC.Iface.Ext.Binary

0 commit comments

Comments
 (0)