about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2017-05-14 21:29:18 -0400
committerSteven Fackler <sfackler@gmail.com>2017-06-20 20:26:22 -0700
commitecbb896b9eb2acadefde57be493e4298c1aa04a3 (patch)
treef46da3b3294c60abfb2343638c79f51124ac95c0
parent445077963c55297ef1e196a3525723090fe80b22 (diff)
downloadrust-ecbb896b9eb2acadefde57be493e4298c1aa04a3.tar.gz
rust-ecbb896b9eb2acadefde57be493e4298c1aa04a3.zip
Add `Read::initializer`.
This is an API that allows types to indicate that they can be passed
buffers of uninitialized memory which can improve performance.
-rw-r--r--src/doc/unstable-book/src/library-features/read-initializer.md7
-rw-r--r--src/libstd/fs.rs14
-rw-r--r--src/libstd/io/buffered.rs22
-rw-r--r--src/libstd/io/cursor.rs7
-rw-r--r--src/libstd/io/impls.rs17
-rw-r--r--src/libstd/io/mod.rs128
-rw-r--r--src/libstd/io/stdio.rs23
-rw-r--r--src/libstd/io/util.rs26
-rw-r--r--src/libstd/net/tcp.rs14
-rw-r--r--src/libstd/process.rs12
-rw-r--r--src/libstd/sys/redox/fd.rs5
-rw-r--r--src/libstd/sys/redox/fs.rs4
-rw-r--r--src/libstd/sys/redox/net/tcp.rs4
-rw-r--r--src/libstd/sys/redox/pipe.rs4
-rw-r--r--src/libstd/sys/redox/stdio.rs7
-rw-r--r--src/libstd/sys/unix/ext/net.rs12
-rw-r--r--src/libstd/sys/unix/fd.rs5
-rw-r--r--src/libstd/sys/unix/fs.rs4
-rw-r--r--src/libstd/sys/unix/net.rs4
-rw-r--r--src/libstd/sys/unix/pipe.rs4
-rw-r--r--src/libstd/sys/unix/stdio.rs7
-rw-r--r--src/libstd/sys/windows/fs.rs4
-rw-r--r--src/libstd/sys/windows/handle.rs5
-rw-r--r--src/libstd/sys/windows/net.rs10
-rw-r--r--src/libstd/sys/windows/pipe.rs4
-rw-r--r--src/libstd/sys/windows/stdio.rs5
-rw-r--r--src/libstd/sys_common/io.rs129
-rw-r--r--src/libstd/sys_common/net.rs4
28 files changed, 222 insertions, 269 deletions
diff --git a/src/doc/unstable-book/src/library-features/read-initializer.md b/src/doc/unstable-book/src/library-features/read-initializer.md
new file mode 100644
index 00000000000..898fe58eeee
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/read-initializer.md
@@ -0,0 +1,7 @@
+# `read_initializer`
+
+The tracking issue for this feature is: [#42788]
+
+[#0]: https://github.com/rust-lang/rust/issues/42788
+
+------------------------
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 69843199348..5b8c0c33990 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -19,7 +19,7 @@
 
 use fmt;
 use ffi::OsString;
-use io::{self, SeekFrom, Seek, Read, Write};
+use io::{self, SeekFrom, Seek, Read, Initializer, Write};
 use path::{Path, PathBuf};
 use sys::fs as fs_imp;
 use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
@@ -446,8 +446,10 @@ impl Read for File {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.inner.read_to_end(buf)
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -468,8 +470,10 @@ impl<'a> Read for &'a File {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.inner.read_to_end(buf)
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 3b82412716e..296ee78aadb 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -15,7 +15,7 @@ use io::prelude::*;
 use cmp;
 use error;
 use fmt;
-use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
+use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
 use memchr;
 
 /// The `BufReader` struct adds buffering to any reader.
@@ -92,11 +92,16 @@ impl<R: Read> BufReader<R> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
-        BufReader {
-            inner: inner,
-            buf: vec![0; cap].into_boxed_slice(),
-            pos: 0,
-            cap: 0,
+        unsafe {
+            let mut buffer = Vec::with_capacity(cap);
+            buffer.set_len(cap);
+            inner.initializer().initialize(&mut buffer);
+            BufReader {
+                inner: inner,
+                buf: buffer.into_boxed_slice(),
+                pos: 0,
+                cap: 0,
+            }
         }
     }
 
@@ -180,6 +185,11 @@ impl<R: Read> Read for BufReader<R> {
         self.consume(nread);
         Ok(nread)
     }
+
+    // we can't skip unconditionally because of the large buffer case in read.
+    unsafe fn initializer(&self) -> Initializer {
+        self.inner.initializer()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs
index 53347eb14db..616b4f47ed3 100644
--- a/src/libstd/io/cursor.rs
+++ b/src/libstd/io/cursor.rs
@@ -12,7 +12,7 @@ use io::prelude::*;
 
 use core::convert::TryInto;
 use cmp;
-use io::{self, SeekFrom, Error, ErrorKind};
+use io::{self, Initializer, SeekFrom, Error, ErrorKind};
 
 /// A `Cursor` wraps another type and provides it with a
 /// [`Seek`] implementation.
@@ -229,6 +229,11 @@ impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
         self.pos += n as u64;
         Ok(n)
     }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs
index f691289811b..d6b41ceda43 100644
--- a/src/libstd/io/impls.rs
+++ b/src/libstd/io/impls.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use cmp;
-use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
+use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind};
 use fmt;
 use mem;
 
@@ -24,6 +24,11 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R {
     }
 
     #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        (**self).initializer()
+    }
+
+    #[inline]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         (**self).read_to_end(buf)
     }
@@ -88,6 +93,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
     }
 
     #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        (**self).initializer()
