preallocated_message_space_ = NULL;
PreallocatedMemoryThreadStop();
- delete heap_profiler_;
- heap_profiler_ = NULL;
- delete cpu_profiler_;
- cpu_profiler_ = NULL;
-
if (runtime_profiler_ != NULL) {
runtime_profiler_->TearDown();
delete runtime_profiler_;
heap_.TearDown();
logger_->TearDown();
+ delete heap_profiler_;
+ heap_profiler_ = NULL;
+ delete cpu_profiler_;
+ cpu_profiler_ = NULL;
+
// The default isolate is re-initializable due to legacy API.
state_ = UNINITIALIZED;
}
date_cache_ = new DateCache();
code_stub_interface_descriptors_ =
new CodeStubInterfaceDescriptor[CodeStub::NUMBER_OF_IDS];
+ cpu_profiler_ = new CpuProfiler(this);
+ heap_profiler_ = new HeapProfiler(heap());
// Enable logging before setting up the heap
logger_->SetUp();
- cpu_profiler_ = new CpuProfiler(this);
- heap_profiler_ = new HeapProfiler(heap());
-
// Initialize other runtime facilities
#if defined(USE_SIMULATOR)
#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_MIPS)
}
-// ----------------------------------------------------------------------------
-// Cygwin profiler support.
-//
-// On Cygwin we use the same sampler implementation as on win32.
-
-class Sampler::PlatformData : public Malloced {
- public:
- // Get a handle to the calling thread. This is the thread that we are
- // going to profile. We need to make a copy of the handle because we are
- // going to use it in the sampler thread. Using GetThreadHandle() will
- // not work in this case. We're using OpenThread because DuplicateHandle
- // for some reason doesn't work in Chrome's sandbox.
- PlatformData()
- : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
- THREAD_SUSPEND_RESUME |
- THREAD_QUERY_INFORMATION,
- false,
- GetCurrentThreadId())),
- profiled_thread_id_(ThreadId::Current()) {}
-
- ~PlatformData() {
- if (profiled_thread_ != NULL) {
- CloseHandle(profiled_thread_);
- profiled_thread_ = NULL;
- }
- }
-
- HANDLE profiled_thread() { return profiled_thread_; }
- ThreadId profiled_thread_id() { return profiled_thread_id_; }
-
- private:
- HANDLE profiled_thread_;
- ThreadId profiled_thread_id_;
-};
-
-
-class SamplerThread : public Thread {
- public:
- static const int kSamplerThreadStackSize = 64 * KB;
-
- explicit SamplerThread(int interval)
- : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- instance_ = new SamplerThread(sampler->interval());
- instance_->StartSynchronously();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- instance_->Join();
- delete instance_;
- instance_ = NULL;
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- }
- 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);
- }
-
- void SampleContext(Sampler* sampler) {
- HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
- if (profiled_thread == NULL) return;
-
- // Context used for sampling the register state of the profiled thread.
- CONTEXT context;
- memset(&context, 0, sizeof(context));
-
- Isolate* isolate = sampler->isolate();
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
- ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
- Isolate::PerIsolateThreadData* per_thread_data = isolate->
- FindPerThreadDataForThread(thread_id);
- if (!per_thread_data) return;
- Simulator* sim = per_thread_data->simulator();
- // Check if there is active simulator before allocating TickSample.
- if (!sim) return;
-#endif
-#endif // USE_SIMULATOR
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
- if (SuspendThread(profiled_thread) == kSuspendFailed) return;
- sample->state = isolate->current_vm_state();
-
- context.ContextFlags = CONTEXT_FULL;
- if (GetThreadContext(profiled_thread, &context) != 0) {
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
- sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
-#elif V8_TARGET_ARCH_MIPS
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
- sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
-#endif
-#else
-#if V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(context.Rip);
- sample->sp = reinterpret_cast<Address>(context.Rsp);
- sample->fp = reinterpret_cast<Address>(context.Rbp);
-#else
- sample->pc = reinterpret_cast<Address>(context.Eip);
- sample->sp = reinterpret_cast<Address>(context.Esp);
- sample->fp = reinterpret_cast<Address>(context.Ebp);
-#endif
-#endif // USE_SIMULATOR
- sampler->SampleStack(sample);
- sampler->Tick(sample);
- }
- ResumeThread(profiled_thread);
- }
-
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SamplerThread* instance_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
void OS::SetUp() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SamplerThread::SetUp();
}
void OS::TearDown() {
- SamplerThread::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SamplerThread::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
}
-class Sampler::PlatformData : public Malloced {
- public:
- PlatformData()
- : profiled_thread_(mach_thread_self()),
- profiled_thread_id_(ThreadId::Current()) {}
-
- ~PlatformData() {
- // Deallocate Mach port for thread.
- mach_port_deallocate(mach_task_self(), profiled_thread_);
- }
-
- thread_act_t profiled_thread() { return profiled_thread_; }
- ThreadId profiled_thread_id() { return profiled_thread_id_; }
-
- 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.
- thread_act_t profiled_thread_;
- ThreadId profiled_thread_id_;
-};
-
-
-class SamplerThread : public Thread {
- public:
- static const int kSamplerThreadStackSize = 64 * KB;
-
- explicit SamplerThread(int interval)
- : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- instance_ = new SamplerThread(sampler->interval());
- instance_->StartSynchronously();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- instance_->Join();
- delete instance_;
- instance_ = NULL;
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- }
- 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);
- }
-
- void SampleContext(Sampler* sampler) {
- thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
- Isolate* isolate = sampler->isolate();
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
- ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
- Isolate::PerIsolateThreadData* per_thread_data = isolate->
- FindPerThreadDataForThread(thread_id);
- if (!per_thread_data) return;
- Simulator* sim = per_thread_data->simulator();
- // Check if there is active simulator before allocating TickSample.
- if (!sim) return;
-#endif
-#endif // USE_SIMULATOR
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- 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;
-#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;
-#if __DARWIN_UNIX03
-#define REGISTER_FIELD(name) __e ## name
-#else
-#define REGISTER_FIELD(name) e ## name
-#endif // __DARWIN_UNIX03
-#else
-#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 = isolate->current_vm_state();
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
- sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
-#elif V8_TARGET_ARCH_MIPS
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
- sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
-#endif
-#else
- 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));
-#endif // USE_SIMULATOR
- sampler->SampleStack(sample);
- sampler->Tick(sample);
- }
- thread_resume(profiled_thread);
- }
-
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SamplerThread* instance_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-#undef REGISTER_FIELD
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
void OS::SetUp() {
// Seed the random number generator. We preserve microsecond resolution.
uint64_t seed = Ticks() ^ (getpid() << 16);
srandom(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SamplerThread::SetUp();
}
void OS::TearDown() {
- SamplerThread::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SamplerThread::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
}
-// ----------------------------------------------------------------------------
-// Win32 profiler support.
-
-class Sampler::PlatformData : public Malloced {
- public:
- // Get a handle to the calling thread. This is the thread that we are
- // going to profile. We need to make a copy of the handle because we are
- // going to use it in the sampler thread. Using GetThreadHandle() will
- // not work in this case. We're using OpenThread because DuplicateHandle
- // for some reason doesn't work in Chrome's sandbox.
- PlatformData()
- : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
- THREAD_SUSPEND_RESUME |
- THREAD_QUERY_INFORMATION,
- false,
- GetCurrentThreadId())),
- profiled_thread_id_(ThreadId::Current()) {}
-
- ~PlatformData() {
- if (profiled_thread_ != NULL) {
- CloseHandle(profiled_thread_);
- profiled_thread_ = NULL;
- }
- }
-
- HANDLE profiled_thread() { return profiled_thread_; }
- ThreadId profiled_thread_id() { return profiled_thread_id_; }
-
- private:
- HANDLE profiled_thread_;
- ThreadId profiled_thread_id_;
-};
-
-
-class SamplerThread : public Thread {
- public:
- static const int kSamplerThreadStackSize = 64 * KB;
-
- explicit SamplerThread(int interval)
- : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
- interval_(interval) {}
-
- static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
- static void TearDown() { delete mutex_; }
-
- static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::AddActiveSampler(sampler);
- if (instance_ == NULL) {
- instance_ = new SamplerThread(sampler->interval());
- instance_->StartSynchronously();
- } else {
- ASSERT(instance_->interval_ == sampler->interval());
- }
- }
-
- static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
- SamplerRegistry::RemoveActiveSampler(sampler);
- if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
- instance_->Join();
- delete instance_;
- instance_ = NULL;
- }
- }
-
- // Implement Thread::Run().
- virtual void Run() {
- SamplerRegistry::State state;
- while ((state = SamplerRegistry::GetState()) !=
- SamplerRegistry::HAS_NO_SAMPLERS) {
- // When CPU profiling is enabled both JavaScript and C++ code is
- // profiled. We must not suspend.
- if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
- SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
- }
- 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);
- }
-
- void SampleContext(Sampler* sampler) {
- HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
- if (profiled_thread == NULL) return;
-
- // Context used for sampling the register state of the profiled thread.
- CONTEXT context;
- memset(&context, 0, sizeof(context));
-
- Isolate* isolate = sampler->isolate();
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
- ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
- Isolate::PerIsolateThreadData* per_thread_data = isolate->
- FindPerThreadDataForThread(thread_id);
- if (!per_thread_data) return;
- Simulator* sim = per_thread_data->simulator();
- // Check if there is active simulator before allocating TickSample.
- if (!sim) return;
-#endif
-#endif // USE_SIMULATOR
- TickSample sample_obj;
- TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
- if (sample == NULL) sample = &sample_obj;
-
- static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
- if (SuspendThread(profiled_thread) == kSuspendFailed) return;
- sample->state = isolate->current_vm_state();
-
- context.ContextFlags = CONTEXT_FULL;
- if (GetThreadContext(profiled_thread, &context) != 0) {
-#if defined(USE_SIMULATOR)
-#if V8_TARGET_ARCH_ARM
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
- sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
-#elif V8_TARGET_ARCH_MIPS
- sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
- sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
- sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
-#endif
-#else
-#if V8_HOST_ARCH_X64
- sample->pc = reinterpret_cast<Address>(context.Rip);
- sample->sp = reinterpret_cast<Address>(context.Rsp);
- sample->fp = reinterpret_cast<Address>(context.Rbp);
-#else
- sample->pc = reinterpret_cast<Address>(context.Eip);
- sample->sp = reinterpret_cast<Address>(context.Esp);
- sample->fp = reinterpret_cast<Address>(context.Ebp);
-#endif
-#endif // USE_SIMULATOR
- sampler->SampleStack(sample);
- sampler->Tick(sample);
- }
- ResumeThread(profiled_thread);
- }
-
- const int interval_;
-
- // Protects the process wide state below.
- static Mutex* mutex_;
- static SamplerThread* instance_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SamplerThread);
-};
-
-
-Mutex* SamplerThread::mutex_ = NULL;
-SamplerThread* SamplerThread::instance_ = NULL;
-
-
void OS::SetUp() {
// Seed the random number generator.
// Convert the current time to a 64-bit integer first, before converting it
uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
srand(static_cast<unsigned int>(seed));
limit_mutex = CreateMutex();
- SamplerThread::SetUp();
}
void OS::TearDown() {
- SamplerThread::TearDown();
delete limit_mutex;
}
-Sampler::Sampler(Isolate* isolate, int interval)
- : isolate_(isolate),
- interval_(interval),
- profiling_(false),
- active_(false),
- samples_taken_(0) {
- data_ = new PlatformData;
-}
-
-
-Sampler::~Sampler() {
- ASSERT(!IsActive());
- delete data_;
-}
-
-
-void Sampler::Start() {
- ASSERT(!IsActive());
- SetActive(true);
- SamplerThread::AddActiveSampler(this);
-}
-
-
-void Sampler::Stop() {
- ASSERT(IsActive());
- SamplerThread::RemoveActiveSampler(this);
- SetActive(false);
-}
-
-
} } // namespace v8::internal
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
- || defined(__NetBSD__) || defined(__sun)
+ || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__)
+
+#define USE_SIGNALS
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/syscall.h>
+#if !defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)
#include <ucontext.h>
-#include <unistd.h>
-
#endif
+#include <unistd.h>
// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
// Old versions of the C library <signal.h> didn't define the type.
#include <asm/sigcontext.h>
#endif
+#elif defined(__MACH__)
+
+#include <mach/mach.h>
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+#include "win32-headers.h"
+
+#endif
+
#include "v8.h"
#include "log.h"
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
- || defined(__NetBSD__) || defined(__sun)
+ || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__)
#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
public:
PlatformData()
: vm_tid_(GetThreadID()),
+ vm_tgid_(getpid()),
profiled_thread_id_(ThreadId::Current()) {}
pthread_t vm_tid() const { return vm_tid_; }
+ int vm_tgid() const { return vm_tgid_; }
ThreadId profiled_thread_id() { return profiled_thread_id_; }
private:
pthread_t vm_tid_;
+ const int vm_tgid_;
ThreadId profiled_thread_id_;
};
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
mcontext_t& mcontext = ucontext->uc_mcontext;
sample->state = isolate->current_vm_state();
-#if defined(__linux__)
+#if defined(__linux__) || defined(__ANDROID__)
#if V8_HOST_ARCH_IA32
sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
#endif // __native_client__
}
+#elif defined(__MACH__)
+class Sampler::PlatformData : public Malloced {
+ public:
+ PlatformData()
+ : profiled_thread_(mach_thread_self()),
+ profiled_thread_id_(ThreadId::Current()) {}
+
+ ~PlatformData() {
+ // Deallocate Mach port for thread.
+ mach_port_deallocate(mach_task_self(), profiled_thread_);
+ }
-class SignalSender : public Thread {
+ thread_act_t profiled_thread() { return profiled_thread_; }
+ ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ 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.
+ thread_act_t profiled_thread_;
+ ThreadId profiled_thread_id_;
+};
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+// ----------------------------------------------------------------------------
+// Win32 profiler support. On Cygwin we use the same sampler implementation as
+// on Win32.
+
+class Sampler::PlatformData : public Malloced {
public:
- static const int kSignalSenderStackSize = 64 * KB;
+ // Get a handle to the calling thread. This is the thread that we are
+ // going to profile. We need to make a copy of the handle because we are
+ // going to use it in the sampler thread. Using GetThreadHandle() will
+ // not work in this case. We're using OpenThread because DuplicateHandle
+ // for some reason doesn't work in Chrome's sandbox.
+ PlatformData()
+ : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
+ THREAD_SUSPEND_RESUME |
+ THREAD_QUERY_INFORMATION,
+ false,
+ GetCurrentThreadId())),
+ profiled_thread_id_(ThreadId::Current()) {}
- explicit SignalSender(int interval)
- : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
- vm_tgid_(getpid()),
+ ~PlatformData() {
+ if (profiled_thread_ != NULL) {
+ CloseHandle(profiled_thread_);
+ profiled_thread_ = NULL;
+ }
+ }
+
+ HANDLE profiled_thread() { return profiled_thread_; }
+ ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+ HANDLE profiled_thread_;
+ ThreadId profiled_thread_id_;
+};
+
+#endif
+
+
+class SamplerThread : public Thread {
+ public:
+ static const int kSamplerThreadStackSize = 64 * KB;
+
+ explicit SamplerThread(int interval)
+ : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
interval_(interval) {}
static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
static void TearDown() { delete mutex_; }
+#if defined(USE_SIGNALS)
static void InstallSignalHandler() {
struct sigaction sa;
sa.sa_sigaction = ProfilerSignalHandler;
signal_handler_installed_ = false;
}
}
+#endif
static void AddActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
if (instance_ == NULL) {
// Start a thread that will send SIGPROF signal to VM threads,
// when CPU profiling will be enabled.
- instance_ = new SignalSender(sampler->interval());
+ instance_ = new SamplerThread(sampler->interval());
instance_->StartSynchronously();
} else {
ASSERT(instance_->interval_ == sampler->interval());
instance_->Join();
delete instance_;
instance_ = NULL;
+#if defined(USE_SIGNALS)
RestoreSignalHandler();
+#endif
}
}
// When CPU profiling is enabled both JavaScript and C++ code is
// profiled. We must not suspend.
if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
+#if defined(USE_SIGNALS)
if (!signal_handler_installed_) InstallSignalHandler();
+#endif
SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
} else {
+#if defined(USE_SIGNALS)
if (signal_handler_installed_) RestoreSignalHandler();
+#endif
}
Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
}
}
static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
+ if (!sampler->isolate()->IsInitialized()) return;
if (!sampler->IsProfiling()) return;
- SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
- sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
+ SamplerThread* sender = reinterpret_cast<SamplerThread*>(raw_sender);
+ sender->SampleContext(sampler);
}
- void SendProfilingSignal(int tid) {
+#if defined(USE_SIGNALS)
+ void SampleContext(Sampler* sampler) {
if (!signal_handler_installed_) return;
+ Sampler::PlatformData* platform_data = sampler->platform_data();
+ int tid = platform_data->vm_tid();
// Glibc doesn't provide a wrapper for tgkill(2).
#if defined(ANDROID)
- syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
+ syscall(__NR_tgkill, platform_data->vm_tgid(), tid, SIGPROF);
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__sun)
pthread_kill(tid, SIGPROF);
#else
- int result = syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
+ int result = syscall(SYS_tgkill, platform_data->vm_tgid(), tid, SIGPROF);
USE(result);
ASSERT(result == 0);
#endif
#ifdef DEBUG
if (result != 0 && errno != EINTR) {
fprintf(stderr,
- "SignalSender usleep error; interval = %u, errno = %d\n",
+ "SamplerThread usleep error; interval = %u, errno = %d\n",
interval,
errno);
ASSERT(result == 0 || errno == EINTR);
#endif // ANDROID
}
- const int vm_tgid_;
+#elif defined(__MACH__)
+
+ void SampleContext(Sampler* sampler) {
+ thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
+ Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+ ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+ Isolate::PerIsolateThreadData* per_thread_data = isolate->
+ FindPerThreadDataForThread(thread_id);
+ if (!per_thread_data) return;
+ Simulator* sim = per_thread_data->simulator();
+ // Check if there is active simulator before allocating TickSample.
+ if (!sim) return;
+#endif
+#endif // USE_SIMULATOR
+ TickSample sample_obj;
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+ 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;
+#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;
+#if __DARWIN_UNIX03
+#define REGISTER_FIELD(name) __e ## name
+#else
+#define REGISTER_FIELD(name) e ## name
+#endif // __DARWIN_UNIX03
+#else
+#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 = isolate->current_vm_state();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+ 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));
+#endif // USE_SIMULATOR
+#undef REGISTER_FIELD
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
+ }
+ thread_resume(profiled_thread);
+ }
+
+ void Sleep() {
+ OS::Sleep(interval_);
+ }
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+ void SampleContext(Sampler* sampler) {
+ HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
+ if (profiled_thread == NULL) return;
+
+ // Context used for sampling the register state of the profiled thread.
+ CONTEXT context;
+ memset(&context, 0, sizeof(context));
+
+ Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+ ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+ Isolate::PerIsolateThreadData* per_thread_data = isolate->
+ FindPerThreadDataForThread(thread_id);
+ if (!per_thread_data) return;
+ Simulator* sim = per_thread_data->simulator();
+ // Check if there is active simulator before allocating TickSample.
+ if (!sim) return;
+#endif
+#endif // USE_SIMULATOR
+ TickSample sample_obj;
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+ if (sample == NULL) sample = &sample_obj;
+
+ static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
+ if (SuspendThread(profiled_thread) == kSuspendFailed) return;
+ sample->state = isolate->current_vm_state();
+
+ context.ContextFlags = CONTEXT_FULL;
+ if (GetThreadContext(profiled_thread, &context) != 0) {
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+#if V8_HOST_ARCH_X64
+ sample->pc = reinterpret_cast<Address>(context.Rip);
+ sample->sp = reinterpret_cast<Address>(context.Rsp);
+ sample->fp = reinterpret_cast<Address>(context.Rbp);
+#else
+ sample->pc = reinterpret_cast<Address>(context.Eip);
+ sample->sp = reinterpret_cast<Address>(context.Esp);
+ sample->fp = reinterpret_cast<Address>(context.Ebp);
+#endif
+#endif // USE_SIMULATOR
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
+ }
+ ResumeThread(profiled_thread);
+ }
+
+ void Sleep() {
+ OS::Sleep(interval_);
+ }
+
+#endif // USE_SIGNALS
+
const int interval_;
// Protects the process wide state below.
static Mutex* mutex_;
- static SignalSender* instance_;
+ static SamplerThread* instance_;
+#if defined(USE_SIGNALS)
static bool signal_handler_installed_;
static struct sigaction old_signal_handler_;
+#endif
private:
- DISALLOW_COPY_AND_ASSIGN(SignalSender);
+ DISALLOW_COPY_AND_ASSIGN(SamplerThread);
};
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
+Mutex* SamplerThread::mutex_ = NULL;
+SamplerThread* SamplerThread::instance_ = NULL;
+#if defined(USE_SIGNALS)
+struct sigaction SamplerThread::old_signal_handler_;
+bool SamplerThread::signal_handler_installed_ = false;
+#endif
void Sampler::SetUp() {
- SignalSender::SetUp();
+ SamplerThread::SetUp();
}
void Sampler::TearDown() {
- SignalSender::TearDown();
+ SamplerThread::TearDown();
}
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
- SignalSender::AddActiveSampler(this);
+ SamplerThread::AddActiveSampler(this);
}
void Sampler::Stop() {
ASSERT(IsActive());
- SignalSender::RemoveActiveSampler(this);
+ SamplerThread::RemoveActiveSampler(this);
SetActive(false);
}
-#else
-
-void Sampler::SetUp() {
-}
-
-
-void Sampler::TearDown() {
-}
-
-#endif // __linux__ || _*BSD__ || __sun
-
void Sampler::SampleStack(TickSample* sample) {
StackTracer::Trace(isolate_, sample);
if (++samples_taken_ < 0) samples_taken_ = 0;