// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "sampler.h"
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/sampler.h"
#if V8_OS_POSIX && !V8_OS_CYGWIN
#include <signal.h>
#include <sys/time.h>
-#if !V8_OS_QNX
-#include <sys/syscall.h>
+#if !V8_OS_QNX && !V8_OS_NACL
+#include <sys/syscall.h> // NOLINT
#endif
#if V8_OS_MACOSX
#include <mach/mach.h>
// OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
// and is a typedef for struct sigcontext. There is no uc_mcontext.
-#elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) \
- && !V8_OS_OPENBSD
+#elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && \
+ !V8_OS_OPENBSD && !V8_OS_NACL
#include <ucontext.h>
#endif
// 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.
#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
- defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
-#include <asm/sigcontext.h>
+ (defined(__arm__) || defined(__aarch64__)) && \
+ !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
+#include <asm/sigcontext.h> // NOLINT
#endif
#elif V8_OS_WIN || V8_OS_CYGWIN
-#include "win32-headers.h"
+#include "src/base/win32-headers.h"
#endif
-#include "v8.h"
+#include "src/v8.h"
-#include "cpu-profiler-inl.h"
-#include "flags.h"
-#include "frames-inl.h"
-#include "log.h"
-#include "platform.h"
-#include "simulator.h"
-#include "v8threads.h"
-#include "vm-state-inl.h"
+#include "src/base/platform/platform.h"
+#include "src/cpu-profiler-inl.h"
+#include "src/flags.h"
+#include "src/frames-inl.h"
+#include "src/log.h"
+#include "src/simulator.h"
+#include "src/v8threads.h"
+#include "src/vm-state-inl.h"
#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
// Other fields are not used by V8, don't define them here.
} ucontext_t;
+#elif defined(__aarch64__)
+
+typedef struct sigcontext mcontext_t;
+
+typedef struct ucontext {
+ uint64_t uc_flags;
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ // Other fields are not used by V8, don't define them here.
+} ucontext_t;
+
#elif defined(__mips__)
// MIPS version of sigcontext, for Android bionic.
typedef struct {
// Other fields are not used by V8, don't define them here.
} ucontext_t;
enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
+
+#elif defined(__x86_64__)
+// x64 version for Android.
+typedef struct {
+ uint64_t gregs[23];
+ void* fpregs;
+ uint64_t __reserved1[8];
+} mcontext_t;
+
+typedef struct ucontext {
+ uint64_t uc_flags;
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ // Other fields are not used by V8, don't define them here.
+} ucontext_t;
+enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
#endif
#endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
}
inline void FillRegisters(RegisterState* state) {
+#if V8_TARGET_ARCH_ARM
state->pc = reinterpret_cast<Address>(simulator_->get_pc());
state->sp = reinterpret_cast<Address>(simulator_->get_register(
Simulator::sp));
-#if V8_TARGET_ARCH_ARM
state->fp = reinterpret_cast<Address>(simulator_->get_register(
Simulator::r11));
+#elif V8_TARGET_ARCH_ARM64
+ if (simulator_->sp() == 0 || simulator_->fp() == 0) {
+ // It possible that the simulator is interrupted while it is updating
+ // the sp or fp register. ARM64 simulator does this in two steps:
+ // first setting it to zero and then setting it to the new value.
+ // Bailout if sp/fp doesn't contain the new value.
+ return;
+ }
+ state->pc = reinterpret_cast<Address>(simulator_->pc());
+ state->sp = reinterpret_cast<Address>(simulator_->sp());
+ state->fp = reinterpret_cast<Address>(simulator_->fp());
#elif V8_TARGET_ARCH_MIPS
+ state->pc = reinterpret_cast<Address>(simulator_->get_pc());
+ state->sp = reinterpret_cast<Address>(simulator_->get_register(
+ Simulator::sp));
+ state->fp = reinterpret_cast<Address>(simulator_->get_register(
+ Simulator::fp));
+#elif V8_TARGET_ARCH_MIPS64
+ state->pc = reinterpret_cast<Address>(simulator_->get_pc());
+ state->sp = reinterpret_cast<Address>(simulator_->get_register(
+ Simulator::sp));
state->fp = reinterpret_cast<Address>(simulator_->get_register(
Simulator::fp));
#endif
class SignalHandler : public AllStatic {
public:
- static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
- static void TearDown() { delete mutex_; }
+ static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
+ static void TearDown() { delete mutex_; mutex_ = NULL; }
static void IncreaseSamplerCount() {
- LockGuard<Mutex> lock_guard(mutex_);
+ base::LockGuard<base::Mutex> lock_guard(mutex_);
if (++client_count_ == 1) Install();
}
static void DecreaseSamplerCount() {
- LockGuard<Mutex> lock_guard(mutex_);
+ base::LockGuard<base::Mutex> lock_guard(mutex_);
if (--client_count_ == 0) Restore();
}
private:
static void Install() {
+#if !V8_OS_NACL
struct sigaction sa;
sa.sa_sigaction = &HandleProfilerSignal;
sigemptyset(&sa.sa_mask);
#endif
signal_handler_installed_ =
(sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
+#endif
}
static void Restore() {
+#if !V8_OS_NACL
if (signal_handler_installed_) {
sigaction(SIGPROF, &old_signal_handler_, 0);
signal_handler_installed_ = false;
}
+#endif
}
+#if !V8_OS_NACL
static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
+#endif
// Protects the process wide state below.
- static Mutex* mutex_;
+ static base::Mutex* mutex_;
static int client_count_;
static bool signal_handler_installed_;
static struct sigaction old_signal_handler_;
};
-Mutex* SignalHandler::mutex_ = NULL;
+base::Mutex* SignalHandler::mutex_ = NULL;
int SignalHandler::client_count_ = 0;
struct sigaction SignalHandler::old_signal_handler_;
bool SignalHandler::signal_handler_installed_ = false;
+// As Native Client does not support signal handling, profiling is disabled.
+#if !V8_OS_NACL
void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
void* context) {
-#if V8_OS_NACL
- // As Native Client does not support signal handling, profiling
- // is disabled.
- return;
-#else
USE(info);
if (signal != SIGPROF) return;
- Isolate* isolate = Isolate::UncheckedCurrent();
+ Isolate* isolate = Isolate::UnsafeCurrent();
if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
// We require a fully initialized and entered isolate.
return;
SimulatorHelper helper;
if (!helper.Init(sampler, isolate)) return;
helper.FillRegisters(&state);
+ // It possible that the simulator is interrupted while it is updating
+ // the sp or fp register. ARM64 simulator does this in two steps:
+ // first setting it to zero and then setting it to the new value.
+ // Bailout if sp/fp doesn't contain the new value.
+ if (state.sp == 0 || state.fp == 0) return;
#else
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
// (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#elif V8_HOST_ARCH_ARM64
+ state.pc = reinterpret_cast<Address>(mcontext.pc);
+ state.sp = reinterpret_cast<Address>(mcontext.sp);
+ // FP is an alias for x29.
+ state.fp = reinterpret_cast<Address>(mcontext.regs[29]);
#elif V8_HOST_ARCH_MIPS
state.pc = reinterpret_cast<Address>(mcontext.pc);
state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
+#elif V8_HOST_ARCH_MIPS64
+ state.pc = reinterpret_cast<Address>(mcontext.pc);
+ state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
+ state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
#endif // V8_HOST_ARCH_*
#elif V8_OS_MACOSX
#if V8_HOST_ARCH_X64
#endif // V8_OS_QNX
#endif // USE_SIMULATOR
sampler->SampleStack(state);
-#endif // V8_OS_NACL
}
+#endif // V8_OS_NACL
#endif
-class SamplerThread : public Thread {
+class SamplerThread : public base::Thread {
public:
static const int kSamplerThreadStackSize = 64 * KB;
explicit SamplerThread(int interval)
- : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
+ : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)),
interval_(interval) {}
- static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
+ static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
static void TearDown() { delete mutex_; mutex_ = NULL; }
static void AddActiveSampler(Sampler* sampler) {
bool need_to_start = false;
- LockGuard<Mutex> lock_guard(mutex_);
+ base::LockGuard<base::Mutex> lock_guard(mutex_);
if (instance_ == NULL) {
// Start a thread that will send SIGPROF signal to VM threads,
// when CPU profiling will be enabled.
need_to_start = true;
}
- ASSERT(sampler->IsActive());
- ASSERT(!instance_->active_samplers_.Contains(sampler));
- ASSERT(instance_->interval_ == sampler->interval());
+ DCHECK(sampler->IsActive());
+ DCHECK(!instance_->active_samplers_.Contains(sampler));
+ DCHECK(instance_->interval_ == sampler->interval());
instance_->active_samplers_.Add(sampler);
if (need_to_start) instance_->StartSynchronously();
static void RemoveActiveSampler(Sampler* sampler) {
SamplerThread* instance_to_remove = NULL;
{
- LockGuard<Mutex> lock_guard(mutex_);
+ base::LockGuard<base::Mutex> lock_guard(mutex_);
- ASSERT(sampler->IsActive());
+ DCHECK(sampler->IsActive());
bool removed = instance_->active_samplers_.RemoveElement(sampler);
- ASSERT(removed);
+ DCHECK(removed);
USE(removed);
// We cannot delete the instance immediately as we need to Join() the
virtual void Run() {
while (true) {
{
- LockGuard<Mutex> lock_guard(mutex_);
+ base::LockGuard<base::Mutex> lock_guard(mutex_);
if (active_samplers_.is_empty()) break;
// When CPU profiling is enabled both JavaScript and C++ code is
// profiled. We must not suspend.
sampler->DoSample();
}
}
- OS::Sleep(interval_);
+ base::OS::Sleep(interval_);
}
}
private:
// Protects the process wide state below.
- static Mutex* mutex_;
+ static base::Mutex* mutex_;
static SamplerThread* instance_;
const int interval_;
};
-Mutex* SamplerThread::mutex_ = NULL;
+base::Mutex* SamplerThread::mutex_ = NULL;
SamplerThread* SamplerThread::instance_ = NULL;
//
DISABLE_ASAN void TickSample::Init(Isolate* isolate,
const RegisterState& regs) {
- ASSERT(isolate->IsInitialized());
+ DCHECK(isolate->IsInitialized());
+ timestamp = base::TimeTicks::HighResolutionNow();
pc = regs.pc;
state = isolate->current_vm_state();
SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
top_frame_type = it.top_frame_type();
- int i = 0;
+ unsigned i = 0;
while (!it.done() && i < TickSample::kMaxFramesCount) {
stack[i++] = it.frame()->pc();
it.Advance();
Sampler::~Sampler() {
- ASSERT(!IsActive());
+ DCHECK(!IsActive());
delete data_;
}
void Sampler::Start() {
- ASSERT(!IsActive());
+ DCHECK(!IsActive());
SetActive(true);
SamplerThread::AddActiveSampler(this);
}
void Sampler::Stop() {
- ASSERT(IsActive());
+ DCHECK(IsActive());
SamplerThread::RemoveActiveSampler(this);
SetActive(false);
}
void Sampler::IncreaseProfilingDepth() {
- NoBarrier_AtomicIncrement(&profiling_, 1);
+ base::NoBarrier_AtomicIncrement(&profiling_, 1);
#if defined(USE_SIGNALS)
SignalHandler::IncreaseSamplerCount();
#endif
#if defined(USE_SIGNALS)
SignalHandler::DecreaseSamplerCount();
#endif
- NoBarrier_AtomicIncrement(&profiling_, -1);
+ base::NoBarrier_AtomicIncrement(&profiling_, -1);
}