about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorJeremy Soller <jackpot51@gmail.com>2016-11-03 08:52:48 -0600
committerJeremy Soller <jackpot51@gmail.com>2016-11-03 08:52:48 -0600
commit74dc845c2de24924f143e345358103102c9f8ed5 (patch)
treed6ce59e7b1dec09d462b9a215393ceeac7cf618e /src/libstd
parent123d08b3d3901d5725af8303c1329b007089cde5 (diff)
parentac919fcd9d4a958baf99b2f2ed5c3d38a2ebf9d0 (diff)
downloadrust-74dc845c2de24924f143e345358103102c9f8ed5.tar.gz
rust-74dc845c2de24924f143e345358103102c9f8ed5.zip
Merge branch 'master' into redox
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/collections/hash/table.rs73
-rw-r--r--src/libstd/error.rs4
-rw-r--r--src/libstd/f32.rs (renamed from src/libstd/num/f32.rs)0
-rw-r--r--src/libstd/f64.rs (renamed from src/libstd/num/f64.rs)0
-rw-r--r--src/libstd/io/cursor.rs16
-rw-r--r--src/libstd/io/mod.rs2
-rw-r--r--src/libstd/io/stdio.rs10
-rw-r--r--src/libstd/lib.rs150
-rw-r--r--src/libstd/num.rs (renamed from src/libstd/num/mod.rs)0
-rw-r--r--src/libstd/panic.rs42
-rw-r--r--src/libstd/path.rs1
-rw-r--r--src/libstd/rand/mod.rs2
-rw-r--r--src/libstd/sys/mod.rs45
-rw-r--r--src/libstd/sys/unix/fast_thread_local.rs167
-rw-r--r--src/libstd/sys/unix/mod.rs12
-rw-r--r--src/libstd/sys/unix/stdio.rs1
-rw-r--r--src/libstd/sys/windows/mod.rs20
-rw-r--r--src/libstd/sys/windows/stdio.rs5
-rw-r--r--src/libstd/sys_common/at_exit_imp.rs (renamed from src/libstd/sys/common/at_exit_imp.rs)0
-rw-r--r--src/libstd/sys_common/backtrace.rs (renamed from src/libstd/sys/common/backtrace.rs)0
-rw-r--r--src/libstd/sys_common/condvar.rs (renamed from src/libstd/sys/common/condvar.rs)0
-rw-r--r--src/libstd/sys_common/gnu/libbacktrace.rs (renamed from src/libstd/sys/common/gnu/libbacktrace.rs)0
-rw-r--r--src/libstd/sys_common/gnu/mod.rs (renamed from src/libstd/sys/common/gnu/mod.rs)0
-rw-r--r--src/libstd/sys_common/io.rs (renamed from src/libstd/sys/common/io.rs)2
-rw-r--r--src/libstd/sys_common/memchr.rs (renamed from src/libstd/sys/common/memchr.rs)0
-rw-r--r--src/libstd/sys_common/mod.rs (renamed from src/libstd/sys/common/mod.rs)30
-rw-r--r--src/libstd/sys_common/mutex.rs (renamed from src/libstd/sys/common/mutex.rs)0
-rw-r--r--src/libstd/sys_common/net.rs (renamed from src/libstd/sys/common/net.rs)0
-rw-r--r--src/libstd/sys_common/poison.rs (renamed from src/libstd/sys/common/poison.rs)0
-rw-r--r--src/libstd/sys_common/remutex.rs (renamed from src/libstd/sys/common/remutex.rs)0
-rw-r--r--src/libstd/sys_common/rwlock.rs (renamed from src/libstd/sys/common/rwlock.rs)0
-rw-r--r--src/libstd/sys_common/thread.rs (renamed from src/libstd/sys/common/thread.rs)0
-rw-r--r--src/libstd/sys_common/thread_info.rs (renamed from src/libstd/sys/common/thread_info.rs)0
-rw-r--r--src/libstd/sys_common/thread_local.rs (renamed from src/libstd/sys/common/thread_local.rs)0
-rw-r--r--src/libstd/sys_common/util.rs (renamed from src/libstd/sys/common/util.rs)34
-rw-r--r--src/libstd/sys_common/wtf8.rs (renamed from src/libstd/sys/common/wtf8.rs)0
-rw-r--r--src/libstd/thread/local.rs163
-rw-r--r--src/libstd/thread/mod.rs11
38 files changed, 452 insertions, 338 deletions
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index b357bc3552a..a784d8e50f9 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -21,7 +21,18 @@ use ptr::{self, Unique, Shared};
 
 use self::BucketState::*;
 
-const EMPTY_BUCKET: u64 = 0;
+/// Integer type used for stored hash values.
+///
+/// No more than bit_width(usize) bits are needed to select a bucket.
+///
+/// The most significant bit is ours to use for tagging `SafeHash`.
+///
+/// (Even if we could have usize::MAX bytes allocated for buckets,
+/// each bucket stores at least a `HashUint`, so there can be no more than
+/// usize::MAX / size_of(usize) buckets.)
+type HashUint = usize;
+
+const EMPTY_BUCKET: HashUint = 0;
 
 /// The raw hashtable, providing safe-ish access to the unzipped and highly
 /// optimized arrays of hashes, and key-value pairs.
