V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
sampler.cc
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 SamplerList::iterator SamplerListIterator;
179 typedef std::atomic_bool AtomicMutex;
180 
181 class AtomicGuard {
182  public:
183  explicit AtomicGuard(AtomicMutex* atomic, bool is_blocking = true)
184  : atomic_(atomic), is_success_(false) {
185  do {
186  bool expected = false;
187  is_success_ = atomic->compare_exchange_weak(expected, true);
188  } while (is_blocking && !is_success_);
189  }
190 
191  bool is_success() const { return is_success_; }
192 
193  ~AtomicGuard() {
194  if (!is_success_) return;
195  atomic_->store(false);
196  }
197 
198  private:
199  AtomicMutex* const atomic_;
200  bool is_success_;
201 };
202 
203 // Returns key for hash map.
204 void* ThreadKey(pthread_t thread_id) {
205  return reinterpret_cast<void*>(thread_id);
206 }
207 
208 // Returns hash value for hash map.
209 uint32_t ThreadHash(pthread_t thread_id) {
210 #if V8_OS_BSD
211  return static_cast<uint32_t>(reinterpret_cast<intptr_t>(thread_id));
212 #else
213  return static_cast<uint32_t>(thread_id);
214 #endif
215 }
216 
217 #endif // USE_SIGNALS
218 
219 } // namespace
220 
221 #if defined(USE_SIGNALS)
222 
223 class Sampler::PlatformData {
224  public:
225  PlatformData() : vm_tid_(pthread_self()) {}
226  pthread_t vm_tid() const { return vm_tid_; }
227 
228  private:
229  pthread_t vm_tid_;
230 };
231 
232 class SamplerManager {
233  public:
234  SamplerManager() : sampler_map_() {}
235 
236  void AddSampler(Sampler* sampler) {
237  AtomicGuard atomic_guard(&samplers_access_counter_);
238  DCHECK(sampler->IsActive() || !sampler->IsRegistered());
239  // Add sampler into map if needed.
240  pthread_t thread_id = sampler->platform_data()->vm_tid();
241  base::HashMap::Entry* entry =
242  sampler_map_.LookupOrInsert(ThreadKey(thread_id),
243  ThreadHash(thread_id));
244  DCHECK_NOT_NULL(entry);
245  if (entry->value == nullptr) {
246  SamplerList* samplers = new SamplerList();
247  samplers->push_back(sampler);
248  entry->value = samplers;
249  } else {
250  SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
251  bool exists = false;
252  for (SamplerListIterator iter = samplers->begin();
253  iter != samplers->end(); ++iter) {
254  if (*iter == sampler) {
255  exists = true;
256  break;
257  }
258  }
259  if (!exists) {
260  samplers->push_back(sampler);
261  }
262  }
263  }
264 
265  void RemoveSampler(Sampler* sampler) {
266  AtomicGuard atomic_guard(&samplers_access_counter_);
267  DCHECK(sampler->IsActive() || sampler->IsRegistered());
268  // Remove sampler from map.
269  pthread_t thread_id = sampler->platform_data()->vm_tid();
270  void* thread_key = ThreadKey(thread_id);
271  uint32_t thread_hash = ThreadHash(thread_id);
272  base::HashMap::Entry* entry = sampler_map_.Lookup(thread_key, thread_hash);
273  DCHECK_NOT_NULL(entry);
274  SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
275  for (SamplerListIterator iter = samplers->begin(); iter != samplers->end();
276  ++iter) {
277  if (*iter == sampler) {
278  samplers->erase(iter);
279  break;
280  }
281  }
282  if (samplers->empty()) {
283  sampler_map_.Remove(thread_key, thread_hash);
284  delete samplers;
285  }
286  }
287 
288 #if defined(USE_SIGNALS)
289  void DoSample(const v8::RegisterState& state) {
290  AtomicGuard atomic_guard(&SamplerManager::samplers_access_counter_, false);
291  if (!atomic_guard.is_success()) return;
292  pthread_t thread_id = pthread_self();
293  base::HashMap::Entry* entry =
294  sampler_map_.Lookup(ThreadKey(thread_id), ThreadHash(thread_id));
295  if (!entry) return;
296  SamplerList& samplers = *static_cast<SamplerList*>(entry->value);
297 
298  for (size_t i = 0; i < samplers.size(); ++i) {
299  Sampler* sampler = samplers[i];
300  Isolate* isolate = sampler->isolate();
301  // We require a fully initialized and entered isolate.
302  if (isolate == nullptr || !isolate->IsInUse()) continue;
303  if (v8::Locker::IsActive() && !Locker::IsLocked(isolate)) continue;
304  sampler->SampleStack(state);
305  }
306  }
307 #endif
308 
309  static SamplerManager* instance() { return instance_.Pointer(); }
310 
311  private:
312  base::HashMap sampler_map_;
313  static AtomicMutex samplers_access_counter_;
314  static base::LazyInstance<SamplerManager>::type instance_;
315 };
316 
317 AtomicMutex SamplerManager::samplers_access_counter_;
318 base::LazyInstance<SamplerManager>::type SamplerManager::instance_ =
319  LAZY_INSTANCE_INITIALIZER;
320 
321 #elif V8_OS_WIN || V8_OS_CYGWIN
322 
323 // ----------------------------------------------------------------------------
324 // Win32 profiler support. On Cygwin we use the same sampler implementation as
325 // on Win32.
326 
327 class Sampler::PlatformData {
328  public:
329  // Get a handle to the calling thread. This is the thread that we are
330  // going to profile. We need to make a copy of the handle because we are
331  // going to use it in the sampler thread. Using GetThreadHandle() will
332  // not work in this case. We're using OpenThread because DuplicateHandle
333  // for some reason doesn't work in Chrome's sandbox.
334  PlatformData()
335  : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
336  THREAD_SUSPEND_RESUME |
337  THREAD_QUERY_INFORMATION,
338  false,
339  GetCurrentThreadId())) {}
340 
341  ~PlatformData() {
342  if (profiled_thread_ != nullptr) {
343  CloseHandle(profiled_thread_);
344  profiled_thread_ = nullptr;
345  }
346  }
347 
348  HANDLE profiled_thread() { return profiled_thread_; }
349 
350  private:
351  HANDLE profiled_thread_;
352 };
353 
354 #elif V8_OS_FUCHSIA
355 
356 class Sampler::PlatformData {
357  public:
358  PlatformData() {
359  zx_handle_duplicate(zx_thread_self(), ZX_RIGHT_SAME_RIGHTS,
360  &profiled_thread_);
361  }
362  ~PlatformData() {
363  if (profiled_thread_ != ZX_HANDLE_INVALID) {
364  zx_handle_close(profiled_thread_);
365  profiled_thread_ = ZX_HANDLE_INVALID;
366  }
367  }
368 
369  zx_handle_t profiled_thread() { return profiled_thread_; }
370 
371  private:
372  zx_handle_t profiled_thread_ = ZX_HANDLE_INVALID;
373 };
374 
375 #endif // USE_SIGNALS
376 
377 
378 #if defined(USE_SIGNALS)
379 class SignalHandler {
380  public:
381  static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
382  static void TearDown() {
383  delete mutex_;
384  mutex_ = nullptr;
385  }
386 
387  static void IncreaseSamplerCount() {
388  base::MutexGuard lock_guard(mutex_);
389  if (++client_count_ == 1) Install();
390  }
391 
392  static void DecreaseSamplerCount() {
393  base::MutexGuard lock_guard(mutex_);
394  if (--client_count_ == 0) Restore();
395  }
396 
397  static bool Installed() {
398  base::MutexGuard lock_guard(mutex_);
399  return signal_handler_installed_;
400  }
401 
402  private:
403  static void Install() {
404  struct sigaction sa;
405  sa.sa_sigaction = &HandleProfilerSignal;
406  sigemptyset(&sa.sa_mask);
407 #if V8_OS_QNX
408  sa.sa_flags = SA_SIGINFO;
409 #else
410  sa.sa_flags = SA_RESTART | SA_SIGINFO;
411 #endif
412  signal_handler_installed_ =
413  (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
414  }
415 
416  static void Restore() {
417  if (signal_handler_installed_) {
418  sigaction(SIGPROF, &old_signal_handler_, nullptr);
419  signal_handler_installed_ = false;
420  }
421  }
422 
423  static void FillRegisterState(void* context, RegisterState* regs);
424  static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
425 
426  // Protects the process wide state below.
427  static base::Mutex* mutex_;
428  static int client_count_;
429  static bool signal_handler_installed_;
430  static struct sigaction old_signal_handler_;
431 };
432 
433 base::Mutex* SignalHandler::mutex_ = nullptr;
434 int SignalHandler::client_count_ = 0;
435 struct sigaction SignalHandler::old_signal_handler_;
436 bool SignalHandler::signal_handler_installed_ = false;
437 
438 
439 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
440  void* context) {
441  USE(info);
442  if (signal != SIGPROF) return;
443  v8::RegisterState state;
444  FillRegisterState(context, &state);
445  SamplerManager::instance()->DoSample(state);
446 }
447 
448 void SignalHandler::FillRegisterState(void* context, RegisterState* state) {
449  // Extracting the sample from the context is extremely machine dependent.
450  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
451 #if !(V8_OS_OPENBSD || (V8_OS_LINUX && (V8_HOST_ARCH_PPC || V8_HOST_ARCH_S390)))
452  mcontext_t& mcontext = ucontext->uc_mcontext;
453 #endif
454 #if V8_OS_LINUX
455 #if V8_HOST_ARCH_IA32
456  state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]);
457  state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]);
458  state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]);
459 #elif V8_HOST_ARCH_X64
460  state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
461  state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
462  state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
463 #elif V8_HOST_ARCH_ARM
464 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
465  // Old GLibc ARM versions used a gregs[] array to access the register
466  // values from mcontext_t.
467  state->pc = reinterpret_cast<void*>(mcontext.gregs[R15]);
468  state->sp = reinterpret_cast<void*>(mcontext.gregs[R13]);
469  state->fp = reinterpret_cast<void*>(mcontext.gregs[R11]);
470 #else
471  state->pc = reinterpret_cast<void*>(mcontext.arm_pc);
472  state->sp = reinterpret_cast<void*>(mcontext.arm_sp);
473  state->fp = reinterpret_cast<void*>(mcontext.arm_fp);
474 #endif // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
475 #elif V8_HOST_ARCH_ARM64
476  state->pc = reinterpret_cast<void*>(mcontext.pc);
477  state->sp = reinterpret_cast<void*>(mcontext.sp);
478  // FP is an alias for x29.
479  state->fp = reinterpret_cast<void*>(mcontext.regs[29]);
480 #elif V8_HOST_ARCH_MIPS
481  state->pc = reinterpret_cast<void*>(mcontext.pc);
482  state->sp = reinterpret_cast<void*>(mcontext.gregs[29]);
483  state->fp = reinterpret_cast<void*>(mcontext.gregs[30]);
484 #elif V8_HOST_ARCH_MIPS64
485  state->pc = reinterpret_cast<void*>(mcontext.pc);
486  state->sp = reinterpret_cast<void*>(mcontext.gregs[29]);
487  state->fp = reinterpret_cast<void*>(mcontext.gregs[30]);
488 #elif V8_HOST_ARCH_PPC
489 #if V8_LIBC_GLIBC
490  state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.regs->nip);
491  state->sp =
492  reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R1]);
493  state->fp =
494  reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R31]);
495 #else
496  // Some C libraries, notably Musl, define the regs member as a void pointer
497  state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[32]);
498  state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[1]);
499  state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[31]);
500 #endif
501 #elif V8_HOST_ARCH_S390
502 #if V8_TARGET_ARCH_32_BIT
503  // 31-bit target will have bit 0 (MSB) of the PSW set to denote addressing
504  // mode. This bit needs to be masked out to resolve actual address.
505  state->pc =
506  reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr & 0x7FFFFFFF);
507 #else
508  state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr);
509 #endif // V8_TARGET_ARCH_32_BIT
510  state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[15]);
511  state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[11]);
512 #endif // V8_HOST_ARCH_*
513 #elif V8_OS_MACOSX
514 #if V8_HOST_ARCH_X64
515 #if __DARWIN_UNIX03
516  state->pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
517  state->sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
518  state->fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
519 #else // !__DARWIN_UNIX03
520  state->pc = reinterpret_cast<void*>(mcontext->ss.rip);
521  state->sp = reinterpret_cast<void*>(mcontext->ss.rsp);
522  state->fp = reinterpret_cast<void*>(mcontext->ss.rbp);
523 #endif // __DARWIN_UNIX03
524 #elif V8_HOST_ARCH_IA32
525 #if __DARWIN_UNIX03
526  state->pc = reinterpret_cast<void*>(mcontext->__ss.__eip);
527  state->sp = reinterpret_cast<void*>(mcontext->__ss.__esp);
528  state->fp = reinterpret_cast<void*>(mcontext->__ss.__ebp);
529 #else // !__DARWIN_UNIX03
530  state->pc = reinterpret_cast<void*>(mcontext->ss.eip);
531  state->sp = reinterpret_cast<void*>(mcontext->ss.esp);
532  state->fp = reinterpret_cast<void*>(mcontext->ss.ebp);
533 #endif // __DARWIN_UNIX03
534 #endif // V8_HOST_ARCH_IA32
535 #elif V8_OS_FREEBSD
536 #if V8_HOST_ARCH_IA32
537  state->pc = reinterpret_cast<void*>(mcontext.mc_eip);
538  state->sp = reinterpret_cast<void*>(mcontext.mc_esp);
539  state->fp = reinterpret_cast<void*>(mcontext.mc_ebp);
540 #elif V8_HOST_ARCH_X64
541  state->pc = reinterpret_cast<void*>(mcontext.mc_rip);
542  state->sp = reinterpret_cast<void*>(mcontext.mc_rsp);
543  state->fp = reinterpret_cast<void*>(mcontext.mc_rbp);
544 #elif V8_HOST_ARCH_ARM
545  state->pc = reinterpret_cast<void*>(mcontext.mc_r15);
546  state->sp = reinterpret_cast<void*>(mcontext.mc_r13);
547  state->fp = reinterpret_cast<void*>(mcontext.mc_r11);
548 #endif // V8_HOST_ARCH_*
549 #elif V8_OS_NETBSD
550 #if V8_HOST_ARCH_IA32
551  state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]);
552  state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]);
553  state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]);
554 #elif V8_HOST_ARCH_X64
555  state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]);
556  state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]);
557  state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]);
558 #endif // V8_HOST_ARCH_*
559 #elif V8_OS_OPENBSD
560 #if V8_HOST_ARCH_IA32
561  state->pc = reinterpret_cast<void*>(ucontext->sc_eip);
562  state->sp = reinterpret_cast<void*>(ucontext->sc_esp);
563  state->fp = reinterpret_cast<void*>(ucontext->sc_ebp);
564 #elif V8_HOST_ARCH_X64
565  state->pc = reinterpret_cast<void*>(ucontext->sc_rip);
566  state->sp = reinterpret_cast<void*>(ucontext->sc_rsp);
567  state->fp = reinterpret_cast<void*>(ucontext->sc_rbp);
568 #endif // V8_HOST_ARCH_*
569 #elif V8_OS_SOLARIS
570  state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]);
571  state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]);
572  state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]);
573 #elif V8_OS_QNX
574 #if V8_HOST_ARCH_IA32
575  state->pc = reinterpret_cast<void*>(mcontext.cpu.eip);
576  state->sp = reinterpret_cast<void*>(mcontext.cpu.esp);
577  state->fp = reinterpret_cast<void*>(mcontext.cpu.ebp);
578 #elif V8_HOST_ARCH_ARM
579  state->pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]);
580  state->sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]);
581  state->fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]);
582 #endif // V8_HOST_ARCH_*
583 #elif V8_OS_AIX
584  state->pc = reinterpret_cast<void*>(mcontext.jmp_context.iar);
585  state->sp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[1]);
586  state->fp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[31]);
587 #endif // V8_OS_AIX
588 }
589 
590 #endif // USE_SIGNALS
591 
592 
593 void Sampler::SetUp() {
594 #if defined(USE_SIGNALS)
595  SignalHandler::SetUp();
596 #endif
597 }
598 
599 
600 void Sampler::TearDown() {
601 #if defined(USE_SIGNALS)
602  SignalHandler::TearDown();
603 #endif
604 }
605 
606 Sampler::Sampler(Isolate* isolate)
607  : is_counting_samples_(false),
608  js_sample_count_(0),
609  external_sample_count_(0),
610  isolate_(isolate),
611  profiling_(false),
612  has_processing_thread_(false),
613  active_(false),
614  registered_(false) {
615  data_ = new PlatformData;
616 }
617 
618 void Sampler::UnregisterIfRegistered() {
619 #if defined(USE_SIGNALS)
620  if (IsRegistered()) {
621  SamplerManager::instance()->RemoveSampler(this);
622  SetRegistered(false);
623  }
624 #endif
625 }
626 
627 Sampler::~Sampler() {
628  DCHECK(!IsActive());
629  DCHECK(!IsRegistered());
630  delete data_;
631 }
632 
633 void Sampler::Start() {
634  DCHECK(!IsActive());
635  SetActive(true);
636 #if defined(USE_SIGNALS)
637  SamplerManager::instance()->AddSampler(this);
638 #endif
639 }
640 
641 
642 void Sampler::Stop() {
643 #if defined(USE_SIGNALS)
644  SamplerManager::instance()->RemoveSampler(this);
645 #endif
646  DCHECK(IsActive());
647  SetActive(false);
648  SetRegistered(false);
649 }
650 
651 
652 void Sampler::IncreaseProfilingDepth() {
653  base::Relaxed_AtomicIncrement(&profiling_, 1);
654 #if defined(USE_SIGNALS)
655  SignalHandler::IncreaseSamplerCount();
656 #endif
657 }
658 
659 
660 void Sampler::DecreaseProfilingDepth() {
661 #if defined(USE_SIGNALS)
662  SignalHandler::DecreaseSamplerCount();
663 #endif
664  base::Relaxed_AtomicIncrement(&profiling_, -1);
665 }
666 
667 
668 #if defined(USE_SIGNALS)
669 
670 void Sampler::DoSample() {
671  if (!SignalHandler::Installed()) return;
672  if (!IsActive() && !IsRegistered()) {
673  SamplerManager::instance()->AddSampler(this);
674  SetRegistered(true);
675  }
676  pthread_kill(platform_data()->vm_tid(), SIGPROF);
677 }
678 
679 #elif V8_OS_WIN || V8_OS_CYGWIN
680 
681 void Sampler::DoSample() {
682  HANDLE profiled_thread = platform_data()->profiled_thread();
683  if (profiled_thread == nullptr) return;
684 
685  const DWORD kSuspendFailed = static_cast<DWORD>(-1);
686  if (SuspendThread(profiled_thread) == kSuspendFailed) return;
687 
688  // Context used for sampling the register state of the profiled thread.
689  CONTEXT context;
690  memset(&context, 0, sizeof(context));
691  context.ContextFlags = CONTEXT_FULL;
692  if (GetThreadContext(profiled_thread, &context) != 0) {
693  v8::RegisterState state;
694 #if V8_HOST_ARCH_X64
695  state.pc = reinterpret_cast<void*>(context.Rip);
696  state.sp = reinterpret_cast<void*>(context.Rsp);
697  state.fp = reinterpret_cast<void*>(context.Rbp);
698 #elif V8_HOST_ARCH_ARM64
699  state.pc = reinterpret_cast<void*>(context.Pc);
700  state.sp = reinterpret_cast<void*>(context.Sp);
701  state.fp = reinterpret_cast<void*>(context.Fp);
702 #else
703  state.pc = reinterpret_cast<void*>(context.Eip);
704  state.sp = reinterpret_cast<void*>(context.Esp);
705  state.fp = reinterpret_cast<void*>(context.Ebp);
706 #endif
707  SampleStack(state);
708  }
709  ResumeThread(profiled_thread);
710 }
711 
712 #elif V8_OS_FUCHSIA
713 
714 void Sampler::DoSample() {
715  zx_handle_t profiled_thread = platform_data()->profiled_thread();
716  if (profiled_thread == ZX_HANDLE_INVALID) return;
717 
718  zx_handle_t suspend_token = ZX_HANDLE_INVALID;
719  if (zx_task_suspend_token(profiled_thread, &suspend_token) != ZX_OK) return;
720 
721  // Wait for the target thread to become suspended, or to exit.
722  // TODO(wez): There is currently no suspension count for threads, so there
723  // is a risk that some other caller resumes the thread in-between our suspend
724  // and wait calls, causing us to miss the SUSPENDED signal. We apply a 100ms
725  // deadline to protect against hanging the sampler thread in this case.
726  zx_signals_t signals = 0;
727  zx_status_t suspended = zx_object_wait_one(
728  profiled_thread, ZX_THREAD_SUSPENDED | ZX_THREAD_TERMINATED,
729  zx_deadline_after(ZX_MSEC(100)), &signals);
730  if (suspended != ZX_OK || (signals & ZX_THREAD_SUSPENDED) == 0) {
731  zx_handle_close(suspend_token);
732  return;
733  }
734 
735  // Fetch a copy of its "general register" states.
736  zx_thread_state_general_regs_t thread_state = {};
737  if (zx_thread_read_state(profiled_thread, ZX_THREAD_STATE_GENERAL_REGS,
738  &thread_state, sizeof(thread_state)) == ZX_OK) {
739  v8::RegisterState state;
740 #if V8_HOST_ARCH_X64
741  state.pc = reinterpret_cast<void*>(thread_state.rip);
742  state.sp = reinterpret_cast<void*>(thread_state.rsp);
743  state.fp = reinterpret_cast<void*>(thread_state.rbp);
744 #elif V8_HOST_ARCH_ARM64
745  state.pc = reinterpret_cast<void*>(thread_state.pc);
746  state.sp = reinterpret_cast<void*>(thread_state.sp);
747  state.fp = reinterpret_cast<void*>(thread_state.r[29]);
748 #endif
749  SampleStack(state);
750  }
751 
752  zx_handle_close(suspend_token);
753 }
754 
755 // TODO(wez): Remove this once the Fuchsia SDK has rolled.
756 #if defined(ZX_THREAD_STATE_REGSET0)
757 #undef ZX_THREAD_STATE_GENERAL_REGS
758 #endif
759 
760 #endif // USE_SIGNALS
761 
762 } // namespace sampler
763 } // namespace v8
Definition: libplatform.h:13