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