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

Generated by: LCOV version 1.10