1// Copyright 2013 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/profiler/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 "src/base/platform/platform.h"
46#include "src/flags.h"
47#include "src/frames-inl.h"
48#include "src/log.h"
49#include "src/profiler/cpu-profiler-inl.h"
50#include "src/simulator.h"
51#include "src/v8threads.h"
52#include "src/vm-state-inl.h"
53
54
55#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
56
57// Not all versions of Android's C library provide ucontext_t.
58// Detect this and provide custom but compatible definitions. Note that these
59// follow the GLibc naming convention to access register values from
60// mcontext_t.
61//
62// See http://code.google.com/p/android/issues/detail?id=34784
63
64#if defined(__arm__)
65
66typedef struct sigcontext mcontext_t;
67
68typedef struct ucontext {
69  uint32_t uc_flags;
70  struct ucontext* uc_link;
71  stack_t uc_stack;
72  mcontext_t uc_mcontext;
73  // Other fields are not used by V8, don't define them here.
74} ucontext_t;
75
76#elif defined(__aarch64__)
77
78typedef struct sigcontext mcontext_t;
79
80typedef struct ucontext {
81  uint64_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(__mips__)
89// MIPS version of sigcontext, for Android bionic.
90typedef struct {
91  uint32_t regmask;
92  uint32_t status;
93  uint64_t pc;
94  uint64_t gregs[32];
95  uint64_t fpregs[32];
96  uint32_t acx;
97  uint32_t fpc_csr;
98  uint32_t fpc_eir;
99  uint32_t used_math;
100  uint32_t dsp;
101  uint64_t mdhi;
102  uint64_t mdlo;
103  uint32_t hi1;
104  uint32_t lo1;
105  uint32_t hi2;
106  uint32_t lo2;
107  uint32_t hi3;
108  uint32_t lo3;
109} mcontext_t;
110
111typedef struct ucontext {
112  uint32_t uc_flags;
113  struct ucontext* uc_link;
114  stack_t uc_stack;
115  mcontext_t uc_mcontext;
116  // Other fields are not used by V8, don't define them here.
117} ucontext_t;
118
119#elif defined(__i386__)
120// x86 version for Android.
121typedef struct {
122  uint32_t gregs[19];
123  void* fpregs;
124  uint32_t oldmask;
125  uint32_t cr2;
126} mcontext_t;
127
128typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
129typedef struct ucontext {
130  uint32_t uc_flags;
131  struct ucontext* uc_link;
132  stack_t uc_stack;
133  mcontext_t uc_mcontext;
134  // Other fields are not used by V8, don't define them here.
135} ucontext_t;
136enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
137
138#elif defined(__x86_64__)
139// x64 version for Android.
140typedef struct {
141  uint64_t gregs[23];
142  void* fpregs;
143  uint64_t __reserved1[8];
144} mcontext_t;
145
146typedef struct ucontext {
147  uint64_t uc_flags;
148  struct ucontext *uc_link;
149  stack_t uc_stack;
150  mcontext_t uc_mcontext;
151  // Other fields are not used by V8, don't define them here.
152} ucontext_t;
153enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
154#endif
155
156#endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
157
158
159namespace v8 {
160namespace internal {
161
162namespace {
163
164class PlatformDataCommon : public Malloced {
165 public:
166  PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
167  ThreadId profiled_thread_id() { return profiled_thread_id_; }
168
169 protected:
170  ~PlatformDataCommon() {}
171
172 private:
173  ThreadId profiled_thread_id_;
174};
175
176
177bool IsSamePage(byte* ptr1, byte* ptr2) {
178  const uint32_t kPageSize = 4096;
179  uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1);
180  return (reinterpret_cast<uintptr_t>(ptr1) & mask) ==
181         (reinterpret_cast<uintptr_t>(ptr2) & mask);
182}
183
184
185// Check if the code at specified address could potentially be a
186// frame setup code.
187bool IsNoFrameRegion(Address address) {
188  struct Pattern {
189    int bytes_count;
190    byte bytes[8];
191    int offsets[4];
192  };
193  byte* pc = reinterpret_cast<byte*>(address);
194  static Pattern patterns[] = {
195#if V8_HOST_ARCH_IA32
196    // push %ebp
197    // mov %esp,%ebp
198    {3, {0x55, 0x89, 0xe5}, {0, 1, -1}},
199    // pop %ebp
200    // ret N
201    {2, {0x5d, 0xc2}, {0, 1, -1}},
202    // pop %ebp
203    // ret
204    {2, {0x5d, 0xc3}, {0, 1, -1}},
205#elif V8_HOST_ARCH_X64
206    // pushq %rbp
207    // movq %rsp,%rbp
208    {4, {0x55, 0x48, 0x89, 0xe5}, {0, 1, -1}},
209    // popq %rbp
210    // ret N
211    {2, {0x5d, 0xc2}, {0, 1, -1}},
212    // popq %rbp
213    // ret
214    {2, {0x5d, 0xc3}, {0, 1, -1}},
215#endif
216    {0, {}, {}}
217  };
218  for (Pattern* pattern = patterns; pattern->bytes_count; ++pattern) {
219    for (int* offset_ptr = pattern->offsets; *offset_ptr != -1; ++offset_ptr) {
220      int offset = *offset_ptr;
221      if (!offset || IsSamePage(pc, pc - offset)) {
222        MSAN_MEMORY_IS_INITIALIZED(pc - offset, pattern->bytes_count);
223        if (!memcmp(pc - offset, pattern->bytes, pattern->bytes_count))
224          return true;
225      } else {
226        // It is not safe to examine bytes on another page as it might not be
227        // allocated thus causing a SEGFAULT.
228        // Check the pattern part that's on the same page and
229        // pessimistically assume it could be the entire pattern match.
230        MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset);
231        if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset))
232          return true;
233      }
234    }
235  }
236  return false;
237}
238
239}  // namespace
240
241#if defined(USE_SIGNALS)
242
243class Sampler::PlatformData : public PlatformDataCommon {
244 public:
245  PlatformData() : vm_tid_(pthread_self()) {}
246  pthread_t vm_tid() const { return vm_tid_; }
247
248 private:
249  pthread_t vm_tid_;
250};
251
252#elif V8_OS_WIN || V8_OS_CYGWIN
253
254// ----------------------------------------------------------------------------
255// Win32 profiler support. On Cygwin we use the same sampler implementation as
256// on Win32.
257
258class Sampler::PlatformData : public PlatformDataCommon {
259 public:
260  // Get a handle to the calling thread. This is the thread that we are
261  // going to profile. We need to make a copy of the handle because we are
262  // going to use it in the sampler thread. Using GetThreadHandle() will
263  // not work in this case. We're using OpenThread because DuplicateHandle
264  // for some reason doesn't work in Chrome's sandbox.
265  PlatformData()
266      : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
267                                    THREAD_SUSPEND_RESUME |
268                                    THREAD_QUERY_INFORMATION,
269                                    false,
270                                    GetCurrentThreadId())) {}
271
272  ~PlatformData() {
273    if (profiled_thread_ != NULL) {
274      CloseHandle(profiled_thread_);
275      profiled_thread_ = NULL;
276    }
277  }
278
279  HANDLE profiled_thread() { return profiled_thread_; }
280
281 private:
282  HANDLE profiled_thread_;
283};
284#endif
285
286
287#if defined(USE_SIMULATOR)
288class SimulatorHelper {
289 public:
290  inline bool Init(Isolate* isolate) {
291    simulator_ = isolate->thread_local_top()->simulator_;
292    // Check if there is active simulator.
293    return simulator_ != NULL;
294  }
295
296  inline void FillRegisters(v8::RegisterState* state) {
297#if V8_TARGET_ARCH_ARM
298    if (!simulator_->has_bad_pc()) {
299      state->pc = reinterpret_cast<Address>(simulator_->get_pc());
300    }
301    state->sp = reinterpret_cast<Address>(simulator_->get_register(
302        Simulator::sp));
303    state->fp = reinterpret_cast<Address>(simulator_->get_register(
304        Simulator::r11));
305#elif V8_TARGET_ARCH_ARM64
306    if (simulator_->sp() == 0 || simulator_->fp() == 0) {
307      // It's possible that the simulator is interrupted while it is updating
308      // the sp or fp register. ARM64 simulator does this in two steps:
309      // first setting it to zero and then setting it to a new value.
310      // Bailout if sp/fp doesn't contain the new value.
311      //
312      // FIXME: The above doesn't really solve the issue.
313      // If a 64-bit target is executed on a 32-bit host even the final
314      // write is non-atomic, so it might obtain a half of the result.
315      // Moreover as long as the register set code uses memcpy (as of now),
316      // it is not guaranteed to be atomic even when both host and target
317      // are of same bitness.
318      return;
319    }
320    state->pc = reinterpret_cast<Address>(simulator_->pc());
321    state->sp = reinterpret_cast<Address>(simulator_->sp());
322    state->fp = reinterpret_cast<Address>(simulator_->fp());
323#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
324    if (!simulator_->has_bad_pc()) {
325      state->pc = reinterpret_cast<Address>(simulator_->get_pc());
326    }
327    state->sp = reinterpret_cast<Address>(simulator_->get_register(
328        Simulator::sp));
329    state->fp = reinterpret_cast<Address>(simulator_->get_register(
330        Simulator::fp));
331#elif V8_TARGET_ARCH_PPC
332    if (!simulator_->has_bad_pc()) {
333      state->pc = reinterpret_cast<Address>(simulator_->get_pc());
334    }
335    state->sp =
336        reinterpret_cast<Address>(simulator_->get_register(Simulator::sp));
337    state->fp =
338        reinterpret_cast<Address>(simulator_->get_register(Simulator::fp));
339#endif
340  }
341
342 private:
343  Simulator* simulator_;
344};
345#endif  // USE_SIMULATOR
346
347
348#if defined(USE_SIGNALS)
349
350class SignalHandler : public AllStatic {
351 public:
352  static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
353  static void TearDown() { delete mutex_; mutex_ = NULL; }
354
355  static void IncreaseSamplerCount() {
356    base::LockGuard<base::Mutex> lock_guard(mutex_);
357    if (++client_count_ == 1) Install();
358  }
359
360  static void DecreaseSamplerCount() {
361    base::LockGuard<base::Mutex> lock_guard(mutex_);
362    if (--client_count_ == 0) Restore();
363  }
364
365  static bool Installed() {
366    return signal_handler_installed_;
367  }
368
369 private:
370  static void Install() {
371#if !V8_OS_NACL
372    struct sigaction sa;
373    sa.sa_sigaction = &HandleProfilerSignal;
374    sigemptyset(&sa.sa_mask);
375#if V8_OS_QNX
376    sa.sa_flags = SA_SIGINFO;
377#else
378    sa.sa_flags = SA_RESTART | SA_SIGINFO;
379#endif
380    signal_handler_installed_ =
381        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
382#endif
383  }
384
385  static void Restore() {
386#if !V8_OS_NACL
387    if (signal_handler_installed_) {
388      sigaction(SIGPROF, &old_signal_handler_, 0);
389      signal_handler_installed_ = false;
390    }
391#endif
392  }
393
394#if !V8_OS_NACL
395  static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
396#endif
397  // Protects the process wide state below.
398  static base::Mutex* mutex_;
399  static int client_count_;
400  static bool signal_handler_installed_;
401  static struct sigaction old_signal_handler_;
402};
403
404
405base::Mutex* SignalHandler::mutex_ = NULL;
406int SignalHandler::client_count_ = 0;
407struct sigaction SignalHandler::old_signal_handler_;
408bool SignalHandler::signal_handler_installed_ = false;
409
410
411// As Native Client does not support signal handling, profiling is disabled.
412#if !V8_OS_NACL
413void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
414                                         void* context) {
415  USE(info);
416  if (signal != SIGPROF) return;
417  Isolate* isolate = Isolate::UnsafeCurrent();
418  if (isolate == NULL || !isolate->IsInUse()) {
419    // We require a fully initialized and entered isolate.
420    return;
421  }
422  if (v8::Locker::IsActive() &&
423      !isolate->thread_manager()->IsLockedByCurrentThread()) {
424    return;
425  }
426
427  Sampler* sampler = isolate->logger()->sampler();
428  if (sampler == NULL) return;
429
430  v8::RegisterState state;
431
432#if defined(USE_SIMULATOR)
433  SimulatorHelper helper;
434  if (!helper.Init(isolate)) return;
435  helper.FillRegisters(&state);
436  // It possible that the simulator is interrupted while it is updating
437  // the sp or fp register. ARM64 simulator does this in two steps:
438  // first setting it to zero and then setting it to the new value.
439  // Bailout if sp/fp doesn't contain the new value.
440  if (state.sp == 0 || state.fp == 0) return;
441#else
442  // Extracting the sample from the context is extremely machine dependent.
443  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
444#if !(V8_OS_OPENBSD || (V8_OS_LINUX && V8_HOST_ARCH_PPC))
445  mcontext_t& mcontext = ucontext->uc_mcontext;
446#endif
447#if V8_OS_LINUX
448#if V8_HOST_ARCH_IA32
449  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
450  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
451  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
452#elif V8_HOST_ARCH_X64
453  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
454  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
455  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
456#elif V8_HOST_ARCH_ARM
457#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
458  // Old GLibc ARM versions used a gregs[] array to access the register
459  // values from mcontext_t.
460  state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
461  state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
462  state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
463#else
464  state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
465  state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
466  state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
467#endif  // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
468#elif V8_HOST_ARCH_ARM64
469  state.pc = reinterpret_cast<Address>(mcontext.pc);
470  state.sp = reinterpret_cast<Address>(mcontext.sp);
471  // FP is an alias for x29.
472  state.fp = reinterpret_cast<Address>(mcontext.regs[29]);
473#elif V8_HOST_ARCH_MIPS
474  state.pc = reinterpret_cast<Address>(mcontext.pc);
475  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
476  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
477#elif V8_HOST_ARCH_MIPS64
478  state.pc = reinterpret_cast<Address>(mcontext.pc);
479  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
480  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
481#elif V8_HOST_ARCH_PPC
482  state.pc = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->nip);
483  state.sp = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->gpr[PT_R1]);
484  state.fp = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->gpr[PT_R31]);
485#endif  // V8_HOST_ARCH_*
486#elif V8_OS_MACOSX
487#if V8_HOST_ARCH_X64
488#if __DARWIN_UNIX03
489  state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
490  state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
491  state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
492#else  // !__DARWIN_UNIX03
493  state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
494  state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
495  state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
496#endif  // __DARWIN_UNIX03
497#elif V8_HOST_ARCH_IA32
498#if __DARWIN_UNIX03
499  state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
500  state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
501  state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
502#else  // !__DARWIN_UNIX03
503  state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
504  state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
505  state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
506#endif  // __DARWIN_UNIX03
507#endif  // V8_HOST_ARCH_IA32
508#elif V8_OS_FREEBSD
509#if V8_HOST_ARCH_IA32
510  state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
511  state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
512  state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
513#elif V8_HOST_ARCH_X64
514  state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
515  state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
516  state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
517#elif V8_HOST_ARCH_ARM
518  state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
519  state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
520  state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
521#endif  // V8_HOST_ARCH_*
522#elif V8_OS_NETBSD
523#if V8_HOST_ARCH_IA32
524  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
525  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
526  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
527#elif V8_HOST_ARCH_X64
528  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
529  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
530  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
531#endif  // V8_HOST_ARCH_*
532#elif V8_OS_OPENBSD
533#if V8_HOST_ARCH_IA32
534  state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
535  state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
536  state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
537#elif V8_HOST_ARCH_X64
538  state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
539  state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
540  state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
541#endif  // V8_HOST_ARCH_*
542#elif V8_OS_SOLARIS
543  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
544  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
545  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
546#elif V8_OS_QNX
547#if V8_HOST_ARCH_IA32
548  state.pc = reinterpret_cast<Address>(mcontext.cpu.eip);
549  state.sp = reinterpret_cast<Address>(mcontext.cpu.esp);
550  state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
551#elif V8_HOST_ARCH_ARM
552  state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
553  state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
554  state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
555#endif  // V8_HOST_ARCH_*
556#elif V8_OS_AIX
557  state.pc = reinterpret_cast<Address>(mcontext.jmp_context.iar);
558  state.sp = reinterpret_cast<Address>(mcontext.jmp_context.gpr[1]);
559  state.fp = reinterpret_cast<Address>(mcontext.jmp_context.gpr[31]);
560#endif  // V8_OS_AIX
561#endif  // USE_SIMULATOR
562  sampler->SampleStack(state);
563}
564#endif  // V8_OS_NACL
565
566#endif
567
568
569class SamplerThread : public base::Thread {
570 public:
571  static const int kSamplerThreadStackSize = 64 * KB;
572
573  explicit SamplerThread(int interval)
574      : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)),
575        interval_(interval) {}
576
577  static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
578  static void TearDown() { delete mutex_; mutex_ = NULL; }
579
580  static void AddActiveSampler(Sampler* sampler) {
581    bool need_to_start = false;
582    base::LockGuard<base::Mutex> lock_guard(mutex_);
583    if (instance_ == NULL) {
584      // Start a thread that will send SIGPROF signal to VM threads,
585      // when CPU profiling will be enabled.
586      instance_ = new SamplerThread(sampler->interval());
587      need_to_start = true;
588    }
589
590    DCHECK(sampler->IsActive());
591    DCHECK(!instance_->active_samplers_.Contains(sampler));
592    DCHECK(instance_->interval_ == sampler->interval());
593    instance_->active_samplers_.Add(sampler);
594
595    if (need_to_start) instance_->StartSynchronously();
596  }
597
598  static void RemoveActiveSampler(Sampler* sampler) {
599    SamplerThread* instance_to_remove = NULL;
600    {
601      base::LockGuard<base::Mutex> lock_guard(mutex_);
602
603      DCHECK(sampler->IsActive());
604      bool removed = instance_->active_samplers_.RemoveElement(sampler);
605      DCHECK(removed);
606      USE(removed);
607
608      // We cannot delete the instance immediately as we need to Join() the
609      // thread but we are holding mutex_ and the thread may try to acquire it.
610      if (instance_->active_samplers_.is_empty()) {
611        instance_to_remove = instance_;
612        instance_ = NULL;
613      }
614    }
615
616    if (!instance_to_remove) return;
617    instance_to_remove->Join();
618    delete instance_to_remove;
619  }
620
621  // Implement Thread::Run().
622  virtual void Run() {
623    while (true) {
624      {
625        base::LockGuard<base::Mutex> lock_guard(mutex_);
626        if (active_samplers_.is_empty()) break;
627        // When CPU profiling is enabled both JavaScript and C++ code is
628        // profiled. We must not suspend.
629        for (int i = 0; i < active_samplers_.length(); ++i) {
630          Sampler* sampler = active_samplers_.at(i);
631          if (!sampler->IsProfiling()) continue;
632          sampler->DoSample();
633        }
634      }
635      base::OS::Sleep(base::TimeDelta::FromMilliseconds(interval_));
636    }
637  }
638
639 private:
640  // Protects the process wide state below.
641  static base::Mutex* mutex_;
642  static SamplerThread* instance_;
643
644  const int interval_;
645  List<Sampler*> active_samplers_;
646
647  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
648};
649
650
651base::Mutex* SamplerThread::mutex_ = NULL;
652SamplerThread* SamplerThread::instance_ = NULL;
653
654
655//
656// StackTracer implementation
657//
658DISABLE_ASAN void TickSample::Init(Isolate* isolate,
659                                   const v8::RegisterState& regs,
660                                   RecordCEntryFrame record_c_entry_frame) {
661  timestamp = base::TimeTicks::HighResolutionNow();
662  pc = reinterpret_cast<Address>(regs.pc);
663  state = isolate->current_vm_state();
664
665  // Avoid collecting traces while doing GC.
666  if (state == GC) return;
667
668  Address js_entry_sp = isolate->js_entry_sp();
669  if (js_entry_sp == 0) return;  // Not executing JS now.
670
671  if (pc && IsNoFrameRegion(pc)) {
672    pc = 0;
673    return;
674  }
675
676  ExternalCallbackScope* scope = isolate->external_callback_scope();
677  Address handler = Isolate::handler(isolate->thread_local_top());
678  // If there is a handler on top of the external callback scope then
679  // we have already entrered JavaScript again and the external callback
680  // is not the top function.
681  if (scope && scope->scope_address() < handler) {
682    external_callback = scope->callback();
683    has_external_callback = true;
684  } else {
685    // sp register may point at an arbitrary place in memory, make
686    // sure MSAN doesn't complain about it.
687    MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address));
688    // Sample potential return address value for frameless invocation of
689    // stubs (we'll figure out later, if this value makes sense).
690    tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp));
691    has_external_callback = false;
692  }
693
694  SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
695                            reinterpret_cast<Address>(regs.sp), js_entry_sp);
696  top_frame_type = it.top_frame_type();
697
698  SampleInfo info;
699  GetStackSample(isolate, regs, record_c_entry_frame,
700                 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info);
701  frames_count = static_cast<unsigned>(info.frames_count);
702}
703
704
705void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs,
706                                RecordCEntryFrame record_c_entry_frame,
707                                void** frames, size_t frames_limit,
708                                v8::SampleInfo* sample_info) {
709  sample_info->frames_count = 0;
710  sample_info->vm_state = isolate->current_vm_state();
711  if (sample_info->vm_state == GC) return;
712
713  Address js_entry_sp = isolate->js_entry_sp();
714  if (js_entry_sp == 0) return;  // Not executing JS now.
715
716  SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
717                            reinterpret_cast<Address>(regs.sp), js_entry_sp);
718  size_t i = 0;
719  if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() &&
720      it.top_frame_type() == StackFrame::EXIT) {
721    frames[i++] = isolate->c_function();
722  }
723  while (!it.done() && i < frames_limit) {
724    frames[i++] = it.frame()->pc();
725    it.Advance();
726  }
727  sample_info->frames_count = i;
728}
729
730
731void Sampler::SetUp() {
732#if defined(USE_SIGNALS)
733  SignalHandler::SetUp();
734#endif
735  SamplerThread::SetUp();
736}
737
738
739void Sampler::TearDown() {
740  SamplerThread::TearDown();
741#if defined(USE_SIGNALS)
742  SignalHandler::TearDown();
743#endif
744}
745
746
747Sampler::Sampler(Isolate* isolate, int interval)
748    : isolate_(isolate),
749      interval_(interval),
750      profiling_(false),
751      has_processing_thread_(false),
752      active_(false),
753      is_counting_samples_(false),
754      js_and_external_sample_count_(0) {
755  data_ = new PlatformData;
756}
757
758
759Sampler::~Sampler() {
760  DCHECK(!IsActive());
761  delete data_;
762}
763
764
765void Sampler::Start() {
766  DCHECK(!IsActive());
767  SetActive(true);
768  SamplerThread::AddActiveSampler(this);
769}
770
771
772void Sampler::Stop() {
773  DCHECK(IsActive());
774  SamplerThread::RemoveActiveSampler(this);
775  SetActive(false);
776}
777
778
779void Sampler::IncreaseProfilingDepth() {
780  base::NoBarrier_AtomicIncrement(&profiling_, 1);
781#if defined(USE_SIGNALS)
782  SignalHandler::IncreaseSamplerCount();
783#endif
784}
785
786
787void Sampler::DecreaseProfilingDepth() {
788#if defined(USE_SIGNALS)
789  SignalHandler::DecreaseSamplerCount();
790#endif
791  base::NoBarrier_AtomicIncrement(&profiling_, -1);
792}
793
794
795void Sampler::SampleStack(const v8::RegisterState& state) {
796  TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
797  TickSample sample_obj;
798  if (sample == NULL) sample = &sample_obj;
799  sample->Init(isolate_, state, TickSample::kIncludeCEntryFrame);
800  if (is_counting_samples_) {
801    if (sample->state == JS || sample->state == EXTERNAL) {
802      ++js_and_external_sample_count_;
803    }
804  }
805  Tick(sample);
806  if (sample != &sample_obj) {
807    isolate_->cpu_profiler()->FinishTickSample();
808  }
809}
810
811
812#if defined(USE_SIGNALS)
813
814void Sampler::DoSample() {
815  if (!SignalHandler::Installed()) return;
816  pthread_kill(platform_data()->vm_tid(), SIGPROF);
817}
818
819#elif V8_OS_WIN || V8_OS_CYGWIN
820
821void Sampler::DoSample() {
822  HANDLE profiled_thread = platform_data()->profiled_thread();
823  if (profiled_thread == NULL) return;
824
825#if defined(USE_SIMULATOR)
826  SimulatorHelper helper;
827  if (!helper.Init(isolate())) return;
828#endif
829
830  const DWORD kSuspendFailed = static_cast<DWORD>(-1);
831  if (SuspendThread(profiled_thread) == kSuspendFailed) return;
832
833  // Context used for sampling the register state of the profiled thread.
834  CONTEXT context;
835  memset(&context, 0, sizeof(context));
836  context.ContextFlags = CONTEXT_FULL;
837  if (GetThreadContext(profiled_thread, &context) != 0) {
838    v8::RegisterState state;
839#if defined(USE_SIMULATOR)
840    helper.FillRegisters(&state);
841#else
842#if V8_HOST_ARCH_X64
843    state.pc = reinterpret_cast<Address>(context.Rip);
844    state.sp = reinterpret_cast<Address>(context.Rsp);
845    state.fp = reinterpret_cast<Address>(context.Rbp);
846#else
847    state.pc = reinterpret_cast<Address>(context.Eip);
848    state.sp = reinterpret_cast<Address>(context.Esp);
849    state.fp = reinterpret_cast<Address>(context.Ebp);
850#endif
851#endif  // USE_SIMULATOR
852    SampleStack(state);
853  }
854  ResumeThread(profiled_thread);
855}
856
857#endif  // USE_SIGNALS
858
859
860}  // namespace internal
861}  // namespace v8
862