Home | History | Annotate | Download | only in src
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/sampler.h"
      6 
      7 #if V8_OS_POSIX && !V8_OS_CYGWIN
      8 
      9 #define USE_SIGNALS
     10 
     11 #include <errno.h>
     12 #include <pthread.h>
     13 #include <signal.h>
     14 #include <sys/time.h>
     15 
     16 #if !V8_OS_QNX && !V8_OS_NACL
     17 #include <sys/syscall.h>  // NOLINT
     18 #endif
     19 
     20 #if V8_OS_MACOSX
     21 #include <mach/mach.h>
     22 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
     23 // and is a typedef for struct sigcontext. There is no uc_mcontext.
     24 #elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && \
     25     !V8_OS_OPENBSD && !V8_OS_NACL
     26 #include <ucontext.h>
     27 #endif
     28 
     29 #include <unistd.h>
     30 
     31 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
     32 // Old versions of the C library <signal.h> didn't define the type.
     33 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
     34     (defined(__arm__) || defined(__aarch64__)) && \
     35     !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
     36 #include <asm/sigcontext.h>  // NOLINT
     37 #endif
     38 
     39 #elif V8_OS_WIN || V8_OS_CYGWIN
     40 
     41 #include "src/base/win32-headers.h"
     42 
     43 #endif
     44 
     45 #include "src/v8.h"
     46 
     47 #include "src/base/platform/platform.h"
     48 #include "src/cpu-profiler-inl.h"
     49 #include "src/flags.h"
     50 #include "src/frames-inl.h"
     51 #include "src/log.h"
     52 #include "src/simulator.h"
     53 #include "src/v8threads.h"
     54 #include "src/vm-state-inl.h"
     55 
     56 
     57 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
     58 
     59 // Not all versions of Android's C library provide ucontext_t.
     60 // Detect this and provide custom but compatible definitions. Note that these
     61 // follow the GLibc naming convention to access register values from
     62 // mcontext_t.
     63 //
     64 // See http://code.google.com/p/android/issues/detail?id=34784
     65 
     66 #if defined(__arm__)
     67 
     68 typedef struct sigcontext mcontext_t;
     69 
     70 typedef struct ucontext {
     71   uint32_t uc_flags;
     72   struct ucontext* uc_link;
     73   stack_t uc_stack;
     74   mcontext_t uc_mcontext;
     75   // Other fields are not used by V8, don't define them here.
     76 } ucontext_t;
     77 
     78 #elif defined(__aarch64__)
     79 
     80 typedef struct sigcontext mcontext_t;
     81 
     82 typedef struct ucontext {
     83   uint64_t uc_flags;
     84   struct ucontext *uc_link;
     85   stack_t uc_stack;
     86   mcontext_t uc_mcontext;
     87   // Other fields are not used by V8, don't define them here.
     88 } ucontext_t;
     89 
     90 #elif defined(__mips__)
     91 // MIPS version of sigcontext, for Android bionic.
     92 typedef struct {
     93   uint32_t regmask;
     94   uint32_t status;
     95   uint64_t pc;
     96   uint64_t gregs[32];
     97   uint64_t fpregs[32];
     98   uint32_t acx;
     99   uint32_t fpc_csr;
    100   uint32_t fpc_eir;
    101   uint32_t used_math;
    102   uint32_t dsp;
    103   uint64_t mdhi;
    104   uint64_t mdlo;
    105   uint32_t hi1;
    106   uint32_t lo1;
    107   uint32_t hi2;
    108   uint32_t lo2;
    109   uint32_t hi3;
    110   uint32_t lo3;
    111 } mcontext_t;
    112 
    113 typedef struct ucontext {
    114   uint32_t uc_flags;
    115   struct ucontext* uc_link;
    116   stack_t uc_stack;
    117   mcontext_t uc_mcontext;
    118   // Other fields are not used by V8, don't define them here.
    119 } ucontext_t;
    120 
    121 #elif defined(__i386__)
    122 // x86 version for Android.
    123 typedef struct {
    124   uint32_t gregs[19];
    125   void* fpregs;
    126   uint32_t oldmask;
    127   uint32_t cr2;
    128 } mcontext_t;
    129 
    130 typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
    131 typedef struct ucontext {
    132   uint32_t uc_flags;
    133   struct ucontext* uc_link;
    134   stack_t uc_stack;
    135   mcontext_t uc_mcontext;
    136   // Other fields are not used by V8, don't define them here.
    137 } ucontext_t;
    138 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
    139 
    140 #elif defined(__x86_64__)
    141 // x64 version for Android.
    142 typedef struct {
    143   uint64_t gregs[23];
    144   void* fpregs;
    145   uint64_t __reserved1[8];
    146 } mcontext_t;
    147 
    148 typedef struct ucontext {
    149   uint64_t uc_flags;
    150   struct ucontext *uc_link;
    151   stack_t uc_stack;
    152   mcontext_t uc_mcontext;
    153   // Other fields are not used by V8, don't define them here.
    154 } ucontext_t;
    155 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
    156 #endif
    157 
    158 #endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
    159 
    160 
    161 namespace v8 {
    162 namespace internal {
    163 
    164 namespace {
    165 
    166 class PlatformDataCommon : public Malloced {
    167  public:
    168   PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
    169   ThreadId profiled_thread_id() { return profiled_thread_id_; }
    170 
    171  protected:
    172   ~PlatformDataCommon() {}
    173 
    174  private:
    175   ThreadId profiled_thread_id_;
    176 };
    177 
    178 }  // namespace
    179 
    180 #if defined(USE_SIGNALS)
    181 
    182 class Sampler::PlatformData : public PlatformDataCommon {
    183  public:
    184   PlatformData() : vm_tid_(pthread_self()) {}
    185   pthread_t vm_tid() const { return vm_tid_; }
    186 
    187  private:
    188   pthread_t vm_tid_;
    189 };
    190 
    191 #elif V8_OS_WIN || V8_OS_CYGWIN
    192 
    193 // ----------------------------------------------------------------------------
    194 // Win32 profiler support. On Cygwin we use the same sampler implementation as
    195 // on Win32.
    196 
    197 class Sampler::PlatformData : public PlatformDataCommon {
    198  public:
    199   // Get a handle to the calling thread. This is the thread that we are
    200   // going to profile. We need to make a copy of the handle because we are
    201   // going to use it in the sampler thread. Using GetThreadHandle() will
    202   // not work in this case. We're using OpenThread because DuplicateHandle
    203   // for some reason doesn't work in Chrome's sandbox.
    204   PlatformData()
    205       : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
    206                                     THREAD_SUSPEND_RESUME |
    207                                     THREAD_QUERY_INFORMATION,
    208                                     false,
    209                                     GetCurrentThreadId())) {}
    210 
    211   ~PlatformData() {
    212     if (profiled_thread_ != NULL) {
    213       CloseHandle(profiled_thread_);
    214       profiled_thread_ = NULL;
    215     }
    216   }
    217 
    218   HANDLE profiled_thread() { return profiled_thread_; }
    219 
    220  private:
    221   HANDLE profiled_thread_;
    222 };
    223 #endif
    224 
    225 
    226 #if defined(USE_SIMULATOR)
    227 class SimulatorHelper {
    228  public:
    229   inline bool Init(Sampler* sampler, Isolate* isolate) {
    230     simulator_ = isolate->thread_local_top()->simulator_;
    231     // Check if there is active simulator.
    232     return simulator_ != NULL;
    233   }
    234 
    235   inline void FillRegisters(RegisterState* state) {
    236 #if V8_TARGET_ARCH_ARM
    237     state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    238     state->sp = reinterpret_cast<Address>(simulator_->get_register(
    239         Simulator::sp));
    240     state->fp = reinterpret_cast<Address>(simulator_->get_register(
    241         Simulator::r11));
    242 #elif V8_TARGET_ARCH_ARM64
    243     if (simulator_->sp() == 0 || simulator_->fp() == 0) {
    244       // It possible that the simulator is interrupted while it is updating
    245       // the sp or fp register. ARM64 simulator does this in two steps:
    246       // first setting it to zero and then setting it to the new value.
    247       // Bailout if sp/fp doesn't contain the new value.
    248       return;
    249     }
    250     state->pc = reinterpret_cast<Address>(simulator_->pc());
    251     state->sp = reinterpret_cast<Address>(simulator_->sp());
    252     state->fp = reinterpret_cast<Address>(simulator_->fp());
    253 #elif V8_TARGET_ARCH_MIPS
    254     state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    255     state->sp = reinterpret_cast<Address>(simulator_->get_register(
    256         Simulator::sp));
    257     state->fp = reinterpret_cast<Address>(simulator_->get_register(
    258         Simulator::fp));
    259 #elif V8_TARGET_ARCH_MIPS64
    260     state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    261     state->sp = reinterpret_cast<Address>(simulator_->get_register(
    262         Simulator::sp));
    263     state->fp = reinterpret_cast<Address>(simulator_->get_register(
    264         Simulator::fp));
    265 #endif
    266   }
    267 
    268  private:
    269   Simulator* simulator_;
    270 };
    271 #endif  // USE_SIMULATOR
    272 
    273 
    274 #if defined(USE_SIGNALS)
    275 
    276 class SignalHandler : public AllStatic {
    277  public:
    278   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
    279   static void TearDown() { delete mutex_; mutex_ = NULL; }
    280 
    281   static void IncreaseSamplerCount() {
    282     base::LockGuard<base::Mutex> lock_guard(mutex_);
    283     if (++client_count_ == 1) Install();
    284   }
    285 
    286   static void DecreaseSamplerCount() {
    287     base::LockGuard<base::Mutex> lock_guard(mutex_);
    288     if (--client_count_ == 0) Restore();
    289   }
    290 
    291   static bool Installed() {
    292     return signal_handler_installed_;
    293   }
    294 
    295  private:
    296   static void Install() {
    297 #if !V8_OS_NACL
    298     struct sigaction sa;
    299     sa.sa_sigaction = &HandleProfilerSignal;
    300     sigemptyset(&sa.sa_mask);
    301 #if V8_OS_QNX
    302     sa.sa_flags = SA_SIGINFO;
    303 #else
    304     sa.sa_flags = SA_RESTART | SA_SIGINFO;
    305 #endif
    306     signal_handler_installed_ =
    307         (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
    308 #endif
    309   }
    310 
    311   static void Restore() {
    312 #if !V8_OS_NACL
    313     if (signal_handler_installed_) {
    314       sigaction(SIGPROF, &old_signal_handler_, 0);
    315       signal_handler_installed_ = false;
    316     }
    317 #endif
    318   }
    319 
    320 #if !V8_OS_NACL
    321   static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
    322 #endif
    323   // Protects the process wide state below.
    324   static base::Mutex* mutex_;
    325   static int client_count_;
    326   static bool signal_handler_installed_;
    327   static struct sigaction old_signal_handler_;
    328 };
    329 
    330 
    331 base::Mutex* SignalHandler::mutex_ = NULL;
    332 int SignalHandler::client_count_ = 0;
    333 struct sigaction SignalHandler::old_signal_handler_;
    334 bool SignalHandler::signal_handler_installed_ = false;
    335 
    336 
    337 // As Native Client does not support signal handling, profiling is disabled.
    338 #if !V8_OS_NACL
    339 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
    340                                          void* context) {
    341   USE(info);
    342   if (signal != SIGPROF) return;
    343   Isolate* isolate = Isolate::UnsafeCurrent();
    344   if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
    345     // We require a fully initialized and entered isolate.
    346     return;
    347   }
    348   if (v8::Locker::IsActive() &&
    349       !isolate->thread_manager()->IsLockedByCurrentThread()) {
    350     return;
    351   }
    352 
    353   Sampler* sampler = isolate->logger()->sampler();
    354   if (sampler == NULL) return;
    355 
    356   RegisterState state;
    357 
    358 #if defined(USE_SIMULATOR)
    359   SimulatorHelper helper;
    360   if (!helper.Init(sampler, isolate)) return;
    361   helper.FillRegisters(&state);
    362   // It possible that the simulator is interrupted while it is updating
    363   // the sp or fp register. ARM64 simulator does this in two steps:
    364   // first setting it to zero and then setting it to the new value.
    365   // Bailout if sp/fp doesn't contain the new value.
    366   if (state.sp == 0 || state.fp == 0) return;
    367 #else
    368   // Extracting the sample from the context is extremely machine dependent.
    369   ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
    370 #if !V8_OS_OPENBSD
    371   mcontext_t& mcontext = ucontext->uc_mcontext;
    372 #endif
    373 #if V8_OS_LINUX
    374 #if V8_HOST_ARCH_IA32
    375   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
    376   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
    377   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
    378 #elif V8_HOST_ARCH_X64
    379   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
    380   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
    381   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
    382 #elif V8_HOST_ARCH_ARM
    383 #if defined(__GLIBC__) && !defined(__UCLIBC__) && \
    384     (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
    385   // Old GLibc ARM versions used a gregs[] array to access the register
    386   // values from mcontext_t.
    387   state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
    388   state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
    389   state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
    390 #else
    391   state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
    392   state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
    393   state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
    394 #endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
    395         // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
    396 #elif V8_HOST_ARCH_ARM64
    397   state.pc = reinterpret_cast<Address>(mcontext.pc);
    398   state.sp = reinterpret_cast<Address>(mcontext.sp);
    399   // FP is an alias for x29.
    400   state.fp = reinterpret_cast<Address>(mcontext.regs[29]);
    401 #elif V8_HOST_ARCH_MIPS
    402   state.pc = reinterpret_cast<Address>(mcontext.pc);
    403   state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
    404   state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
    405 #elif V8_HOST_ARCH_MIPS64
    406   state.pc = reinterpret_cast<Address>(mcontext.pc);
    407   state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
    408   state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
    409 #endif  // V8_HOST_ARCH_*
    410 #elif V8_OS_MACOSX
    411 #if V8_HOST_ARCH_X64
    412 #if __DARWIN_UNIX03
    413   state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
    414   state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
    415   state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
    416 #else  // !__DARWIN_UNIX03
    417   state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
    418   state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
    419   state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
    420 #endif  // __DARWIN_UNIX03
    421 #elif V8_HOST_ARCH_IA32
    422 #if __DARWIN_UNIX03
    423   state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
    424   state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
    425   state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
    426 #else  // !__DARWIN_UNIX03
    427   state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
    428   state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
    429   state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
    430 #endif  // __DARWIN_UNIX03
    431 #endif  // V8_HOST_ARCH_IA32
    432 #elif V8_OS_FREEBSD
    433 #if V8_HOST_ARCH_IA32
    434   state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
    435   state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
    436   state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
    437 #elif V8_HOST_ARCH_X64
    438   state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
    439   state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
    440   state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
    441 #elif V8_HOST_ARCH_ARM
    442   state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
    443   state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
    444   state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
    445 #endif  // V8_HOST_ARCH_*
    446 #elif V8_OS_NETBSD
    447 #if V8_HOST_ARCH_IA32
    448   state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
    449   state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
    450   state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
    451 #elif V8_HOST_ARCH_X64
    452   state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
    453   state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
    454   state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
    455 #endif  // V8_HOST_ARCH_*
    456 #elif V8_OS_OPENBSD
    457 #if V8_HOST_ARCH_IA32
    458   state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
    459   state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
    460   state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
    461 #elif V8_HOST_ARCH_X64
    462   state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
    463   state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
    464   state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
    465 #endif  // V8_HOST_ARCH_*
    466 #elif V8_OS_SOLARIS
    467   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
    468   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
    469   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
    470 #elif V8_OS_QNX
    471 #if V8_HOST_ARCH_IA32
    472   state.pc = reinterpret_cast<Address>(mcontext.cpu.eip);
    473   state.sp = reinterpret_cast<Address>(mcontext.cpu.esp);
    474   state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
    475 #elif V8_HOST_ARCH_ARM
    476   state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
    477   state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
    478   state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
    479 #endif  // V8_HOST_ARCH_*
    480 #endif  // V8_OS_QNX
    481 #endif  // USE_SIMULATOR
    482   sampler->SampleStack(state);
    483 }
    484 #endif  // V8_OS_NACL
    485 
    486 #endif
    487 
    488 
    489 class SamplerThread : public base::Thread {
    490  public:
    491   static const int kSamplerThreadStackSize = 64 * KB;
    492 
    493   explicit SamplerThread(int interval)
    494       : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)),
    495         interval_(interval) {}
    496 
    497   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
    498   static void TearDown() { delete mutex_; mutex_ = NULL; }
    499 
    500   static void AddActiveSampler(Sampler* sampler) {
    501     bool need_to_start = false;
    502     base::LockGuard<base::Mutex> lock_guard(mutex_);
    503     if (instance_ == NULL) {
    504       // Start a thread that will send SIGPROF signal to VM threads,
    505       // when CPU profiling will be enabled.
    506       instance_ = new SamplerThread(sampler->interval());
    507       need_to_start = true;
    508     }
    509 
    510     DCHECK(sampler->IsActive());
    511     DCHECK(!instance_->active_samplers_.Contains(sampler));
    512     DCHECK(instance_->interval_ == sampler->interval());
    513     instance_->active_samplers_.Add(sampler);
    514 
    515     if (need_to_start) instance_->StartSynchronously();
    516   }
    517 
    518   static void RemoveActiveSampler(Sampler* sampler) {
    519     SamplerThread* instance_to_remove = NULL;
    520     {
    521       base::LockGuard<base::Mutex> lock_guard(mutex_);
    522 
    523       DCHECK(sampler->IsActive());
    524       bool removed = instance_->active_samplers_.RemoveElement(sampler);
    525       DCHECK(removed);
    526       USE(removed);
    527 
    528       // We cannot delete the instance immediately as we need to Join() the
    529       // thread but we are holding mutex_ and the thread may try to acquire it.
    530       if (instance_->active_samplers_.is_empty()) {
    531         instance_to_remove = instance_;
    532         instance_ = NULL;
    533       }
    534     }
    535 
    536     if (!instance_to_remove) return;
    537     instance_to_remove->Join();
    538     delete instance_to_remove;
    539   }
    540 
    541   // Implement Thread::Run().
    542   virtual void Run() {
    543     while (true) {
    544       {
    545         base::LockGuard<base::Mutex> lock_guard(mutex_);
    546         if (active_samplers_.is_empty()) break;
    547         // When CPU profiling is enabled both JavaScript and C++ code is
    548         // profiled. We must not suspend.
    549         for (int i = 0; i < active_samplers_.length(); ++i) {
    550           Sampler* sampler = active_samplers_.at(i);
    551           if (!sampler->isolate()->IsInitialized()) continue;
    552           if (!sampler->IsProfiling()) continue;
    553           sampler->DoSample();
    554         }
    555       }
    556       base::OS::Sleep(interval_);
    557     }
    558   }
    559 
    560  private:
    561   // Protects the process wide state below.
    562   static base::Mutex* mutex_;
    563   static SamplerThread* instance_;
    564 
    565   const int interval_;
    566   List<Sampler*> active_samplers_;
    567 
    568   DISALLOW_COPY_AND_ASSIGN(SamplerThread);
    569 };
    570 
    571 
    572 base::Mutex* SamplerThread::mutex_ = NULL;
    573 SamplerThread* SamplerThread::instance_ = NULL;
    574 
    575 
    576 //
    577 // StackTracer implementation
    578 //
    579 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
    580                                    const RegisterState& regs) {
    581   DCHECK(isolate->IsInitialized());
    582   timestamp = base::TimeTicks::HighResolutionNow();
    583   pc = regs.pc;
    584   state = isolate->current_vm_state();
    585 
    586   // Avoid collecting traces while doing GC.
    587   if (state == GC) return;
    588 
    589   Address js_entry_sp = isolate->js_entry_sp();
    590   if (js_entry_sp == 0) {
    591     // Not executing JS now.
    592     return;
    593   }
    594 
    595   ExternalCallbackScope* scope = isolate->external_callback_scope();
    596   Address handler = Isolate::handler(isolate->thread_local_top());
    597   // If there is a handler on top of the external callback scope then
    598   // we have already entrered JavaScript again and the external callback
    599   // is not the top function.
    600   if (scope && scope->scope_address() < handler) {
    601     external_callback = scope->callback();
    602     has_external_callback = true;
    603   } else {
    604     // Sample potential return address value for frameless invocation of
    605     // stubs (we'll figure out later, if this value makes sense).
    606     tos = Memory::Address_at(regs.sp);
    607     has_external_callback = false;
    608   }
    609 
    610   SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
    611   top_frame_type = it.top_frame_type();
    612   unsigned i = 0;
    613   while (!it.done() && i < TickSample::kMaxFramesCount) {
    614     stack[i++] = it.frame()->pc();
    615     it.Advance();
    616   }
    617   frames_count = i;
    618 }
    619 
    620 
    621 void Sampler::SetUp() {
    622 #if defined(USE_SIGNALS)
    623   SignalHandler::SetUp();
    624 #endif
    625   SamplerThread::SetUp();
    626 }
    627 
    628 
    629 void Sampler::TearDown() {
    630   SamplerThread::TearDown();
    631 #if defined(USE_SIGNALS)
    632   SignalHandler::TearDown();
    633 #endif
    634 }
    635 
    636 
    637 Sampler::Sampler(Isolate* isolate, int interval)
    638     : isolate_(isolate),
    639       interval_(interval),
    640       profiling_(false),
    641       has_processing_thread_(false),
    642       active_(false),
    643       is_counting_samples_(false),
    644       js_and_external_sample_count_(0) {
    645   data_ = new PlatformData;
    646 }
    647 
    648 
    649 Sampler::~Sampler() {
    650   DCHECK(!IsActive());
    651   delete data_;
    652 }
    653 
    654 
    655 void Sampler::Start() {
    656   DCHECK(!IsActive());
    657   SetActive(true);
    658   SamplerThread::AddActiveSampler(this);
    659 }
    660 
    661 
    662 void Sampler::Stop() {
    663   DCHECK(IsActive());
    664   SamplerThread::RemoveActiveSampler(this);
    665   SetActive(false);
    666 }
    667 
    668 
    669 void Sampler::IncreaseProfilingDepth() {
    670   base::NoBarrier_AtomicIncrement(&profiling_, 1);
    671 #if defined(USE_SIGNALS)
    672   SignalHandler::IncreaseSamplerCount();
    673 #endif
    674 }
    675 
    676 
    677 void Sampler::DecreaseProfilingDepth() {
    678 #if defined(USE_SIGNALS)
    679   SignalHandler::DecreaseSamplerCount();
    680 #endif
    681   base::NoBarrier_AtomicIncrement(&profiling_, -1);
    682 }
    683 
    684 
    685 void Sampler::SampleStack(const RegisterState& state) {
    686   TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
    687   TickSample sample_obj;
    688   if (sample == NULL) sample = &sample_obj;
    689   sample->Init(isolate_, state);
    690   if (is_counting_samples_) {
    691     if (sample->state == JS || sample->state == EXTERNAL) {
    692       ++js_and_external_sample_count_;
    693     }
    694   }
    695   Tick(sample);
    696   if (sample != &sample_obj) {
    697     isolate_->cpu_profiler()->FinishTickSample();
    698   }
    699 }
    700 
    701 
    702 #if defined(USE_SIGNALS)
    703 
    704 void Sampler::DoSample() {
    705   if (!SignalHandler::Installed()) return;
    706   pthread_kill(platform_data()->vm_tid(), SIGPROF);
    707 }
    708 
    709 #elif V8_OS_WIN || V8_OS_CYGWIN
    710 
    711 void Sampler::DoSample() {
    712   HANDLE profiled_thread = platform_data()->profiled_thread();
    713   if (profiled_thread == NULL) return;
    714 
    715 #if defined(USE_SIMULATOR)
    716   SimulatorHelper helper;
    717   if (!helper.Init(this, isolate())) return;
    718 #endif
    719 
    720   const DWORD kSuspendFailed = static_cast<DWORD>(-1);
    721   if (SuspendThread(profiled_thread) == kSuspendFailed) return;
    722 
    723   // Context used for sampling the register state of the profiled thread.
    724   CONTEXT context;
    725   memset(&context, 0, sizeof(context));
    726   context.ContextFlags = CONTEXT_FULL;
    727   if (GetThreadContext(profiled_thread, &context) != 0) {
    728     RegisterState state;
    729 #if defined(USE_SIMULATOR)
    730     helper.FillRegisters(&state);
    731 #else
    732 #if V8_HOST_ARCH_X64
    733     state.pc = reinterpret_cast<Address>(context.Rip);
    734     state.sp = reinterpret_cast<Address>(context.Rsp);
    735     state.fp = reinterpret_cast<Address>(context.Rbp);
    736 #else
    737     state.pc = reinterpret_cast<Address>(context.Eip);
    738     state.sp = reinterpret_cast<Address>(context.Esp);
    739     state.fp = reinterpret_cast<Address>(context.Ebp);
    740 #endif
    741 #endif  // USE_SIMULATOR
    742     SampleStack(state);
    743   }
    744   ResumeThread(profiled_thread);
    745 }
    746 
    747 #endif  // USE_SIGNALS
    748 
    749 
    750 } }  // namespace v8::internal
    751