diff --git a/src/base/platform/platform-posix.cc b/src/base/platform/platform-posix.cc index 9759febf2a..97453b83a6 100644 --- a/src/base/platform/platform-posix.cc +++ b/src/base/platform/platform-posix.cc @@ -1130,7 +1130,47 @@ static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) { #endif } -#if defined(V8_FAST_TLS_SUPPORTED) && defined(DEBUG) + +#ifdef V8_FAST_TLS_SUPPORTED + +static std::atomic tls_base_offset_initialized{false}; +intptr_t kMacTlsBaseOffset = 0; + +// It's safe to do the initialization more that once, but it has to be +// done at least once. +static void InitializeTlsBaseOffset() { + const size_t kBufferSize = 128; + char buffer[kBufferSize]; + size_t buffer_size = kBufferSize; + int ctl_name[] = { CTL_KERN , KERN_OSRELEASE }; + if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) { + FATAL("V8 failed to get kernel version"); + } + // The buffer now contains a string of the form XX.YY.ZZ, where + // XX is the major kernel version component. + // Make sure the buffer is 0-terminated. + buffer[kBufferSize - 1] = '\0'; + char* period_pos = strchr(buffer, '.'); + *period_pos = '\0'; + int kernel_version_major = static_cast(strtol(buffer, nullptr, 10)); + // The constants below are taken from pthreads.s from the XNU kernel + // sources archive at www.opensource.apple.com. + if (kernel_version_major < 11) { + // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the + // same offsets. +#if V8_HOST_ARCH_IA32 + kMacTlsBaseOffset = 0x48; +#else + kMacTlsBaseOffset = 0x60; +#endif + } else { + // 11.x.x (Lion) changed the offset. + kMacTlsBaseOffset = 0; + } + + tls_base_offset_initialized.store(true, std::memory_order_release); +} + static void CheckFastTls(Thread::LocalStorageKey key) { void* expected = reinterpret_cast(0x1234CAFE); @@ -1142,20 +1182,30 @@ static void CheckFastTls(Thread::LocalStorageKey key) { Thread::SetThreadLocal(key, nullptr); } -#endif // defined(V8_FAST_TLS_SUPPORTED) && defined(DEBUG) +#endif // V8_FAST_TLS_SUPPORTED + Thread::LocalStorageKey Thread::CreateThreadLocalKey() { +#ifdef V8_FAST_TLS_SUPPORTED + bool check_fast_tls = false; + if (!tls_base_offset_initialized.load(std::memory_order_acquire)) { + check_fast_tls = true; + InitializeTlsBaseOffset(); + } +#endif pthread_key_t key; int result = pthread_key_create(&key, nullptr); DCHECK_EQ(0, result); USE(result); LocalStorageKey local_key = PthreadKeyToLocalKey(key); -#if defined(V8_FAST_TLS_SUPPORTED) && defined(DEBUG) - CheckFastTls(local_key); +#ifdef V8_FAST_TLS_SUPPORTED + // If we just initialized fast TLS support, make sure it works. + if (check_fast_tls) CheckFastTls(local_key); #endif return local_key; } + void Thread::DeleteThreadLocalKey(LocalStorageKey key) { pthread_key_t pthread_key = LocalKeyToPthreadKey(key); int result = pthread_key_delete(pthread_key); diff --git a/src/base/platform/platform.h b/src/base/platform/platform.h index 95c0952371..f67d5c079a 100644 --- a/src/base/platform/platform.h +++ b/src/base/platform/platform.h @@ -71,7 +71,9 @@ namespace base { #define V8_FAST_TLS_SUPPORTED 1 -V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index) { +V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index); + +inline intptr_t InternalGetExistingThreadLocal(intptr_t index) { const intptr_t kTibInlineTlsOffset = 0xE10; const intptr_t kTibExtraTlsOffset = 0xF94; const intptr_t kMaxInlineSlots = 64; @@ -89,8 +91,6 @@ V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index) { (index - kMaxInlineSlots)); } -// Not possible on ARM64, the register holding the base pointer is not stable -// across major releases. #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64) // tvOS simulator does not use intptr_t as TLS key. @@ -98,14 +98,20 @@ V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index) { #define V8_FAST_TLS_SUPPORTED 1 -V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index) { +extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset; + +V8_INLINE intptr_t InternalGetExistingThreadLocal(intptr_t index); + +inline intptr_t InternalGetExistingThreadLocal(intptr_t index) { intptr_t result; #if V8_HOST_ARCH_IA32 - asm("movl %%gs:(,%1,4), %0;" - : "=r"(result) // Output must be a writable register. - : "r"(index)); + asm("movl %%gs:(%1,%2,4), %0;" + :"=r"(result) // Output must be a writable register. + :"r"(kMacTlsBaseOffset), "r"(index)); #else - asm("movq %%gs:(,%1,8), %0;" : "=r"(result) : "r"(index)); + asm("movq %%gs:(%1,%2,8), %0;" + :"=r"(result) + :"r"(kMacTlsBaseOffset), "r"(index)); #endif return result; }