From ce9837db9a1a371b334169a263f420f7b2e8a1f6 Mon Sep 17 00:00:00 2001 From: Sean Cannella Date: Mon, 8 Jul 2013 00:22:35 -0700 Subject: [PATCH] emitTLSLoad doesn't work on OSX with emulated TLS - Provide a TLS solution that works on OSX with __emutls_* --- hphp/runtime/vm/jit/x64-util.h | 38 ++++++++++++++++++++++++---------- hphp/util/thread_local.h | 18 ++++++++++++---- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/hphp/runtime/vm/jit/x64-util.h b/hphp/runtime/vm/jit/x64-util.h index 816ad03e3..d66e9402f 100644 --- a/hphp/runtime/vm/jit/x64-util.h +++ b/hphp/runtime/vm/jit/x64-util.h @@ -17,6 +17,11 @@ #define X64_UTIL_H_ #include "hphp/util/asm-x64.h" +#ifndef USE_GCC_FAST_TLS +#include +#include "hphp/runtime/vm/jit/abi-x64.h" +#include "hphp/runtime/vm/jit/physreg.h" +#endif #include "hphp/runtime/vm/jit/translator-inline.h" namespace HPHP { @@ -29,6 +34,8 @@ translator_not_reached(X64Assembler &a) { } } +#ifdef USE_GCC_FAST_TLS + /* * TLS access: XXX we currently only support static-style TLS directly * linked off of FS. @@ -46,23 +53,32 @@ translator_not_reached(X64Assembler &a) { * * The virtual addresses of TLS data are not exposed to C/C++. To figure it * out, we take a datum's linear address, and subtract it from the linear - * address where TLS starts. If you use the void* variant here, it's up to - * the programmer to ensure that it really is a TLS address. + * address where TLS starts. */ -static inline void -emitTLSLoad(X64Assembler& a, const void* datum, RegNumber reg) { - uintptr_t virtualAddress = uintptr_t(datum) - tlsBase(); - a. fs(); - a. load_disp32_reg64(virtualAddress, reg); -} - -//TODO(2525714) Will not work without USE_GCC_FAST_TLS being defined template static inline void emitTLSLoad(X64Assembler& a, const ThreadLocalNoCheck& datum, RegNumber reg) { - emitTLSLoad(a, &datum.m_node.m_p, reg); + uintptr_t virtualAddress = uintptr_t(&datum.m_node.m_p) - tlsBase(); + a. fs(); + a. load_disp32_reg64(virtualAddress, reg); } +#else // USE_GCC_FAST_TLS + +template +static inline void +emitTLSLoad(X64Assembler& a, const ThreadLocalNoCheck& datum, + RegNumber reg) { + PhysRegSaver(a, kGPCallerSaved); // we don't know for sure what's alive + a. emitImmReg(&datum.m_key, argNumToRegName[0]); + a. call((TCA)pthread_getspecific); + if (reg != reg::rax) { + a. mov_reg64_reg64(reg::rax, reg); + } +} + +#endif // USE_GCC_FAST_TLS + } } #endif diff --git a/hphp/util/thread_local.h b/hphp/util/thread_local.h index 2c0b67d3c..25ad1aa8d 100644 --- a/hphp/util/thread_local.h +++ b/hphp/util/thread_local.h @@ -31,12 +31,22 @@ namespace HPHP { // Clang seems to have added this feature, or at the very least it is ignoring // __thread keyword and compiling anyway // +// On OSX, gcc does emulate TLS but in a manner that invalidates assumptions +// we have made about __thread and makes accessing thread-local variables in a +// JIT-friendly fashion difficult (as the compiler is doing a lot of magic that +// is not contractual or documented that we would need to duplicate in emitted +// code) so for now we're not going to use it. One possibility if we really +// want to do this is to generate functions that access variables of interest +// in ThreadLocal* (all of them are NoCheck right now) and use the bytes of +// gcc's compiled functions to find the values we would need to pass to +// __emutls_get_address. +// // icc 13.0.0 appears to support it as well but we end up with // assembler warnings of unknown importance about incorrect section // types -#if !defined(NO_TLS) && \ - ((__llvm__ && __clang__) || \ +#if !defined(NO_TLS) && !defined(__APPLE__) && \ + ((__llvm__ && __clang__) || \ __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 3) || \ __INTEL_COMPILER) #define USE_GCC_FAST_TLS @@ -65,7 +75,7 @@ inline void ThreadLocalCreateKey(pthread_key_t *key, void (*del)(void*)) { /** * A thread-local object is a "global" object within a thread. This is useful - * for writing apartment-threaded code, where nothing is actullay shared + * for writing apartment-threaded code, where nothing is actually shared * between different threads (hence no locking) but those variables are not * on stack in local scope. To use it, just do something like this, * @@ -426,7 +436,7 @@ public: return *getNoCheck(); } -private: +public: pthread_key_t m_key; };