@@ -64,7 +75,7 @@ const EMPTY_BUCKET: u64 = 0;
 pub struct RawTable<K, V> {
     capacity: usize,
     size: usize,
-    hashes: Unique<u64>,
+    hashes: Unique<HashUint>,
 
     // Because K/V do not appear directly in any of the types in the struct,
     // inform rustc that in fact instances of K and V are reachable from here.
@@ -75,7 +86,7 @@ unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {}
 unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {}
 
 struct RawBucket<K, V> {
-    hash: *mut u64,
+    hash: *mut HashUint,
     // We use *const to ensure covariance with respect to K and V
     pair: *const (K, V),
     _marker: marker::PhantomData<(K, V)>,
@@ -113,10 +124,6 @@ pub struct FullBucket<K, V, M> {
     table: M,
 }
 
-pub type EmptyBucketImm<'table, K, V> = EmptyBucket<K, V, &'table RawTable<K, V>>;
-pub type FullBucketImm<'table, K, V> = FullBucket<K, V, &'table RawTable<K, V>>;
-
-pub type EmptyBucketMut<'table, K, V> = EmptyBucket<K, V, &'table mut RawTable<K, V>>;
 pub type FullBucketMut<'table, K, V> = FullBucket<K, V, &'table mut RawTable<K, V>>;
 
 pub enum BucketState<K, V, M> {
@@ -136,15 +143,27 @@ pub struct GapThenFull<K, V, M> {
 /// buckets.
 #[derive(PartialEq, Copy, Clone)]
 pub struct SafeHash {
-    hash: u64,
+    hash: HashUint,
 }
 
 impl SafeHash {
     /// Peek at the hash value, which is guaranteed to be non-zero.
     #[inline(always)]
-    pub fn inspect(&self) -> u64 {
+    pub fn inspect(&self) -> HashUint {
         self.hash
     }
+
+    #[inline(always)]
+    pub fn new(hash: u64) -> Self {
+        // We need to avoid 0 in order to prevent collisions with
+        // EMPTY_HASH. We can maintain our precious uniform distribution
+        // of initial indexes by unconditionally setting the MSB,
+        // effectively reducing the hashes by one bit.
+        //
+        // Truncate hash to fit in `HashUint`.
+        let hash_bits = size_of::<HashUint>() * 8;
+        SafeHash { hash: (1 << (hash_bits - 1)) | (hash as HashUint) }
+    }
 }
 
 /// We need to remove hashes of 0. That's reserved for empty buckets.
@@ -156,25 +175,21 @@ pub fn make_hash<T: ?Sized, S>(hash_state: &S, t: &T) -> SafeHash
 {
     let mut state = hash_state.build_hasher();
     t.hash(&mut state);
-    // We need to avoid 0 in order to prevent collisions with
-    // EMPTY_HASH. We can maintain our precious uniform distribution
-    // of initial indexes by unconditionally setting the MSB,
-    // effectively reducing 64-bits hashes to 63 bits.
-    SafeHash { hash: 0x8000_0000_0000_0000 | state.finish() }
+    SafeHash::new(state.finish())
 }
 
-// `replace` casts a `*u64` to a `*SafeHash`. Since we statically
+// `replace` casts a `*HashUint` to a `*SafeHash`. Since we statically
 // ensure that a `FullBucket` points to an index with a non-zero hash,
-// and a `SafeHash` is just a `u64` with a different name, this is
+// and a `SafeHash` is just a `HashUint` with a different name, this is
 // safe.
 //
 // This test ensures that a `SafeHash` really IS the same size as a
-// `u64`. If you need to change the size of `SafeHash` (and
+// `HashUint`. If you need to change the size of `SafeHash` (and
 // consequently made this test fail), `replace` needs to be
 // modified to no longer assume this.
 #[test]
-fn can_alias_safehash_as_u64() {
-    assert_eq!(size_of::<SafeHash>(), size_of::<u64>())
+fn can_alias_safehash_as_hash() {
+    assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>())
 }
 
 impl<K, V> RawBucket<K, V> {
@@ -605,14 +620,14 @@ impl<K, V> RawTable<K, V> {
             return RawTable {
                 size: 0,
                 capacity: 0,
-                hashes: Unique::new(EMPTY as *mut u64),
+                hashes: Unique::new(EMPTY as *mut HashUint),
                 marker: marker::PhantomData,
             };
         }
 
         // No need for `checked_mul` before a more restrictive check performed
         // later in this method.
-        let hashes_size = capacity.wrapping_mul(size_of::<u64>());
+        let hashes_size = capacity.wrapping_mul(size_of::<HashUint>());
         let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>());
 
         // Allocating hashmaps is a little tricky. We need to allocate two
@@ -624,13 +639,13 @@ impl<K, V> RawTable<K, V> {
         // right is a little subtle. Therefore, calculating offsets has been
         // factored out into a different function.
         let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
-                                                                        align_of::<u64>(),
+                                                                        align_of::<HashUint>(),
                                                                         pairs_size,
                                                                         align_of::<(K, V)>());
         assert!(!oflo, "capacity overflow");
 
         // One check for overflow that covers calculation and rounding of size.
-        let size_of_bucket = size_of::<u64>().checked_add(size_of::<(K, V)>()).unwrap();
+        let size_of_bucket = size_of::<HashUint>().checked_add(size_of::<(K, V)>()).unwrap();
         assert!(size >=
                 capacity.checked_mul(size_of_bucket)
                     .expect("capacity overflow"),
@@ -641,7 +656,7 @@ impl<K, V> RawTable<K, V> {
             ::alloc::oom()
         }
 
-        let hashes = buffer.offset(hash_offset as isize) as *mut u64;
+        let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
 
         RawTable {
             capacity: capacity,
@@ -652,7 +667,7 @@ impl<K, V> RawTable<K, V> {
     }
 
     fn first_bucket_raw(&self) -> RawBucket<K, V> {
-        let hashes_size = self.capacity * size_of::<u64>();
+        let hashes_size = self.capacity * size_of::<HashUint>();
         let pairs_size = self.capacity * size_of::<(K, V)>();
 
         let buffer = *self.hashes as *mut u8;
@@ -756,7 +771,7 @@ impl<K, V> RawTable<K, V> {
 /// this interface is safe, it's not used outside this module.
 struct RawBuckets<'a, K, V> {
     raw: RawBucket<K, V>,
-    hashes_end: *mut u64,
+    hashes_end: *mut HashUint,
 
     // Strictly speaking, this should be &'a (K,V), but that would
     // require that K:'a, and we often use RawBuckets<'static...> for
@@ -802,7 +817,7 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> {
 /// the table's remaining entries. It's used in the implementation of Drop.
 struct RevMoveBuckets<'a, K, V> {
     raw: RawBucket<K, V>,
-    hashes_end: *mut u64,
+    hashes_end: *mut HashUint,
     elems_left: usize,
 
     // As above, `&'a (K,V)` would seem better, but we often use
@@ -1036,10 +1051,10 @@ impl<K, V> Drop for RawTable<K, V> {
             }
         }
 
-        let hashes_size = self.capacity * size_of::<u64>();
+        let hashes_size = self.capacity * size_of::<HashUint>();
         let pairs_size = self.capacity * size_of::<(K, V)>();
         let (align, _, size, oflo) = calculate_allocation(hashes_size,
-                                                          align_of::<u64>(),
+                                                          align_of::<HashUint>(),
                                                           pairs_size,
                                                           align_of::<(K, V)>());
 
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index a1909b0f957..454fa47cfbc 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -69,7 +69,9 @@ pub trait Error: Debug + Display {
     /// It should not contain newlines or sentence-ending punctuation,
     /// to facilitate embedding in larger user-facing strings.
     /// For showing formatted error messages with more information see
-    /// [Display](https://doc.rust-lang.org/std/fmt/trait.Display.html).
+    /// [`Display`].
+    ///
+    /// [`Display`]: ../fmt/trait.Display.html
     ///
     /// # Examples
     ///
diff --git a/src/libstd/num/f32.rs b/src/libstd/f32.rs
index 7a676c041ad..7a676c041ad 100644
--- a/src/libstd/num/f32.rs
+++ b/src/libstd/f32.rs
diff --git a/src/libstd/num/f64.rs b/src/libstd/f64.rs
index 67a1c302483..67a1c302483 100644
--- a/src/libstd/num/f64.rs
+++ b/src/libstd/f64.rs
diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs
index ca9452ffe3e..1b5023380a7 100644
--- a/src/libstd/io/cursor.rs
+++ b/src/libstd/io/cursor.rs
@@ -23,7 +23,7 @@ use io::{self, SeekFrom, Error, ErrorKind};
 ///
 /// The standard library implements some I/O traits on various types which
 /// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
-/// `Cursor<`[`&[u8]`]`>`.
+/// `Cursor<`[`&[u8]`][bytes]`>`.
 ///
 /// # Examples
 ///
@@ -35,7 +35,7 @@ use io::{self, SeekFrom, Error, ErrorKind};
 /// [`Read`]: ../../std/io/trait.Read.html
 /// [`Write`]: ../../std/io/trait.Write.html
 /// [`Vec`]: ../../std/vec/struct.Vec.html
-/// [`&[u8]`]: ../../std/primitive.slice.html
+/// [bytes]: ../../std/primitive.slice.html
 /// [`File`]: ../fs/struct.File.html
 ///
 /// ```no_run
@@ -392,7 +392,7 @@ mod tests {
 
     #[test]
     fn test_mem_reader() {
-        let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
+        let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
         let mut buf = [];
         assert_eq!(reader.read(&mut buf).unwrap(), 0);
         assert_eq!(reader.position(), 0);
@@ -414,7 +414,7 @@ mod tests {
 
     #[test]
     fn test_boxed_slice_reader() {
-        let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7).into_boxed_slice());
+        let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice());
         let mut buf = [];
         assert_eq!(reader.read(&mut buf).unwrap(), 0);
         assert_eq!(reader.position(), 0);
@@ -436,7 +436,7 @@ mod tests {
 
     #[test]
     fn read_to_end() {
-        let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
+        let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]);
         let mut v = Vec::new();
         reader.read_to_end(&mut v).unwrap();
         assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
@@ -512,7 +512,7 @@ mod tests {
         assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
         assert_eq!(r.read(&mut [0]).unwrap(), 0);
 
-        let mut r = Cursor::new(vec!(10));
+        let mut r = Cursor::new(vec![10]);
         assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
         assert_eq!(r.read(&mut [0]).unwrap(), 0);
 
@@ -532,14 +532,14 @@ mod tests {
         let mut r = Cursor::new(&buf[..]);
         assert!(r.seek(SeekFrom::End(-2)).is_err());
 
-        let mut r = Cursor::new(vec!(10));
+        let mut r = Cursor::new(vec![10]);
         assert!(r.seek(SeekFrom::End(-2)).is_err());
 
         let mut buf = [0];
         let mut r = Cursor::new(&mut buf[..]);
         assert!(r.seek(SeekFrom::End(-2)).is_err());
 
-        let mut r = Cursor::new(vec!(10).into_boxed_slice());
+        let mut r = Cursor::new(vec![10].into_boxed_slice());
         assert!(r.seek(SeekFrom::End(-2)).is_err());
     }
 
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 37c3f70d54d..193f396c0d4 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -289,7 +289,7 @@ mod lazy;
 mod util;
 mod stdio;
 
-const DEFAULT_BUF_SIZE: usize = 8 * 1024;
+const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
 
 // 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
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index c24ee8ff303..1777b79ea1b 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -214,15 +214,7 @@ pub fn stdin() -> Stdin {
             _ => Maybe::Fake
         };
 
-        // The default buffer capacity is 64k, but apparently windows
-        // doesn't like 64k reads on stdin. See #13304 for details, but the
-        // idea is that on windows we use a slightly smaller buffer that's
-        // been seen to be acceptable.
-        Arc::new(Mutex::new(if cfg!(windows) {
-            BufReader::with_capacity(8 * 1024, stdin)
-        } else {
-            BufReader::new(stdin)
-        }))
+        Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin)))
     }
 }
 
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 82a719693ec..8d973fc1ade 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -210,14 +210,34 @@
        test(no_crate_inject, attr(deny(warnings))),
        test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
 
+// Don't link to std. We are std.
+#![no_std]
+
+#![deny(missing_docs)]
+
+// Tell the compiler to link to either panic_abort or panic_unwind
 #![needs_panic_runtime]
 
+// Always use alloc_system during stage0 since jemalloc might be unavailable or
+// disabled (Issue #30592)
+#![cfg_attr(stage0, feature(alloc_system))]
+
+// Turn warnings into errors, but only after stage0, where it can be useful for
+// code to emit warnings during language transitions
+#![cfg_attr(not(stage0), deny(warnings))]
+
+// std may use features in a platform-specific way
+#![allow(unused_features)]
+
+// std is implemented with unstable features, many of which are internal
+// compiler details that will never be stable
 #![feature(alloc)]
 #![feature(allow_internal_unstable)]
 #![feature(asm)]
 #![feature(associated_consts)]
 #![feature(borrow_state)]
 #![feature(box_syntax)]
+#![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
 #![feature(cfg_target_vendor)]
 #![feature(char_escape_debug)]
@@ -240,13 +260,13 @@
 #![feature(heap_api)]
 #![feature(inclusive_range)]
 #![feature(int_error_internals)]
+#![feature(integer_atomics)]
 #![feature(into_cow)]
 #![feature(lang_items)]
 #![feature(libc)]
 #![feature(link_args)]
 #![feature(linkage)]
 #![feature(macro_reexport)]
-#![cfg_attr(test, feature(map_values_mut))]
 #![feature(needs_panic_runtime)]
 #![feature(num_bits_bytes)]
 #![feature(old_wrapping)]
@@ -282,21 +302,13 @@
 #![feature(zero_one)]
 #![cfg_attr(test, feature(update_panic_count))]
 
-// Issue# 30592: Systematically use alloc_system during stage0 since jemalloc
-// might be unavailable or disabled
-#![cfg_attr(stage0, feature(alloc_system))]
-
-// Don't link to std. We are std.
-#![no_std]
-
-#![deny(missing_docs)]
-#![allow(unused_features)] // std may use features in a platform-specific way
-#![cfg_attr(not(stage0), deny(warnings))]
-
+// Explicitly import the prelude. The compiler uses this same unstable attribute
+// to import the prelude implicitly when building crates that depend on std.
 #[prelude_import]
 #[allow(unused)]
 use prelude::v1::*;
 
+// Access to Bencher, etc.
 #[cfg(test)] extern crate test;
 
 // We want to reexport a few macros from core but libcore has already been
@@ -324,11 +336,22 @@ extern crate alloc_system;
 // compiler-rt intrinsics
 extern crate compiler_builtins;
 
-// Make std testable by not duplicating lang items and other globals. See #2912
+// During testing, this crate is not actually the "real" std library, but rather
+// it links to the real std library, which was compiled from this same source
+// code. So any lang items std defines are conditionally excluded (or else they
+// wolud generate duplicate lang item errors), and any globals it defines are
+// _not_ the globals used by "real" std. So this import, defined only during
+// testing gives test-std access to real-std lang items and globals. See #2912
 #[cfg(test)] extern crate std as realstd;
 
-// NB: These reexports are in the order they should be listed in rustdoc
+// The standard macros that are not built-in to the compiler.
+#[macro_use]
+mod macros;
+
+// The Rust prelude
+pub mod prelude;
 
+// Public module declarations and reexports
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::any;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -361,48 +384,6 @@ pub use core::raw;
 pub use core::result;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::option;
-
-pub mod error;
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc::boxed;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use alloc::rc;
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use core_collections::borrow;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use core_collections::fmt;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use core_collections::slice;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use core_collections::str;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use core_collections::string;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use core_collections::vec;
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use rustc_unicode::char;
-
-/* Exported macros */
-
-#[macro_use]
-mod macros;
-
-mod rtdeps;
-
-/* The Prelude. */
-
-pub mod prelude;
-
-
-/* Primitive types */
-
-// NB: slice and str are primitive types too, but their module docs + primitive
-// doc pages are inlined from the public re-exports of core_collections::{slice,
-// str} above.
-
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::isize;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -413,7 +394,6 @@ pub use core::i16;
 pub use core::i32;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::i64;
-
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::usize;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -424,48 +404,62 @@ pub use core::u16;
 pub use core::u32;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::u64;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc::boxed;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use alloc::rc;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core_collections::borrow;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core_collections::fmt;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core_collections::slice;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core_collections::str;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core_collections::string;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core_collections::vec;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use rustc_unicode::char;
 
-#[path = "num/f32.rs"]   pub mod f32;
-#[path = "num/f64.rs"]   pub mod f64;
-
-pub mod ascii;
-
-/* Common traits */
-
-pub mod num;
-
-/* Runtime and platform support */
+pub mod f32;
+pub mod f64;
 
 #[macro_use]
 pub mod thread;
-
+pub mod ascii;
 pub mod collections;
 pub mod env;
+pub mod error;
 pub mod ffi;
 pub mod fs;
 pub mod io;
 pub mod net;
+pub mod num;
 pub mod os;
 pub mod panic;
 pub mod path;
 pub mod process;
 pub mod sync;
 pub mod time;
-mod memchr;
 
+// Platform-abstraction modules
 #[macro_use]
-#[path = "sys/common/mod.rs"] mod sys_common;
-
-#[cfg(redox)]
-#[path = "sys/redox/mod.rs"] mod sys;
-#[cfg(unix)]
-#[path = "sys/unix/mod.rs"] mod sys;
-#[cfg(windows)]
-#[path = "sys/windows/mod.rs"] mod sys;
+mod sys_common;
+mod sys;
 
-pub mod rt;
+// Private support modules
 mod panicking;
 mod rand;
+mod memchr;
+
+// This module just defines per-platform native library dependencies
+mod rtdeps;
+
+// The runtime entry point and a few unstable public functions used by the
+// compiler
+pub mod rt;
 
 // Some external utilities of the standard library rely on randomness (aka
 // rustc_back::TempDir and tests) and need a way to get at the OS rng we've got
diff --git a/src/libstd/num/mod.rs b/src/libstd/num.rs
index d1c2fc3d3fc..d1c2fc3d3fc 100644
--- a/src/libstd/num/mod.rs
+++ b/src/libstd/num.rs
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
index 3788568a2fd..a7e8c4fab37 100644
--- a/src/libstd/panic.rs
+++ b/src/libstd/panic.rs
@@ -18,7 +18,7 @@ use ops::{Deref, DerefMut};
 use panicking;
 use ptr::{Unique, Shared};
 use rc::Rc;
-use sync::{Arc, Mutex, RwLock};
+use sync::{Arc, Mutex, RwLock, atomic};
 use thread::Result;
 
 #[stable(feature = "panic_hooks", since = "1.10.0")]
@@ -231,6 +231,46 @@ impl<T: ?Sized> RefUnwindSafe for Mutex<T> {}
 #[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
 impl<T: ?Sized> RefUnwindSafe for RwLock<T> {}
 
+#[cfg(target_has_atomic = "ptr")]
+#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+impl RefUnwindSafe for atomic::AtomicIsize {}
+#[cfg(target_has_atomic = "8")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI8 {}
+#[cfg(target_has_atomic = "16")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI16 {}
+#[cfg(target_has_atomic = "32")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI32 {}
+#[cfg(target_has_atomic = "64")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI64 {}
+
+#[cfg(target_has_atomic = "ptr")]
+#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+impl RefUnwindSafe for atomic::AtomicUsize {}
+#[cfg(target_has_atomic = "8")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU8 {}
+#[cfg(target_has_atomic = "16")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU16 {}
+#[cfg(target_has_atomic = "32")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU32 {}
+#[cfg(target_has_atomic = "64")]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU64 {}
+
+#[cfg(target_has_atomic = "8")]
+#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+impl RefUnwindSafe for atomic::AtomicBool {}
+
+#[cfg(target_has_atomic = "ptr")]
+#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+impl<T> RefUnwindSafe for atomic::AtomicPtr<T> {}
+
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl<T> Deref for AssertUnwindSafe<T> {
     type Target = T;
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index a55318d3883..9b7f9980cc0 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -914,6 +914,7 @@ impl<'a> cmp::Ord for Components<'a> {
 /// [`Path`]: struct.Path.html
 /// [`push`]: struct.PathBuf.html#method.push
 /// [`set_extension`]: struct.PathBuf.html#method.set_extension
+/// [`Deref`]: ../ops/trait.Deref.html
 ///
 /// More details about the overall approach can be found in
 /// the module documentation.
diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs
index 69cd37651d5..f48325218fb 100644
--- a/src/libstd/rand/mod.rs
+++ b/src/libstd/rand/mod.rs
@@ -245,7 +245,7 @@ mod tests {
     #[cfg_attr(target_os = "emscripten", ignore)]
     fn test_os_rng_tasks() {
 
-        let mut txs = vec!();
+        let mut txs = vec![];
         for _ in 0..20 {
             let (tx, rx) = channel();
             txs.push(tx);
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
new file mode 100644
index 00000000000..c196bf39432
--- /dev/null
+++ b/src/libstd/sys/mod.rs
@@ -0,0 +1,45 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <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.
+
+//! Platform-dependent platform abstraction
+//!
+//! The `std::sys` module is the abstracted interface through which
+//! `std` talks to the underlying operating system. It has different
+//! implementations for different operating system families, today
+//! just Unix and Windows.
+//!
+//! The centralization of platform-specific code in this module is
+//! enforced by the "platform abstraction layer" tidy script in
+//! `tools/tidy/pal.rs`.
+//!
+//! This module is closely related to the platform-independent system
+//! integration code in `std::sys_common`. See that module's
+//! documentation for details.
+//!
+//! In the future it would be desirable for the indepedent
+//! implementations of this module to be extracted to their own crates
+//! that `std` can link to, thus enabling their implementation
+//! out-of-tree via crate replacement. Though due to the complex
+//! inter-dependencies within `std` that will be a challenging goal to
+//! achieve.
+
+pub use self::imp::*;
+
+#[cfg(redox)]
+#[path = "redox/mod.rs"]
+mod imp;
+
+#[cfg(unix)]
+#[path = "unix/mod.rs"]
+mod imp;
+
+#[cfg(windows)]
+#[path = "windows/mod.rs"]
+mod imp;
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
new file mode 100644
index 00000000000..0c625e7add9
--- /dev/null
+++ b/src/libstd/sys/unix/fast_thread_local.rs
@@ -0,0 +1,167 @@
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <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.
+
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+use cell::{Cell, UnsafeCell};
+use intrinsics;
+use ptr;
+
+pub struct Key<T> {
+    inner: UnsafeCell<Option<T>>,
+
+    // Metadata to keep track of the state of the destructor. Remember that
+    // these variables are thread-local, not global.
+    dtor_registered: Cell<bool>,
+    dtor_running: Cell<bool>,
+}
+
+unsafe impl<T> ::marker::Sync for Key<T> { }
+
+impl<T> Key<T> {
+    pub const fn new() -> Key<T> {
+        Key {
+            inner: UnsafeCell::new(None),
+            dtor_registered: Cell::new(false),
+            dtor_running: Cell::new(false)
+        }
+    }
+
+    pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
+        unsafe {
+            if intrinsics::needs_drop::<T>() && self.dtor_running.get() {
+                return None
+            }
+            self.register_dtor();
+        }
+        Some(&self.inner)
+    }
+
+    unsafe fn register_dtor(&self) {
+        if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() {
+            return
+        }
+
+        register_dtor(self as *const _ as *mut u8,
+                      destroy_value::<T>);
+        self.dtor_registered.set(true);
+    }
+}
+
+#[cfg(any(target_os = "linux", target_os = "fuchsia"))]
+unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+    // The fallback implementation uses a vanilla OS-based TLS key to track
+    // the list of destructors that need to be run for this thread. The key
+    // then has its own destructor which runs all the other destructors.
+    //
+    // The destructor for DTORS is a little special in that it has a `while`
+    // loop to continuously drain the list of registered destructors. It
+    // *should* be the case that this loop always terminates because we
+    // provide the guarantee that a TLS key cannot be set after it is
+    // flagged for destruction.
+    use sys_common::thread_local as os;
+
+    static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors));
+    type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+    if DTORS.get().is_null() {
+        let v: Box<List> = box Vec::new();
+        DTORS.set(Box::into_raw(v) as *mut u8);
+    }
+    let list: &mut List = &mut *(DTORS.get() as *mut List);
+    list.push((t, dtor));
+
+    unsafe extern fn run_dtors(mut ptr: *mut u8) {
+        while !ptr.is_null() {
+            let list: Box<List> = Box::from_raw(ptr as *mut List);
+            for &(ptr, dtor) in list.iter() {
+                dtor(ptr);
+            }
+            ptr = DTORS.get();
+            DTORS.set(ptr::null_mut());
+        }
+    }
+}
+
+// Since what appears to be glibc 2.18 this symbol has been shipped which
+// GCC and clang both use to invoke destructors in thread_local globals, so
+// let's do the same!
+//
+// Note, however, that we run on lots older linuxes, as well as cross
+// compiling from a newer linux to an older linux, so we also have a
+// fallback implementation to use as well.
+//
+// Due to rust-lang/rust#18804, make sure this is not generic!
+#[cfg(target_os = "linux")]
+unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+    use mem;
+    use libc;
+
+    extern {
+        #[linkage = "extern_weak"]
+        static __dso_handle: *mut u8;
+        #[linkage = "extern_weak"]
+        static __cxa_thread_atexit_impl: *const libc::c_void;
+    }
+    if !__cxa_thread_atexit_impl.is_null() {
+        type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
+                                  arg: *mut u8,
+                                  dso_handle: *mut u8) -> libc::c_int;
+        mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
+            (dtor, t, &__dso_handle as *const _ as *mut _);
+        return
+    }
+    register_dtor_fallback(t, dtor);
+}
+
+// OSX's analog of the above linux function is this _tlv_atexit function.
+// The disassembly of thread_local globals in C++ (at least produced by
+// clang) will have this show up in the output.
+#[cfg(target_os = "macos")]
+unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+    extern {
+        fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
+                       arg: *mut u8);
+    }
+    _tlv_atexit(dtor, t);
+}
+
+// Just use the thread_local fallback implementation, at least until there's
+// a more direct implementation.
+#[cfg(target_os = "fuchsia")]
+unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+    register_dtor_fallback(t, dtor);
+}
+
+pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
+    let ptr = ptr as *mut Key<T>;
+    // Right before we run the user destructor be sure to flag the
+    // destructor as running for this thread so calls to `get` will return
+    // `None`.
+    (*ptr).dtor_running.set(true);
+
+    // The OSX implementation of TLS apparently had an odd aspect to it
+    // where the pointer we have may be overwritten while this destructor
+    // is running. Specifically if a TLS destructor re-accesses TLS it may
+    // trigger a re-initialization of all TLS variables, paving over at
+    // least some destroyed ones with initial values.
+    //
+    // This means that if we drop a TLS value in place on OSX that we could
+    // revert the value to its original state halfway through the
+    // destructor, which would be bad!
+    //
+    // Hence, we use `ptr::read` on OSX (to move to a "safe" location)
+    // instead of drop_in_place.
+    if cfg!(target_os = "macos") {
+        ptr::read((*ptr).inner.get());
+    } else {
+        ptr::drop_in_place((*ptr).inner.get());
+    }
+}
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index 66bc9d4a491..fd7dc17cccd 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -38,6 +38,7 @@ pub mod backtrace;
 pub mod condvar;
 pub mod env;
 pub mod ext;
+pub mod fast_thread_local;
 pub mod fd;
 pub mod fs;
 pub mod memchr;
@@ -162,3 +163,14 @@ pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
         }
     }
 }
