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