diff --git a/Foreign/C/Types.hs b/Foreign/C/Types.hs
--- a/Foreign/C/Types.hs
+++ b/Foreign/C/Types.hs
@@ -23,6 +23,12 @@
         ( -- * Representations of C types
           -- $ctypes
 
+          -- ** Platform differences
+          -- | This module contains platform specific information about types.
+          --   __/As such the types presented on this page reflect the platform
+          --   on which the documentation was generated and may not coincide with
+          --   the types on your platform./__
+
           -- ** Integral types
           -- | These types are represented as @newtype@s of
           -- types in "Data.Int" and "Data.Word", and are instances of
diff --git a/GHC/Base.hs b/GHC/Base.hs
--- a/GHC/Base.hs
+++ b/GHC/Base.hs
@@ -456,7 +456,7 @@
 
 * @'return' a '>>=' k  =  k a@
 * @m '>>=' 'return'  =  m@
-* @m '>>=' (\x -> k x '>>=' h)  =  (m '>>=' k) '>>=' h@
+* @m '>>=' (\\x -> k x '>>=' h)  =  (m '>>=' k) '>>=' h@
 
 Furthermore, the 'Monad' and 'Applicative' operations should relate as follows:
 
diff --git a/GHC/Enum.hs b/GHC/Enum.hs
--- a/GHC/Enum.hs
+++ b/GHC/Enum.hs
@@ -636,26 +636,150 @@
         | x <= maxIntWord = I# (word2Int# x#)
         | otherwise       = fromEnumError "Word" x
 
-    enumFrom n             = map integerToWordX [wordToIntegerX n .. wordToIntegerX (maxBound :: Word)]
-    enumFromTo n1 n2       = map integerToWordX [wordToIntegerX n1 .. wordToIntegerX n2]
-    enumFromThenTo n1 n2 m = map integerToWordX [wordToIntegerX n1, wordToIntegerX n2 .. wordToIntegerX m]
-    enumFromThen n1 n2     = map integerToWordX [wordToIntegerX n1, wordToIntegerX n2 .. wordToIntegerX limit]
-      where
-         limit :: Word
-         limit  | n2 >= n1  = maxBound
-                | otherwise = minBound
+    {-# INLINE enumFrom #-}
+    enumFrom (W# x#)      = eftWord x# maxWord#
+        where !(W# maxWord#) = maxBound
+        -- Blarg: technically I guess enumFrom isn't strict!
 
+    {-# INLINE enumFromTo #-}
+    enumFromTo (W# x) (W# y) = eftWord x y
+
+    {-# INLINE enumFromThen #-}
+    enumFromThen (W# x1) (W# x2) = efdWord x1 x2
+
+    {-# INLINE enumFromThenTo #-}
+    enumFromThenTo (W# x1) (W# x2) (W# y) = efdtWord x1 x2 y
+
 maxIntWord :: Word
 -- The biggest word representable as an Int
 maxIntWord = W# (case maxInt of I# i -> int2Word# i)
 
--- For some reason integerToWord and wordToInteger (GHC.Integer.Type)
--- work over Word#
-integerToWordX :: Integer -> Word
-integerToWordX i = W# (integerToWord i)
+-----------------------------------------------------
+-- eftWord and eftWordFB deal with [a..b], which is the
+-- most common form, so we take a lot of care
+-- In particular, we have rules for deforestation
 
-wordToIntegerX :: Word -> Integer
-wordToIntegerX (W# x#) = wordToInteger x#
+{-# RULES
+"eftWord"        [~1] forall x y. eftWord x y = build (\ c n -> eftWordFB c n x y)
+"eftWordList"    [1] eftWordFB  (:) [] = eftWord
+ #-}
+
+-- The Enum rules for Word work much the same way that they do for Int.
+-- See Note [How the Enum rules work].
+
+{-# NOINLINE [1] eftWord #-}
+eftWord :: Word# -> Word# -> [Word]
+-- [x1..x2]
+eftWord x0 y | isTrue# (x0 `gtWord#` y) = []
+             | otherwise                = go x0
+                where
+                  go x = W# x : if isTrue# (x `eqWord#` y)
+                                then []
+                                else go (x `plusWord#` 1##)
+
+{-# INLINE [0] eftWordFB #-}
+eftWordFB :: (Word -> r -> r) -> r -> Word# -> Word# -> r
+eftWordFB c n x0 y | isTrue# (x0 `gtWord#` y) = n
+                   | otherwise                = go x0
+                  where
+                    go x = W# x `c` if isTrue# (x `eqWord#` y)
+                                    then n
+                                    else go (x `plusWord#` 1##)
+                        -- Watch out for y=maxBound; hence ==, not >
+        -- Be very careful not to have more than one "c"
+        -- so that when eftInfFB is inlined we can inline
+        -- whatever is bound to "c"
+
+
+-----------------------------------------------------
+-- efdWord and efdtWord deal with [a,b..] and [a,b..c].
+-- The code is more complicated because of worries about Word overflow.
+
+-- See Note [How the Enum rules work]
+{-# RULES
+"efdtWord"       [~1] forall x1 x2 y.
+                     efdtWord x1 x2 y = build (\ c n -> efdtWordFB c n x1 x2 y)
+"efdtWordUpList" [1]  efdtWordFB (:) [] = efdtWord
+ #-}
+
+efdWord :: Word# -> Word# -> [Word]
+-- [x1,x2..maxWord]
+efdWord x1 x2
+ | isTrue# (x2 `geWord#` x1) = case maxBound of W# y -> efdtWordUp x1 x2 y
+ | otherwise                 = case minBound of W# y -> efdtWordDn x1 x2 y
+
+{-# NOINLINE [1] efdtWord #-}
+efdtWord :: Word# -> Word# -> Word# -> [Word]
+-- [x1,x2..y]
+efdtWord x1 x2 y
+ | isTrue# (x2 `geWord#` x1) = efdtWordUp x1 x2 y
+ | otherwise                 = efdtWordDn x1 x2 y
+
+{-# INLINE [0] efdtWordFB #-}
+efdtWordFB :: (Word -> r -> r) -> r -> Word# -> Word# -> Word# -> r
+efdtWordFB c n x1 x2 y
+ | isTrue# (x2 `geWord#` x1) = efdtWordUpFB c n x1 x2 y
+ | otherwise                 = efdtWordDnFB c n x1 x2 y
+
+-- Requires x2 >= x1
+efdtWordUp :: Word# -> Word# -> Word# -> [Word]
+efdtWordUp x1 x2 y    -- Be careful about overflow!
+ | isTrue# (y `ltWord#` x2) = if isTrue# (y `ltWord#` x1) then [] else [W# x1]
+ | otherwise = -- Common case: x1 <= x2 <= y
+               let !delta = x2 `minusWord#` x1 -- >= 0
+                   !y' = y `minusWord#` delta  -- x1 <= y' <= y; hence y' is representable
+
+                   -- Invariant: x <= y
+                   -- Note that: z <= y' => z + delta won't overflow
+                   -- so we are guaranteed not to overflow if/when we recurse
+                   go_up x | isTrue# (x `gtWord#` y') = [W# x]
+                           | otherwise                = W# x : go_up (x `plusWord#` delta)
+               in W# x1 : go_up x2
+
+-- Requires x2 >= x1
+efdtWordUpFB :: (Word -> r -> r) -> r -> Word# -> Word# -> Word# -> r
+efdtWordUpFB c n x1 x2 y    -- Be careful about overflow!
+ | isTrue# (y `ltWord#` x2) = if isTrue# (y `ltWord#` x1) then n else W# x1 `c` n
+ | otherwise = -- Common case: x1 <= x2 <= y
+               let !delta = x2 `minusWord#` x1 -- >= 0
+                   !y' = y `minusWord#` delta  -- x1 <= y' <= y; hence y' is representable
+
+                   -- Invariant: x <= y
+                   -- Note that: z <= y' => z + delta won't overflow
+                   -- so we are guaranteed not to overflow if/when we recurse
+                   go_up x | isTrue# (x `gtWord#` y') = W# x `c` n
+                           | otherwise                = W# x `c` go_up (x `plusWord#` delta)
+               in W# x1 `c` go_up x2
+
+-- Requires x2 <= x1
+efdtWordDn :: Word# -> Word# -> Word# -> [Word]
+efdtWordDn x1 x2 y    -- Be careful about underflow!
+ | isTrue# (y `gtWord#` x2) = if isTrue# (y `gtWord#` x1) then [] else [W# x1]
+ | otherwise = -- Common case: x1 >= x2 >= y
+               let !delta = x2 `minusWord#` x1 -- <= 0
+                   !y' = y `minusWord#` delta  -- y <= y' <= x1; hence y' is representable
+
+                   -- Invariant: x >= y
+                   -- Note that: z >= y' => z + delta won't underflow
+                   -- so we are guaranteed not to underflow if/when we recurse
+                   go_dn x | isTrue# (x `ltWord#` y') = [W# x]
+                           | otherwise                = W# x : go_dn (x `plusWord#` delta)
+   in W# x1 : go_dn x2
+
+-- Requires x2 <= x1
+efdtWordDnFB :: (Word -> r -> r) -> r -> Word# -> Word# -> Word# -> r
+efdtWordDnFB c n x1 x2 y    -- Be careful about underflow!
+ | isTrue# (y `gtWord#` x2) = if isTrue# (y `gtWord#` x1) then n else W# x1 `c` n
+ | otherwise = -- Common case: x1 >= x2 >= y
+               let !delta = x2 `minusWord#` x1 -- <= 0
+                   !y' = y `minusWord#` delta  -- y <= y' <= x1; hence y' is representable
+
+                   -- Invariant: x >= y
+                   -- Note that: z >= y' => z + delta won't underflow
+                   -- so we are guaranteed not to underflow if/when we recurse
+                   go_dn x | isTrue# (x `ltWord#` y') = W# x `c` n
+                           | otherwise                = W# x `c` go_dn (x `plusWord#` delta)
+               in W# x1 `c` go_dn x2
 
 ------------------------------------------------------------------------
 -- Integer
diff --git a/GHC/Foreign.hs b/GHC/Foreign.hs
--- a/GHC/Foreign.hs
+++ b/GHC/Foreign.hs
@@ -32,6 +32,7 @@
     --
     withCString,
     withCStringLen,
+    withCStringsLen,
 
     charIsRepresentable,
   ) where
@@ -134,6 +135,23 @@
 withCStringLen         :: TextEncoding -> String -> (CStringLen -> IO a) -> IO a
 withCStringLen enc = withEncodedCString enc False
 
+-- | Marshal a list of Haskell strings into an array of NUL terminated C strings
+-- using temporary storage.
+--
+-- * the Haskell strings may /not/ contain any NUL characters
+--
+-- * the memory is freed when the subcomputation terminates (either
+--   normally or via an exception), so the pointer to the temporary
+--   storage must /not/ be used after this.
+--
+withCStringsLen :: TextEncoding
+                -> [String]
+                -> (Int -> Ptr CString -> IO a)
+                -> IO a
+withCStringsLen enc strs f = go [] strs
+  where
+  go cs (s:ss) = withCString enc s $ \c -> go (c:cs) ss
+  go cs [] = withArrayLen (reverse cs) f
 
 -- | Determines whether a character can be accurately encoded in a 'CString'.
 --
diff --git a/GHC/IO/FD.hs b/GHC/IO/FD.hs
--- a/GHC/IO/FD.hs
+++ b/GHC/IO/FD.hs
@@ -606,18 +606,18 @@
 
 blockingReadRawBufferPtr :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
 blockingReadRawBufferPtr loc fd buf off len
-  = fmap fromIntegral $ throwErrnoIfMinus1Retry loc $
+  = throwErrnoIfMinus1Retry loc $
         if fdIsSocket fd
-           then c_safe_recv (fdFD fd) (buf `plusPtr` off) len 0
-           else c_safe_read (fdFD fd) (buf `plusPtr` off) len
+           then c_safe_recv (fdFD fd) (buf `plusPtr` off) (fromIntegral len) 0
+           else c_safe_read (fdFD fd) (buf `plusPtr` off) (fromIntegral len)
 
 blockingWriteRawBufferPtr :: String -> FD -> Ptr Word8-> Int -> CSize -> IO CInt
 blockingWriteRawBufferPtr loc fd buf off len
-  = fmap fromIntegral $ throwErrnoIfMinus1Retry loc $
+  = throwErrnoIfMinus1Retry loc $
         if fdIsSocket fd
-           then c_safe_send  (fdFD fd) (buf `plusPtr` off) len 0
+           then c_safe_send  (fdFD fd) (buf `plusPtr` off) (fromIntegral len) 0
            else do
-             r <- c_safe_write (fdFD fd) (buf `plusPtr` off) len
+             r <- c_safe_write (fdFD fd) (buf `plusPtr` off) (fromIntegral len)
              when (r == -1) c_maperrno
              return r
       -- we don't trust write() to give us the correct errno, and
@@ -631,10 +631,10 @@
 -- These calls may block, but that's ok.
 
 foreign import WINDOWS_CCONV safe "recv"
-   c_safe_recv :: CInt -> Ptr Word8 -> CSize -> CInt{-flags-} -> IO CSsize
+   c_safe_recv :: CInt -> Ptr Word8 -> CInt -> CInt{-flags-} -> IO CInt
 
 foreign import WINDOWS_CCONV safe "send"
-   c_safe_send :: CInt -> Ptr Word8 -> CSize -> CInt{-flags-} -> IO CSsize
+   c_safe_send :: CInt -> Ptr Word8 -> CInt -> CInt{-flags-} -> IO CInt
 
 #endif
 
diff --git a/GHC/Read.hs b/GHC/Read.hs
--- a/GHC/Read.hs
+++ b/GHC/Read.hs
@@ -229,7 +229,13 @@
 --
 lexLitChar :: ReadS String      -- As defined by H2010
 lexLitChar = readP_to_S (do { (s, _) <- P.gather L.lexChar ;
-                              return s })
+                              let s' = removeNulls s in
+                              return s' })
+    where
+    -- remove nulls from end of the character if they exist
+    removeNulls [] = []
+    removeNulls ('\\':'&':xs) = removeNulls xs
+    removeNulls (first:rest) = first : removeNulls rest
         -- There was a skipSpaces before the P.gather L.lexChar,
         -- but that seems inconsistent with readLitChar
 
@@ -256,13 +262,49 @@
 expectP :: L.Lexeme -> ReadPrec ()
 expectP lexeme = lift (L.expect lexeme)
 
+expectCharP :: Char -> ReadPrec a -> ReadPrec a
+expectCharP c a = do
+  q <- get
+  if q == c
+    then a
+    else pfail
+{-# INLINE expectCharP #-}
+
+-- A version of skipSpaces that takes the next
+-- parser as an argument. That is,
+--
+-- skipSpacesThenP m = lift skipSpaces >> m
+--
+-- Since skipSpaces is recursive, it appears that we get
+-- cleaner code by providing the continuation explicitly.
+-- In particular, we avoid passing an extra continuation
+-- of the form
+--
+-- \ () -> ...
+skipSpacesThenP :: ReadPrec a -> ReadPrec a
+skipSpacesThenP m =
+  do s <- look
+     skip s
+ where
+   skip (c:s) | isSpace c = get *> skip s
+   skip _ = m
+
 paren :: ReadPrec a -> ReadPrec a
 -- ^ @(paren p)@ parses \"(P0)\"
 --      where @p@ parses \"P0\" in precedence context zero
-paren p = do expectP (L.Punc "(")
-             x <- reset p
-             expectP (L.Punc ")")
-             return x
+paren p = skipSpacesThenP (paren' p)
+
+-- We try very hard to make paren' efficient, because parens is ubiquitous.
+-- Earlier code used `expectP` to look for the parentheses. The problem is that
+-- this lexes a (potentially long) token just to check if it's a parenthesis or
+-- not. So the first token of pretty much every value would be fully lexed
+-- twice. Now, we look for the '(' by hand instead. Since there's no reason not
+-- to, and it allows for faster failure, we do the same for ')'. This strategy
+-- works particularly well here because neither '(' nor ')' can begin any other
+-- lexeme.
+paren' :: ReadPrec a -> ReadPrec a
+paren' p = expectCharP '(' $ reset p >>= \x ->
+              skipSpacesThenP (expectCharP ')' (pure x))
 
 parens :: ReadPrec a -> ReadPrec a
 -- ^ @(parens p)@ parses \"P\", \"(P0)\", \"((P0))\", etc,
diff --git a/System/Environment.hs b/System/Environment.hs
--- a/System/Environment.hs
+++ b/System/Environment.hs
@@ -32,12 +32,14 @@
 import Foreign
 import Foreign.C
 import System.IO.Error (mkIOError)
-import Control.Exception.Base (bracket, throwIO)
+import Control.Exception.Base (bracket_, throwIO)
+#ifdef mingw32_HOST_OS
+import Control.Exception.Base (bracket)
+#endif
 -- import GHC.IO
 import GHC.IO.Exception
 import GHC.IO.Encoding (getFileSystemEncoding)
 import qualified GHC.Foreign as GHC
-import Data.List
 import Control.Monad
 #ifdef mingw32_HOST_OS
 import GHC.Environment
@@ -369,25 +371,17 @@
 withProgArgv new_args act = do
   pName <- System.Environment.getProgName
   existing_args <- System.Environment.getArgs
-  bracket (setProgArgv new_args)
-          (\argv -> do _ <- setProgArgv (pName:existing_args)
-                       freeProgArgv argv)
-          (const act)
-
-freeProgArgv :: Ptr CString -> IO ()
-freeProgArgv argv = do
-  size <- lengthArray0 nullPtr argv
-  sequence_ [ peek (argv `advancePtr` i) >>= free
-            | i <- [size - 1, size - 2 .. 0]]
-  free argv
+  bracket_ (setProgArgv new_args)
+           (setProgArgv (pName:existing_args))
+           act
 
-setProgArgv :: [String] -> IO (Ptr CString)
+setProgArgv :: [String] -> IO ()
 setProgArgv argv = do
   enc <- getFileSystemEncoding
-  vs <- mapM (GHC.newCString enc) argv >>= newArray0 nullPtr
-  c_setProgArgv (genericLength argv) vs
-  return vs
+  GHC.withCStringsLen enc argv $ \len css ->
+    c_setProgArgv (fromIntegral len) css
 
+-- setProgArgv copies the arguments
 foreign import ccall unsafe "setProgArgv"
   c_setProgArgv  :: CInt -> Ptr CString -> IO ()
 
diff --git a/System/Posix/Internals.hs b/System/Posix/Internals.hs
--- a/System/Posix/Internals.hs
+++ b/System/Posix/Internals.hs
@@ -378,121 +378,92 @@
 
 See https://msdn.microsoft.com/en-us/library/ms235384.aspx
 for more.
+
+However since we can't hope to get people to support Windows
+packages we should support the deprecated names. See #12497
 -}
-#if defined(mingw32_HOST_OS)
-foreign import ccall unsafe "io.h _lseeki64"
-   c_lseek :: CInt -> Int64 -> CInt -> IO Int64
+foreign import capi unsafe "unistd.h lseek"
+   c_lseek :: CInt -> COff -> CInt -> IO COff
 
-foreign import ccall unsafe "HsBase.h _access"
+foreign import ccall unsafe "HsBase.h access"
    c_access :: CString -> CInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h _chmod"
+foreign import ccall unsafe "HsBase.h chmod"
    c_chmod :: CString -> CMode -> IO CInt
 
-foreign import ccall unsafe "HsBase.h _close"
+foreign import ccall unsafe "HsBase.h close"
    c_close :: CInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h _creat"
+foreign import ccall unsafe "HsBase.h creat"
    c_creat :: CString -> CMode -> IO CInt
 
-foreign import ccall unsafe "HsBase.h _dup"
+foreign import ccall unsafe "HsBase.h dup"
    c_dup :: CInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h _dup2"
+foreign import ccall unsafe "HsBase.h dup2"
    c_dup2 :: CInt -> CInt -> IO CInt
 
-foreign import ccall unsafe "HsBase.h _isatty"
+foreign import ccall unsafe "HsBase.h isatty"
    c_isatty :: CInt -> IO CInt
 
--- See Note: CSsize
+#if defined(mingw32_HOST_OS)
+-- See Note: Windows types
 foreign import capi unsafe "HsBase.h _read"
-   c_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
+   c_read :: CInt -> Ptr Word8 -> CUInt -> IO CInt
 
--- See Note: CSsize
+-- See Note: Windows types
 foreign import capi safe "HsBase.h _read"
-   c_safe_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
+   c_safe_read :: CInt -> Ptr Word8 -> CUInt -> IO CInt
 
 foreign import ccall unsafe "HsBase.h _umask"
    c_umask :: CMode -> IO CMode
 
--- See Note: CSsize
+-- See Note: Windows types
 foreign import capi unsafe "HsBase.h _write"
-   c_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
+   c_write :: CInt -> Ptr Word8 -> CUInt -> IO CInt
 
--- See Note: CSsize
+-- See Note: Windows types
 foreign import capi safe "HsBase.h _write"
-   c_safe_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
-
-foreign import ccall unsafe "HsBase.h _unlink"
-   c_unlink :: CString -> IO CInt
+   c_safe_write :: CInt -> Ptr Word8 -> CUInt -> IO CInt
 
 foreign import ccall unsafe "HsBase.h _pipe"
    c_pipe :: Ptr CInt -> IO CInt
-
-foreign import capi unsafe "HsBase.h _utime"
-   c_utime :: CString -> Ptr CUtimbuf -> IO CInt
-
-foreign import ccall unsafe "HsBase.h _getpid"
-   c_getpid :: IO CPid
 #else
 -- We use CAPI as on some OSs (eg. Linux) this is wrapped by a macro
 -- which redirects to the 64-bit-off_t versions when large file
 -- support is enabled.
-foreign import capi unsafe "unistd.h lseek"
-   c_lseek :: CInt -> COff -> CInt -> IO COff
 
-foreign import ccall unsafe "HsBase.h access"
-   c_access :: CString -> CInt -> IO CInt
-
-foreign import ccall unsafe "HsBase.h chmod"
-   c_chmod :: CString -> CMode -> IO CInt
-
-foreign import ccall unsafe "HsBase.h close"
-   c_close :: CInt -> IO CInt
-
-foreign import ccall unsafe "HsBase.h creat"
-   c_creat :: CString -> CMode -> IO CInt
-
-foreign import ccall unsafe "HsBase.h dup"
-   c_dup :: CInt -> IO CInt
-
-foreign import ccall unsafe "HsBase.h dup2"
-   c_dup2 :: CInt -> CInt -> IO CInt
-
-foreign import ccall unsafe "HsBase.h isatty"
-   c_isatty :: CInt -> IO CInt
-
--- See Note: CSsize
+-- See Note: Windows types
 foreign import capi unsafe "HsBase.h read"
    c_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 
--- See Note: CSsize
+-- See Note: Windows types
 foreign import capi safe "HsBase.h read"
    c_safe_read :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 
 foreign import ccall unsafe "HsBase.h umask"
    c_umask :: CMode -> IO CMode
 
--- See Note: CSsize
+-- See Note: Windows types
 foreign import capi unsafe "HsBase.h write"
    c_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 
--- See Note: CSsize
+-- See Note: Windows types
 foreign import capi safe "HsBase.h write"
    c_safe_write :: CInt -> Ptr Word8 -> CSize -> IO CSsize
 
-foreign import ccall unsafe "HsBase.h unlink"
-   c_unlink :: CString -> IO CInt
-
 foreign import ccall unsafe "HsBase.h pipe"
    c_pipe :: Ptr CInt -> IO CInt
+#endif
 
+foreign import ccall unsafe "HsBase.h unlink"
+   c_unlink :: CString -> IO CInt
+
 foreign import capi unsafe "HsBase.h utime"
    c_utime :: CString -> Ptr CUtimbuf -> IO CInt
 
 foreign import ccall unsafe "HsBase.h getpid"
    c_getpid :: IO CPid
-#endif
 
 foreign import ccall unsafe "HsBase.h __hscore_stat"
    c_stat :: CFilePath -> Ptr CStat -> IO CInt
@@ -619,14 +590,13 @@
 foreign import capi  unsafe "stdio.h value SEEK_END" sEEK_END :: CInt
 
 {-
-Note: CSsize
-
-On Win64, ssize_t is 64 bit, but functions like read return 32 bit
-ints. The CAPI wrapper means the C compiler takes care of doing all
-the necessary casting.
+Note: Windows types
 
-When using ccall instead, when the functions failed with -1, we thought
-they were returning with 4294967295, and so didn't throw an exception.
-This lead to a segfault in echo001(ghci).
+Windows' _read and _write have types that differ from POSIX. They take an
+unsigned int for lengh and return a signed int where POSIX uses size_t and
+ssize_t. Those are different on x86_64 and equivalent on x86. We import them
+with the types in Microsoft's documentation which means that c_read,
+c_safe_read, c_write and c_safe_write have different Haskell types depending on
+the OS.
 -}
 
diff --git a/System/Posix/Types.hs b/System/Posix/Types.hs
--- a/System/Posix/Types.hs
+++ b/System/Posix/Types.hs
@@ -25,6 +25,12 @@
 module System.Posix.Types (
 
   -- * POSIX data types
+
+  -- ** Platform differences
+  -- | This module contains platform specific information about types.
+  --   __/As such the types presented on this page reflect the platform
+  --   on which the documentation was generated and may not coincide with
+  --   the types on your platform./__
 #if defined(HTYPE_DEV_T)
   CDev(..),
 #endif
diff --git a/Text/Read/Lex.hs b/Text/Read/Lex.hs
--- a/Text/Read/Lex.hs
+++ b/Text/Read/Lex.hs
@@ -253,7 +253,16 @@
      return (Char c)
 
 lexChar :: ReadP Char
-lexChar = do { (c,_) <- lexCharE; return c }
+lexChar = do { (c,_) <- lexCharE; consumeEmpties; return c }
+    where
+    -- Consumes the string "\&" repeatedly and greedily (will only produce one match)
+    consumeEmpties :: ReadP ()
+    consumeEmpties = do
+        rest <- look
+        case rest of
+            ('\\':'&':_) -> string "\\&" >> consumeEmpties
+            _ -> return ()
+
 
 lexCharE :: ReadP (Char, Bool)  -- "escaped or not"?
 lexCharE =
diff --git a/base.cabal b/base.cabal
--- a/base.cabal
+++ b/base.cabal
@@ -1,5 +1,5 @@
 name:           base
-version:        4.9.0.0
+version:        4.9.1.0
 -- NOTE: Don't forget to update ./changelog.md
 license:        BSD3
 license-file:   LICENSE
@@ -44,13 +44,11 @@
 
 Flag integer-simple
     Description: Use integer-simple
-    Manual: True
     Default: False
 
 Flag integer-gmp
     Description: Use integer-gmp
-    Manual: True
-    Default: False
+    Default: True
 
 Library
     default-language: Haskell2010
diff --git a/cbits/inputReady.c b/cbits/inputReady.c
--- a/cbits/inputReady.c
+++ b/cbits/inputReady.c
@@ -7,6 +7,9 @@
 /* select and supporting types is not Posix */
 /* #include "PosixSource.h" */
 #include "HsBase.h"
+#if !defined(_WIN32)
+#include <poll.h>
+#endif
 
 /*
  * inputReady(fd) checks to see whether input is available on the file
@@ -16,19 +19,41 @@
 int
 fdReady(int fd, int write, int msecs, int isSock)
 {
-    if 
-#if defined(_WIN32)
-    ( isSock ) {
+
+#if !defined(_WIN32)
+
+    // We only handle msecs == 0 on non-Windows, because this is the
+    // only case we need.  Non-zero waiting is handled by the IO manager.
+    if (msecs != 0) {
+        fprintf(stderr, "fdReady: msecs != 0, this shouldn't happen");
+        abort();
+    }
+
+    struct pollfd fds[1];
+
+    fds[0].fd = fd;
+    fds[0].events = write ? POLLOUT : POLLIN;
+    fds[0].revents = 0;
+
+    int res;
+    while ((res = poll(fds, 1, 0)) < 0) {
+        if (errno != EINTR) {
+            return (-1);
+        }
+    }
+
+    // res is the number of FDs with events
+    return (res > 0);
+
 #else
-    ( 1 ) {
-#endif
+
+    if (isSock) {
 	int maxfd, ready;
 	fd_set rfd, wfd;
 	struct timeval tv;
         if ((fd >= (int)FD_SETSIZE) || (fd < 0)) {
-            /* avoid memory corruption on too large FDs */
-            errno = EINVAL;
-            return -1;
+            fprintf(stderr, "fdReady: fd is too big");
+            abort();
         }
 	FD_ZERO(&rfd);
 	FD_ZERO(&wfd);
@@ -54,7 +79,6 @@
 	/* 1 => Input ready, 0 => not ready, -1 => error */
 	return (ready);
     }
-#if defined(_WIN32)
     else {
 	DWORD rc;
 	HANDLE hFile = (HANDLE)_get_osfhandle(fd);
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,13 @@
 # Changelog for [`base` package](http://hackage.haskell.org/package/base)
 
+## 4.9.1.0  *Jan 2017*
+
+  * Bundled with GHC 8.0.2
+
+  * Performance improvements in `Read` implementation
+
+  * Teach event manager to use poll instead of select (#12912)
+
 ## 4.9.0.0  *May 2016*
 
   * Bundled with GHC 8.0
