1// Copyright 2012 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// Platform specific code for POSIX goes here. This is not a platform on its 29// own but contains the parts which are the same across POSIX platforms Linux, 30// Mac OS, FreeBSD and OpenBSD. 31 32#include <dlfcn.h> 33#include <pthread.h> 34#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 35#include <pthread_np.h> // for pthread_set_name_np 36#endif 37#include <sched.h> // for sched_yield 38#include <unistd.h> 39#include <errno.h> 40#include <time.h> 41 42#include <sys/mman.h> 43#include <sys/socket.h> 44#include <sys/resource.h> 45#include <sys/time.h> 46#include <sys/types.h> 47#include <sys/stat.h> 48#if defined(__linux__) 49#include <sys/prctl.h> // for prctl 50#endif 51#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \ 52 defined(__NetBSD__) || defined(__OpenBSD__) 53#include <sys/sysctl.h> // for sysctl 54#endif 55 56#include <arpa/inet.h> 57#include <netinet/in.h> 58#include <netdb.h> 59 60#undef MAP_TYPE 61 62#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 63#define LOG_TAG "v8" 64#include <android/log.h> 65#endif 66 67#include "v8.h" 68 69#include "codegen.h" 70#include "isolate-inl.h" 71#include "platform.h" 72 73namespace v8 { 74namespace internal { 75 76// 0 is never a valid thread id. 77static const pthread_t kNoThread = (pthread_t) 0; 78 79 80uint64_t OS::CpuFeaturesImpliedByPlatform() { 81#if V8_OS_MACOSX 82 // Mac OS X requires all these to install so we can assume they are present. 83 // These constants are defined by the CPUid instructions. 84 const uint64_t one = 1; 85 return (one << SSE2) | (one << CMOV); 86#else 87 return 0; // Nothing special about the other systems. 88#endif 89} 90 91 92// Maximum size of the virtual memory. 0 means there is no artificial 93// limit. 94 95intptr_t OS::MaxVirtualMemory() { 96 struct rlimit limit; 97 int result = getrlimit(RLIMIT_DATA, &limit); 98 if (result != 0) return 0; 99 return limit.rlim_cur; 100} 101 102 103uint64_t OS::TotalPhysicalMemory() { 104#if V8_OS_MACOSX 105 int mib[2]; 106 mib[0] = CTL_HW; 107 mib[1] = HW_MEMSIZE; 108 int64_t size = 0; 109 size_t len = sizeof(size); 110 if (sysctl(mib, 2, &size, &len, NULL, 0) != 0) { 111 UNREACHABLE(); 112 return 0; 113 } 114 return static_cast<uint64_t>(size); 115#elif V8_OS_FREEBSD 116 int pages, page_size; 117 size_t size = sizeof(pages); 118 sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0); 119 sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0); 120 if (pages == -1 || page_size == -1) { 121 UNREACHABLE(); 122 return 0; 123 } 124 return static_cast<uint64_t>(pages) * page_size; 125#elif V8_OS_CYGWIN 126 MEMORYSTATUS memory_info; 127 memory_info.dwLength = sizeof(memory_info); 128 if (!GlobalMemoryStatus(&memory_info)) { 129 UNREACHABLE(); 130 return 0; 131 } 132 return static_cast<uint64_t>(memory_info.dwTotalPhys); 133#else 134 intptr_t pages = sysconf(_SC_PHYS_PAGES); 135 intptr_t page_size = sysconf(_SC_PAGESIZE); 136 if (pages == -1 || page_size == -1) { 137 UNREACHABLE(); 138 return 0; 139 } 140 return static_cast<uint64_t>(pages) * page_size; 141#endif 142} 143 144 145int OS::ActivationFrameAlignment() { 146#if V8_TARGET_ARCH_ARM 147 // On EABI ARM targets this is required for fp correctness in the 148 // runtime system. 149 return 8; 150#elif V8_TARGET_ARCH_MIPS 151 return 8; 152#else 153 // Otherwise we just assume 16 byte alignment, i.e.: 154 // - With gcc 4.4 the tree vectorization optimizer can generate code 155 // that requires 16 byte alignment such as movdqa on x86. 156 // - Mac OS X and Solaris (64-bit) activation frames must be 16 byte-aligned; 157 // see "Mac OS X ABI Function Call Guide" 158 return 16; 159#endif 160} 161 162 163intptr_t OS::CommitPageSize() { 164 static intptr_t page_size = getpagesize(); 165 return page_size; 166} 167 168 169void OS::Free(void* address, const size_t size) { 170 // TODO(1240712): munmap has a return value which is ignored here. 171 int result = munmap(address, size); 172 USE(result); 173 ASSERT(result == 0); 174} 175 176 177// Get rid of writable permission on code allocations. 178void OS::ProtectCode(void* address, const size_t size) { 179#if defined(__CYGWIN__) 180 DWORD old_protect; 181 VirtualProtect(address, size, PAGE_EXECUTE_READ, &old_protect); 182#elif defined(__native_client__) 183 // The Native Client port of V8 uses an interpreter, so 184 // code pages don't need PROT_EXEC. 185 mprotect(address, size, PROT_READ); 186#else 187 mprotect(address, size, PROT_READ | PROT_EXEC); 188#endif 189} 190 191 192// Create guard pages. 193void OS::Guard(void* address, const size_t size) { 194#if defined(__CYGWIN__) 195 DWORD oldprotect; 196 VirtualProtect(address, size, PAGE_NOACCESS, &oldprotect); 197#else 198 mprotect(address, size, PROT_NONE); 199#endif 200} 201 202 203void* OS::GetRandomMmapAddr() { 204#if defined(__native_client__) 205 // TODO(bradchen): restore randomization once Native Client gets 206 // smarter about using mmap address hints. 207 // See http://code.google.com/p/nativeclient/issues/3341 208 return NULL; 209#endif 210 Isolate* isolate = Isolate::UncheckedCurrent(); 211 // Note that the current isolate isn't set up in a call path via 212 // CpuFeatures::Probe. We don't care about randomization in this case because 213 // the code page is immediately freed. 214 if (isolate != NULL) { 215 uintptr_t raw_addr; 216 isolate->random_number_generator()->NextBytes(&raw_addr, sizeof(raw_addr)); 217#if V8_TARGET_ARCH_X64 218 // Currently available CPUs have 48 bits of virtual addressing. Truncate 219 // the hint address to 46 bits to give the kernel a fighting chance of 220 // fulfilling our placement request. 221 raw_addr &= V8_UINT64_C(0x3ffffffff000); 222#else 223 raw_addr &= 0x3ffff000; 224 225# ifdef __sun 226 // For our Solaris/illumos mmap hint, we pick a random address in the bottom 227 // half of the top half of the address space (that is, the third quarter). 228 // Because we do not MAP_FIXED, this will be treated only as a hint -- the 229 // system will not fail to mmap() because something else happens to already 230 // be mapped at our random address. We deliberately set the hint high enough 231 // to get well above the system's break (that is, the heap); Solaris and 232 // illumos will try the hint and if that fails allocate as if there were 233 // no hint at all. The high hint prevents the break from getting hemmed in 234 // at low values, ceding half of the address space to the system heap. 235 raw_addr += 0x80000000; 236# else 237 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a 238 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos 239 // 10.6 and 10.7. 240 raw_addr += 0x20000000; 241# endif 242#endif 243 return reinterpret_cast<void*>(raw_addr); 244 } 245 return NULL; 246} 247 248 249size_t OS::AllocateAlignment() { 250 return getpagesize(); 251} 252 253 254void OS::Sleep(int milliseconds) { 255 useconds_t ms = static_cast<useconds_t>(milliseconds); 256 usleep(1000 * ms); 257} 258 259 260void OS::Abort() { 261 // Redirect to std abort to signal abnormal program termination. 262 if (FLAG_break_on_abort) { 263 DebugBreak(); 264 } 265 abort(); 266} 267 268 269void OS::DebugBreak() { 270#if V8_HOST_ARCH_ARM 271 asm("bkpt 0"); 272#elif V8_HOST_ARCH_MIPS 273 asm("break"); 274#elif V8_HOST_ARCH_IA32 275#if defined(__native_client__) 276 asm("hlt"); 277#else 278 asm("int $3"); 279#endif // __native_client__ 280#elif V8_HOST_ARCH_X64 281 asm("int $3"); 282#else 283#error Unsupported host architecture. 284#endif 285} 286 287 288// ---------------------------------------------------------------------------- 289// Math functions 290 291double modulo(double x, double y) { 292 return fmod(x, y); 293} 294 295 296#define UNARY_MATH_FUNCTION(name, generator) \ 297static UnaryMathFunction fast_##name##_function = NULL; \ 298void init_fast_##name##_function() { \ 299 fast_##name##_function = generator; \ 300} \ 301double fast_##name(double x) { \ 302 return (*fast_##name##_function)(x); \ 303} 304 305UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) 306UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) 307UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) 308UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) 309UNARY_MATH_FUNCTION(exp, CreateExpFunction()) 310UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) 311 312#undef UNARY_MATH_FUNCTION 313 314 315void lazily_initialize_fast_exp() { 316 if (fast_exp_function == NULL) { 317 init_fast_exp_function(); 318 } 319} 320 321 322double OS::nan_value() { 323 // NAN from math.h is defined in C99 and not in POSIX. 324 return NAN; 325} 326 327 328int OS::GetCurrentProcessId() { 329 return static_cast<int>(getpid()); 330} 331 332 333// ---------------------------------------------------------------------------- 334// POSIX date/time support. 335// 336 337int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 338 struct rusage usage; 339 340 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1; 341 *secs = usage.ru_utime.tv_sec; 342 *usecs = usage.ru_utime.tv_usec; 343 return 0; 344} 345 346 347double OS::TimeCurrentMillis() { 348 return Time::Now().ToJsTime(); 349} 350 351 352double OS::DaylightSavingsOffset(double time) { 353 if (std::isnan(time)) return nan_value(); 354 time_t tv = static_cast<time_t>(floor(time/msPerSecond)); 355 struct tm* t = localtime(&tv); 356 if (NULL == t) return nan_value(); 357 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0; 358} 359 360 361int OS::GetLastError() { 362 return errno; 363} 364 365 366// ---------------------------------------------------------------------------- 367// POSIX stdio support. 368// 369 370FILE* OS::FOpen(const char* path, const char* mode) { 371 FILE* file = fopen(path, mode); 372 if (file == NULL) return NULL; 373 struct stat file_stat; 374 if (fstat(fileno(file), &file_stat) != 0) return NULL; 375 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0); 376 if (is_regular_file) return file; 377 fclose(file); 378 return NULL; 379} 380 381 382bool OS::Remove(const char* path) { 383 return (remove(path) == 0); 384} 385 386 387FILE* OS::OpenTemporaryFile() { 388 return tmpfile(); 389} 390 391 392const char* const OS::LogFileOpenMode = "w"; 393 394 395void OS::Print(const char* format, ...) { 396 va_list args; 397 va_start(args, format); 398 VPrint(format, args); 399 va_end(args); 400} 401 402 403void OS::VPrint(const char* format, va_list args) { 404#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 405 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 406#else 407 vprintf(format, args); 408#endif 409} 410 411 412void OS::FPrint(FILE* out, const char* format, ...) { 413 va_list args; 414 va_start(args, format); 415 VFPrint(out, format, args); 416 va_end(args); 417} 418 419 420void OS::VFPrint(FILE* out, const char* format, va_list args) { 421#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 422 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 423#else 424 vfprintf(out, format, args); 425#endif 426} 427 428 429void OS::PrintError(const char* format, ...) { 430 va_list args; 431 va_start(args, format); 432 VPrintError(format, args); 433 va_end(args); 434} 435 436 437void OS::VPrintError(const char* format, va_list args) { 438#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 439 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); 440#else 441 vfprintf(stderr, format, args); 442#endif 443} 444 445 446int OS::SNPrintF(Vector<char> str, const char* format, ...) { 447 va_list args; 448 va_start(args, format); 449 int result = VSNPrintF(str, format, args); 450 va_end(args); 451 return result; 452} 453 454 455int OS::VSNPrintF(Vector<char> str, 456 const char* format, 457 va_list args) { 458 int n = vsnprintf(str.start(), str.length(), format, args); 459 if (n < 0 || n >= str.length()) { 460 // If the length is zero, the assignment fails. 461 if (str.length() > 0) 462 str[str.length() - 1] = '\0'; 463 return -1; 464 } else { 465 return n; 466 } 467} 468 469 470#if V8_TARGET_ARCH_IA32 471static void MemMoveWrapper(void* dest, const void* src, size_t size) { 472 memmove(dest, src, size); 473} 474 475 476// Initialize to library version so we can call this at any time during startup. 477static OS::MemMoveFunction memmove_function = &MemMoveWrapper; 478 479// Defined in codegen-ia32.cc. 480OS::MemMoveFunction CreateMemMoveFunction(); 481 482// Copy memory area. No restrictions. 483void OS::MemMove(void* dest, const void* src, size_t size) { 484 if (size == 0) return; 485 // Note: here we rely on dependent reads being ordered. This is true 486 // on all architectures we currently support. 487 (*memmove_function)(dest, src, size); 488} 489 490#elif defined(V8_HOST_ARCH_ARM) 491void OS::MemCopyUint16Uint8Wrapper(uint16_t* dest, 492 const uint8_t* src, 493 size_t chars) { 494 uint16_t *limit = dest + chars; 495 while (dest < limit) { 496 *dest++ = static_cast<uint16_t>(*src++); 497 } 498} 499 500 501OS::MemCopyUint8Function OS::memcopy_uint8_function = &OS::MemCopyUint8Wrapper; 502OS::MemCopyUint16Uint8Function OS::memcopy_uint16_uint8_function = 503 &OS::MemCopyUint16Uint8Wrapper; 504// Defined in codegen-arm.cc. 505OS::MemCopyUint8Function CreateMemCopyUint8Function( 506 OS::MemCopyUint8Function stub); 507OS::MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function( 508 OS::MemCopyUint16Uint8Function stub); 509#endif 510 511 512void OS::PostSetUp() { 513#if V8_TARGET_ARCH_IA32 514 OS::MemMoveFunction generated_memmove = CreateMemMoveFunction(); 515 if (generated_memmove != NULL) { 516 memmove_function = generated_memmove; 517 } 518#elif defined(V8_HOST_ARCH_ARM) 519 OS::memcopy_uint8_function = 520 CreateMemCopyUint8Function(&OS::MemCopyUint8Wrapper); 521 OS::memcopy_uint16_uint8_function = 522 CreateMemCopyUint16Uint8Function(&OS::MemCopyUint16Uint8Wrapper); 523#endif 524 init_fast_sin_function(); 525 init_fast_cos_function(); 526 init_fast_tan_function(); 527 init_fast_log_function(); 528 // fast_exp is initialized lazily. 529 init_fast_sqrt_function(); 530} 531 532 533// ---------------------------------------------------------------------------- 534// POSIX string support. 535// 536 537char* OS::StrChr(char* str, int c) { 538 return strchr(str, c); 539} 540 541 542void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) { 543 strncpy(dest.start(), src, n); 544} 545 546 547// ---------------------------------------------------------------------------- 548// POSIX thread support. 549// 550 551class Thread::PlatformData : public Malloced { 552 public: 553 PlatformData() : thread_(kNoThread) {} 554 pthread_t thread_; // Thread handle for pthread. 555}; 556 557Thread::Thread(const Options& options) 558 : data_(new PlatformData), 559 stack_size_(options.stack_size()), 560 start_semaphore_(NULL) { 561 if (stack_size_ > 0 && stack_size_ < PTHREAD_STACK_MIN) { 562 stack_size_ = PTHREAD_STACK_MIN; 563 } 564 set_name(options.name()); 565} 566 567 568Thread::~Thread() { 569 delete data_; 570} 571 572 573static void SetThreadName(const char* name) { 574#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 575 pthread_set_name_np(pthread_self(), name); 576#elif defined(__NetBSD__) 577 STATIC_ASSERT(Thread::kMaxThreadNameLength <= PTHREAD_MAX_NAMELEN_NP); 578 pthread_setname_np(pthread_self(), "%s", name); 579#elif defined(__APPLE__) 580 // pthread_setname_np is only available in 10.6 or later, so test 581 // for it at runtime. 582 int (*dynamic_pthread_setname_np)(const char*); 583 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) = 584 dlsym(RTLD_DEFAULT, "pthread_setname_np"); 585 if (dynamic_pthread_setname_np == NULL) 586 return; 587 588 // Mac OS X does not expose the length limit of the name, so hardcode it. 589 static const int kMaxNameLength = 63; 590 STATIC_ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength); 591 dynamic_pthread_setname_np(name); 592#elif defined(PR_SET_NAME) 593 prctl(PR_SET_NAME, 594 reinterpret_cast<unsigned long>(name), // NOLINT 595 0, 0, 0); 596#endif 597} 598 599 600static void* ThreadEntry(void* arg) { 601 Thread* thread = reinterpret_cast<Thread*>(arg); 602 // This is also initialized by the first argument to pthread_create() but we 603 // don't know which thread will run first (the original thread or the new 604 // one) so we initialize it here too. 605 thread->data()->thread_ = pthread_self(); 606 SetThreadName(thread->name()); 607 ASSERT(thread->data()->thread_ != kNoThread); 608 thread->NotifyStartedAndRun(); 609 return NULL; 610} 611 612 613void Thread::set_name(const char* name) { 614 strncpy(name_, name, sizeof(name_)); 615 name_[sizeof(name_) - 1] = '\0'; 616} 617 618 619void Thread::Start() { 620 int result; 621 pthread_attr_t attr; 622 memset(&attr, 0, sizeof(attr)); 623 result = pthread_attr_init(&attr); 624 ASSERT_EQ(0, result); 625 // Native client uses default stack size. 626#if !defined(__native_client__) 627 if (stack_size_ > 0) { 628 result = pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); 629 ASSERT_EQ(0, result); 630 } 631#endif 632 result = pthread_create(&data_->thread_, &attr, ThreadEntry, this); 633 ASSERT_EQ(0, result); 634 result = pthread_attr_destroy(&attr); 635 ASSERT_EQ(0, result); 636 ASSERT(data_->thread_ != kNoThread); 637 USE(result); 638} 639 640 641void Thread::Join() { 642 pthread_join(data_->thread_, NULL); 643} 644 645 646void Thread::YieldCPU() { 647 int result = sched_yield(); 648 ASSERT_EQ(0, result); 649 USE(result); 650} 651 652 653static Thread::LocalStorageKey PthreadKeyToLocalKey(pthread_key_t pthread_key) { 654#if defined(__CYGWIN__) 655 // We need to cast pthread_key_t to Thread::LocalStorageKey in two steps 656 // because pthread_key_t is a pointer type on Cygwin. This will probably not 657 // work on 64-bit platforms, but Cygwin doesn't support 64-bit anyway. 658 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t)); 659 intptr_t ptr_key = reinterpret_cast<intptr_t>(pthread_key); 660 return static_cast<Thread::LocalStorageKey>(ptr_key); 661#else 662 return static_cast<Thread::LocalStorageKey>(pthread_key); 663#endif 664} 665 666 667static pthread_key_t LocalKeyToPthreadKey(Thread::LocalStorageKey local_key) { 668#if defined(__CYGWIN__) 669 STATIC_ASSERT(sizeof(Thread::LocalStorageKey) == sizeof(pthread_key_t)); 670 intptr_t ptr_key = static_cast<intptr_t>(local_key); 671 return reinterpret_cast<pthread_key_t>(ptr_key); 672#else 673 return static_cast<pthread_key_t>(local_key); 674#endif 675} 676 677 678#ifdef V8_FAST_TLS_SUPPORTED 679 680static Atomic32 tls_base_offset_initialized = 0; 681intptr_t kMacTlsBaseOffset = 0; 682 683// It's safe to do the initialization more that once, but it has to be 684// done at least once. 685static void InitializeTlsBaseOffset() { 686 const size_t kBufferSize = 128; 687 char buffer[kBufferSize]; 688 size_t buffer_size = kBufferSize; 689 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE }; 690 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) { 691 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version"); 692 } 693 // The buffer now contains a string of the form XX.YY.ZZ, where 694 // XX is the major kernel version component. 695 // Make sure the buffer is 0-terminated. 696 buffer[kBufferSize - 1] = '\0'; 697 char* period_pos = strchr(buffer, '.'); 698 *period_pos = '\0'; 699 int kernel_version_major = 700 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT 701 // The constants below are taken from pthreads.s from the XNU kernel 702 // sources archive at www.opensource.apple.com. 703 if (kernel_version_major < 11) { 704 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the 705 // same offsets. 706#if V8_HOST_ARCH_IA32 707 kMacTlsBaseOffset = 0x48; 708#else 709 kMacTlsBaseOffset = 0x60; 710#endif 711 } else { 712 // 11.x.x (Lion) changed the offset. 713 kMacTlsBaseOffset = 0; 714 } 715 716 Release_Store(&tls_base_offset_initialized, 1); 717} 718 719 720static void CheckFastTls(Thread::LocalStorageKey key) { 721 void* expected = reinterpret_cast<void*>(0x1234CAFE); 722 Thread::SetThreadLocal(key, expected); 723 void* actual = Thread::GetExistingThreadLocal(key); 724 if (expected != actual) { 725 V8_Fatal(__FILE__, __LINE__, 726 "V8 failed to initialize fast TLS on current kernel"); 727 } 728 Thread::SetThreadLocal(key, NULL); 729} 730 731#endif // V8_FAST_TLS_SUPPORTED 732 733 734Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 735#ifdef V8_FAST_TLS_SUPPORTED 736 bool check_fast_tls = false; 737 if (tls_base_offset_initialized == 0) { 738 check_fast_tls = true; 739 InitializeTlsBaseOffset(); 740 } 741#endif 742 pthread_key_t key; 743 int result = pthread_key_create(&key, NULL); 744 ASSERT_EQ(0, result); 745 USE(result); 746 LocalStorageKey local_key = PthreadKeyToLocalKey(key); 747#ifdef V8_FAST_TLS_SUPPORTED 748 // If we just initialized fast TLS support, make sure it works. 749 if (check_fast_tls) CheckFastTls(local_key); 750#endif 751 return local_key; 752} 753 754 755void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 756 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 757 int result = pthread_key_delete(pthread_key); 758 ASSERT_EQ(0, result); 759 USE(result); 760} 761 762 763void* Thread::GetThreadLocal(LocalStorageKey key) { 764 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 765 return pthread_getspecific(pthread_key); 766} 767 768 769void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 770 pthread_key_t pthread_key = LocalKeyToPthreadKey(key); 771 int result = pthread_setspecific(pthread_key, value); 772 ASSERT_EQ(0, result); 773 USE(result); 774} 775 776 777} } // namespace v8::internal 778