1 // Copyright 2006-2008 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 MacOS goes here. For the POSIX comaptible parts 29 // the implementation is in platform-posix.cc. 30 31 #include <dlfcn.h> 32 #include <unistd.h> 33 #include <sys/mman.h> 34 #include <mach/mach_init.h> 35 #include <mach-o/dyld.h> 36 #include <mach-o/getsect.h> 37 38 #include <AvailabilityMacros.h> 39 40 #include <pthread.h> 41 #include <semaphore.h> 42 #include <signal.h> 43 #include <libkern/OSAtomic.h> 44 #include <mach/mach.h> 45 #include <mach/semaphore.h> 46 #include <mach/task.h> 47 #include <mach/vm_statistics.h> 48 #include <sys/time.h> 49 #include <sys/resource.h> 50 #include <sys/types.h> 51 #include <sys/sysctl.h> 52 #include <stdarg.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <errno.h> 56 57 #undef MAP_TYPE 58 59 #include "v8.h" 60 61 #include "platform.h" 62 #include "vm-state-inl.h" 63 64 // Manually define these here as weak imports, rather than including execinfo.h. 65 // This lets us launch on 10.4 which does not have these calls. 66 extern "C" { 67 extern int backtrace(void**, int) __attribute__((weak_import)); 68 extern char** backtrace_symbols(void* const*, int) 69 __attribute__((weak_import)); 70 extern void backtrace_symbols_fd(void* const*, int, int) 71 __attribute__((weak_import)); 72 } 73 74 75 namespace v8 { 76 namespace internal { 77 78 // 0 is never a valid thread id on MacOSX since a ptread_t is 79 // a pointer. 80 static const pthread_t kNoThread = (pthread_t) 0; 81 82 83 double ceiling(double x) { 84 // Correct Mac OS X Leopard 'ceil' behavior. 85 if (-1.0 < x && x < 0.0) { 86 return -0.0; 87 } else { 88 return ceil(x); 89 } 90 } 91 92 93 static Mutex* limit_mutex = NULL; 94 95 96 void OS::Setup() { 97 // Seed the random number generator. 98 // Convert the current time to a 64-bit integer first, before converting it 99 // to an unsigned. Going directly will cause an overflow and the seed to be 100 // set to all ones. The seed will be identical for different instances that 101 // call this setup code within the same millisecond. 102 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); 103 srandom(static_cast<unsigned int>(seed)); 104 limit_mutex = CreateMutex(); 105 } 106 107 108 // We keep the lowest and highest addresses mapped as a quick way of 109 // determining that pointers are outside the heap (used mostly in assertions 110 // and verification). The estimate is conservative, ie, not all addresses in 111 // 'allocated' space are actually allocated to our heap. The range is 112 // [lowest, highest), inclusive on the low and and exclusive on the high end. 113 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); 114 static void* highest_ever_allocated = reinterpret_cast<void*>(0); 115 116 117 static void UpdateAllocatedSpaceLimits(void* address, int size) { 118 ASSERT(limit_mutex != NULL); 119 ScopedLock lock(limit_mutex); 120 121 lowest_ever_allocated = Min(lowest_ever_allocated, address); 122 highest_ever_allocated = 123 Max(highest_ever_allocated, 124 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); 125 } 126 127 128 bool OS::IsOutsideAllocatedSpace(void* address) { 129 return address < lowest_ever_allocated || address >= highest_ever_allocated; 130 } 131 132 133 size_t OS::AllocateAlignment() { 134 return getpagesize(); 135 } 136 137 138 // Constants used for mmap. 139 // kMmapFd is used to pass vm_alloc flags to tag the region with the user 140 // defined tag 255 This helps identify V8-allocated regions in memory analysis 141 // tools like vmmap(1). 142 static const int kMmapFd = VM_MAKE_TAG(255); 143 static const off_t kMmapFdOffset = 0; 144 145 146 void* OS::Allocate(const size_t requested, 147 size_t* allocated, 148 bool is_executable) { 149 const size_t msize = RoundUp(requested, getpagesize()); 150 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 151 void* mbase = mmap(NULL, msize, prot, 152 MAP_PRIVATE | MAP_ANON, 153 kMmapFd, kMmapFdOffset); 154 if (mbase == MAP_FAILED) { 155 LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed")); 156 return NULL; 157 } 158 *allocated = msize; 159 UpdateAllocatedSpaceLimits(mbase, msize); 160 return mbase; 161 } 162 163 164 void OS::Free(void* address, const size_t size) { 165 // TODO(1240712): munmap has a return value which is ignored here. 166 int result = munmap(address, size); 167 USE(result); 168 ASSERT(result == 0); 169 } 170 171 172 #ifdef ENABLE_HEAP_PROTECTION 173 174 void OS::Protect(void* address, size_t size) { 175 UNIMPLEMENTED(); 176 } 177 178 179 void OS::Unprotect(void* address, size_t size, bool is_executable) { 180 UNIMPLEMENTED(); 181 } 182 183 #endif 184 185 186 void OS::Sleep(int milliseconds) { 187 usleep(1000 * milliseconds); 188 } 189 190 191 void OS::Abort() { 192 // Redirect to std abort to signal abnormal program termination 193 abort(); 194 } 195 196 197 void OS::DebugBreak() { 198 asm("int $3"); 199 } 200 201 202 class PosixMemoryMappedFile : public OS::MemoryMappedFile { 203 public: 204 PosixMemoryMappedFile(FILE* file, void* memory, int size) 205 : file_(file), memory_(memory), size_(size) { } 206 virtual ~PosixMemoryMappedFile(); 207 virtual void* memory() { return memory_; } 208 virtual int size() { return size_; } 209 private: 210 FILE* file_; 211 void* memory_; 212 int size_; 213 }; 214 215 216 OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name) { 217 FILE* file = fopen(name, "r+"); 218 if (file == NULL) return NULL; 219 220 fseek(file, 0, SEEK_END); 221 int size = ftell(file); 222 223 void* memory = 224 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); 225 return new PosixMemoryMappedFile(file, memory, size); 226 } 227 228 229 OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size, 230 void* initial) { 231 FILE* file = fopen(name, "w+"); 232 if (file == NULL) return NULL; 233 int result = fwrite(initial, size, 1, file); 234 if (result < 1) { 235 fclose(file); 236 return NULL; 237 } 238 void* memory = 239 mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0); 240 return new PosixMemoryMappedFile(file, memory, size); 241 } 242 243 244 PosixMemoryMappedFile::~PosixMemoryMappedFile() { 245 if (memory_) munmap(memory_, size_); 246 fclose(file_); 247 } 248 249 250 void OS::LogSharedLibraryAddresses() { 251 #ifdef ENABLE_LOGGING_AND_PROFILING 252 unsigned int images_count = _dyld_image_count(); 253 for (unsigned int i = 0; i < images_count; ++i) { 254 const mach_header* header = _dyld_get_image_header(i); 255 if (header == NULL) continue; 256 #if V8_HOST_ARCH_X64 257 uint64_t size; 258 char* code_ptr = getsectdatafromheader_64( 259 reinterpret_cast<const mach_header_64*>(header), 260 SEG_TEXT, 261 SECT_TEXT, 262 &size); 263 #else 264 unsigned int size; 265 char* code_ptr = getsectdatafromheader(header, SEG_TEXT, SECT_TEXT, &size); 266 #endif 267 if (code_ptr == NULL) continue; 268 const uintptr_t slide = _dyld_get_image_vmaddr_slide(i); 269 const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide; 270 LOG(Isolate::Current(), 271 SharedLibraryEvent(_dyld_get_image_name(i), start, start + size)); 272 } 273 #endif // ENABLE_LOGGING_AND_PROFILING 274 } 275 276 277 void OS::SignalCodeMovingGC() { 278 } 279 280 281 uint64_t OS::CpuFeaturesImpliedByPlatform() { 282 // MacOSX requires all these to install so we can assume they are present. 283 // These constants are defined by the CPUid instructions. 284 const uint64_t one = 1; 285 return (one << SSE2) | (one << CMOV) | (one << RDTSC) | (one << CPUID); 286 } 287 288 289 int OS::ActivationFrameAlignment() { 290 // OS X activation frames must be 16 byte-aligned; see "Mac OS X ABI 291 // Function Call Guide". 292 return 16; 293 } 294 295 296 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) { 297 OSMemoryBarrier(); 298 *ptr = value; 299 } 300 301 302 const char* OS::LocalTimezone(double time) { 303 if (isnan(time)) return ""; 304 time_t tv = static_cast<time_t>(floor(time/msPerSecond)); 305 struct tm* t = localtime(&tv); 306 if (NULL == t) return ""; 307 return t->tm_zone; 308 } 309 310 311 double OS::LocalTimeOffset() { 312 time_t tv = time(NULL); 313 struct tm* t = localtime(&tv); 314 // tm_gmtoff includes any daylight savings offset, so subtract it. 315 return static_cast<double>(t->tm_gmtoff * msPerSecond - 316 (t->tm_isdst > 0 ? 3600 * msPerSecond : 0)); 317 } 318 319 320 int OS::StackWalk(Vector<StackFrame> frames) { 321 // If weak link to execinfo lib has failed, ie because we are on 10.4, abort. 322 if (backtrace == NULL) 323 return 0; 324 325 int frames_size = frames.length(); 326 ScopedVector<void*> addresses(frames_size); 327 328 int frames_count = backtrace(addresses.start(), frames_size); 329 330 char** symbols = backtrace_symbols(addresses.start(), frames_count); 331 if (symbols == NULL) { 332 return kStackWalkError; 333 } 334 335 for (int i = 0; i < frames_count; i++) { 336 frames[i].address = addresses[i]; 337 // Format a text representation of the frame based on the information 338 // available. 339 SNPrintF(MutableCStrVector(frames[i].text, 340 kStackWalkMaxTextLen), 341 "%s", 342 symbols[i]); 343 // Make sure line termination is in place. 344 frames[i].text[kStackWalkMaxTextLen - 1] = '\0'; 345 } 346 347 free(symbols); 348 349 return frames_count; 350 } 351 352 353 354 355 VirtualMemory::VirtualMemory(size_t size) { 356 address_ = mmap(NULL, size, PROT_NONE, 357 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, 358 kMmapFd, kMmapFdOffset); 359 size_ = size; 360 } 361 362 363 VirtualMemory::~VirtualMemory() { 364 if (IsReserved()) { 365 if (0 == munmap(address(), size())) address_ = MAP_FAILED; 366 } 367 } 368 369 370 bool VirtualMemory::IsReserved() { 371 return address_ != MAP_FAILED; 372 } 373 374 375 bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { 376 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); 377 if (MAP_FAILED == mmap(address, size, prot, 378 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 379 kMmapFd, kMmapFdOffset)) { 380 return false; 381 } 382 383 UpdateAllocatedSpaceLimits(address, size); 384 return true; 385 } 386 387 388 bool VirtualMemory::Uncommit(void* address, size_t size) { 389 return mmap(address, size, PROT_NONE, 390 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_FIXED, 391 kMmapFd, kMmapFdOffset) != MAP_FAILED; 392 } 393 394 395 class Thread::PlatformData : public Malloced { 396 public: 397 PlatformData() : thread_(kNoThread) {} 398 pthread_t thread_; // Thread handle for pthread. 399 }; 400 401 Thread::Thread(Isolate* isolate, const Options& options) 402 : data_(new PlatformData), 403 isolate_(isolate), 404 stack_size_(options.stack_size) { 405 set_name(options.name); 406 } 407 408 409 Thread::Thread(Isolate* isolate, const char* name) 410 : data_(new PlatformData), 411 isolate_(isolate), 412 stack_size_(0) { 413 set_name(name); 414 } 415 416 417 Thread::~Thread() { 418 delete data_; 419 } 420 421 422 static void SetThreadName(const char* name) { 423 // pthread_setname_np is only available in 10.6 or later, so test 424 // for it at runtime. 425 int (*dynamic_pthread_setname_np)(const char*); 426 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) = 427 dlsym(RTLD_DEFAULT, "pthread_setname_np"); 428 if (!dynamic_pthread_setname_np) 429 return; 430 431 // Mac OS X does not expose the length limit of the name, so hardcode it. 432 static const int kMaxNameLength = 63; 433 USE(kMaxNameLength); 434 ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength); 435 dynamic_pthread_setname_np(name); 436 } 437 438 439 static void* ThreadEntry(void* arg) { 440 Thread* thread = reinterpret_cast<Thread*>(arg); 441 // This is also initialized by the first argument to pthread_create() but we 442 // don't know which thread will run first (the original thread or the new 443 // one) so we initialize it here too. 444 thread->data()->thread_ = pthread_self(); 445 SetThreadName(thread->name()); 446 ASSERT(thread->data()->thread_ != kNoThread); 447 Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate()); 448 thread->Run(); 449 return NULL; 450 } 451 452 453 void Thread::set_name(const char* name) { 454 strncpy(name_, name, sizeof(name_)); 455 name_[sizeof(name_) - 1] = '\0'; 456 } 457 458 459 void Thread::Start() { 460 pthread_attr_t* attr_ptr = NULL; 461 pthread_attr_t attr; 462 if (stack_size_ > 0) { 463 pthread_attr_init(&attr); 464 pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_)); 465 attr_ptr = &attr; 466 } 467 pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this); 468 ASSERT(data_->thread_ != kNoThread); 469 } 470 471 472 void Thread::Join() { 473 pthread_join(data_->thread_, NULL); 474 } 475 476 477 #ifdef V8_FAST_TLS_SUPPORTED 478 479 static Atomic32 tls_base_offset_initialized = 0; 480 intptr_t kMacTlsBaseOffset = 0; 481 482 // It's safe to do the initialization more that once, but it has to be 483 // done at least once. 484 static void InitializeTlsBaseOffset() { 485 const size_t kBufferSize = 128; 486 char buffer[kBufferSize]; 487 size_t buffer_size = kBufferSize; 488 int ctl_name[] = { CTL_KERN , KERN_OSRELEASE }; 489 if (sysctl(ctl_name, 2, buffer, &buffer_size, NULL, 0) != 0) { 490 V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version"); 491 } 492 // The buffer now contains a string of the form XX.YY.ZZ, where 493 // XX is the major kernel version component. 494 // Make sure the buffer is 0-terminated. 495 buffer[kBufferSize - 1] = '\0'; 496 char* period_pos = strchr(buffer, '.'); 497 *period_pos = '\0'; 498 int kernel_version_major = 499 static_cast<int>(strtol(buffer, NULL, 10)); // NOLINT 500 // The constants below are taken from pthreads.s from the XNU kernel 501 // sources archive at www.opensource.apple.com. 502 if (kernel_version_major < 11) { 503 // 8.x.x (Tiger), 9.x.x (Leopard), 10.x.x (Snow Leopard) have the 504 // same offsets. 505 #if defined(V8_HOST_ARCH_IA32) 506 kMacTlsBaseOffset = 0x48; 507 #else 508 kMacTlsBaseOffset = 0x60; 509 #endif 510 } else { 511 // 11.x.x (Lion) changed the offset. 512 kMacTlsBaseOffset = 0; 513 } 514 515 Release_Store(&tls_base_offset_initialized, 1); 516 } 517 518 static void CheckFastTls(Thread::LocalStorageKey key) { 519 void* expected = reinterpret_cast<void*>(0x1234CAFE); 520 Thread::SetThreadLocal(key, expected); 521 void* actual = Thread::GetExistingThreadLocal(key); 522 if (expected != actual) { 523 V8_Fatal(__FILE__, __LINE__, 524 "V8 failed to initialize fast TLS on current kernel"); 525 } 526 Thread::SetThreadLocal(key, NULL); 527 } 528 529 #endif // V8_FAST_TLS_SUPPORTED 530 531 532 Thread::LocalStorageKey Thread::CreateThreadLocalKey() { 533 #ifdef V8_FAST_TLS_SUPPORTED 534 bool check_fast_tls = false; 535 if (tls_base_offset_initialized == 0) { 536 check_fast_tls = true; 537 InitializeTlsBaseOffset(); 538 } 539 #endif 540 pthread_key_t key; 541 int result = pthread_key_create(&key, NULL); 542 USE(result); 543 ASSERT(result == 0); 544 LocalStorageKey typed_key = static_cast<LocalStorageKey>(key); 545 #ifdef V8_FAST_TLS_SUPPORTED 546 // If we just initialized fast TLS support, make sure it works. 547 if (check_fast_tls) CheckFastTls(typed_key); 548 #endif 549 return typed_key; 550 } 551 552 553 void Thread::DeleteThreadLocalKey(LocalStorageKey key) { 554 pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 555 int result = pthread_key_delete(pthread_key); 556 USE(result); 557 ASSERT(result == 0); 558 } 559 560 561 void* Thread::GetThreadLocal(LocalStorageKey key) { 562 pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 563 return pthread_getspecific(pthread_key); 564 } 565 566 567 void Thread::SetThreadLocal(LocalStorageKey key, void* value) { 568 pthread_key_t pthread_key = static_cast<pthread_key_t>(key); 569 pthread_setspecific(pthread_key, value); 570 } 571 572 573 void Thread::YieldCPU() { 574 sched_yield(); 575 } 576 577 578 class MacOSMutex : public Mutex { 579 public: 580 581 MacOSMutex() { 582 pthread_mutexattr_t attr; 583 pthread_mutexattr_init(&attr); 584 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 585 pthread_mutex_init(&mutex_, &attr); 586 } 587 588 virtual ~MacOSMutex() { pthread_mutex_destroy(&mutex_); } 589 590 virtual int Lock() { return pthread_mutex_lock(&mutex_); } 591 virtual int Unlock() { return pthread_mutex_unlock(&mutex_); } 592 593 virtual bool TryLock() { 594 int result = pthread_mutex_trylock(&mutex_); 595 // Return false if the lock is busy and locking failed. 596 if (result == EBUSY) { 597 return false; 598 } 599 ASSERT(result == 0); // Verify no other errors. 600 return true; 601 } 602 603 private: 604 pthread_mutex_t mutex_; 605 }; 606 607 608 Mutex* OS::CreateMutex() { 609 return new MacOSMutex(); 610 } 611 612 613 class MacOSSemaphore : public Semaphore { 614 public: 615 explicit MacOSSemaphore(int count) { 616 semaphore_create(mach_task_self(), &semaphore_, SYNC_POLICY_FIFO, count); 617 } 618 619 ~MacOSSemaphore() { 620 semaphore_destroy(mach_task_self(), semaphore_); 621 } 622 623 // The MacOS mach semaphore documentation claims it does not have spurious 624 // wakeups, the way pthreads semaphores do. So the code from the linux 625 // platform is not needed here. 626 void Wait() { semaphore_wait(semaphore_); } 627 628 bool Wait(int timeout); 629 630 void Signal() { semaphore_signal(semaphore_); } 631 632 private: 633 semaphore_t semaphore_; 634 }; 635 636 637 bool MacOSSemaphore::Wait(int timeout) { 638 mach_timespec_t ts; 639 ts.tv_sec = timeout / 1000000; 640 ts.tv_nsec = (timeout % 1000000) * 1000; 641 return semaphore_timedwait(semaphore_, ts) != KERN_OPERATION_TIMED_OUT; 642 } 643 644 645 Semaphore* OS::CreateSemaphore(int count) { 646 return new MacOSSemaphore(count); 647 } 648 649 650 #ifdef ENABLE_LOGGING_AND_PROFILING 651 652 class Sampler::PlatformData : public Malloced { 653 public: 654 PlatformData() : profiled_thread_(mach_thread_self()) {} 655 656 ~PlatformData() { 657 // Deallocate Mach port for thread. 658 mach_port_deallocate(mach_task_self(), profiled_thread_); 659 } 660 661 thread_act_t profiled_thread() { return profiled_thread_; } 662 663 private: 664 // Note: for profiled_thread_ Mach primitives are used instead of PThread's 665 // because the latter doesn't provide thread manipulation primitives required. 666 // For details, consult "Mac OS X Internals" book, Section 7.3. 667 thread_act_t profiled_thread_; 668 }; 669 670 class SamplerThread : public Thread { 671 public: 672 explicit SamplerThread(int interval) 673 : Thread(NULL, "SamplerThread"), 674 interval_(interval) {} 675 676 static void AddActiveSampler(Sampler* sampler) { 677 ScopedLock lock(mutex_); 678 SamplerRegistry::AddActiveSampler(sampler); 679 if (instance_ == NULL) { 680 instance_ = new SamplerThread(sampler->interval()); 681 instance_->Start(); 682 } else { 683 ASSERT(instance_->interval_ == sampler->interval()); 684 } 685 } 686 687 static void RemoveActiveSampler(Sampler* sampler) { 688 ScopedLock lock(mutex_); 689 SamplerRegistry::RemoveActiveSampler(sampler); 690 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { 691 RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); 692 instance_->Join(); 693 delete instance_; 694 instance_ = NULL; 695 } 696 } 697 698 // Implement Thread::Run(). 699 virtual void Run() { 700 SamplerRegistry::State state; 701 while ((state = SamplerRegistry::GetState()) != 702 SamplerRegistry::HAS_NO_SAMPLERS) { 703 bool cpu_profiling_enabled = 704 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); 705 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); 706 // When CPU profiling is enabled both JavaScript and C++ code is 707 // profiled. We must not suspend. 708 if (!cpu_profiling_enabled) { 709 if (rate_limiter_.SuspendIfNecessary()) continue; 710 } 711 if (cpu_profiling_enabled) { 712 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { 713 return; 714 } 715 } 716 if (runtime_profiler_enabled) { 717 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { 718 return; 719 } 720 } 721 OS::Sleep(interval_); 722 } 723 } 724 725 static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { 726 if (!sampler->isolate()->IsInitialized()) return; 727 if (!sampler->IsProfiling()) return; 728 SamplerThread* sampler_thread = 729 reinterpret_cast<SamplerThread*>(raw_sampler_thread); 730 sampler_thread->SampleContext(sampler); 731 } 732 733 static void DoRuntimeProfile(Sampler* sampler, void* ignored) { 734 if (!sampler->isolate()->IsInitialized()) return; 735 sampler->isolate()->runtime_profiler()->NotifyTick(); 736 } 737 738 void SampleContext(Sampler* sampler) { 739 thread_act_t profiled_thread = sampler->platform_data()->profiled_thread(); 740 TickSample sample_obj; 741 TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate()); 742 if (sample == NULL) sample = &sample_obj; 743 744 if (KERN_SUCCESS != thread_suspend(profiled_thread)) return; 745 746 #if V8_HOST_ARCH_X64 747 thread_state_flavor_t flavor = x86_THREAD_STATE64; 748 x86_thread_state64_t state; 749 mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; 750 #if __DARWIN_UNIX03 751 #define REGISTER_FIELD(name) __r ## name 752 #else 753 #define REGISTER_FIELD(name) r ## name 754 #endif // __DARWIN_UNIX03 755 #elif V8_HOST_ARCH_IA32 756 thread_state_flavor_t flavor = i386_THREAD_STATE; 757 i386_thread_state_t state; 758 mach_msg_type_number_t count = i386_THREAD_STATE_COUNT; 759 #if __DARWIN_UNIX03 760 #define REGISTER_FIELD(name) __e ## name 761 #else 762 #define REGISTER_FIELD(name) e ## name 763 #endif // __DARWIN_UNIX03 764 #else 765 #error Unsupported Mac OS X host architecture. 766 #endif // V8_HOST_ARCH 767 768 if (thread_get_state(profiled_thread, 769 flavor, 770 reinterpret_cast<natural_t*>(&state), 771 &count) == KERN_SUCCESS) { 772 sample->state = sampler->isolate()->current_vm_state(); 773 sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip)); 774 sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp)); 775 sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp)); 776 sampler->SampleStack(sample); 777 sampler->Tick(sample); 778 } 779 thread_resume(profiled_thread); 780 } 781 782 const int interval_; 783 RuntimeProfilerRateLimiter rate_limiter_; 784 785 // Protects the process wide state below. 786 static Mutex* mutex_; 787 static SamplerThread* instance_; 788 789 DISALLOW_COPY_AND_ASSIGN(SamplerThread); 790 }; 791 792 #undef REGISTER_FIELD 793 794 795 Mutex* SamplerThread::mutex_ = OS::CreateMutex(); 796 SamplerThread* SamplerThread::instance_ = NULL; 797 798 799 Sampler::Sampler(Isolate* isolate, int interval) 800 : isolate_(isolate), 801 interval_(interval), 802 profiling_(false), 803 active_(false), 804 samples_taken_(0) { 805 data_ = new PlatformData; 806 } 807 808 809 Sampler::~Sampler() { 810 ASSERT(!IsActive()); 811 delete data_; 812 } 813 814 815 void Sampler::Start() { 816 ASSERT(!IsActive()); 817 SetActive(true); 818 SamplerThread::AddActiveSampler(this); 819 } 820 821 822 void Sampler::Stop() { 823 ASSERT(IsActive()); 824 SamplerThread::RemoveActiveSampler(this); 825 SetActive(false); 826 } 827 828 #endif // ENABLE_LOGGING_AND_PROFILING 829 830 } } // namespace v8::internal 831