LCOV - code coverage report
Current view: top level - src/libsampler - sampler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 114 126 90.5 %
Date: 2017-10-20 Functions: 21 25 84.0 %

          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             : #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_FUCHSIA && !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       32623 :   explicit AtomicGuard(AtomicMutex* atomic, bool is_blocking = true)
     169       32623 :       : atomic_(atomic), is_success_(false) {
     170       32623 :     do {
     171             :       // Use Acquire_Load to gain mutual exclusion.
     172       32623 :       USE(atomic_->Value());
     173       65246 :       is_success_ = atomic_->TrySetValue(false, true);
     174         388 :     } while (is_blocking && !is_success_);
     175       32623 :   }
     176             : 
     177             :   bool is_success() const { return is_success_; }
     178             : 
     179       32623 :   ~AtomicGuard() {
     180       32623 :     if (!is_success_) return;
     181       32623 :     atomic_->SetValue(false);
     182       32623 :   }
     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       32623 :   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       32623 :   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       55274 :   PlatformData() : vm_tid_(pthread_self()) {}
     212       34513 :   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         194 :   void AddSampler(Sampler* sampler) {
     223         194 :     AtomicGuard atomic_guard(&samplers_access_counter_);
     224             :     DCHECK(sampler->IsActive() || !sampler->IsRegistered());
     225             :     // Add sampler into map if needed.
     226         194 :     pthread_t thread_id = sampler->platform_data()->vm_tid();
     227             :     base::HashMap::Entry* entry =
     228             :             sampler_map_.LookupOrInsert(ThreadKey(thread_id),
     229         388 :                                         ThreadHash(thread_id));
     230             :     DCHECK_NOT_NULL(entry);
     231         194 :     if (entry->value == nullptr) {
     232         194 :       SamplerList* samplers = new SamplerList();
     233         194 :       samplers->push_back(sampler);
     234         194 :       entry->value = samplers;
     235             :     } else {
     236             :       SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
     237             :       bool exists = false;
     238           0 :       for (SamplerListIterator iter = samplers->begin();
     239             :            iter != samplers->end(); ++iter) {
     240           0 :         if (*iter == sampler) {
     241             :           exists = true;
     242             :           break;
     243             :         }
     244             :       }
     245           0 :       if (!exists) {
     246           0 :         samplers->push_back(sampler);
     247             :       }
     248         194 :     }
     249         194 :   }
     250             : 
     251         388 :   void RemoveSampler(Sampler* sampler) {
     252         194 :     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         194 :     void* thread_key = ThreadKey(thread_id);
     257             :     uint32_t thread_hash = ThreadHash(thread_id);
     258         194 :     base::HashMap::Entry* entry = sampler_map_.Lookup(thread_key, thread_hash);
     259             :     DCHECK_NOT_NULL(entry);
     260         194 :     SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
     261         388 :     for (SamplerListIterator iter = samplers->begin(); iter != samplers->end();
     262             :          ++iter) {
     263         194 :       if (*iter == sampler) {
     264         194 :         samplers->erase(iter);
     265         194 :         break;
     266             :       }
     267             :     }
     268         194 :     if (samplers->empty()) {
     269         194 :       sampler_map_.Remove(thread_key, thread_hash);
     270         388 :       delete samplers;
     271         194 :     }
     272         194 :   }
     273             : 
     274             : #if defined(USE_SIGNALS)
     275       32235 :   void DoSample(const v8::RegisterState& state) {
     276       32235 :     AtomicGuard atomic_guard(&SamplerManager::samplers_access_counter_, false);
     277       32235 :     if (!atomic_guard.is_success()) return;
     278       32235 :     pthread_t thread_id = pthread_self();
     279             :     base::HashMap::Entry* entry =
     280       32235 :         sampler_map_.Lookup(ThreadKey(thread_id), ThreadHash(thread_id));
     281       32235 :     if (!entry) return;
     282       96705 :     SamplerList& samplers = *static_cast<SamplerList*>(entry->value);
     283             : 
     284      128940 :     for (size_t i = 0; i < samplers.size(); ++i) {
     285       32235 :       Sampler* sampler = samplers[i];
     286             :       Isolate* isolate = sampler->isolate();
     287             :       // We require a fully initialized and entered isolate.
     288       32235 :       if (isolate == nullptr || !isolate->IsInUse()) continue;
     289       32234 :       if (v8::Locker::IsActive() && !Locker::IsLocked(isolate)) continue;
     290       32234 :       sampler->SampleStack(state);
     291       32235 :     }
     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       53977 :   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
     346       29500 :   static void TearDown() {
     347       29500 :     delete mutex_;
     348       29500 :     mutex_ = nullptr;
     349       29500 :   }
     350             : 
     351         275 :   static void IncreaseSamplerCount() {
     352         275 :     base::LockGuard<base::Mutex> lock_guard(mutex_);
     353         275 :     if (++client_count_ == 1) Install();
     354         275 :   }
     355             : 
     356         275 :   static void DecreaseSamplerCount() {
     357         275 :     base::LockGuard<base::Mutex> lock_guard(mutex_);
     358         275 :     if (--client_count_ == 0) Restore();
     359         275 :   }
     360             : 
     361       34125 :   static bool Installed() {
     362       34125 :     base::LockGuard<base::Mutex> lock_guard(mutex_);
     363       68250 :     return signal_handler_installed_;
     364             :   }
     365             : 
     366             :  private:
     367         275 :   static void Install() {
     368             :     struct sigaction sa;
     369         275 :     sa.sa_sigaction = &HandleProfilerSignal;
     370         275 :     sigemptyset(&sa.sa_mask);
     371             : #if V8_OS_QNX
     372             :     sa.sa_flags = SA_SIGINFO;
     373             : #else
     374         275 :     sa.sa_flags = SA_RESTART | SA_SIGINFO;
     375             : #endif
     376             :     signal_handler_installed_ =
     377         275 :         (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
     378         275 :   }
     379             : 
     380         275 :   static void Restore() {
     381         275 :     if (signal_handler_installed_) {
     382         275 :       sigaction(SIGPROF, &old_signal_handler_, 0);
     383         275 :       signal_handler_installed_ = false;
     384             :     }
     385         275 :   }
     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       32235 : void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
     404             :                                          void* context) {
     405             :   USE(info);
     406       32235 :   if (signal != SIGPROF) return;
     407             :   v8::RegisterState state;
     408             :   FillRegisterState(context, &state);
     409       32235 :   SamplerManager::instance()->DoSample(state);
     410             : }
     411             : 
     412           0 : 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 || V8_OS_FUCHSIA
     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       32235 :   state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
     425       32235 :   state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
     426       32235 :   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             : #if V8_LIBC_GLIBC
     454             :   state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.regs->nip);
     455             :   state->sp =
     456             :       reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R1]);
     457             :   state->fp =
     458             :       reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R31]);
     459             : #else
     460             :   // Some C libraries, notably Musl, define the regs member as a void pointer
     461             :   state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[32]);
     462             :   state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[1]);
     463             :   state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[31]);
     464             : #endif
     465             : #elif V8_HOST_ARCH_S390
     466             : #if V8_TARGET_ARCH_32_BIT
     467             :   // 31-bit target will have bit 0 (MSB) of the PSW set to denote addressing
     468             :   // mode.  This bit needs to be masked out to resolve actual address.
     469             :   state->pc =
     470             :       reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr & 0x7FFFFFFF);
     471             : #else
     472             :   state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr);
     473             : #endif  // V8_TARGET_ARCH_32_BIT
     474             :   state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[15]);
     475             :   state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[11]);
     476             : #endif  // V8_HOST_ARCH_*
     477             : #elif V8_OS_MACOSX
     478             : #if V8_HOST_ARCH_X64
     479             : #if __DARWIN_UNIX03
     480             :   state->pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
     481             :   state->sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
     482             :   state->fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
     483             : #else  // !__DARWIN_UNIX03
     484             :   state->pc = reinterpret_cast<void*>(mcontext->ss.rip);
     485             :   state->sp = reinterpret_cast<void*>(mcontext->ss.rsp);
     486             :   state->fp = reinterpret_cast<void*>(mcontext->ss.rbp);
     487             : #endif  // __DARWIN_UNIX03
     488             : #elif V8_HOST_ARCH_IA32
     489             : #if __DARWIN_UNIX03
     490             :   state->pc = reinterpret_cast<void*>(mcontext->__ss.__eip);
     491             :   state->sp = reinterpret_cast<void*>(mcontext->__ss.__esp);
     492             :   state->fp = reinterpret_cast<void*>(mcontext->__ss.__ebp);
     493             : #else  // !__DARWIN_UNIX03
     494             :   state->pc = reinterpret_cast<void*>(mcontext->ss.eip);
     495             :   state->sp = reinterpret_cast<void*>(mcontext->ss.esp);
     496             :   state->fp = reinterpret_cast<void*>(mcontext->ss.ebp);
     497             : #endif  // __DARWIN_UNIX03
     498             : #endif  // V8_HOST_ARCH_IA32
     499             : #elif V8_OS_FREEBSD
     500             : #if V8_HOST_ARCH_IA32
     501             :   state->pc = reinterpret_cast<void*>(mcontext.mc_eip);
     502             :   state->sp = reinterpret_cast<void*>(mcontext.mc_esp);
     503             :   state->fp = reinterpret_cast<void*>(mcontext.mc_ebp);
     504             : #elif V8_HOST_ARCH_X64
     505             :   state->pc = reinterpret_cast<void*>(mcontext.mc_rip);
     506             :   state->sp = reinterpret_cast<void*>(mcontext.mc_rsp);
     507             :   state->fp = reinterpret_cast<void*>(mcontext.mc_rbp);
     508             : #elif V8_HOST_ARCH_ARM
     509             :   state->pc = reinterpret_cast<void*>(mcontext.mc_r15);
     510             :   state->sp = reinterpret_cast<void*>(mcontext.mc_r13);
     511             :   state->fp = reinterpret_cast<void*>(mcontext.mc_r11);
     512             : #endif  // V8_HOST_ARCH_*
     513             : #elif V8_OS_NETBSD
     514             : #if V8_HOST_ARCH_IA32
     515             :   state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]);
     516             :   state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]);
     517             :   state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]);
     518             : #elif V8_HOST_ARCH_X64
     519             :   state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]);
     520             :   state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]);
     521             :   state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]);
     522             : #endif  // V8_HOST_ARCH_*
     523             : #elif V8_OS_OPENBSD
     524             : #if V8_HOST_ARCH_IA32
     525             :   state->pc = reinterpret_cast<void*>(ucontext->sc_eip);
     526             :   state->sp = reinterpret_cast<void*>(ucontext->sc_esp);
     527             :   state->fp = reinterpret_cast<void*>(ucontext->sc_ebp);
     528             : #elif V8_HOST_ARCH_X64
     529             :   state->pc = reinterpret_cast<void*>(ucontext->sc_rip);
     530             :   state->sp = reinterpret_cast<void*>(ucontext->sc_rsp);
     531             :   state->fp = reinterpret_cast<void*>(ucontext->sc_rbp);
     532             : #endif  // V8_HOST_ARCH_*
     533             : #elif V8_OS_SOLARIS
     534             :   state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]);
     535             :   state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]);
     536             :   state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]);
     537             : #elif V8_OS_QNX
     538             : #if V8_HOST_ARCH_IA32
     539             :   state->pc = reinterpret_cast<void*>(mcontext.cpu.eip);
     540             :   state->sp = reinterpret_cast<void*>(mcontext.cpu.esp);
     541             :   state->fp = reinterpret_cast<void*>(mcontext.cpu.ebp);
     542             : #elif V8_HOST_ARCH_ARM
     543             :   state->pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]);
     544             :   state->sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]);
     545             :   state->fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]);
     546             : #endif  // V8_HOST_ARCH_*
     547             : #elif V8_OS_AIX
     548             :   state->pc = reinterpret_cast<void*>(mcontext.jmp_context.iar);
     549             :   state->sp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[1]);
     550             :   state->fp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[31]);
     551             : #endif  // V8_OS_AIX
     552           0 : }
     553             : 
     554             : #endif  // USE_SIGNALS
     555             : 
     556             : 
     557       53977 : void Sampler::SetUp() {
     558             : #if defined(USE_SIGNALS)
     559       53977 :   SignalHandler::SetUp();
     560             : #endif
     561       53977 : }
     562             : 
     563             : 
     564       29500 : void Sampler::TearDown() {
     565             : #if defined(USE_SIGNALS)
     566       29500 :   SignalHandler::TearDown();
     567             : #endif
     568       29500 : }
     569             : 
     570       55273 : Sampler::Sampler(Isolate* isolate)
     571             :     : is_counting_samples_(false),
     572             :       js_sample_count_(0),
     573             :       external_sample_count_(0),
     574             :       isolate_(isolate),
     575             :       profiling_(false),
     576             :       has_processing_thread_(false),
     577             :       active_(false),
     578       55273 :       registered_(false) {
     579      110545 :   data_ = new PlatformData;
     580       55272 : }
     581             : 
     582       53640 : Sampler::~Sampler() {
     583             :   DCHECK(!IsActive());
     584             : #if defined(USE_SIGNALS)
     585       53640 :   if (IsRegistered()) {
     586         194 :     SamplerManager::instance()->RemoveSampler(this);
     587             :   }
     588             : #endif
     589       53640 :   delete data_;
     590       53640 : }
     591             : 
     592           0 : void Sampler::Start() {
     593             :   DCHECK(!IsActive());
     594             :   SetActive(true);
     595             : #if defined(USE_SIGNALS)
     596           0 :   SamplerManager::instance()->AddSampler(this);
     597             : #endif
     598           0 : }
     599             : 
     600             : 
     601           0 : void Sampler::Stop() {
     602             : #if defined(USE_SIGNALS)
     603           0 :   SamplerManager::instance()->RemoveSampler(this);
     604             : #endif
     605             :   DCHECK(IsActive());
     606             :   SetActive(false);
     607             :   SetRegistered(false);
     608           0 : }
     609             : 
     610             : 
     611         275 : void Sampler::IncreaseProfilingDepth() {
     612         275 :   base::Relaxed_AtomicIncrement(&profiling_, 1);
     613             : #if defined(USE_SIGNALS)
     614         275 :   SignalHandler::IncreaseSamplerCount();
     615             : #endif
     616         275 : }
     617             : 
     618             : 
     619         275 : void Sampler::DecreaseProfilingDepth() {
     620             : #if defined(USE_SIGNALS)
     621         275 :   SignalHandler::DecreaseSamplerCount();
     622             : #endif
     623         275 :   base::Relaxed_AtomicIncrement(&profiling_, -1);
     624         275 : }
     625             : 
     626             : 
     627             : #if defined(USE_SIGNALS)
     628             : 
     629       68250 : void Sampler::DoSample() {
     630       68250 :   if (!SignalHandler::Installed()) return;
     631       68250 :   if (!IsActive() && !IsRegistered()) {
     632         194 :     SamplerManager::instance()->AddSampler(this);
     633             :     SetRegistered(true);
     634             :   }
     635       34125 :   pthread_kill(platform_data()->vm_tid(), SIGPROF);
     636             : }
     637             : 
     638             : #elif V8_OS_WIN || V8_OS_CYGWIN
     639             : 
     640             : void Sampler::DoSample() {
     641             :   HANDLE profiled_thread = platform_data()->profiled_thread();
     642             :   if (profiled_thread == nullptr) return;
     643             : 
     644             :   const DWORD kSuspendFailed = static_cast<DWORD>(-1);
     645             :   if (SuspendThread(profiled_thread) == kSuspendFailed) return;
     646             : 
     647             :   // Context used for sampling the register state of the profiled thread.
     648             :   CONTEXT context;
     649             :   memset(&context, 0, sizeof(context));
     650             :   context.ContextFlags = CONTEXT_FULL;
     651             :   if (GetThreadContext(profiled_thread, &context) != 0) {
     652             :     v8::RegisterState state;
     653             : #if V8_HOST_ARCH_X64
     654             :     state.pc = reinterpret_cast<void*>(context.Rip);
     655             :     state.sp = reinterpret_cast<void*>(context.Rsp);
     656             :     state.fp = reinterpret_cast<void*>(context.Rbp);
     657             : #else
     658             :     state.pc = reinterpret_cast<void*>(context.Eip);
     659             :     state.sp = reinterpret_cast<void*>(context.Esp);
     660             :     state.fp = reinterpret_cast<void*>(context.Ebp);
     661             : #endif
     662             :     SampleStack(state);
     663             :   }
     664             :   ResumeThread(profiled_thread);
     665             : }
     666             : 
     667             : #endif  // USE_SIGNALS
     668             : 
     669             : }  // namespace sampler
     670      107968 : }  // namespace v8

Generated by: LCOV version 1.10