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
     17 #include <sys/syscall.h>
     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
     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>
     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/cpu-profiler-inl.h"
     48 #include "src/flags.h"
     49 #include "src/frames-inl.h"
     50 #include "src/log.h"
     51 #include "src/platform.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 #endif
    260   }
    261 
    262  private:
    263   Simulator* simulator_;
    264 };
    265 #endif  // USE_SIMULATOR
    266 
    267 
    268 #if defined(USE_SIGNALS)
    269 
    270 class SignalHandler : public AllStatic {
    271  public:
    272   static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
    273   static void TearDown() { delete mutex_; }
    274 
    275   static void IncreaseSamplerCount() {
    276     LockGuard<Mutex> lock_guard(mutex_);
    277     if (++client_count_ == 1) Install();
    278   }
    279 
    280   static void DecreaseSamplerCount() {
    281     LockGuard<Mutex> lock_guard(mutex_);
    282     if (--client_count_ == 0) Restore();
    283   }
    284 
    285   static bool Installed() {
    286     return signal_handler_installed_;
    287   }
    288 
    289  private:
    290   static void Install() {
    291     struct sigaction sa;
    292     sa.sa_sigaction = &HandleProfilerSignal;
    293     sigemptyset(&sa.sa_mask);
    294 #if V8_OS_QNX
    295     sa.sa_flags = SA_SIGINFO;
    296 #else
    297     sa.sa_flags = SA_RESTART | SA_SIGINFO;
    298 #endif
    299     signal_handler_installed_ =
    300         (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
    301   }
    302 
    303   static void Restore() {
    304     if (signal_handler_installed_) {
    305       sigaction(SIGPROF, &old_signal_handler_, 0);
    306       signal_handler_installed_ = false;
    307     }
    308   }
    309 
    310   static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
    311   // Protects the process wide state below.
    312   static Mutex* mutex_;
    313   static int client_count_;
    314   static bool signal_handler_installed_;
    315   static struct sigaction old_signal_handler_;
    316 };
    317 
    318 
    319 Mutex* SignalHandler::mutex_ = NULL;
    320 int SignalHandler::client_count_ = 0;
    321 struct sigaction SignalHandler::old_signal_handler_;
    322 bool SignalHandler::signal_handler_installed_ = false;
    323 
    324 
    325 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
    326                                          void* context) {
    327 #if V8_OS_NACL
    328   // As Native Client does not support signal handling, profiling
    329   // is disabled.
    330   return;
    331 #else
    332   USE(info);
    333   if (signal != SIGPROF) return;
    334   Isolate* isolate = Isolate::UncheckedCurrent();
    335   if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
    336     // We require a fully initialized and entered isolate.
    337     return;
    338   }
    339   if (v8::Locker::IsActive() &&
    340       !isolate->thread_manager()->IsLockedByCurrentThread()) {
    341     return;
    342   }
    343 
    344   Sampler* sampler = isolate->logger()->sampler();
    345   if (sampler == NULL) return;
    346 
    347   RegisterState state;
    348 
    349 #if defined(USE_SIMULATOR)
    350   SimulatorHelper helper;
    351   if (!helper.Init(sampler, isolate)) return;
    352   helper.FillRegisters(&state);
    353   // It possible that the simulator is interrupted while it is updating
    354   // the sp or fp register. ARM64 simulator does this in two steps:
    355   // first setting it to zero and then setting it to the new value.
    356   // Bailout if sp/fp doesn't contain the new value.
    357   if (state.sp == 0 || state.fp == 0) return;
    358 #else
    359   // Extracting the sample from the context is extremely machine dependent.
    360   ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
    361 #if !V8_OS_OPENBSD
    362   mcontext_t& mcontext = ucontext->uc_mcontext;
    363 #endif
    364 #if V8_OS_LINUX
    365 #if V8_HOST_ARCH_IA32
    366   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
    367   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
    368   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
    369 #elif V8_HOST_ARCH_X64
    370   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
    371   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
    372   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
    373 #elif V8_HOST_ARCH_ARM
    374 #if defined(__GLIBC__) && !defined(__UCLIBC__) && \
    375     (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
    376   // Old GLibc ARM versions used a gregs[] array to access the register
    377   // values from mcontext_t.
    378   state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
    379   state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
    380   state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
    381 #else
    382   state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
    383   state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
    384   state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
    385 #endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
    386         // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
    387 #elif V8_HOST_ARCH_ARM64
    388   state.pc = reinterpret_cast<Address>(mcontext.pc);
    389   state.sp = reinterpret_cast<Address>(mcontext.sp);
    390   // FP is an alias for x29.
    391   state.fp = reinterpret_cast<Address>(mcontext.regs[29]);
    392 #elif V8_HOST_ARCH_MIPS
    393   state.pc = reinterpret_cast<Address>(mcontext.pc);
    394   state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
    395   state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
    396 #endif  // V8_HOST_ARCH_*
    397 #elif V8_OS_MACOSX
    398 #if V8_HOST_ARCH_X64
    399 #if __DARWIN_UNIX03
    400   state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
    401   state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
    402   state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
    403 #else  // !__DARWIN_UNIX03
    404   state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
    405   state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
    406   state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
    407 #endif  // __DARWIN_UNIX03
    408 #elif V8_HOST_ARCH_IA32
    409 #if __DARWIN_UNIX03
    410   state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
    411   state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
    412   state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
    413 #else  // !__DARWIN_UNIX03
    414   state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
    415   state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
    416   state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
    417 #endif  // __DARWIN_UNIX03
    418 #endif  // V8_HOST_ARCH_IA32
    419 #elif V8_OS_FREEBSD
    420 #if V8_HOST_ARCH_IA32
    421   state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
    422   state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
    423   state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
    424 #elif V8_HOST_ARCH_X64
    425   state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
    426   state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
    427   state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
    428 #elif V8_HOST_ARCH_ARM
    429   state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
    430   state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
    431   state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
    432 #endif  // V8_HOST_ARCH_*
    433 #elif V8_OS_NETBSD
    434 #if V8_HOST_ARCH_IA32
    435   state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
    436   state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
    437   state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
    438 #elif V8_HOST_ARCH_X64
    439   state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
    440   state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
    441   state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
    442 #endif  // V8_HOST_ARCH_*
    443 #elif V8_OS_OPENBSD
    444 #if V8_HOST_ARCH_IA32
    445   state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
    446   state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
    447   state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
    448 #elif V8_HOST_ARCH_X64
    449   state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
    450   state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
    451   state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
    452 #endif  // V8_HOST_ARCH_*
    453 #elif V8_OS_SOLARIS
    454   state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
    455   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
    456   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
    457 #elif V8_OS_QNX
    458 #if V8_HOST_ARCH_IA32
    459   state.pc = reinterpret_cast<Address>(mcontext.cpu.eip);
    460   state.sp = reinterpret_cast<Address>(mcontext.cpu.esp);
    461   state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
    462 #elif V8_HOST_ARCH_ARM
    463   state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
    464   state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
    465   state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
    466 #endif  // V8_HOST_ARCH_*
    467 #endif  // V8_OS_QNX
    468 #endif  // USE_SIMULATOR
    469   sampler->SampleStack(state);
    470 #endif  // V8_OS_NACL
    471 }
    472 
    473 #endif
    474 
    475 
    476 class SamplerThread : public Thread {
    477  public:
    478   static const int kSamplerThreadStackSize = 64 * KB;
    479 
    480   explicit SamplerThread(int interval)
    481       : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
    482         interval_(interval) {}
    483 
    484   static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
    485   static void TearDown() { delete mutex_; mutex_ = NULL; }
    486 
    487   static void AddActiveSampler(Sampler* sampler) {
    488     bool need_to_start = false;
    489     LockGuard<Mutex> lock_guard(mutex_);
    490     if (instance_ == NULL) {
    491       // Start a thread that will send SIGPROF signal to VM threads,
    492       // when CPU profiling will be enabled.
    493       instance_ = new SamplerThread(sampler->interval());
    494       need_to_start = true;
    495     }
    496 
    497     ASSERT(sampler->IsActive());
    498     ASSERT(!instance_->active_samplers_.Contains(sampler));
    499     ASSERT(instance_->interval_ == sampler->interval());
    500     instance_->active_samplers_.Add(sampler);
    501 
    502     if (need_to_start) instance_->StartSynchronously();
    503   }
    504 
    505   static void RemoveActiveSampler(Sampler* sampler) {
    506     SamplerThread* instance_to_remove = NULL;
    507     {
    508       LockGuard<Mutex> lock_guard(mutex_);
    509 
    510       ASSERT(sampler->IsActive());
    511       bool removed = instance_->active_samplers_.RemoveElement(sampler);
    512       ASSERT(removed);
    513       USE(removed);
    514 
    515       // We cannot delete the instance immediately as we need to Join() the
    516       // thread but we are holding mutex_ and the thread may try to acquire it.
    517       if (instance_->active_samplers_.is_empty()) {
    518         instance_to_remove = instance_;
    519         instance_ = NULL;
    520       }
    521     }
    522 
    523     if (!instance_to_remove) return;
    524     instance_to_remove->Join();
    525     delete instance_to_remove;
    526   }
    527 
    528   // Implement Thread::Run().
    529   virtual void Run() {
    530     while (true) {
    531       {
    532         LockGuard<Mutex> lock_guard(mutex_);
    533         if (active_samplers_.is_empty()) break;
    534         // When CPU profiling is enabled both JavaScript and C++ code is
    535         // profiled. We must not suspend.
    536         for (int i = 0; i < active_samplers_.length(); ++i) {
    537           Sampler* sampler = active_samplers_.at(i);
    538           if (!sampler->isolate()->IsInitialized()) continue;
    539           if (!sampler->IsProfiling()) continue;
    540           sampler->DoSample();
    541         }
    542       }
    543       OS::Sleep(interval_);
    544     }
    545   }
    546 
    547  private:
    548   // Protects the process wide state below.
    549   static Mutex* mutex_;
    550   static SamplerThread* instance_;
    551 
    552   const int interval_;
    553   List<Sampler*> active_samplers_;
    554 
    555   DISALLOW_COPY_AND_ASSIGN(SamplerThread);
    556 };
    557 
    558 
    559 Mutex* SamplerThread::mutex_ = NULL;
    560 SamplerThread* SamplerThread::instance_ = NULL;
    561 
    562 
    563 //
    564 // StackTracer implementation
    565 //
    566 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
    567                                    const RegisterState& regs) {
    568   ASSERT(isolate->IsInitialized());
    569   timestamp = TimeTicks::HighResolutionNow();
    570   pc = regs.pc;
    571   state = isolate->current_vm_state();
    572 
    573   // Avoid collecting traces while doing GC.
    574   if (state == GC) return;
    575 
    576   Address js_entry_sp = isolate->js_entry_sp();
    577   if (js_entry_sp == 0) {
    578     // Not executing JS now.
    579     return;
    580   }
    581 
    582   ExternalCallbackScope* scope = isolate->external_callback_scope();
    583   Address handler = Isolate::handler(isolate->thread_local_top());
    584   // If there is a handler on top of the external callback scope then
    585   // we have already entrered JavaScript again and the external callback
    586   // is not the top function.
    587   if (scope && scope->scope_address() < handler) {
    588     external_callback = scope->callback();
    589     has_external_callback = true;
    590   } else {
    591     // Sample potential return address value for frameless invocation of
    592     // stubs (we'll figure out later, if this value makes sense).
    593     tos = Memory::Address_at(regs.sp);
    594     has_external_callback = false;
    595   }
    596 
    597   SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
    598   top_frame_type = it.top_frame_type();
    599   int i = 0;
    600   while (!it.done() && i < TickSample::kMaxFramesCount) {
    601     stack[i++] = it.frame()->pc();
    602     it.Advance();
    603   }
    604   frames_count = i;
    605 }
    606 
    607 
    608 void Sampler::SetUp() {
    609 #if defined(USE_SIGNALS)
    610   SignalHandler::SetUp();
    611 #endif
    612   SamplerThread::SetUp();
    613 }
    614 
    615 
    616 void Sampler::TearDown() {
    617   SamplerThread::TearDown();
    618 #if defined(USE_SIGNALS)
    619   SignalHandler::TearDown();
    620 #endif
    621 }
    622 
    623 
    624 Sampler::Sampler(Isolate* isolate, int interval)
    625     : isolate_(isolate),
    626       interval_(interval),
    627       profiling_(false),
    628       has_processing_thread_(false),
    629       active_(false),
    630       is_counting_samples_(false),
    631       js_and_external_sample_count_(0) {
    632   data_ = new PlatformData;
    633 }
    634 
    635 
    636 Sampler::~Sampler() {
    637   ASSERT(!IsActive());
    638   delete data_;
    639 }
    640 
    641 
    642 void Sampler::Start() {
    643   ASSERT(!IsActive());
    644   SetActive(true);
    645   SamplerThread::AddActiveSampler(this);
    646 }
    647 
    648 
    649 void Sampler::Stop() {
    650   ASSERT(IsActive());
    651   SamplerThread::RemoveActiveSampler(this);
    652   SetActive(false);
    653 }
    654 
    655 
    656 void Sampler::IncreaseProfilingDepth() {
    657   base::NoBarrier_AtomicIncrement(&profiling_, 1);
    658 #if defined(USE_SIGNALS)
    659   SignalHandler::IncreaseSamplerCount();
    660 #endif
    661 }
    662 
    663 
    664 void Sampler::DecreaseProfilingDepth() {
    665 #if defined(USE_SIGNALS)
    666   SignalHandler::DecreaseSamplerCount();
    667 #endif
    668   base::NoBarrier_AtomicIncrement(&profiling_, -1);
    669 }
    670 
    671 
    672 void Sampler::SampleStack(const RegisterState& state) {
    673   TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
    674   TickSample sample_obj;
    675   if (sample == NULL) sample = &sample_obj;
    676   sample->Init(isolate_, state);
    677   if (is_counting_samples_) {
    678     if (sample->state == JS || sample->state == EXTERNAL) {
    679       ++js_and_external_sample_count_;
    680     }
    681   }
    682   Tick(sample);
    683   if (sample != &sample_obj) {
    684     isolate_->cpu_profiler()->FinishTickSample();
    685   }
    686 }
    687 
    688 
    689 #if defined(USE_SIGNALS)
    690 
    691 void Sampler::DoSample() {
    692   if (!SignalHandler::Installed()) return;
    693   pthread_kill(platform_data()->vm_tid(), SIGPROF);
    694 }
    695 
    696 #elif V8_OS_WIN || V8_OS_CYGWIN
    697 
    698 void Sampler::DoSample() {
    699   HANDLE profiled_thread = platform_data()->profiled_thread();
    700   if (profiled_thread == NULL) return;
    701 
    702 #if defined(USE_SIMULATOR)
    703   SimulatorHelper helper;
    704   if (!helper.Init(this, isolate())) return;
    705 #endif
    706 
    707   const DWORD kSuspendFailed = static_cast<DWORD>(-1);
    708   if (SuspendThread(profiled_thread) == kSuspendFailed) return;
    709 
    710   // Context used for sampling the register state of the profiled thread.
    711   CONTEXT context;
    712   memset(&context, 0, sizeof(context));
    713   context.ContextFlags = CONTEXT_FULL;
    714   if (GetThreadContext(profiled_thread, &context) != 0) {
    715     RegisterState state;
    716 #if defined(USE_SIMULATOR)
    717     helper.FillRegisters(&state);
    718 #else
    719 #if V8_HOST_ARCH_X64
    720     state.pc = reinterpret_cast<Address>(context.Rip);
    721     state.sp = reinterpret_cast<Address>(context.Rsp);
    722     state.fp = reinterpret_cast<Address>(context.Rbp);
    723 #else
    724     state.pc = reinterpret_cast<Address>(context.Eip);
    725     state.sp = reinterpret_cast<Address>(context.Esp);
    726     state.fp = reinterpret_cast<Address>(context.Ebp);
    727 #endif
    728 #endif  // USE_SIMULATOR
    729     SampleStack(state);
    730   }
    731   ResumeThread(profiled_thread);
    732 }
    733 
    734 #endif  // USE_SIGNALS
    735 
    736 
    737 } }  // namespace v8::internal
    738