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