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