Home | History | Annotate | Download | only in libsampler
      1 // Copyright 2016 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/libsampler/v8-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 && !V8_OS_AIX
     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 <algorithm>
     46 #include <vector>
     47 #include <map>
     48 
     49 #include "src/base/atomic-utils.h"
     50 #include "src/base/hashmap.h"
     51 #include "src/base/platform/platform.h"
     52 
     53 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
     54 
     55 // Not all versions of Android's C library provide ucontext_t.
     56 // Detect this and provide custom but compatible definitions. Note that these
     57 // follow the GLibc naming convention to access register values from
     58 // mcontext_t.
     59 //
     60 // See http://code.google.com/p/android/issues/detail?id=34784
     61 
     62 #if defined(__arm__)
     63 
     64 typedef struct sigcontext mcontext_t;
     65 
     66 typedef struct ucontext {
     67   uint32_t uc_flags;
     68   struct ucontext* uc_link;
     69   stack_t uc_stack;
     70   mcontext_t uc_mcontext;
     71   // Other fields are not used by V8, don't define them here.
     72 } ucontext_t;
     73 
     74 #elif defined(__aarch64__)
     75 
     76 typedef struct sigcontext mcontext_t;
     77 
     78 typedef struct ucontext {
     79   uint64_t uc_flags;
     80   struct ucontext *uc_link;
     81   stack_t uc_stack;
     82   mcontext_t uc_mcontext;
     83   // Other fields are not used by V8, don't define them here.
     84 } ucontext_t;
     85 
     86 #elif defined(__mips__)
     87 // MIPS version of sigcontext, for Android bionic.
     88 typedef struct {
     89   uint32_t regmask;
     90   uint32_t status;
     91   uint64_t pc;
     92   uint64_t gregs[32];
     93   uint64_t fpregs[32];
     94   uint32_t acx;
     95   uint32_t fpc_csr;
     96   uint32_t fpc_eir;
     97   uint32_t used_math;
     98   uint32_t dsp;
     99   uint64_t mdhi;
    100   uint64_t mdlo;
    101   uint32_t hi1;
    102   uint32_t lo1;
    103   uint32_t hi2;
    104   uint32_t lo2;
    105   uint32_t hi3;
    106   uint32_t lo3;
    107 } mcontext_t;
    108 
    109 typedef struct ucontext {
    110   uint32_t uc_flags;
    111   struct ucontext* uc_link;
    112   stack_t uc_stack;
    113   mcontext_t uc_mcontext;
    114   // Other fields are not used by V8, don't define them here.
    115 } ucontext_t;
    116 
    117 #elif defined(__i386__)
    118 // x86 version for Android.
    119 typedef struct {
    120   uint32_t gregs[19];
    121   void* fpregs;
    122   uint32_t oldmask;
    123   uint32_t cr2;
    124 } mcontext_t;
    125 
    126 typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
    127 typedef struct ucontext {
    128   uint32_t uc_flags;
    129   struct ucontext* uc_link;
    130   stack_t uc_stack;
    131   mcontext_t uc_mcontext;
    132   // Other fields are not used by V8, don't define them here.
    133 } ucontext_t;
    134 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
    135 
    136 #elif defined(__x86_64__)
    137 // x64 version for Android.
    138 typedef struct {
    139   uint64_t gregs[23];
    140   void* fpregs;
    141   uint64_t __reserved1[8];
    142 } mcontext_t;
    143 
    144 typedef struct ucontext {
    145   uint64_t uc_flags;
    146   struct ucontext *uc_link;
    147   stack_t uc_stack;
    148   mcontext_t uc_mcontext;
    149   // Other fields are not used by V8, don't define them here.
    150 } ucontext_t;
    151 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
    152 #endif
    153 
    154 #endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
    155 
    156 
    157 namespace v8 {
    158 namespace sampler {
    159 
    160 namespace {
    161 
    162 #if defined(USE_SIGNALS)
    163 typedef std::vector<Sampler*> SamplerList;
    164 typedef SamplerList::iterator SamplerListIterator;
    165 typedef base::AtomicValue<bool> AtomicMutex;
    166 
    167 class AtomicGuard {
    168  public:
    169   explicit AtomicGuard(AtomicMutex* atomic, bool is_blocking = true)
    170       : atomic_(atomic), is_success_(false) {
    171     do {
    172       // Use Acquire_Load to gain mutual exclusion.
    173       USE(atomic_->Value());
    174       is_success_ = atomic_->TrySetValue(false, true);
    175     } while (is_blocking && !is_success_);
    176   }
    177 
    178   bool is_success() const { return is_success_; }
    179 
    180   ~AtomicGuard() {
    181     if (!is_success_) return;
    182     atomic_->SetValue(false);
    183   }
    184 
    185  private:
    186   AtomicMutex* const atomic_;
    187   bool is_success_;
    188 };
    189 
    190 // Returns key for hash map.
    191 void* ThreadKey(pthread_t thread_id) {
    192   return reinterpret_cast<void*>(thread_id);
    193 }
    194 
    195 // Returns hash value for hash map.
    196 uint32_t ThreadHash(pthread_t thread_id) {
    197 #if V8_OS_MACOSX
    198   return static_cast<uint32_t>(reinterpret_cast<intptr_t>(thread_id));
    199 #else
    200   return static_cast<uint32_t>(thread_id);
    201 #endif
    202 }
    203 
    204 #endif  // USE_SIGNALS
    205 
    206 }  // namespace
    207 
    208 #if defined(USE_SIGNALS)
    209 
    210 class Sampler::PlatformData {
    211  public:
    212   PlatformData() : vm_tid_(pthread_self()) {}
    213   pthread_t vm_tid() const { return vm_tid_; }
    214 
    215  private:
    216   pthread_t vm_tid_;
    217 };
    218 
    219 class SamplerManager {
    220  public:
    221   SamplerManager() : sampler_map_(base::HashMap::PointersMatch) {}
    222 
    223   void AddSampler(Sampler* sampler) {
    224     AtomicGuard atomic_guard(&samplers_access_counter_);
    225     DCHECK(sampler->IsActive() || !sampler->IsRegistered());
    226     // Add sampler into map if needed.
    227     pthread_t thread_id = sampler->platform_data()->vm_tid();
    228     base::HashMap::Entry* entry =
    229             sampler_map_.LookupOrInsert(ThreadKey(thread_id),
    230                                         ThreadHash(thread_id));
    231     DCHECK(entry != nullptr);
    232     if (entry->value == nullptr) {
    233       SamplerList* samplers = new SamplerList();
    234       samplers->push_back(sampler);
    235       entry->value = samplers;
    236     } else {
    237       SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
    238       bool exists = false;
    239       for (SamplerListIterator iter = samplers->begin();
    240            iter != samplers->end(); ++iter) {
    241         if (*iter == sampler) {
    242           exists = true;
    243           break;
    244         }
    245       }
    246       if (!exists) {
    247         samplers->push_back(sampler);
    248       }
    249     }
    250   }
    251 
    252   void RemoveSampler(Sampler* sampler) {
    253     AtomicGuard atomic_guard(&samplers_access_counter_);
    254     DCHECK(sampler->IsActive() || sampler->IsRegistered());
    255     // Remove sampler from map.
    256     pthread_t thread_id = sampler->platform_data()->vm_tid();
    257     void* thread_key = ThreadKey(thread_id);
    258     uint32_t thread_hash = ThreadHash(thread_id);
    259     base::HashMap::Entry* entry = sampler_map_.Lookup(thread_key, thread_hash);
    260     DCHECK(entry != nullptr);
    261     SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
    262     for (SamplerListIterator iter = samplers->begin(); iter != samplers->end();
    263          ++iter) {
    264       if (*iter == sampler) {
    265         samplers->erase(iter);
    266         break;
    267       }
    268     }
    269     if (samplers->empty()) {
    270       sampler_map_.Remove(thread_key, thread_hash);
    271       delete samplers;
    272     }
    273   }
    274 
    275 #if defined(USE_SIGNALS)
    276   void DoSample(const v8::RegisterState& state) {
    277     AtomicGuard atomic_guard(&SamplerManager::samplers_access_counter_, false);
    278     if (!atomic_guard.is_success()) return;
    279     pthread_t thread_id = pthread_self();
    280     base::HashMap::Entry* entry =
    281         sampler_map_.Lookup(ThreadKey(thread_id), ThreadHash(thread_id));
    282     if (!entry) return;
    283     SamplerList& samplers = *static_cast<SamplerList*>(entry->value);
    284 
    285     for (int i = 0; i < samplers.size(); ++i) {
    286       Sampler* sampler = samplers[i];
    287       Isolate* isolate = sampler->isolate();
    288       // We require a fully initialized and entered isolate.
    289       if (isolate == nullptr || !isolate->IsInUse()) continue;
    290       if (v8::Locker::IsActive() && !Locker::IsLocked(isolate)) continue;
    291       sampler->SampleStack(state);
    292     }
    293   }
    294 #endif
    295 
    296   static SamplerManager* instance() { return instance_.Pointer(); }
    297 
    298  private:
    299   base::HashMap sampler_map_;
    300   static AtomicMutex samplers_access_counter_;
    301   static base::LazyInstance<SamplerManager>::type instance_;
    302 };
    303 
    304 AtomicMutex SamplerManager::samplers_access_counter_;
    305 base::LazyInstance<SamplerManager>::type SamplerManager::instance_ =
    306     LAZY_INSTANCE_INITIALIZER;
    307 
    308 #elif V8_OS_WIN || V8_OS_CYGWIN
    309 
    310 // ----------------------------------------------------------------------------
    311 // Win32 profiler support. On Cygwin we use the same sampler implementation as
    312 // on Win32.
    313 
    314 class Sampler::PlatformData {
    315  public:
    316   // Get a handle to the calling thread. This is the thread that we are
    317   // going to profile. We need to make a copy of the handle because we are
    318   // going to use it in the sampler thread. Using GetThreadHandle() will
    319   // not work in this case. We're using OpenThread because DuplicateHandle
    320   // for some reason doesn't work in Chrome's sandbox.
    321   PlatformData()
    322       : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
    323                                     THREAD_SUSPEND_RESUME |
    324                                     THREAD_QUERY_INFORMATION,
    325                                     false,
    326                                     GetCurrentThreadId())) {}
    327 
    328   ~PlatformData() {
    329     if (profiled_thread_ != nullptr) {
    330       CloseHandle(profiled_thread_);
    331       profiled_thread_ = nullptr;
    332     }
    333   }
    334 
    335   HANDLE profiled_thread() { return profiled_thread_; }
    336 
    337  private:
    338   HANDLE profiled_thread_;
    339 };
    340 #endif  // USE_SIGNALS
    341 
    342 
    343 #if defined(USE_SIGNALS)
    344 class SignalHandler {
    345  public:
    346   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
    347   static void TearDown() {
    348     delete mutex_;
    349     mutex_ = nullptr;
    350   }
    351 
    352   static void IncreaseSamplerCount() {
    353     base::LockGuard<base::Mutex> lock_guard(mutex_);
    354     if (++client_count_ == 1) Install();
    355   }
    356 
    357   static void DecreaseSamplerCount() {
    358     base::LockGuard<base::Mutex> lock_guard(mutex_);
    359     if (--client_count_ == 0) Restore();
    360   }
    361 
    362   static bool Installed() {
    363     base::LockGuard<base::Mutex> lock_guard(mutex_);
    364     return signal_handler_installed_;
    365   }
    366 
    367  private:
    368   static void Install() {
    369 #if !V8_OS_NACL
    370     struct sigaction sa;
    371     sa.sa_sigaction = &HandleProfilerSignal;
    372     sigemptyset(&sa.sa_mask);
    373 #if V8_OS_QNX
    374     sa.sa_flags = SA_SIGINFO;
    375 #else
    376     sa.sa_flags = SA_RESTART | SA_SIGINFO;
    377 #endif
    378     signal_handler_installed_ =
    379         (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
    380 #endif  // !V8_OS_NACL
    381   }
    382 
    383   static void Restore() {
    384 #if !V8_OS_NACL
    385     if (signal_handler_installed_) {
    386       sigaction(SIGPROF, &old_signal_handler_, 0);
    387       signal_handler_installed_ = false;
    388     }
    389 #endif
    390   }
    391 
    392 #if !V8_OS_NACL
    393   static void FillRegisterState(void* context, RegisterState* regs);
    394   static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
    395 #endif
    396   // Protects the process wide state below.
    397   static base::Mutex* mutex_;
    398   static int client_count_;
    399   static bool signal_handler_installed_;
    400   static struct sigaction old_signal_handler_;
    401 };
    402 
    403 base::Mutex* SignalHandler::mutex_ = nullptr;
    404 int SignalHandler::client_count_ = 0;
    405 struct sigaction SignalHandler::old_signal_handler_;
    406 bool SignalHandler::signal_handler_installed_ = false;
    407 
    408 
    409 // As Native Client does not support signal handling, profiling is disabled.
    410 #if !V8_OS_NACL
    411 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
    412                                          void* context) {
    413   USE(info);
    414   if (signal != SIGPROF) return;
    415   v8::RegisterState state;
    416   FillRegisterState(context, &state);
    417   SamplerManager::instance()->DoSample(state);
    418 }
    419 
    420 void SignalHandler::FillRegisterState(void* context, RegisterState* state) {
    421   // Extracting the sample from the context is extremely machine dependent.
    422   ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
    423 #if !(V8_OS_OPENBSD || (V8_OS_LINUX && (V8_HOST_ARCH_PPC || V8_HOST_ARCH_S390)))
    424   mcontext_t& mcontext = ucontext->uc_mcontext;
    425 #endif
    426 #if V8_OS_LINUX
    427 #if V8_HOST_ARCH_IA32
    428   state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]);
    429   state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]);
    430   state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]);
    431 #elif V8_HOST_ARCH_X64
    432   state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
    433   state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
    434   state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
    435 #elif V8_HOST_ARCH_ARM
    436 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
    437   // Old GLibc ARM versions used a gregs[] array to access the register
    438   // values from mcontext_t.
    439   state->pc = reinterpret_cast<void*>(mcontext.gregs[R15]);
    440   state->sp = reinterpret_cast<void*>(mcontext.gregs[R13]);
    441   state->fp = reinterpret_cast<void*>(mcontext.gregs[R11]);
    442 #else
    443   state->pc = reinterpret_cast<void*>(mcontext.arm_pc);
    444   state->sp = reinterpret_cast<void*>(mcontext.arm_sp);
    445   state->fp = reinterpret_cast<void*>(mcontext.arm_fp);
    446 #endif  // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
    447 #elif V8_HOST_ARCH_ARM64
    448   state->pc = reinterpret_cast<void*>(mcontext.pc);
    449   state->sp = reinterpret_cast<void*>(mcontext.sp);
    450   // FP is an alias for x29.
    451   state->fp = reinterpret_cast<void*>(mcontext.regs[29]);
    452 #elif V8_HOST_ARCH_MIPS
    453   state->pc = reinterpret_cast<void*>(mcontext.pc);
    454   state->sp = reinterpret_cast<void*>(mcontext.gregs[29]);
    455   state->fp = reinterpret_cast<void*>(mcontext.gregs[30]);
    456 #elif V8_HOST_ARCH_MIPS64
    457   state->pc = reinterpret_cast<void*>(mcontext.pc);
    458   state->sp = reinterpret_cast<void*>(mcontext.gregs[29]);
    459   state->fp = reinterpret_cast<void*>(mcontext.gregs[30]);
    460 #elif V8_HOST_ARCH_PPC
    461   state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.regs->nip);
    462   state->sp =
    463       reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R1]);
    464   state->fp =
    465       reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R31]);
    466 #elif V8_HOST_ARCH_S390
    467 #if V8_TARGET_ARCH_32_BIT
    468   // 31-bit target will have bit 0 (MSB) of the PSW set to denote addressing
    469   // mode.  This bit needs to be masked out to resolve actual address.
    470   state->pc =
    471       reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr & 0x7FFFFFFF);
    472 #else
    473   state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr);
    474 #endif  // V8_TARGET_ARCH_32_BIT
    475   state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[15]);
    476   state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[11]);
    477 #endif  // V8_HOST_ARCH_*
    478 #elif V8_OS_MACOSX
    479 #if V8_HOST_ARCH_X64
    480 #if __DARWIN_UNIX03
    481   state->pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
    482   state->sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
    483   state->fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
    484 #else  // !__DARWIN_UNIX03
    485   state->pc = reinterpret_cast<void*>(mcontext->ss.rip);
    486   state->sp = reinterpret_cast<void*>(mcontext->ss.rsp);
    487   state->fp = reinterpret_cast<void*>(mcontext->ss.rbp);
    488 #endif  // __DARWIN_UNIX03
    489 #elif V8_HOST_ARCH_IA32
    490 #if __DARWIN_UNIX03
    491   state->pc = reinterpret_cast<void*>(mcontext->__ss.__eip);
    492   state->sp = reinterpret_cast<void*>(mcontext->__ss.__esp);
    493   state->fp = reinterpret_cast<void*>(mcontext->__ss.__ebp);
    494 #else  // !__DARWIN_UNIX03
    495   state->pc = reinterpret_cast<void*>(mcontext->ss.eip);
    496   state->sp = reinterpret_cast<void*>(mcontext->ss.esp);
    497   state->fp = reinterpret_cast<void*>(mcontext->ss.ebp);
    498 #endif  // __DARWIN_UNIX03
    499 #endif  // V8_HOST_ARCH_IA32
    500 #elif V8_OS_FREEBSD
    501 #if V8_HOST_ARCH_IA32
    502   state->pc = reinterpret_cast<void*>(mcontext.mc_eip);
    503   state->sp = reinterpret_cast<void*>(mcontext.mc_esp);
    504   state->fp = reinterpret_cast<void*>(mcontext.mc_ebp);
    505 #elif V8_HOST_ARCH_X64
    506   state->pc = reinterpret_cast<void*>(mcontext.mc_rip);
    507   state->sp = reinterpret_cast<void*>(mcontext.mc_rsp);
    508   state->fp = reinterpret_cast<void*>(mcontext.mc_rbp);
    509 #elif V8_HOST_ARCH_ARM
    510   state->pc = reinterpret_cast<void*>(mcontext.mc_r15);
    511   state->sp = reinterpret_cast<void*>(mcontext.mc_r13);
    512   state->fp = reinterpret_cast<void*>(mcontext.mc_r11);
    513 #endif  // V8_HOST_ARCH_*
    514 #elif V8_OS_NETBSD
    515 #if V8_HOST_ARCH_IA32
    516   state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]);
    517   state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]);
    518   state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]);
    519 #elif V8_HOST_ARCH_X64
    520   state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]);
    521   state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]);
    522   state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]);
    523 #endif  // V8_HOST_ARCH_*
    524 #elif V8_OS_OPENBSD
    525 #if V8_HOST_ARCH_IA32
    526   state->pc = reinterpret_cast<void*>(ucontext->sc_eip);
    527   state->sp = reinterpret_cast<void*>(ucontext->sc_esp);
    528   state->fp = reinterpret_cast<void*>(ucontext->sc_ebp);
    529 #elif V8_HOST_ARCH_X64
    530   state->pc = reinterpret_cast<void*>(ucontext->sc_rip);
    531   state->sp = reinterpret_cast<void*>(ucontext->sc_rsp);
    532   state->fp = reinterpret_cast<void*>(ucontext->sc_rbp);
    533 #endif  // V8_HOST_ARCH_*
    534 #elif V8_OS_SOLARIS
    535   state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]);
    536   state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]);
    537   state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]);
    538 #elif V8_OS_QNX
    539 #if V8_HOST_ARCH_IA32
    540   state->pc = reinterpret_cast<void*>(mcontext.cpu.eip);
    541   state->sp = reinterpret_cast<void*>(mcontext.cpu.esp);
    542   state->fp = reinterpret_cast<void*>(mcontext.cpu.ebp);
    543 #elif V8_HOST_ARCH_ARM
    544   state->pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]);
    545   state->sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]);
    546   state->fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]);
    547 #endif  // V8_HOST_ARCH_*
    548 #elif V8_OS_AIX
    549   state->pc = reinterpret_cast<void*>(mcontext.jmp_context.iar);
    550   state->sp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[1]);
    551   state->fp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[31]);
    552 #endif  // V8_OS_AIX
    553 }
    554 
    555 #endif  // !V8_OS_NACL
    556 
    557 #endif  // USE_SIGNALS
    558 
    559 
    560 void Sampler::SetUp() {
    561 #if defined(USE_SIGNALS)
    562   SignalHandler::SetUp();
    563 #endif
    564 }
    565 
    566 
    567 void Sampler::TearDown() {
    568 #if defined(USE_SIGNALS)
    569   SignalHandler::TearDown();
    570 #endif
    571 }
    572 
    573 Sampler::Sampler(Isolate* isolate)
    574     : is_counting_samples_(false),
    575       js_sample_count_(0),
    576       external_sample_count_(0),
    577       isolate_(isolate),
    578       profiling_(false),
    579       has_processing_thread_(false),
    580       active_(false),
    581       registered_(false) {
    582   data_ = new PlatformData;
    583 }
    584 
    585 Sampler::~Sampler() {
    586   DCHECK(!IsActive());
    587 #if defined(USE_SIGNALS)
    588   if (IsRegistered()) {
    589     SamplerManager::instance()->RemoveSampler(this);
    590   }
    591 #endif
    592   delete data_;
    593 }
    594 
    595 void Sampler::Start() {
    596   DCHECK(!IsActive());
    597   SetActive(true);
    598 #if defined(USE_SIGNALS)
    599   SamplerManager::instance()->AddSampler(this);
    600 #endif
    601 }
    602 
    603 
    604 void Sampler::Stop() {
    605 #if defined(USE_SIGNALS)
    606   SamplerManager::instance()->RemoveSampler(this);
    607 #endif
    608   DCHECK(IsActive());
    609   SetActive(false);
    610   SetRegistered(false);
    611 }
    612 
    613 
    614 void Sampler::IncreaseProfilingDepth() {
    615   base::NoBarrier_AtomicIncrement(&profiling_, 1);
    616 #if defined(USE_SIGNALS)
    617   SignalHandler::IncreaseSamplerCount();
    618 #endif
    619 }
    620 
    621 
    622 void Sampler::DecreaseProfilingDepth() {
    623 #if defined(USE_SIGNALS)
    624   SignalHandler::DecreaseSamplerCount();
    625 #endif
    626   base::NoBarrier_AtomicIncrement(&profiling_, -1);
    627 }
    628 
    629 
    630 #if defined(USE_SIGNALS)
    631 
    632 void Sampler::DoSample() {
    633   if (!SignalHandler::Installed()) return;
    634   if (!IsActive() && !IsRegistered()) {
    635     SamplerManager::instance()->AddSampler(this);
    636     SetRegistered(true);
    637   }
    638   pthread_kill(platform_data()->vm_tid(), SIGPROF);
    639 }
    640 
    641 #elif V8_OS_WIN || V8_OS_CYGWIN
    642 
    643 void Sampler::DoSample() {
    644   HANDLE profiled_thread = platform_data()->profiled_thread();
    645   if (profiled_thread == nullptr) return;
    646 
    647   const DWORD kSuspendFailed = static_cast<DWORD>(-1);
    648   if (SuspendThread(profiled_thread) == kSuspendFailed) return;
    649 
    650   // Context used for sampling the register state of the profiled thread.
    651   CONTEXT context;
    652   memset(&context, 0, sizeof(context));
    653   context.ContextFlags = CONTEXT_FULL;
    654   if (GetThreadContext(profiled_thread, &context) != 0) {
    655     v8::RegisterState state;
    656 #if V8_HOST_ARCH_X64
    657     state.pc = reinterpret_cast<void*>(context.Rip);
    658     state.sp = reinterpret_cast<void*>(context.Rsp);
    659     state.fp = reinterpret_cast<void*>(context.Rbp);
    660 #else
    661     state.pc = reinterpret_cast<void*>(context.Eip);
    662     state.sp = reinterpret_cast<void*>(context.Esp);
    663     state.fp = reinterpret_cast<void*>(context.Ebp);
    664 #endif
    665     SampleStack(state);
    666   }
    667   ResumeThread(profiled_thread);
    668 }
    669 
    670 #endif  // USE_SIGNALS
    671 
    672 }  // namespace sampler
    673 }  // namespace v8
    674