LCOV - code coverage report
Current view: top level - src/libsampler - sampler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 79 81 97.5 %
Date: 2019-04-19 Functions: 17 19 89.5 %

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

Generated by: LCOV version 1.10