+
+// On Unix-like platforms, libc::abort will unregister signal handlers
+// including the SIGABRT handler, preventing the abort from being blocked, and
+// fclose streams, with the side effect of flushing them so libc bufferred
+// output will be printed.  Additionally the shell will generally print a more
+// understandable error message like "Abort trap" rather than "Illegal
+// instruction" that intrinsics::abort would cause, as intrinsics::abort is
+// implemented as an illegal instruction.
+pub unsafe fn abort_internal() -> ! {
+    ::libc::abort()
+}
diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs
index 947ba2cc752..273341b1918 100644
--- a/src/libstd/sys/unix/stdio.rs
+++ b/src/libstd/sys/unix/stdio.rs
@@ -67,3 +67,4 @@ impl io::Write for Stderr {
 }
 
 pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
+pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 9cd6e6ca176..defc41c5f46 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -179,7 +179,7 @@ pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
     }
 }
 
-trait IsZero {
+pub trait IsZero {
     fn is_zero(&self) -> bool;
 }
 
@@ -193,7 +193,7 @@ macro_rules! impl_is_zero {
 
 impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
 
-fn cvt<I: IsZero>(i: I) -> io::Result<I> {
+pub fn cvt<I: IsZero>(i: I) -> io::Result<I> {
     if i.is_zero() {
         Err(io::Error::last_os_error())
     } else {
@@ -201,7 +201,7 @@ fn cvt<I: IsZero>(i: I) -> io::Result<I> {
     }
 }
 
-fn dur2timeout(dur: Duration) -> c::DWORD {
+pub fn dur2timeout(dur: Duration) -> c::DWORD {
     // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
     // timeouts in windows APIs are typically u32 milliseconds. To translate, we
     // have two pieces to take care of:
@@ -221,3 +221,17 @@ fn dur2timeout(dur: Duration) -> c::DWORD {
         }
     }).unwrap_or(c::INFINITE)
 }
+
+// On Windows, use the processor-specific __fastfail mechanism.  In Windows 8
+// and later, this will terminate the process immediately without running any
+// in-process exception handlers.  In earlier versions of Windows, this
+// sequence of instructions will be treated as an access violation,
+// terminating the process but without necessarily bypassing all exception
+// handlers.
+//
+// https://msdn.microsoft.com/en-us/library/dn774154.aspx
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub unsafe fn abort_internal() -> ! {
+    asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
+    ::intrinsics::unreachable();
+}
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index 5f097d2631d..72788776ded 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -207,3 +207,8 @@ fn invalid_encoding() -> io::Error {
 }
 
 pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
+// The default buffer capacity is 64k, but apparently windows
+// doesn't like 64k reads on stdin. See #13304 for details, but the
+// idea is that on windows we use a slightly smaller buffer that's
+// been seen to be acceptable.
+pub const STDIN_BUF_SIZE: usize = 8 * 1024;
diff --git a/src/libstd/sys/common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs
index ce6fd4cb075..ce6fd4cb075 100644
--- a/src/libstd/sys/common/at_exit_imp.rs
+++ b/src/libstd/sys_common/at_exit_imp.rs
diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys_common/backtrace.rs
index a8540fed928..a8540fed928 100644
--- a/src/libstd/sys/common/backtrace.rs
+++ b/src/libstd/sys_common/backtrace.rs
diff --git a/src/libstd/sys/common/condvar.rs b/src/libstd/sys_common/condvar.rs
index b6f29dd5fc3..b6f29dd5fc3 100644
--- a/src/libstd/sys/common/condvar.rs
+++ b/src/libstd/sys_common/condvar.rs
diff --git a/src/libstd/sys/common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs
index b5802afc109..b5802afc109 100644
--- a/src/libstd/sys/common/gnu/libbacktrace.rs
+++ b/src/libstd/sys_common/gnu/libbacktrace.rs
diff --git a/src/libstd/sys/common/gnu/mod.rs b/src/libstd/sys_common/gnu/mod.rs
index 3a8cf2d8425..3a8cf2d8425 100644
--- a/src/libstd/sys/common/gnu/mod.rs
+++ b/src/libstd/sys_common/gnu/mod.rs
diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys_common/io.rs
index 0483725dd83..23daeeb5187 100644
--- a/src/libstd/sys/common/io.rs
+++ b/src/libstd/sys_common/io.rs
@@ -12,6 +12,8 @@ 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
diff --git a/src/libstd/sys/common/memchr.rs b/src/libstd/sys_common/memchr.rs
index 3824a5fb528..3824a5fb528 100644
--- a/src/libstd/sys/common/memchr.rs
+++ b/src/libstd/sys_common/memchr.rs
diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys_common/mod.rs
index 274f3c10d9c..bbd2f679bca 100644
--- a/src/libstd/sys/common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -8,23 +8,25 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Platform-independent platform abstraction
+//!
+//! This is the platform-independent portion of the standard libraries
+//! platform abstraction layer, whereas `std::sys` is the
+//! platform-specific portion.
+//!
+//! The relationship between `std::sys_common`, `std::sys` and the
+//! rest of `std` is complex, with dependencies going in all
+//! directions: `std` depending on `sys_common`, `sys_common`
+//! depending on `sys`, and `sys` depending on `sys_common` and `std`.
+//! Ideally `sys_common` would be split into two and the dependencies
+//! between them all would form a dag, facilitating the extraction of
+//! `std::sys` from the standard library.
+
 #![allow(missing_docs)]
 
 use sync::Once;
 use sys;
 
-macro_rules! rtabort {
-    ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*)))
-}
-
-macro_rules! rtassert {
-    ($e:expr) => ({
-        if !$e {
-            rtabort!(concat!("assertion failed: ", stringify!($e)))
-        }
-    })
-}
-
 pub mod at_exit_imp;
 #[cfg(any(not(cargobuild), feature = "backtrace"))]
 pub mod backtrace;
