about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authortyler <tyler@brainiumstudios.com>2019-04-27 08:01:32 -0700
committertyler <tyler@brainiumstudios.com>2019-05-15 07:30:33 -0700
commit430a091cd80c0e4b6bf44f6a19463a832e566f97 (patch)
tree9c9d3baeed0c0eab8d434a76b41148997d42611a /src/libstd
parentae4be16e407061828fe604b1ccbd61181b14a3f1 (diff)
downloadrust-430a091cd80c0e4b6bf44f6a19463a832e566f97.tar.gz
rust-430a091cd80c0e4b6bf44f6a19463a832e566f97.zip
ensure fast thread local lookups occur once per access on macos
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/sys/redox/fast_thread_local.rs6
-rw-r--r--src/libstd/sys/unix/fast_thread_local.rs17
-rw-r--r--src/libstd/sys/windows/fast_thread_local.rs4
-rw-r--r--src/libstd/thread/local.rs11
4 files changed, 32 insertions, 6 deletions
diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs
index 67b92d490b2..c34cd575db7 100644
--- a/src/libstd/sys/redox/fast_thread_local.rs
+++ b/src/libstd/sys/redox/fast_thread_local.rs
@@ -1,4 +1,8 @@
 #![cfg(target_thread_local)]
 #![unstable(feature = "thread_local_internals", issue = "0")]
 
-pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
\ No newline at end of file
+pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
+
+pub unsafe fn lookup_once<T>(ptr: *const &T) -> &T {
+    *ptr
+}
diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs
index c34c2e6e786..28fb9800541 100644
--- a/src/libstd/sys/unix/fast_thread_local.rs
+++ b/src/libstd/sys/unix/fast_thread_local.rs
@@ -82,3 +82,20 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
         }
     }
 }
+
+#[cfg(not(target_os = "macos"))]
+pub unsafe fn lookup_once<T>(ptr: *const &T) -> &T {
+    *ptr
+}
+
+#[cfg(target_os = "macos")]
+pub unsafe fn lookup_once<T>(ptr: *const &T) -> &T {
+    // On macos, thread_local lookups can result in terrible code due to
+    // aggressive rerunning of the macos equivalent of `__tls_get_addr` - four
+    // lookups per actual reference in user code.
+    //
+    // Using a read_volatile on a value holding fast Key's address tricks the
+    // optimizer into only calling the macos get_addr equivalent once per time
+    // requested by the user.
+    crate::ptr::read_volatile(ptr)
+}
diff --git a/src/libstd/sys/windows/fast_thread_local.rs b/src/libstd/sys/windows/fast_thread_local.rs
index 31d0bd1e72e..566d5524fd7 100644
--- a/src/libstd/sys/windows/fast_thread_local.rs
+++ b/src/libstd/sys/windows/fast_thread_local.rs
@@ -2,3 +2,7 @@
 #![cfg(target_thread_local)]
 
 pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
+
+pub unsafe fn lookup_once<T>(ptr: *const &T) -> &T {
+    *ptr
+}
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index 0d5e1f2af38..9ce2fcf2352 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -344,7 +344,7 @@ pub mod fast {
     use crate::fmt;
     use crate::mem;
     use crate::ptr;
-    use crate::sys::fast_thread_local::register_dtor;
+    use crate::sys::fast_thread_local::{lookup_once, register_dtor};
 
     pub struct Key<T> {
         inner: UnsafeCell<Option<T>>,
@@ -371,11 +371,12 @@ pub mod fast {
         }
 
         pub unsafe fn get(&self) -> Option<&'static UnsafeCell<Option<T>>> {
-            if mem::needs_drop::<T>() && self.dtor_running.get() {
+            let this = lookup_once(&self);
+            if mem::needs_drop::<T>() && this.dtor_running.get() {
                 return None
             }
-            self.register_dtor();
-            Some(&*(&self.inner as *const _))
+            this.register_dtor();
+            Some(&*(&this.inner as *const _))
         }
 
         unsafe fn register_dtor(&self) {
@@ -395,7 +396,7 @@ pub mod fast {
         // destructor as running for this thread so calls to `get` will return
         // `None`.
         (*ptr).dtor_running.set(true);
-        
+
         ptr::drop_in_place((*ptr).inner.get());
     }
 }