[project @ 2002-12-12 16:35:14 by simonmar]
[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        ( 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 #if __GLASGOW_HASKELL__ <= 408
301         throw (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
302 #else
303         ioError (mkIOError eofErrorType "Data.Binary.getWord8" Nothing Nothing)
304 #endif
305     arr <- readIORef arr_r
306     w <- unsafeRead arr ix
307     writeFastMutInt ix_r (ix+1)
308     return w
309 getWord8 (BinIO _ ix_r h) = do
310     ix <- readFastMutInt ix_r
311     c <- hGetChar h
312     writeFastMutInt ix_r (ix+1)
313     return $! (fromIntegral (ord c))    -- XXX not really correct
314
315 putByte :: BinHandle -> Word8 -> IO ()
316 putByte bh w = put_ bh w
317
318 getByte :: BinHandle -> IO Word8
319 getByte = getWord8
320
321 -- -----------------------------------------------------------------------------
322 -- Primitve Word writes
323
324 instance Binary Word8 where
325   put_ = putWord8
326   get  = getWord8
327
328 instance Binary Word16 where
329   put_ h w = do -- XXX too slow.. inline putWord8?
330     putByte h (fromIntegral (w `shiftR` 8))
331     putByte h (fromIntegral (w .&. 0xff))
332   get h = do
333     w1 <- getWord8 h
334     w2 <- getWord8 h
335     return $! ((fromIntegral w1 `shiftL` 8) .|. fromIntegral w2)
336
337
338 instance Binary Word32 where
339   put_ h w = do
340     putByte h (fromIntegral (w `shiftR` 24))
341     putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
342     putByte h (fromIntegral ((w `shiftR` 8)  .&. 0xff))
343     putByte h (fromIntegral (w .&. 0xff))
344   get h = do
345     w1 <- getWord8 h
346     w2 <- getWord8 h
347     w3 <- getWord8 h
348     w4 <- getWord8 h
349     return $! ((fromIntegral w1 `shiftL` 24) .|. 
350                (fromIntegral w2 `shiftL` 16) .|. 
351                (fromIntegral w3 `shiftL`  8) .|. 
352                (fromIntegral w4))
353
354
355 instance Binary Word64 where
356   put_ h w = do
357     putByte h (fromIntegral (w `shiftR` 56))
358     putByte h (fromIntegral ((w `shiftR` 48) .&. 0xff))
359     putByte h (fromIntegral ((w `shiftR` 40) .&. 0xff))
360     putByte h (fromIntegral ((w `shiftR` 32) .&. 0xff))
361     putByte h (fromIntegral ((w `shiftR` 24) .&. 0xff))
362     putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
363     putByte h (fromIntegral ((w `shiftR`  8) .&. 0xff))
364     putByte h (fromIntegral (w .&. 0xff))
365   get h = do
366     w1 <- getWord8 h
367     w2 <- getWord8 h
368     w3 <- getWord8 h
369     w4 <- getWord8 h
370     w5 <- getWord8 h
371     w6 <- getWord8 h
372     w7 <- getWord8 h
373     w8 <- getWord8 h
374     return $! ((fromIntegral w1 `shiftL` 56) .|. 
375                (fromIntegral w2 `shiftL` 48) .|. 
376                (fromIntegral w3 `shiftL` 40) .|. 
377                (fromIntegral w4 `shiftL` 32) .|. 
378                (fromIntegral w5 `shiftL` 24) .|. 
379                (fromIntegral w6 `shiftL` 16) .|. 
380                (fromIntegral w7 `shiftL`  8) .|. 
381                (fromIntegral w8))
382
383 -- -----------------------------------------------------------------------------
384 -- Primitve Int writes
385
386 instance Binary Int8 where
387   put_ h w = put_ h (fromIntegral w :: Word8)
388   get h    = do w <- get h; return $! (fromIntegral (w::Word8))
389
390 instance Binary Int16 where
391   put_ h w = put_ h (fromIntegral w :: Word16)
392   get h    = do w <- get h; return $! (fromIntegral (w::Word16))
393
394 instance Binary Int32 where
395   put_ h w = put_ h (fromIntegral w :: Word32)
396   get h    = do w <- get h; return $! (fromIntegral (w::Word32))
397
398 instance Binary Int64 where
399   put_ h w = put_ h (fromIntegral w :: Word64)
400   get h    = do w <- get h; return $! (fromIntegral (w::Word64))
401
402 -- -----------------------------------------------------------------------------
403 -- Instances for standard types
404
405 instance Binary () where
406     put_ bh () = return ()
407     get  _     = return ()
408 --    getF bh p  = case getBitsF bh 0 p of (_,b) -> ((),b)
409
410 instance Binary Bool where
411     put_ bh b = putByte bh (fromIntegral (fromEnum b))
412     get  bh   = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))
413 --    getF bh p = case getBitsF bh 1 p of (x,b) -> (toEnum x,b)
414
415 instance Binary Char where
416     put_  bh c = put_ bh (fromIntegral (ord c) :: Word32)
417     get  bh   = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))
418 --    getF bh p = case getBitsF bh 8 p of (x,b) -> (toEnum x,b)
419
420 instance Binary Int where
421 #if SIZEOF_HSINT == 4
422     put_ bh i = put_ bh (fromIntegral i :: Int32)
423     get  bh = do
424         x <- get bh
425         return $! (fromIntegral (x :: Int32))
426 #elif SIZEOF_HSINT == 8
427     put_ bh i = put_ bh (fromIntegral i :: Int64)
428     get  bh = do
429         x <- get bh
430         return $! (fromIntegral (x :: Int64))
431 #else
432 #error "unsupported sizeof(HsInt)"
433 #endif
434 --    getF bh   = getBitsF bh 32
435
436 instance Binary a => Binary [a] where
437     put_ bh []     = putByte bh 0
438     put_ bh (x:xs) = do putByte bh 1; put_ bh x; put_ bh xs
439     get bh         = do h <- getWord8 bh
440                         case h of
441                           0 -> return []
442                           _ -> do x  <- get bh
443                                   xs <- get bh
444                                   return (x:xs)
445
446 instance (Binary a, Binary b) => Binary (a,b) where
447     put_ bh (a,b) = do put_ bh a; put_ bh b
448     get bh        = do a <- get bh
449                        b <- get bh
450                        return (a,b)
451
452 instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where
453     put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c
454     get bh          = do a <- get bh
455                          b <- get bh
456                          c <- get bh
457                          return (a,b,c)
458
459 instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where
460     put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d
461     get bh          = do a <- get bh
462                          b <- get bh
463                          c <- get bh
464                          d <- get bh
465                          return (a,b,c,d)
466
467 instance Binary a => Binary (Maybe a) where
468     put_ bh Nothing  = putByte bh 0
469     put_ bh (Just a) = do putByte bh 1; put_ bh a
470     get bh           = do h <- getWord8 bh
471                           case h of
472                             0 -> return Nothing
473                             _ -> do x <- get bh; return (Just x)
474
475 instance (Binary a, Binary b) => Binary (Either a b) where
476     put_ bh (Left  a) = do putByte bh 0; put_ bh a
477     put_ bh (Right b) = do putByte bh 1; put_ bh b
478     get bh            = do h <- getWord8 bh
479                            case h of
480                              0 -> do a <- get bh ; return (Left a)
481                              _ -> do b <- get bh ; return (Right b)
482
483 #ifdef __GLASGOW_HASKELL__
484 instance Binary Integer where
485     put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
486     put_ bh (J# s# a#) = do
487         p <- putByte bh 1;
488         put_ bh (I# s#)
489         let sz# = sizeofByteArray# a#  -- in *bytes*
490         put_ bh (I# sz#)  -- in *bytes*
491         putByteArray bh a# sz#
492    
493     get bh = do 
494         b <- getByte bh
495         case b of
496           0 -> do (I# i#) <- get bh
497                   return (S# i#)
498           _ -> do (I# s#) <- get bh
499                   sz <- get bh
500                   (BA a#) <- getByteArray bh sz
501                   return (J# s# a#)
502
503 putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
504 putByteArray bh a s# = loop 0#
505   where loop n# 
506            | n# ==# s# = return ()
507            | otherwise = do
508                 putByte bh (indexByteArray a n#)
509                 loop (n# +# 1#)
510
511 getByteArray :: BinHandle -> Int -> IO ByteArray
512 getByteArray bh (I# sz) = do
513   (MBA arr) <- newByteArray sz 
514   let loop n
515            | n ==# sz = return ()
516            | otherwise = do
517                 w <- getByte bh 
518                 writeByteArray arr n w
519                 loop (n +# 1#)
520   loop 0#
521   freezeByteArray arr
522
523
524 data ByteArray = BA ByteArray#
525 data MBA = MBA (MutableByteArray# RealWorld)
526
527 newByteArray :: Int# -> IO MBA
528 newByteArray sz = IO $ \s ->
529   case newByteArray# sz s of { (# s, arr #) ->
530   (# s, MBA arr #) }
531
532 freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
533 freezeByteArray arr = IO $ \s ->
534   case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
535   (# s, BA arr #) }
536
537 writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
538
539 #if __GLASGOW_HASKELL__ < 503
540 writeByteArray arr i w8 = IO $ \s ->
541   case word8ToWord w8 of { W# w# -> 
542   case writeCharArray# arr i (chr# (word2Int# w#)) s  of { s ->
543   (# s , () #) }}
544 #else
545 writeByteArray arr i (W8# w) = IO $ \s ->
546   case writeWord8Array# arr i w s of { s ->
547   (# s, () #) }
548 #endif
549
550 #if __GLASGOW_HASKELL__ < 503
551 indexByteArray a# n# = fromIntegral (I# (ord# (indexCharArray# a# n#)))
552 #else
553 indexByteArray a# n# = W8# (indexWord8Array# a# n#)
554 #endif
555
556 instance (Integral a, Binary a) => Binary (Ratio a) where
557     put_ bh (a :% b) = do put_ bh a; put_ bh b
558     get bh = do a <- get bh; b <- get bh; return (a :% b)
559 #endif
560
561 instance Binary (Bin a) where
562   put_ bh (BinPtr i) = put_ bh i
563   get bh = do i <- get bh; return (BinPtr i)
564
565 -- -----------------------------------------------------------------------------
566 -- Lazy reading/writing
567
568 lazyPut :: Binary a => BinHandle -> a -> IO ()
569 lazyPut bh a = do
570         -- output the obj with a ptr to skip over it:
571     pre_a <- tellBin bh
572     put_ bh pre_a       -- save a slot for the ptr
573     put_ bh a           -- dump the object
574     q <- tellBin bh     -- q = ptr to after object
575     putAt bh pre_a q    -- fill in slot before a with ptr to q
576     seekBin bh q        -- finally carry on writing at q
577
578 lazyGet :: Binary a => BinHandle -> IO a
579 lazyGet bh = do
580     p <- get bh         -- a BinPtr
581     p_a <- tellBin bh
582     a <- unsafeInterleaveIO (getAt bh p_a)
583     seekBin bh p -- skip over the object for now
584     return a
585
586 -- -----------------------------------------------------------------------------
587 -- BinHandleState
588
589 type BinHandleState = 
590         (Module, 
591          IORef Int,
592          IORef (UniqFM (Int,FastString)),
593          Array Int FastString)
594
595 initReadState :: BinHandleState
596 initReadState = (undef, undef, undef, undef)
597
598 newWriteState :: Module -> IO BinHandleState
599 newWriteState m = do
600   j_r <- newIORef 0
601   out_r <- newIORef emptyUFM
602   return (m,j_r,out_r,undef)
603
604 undef = error "Binary.BinHandleState"
605
606 -- -----------------------------------------------------------------------------
607 -- FastString binary interface
608
609 getBinFileWithDict :: Binary a => FilePath -> IO a
610 getBinFileWithDict file_path = do
611   bh <- Binary.readBinMem file_path
612   magic <- get bh
613   when (magic /= binaryInterfaceMagic) $
614         throwDyn (ProgramError (
615            "magic number mismatch: old/corrupt interface file?"))
616   dict_p <- Binary.get bh               -- get the dictionary ptr
617   data_p <- tellBin bh
618   seekBin bh dict_p
619   dict <- getDictionary bh
620   seekBin bh data_p
621   let (mod, j_r, out_r, _) = state bh
622   get bh{ state = (mod,j_r,out_r,dict) }
623
624 initBinMemSize = (1024*1024) :: Int
625
626 binaryInterfaceMagic = 0x1face :: Word32
627
628 putBinFileWithDict :: Binary a => FilePath -> Module -> a -> IO ()
629 putBinFileWithDict file_path mod a = do
630   bh <- openBinMem initBinMemSize mod
631   put_ bh binaryInterfaceMagic
632   p <- tellBin bh
633   put_ bh p             -- placeholder for ptr to dictionary
634   put_ bh a
635   let (_, j_r, fm_r, _) = state bh
636   j <- readIORef j_r
637   fm <- readIORef fm_r
638   dict_p <- tellBin bh
639   putAt bh p dict_p     -- fill in the placeholder
640   seekBin bh dict_p     -- seek back to the end of the file
641   putDictionary bh j (constructDictionary j fm)
642   writeBinMem bh file_path
643   
644 type Dictionary = Array Int FastString
645         -- should be 0-indexed
646
647 putDictionary :: BinHandle -> Int -> Dictionary -> IO ()
648 putDictionary bh sz dict = do
649   put_ bh sz
650   mapM_ (putFS bh) (elems dict)
651
652 getDictionary :: BinHandle -> IO Dictionary
653 getDictionary bh = do 
654   sz <- get bh
655   elems <- sequence (take sz (repeat (getFS bh)))
656   return (listArray (0,sz-1) elems)
657
658 constructDictionary :: Int -> UniqFM (Int,FastString) -> Dictionary
659 constructDictionary j fm = array (0,j-1) (eltsUFM fm)
660
661 putFS bh (FastString id l ba) = do
662   put_ bh (I# l)
663   putByteArray bh ba l
664 putFS bh s = error ("Binary.put_(FastString): " ++ unpackFS s)
665         -- Note: the length of the FastString is *not* the same as
666         -- the size of the ByteArray: the latter is rounded up to a
667         -- multiple of the word size.
668   
669 {- -- possible faster version, not quite there yet:
670 getFS bh@BinMem{} = do
671   (I# l) <- get bh
672   arr <- readIORef (arr_r bh)
673   off <- readFastMutInt (off_r bh)
674   return $! (mkFastSubStringBA# arr off l)
675 -}
676 getFS bh = do
677   (I# l) <- get bh
678   (BA ba) <- getByteArray bh (I# l)
679   return $! (mkFastSubStringBA# ba 0# l)
680
681 instance Binary FastString where
682   put_ bh f@(FastString id l ba) =
683     case getUserData bh of { (_, j_r, out_r, dict) -> do
684     out <- readIORef out_r
685     let uniq = getUnique f
686     case lookupUFM out uniq of
687         Just (j,f)  -> put_ bh j
688         Nothing -> do
689            j <- readIORef j_r
690            put_ bh j
691            writeIORef j_r (j+1)
692            writeIORef out_r (addToUFM out uniq (j,f))
693     }
694   put_ bh s = error ("Binary.put_(FastString): " ++ show (unpackFS s))
695
696   get bh = do 
697         j <- get bh
698         case getUserData bh of (_, _, _, arr) -> return $! (arr ! j)