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 
66 typedef struct sigcontext mcontext_t;
67 
68 typedef 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 
78 typedef struct sigcontext mcontext_t;
79 
80 typedef 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.
90 typedef 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 
111 typedef 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.
121 typedef struct {
122   uint32_t gregs[19];
123   void* fpregs;
124   uint32_t oldmask;
125   uint32_t cr2;
126 } mcontext_t;
127 
128 typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
129 typedef 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;
136 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
137 
138 #elif defined(__x86_64__)
139 // x64 version for Android.
140 typedef struct {
141   uint64_t gregs[23];
142   void* fpregs;
143   uint64_t __reserved1[8];
144 } mcontext_t;
145 
146 typedef 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;
153 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
154 #endif
155 
156 #endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
157 
158 
159 namespace v8 {
160 namespace internal {
161 
162 namespace {
163 
164 class PlatformDataCommon : public Malloced {
165  public:
PlatformDataCommon()166   PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
profiled_thread_id()167   ThreadId profiled_thread_id() { return profiled_thread_id_; }
168 
169  protected:
~PlatformDataCommon()170   ~PlatformDataCommon() {}
171 
172  private:
173   ThreadId profiled_thread_id_;
174 };
175 
176 
IsSamePage(byte * ptr1,byte * ptr2)177 bool 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.
IsNoFrameRegion(Address address)187 bool 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 
243 class Sampler::PlatformData : public PlatformDataCommon {
244  public:
PlatformData()245   PlatformData() : vm_tid_(pthread_self()) {}
vm_tid() const246   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 
258 class 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.
PlatformData()265   PlatformData()
266       : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
267                                     THREAD_SUSPEND_RESUME |
268                                     THREAD_QUERY_INFORMATION,
269                                     false,
270                                     GetCurrentThreadId())) {}
271 
~PlatformData()272   ~PlatformData() {
273     if (profiled_thread_ != NULL) {
274       CloseHandle(profiled_thread_);
275       profiled_thread_ = NULL;
276     }
277   }
278 
profiled_thread()279   HANDLE profiled_thread() { return profiled_thread_; }
280 
281  private:
282   HANDLE profiled_thread_;
283 };
284 #endif
285 
286 
287 #if defined(USE_SIMULATOR)
288 class SimulatorHelper {
289  public:
Init(Isolate * isolate)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 
FillRegisters(v8::RegisterState * state)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 
350 class SignalHandler : public AllStatic {
351  public:
SetUp()352   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
TearDown()353   static void TearDown() { delete mutex_; mutex_ = NULL; }
354 
IncreaseSamplerCount()355   static void IncreaseSamplerCount() {
356     base::LockGuard<base::Mutex> lock_guard(mutex_);
357     if (++client_count_ == 1) Install();
358   }
359 
DecreaseSamplerCount()360   static void DecreaseSamplerCount() {
361     base::LockGuard<base::Mutex> lock_guard(mutex_);
362     if (--client_count_ == 0) Restore();
363   }
364 
Installed()365   static bool Installed() {
366     return signal_handler_installed_;
367   }
368 
369  private:
Install()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 
Restore()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 
405 base::Mutex* SignalHandler::mutex_ = NULL;
406 int SignalHandler::client_count_ = 0;
407 struct sigaction SignalHandler::old_signal_handler_;
408 bool SignalHandler::signal_handler_installed_ = false;
409 
410 
411 // As Native Client does not support signal handling, profiling is disabled.
412 #if !V8_OS_NACL
HandleProfilerSignal(int signal,siginfo_t * info,void * context)413 void 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 
569 class SamplerThread : public base::Thread {
570  public:
571   static const int kSamplerThreadStackSize = 64 * KB;
572 
SamplerThread(int interval)573   explicit SamplerThread(int interval)
574       : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)),
575         interval_(interval) {}
576 
SetUp()577   static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
TearDown()578   static void TearDown() { delete mutex_; mutex_ = NULL; }
579 
AddActiveSampler(Sampler * sampler)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 
RemoveActiveSampler(Sampler * sampler)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().
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 
651 base::Mutex* SamplerThread::mutex_ = NULL;
652 SamplerThread* SamplerThread::instance_ = NULL;
653 
654 
655 //
656 // StackTracer implementation
657 //
Init(Isolate * isolate,const v8::RegisterState & regs,RecordCEntryFrame record_c_entry_frame)658 DISABLE_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 
GetStackSample(Isolate * isolate,const v8::RegisterState & regs,RecordCEntryFrame record_c_entry_frame,void ** frames,size_t frames_limit,v8::SampleInfo * sample_info)705 void 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 
SetUp()731 void Sampler::SetUp() {
732 #if defined(USE_SIGNALS)
733   SignalHandler::SetUp();
734 #endif
735   SamplerThread::SetUp();
736 }
737 
738 
TearDown()739 void Sampler::TearDown() {
740   SamplerThread::TearDown();
741 #if defined(USE_SIGNALS)
742   SignalHandler::TearDown();
743 #endif
744 }
745 
746 
Sampler(Isolate * isolate,int interval)747 Sampler::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 
~Sampler()759 Sampler::~Sampler() {
760   DCHECK(!IsActive());
761   delete data_;
762 }
763 
764 
Start()765 void Sampler::Start() {
766   DCHECK(!IsActive());
767   SetActive(true);
768   SamplerThread::AddActiveSampler(this);
769 }
770 
771 
Stop()772 void Sampler::Stop() {
773   DCHECK(IsActive());
774   SamplerThread::RemoveActiveSampler(this);
775   SetActive(false);
776 }
777 
778 
IncreaseProfilingDepth()779 void Sampler::IncreaseProfilingDepth() {
780   base::NoBarrier_AtomicIncrement(&profiling_, 1);
781 #if defined(USE_SIGNALS)
782   SignalHandler::IncreaseSamplerCount();
783 #endif
784 }
785 
786 
DecreaseProfilingDepth()787 void Sampler::DecreaseProfilingDepth() {
788 #if defined(USE_SIGNALS)
789   SignalHandler::DecreaseSamplerCount();
790 #endif
791   base::NoBarrier_AtomicIncrement(&profiling_, -1);
792 }
793 
794 
SampleStack(const v8::RegisterState & state)795 void 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 
DoSample()814 void 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 
DoSample()821 void 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