+    }
+
+    #[inline]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         (**self).read_to_end(buf)
     }
@@ -172,6 +182,11 @@ impl<'a> Read for &'a [u8] {
     }
 
     #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+
+    #[inline]
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         if buf.len() > self.len() {
             return Err(Error::new(ErrorKind::UnexpectedEof,
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 3f859c45c28..680a5f32ae2 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -275,6 +275,7 @@ use fmt;
 use result;
 use str;
 use memchr;
+use ptr;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::buffered::{BufReader, BufWriter, LineWriter};
@@ -292,7 +293,7 @@ pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr};
 pub use self::stdio::{StdoutLock, StderrLock, StdinLock};
 #[unstable(feature = "print_internals", issue = "0")]
 pub use self::stdio::{_print, _eprint};
-#[unstable(feature = "libstd_io_internals", issue = "0")]
+#[unstable(feature = "libstd_io_internals", issue = "42788")]
 #[doc(no_inline, hidden)]
 pub use self::stdio::{set_panic, set_print};
 
@@ -307,6 +308,14 @@ mod stdio;
 
 const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
 
+struct Guard<'a> { buf: &'a mut Vec<u8>, len: usize }
+
+impl<'a> Drop for Guard<'a> {
+    fn drop(&mut self) {
+        unsafe { self.buf.set_len(self.len); }
+    }
+}
+
 // A few methods below (read_to_string, read_line) will append data into a
 // `String` buffer, but we need to be pretty careful when doing this. The
 // implementation will just call `.as_mut_vec()` and then delegate to a
@@ -328,23 +337,16 @@ const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
 fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
     where F: FnOnce(&mut Vec<u8>) -> Result<usize>
 {
-    struct Guard<'a> { s: &'a mut Vec<u8>, len: usize }
-        impl<'a> Drop for Guard<'a> {
-        fn drop(&mut self) {
-            unsafe { self.s.set_len(self.len); }
-        }
-    }
-
     unsafe {
-        let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() };
-        let ret = f(g.s);
-        if str::from_utf8(&g.s[g.len..]).is_err() {
+        let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
+        let ret = f(g.buf);
+        if str::from_utf8(&g.buf[g.len..]).is_err() {
             ret.and_then(|_| {
                 Err(Error::new(ErrorKind::InvalidData,
                                "stream did not contain valid UTF-8"))
             })
         } else {
-            g.len = g.s.len();
+            g.len = g.buf.len();
             ret
         }
     }
@@ -356,25 +358,32 @@ fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
 // of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
 // time is 4,500 times (!) slower than this if the reader has a very small
 // amount of data to return.
+//
+// Because we're extending the buffer with uninitialized data for trusted
+// readers, we need to make sure to truncate that if any of this panics.
 fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
     let start_len = buf.len();
-    let mut len = start_len;
+    let mut g = Guard { len: buf.len(), buf: buf };
     let mut new_write_size = 16;
     let ret;
     loop {
-        if len == buf.len() {
+        if g.len == g.buf.len() {
             if new_write_size < DEFAULT_BUF_SIZE {
                 new_write_size *= 2;
             }
-            buf.resize(len + new_write_size, 0);
+            unsafe {
+                g.buf.reserve(new_write_size);
+                g.buf.set_len(g.len + new_write_size);
+                r.initializer().initialize(&mut g.buf[g.len..]);
+            }
         }
 
-        match r.read(&mut buf[len..]) {
+        match r.read(&mut g.buf[g.len..]) {
             Ok(0) => {
-                ret = Ok(len - start_len);
+                ret = Ok(g.len - start_len);
                 break;
             }
-            Ok(n) => len += n,
+            Ok(n) => g.len += n,
             Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
             Err(e) => {
                 ret = Err(e);
@@ -383,7 +392,6 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
         }
     }
 
-    buf.truncate(len);
     ret
 }
 
@@ -494,6 +502,31 @@ pub trait Read {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
 
+    /// Determines if this `Read`er can work with buffers of uninitialized
+    /// memory.
+    ///
+    /// The default implementation returns an initializer which will zero
+    /// buffers.
+    ///
+    /// If a `Read`er guarantees that it can work properly with uninitialized
+    /// memory, it should call `Initializer::nop()`. See the documentation for
+    /// `Initializer` for details.
+    ///
+    /// The behavior of this method must be independent of the state of the
+    /// `Read`er - the method only takes `&self` so that it can be used through
+    /// trait objects.
+    ///
+    /// # Unsafety
+    ///
+    /// This method is unsafe because a `Read`er could otherwise return a
+    /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
+    /// block.
+    #[unstable(feature = "read_initializer", issue = "42788")]
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::zeroing()
+    }
+
     /// Read all bytes until EOF in this source, placing them into `buf`.
     ///
     /// All bytes read from this source will be appended to the specified buffer
@@ -829,6 +862,50 @@ pub trait Read {
     }
 }
 
+/// A type used to conditionally initialize buffers passed to `Read` methods.
+#[unstable(feature = "read_initializer", issue = "42788")]
+#[derive(Debug)]
+pub struct Initializer(bool);
+
+impl Initializer {
+    /// Returns a new `Initializer` which will zero out buffers.
+    #[unstable(feature = "read_initializer", issue = "42788")]
+    #[inline]
+    pub fn zeroing() -> Initializer {
+        Initializer(true)
+    }
+
+    /// Returns a new `Initializer` which will not zero out buffers.
+    ///
+    /// # Unsafety
+    ///
+    /// This may only be called by `Read`ers which guarantee that they will not
+    /// read from buffers passed to `Read` methods, and that the return value of
+    /// the method accurately reflects the number of bytes that have been
+    /// written to the head of the buffer.
+    #[unstable(feature = "read_initializer", issue = "42788")]
+    #[inline]
+    pub unsafe fn nop() -> Initializer {
+        Initializer(false)
+    }
+
+    /// Indicates if a buffer should be initialized.
+    #[unstable(feature = "read_initializer", issue = "42788")]
+    #[inline]
+    pub fn should_initialize(&self) -> bool {
+        self.0
+    }
+
+    /// Initializes a buffer if necessary.
+    #[unstable(feature = "read_initializer", issue = "42788")]
+    #[inline]
+    pub fn initialize(&self, buf: &mut [u8]) {
+        if self.should_initialize() {
+            unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
+        }
+    }
+}
+
 /// A trait for objects which are byte-oriented sinks.
 ///
 /// Implementors of the `Write` trait are sometimes called 'writers'.
@@ -1608,6 +1685,15 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
         }
         self.second.read(buf)
     }
