[project @ 2002-09-13 15:02:25 by simonpj]
[ghc-hetmet.git] / ghc / compiler / utils / Binary.hs
1 {-# OPTIONS -cpp #-}
2 --
3 -- (c) The University of Glasgow 2002
4 --
5 -- Binary I/O library, with special tweaks for GHC
6 --
7 -- Based on the nhc98 Binary library, which is copyright
8 -- (c) Malcolm Wallace and Colin Runciman, University of York, 1998.
9 -- Under the terms of the license for that software, we must tell you
10 -- where you can obtain the original version of the Binary library, namely
11 --     http://www.cs.york.ac.uk/fp/nhc98/
12
13 module Binary
14   ( {-type-}  Bin,
15     {-class-} Binary(..),
16     {-type-}  BinHandle,
17
18    openBinIO, openBinIO_,
19    openBinMem,
20 --   closeBin,
21
22    getUserData,
23
24    seekBin,
25    tellBin,
26    castBin,
27
28    writeBinMem,
29    readBinMem,
30
31    isEOFBin,
32
33    -- for writing instances:
34    putByte,
35    getByte,
36
37    -- lazy Bin I/O
38    lazyGet,
39    lazyPut,
40
41    -- GHC only:
42    ByteArray(..),
43    getByteArray,
44    putByteArray,
45
46    getBinFileWithDict,  -- :: Binary a => FilePath -> IO a
47    putBinFileWithDict,  -- :: Binary a => FilePath -> Module -> a -> IO ()
48
49   ) where
50
51 #include "HsVersions.h"
52 #include "MachDeps.h"
53
54 import {-# SOURCE #-} Module
55 import FastString
56 import Unique
57 import Panic
58 import UniqFM
59 import FastMutInt
60
61 #if __GLASGOW_HASKELL__ < 503
62 import DATA_IOREF
63 import DATA_BITS
64 import DATA_INT
65 import DATA_WORD
66 import Char
67 import Monad
68 import Exception
69 import GlaExts hiding (ByteArray, newByteArray, freezeByteArray)
70 import Array
71 import IO
72 import PrelIOBase               ( IOError(..), IOErrorType(..)
73 #if __GLASGOW_HASKELL__ > 411
74                                 , IOException(..)
75 #endif
76                                 )
77 import PrelReal                 ( Ratio(..) )
78 import PrelIOBase               ( IO(..) )
79 #else
80 import Data.Array.IO
81 import Data.Array
82 import Data.Bits
83 import Data.Int
84 import Data.Word
85 import Data.IORef
86 import Data.Char                ( ord, chr )
87 import Data.Array.Base          ( unsafeRead, unsafeWrite )
88 import Control.Monad            ( when )
89 import Control.Exception        ( throw, throwDyn )
90 import System.IO as IO
91 import System.IO.Unsafe         ( unsafeInterleaveIO )
92 import System.IO.Error          ( mkIOError, eofErrorType )
93 import GHC.Real                 ( Ratio(..) )
94 import GHC.Exts
95 import GHC.IOBase               ( IO(..) )
96 import GHC.Word                 ( Word8(..) )
97 import GHC.Handle               ( openFileEx, IOModeEx(..) )
98 #endif
99
100 #if __GLASGOW_HASKELL__ < 503
101 type BinArray = MutableByteArray RealWorld Int
102 newArray_ bounds     = stToIO (newCharArray bounds)
103 unsafeWrite arr ix e = stToIO (writeWord8Array arr ix e)
104 unsafeRead  arr ix   = stToIO (readWord8Array arr ix)
105 #if __GLASGOW_HASKELL__ < 411
106 newByteArray#        = newCharArray#
107 #endif
108 hPutArray h arr sz   = hPutBufBAFull h arr sz
109 hGetArray h sz       = hGetBufBAFull h sz
110
111 mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> Exception
112 mkIOError t location maybe_hdl maybe_filename
113   = IOException (IOError maybe_hdl t location ""
114 #if __GLASGOW_HASKELL__ > 411
115                          maybe_filename
116 #endif
117                 )
118
119 eofErrorType = EOF
120
121 #ifndef SIZEOF_HSINT
122 #define SIZEOF_HSINT  INT_SIZE_IN_BYTES
123 #endif
124
125 #ifndef SIZEOF_HSWORD
126 #define SIZEOF_HSWORD WORD_SIZE_IN_BYTES
127 #endif
128
129 #else
130 type BinArray = IOUArray Int Word8
131 #endif
132
133 data BinHandle
134   = BinMem {            -- binary data stored in an unboxed array
135      state :: BinHandleState,   -- sigh, need parameterized modules :-)
136      off_r :: !FastMutInt,              -- the current offset
137      sz_r  :: !FastMutInt,              -- size of the array (cached)
138      arr_r :: !(IORef BinArray)         -- the array (bounds: (0,size-1))
139     }
140         -- XXX: should really store a "high water mark" for dumping out
141         -- the binary data to a file.
142
143   | BinIO {             -- binary data stored in a file
144      state :: BinHandleState,
145      off_r :: !FastMutInt,              -- the current offset (cached)
146      hdl   :: !IO.Handle                -- the file handle (must be seekable)
147    }
148         -- cache the file ptr in BinIO; using hTell is too expensive
149         -- to call repeatedly.  If anyone else is modifying this Handle
150         -- at the same time, we'll be screwed.
151
152 newtype Bin a = BinPtr Int 
153   deriving (Eq, Ord, Show, Bounded)
154
155 castBin :: Bin a -> Bin b
156 castBin (BinPtr i) = BinPtr i
157
158 class Binary a where
159     put_   :: BinHandle -> a -> IO ()
160     put    :: BinHandle -> a -> IO (Bin a)
161     get    :: BinHandle -> IO a
162
163     -- define one of put_, put.  Use of put_ is recommended because it
164     -- is more likely that tail-calls can kick in, and we rarely need the
165     -- position return value.
166     put_ bh a = do put bh a; return ()
167     put bh a  = do p <- tellBin bh; put_ bh a; return p
168
169 putAt  :: Binary a => BinHandle -> Bin a -> a -> IO ()
170 putAt bh p x = do seekBin bh p; put bh x; return ()
171
172 getAt  :: Binary a => BinHandle -> Bin a -> IO a
173 getAt bh p = do seekBin bh p; get bh
174
175 openBinIO_ :: IO.Handle -> IO BinHandle
176 openBinIO_ h = openBinIO h noBinHandleUserData
177
178 openBinIO :: IO.Handle -> Module -> IO BinHandle
179 openBinIO h mod = do
180   r <- newFastMutInt
181   writeFastMutInt r 0
182   state <- newWriteState mod
183   return (BinIO state r h)
184
185 openBinMem :: Int -> Module -> IO BinHandle
186 openBinMem size mod
187  | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
188  | otherwise = do
189    arr <- newArray_ (0,size-1)
190    arr_r <- newIORef arr
191    ix_r <- newFastMutInt
192    writeFastMutInt ix_r 0
193    sz_r <- newFastMutInt
194    writeFastMutInt sz_r size
195    state <- newWriteState mod
196    return (BinMem state ix_r sz_r arr_r)
197
198 noBinHandleUserData = error "Binary.BinHandle: no user data"
199
200 getUserData :: BinHandle -> BinHandleState
201 getUserData bh = state bh
202
203 tellBin :: BinHandle -> IO (Bin a)
204 tellBin (BinIO  _ r _)   = do ix <- readFastMutInt r; return (BinPtr ix)
205 tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
206
207 seekBin :: BinHandle -> Bin a -> IO ()
208 seekBin (BinIO _ ix_r h) (BinPtr p) = do 
209   writeFastMutInt ix_r p
210   hSeek h AbsoluteSeek (fromIntegral p)
211 seekBin h@(BinMem _ ix_r sz_r a) (BinPtr p) = do
212   sz <- readFastMutInt sz_r
213   if (p >= sz)
214         then do expandBin h p; writeFastMutInt ix_r p
215         else writeFastMutInt ix_r p
216
217 isEOFBin :: BinHandle -> IO Bool
218 isEOFBin (BinMem _ ix_r sz_r a) = do
219   ix <- readFastMutInt ix_r
220   sz <- readFastMutInt sz_r
221   return (ix >= sz)
222 isEOFBin (BinIO _ ix_r h) = hIsEOF h
223
224 writeBinMem :: BinHandle -> FilePath -> IO ()
225 writeBinMem (BinIO _ _ _) _ = error "Data.Binary.writeBinMem: not a memory handle"
226 writeBinMem (BinMem _ ix_r sz_r arr_r) fn = do
227   h <- openFileEx fn (BinaryMode WriteMode)
228   arr <- readIORef arr_r
229   ix  <- readFastMutInt ix_r
230   hPutArray h arr ix
231 #if __GLASGOW_HASKELL__ <= 500
232   -- workaround a bug in old implementation of hPutBuf (it doesn't
233   -- set the FILEOBJ_RW_WRITTEN flag on the file object, so the file doens't
234   -- get flushed properly).  Adding an extra '\0' doens't do any harm.
235   hPutChar h '\0'
236 #endif
237   hClose h
238
239 readBinMem :: FilePath -> IO BinHandle
240 readBinMem filename = do
241   h <- openFileEx filename (BinaryMode ReadMode)
242   filesize' <- hFileSize h
243   let filesize = fromIntegral filesize'
244   arr <- newArray_ (0,filesize-1)
245   count <- hGetArray h arr filesize
246   when (count /= filesize)
247         (error ("Binary.readBinMem: only read " ++ show count ++ " bytes"))
248   hClose h
249   arr_r <- newIORef arr
250   ix_r <- newFastMutInt
251   writeFastMutInt ix_r 0
252   sz_r <- newFastMutInt
253   writeFastMutInt sz_r filesize
254   return (BinMem initReadState ix_r sz_r arr_r)
255
256 -- expand the size of the array to include a specified offset
257 expandBin :: BinHandle -> Int -> IO ()
258 expandBin (BinMem _ ix_r sz_r arr_r) off = do
259    sz <- readFastMutInt sz_r
260    let sz' = head (dropWhile (<= off) (iterate (* 2) sz))
261    arr <- readIORef arr_r
262    arr' <- newArray_ (0,sz'-1)
263    sequence_ [ unsafeRead arr i >>= unsafeWrite arr' i
264              | i <- [ 0 .. sz-1 ] ]
265    writeFastMutInt sz_r sz'
266    writeIORef arr_r arr'
267 #ifdef DEBUG
268    hPutStrLn stderr ("Binary: expanding to size: " ++ show sz')
269 #endif
270    return ()
271 expandBin (BinIO _ _ _) _ = return ()
272         -- no need to expand a file, we'll assume they expand by themselves.
273
274 -- -----------------------------------------------------------------------------
275 -- Low-level reading/writing of bytes
276
277 putWord8 :: BinHandle -> Word8 -> IO ()
278 putWord8 h@(BinMem _ ix_r sz_r arr_r) w = do
279     ix <- readFastMutInt ix_r
280     sz <- readFastMutInt sz_r
281         -- double the size of the array if it overflows
282     if (ix >= sz) 
283         then do expandBin h ix
284                 putWord8 h w
285         else do arr <- readIORef arr_r
286                 unsafeWrite arr ix w
287                 writeFastMutInt ix_r (ix+1)
288                 return ()
289 putWord8 (BinIO _ ix_r h) w = do
290     ix <- readFastMutInt ix_r
291     hPutChar h (chr (fromIntegral w))   -- XXX not really correct
292     writeFastMutInt ix_r (ix+1)
293     return ()
294
295 getWord8 :: BinHandle -> IO Word8
296 getWord8 (BinMem _ ix_r sz_r arr_r) = do
297     ix <- readFastMutInt ix_r
298     sz <- readFastMutInt sz_r
299     when (ix >= sz)  $
300         throw (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
301     arr <- readIORef arr_r
302     w <- unsafeRead arr ix
303     writeFastMutInt ix_r (ix+1)
304     return w
305 getWord8 (BinIO _ ix_r h) = do
306     ix <- readFastMutInt ix_r
307     c <- hGetChar h
308     writeFastMutInt ix_r (ix+1)
309     return $! (fromIntegral (ord c))    -- XXX not really correct
310
311 putByte :: BinHandle -> Word8 -> IO ()
312 putByte bh w = put_ bh w
313
314 getByte :: BinHandle -> IO Word8
315 getByte = getWord8
316
317 -- -----------------------------------------------------------------------------
318 -- Primitve Word writes
319
320 instance Binary Word8 where
321   put_ = putWord8
322   get  = getWord8
323
324 instance Binary Word16 where
325   put_ h w = do -- XXX too slow.. inline putWord8?
326     putByte h (fromIntegral (w `shiftR` 8))
327     putByte h (fromIntegral (w .&. 0xff))
328   get h = do
329     w1 <- getWord8 h
330     w2 <- getWord8 h
331     return $! ((fromIntegral w1 `shiftL` 8) .|. fromIntegral w2)
332
333
334 instance Binary Word32 where
335   put_ h w = do
336     putByte h (fromIntegral (w `shiftR` 24))
337     putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
338     putByte h (fromIntegral ((w `shiftR` 8)  .&. 0xff))
339     putByte h (fromIntegral (w .&. 0xff))
340   get h = do
341     w1 <- getWord8 h
342     w2 <- getWord8 h
343     w3 <- getWord8 h
344     w4 <- getWord8 h
345     return $! ((fromIntegral w1 `shiftL` 24) .|. 
346                (fromIntegral w2 `shiftL` 16) .|. 
347                (fromIntegral w3 `shiftL`  8) .|. 
348                (fromIntegral w4))
349
350
351 instance Binary Word64 where
352   put_ h w = do
353     putByte h (fromIntegral (w `shiftR` 56))
354     putByte h (fromIntegral ((w `shiftR` 48) .&. 0xff))
355     putByte h (fromIntegral ((w `shiftR` 40) .&. 0xff))
356     putByte h (fromIntegral ((w `shiftR` 32) .&. 0xff))
357     putByte h (fromIntegral ((w `shiftR` 24) .&. 0xff))
358     putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
359     putByte h (fromIntegral ((w `shiftR`  8) .&. 0xff))
360     putByte h (fromIntegral (w .&. 0xff))
361   get h = do
362     w1 <- getWord8 h
363     w2 <- getWord8 h
364     w3 <- getWord8 h
365     w4 <- getWord8 h
366     w5 <- getWord8 h
367     w6 <- getWord8 h
368     w7 <- getWord8 h
369     w8 <- getWord8 h
370     return $! ((fromIntegral w1 `shiftL` 56) .|. 
371                (fromIntegral w2 `shiftL` 48) .|. 
372                (fromIntegral w3 `shiftL` 40) .|. 
373                (fromIntegral w4 `shiftL` 32) .|. 
374                (fromIntegral w5 `shiftL` 24) .|. 
375                (fromIntegral w6 `shiftL` 16) .|. 
376                (fromIntegral w7 `shiftL`  8) .|. 
377                (fromIntegral w8))
378
379 -- -----------------------------------------------------------------------------
380 -- Primitve Int writes
381
382 instance Binary Int8 where
383   put_ h w = put_ h (fromIntegral w :: Word8)
384   get h    = do w <- get h; return $! (fromIntegral (w::Word8))
385
386 instance Binary Int16 where
387   put_ h w = put_ h (fromIntegral w :: Word16)
388   get h    = do w <- get h; return $! (fromIntegral (w::Word16))
389
390 instance Binary Int32 where
391   put_ h w = put_ h (fromIntegral w :: Word32)
392   get h    = do w <- get h; return $! (fromIntegral (w::Word32))
393
394 instance Binary Int64 where
395   put_ h w = put_ h (fromIntegral w :: Word64)
396   get h    = do w <- get h; return $! (fromIntegral (w::Word64))
397
398 -- -----------------------------------------------------------------------------
399 -- Instances for standard types
400
401 instance Binary () where
402     put_ bh () = return ()
403     get  _     = return ()
404 --    getF bh p  = case getBitsF bh 0 p of (_,b) -> ((),b)
405
406 instance Binary Bool where
407     put_ bh b = putByte bh (fromIntegral (fromEnum b))
408     get  bh   = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))
409 --    getF bh p = case getBitsF bh 1 p of (x,b) -> (toEnum x,b)
410
411 instance Binary Char where
412     put_  bh c = put_ bh (fromIntegral (ord c) :: Word32)
413     get  bh   = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))
414 --    getF bh p = case getBitsF bh 8 p of (x,b) -> (toEnum x,b)
415
416 instance Binary Int where
417 #if SIZEOF_HSINT == 4
418     put_ bh i = put_ bh (fromIntegral i :: Int32)
419     get  bh = do
420         x <- get bh
421         return $! (fromIntegral (x :: Int32))
422 #elif SIZEOF_HSINT == 8
423     put_ bh i = put_ bh (fromIntegral i :: Int64)
424     get  bh = do
425         x <- get bh
426         return $! (fromIntegral (x :: Int64))
427 #else
428 #error "unsupported sizeof(HsInt)"
429 #endif
430 --    getF bh   = getBitsF bh 32
431
432 instance Binary a => Binary [a] where
433     put_ bh []     = putByte bh 0
434     put_ bh (x:xs) = do putByte bh 1; put_ bh x; put_ bh xs
435     get bh         = do h <- getWord8 bh
436                         case h of
437                           0 -> return []
438                           _ -> do x  <- get bh
439                                   xs <- get bh
440                                   return (x:xs)
441
442 instance (Binary a, Binary b) => Binary (a,b) where
443     put_ bh (a,b) = do put_ bh a; put_ bh b
444     get bh        = do a <- get bh
445                        b <- get bh
446                        return (a,b)
447
448 instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where
449     put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c
450     get bh          = do a <- get bh
451                          b <- get bh
452                          c <- get bh
453                          return (a,b,c)
454
455 instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where
456     put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d
457     get bh          = do a <- get bh
458                          b <- get bh
459                          c <- get bh
460                          d <- get bh
461                          return (a,b,c,d)
462
463 instance Binary a => Binary (Maybe a) where
464     put_ bh Nothing  = putByte bh 0
465     put_ bh (Just a) = do putByte bh 1; put_ bh a
466     get bh           = do h <- getWord8 bh
467                           case h of
468                             0 -> return Nothing
469                             _ -> do x <- get bh; return (Just x)
470
471 instance (Binary a, Binary b) => Binary (Either a b) where
472     put_ bh (Left  a) = do putByte bh 0; put_ bh a
473     put_ bh (Right b) = do putByte bh 1; put_ bh b
474     get bh            = do h <- getWord8 bh
475                            case h of
476                              0 -> do a <- get bh ; return (Left a)
477                              _ -> do b <- get bh ; return (Right b)
478
479 #ifdef __GLASGOW_HASKELL__
480 instance Binary Integer where
481     put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
482     put_ bh (J# s# a#) = do
483         p <- putByte bh 1;
484         put_ bh (I# s#)
485         let sz# = sizeofByteArray# a#  -- in *bytes*
486         put_ bh (I# sz#)  -- in *bytes*
487         putByteArray bh a# sz#
488    
489     get bh = do 
490         b <- getByte bh
491         case b of
492           0 -> do (I# i#) <- get bh
493                   return (S# i#)
494           _ -> do (I# s#) <- get bh
495                   sz <- get bh
496                   (BA a#) <- getByteArray bh sz
497                   return (J# s# a#)
498
499 putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
500 putByteArray bh a s# = loop 0#
501   where loop n# 
502            | n# ==# s# = return ()
503            | otherwise = do
504                 putByte bh (indexByteArray a n#)
505                 loop (n# +# 1#)
506
507 getByteArray :: BinHandle -> Int -> IO ByteArray
508 getByteArray bh (I# sz) = do
509   (MBA arr) <- newByteArray sz 
510   let loop n
511            | n ==# sz = return ()
512            | otherwise = do
513                 w <- getByte bh 
514                 writeByteArray arr n w
515                 loop (n +# 1#)
516   loop 0#
517   freezeByteArray arr
518
519
520 data ByteArray = BA ByteArray#
521 data MBA = MBA (MutableByteArray# RealWorld)
522
523 newByteArray :: Int# -> IO MBA
524 newByteArray sz = IO $ \s ->
525   case newByteArray# sz s of { (# s, arr #) ->
526   (# s, MBA arr #) }
527
528 freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
529 freezeByteArray arr = IO $ \s ->
530   case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
531   (# s, BA arr #) }
532
533 writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
534
535 #if __GLASGOW_HASKELL__ < 503
536 writeByteArray arr i w8 = IO $ \s ->
537   case word8ToWord w8 of { W# w# -> 
538   case writeCharArray# arr i (chr# (word2Int# w#)) s  of { s ->
539   (# s , () #) }}
540 #else
541 writeByteArray arr i (W8# w) = IO $ \s ->
542   case writeWord8Array# arr i w s of { s ->
543   (# s, () #) }
544 #endif
545
546 #if __GLASGOW_HASKELL__ < 503
547 indexByteArray a# n# = fromIntegral (I# (ord# (indexCharArray# a# n#)))
548 #else
549 indexByteArray a# n# = W8# (indexWord8Array# a# n#)
550 #endif
551
552 instance (Integral a, Binary a) => Binary (Ratio a) where
553     put_ bh (a :% b) = do put_ bh a; put_ bh b
554     get bh = do a <- get bh; b <- get bh; return (a :% b)
555 #endif
556
557 instance Binary (Bin a) where
558   put_ bh (BinPtr i) = put_ bh i
559   get bh = do i <- get bh; return (BinPtr i)
560
561 -- -----------------------------------------------------------------------------
562 -- Lazy reading/writing
563
564 lazyPut :: Binary a => BinHandle -> a -> IO ()
565 lazyPut bh a = do
566         -- output the obj with a ptr to skip over it:
567     pre_a <- tellBin bh
568     put_ bh pre_a       -- save a slot for the ptr
569     put_ bh a           -- dump the object
570     q <- tellBin bh     -- q = ptr to after object
571     putAt bh pre_a q    -- fill in slot before a with ptr to q
572     seekBin bh q        -- finally carry on writing at q
573
574 lazyGet :: Binary a => BinHandle -> IO a
575 lazyGet bh = do
576     p <- get bh         -- a BinPtr
577     p_a <- tellBin bh
578     a <- unsafeInterleaveIO (getAt bh p_a)
579     seekBin bh p -- skip over the object for now
580     return a
581
582 -- -----------------------------------------------------------------------------
583 -- BinHandleState
584
585 type BinHandleState = 
586         (Module, 
587          IORef Int,
588          IORef (UniqFM (Int,FastString)),
589          Array Int FastString)
590
591 initReadState :: BinHandleState
592 initReadState = (undef, undef, undef, undef)
593
594 newWriteState :: Module -> IO BinHandleState
595 newWriteState m = do
596   j_r <- newIORef 0
597   out_r <- newIORef emptyUFM
598   return (m,j_r,out_r,undef)
599
600 undef = error "Binary.BinHandleState"
601
602 -- -----------------------------------------------------------------------------
603 -- FastString binary interface
604
605 getBinFileWithDict :: Binary a => FilePath -> IO a
606 getBinFileWithDict file_path = do
607   bh <- Binary.readBinMem file_path
608   magic <- get bh
609   when (magic /= binaryInterfaceMagic) $
610         throwDyn (ProgramError (
611            "magic number mismatch: old/corrupt interface file?"))
612   dict_p <- Binary.get bh               -- get the dictionary ptr
613   data_p <- tellBin bh
614   seekBin bh dict_p
615   dict <- getDictionary bh
616   seekBin bh data_p
617   let (mod, j_r, out_r, _) = state bh
618   get bh{ state = (mod,j_r,out_r,dict) }
619
620 initBinMemSize = (1024*1024) :: Int
621
622 binaryInterfaceMagic = 0x1face :: Word32
623
624 putBinFileWithDict :: Binary a => FilePath -> Module -> a -> IO ()
625 putBinFileWithDict file_path mod a = do
626   bh <- openBinMem initBinMemSize mod
627   put_ bh binaryInterfaceMagic
628   p <- tellBin bh
629   put_ bh p             -- placeholder for ptr to dictionary
630   put_ bh a
631   let (_, j_r, fm_r, _) = state bh
632   j <- readIORef j_r
633   fm <- readIORef fm_r
634   dict_p <- tellBin bh
635   putAt bh p dict_p     -- fill in the placeholder
636   seekBin bh dict_p     -- seek back to the end of the file
637   putDictionary bh j (constructDictionary j fm)
638   writeBinMem bh file_path
639   
640 type Dictionary = Array Int FastString
641         -- should be 0-indexed
642
643 putDictionary :: BinHandle -> Int -> Dictionary -> IO ()
644 putDictionary bh sz dict = do
645   put_ bh sz
646   mapM_ (putFS bh) (elems dict)
647
648 getDictionary :: BinHandle -> IO Dictionary
649 getDictionary bh = do 
650   sz <- get bh
651   elems <- sequence (take sz (repeat (getFS bh)))
652   return (listArray (0,sz-1) elems)
653
654 constructDictionary :: Int -> UniqFM (Int,FastString) -> Dictionary
655 constructDictionary j fm = array (0,j-1) (eltsUFM fm)
656
657 putFS bh (FastString id l ba) = do
658   put_ bh (I# l)
659   putByteArray bh ba l
660 putFS bh s = error ("Binary.put_(FastString): " ++ unpackFS s)
661         -- Note: the length of the FastString is *not* the same as
662         -- the size of the ByteArray: the latter is rounded up to a
663         -- multiple of the word size.
664   
665 {- -- possible faster version, not quite there yet:
666 getFS bh@BinMem{} = do
667   (I# l) <- get bh
668   arr <- readIORef (arr_r bh)
669   off <- readFastMutInt (off_r bh)
670   return $! (mkFastSubStringBA# arr off l)
671 -}
672 getFS bh = do
673   (I# l) <- get bh
674   (BA ba) <- getByteArray bh (I# l)
675   return $! (mkFastSubStringBA# ba 0# l)
676
677 instance Binary FastString where
678   put_ bh f@(FastString id l ba) =
679     case getUserData bh of { (_, j_r, out_r, dict) -> do
680     out <- readIORef out_r
681     let uniq = getUnique f
682     case lookupUFM out uniq of
683         Just (j,f)  -> put_ bh j
684         Nothing -> do
685            j <- readIORef j_r
686            put_ bh j
687            writeIORef j_r (j+1)
688            writeIORef out_r (addToUFM out uniq (j,f))
689     }
690   put_ bh s = error ("Binary.put_(FastString): " ++ show (unpackFS s))
691
692   get bh = do 
693         j <- get bh
694         case getUserData bh of (_, _, _, arr) -> return $! (arr ! j)