summaryrefslogtreecommitdiff
path: root/compiler/utils/Fingerprint.hsc
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2008-05-28 12:52:58 +0000
committerSimon Marlow <marlowsd@gmail.com>2008-05-28 12:52:58 +0000
commit526c3af1dc98987b6949f4df73c0debccf9875bd (patch)
treee9dd06d73e2f4281cec06d1f46ae63f1063799e6 /compiler/utils/Fingerprint.hsc
parent842e9d6628a27cf1f420d53f6a5901935dc50c54 (diff)
downloadhaskell-526c3af1dc98987b6949f4df73c0debccf9875bd.tar.gz
Use MD5 checksums for recompilation checking (fixes #1372, #1959)
This is a much more robust way to do recompilation checking. The idea is to create a fingerprint of the ABI of an interface, and track dependencies by recording the fingerprints of ABIs that a module depends on. If any of those ABIs have changed, then we need to recompile. In bug #1372 we weren't recording dependencies on package modules, this patch fixes that by recording fingerprints of package modules that we depend on. Within a package there is still fine-grained recompilation avoidance as before. We currently use MD5 for fingerprints, being a good compromise between efficiency and security. We're not worried about attackers, but we are worried about accidental collisions. All the MD5 sums do make interface files a bit bigger, but compile times on the whole are about the same as before. Recompilation avoidance should be a bit more accurate than in 6.8.2 due to fixing #1959, especially when using -O.
Diffstat (limited to 'compiler/utils/Fingerprint.hsc')
-rw-r--r--compiler/utils/Fingerprint.hsc77
1 files changed, 77 insertions, 0 deletions
diff --git a/compiler/utils/Fingerprint.hsc b/compiler/utils/Fingerprint.hsc
new file mode 100644
index 0000000000..d5a2409a26
--- /dev/null
+++ b/compiler/utils/Fingerprint.hsc
@@ -0,0 +1,77 @@
+-- ----------------------------------------------------------------------------
+--
+-- (c) The University of Glasgow 2006
+--
+-- Fingerprints for recompilation checking and ABI versioning.
+--
+-- http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance
+--
+-- ----------------------------------------------------------------------------
+
+module Fingerprint (
+ Fingerprint(..), fingerprint0,
+ readHexFingerprint,
+ fingerprintData
+ ) where
+
+#include "md5.h"
+##include "HsVersions.h"
+
+import Outputable
+
+import Foreign
+import Foreign.C
+import Text.Printf
+import Data.Word
+import Numeric ( readHex )
+
+-- Using 128-bit MD5 fingerprints for now.
+
+data Fingerprint = Fingerprint {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64
+ deriving (Eq, Ord)
+ -- or ByteString?
+
+fingerprint0 :: Fingerprint
+fingerprint0 = Fingerprint 0 0
+
+instance Outputable Fingerprint where
+ ppr (Fingerprint w1 w2) = text (printf "%016x%016x" w1 w2)
+
+-- useful for parsing the output of 'md5sum', should we want to do that.
+readHexFingerprint :: String -> Fingerprint
+readHexFingerprint s = Fingerprint w1 w2
+ where (s1,s2) = splitAt 16 s
+ [(w1,"")] = readHex s1
+ [(w2,"")] = readHex (take 16 s2)
+
+peekFingerprint :: Ptr Word8 -> IO Fingerprint
+peekFingerprint p = do
+ let peekW64 :: Ptr Word8 -> Int -> Word64 -> IO Word64
+ STRICT3(peekW64)
+ peekW64 _ 0 i = return i
+ peekW64 p n i = do
+ w8 <- peek p
+ peekW64 (p `plusPtr` 1) (n-1)
+ ((i `shiftL` 8) .|. fromIntegral w8)
+
+ high <- peekW64 p 8 0
+ low <- peekW64 (p `plusPtr` 8) 8 0
+ return (Fingerprint high low)
+
+fingerprintData :: Ptr Word8 -> Int -> IO Fingerprint
+fingerprintData buf len = do
+ allocaBytes (#const sizeof(struct MD5Context)) $ \pctxt -> do
+ c_MD5Init pctxt
+ c_MD5Update pctxt buf (fromIntegral len)
+ allocaBytes 16 $ \pdigest -> do
+ c_MD5Final pdigest pctxt
+ peekFingerprint (castPtr pdigest)
+
+data MD5Context
+
+foreign import ccall unsafe "MD5Init"
+ c_MD5Init :: Ptr MD5Context -> IO ()
+foreign import ccall unsafe "MD5Update"
+ c_MD5Update :: Ptr MD5Context -> Ptr Word8 -> CInt -> IO ()
+foreign import ccall unsafe "MD5Final"
+ c_MD5Final :: Ptr Word8 -> Ptr MD5Context -> IO ()