+
+    unsafe fn initializer(&self) -> Initializer {
+        let initializer = self.first.initializer();
+        if initializer.should_initialize() {
+            initializer
+        } else {
+            self.second.initializer()
+        }
+    }
 }
 
 #[stable(feature = "chain_bufread", since = "1.9.0")]
@@ -1772,6 +1858,10 @@ impl<T: Read> Read for Take<T> {
         self.limit -= n as u64;
         Ok(n)
     }
+
+    unsafe fn initializer(&self) -> Initializer {
+        self.inner.initializer()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index a8b0bf0071a..fb489bf487b 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -13,7 +13,7 @@ use io::prelude::*;
 use cell::RefCell;
 use fmt;
 use io::lazy::Lazy;
-use io::{self, BufReader, LineWriter};
+use io::{self, Initializer, BufReader, LineWriter};
 use sync::{Arc, Mutex, MutexGuard};
 use sys::stdio;
 use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
@@ -75,8 +75,10 @@ fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
 
 impl Read for StdinRaw {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 impl Write for StdoutRaw {
@@ -116,12 +118,6 @@ impl<R: io::Read> io::Read for Maybe<R> {
             Maybe::Fake => Ok(0)
         }
     }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        match *self {
-            Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0),
-            Maybe::Fake => Ok(0)
-        }
-    }
 }
 
 fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