@@ -92,6 +94,10 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
     if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
 }
 
+macro_rules! rtabort {
+    ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*)))
+}
+
 /// One-time runtime cleanup.
 pub fn cleanup() {
     static CLEANUP: Once = Once::new();
diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys_common/mutex.rs
index d1a738770d3..d1a738770d3 100644
--- a/src/libstd/sys/common/mutex.rs
+++ b/src/libstd/sys_common/mutex.rs
diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys_common/net.rs
index 10ad61f4c80..10ad61f4c80 100644
--- a/src/libstd/sys/common/net.rs
+++ b/src/libstd/sys_common/net.rs
diff --git a/src/libstd/sys/common/poison.rs b/src/libstd/sys_common/poison.rs
index bdc727f1dfc..bdc727f1dfc 100644
--- a/src/libstd/sys/common/poison.rs
+++ b/src/libstd/sys_common/poison.rs
diff --git a/src/libstd/sys/common/remutex.rs b/src/libstd/sys_common/remutex.rs
index 4d0407ccf6c..4d0407ccf6c 100644
--- a/src/libstd/sys/common/remutex.rs
+++ b/src/libstd/sys_common/remutex.rs
diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys_common/rwlock.rs
index 71a4f01ec4c..71a4f01ec4c 100644
--- a/src/libstd/sys/common/rwlock.rs
+++ b/src/libstd/sys_common/rwlock.rs
diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys_common/thread.rs
index 3ee160da5fa..3ee160da5fa 100644
--- a/src/libstd/sys/common/thread.rs
+++ b/src/libstd/sys_common/thread.rs
diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys_common/thread_info.rs
index 95d8b6cc951..95d8b6cc951 100644
--- a/src/libstd/sys/common/thread_info.rs
+++ b/src/libstd/sys_common/thread_info.rs
diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys_common/thread_local.rs
index 25a9d5720d9..25a9d5720d9 100644
--- a/src/libstd/sys/common/thread_local.rs
+++ b/src/libstd/sys_common/thread_local.rs
diff --git a/src/libstd/sys/common/util.rs b/src/libstd/sys_common/util.rs
index dda0abb4c0c..daa0c15920b 100644
--- a/src/libstd/sys/common/util.rs
+++ b/src/libstd/sys_common/util.rs
@@ -33,38 +33,6 @@ pub fn dumb_print(args: fmt::Arguments) {
     let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
 }
 
-// On Redox, use an illegal instruction
-#[cfg(redox)]
-unsafe fn abort_internal() -> ! {
-    ::intrinsics::abort()
-}
-
-// On Unix-like platforms, libc::abort will unregister signal handlers
-// including the SIGABRT handler, preventing the abort from being blocked, and
-// fclose streams, with the side effect of flushing them so libc bufferred
-// output will be printed.  Additionally the shell will generally print a more
-// understandable error message like "Abort trap" rather than "Illegal
-// instruction" that intrinsics::abort would cause, as intrinsics::abort is
-// implemented as an illegal instruction.
-#[cfg(unix)]
-unsafe fn abort_internal() -> ! {
-    ::libc::abort()
-}
-
-// On Windows, use the processor-specific __fastfail mechanism.  In Windows 8
-// and later, this will terminate the process immediately without running any
-// in-process exception handlers.  In earlier versions of Windows, this
-// sequence of instructions will be treated as an access violation,
-// terminating the process but without necessarily bypassing all exception
-// handlers.
-//
-// https://msdn.microsoft.com/en-us/library/dn774154.aspx
-#[cfg(all(windows, any(target_arch = "x86", target_arch = "x86_64")))]
-unsafe fn abort_internal() -> ! {
-    asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
-    ::intrinsics::unreachable();
-}
-
 // Other platforms should use the appropriate platform-specific mechanism for
 // aborting the process.  If no platform-specific mechanism is available,
 // ::intrinsics::abort() may be used instead.  The above implementations cover
@@ -72,7 +40,7 @@ unsafe fn abort_internal() -> ! {
 
 pub fn abort(args: fmt::Arguments) -> ! {
     dumb_print(format_args!("fatal runtime error: {}\n", args));
-    unsafe { abort_internal(); }
+    unsafe { ::sys::abort_internal(); }
 }
 
 #[allow(dead_code)] // stack overflow detection not enabled on all platforms
diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys_common/wtf8.rs
index 0a94ff1e958..0a94ff1e958 100644
--- a/src/libstd/sys/common/wtf8.rs
+++ b/src/libstd/sys_common/wtf8.rs
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index a1ae2c1cb42..f74dd592495 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -166,8 +166,8 @@ macro_rules! __thread_local_inner {
         {
             #[thread_local]
             #[cfg(target_thread_local)]
-            static __KEY: $crate::thread::__ElfLocalKeyInner<$t> =
-                $crate::thread::__ElfLocalKeyInner::new();
+            static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
+                $crate::thread::__FastLocalKeyInner::new();
 
             #[cfg(not(target_thread_local))]
             static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
@@ -310,165 +310,6 @@ impl<T: 'static> LocalKey<T> {
     }
 }
 
-#[cfg(target_thread_local)]
-#[doc(hidden)]
-pub mod elf {
-    use cell::{Cell, UnsafeCell};
-    use intrinsics;
-    use ptr;
-
-    pub struct Key<T> {
-        inner: UnsafeCell<Option<T>>,
-
-        // Metadata to keep track of the state of the destructor. Remember that
-        // these variables are thread-local, not global.
-        dtor_registered: Cell<bool>,
-        dtor_running: Cell<bool>,
-    }
-
-    unsafe impl<T> ::marker::Sync for Key<T> { }
-
-    impl<T> Key<T> {
-        pub const fn new() -> Key<T> {
-            Key {
-                inner: UnsafeCell::new(None),
-                dtor_registered: Cell::new(false),
-                dtor_running: Cell::new(false)
-            }
-        }
-
-        pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
-            unsafe {
-                if intrinsics::needs_drop::<T>() && self.dtor_running.get() {
-                    return None
-                }
-                self.register_dtor();
-            }
-            Some(&self.inner)
-        }
-
-        unsafe fn register_dtor(&self) {
-            if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() {
-                return
-            }
-
-            register_dtor(self as *const _ as *mut u8,
-                          destroy_value::<T>);
-            self.dtor_registered.set(true);
-        }
-    }
-
-    #[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
-    unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        // The fallback implementation uses a vanilla OS-based TLS key to track
-        // the list of destructors that need to be run for this thread. The key
-        // then has its own destructor which runs all the other destructors.
-        //
-        // The destructor for DTORS is a little special in that it has a `while`
-        // loop to continuously drain the list of registered destructors. It
-        // *should* be the case that this loop always terminates because we
-        // provide the guarantee that a TLS key cannot be set after it is
-        // flagged for destruction.
-        use sys_common::thread_local as os;
-
-        static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors));
-        type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
-        if DTORS.get().is_null() {
-            let v: Box<List> = box Vec::new();
-            DTORS.set(Box::into_raw(v) as *mut u8);
-        }
-        let list: &mut List = &mut *(DTORS.get() as *mut List);
-        list.push((t, dtor));
-
-        unsafe extern fn run_dtors(mut ptr: *mut u8) {
-            while !ptr.is_null() {
-                let list: Box<List> = Box::from_raw(ptr as *mut List);
-                for &(ptr, dtor) in list.iter() {
-                    dtor(ptr);
-                }
-                ptr = DTORS.get();
-                DTORS.set(ptr::null_mut());
-            }
-        }
-    }
-
-    // Since what appears to be glibc 2.18 this symbol has been shipped which
-    // GCC and clang both use to invoke destructors in thread_local globals, so
-    // let's do the same!
-    //
-    // Note, however, that we run on lots older linuxes, as well as cross
-    // compiling from a newer linux to an older linux, so we also have a
-    // fallback implementation to use as well.
-    //
-    // Due to rust-lang/rust#18804, make sure this is not generic!
-    #[cfg(target_os = "linux")]
-    unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        use mem;
-        use libc;
-
-        extern {
-            #[linkage = "extern_weak"]
-            static __dso_handle: *mut u8;
-            #[linkage = "extern_weak"]
-            static __cxa_thread_atexit_impl: *const libc::c_void;
-        }
-        if !__cxa_thread_atexit_impl.is_null() {
-            type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
-                                      arg: *mut u8,
-                                      dso_handle: *mut u8) -> libc::c_int;
-            mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
-            (dtor, t, &__dso_handle as *const _ as *mut _);
-            return
-        }
-        register_dtor_fallback(t, dtor);
-    }
-
-    // OSX's analog of the above linux function is this _tlv_atexit function.
-    // The disassembly of thread_local globals in C++ (at least produced by
-    // clang) will have this show up in the output.
-    #[cfg(target_os = "macos")]
-    unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        extern {
-            fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
-                           arg: *mut u8);
-        }
-        _tlv_atexit(dtor, t);
-    }
-
-    // Just use the thread_local fallback implementation, at least until there's
-    // a more direct implementation.
-    #[cfg(any(target_os = "fuchsia", target_os = "redox"))]
-    unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-        register_dtor_fallback(t, dtor);
-    }
-
-    pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
-        let ptr = ptr as *mut Key<T>;
-        // Right before we run the user destructor be sure to flag the
-        // destructor as running for this thread so calls to `get` will return
-        // `None`.
-        (*ptr).dtor_running.set(true);
-
-        // The OSX implementation of TLS apparently had an odd aspect to it
-        // where the pointer we have may be overwritten while this destructor
-        // is running. Specifically if a TLS destructor re-accesses TLS it may
-        // trigger a re-initialization of all TLS variables, paving over at
-        // least some destroyed ones with initial values.
-        //
-        // This means that if we drop a TLS value in place on OSX that we could
-        // revert the value to its original state halfway through the
-        // destructor, which would be bad!
-        //
-        // Hence, we use `ptr::read` on OSX (to move to a "safe" location)
-        // instead of drop_in_place.
-        if cfg!(target_os = "macos") {
-            ptr::read((*ptr).inner.get());
-        } else {
-            ptr::drop_in_place((*ptr).inner.get());
-        }
-    }
-}
-
 #[doc(hidden)]
 pub mod os {
     use cell::{Cell, UnsafeCell};
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 150482e4af4..255cd2a9bc0 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -181,9 +181,18 @@ use time::Duration;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::local::{LocalKey, LocalKeyState};
 
+// The types used by the thread_local! macro to access TLS keys. Note that there
+// are two types, the "OS" type and the "fast" type. The OS thread local key
+// type is accessed via platform-specific API calls and is slow, while the fast
+// key type is accessed via code generated via LLVM, where TLS keys are set up
+// by the elf linker. Note that the OS TLS type is always available: on macOS
+// the standard library is compiled with support for older platform versions
+// where fast TLS was not available; end-user code is compiled with fast TLS
+// where available, but both are needed.
+
 #[unstable(feature = "libstd_thread_internals", issue = "0")]
 #[cfg(target_thread_local)]
-#[doc(hidden)] pub use self::local::elf::Key as __ElfLocalKeyInner;
+#[doc(hidden)] pub use sys::fast_thread_local::Key as __FastLocalKeyInner;
 #[unstable(feature = "libstd_thread_internals", issue = "0")]
 #[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner;