summaryrefslogtreecommitdiff
path: root/deps/v8/src/platform-macos.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/platform-macos.cc')
-rw-r--r--deps/v8/src/platform-macos.cc341
1 files changed, 218 insertions, 123 deletions
diff --git a/deps/v8/src/platform-macos.cc b/deps/v8/src/platform-macos.cc
index 35724c3525..cdbbb12d4a 100644
--- a/deps/v8/src/platform-macos.cc
+++ b/deps/v8/src/platform-macos.cc
@@ -48,8 +48,10 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
+#include <sys/sysctl.h>
#include <stdarg.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#undef MAP_TYPE
@@ -88,6 +90,9 @@ double ceiling(double x) {
}
+static Mutex* limit_mutex = NULL;
+
+
void OS::Setup() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
@@ -96,6 +101,7 @@ void OS::Setup() {
// call this setup code within the same millisecond.
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
+ limit_mutex = CreateMutex();
}
@@ -109,6 +115,9 @@ static void* highest_ever_allocated = reinterpret_cast<void*>(0);
static void UpdateAllocatedSpaceLimits(void* address, int size) {
+ ASSERT(limit_mutex != NULL);
+ ScopedLock lock(limit_mutex);
+
lowest_ever_allocated = Min(lowest_ever_allocated, address);
highest_ever_allocated =
Max(highest_ever_allocated,
@@ -143,7 +152,7 @@ void* OS::Allocate(const size_t requested,
MAP_PRIVATE | MAP_ANON,
kMmapFd, kMmapFdOffset);
if (mbase == MAP_FAILED) {
- LOG(StringEvent("OS::Allocate", "mmap failed"));
+ LOG(Isolate::Current(), StringEvent("OS::Allocate", "mmap failed"));
return NULL;
}
*allocated = msize;
@@ -258,7 +267,8 @@ void OS::LogSharedLibraryAddresses() {
if (code_ptr == NULL) continue;
const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
const uintptr_t start = reinterpret_cast<uintptr_t>(code_ptr) + slide;
- LOG(SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
+ LOG(Isolate::Current(),
+ SharedLibraryEvent(_dyld_get_image_name(i), start, start + size));
}
#endif // ENABLE_LOGGING_AND_PROFILING
}
@@ -382,63 +392,31 @@ bool VirtualMemory::Uncommit(void* address, size_t size) {
}
-class ThreadHandle::PlatformData : public Malloced {
+class Thread::PlatformData : public Malloced {
public:
- explicit PlatformData(ThreadHandle::Kind kind) {
- Initialize(kind);
- }
-
- void Initialize(ThreadHandle::Kind kind) {
- switch (kind) {
- case ThreadHandle::SELF: thread_ = pthread_self(); break;
- case ThreadHandle::INVALID: thread_ = kNoThread; break;
- }
- }
+ PlatformData() : thread_(kNoThread) {}
pthread_t thread_; // Thread handle for pthread.
};
-
-
-ThreadHandle::ThreadHandle(Kind kind) {
- data_ = new PlatformData(kind);
-}
-
-
-void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
- data_->Initialize(kind);
-}
-
-
-ThreadHandle::~ThreadHandle() {
- delete data_;
-}
-
-
-bool ThreadHandle::IsSelf() const {
- return pthread_equal(data_->thread_, pthread_self());
+Thread::Thread(const Options& options)
+ : data_(new PlatformData),
+ stack_size_(options.stack_size) {
+ set_name(options.name);
}
-bool ThreadHandle::IsValid() const {
- return data_->thread_ != kNoThread;
-}
-
-
-Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
- set_name("v8:<unknown>");
-}
-
-
-Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) {
+Thread::Thread(const char* name)
+ : data_(new PlatformData),
+ stack_size_(0) {
set_name(name);
}
Thread::~Thread() {
+ delete data_;
}
-
static void SetThreadName(const char* name) {
// pthread_setname_np is only available in 10.6 or later, so test
// for it at runtime.
@@ -461,9 +439,9 @@ static void* ThreadEntry(void* arg) {
// This is also initialized by the first argument to pthread_create() but we
// don't know which thread will run first (the original thread or the new
// one) so we initialize it here too.
- thread->thread_handle_data()->thread_ = pthread_self();
+ thread->data()->thread_ = pthread_self();
SetThreadName(thread->name());
- ASSERT(thread->IsValid());
+ ASSERT(thread->data()->thread_ != kNoThread);
thread->Run();
return NULL;
}
@@ -476,21 +454,96 @@ void Thread::set_name(const char* name) {
void Thread::Start() {
- pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+ pthread_attr_t* attr_ptr = NULL;
+ pthread_attr_t attr;
+ if (stack_size_ > 0) {
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
+ attr_ptr = &attr;
+ }
+ pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
+ ASSERT(data_->thread_ != kNoThread);
}
void Thread::Join() {
- pthread_join(thread_handle_data()->thread_, NULL);
+ pthread_join(data_->thread_, NULL);
}
+#ifdef V8_FAST_TLS_SUPPORTED
+
+static Atomic32 tls_base_offset_initialized = 0;
+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, NULL, 0) != 0) {
+ V8_Fatal(__FILE__, __LINE__, "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<int>(strtol(buffer, NULL, 10)); // NOLINT
+ // 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 defined(V8_HOST_ARCH_IA32)
+ kMacTlsBaseOffset = 0x48;
+#else
+ kMacTlsBaseOffset = 0x60;
+#endif
+ } else {
+ // 11.x.x (Lion) changed the offset.
+ kMacTlsBaseOffset = 0;
+ }
+
+ Release_Store(&tls_base_offset_initialized, 1);
+}
+
+static void CheckFastTls(Thread::LocalStorageKey key) {
+ void* expected = reinterpret_cast<void*>(0x1234CAFE);
+ Thread::SetThreadLocal(key, expected);
+ void* actual = Thread::GetExistingThreadLocal(key);
+ if (expected != actual) {
+ V8_Fatal(__FILE__, __LINE__,
+ "V8 failed to initialize fast TLS on current kernel");
+ }
+ Thread::SetThreadLocal(key, NULL);
+}
+
+#endif // V8_FAST_TLS_SUPPORTED
+
+
Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
+#ifdef V8_FAST_TLS_SUPPORTED
+ bool check_fast_tls = false;
+ if (tls_base_offset_initialized == 0) {
+ check_fast_tls = true;
+ InitializeTlsBaseOffset();
+ }
+#endif
pthread_key_t key;
int result = pthread_key_create(&key, NULL);
USE(result);
ASSERT(result == 0);
- return static_cast<LocalStorageKey>(key);
+ LocalStorageKey typed_key = static_cast<LocalStorageKey>(key);
+#ifdef V8_FAST_TLS_SUPPORTED
+ // If we just initialized fast TLS support, make sure it works.
+ if (check_fast_tls) CheckFastTls(typed_key);
+#endif
+ return typed_key;
}
@@ -595,52 +648,111 @@ Semaphore* OS::CreateSemaphore(int count) {
class Sampler::PlatformData : public Malloced {
public:
- explicit PlatformData(Sampler* sampler)
- : sampler_(sampler),
- task_self_(mach_task_self()),
- profiled_thread_(0),
- sampler_thread_(0) {
+ PlatformData() : profiled_thread_(mach_thread_self()) {}
+
+ ~PlatformData() {
+ // Deallocate Mach port for thread.
+ mach_port_deallocate(mach_task_self(), profiled_thread_);
}
- Sampler* sampler_;
+ thread_act_t profiled_thread() { return profiled_thread_; }
+
+ private:
// Note: for profiled_thread_ Mach primitives are used instead of PThread's
// because the latter doesn't provide thread manipulation primitives required.
// For details, consult "Mac OS X Internals" book, Section 7.3.
- mach_port_t task_self_;
thread_act_t profiled_thread_;
- pthread_t sampler_thread_;
- RuntimeProfilerRateLimiter rate_limiter_;
+};
- // Sampler thread handler.
- void Runner() {
- while (sampler_->IsActive()) {
- if (rate_limiter_.SuspendIfNecessary()) continue;
- Sample();
- OS::Sleep(sampler_->interval_);
+class SamplerThread : public Thread {
+ public:
+ explicit SamplerThread(int interval)
+ : Thread("SamplerThread"),
+ interval_(interval) {}
+
+ static void AddActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::AddActiveSampler(sampler);
+ if (instance_ == NULL) {
+ instance_ = new SamplerThread(sampler->interval());
+ instance_->Start();
+ } else {
+ ASSERT(instance_->interval_ == sampler->interval());
}
}
- void Sample() {
- if (sampler_->IsProfiling()) {
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
+ static void RemoveActiveSampler(Sampler* sampler) {
+ ScopedLock lock(mutex_);
+ SamplerRegistry::RemoveActiveSampler(sampler);
+ if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
+ RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown();
+ instance_->Join();
+ delete instance_;
+ instance_ = NULL;
+ }
+ }
- if (KERN_SUCCESS != thread_suspend(profiled_thread_)) return;
+ // Implement Thread::Run().
+ virtual void Run() {
+ SamplerRegistry::State state;
+ while ((state = SamplerRegistry::GetState()) !=
+ SamplerRegistry::HAS_NO_SAMPLERS) {
+ bool cpu_profiling_enabled =
+ (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
+ bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
+ // When CPU profiling is enabled both JavaScript and C++ code is
+ // profiled. We must not suspend.
+ if (!cpu_profiling_enabled) {
+ if (rate_limiter_.SuspendIfNecessary()) continue;
+ }
+ if (cpu_profiling_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
+ return;
+ }
+ }
+ if (runtime_profiler_enabled) {
+ if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
+ return;
+ }
+ }
+ OS::Sleep(interval_);
+ }
+ }
+
+ static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) {
+ if (!sampler->isolate()->IsInitialized()) return;
+ if (!sampler->IsProfiling()) return;
+ SamplerThread* sampler_thread =
+ reinterpret_cast<SamplerThread*>(raw_sampler_thread);
+ sampler_thread->SampleContext(sampler);
+ }
+
+ static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
+ if (!sampler->isolate()->IsInitialized()) return;
+ sampler->isolate()->runtime_profiler()->NotifyTick();
+ }
+
+ void SampleContext(Sampler* sampler) {
+ thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
+ TickSample sample_obj;
+ TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
+ if (sample == NULL) sample = &sample_obj;
+
+ if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
#if V8_HOST_ARCH_X64
- thread_state_flavor_t flavor = x86_THREAD_STATE64;
- x86_thread_state64_t state;
- mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+ x86_thread_state64_t state;
+ mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
#if __DARWIN_UNIX03
#define REGISTER_FIELD(name) __r ## name
#else
#define REGISTER_FIELD(name) r ## name
#endif // __DARWIN_UNIX03
#elif V8_HOST_ARCH_IA32
- thread_state_flavor_t flavor = i386_THREAD_STATE;
- i386_thread_state_t state;
- mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = i386_THREAD_STATE;
+ i386_thread_state_t state;
+ mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
#if __DARWIN_UNIX03
#define REGISTER_FIELD(name) __e ## name
#else
@@ -650,81 +762,64 @@ class Sampler::PlatformData : public Malloced {
#error Unsupported Mac OS X host architecture.
#endif // V8_HOST_ARCH
- if (thread_get_state(profiled_thread_,
- flavor,
- reinterpret_cast<natural_t*>(&state),
- &count) == KERN_SUCCESS) {
- sample->state = Top::current_vm_state();
- sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
- sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
- sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
- sampler_->SampleStack(sample);
- sampler_->Tick(sample);
- }
- thread_resume(profiled_thread_);
+ if (thread_get_state(profiled_thread,
+ flavor,
+ reinterpret_cast<natural_t*>(&state),
+ &count) == KERN_SUCCESS) {
+ sample->state = sampler->isolate()->current_vm_state();
+ sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
+ sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
+ sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
}
- if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick();
+ thread_resume(profiled_thread);
}
+
+ const int interval_;
+ RuntimeProfilerRateLimiter rate_limiter_;
+
+ // Protects the process wide state below.
+ static Mutex* mutex_;
+ static SamplerThread* instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(SamplerThread);
};
#undef REGISTER_FIELD
-// Entry point for sampler thread.
-static void* SamplerEntry(void* arg) {
- Sampler::PlatformData* data =
- reinterpret_cast<Sampler::PlatformData*>(arg);
- data->Runner();
- return 0;
-}
+Mutex* SamplerThread::mutex_ = OS::CreateMutex();
+SamplerThread* SamplerThread::instance_ = NULL;
-Sampler::Sampler(int interval)
- : interval_(interval),
+Sampler::Sampler(Isolate* isolate, int interval)
+ : isolate_(isolate),
+ interval_(interval),
profiling_(false),
active_(false),
samples_taken_(0) {
- data_ = new PlatformData(this);
+ data_ = new PlatformData;
}
Sampler::~Sampler() {
+ ASSERT(!IsActive());
delete data_;
}
void Sampler::Start() {
- // Do not start multiple threads for the same sampler.
ASSERT(!IsActive());
- data_->profiled_thread_ = mach_thread_self();
-
- // Create sampler thread with high priority.
- // According to POSIX spec, when SCHED_FIFO policy is used, a thread
- // runs until it exits or blocks.
- pthread_attr_t sched_attr;
- sched_param fifo_param;
- pthread_attr_init(&sched_attr);
- pthread_attr_setinheritsched(&sched_attr, PTHREAD_EXPLICIT_SCHED);
- pthread_attr_setschedpolicy(&sched_attr, SCHED_FIFO);
- fifo_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
- pthread_attr_setschedparam(&sched_attr, &fifo_param);
-
SetActive(true);
- pthread_create(&data_->sampler_thread_, &sched_attr, SamplerEntry, data_);
+ SamplerThread::AddActiveSampler(this);
}
void Sampler::Stop() {
- // Seting active to false triggers termination of the sampler
- // thread.
+ ASSERT(IsActive());
+ SamplerThread::RemoveActiveSampler(this);
SetActive(false);
-
- // Wait for sampler thread to terminate.
- Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
- pthread_join(data_->sampler_thread_, NULL);
-
- // Deallocate Mach port for thread.
- mach_port_deallocate(data_->task_self_, data_->profiled_thread_);
}
#endif // ENABLE_LOGGING_AND_PROFILING