@@ -294,6 +290,10 @@ impl Read for Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.lock().read(buf)
     }
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
         self.lock().read_to_end(buf)
     }
@@ -310,8 +310,9 @@ impl<'a> Read for StdinLock<'a> {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.inner.read_to_end(buf)
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 
diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs
index 078f1ad3f6c..88f4214296d 100644
--- a/src/libstd/io/util.rs
+++ b/src/libstd/io/util.rs
@@ -11,7 +11,8 @@
 #![allow(missing_copy_implementations)]
 
 use fmt;
-use io::{self, Read, Write, ErrorKind, BufRead};
+use io::{self, Read, Initializer, Write, ErrorKind, BufRead};
+use mem;
 
 /// Copies the entire contents of a reader into a writer.
 ///
@@ -47,7 +48,12 @@ use io::{self, Read, Write, ErrorKind, BufRead};
 pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
     where R: Read, W: Write
 {
-    let mut buf = [0; super::DEFAULT_BUF_SIZE];
+    let mut buf = unsafe {
+        let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
+        reader.initializer().initialize(&mut buf);
+        buf
+    };
+
     let mut written = 0;
     loop {
         let len = match reader.read(&mut buf) {
@@ -90,11 +96,19 @@ pub fn empty() -> Empty { Empty { _priv: () } }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Read for Empty {
+    #[inline]
     fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl BufRead for Empty {
+    #[inline]
     fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
+    #[inline]
     fn consume(&mut self, _n: usize) {}
 }
 
@@ -133,12 +147,18 @@ pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Read for Repeat {
+    #[inline]
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         for slot in &mut *buf {
             *slot = self.byte;
         }
         Ok(buf.len())
     }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -176,7 +196,9 @@ pub fn sink() -> Sink { Sink { _priv: () } }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Write for Sink {
+    #[inline]
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+    #[inline]
     fn flush(&mut self) -> io::Result<()> { Ok(()) }
 }
 
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index c1493c9c6f4..7be1fc9cd8c 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -11,7 +11,7 @@
 use io::prelude::*;
 
 use fmt;
-use io;
+use io::{self, Initializer};
 use net::{ToSocketAddrs, SocketAddr, Shutdown};
 use sys_common::net as net_imp;
 use sys_common::{AsInner, FromInner, IntoInner};
@@ -481,8 +481,10 @@ impl TcpStream {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Read for TcpStream {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -493,8 +495,10 @@ impl Write for TcpStream {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Read for &'a TcpStream {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 4c6d88c0ae8..4632c8a918e 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -60,7 +60,7 @@ use io::prelude::*;
 use ffi::OsStr;
 use fmt;
 use fs;
-use io;
+use io::{self, Initializer};
 use path::Path;
 use str;
 use sys::pipe::{read2, AnonPipe};
@@ -208,8 +208,9 @@ impl Read for ChildStdout {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.inner.read_to_end(buf)
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 
@@ -250,8 +251,9 @@ impl Read for ChildStderr {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.inner.read(buf)
     }
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.inner.read_to_end(buf)
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 
diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs
index b6de68a9dc1..1b37aafef56 100644
--- a/src/libstd/sys/redox/fd.rs
+++ b/src/libstd/sys/redox/fd.rs
@@ -14,7 +14,6 @@ use io::{self, Read};
 use mem;
 use sys::{cvt, syscall};
 use sys_common::AsInner;
-use sys_common::io::read_to_end_uninitialized;
 
 pub struct FileDesc {
     fd: usize,
@@ -78,10 +77,6 @@ impl<'a> Read for &'a FileDesc {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         (**self).read(buf)
     }
-
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
-    }
 }
 
 impl AsInner<usize> for FileDesc {
diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs
index a8391d2b898..48d9cdcb2c9 100644
--- a/src/libstd/sys/redox/fs.rs
+++ b/src/libstd/sys/redox/fs.rs
@@ -285,10 +285,6 @@ impl File {
         self.0.read(buf)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
-    }
-
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs
index 936097d7fb2..ac3fd2ad6b9 100644
--- a/src/libstd/sys/redox/net/tcp.rs
+++ b/src/libstd/sys/redox/net/tcp.rs
@@ -41,10 +41,6 @@ impl TcpStream {
         self.0.read(buf)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
-        self.0.read_to_end(buf)
-    }
-
     pub fn write(&self, buf: &[u8]) -> Result<usize> {
         self.0.write(buf)
     }
diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs
index e7240fbe7bf..05863adf108 100644
--- a/src/libstd/sys/redox/pipe.rs
+++ b/src/libstd/sys/redox/pipe.rs
@@ -34,10 +34,6 @@ impl AnonPipe {
         self.0.read(buf)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
-    }
-
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs
index 607eef051d6..c839531cc26 100644
--- a/src/libstd/sys/redox/stdio.rs
+++ b/src/libstd/sys/redox/stdio.rs
@@ -25,13 +25,6 @@ impl Stdin {
         fd.into_raw();
         ret
     }
-
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        let fd = FileDesc::new(0);
-        let ret = fd.read_to_end(buf);
-        fd.into_raw();
-        ret
-    }
 }
 
 impl Stdout {
diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs
index d688f2fa504..94b87a6bff4 100644
--- a/src/libstd/sys/unix/ext/net.rs
+++ b/src/libstd/sys/unix/ext/net.rs
@@ -17,7 +17,7 @@ use libc;
 use ascii;
 use ffi::OsStr;
 use fmt;
-use io;
+use io::{self, Initializer};
 use mem;
 use net::Shutdown;
 use os::unix::ffi::OsStrExt;
@@ -516,8 +516,9 @@ impl io::Read for UnixStream {
         io::Read::read(&mut &*self, buf)
     }
 
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        io::Read::read_to_end(&mut &*self, buf)
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 
@@ -527,8 +528,9 @@ impl<'a> io::Read for &'a UnixStream {
         self.0.read(buf)
     }
 
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
     }
 }
 
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index 405fac2b9d7..138087f1651 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -17,7 +17,6 @@ use mem;
 use sync::atomic::{AtomicBool, Ordering};
 use sys::cvt;
 use sys_common::AsInner;
-use sys_common::io::read_to_end_uninitialized;
 
 #[derive(Debug)]
 pub struct FileDesc {
@@ -232,10 +231,6 @@ impl<'a> Read for &'a FileDesc {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         (**self).read(buf)
     }
-
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
-    }
 }
 
 impl AsInner<c_int> for FileDesc {
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index e893a139094..59dceba8953 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -491,10 +491,6 @@ impl File {
         self.0.read(buf)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
-    }
-
     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
         self.0.read_at(buf, offset)
     }
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index 5efddca110f..8fb361a78e2 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -198,10 +198,6 @@ impl Socket {
         self.recv_from_with_flags(buf, MSG_PEEK)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
-    }
-
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index ca5ef4bcfc5..ec9b6f17dca 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -71,10 +71,6 @@ impl AnonPipe {
         self.0.read(buf)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.0.read_to_end(buf)
-    }
-
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs
index 6d38b00b39e..7a8fe25d98e 100644
--- a/src/libstd/sys/unix/stdio.rs
+++ b/src/libstd/sys/unix/stdio.rs
@@ -25,13 +25,6 @@ impl Stdin {
         fd.into_raw();
         ret
     }
-
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        let fd = FileDesc::new(libc::STDIN_FILENO);
-        let ret = fd.read_to_end(buf);
-        fd.into_raw();
-        ret
-    }
 }
 
 impl Stdout {
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 4efc68afdc4..7f3291cf304 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -324,10 +324,6 @@ impl File {
         self.handle.read_at(buf, offset)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.handle.read_to_end(buf)
-    }
-
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.handle.write(buf)
     }
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
index fdb9483fe1c..3729d6d6534 100644
--- a/src/libstd/sys/windows/handle.rs
+++ b/src/libstd/sys/windows/handle.rs
@@ -18,7 +18,6 @@ use ops::Deref;
 use ptr;
 use sys::c;
 use sys::cvt;
-use sys_common::io::read_to_end_uninitialized;
 
 /// An owned container for `HANDLE` object, closing them on Drop.
 ///
@@ -216,8 +215,4 @@ impl<'a> Read for &'a RawHandle {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         (**self).read(buf)
     }
-
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
-    }
 }
diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs
index adf6210d82e..f2a2793425d 100644
--- a/src/libstd/sys/windows/net.rs
+++ b/src/libstd/sys/windows/net.rs
@@ -20,7 +20,6 @@ use sync::Once;
 use sys::c;
 use sys;
 use sys_common::{self, AsInner, FromInner, IntoInner};
-use sys_common::io::read_to_end_uninitialized;
 use sys_common::net;
 use time::Duration;
 
@@ -200,11 +199,6 @@ impl Socket {
         self.recv_from_with_flags(buf, c::MSG_PEEK)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        let mut me = self;
-        (&mut me).read_to_end(buf)
-    }
-
     pub fn set_timeout(&self, dur: Option<Duration>,
                        kind: c_int) -> io::Result<()> {
         let timeout = match dur {
@@ -283,10 +277,6 @@ impl<'a> Read for &'a Socket {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         (**self).read(buf)
     }
-
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
-    }
 }
 
 impl Drop for Socket {
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
index 8073473f7ff..be7482c4bb1 100644
--- a/src/libstd/sys/windows/pipe.rs
+++ b/src/libstd/sys/windows/pipe.rs
@@ -164,10 +164,6 @@ impl AnonPipe {
         self.inner.read(buf)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.inner.read_to_end(buf)
-    }
-
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.inner.write(buf)
     }
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index d72e4b4438b..b5e5b5760f2 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -20,7 +20,6 @@ use sync::Mutex;
 use sys::c;
 use sys::cvt;
 use sys::handle::Handle;
-use sys_common::io::read_to_end_uninitialized;
 
 pub enum Output {
     Console(c::HANDLE),
@@ -151,10 +150,6 @@ impl<'a> Read for &'a Stdin {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         (**self).read(buf)
     }
-
-    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        unsafe { read_to_end_uninitialized(self, buf) }
-    }
 }
 
 impl Stdout {
diff --git a/src/libstd/sys_common/io.rs b/src/libstd/sys_common/io.rs
index 23daeeb5187..ab23936358e 100644
--- a/src/libstd/sys_common/io.rs
+++ b/src/libstd/sys_common/io.rs
@@ -7,51 +7,8 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-use io;
-use io::ErrorKind;
-use io::Read;
-use slice::from_raw_parts_mut;
-
 pub const DEFAULT_BUF_SIZE: usize = 8 * 1024;
 
-// Provides read_to_end functionality over an uninitialized buffer.
-// This function is unsafe because it calls the underlying
-// read function with a slice into uninitialized memory. The default
-// implementation of read_to_end for readers will zero out new memory in
-// the buf before passing it to read, but avoiding this zero can often
-// lead to a fairly significant performance win.
-//
-// Implementations using this method have to adhere to two guarantees:
-//  *  The implementation of read never reads the buffer provided.
-//  *  The implementation of read correctly reports how many bytes were written.
-pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::Result<usize> {
-
-    let start_len = buf.len();
-    buf.reserve(16);
-
-    // Always try to read into the empty space of the vector (from the length to the capacity).
-    // If the vector ever fills up then we reserve an extra byte which should trigger the normal
-    // reallocation routines for the vector, which will likely double the size.
-    //
-    // This function is similar to the read_to_end function in std::io, but the logic about
-    // reservations and slicing is different enough that this is duplicated here.
-    loop {
-        if buf.len() == buf.capacity() {
-            buf.reserve(1);
-        }
-
-        let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize),
-                                           buf.capacity() - buf.len());
-
-        match r.read(buf_slice) {
-            Ok(0) => { return Ok(buf.len() - start_len); }
-            Ok(n) => { let len = buf.len() + n; buf.set_len(len); },
-            Err(ref e) if e.kind() == ErrorKind::Interrupted => { }
-            Err(e) => { return Err(e); }
-        }
-    }
-}
-
 #[cfg(test)]
 #[allow(dead_code)] // not used on emscripten
 pub mod test {
@@ -91,89 +48,3 @@ pub mod test {
         TempDir(ret)
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use io::prelude::*;
-    use super::*;
-    use io;
-    use io::{ErrorKind, Take, Repeat, repeat};
-    use slice::from_raw_parts;
-
-    struct ErrorRepeat {
-        lr: Take<Repeat>
-    }
-
-    fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat {
-        ErrorRepeat { lr: repeat(byte).take(limit) }
-    }
-
-    impl Read for ErrorRepeat {
-        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-            let ret = self.lr.read(buf);
-            if let Ok(0) = ret {
-                return Err(io::Error::new(ErrorKind::Other, ""))
-            }
-            ret
-        }
-    }
-
-    fn init_vec_data() -> Vec<u8> {
-        let mut vec = vec![10u8; 200];
-        unsafe { vec.set_len(0); }
-        vec
-    }
-
-    fn assert_all_eq(buf: &[u8], value: u8) {
-        for n in buf {
-            assert_eq!(*n, value);
-        }
-    }
-
-    fn validate(buf: &Vec<u8>, good_read_len: usize) {
-        assert_all_eq(buf, 1u8);
-        let cap = buf.capacity();
-        let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize),
-                                                    cap - good_read_len) };
-        assert_all_eq(end_slice, 10u8);
-    }
-
-    #[test]
-    fn read_to_end_uninit_error() {
-        let mut er = error_repeat(1,100);
-        let mut vec = init_vec_data();
-        if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } {
-            validate(&vec, 100);
-        } else {
-            assert!(false);
-        }
-    }
-
-    #[test]
-    fn read_to_end_uninit_zero_len_vec() {
-        let mut er = repeat(1).take(100);
-        let mut vec = Vec::new();
-        let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() };
-        assert_all_eq(&vec, 1u8);
-        assert_eq!(vec.len(), n);
-    }
-
-    #[test]
-    fn read_to_end_uninit_good() {
-        let mut er = repeat(1).take(100);
-        let mut vec = init_vec_data();
-        let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() };
-        validate(&vec, 100);
-        assert_eq!(vec.len(), n);
-    }
-
-    #[bench]
-    #[cfg_attr(target_os = "emscripten", ignore)]
-    fn bench_uninitialized(b: &mut ::test::Bencher) {
-        b.iter(|| {
-            let mut lr = repeat(1).take(10000000);
-            let mut vec = Vec::with_capacity(1024);
-            unsafe { read_to_end_uninitialized(&mut lr, &mut vec) }
-        });
-    }
-}
diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs
index a1897c8bd67..809b728379d 100644
--- a/src/libstd/sys_common/net.rs
+++ b/src/libstd/sys_common/net.rs
@@ -243,10 +243,6 @@ impl TcpStream {
         self.inner.read(buf)
     }
 
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        self.inner.read_to_end(buf)
-    }
-
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
         let ret = cvt(unsafe {