1// Copyright 2013 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "sampler.h"
29
30#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
31    || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__) \
32    || defined(__native_client__)
33
34#define USE_SIGNALS
35
36#include <errno.h>
37#include <pthread.h>
38#include <signal.h>
39#include <sys/time.h>
40#include <sys/syscall.h>
41// OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
42// and is a typedef for struct sigcontext. There is no uc_mcontext.
43#if (!defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)) \
44    && !defined(__OpenBSD__)
45#include <ucontext.h>
46#endif
47#include <unistd.h>
48
49// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
50// Old versions of the C library <signal.h> didn't define the type.
51#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
52    defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
53#include <asm/sigcontext.h>
54#endif
55
56#elif defined(__MACH__)
57
58#include <mach/mach.h>
59
60#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
61
62#include "win32-headers.h"
63
64#endif
65
66#include "v8.h"
67
68#include "cpu-profiler.h"
69#include "flags.h"
70#include "frames-inl.h"
71#include "log.h"
72#include "platform.h"
73#include "simulator.h"
74#include "v8threads.h"
75#include "vm-state-inl.h"
76
77
78#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
79
80// Not all versions of Android's C library provide ucontext_t.
81// Detect this and provide custom but compatible definitions. Note that these
82// follow the GLibc naming convention to access register values from
83// mcontext_t.
84//
85// See http://code.google.com/p/android/issues/detail?id=34784
86
87#if defined(__arm__)
88
89typedef struct sigcontext mcontext_t;
90
91typedef struct ucontext {
92  uint32_t uc_flags;
93  struct ucontext* uc_link;
94  stack_t uc_stack;
95  mcontext_t uc_mcontext;
96  // Other fields are not used by V8, don't define them here.
97} ucontext_t;
98
99#elif defined(__mips__)
100// MIPS version of sigcontext, for Android bionic.
101typedef struct {
102  uint32_t regmask;
103  uint32_t status;
104  uint64_t pc;
105  uint64_t gregs[32];
106  uint64_t fpregs[32];
107  uint32_t acx;
108  uint32_t fpc_csr;
109  uint32_t fpc_eir;
110  uint32_t used_math;
111  uint32_t dsp;
112  uint64_t mdhi;
113  uint64_t mdlo;
114  uint32_t hi1;
115  uint32_t lo1;
116  uint32_t hi2;
117  uint32_t lo2;
118  uint32_t hi3;
119  uint32_t lo3;
120} mcontext_t;
121
122typedef struct ucontext {
123  uint32_t uc_flags;
124  struct ucontext* uc_link;
125  stack_t uc_stack;
126  mcontext_t uc_mcontext;
127  // Other fields are not used by V8, don't define them here.
128} ucontext_t;
129
130#elif defined(__i386__)
131// x86 version for Android.
132typedef struct {
133  uint32_t gregs[19];
134  void* fpregs;
135  uint32_t oldmask;
136  uint32_t cr2;
137} mcontext_t;
138
139typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
140typedef struct ucontext {
141  uint32_t uc_flags;
142  struct ucontext* uc_link;
143  stack_t uc_stack;
144  mcontext_t uc_mcontext;
145  // Other fields are not used by V8, don't define them here.
146} ucontext_t;
147enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
148#endif
149
150#endif  // __ANDROID__ && !defined(__BIONIC_HAVE_UCONTEXT_T)
151
152
153namespace v8 {
154namespace internal {
155
156namespace {
157
158class PlatformDataCommon : public Malloced {
159 public:
160  PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
161  ThreadId profiled_thread_id() { return profiled_thread_id_; }
162
163 protected:
164  ~PlatformDataCommon() {}
165
166 private:
167  ThreadId profiled_thread_id_;
168};
169
170}  // namespace
171
172#if defined(USE_SIGNALS)
173
174class Sampler::PlatformData : public PlatformDataCommon {
175 public:
176  PlatformData() : vm_tid_(pthread_self()) {}
177  pthread_t vm_tid() const { return vm_tid_; }
178
179 private:
180  pthread_t vm_tid_;
181};
182
183#elif defined(__MACH__)
184
185class Sampler::PlatformData : public PlatformDataCommon {
186 public:
187  PlatformData() : profiled_thread_(mach_thread_self()) {}
188
189  ~PlatformData() {
190    // Deallocate Mach port for thread.
191    mach_port_deallocate(mach_task_self(), profiled_thread_);
192  }
193
194  thread_act_t profiled_thread() { return profiled_thread_; }
195
196 private:
197  // Note: for profiled_thread_ Mach primitives are used instead of PThread's
198  // because the latter doesn't provide thread manipulation primitives required.
199  // For details, consult "Mac OS X Internals" book, Section 7.3.
200  thread_act_t profiled_thread_;
201};
202
203#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
204
205// ----------------------------------------------------------------------------
206// Win32 profiler support. On Cygwin we use the same sampler implementation as
207// on Win32.
208
209class Sampler::PlatformData : public PlatformDataCommon {
210 public:
211  // Get a handle to the calling thread. This is the thread that we are
212  // going to profile. We need to make a copy of the handle because we are
213  // going to use it in the sampler thread. Using GetThreadHandle() will
214  // not work in this case. We're using OpenThread because DuplicateHandle
215  // for some reason doesn't work in Chrome's sandbox.
216  PlatformData()
217      : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
218                                    THREAD_SUSPEND_RESUME |
219                                    THREAD_QUERY_INFORMATION,
220                                    false,
221                                    GetCurrentThreadId())) {}
222
223  ~PlatformData() {
224    if (profiled_thread_ != NULL) {
225      CloseHandle(profiled_thread_);
226      profiled_thread_ = NULL;
227    }
228  }
229
230  HANDLE profiled_thread() { return profiled_thread_; }
231
232 private:
233  HANDLE profiled_thread_;
234};
235#endif
236
237
238#if defined(USE_SIMULATOR)
239class SimulatorHelper {
240 public:
241  inline bool Init(Sampler* sampler, Isolate* isolate) {
242    ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
243    Isolate::PerIsolateThreadData* per_thread_data = isolate->
244        FindPerThreadDataForThread(thread_id);
245    if (!per_thread_data) return false;
246    simulator_ = per_thread_data->simulator();
247    // Check if there is active simulator.
248    return simulator_ != NULL;
249  }
250
251  inline void FillRegisters(RegisterState* state) {
252    state->pc = reinterpret_cast<Address>(simulator_->get_pc());
253    state->sp = reinterpret_cast<Address>(simulator_->get_register(
254        Simulator::sp));
255#if V8_TARGET_ARCH_ARM
256    state->fp = reinterpret_cast<Address>(simulator_->get_register(
257        Simulator::r11));
258#elif V8_TARGET_ARCH_MIPS
259    state->fp = reinterpret_cast<Address>(simulator_->get_register(
260        Simulator::fp));
261#endif
262  }
263
264 private:
265  Simulator* simulator_;
266};
267#endif  // USE_SIMULATOR
268
269
270#if defined(USE_SIGNALS)
271
272class SignalHandler : public AllStatic {
273 public:
274  static inline void EnsureInstalled() {
275    if (signal_handler_installed_) return;
276    struct sigaction sa;
277    sa.sa_sigaction = &HandleProfilerSignal;
278    sigemptyset(&sa.sa_mask);
279    sa.sa_flags = SA_RESTART | SA_SIGINFO;
280    signal_handler_installed_ =
281        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
282  }
283
284  static inline void Restore() {
285    if (signal_handler_installed_) {
286      sigaction(SIGPROF, &old_signal_handler_, 0);
287      signal_handler_installed_ = false;
288    }
289  }
290
291  static inline bool Installed() {
292    return signal_handler_installed_;
293  }
294
295 private:
296  static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
297  static bool signal_handler_installed_;
298  static struct sigaction old_signal_handler_;
299};
300
301struct sigaction SignalHandler::old_signal_handler_;
302bool SignalHandler::signal_handler_installed_ = false;
303
304
305void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
306                                         void* context) {
307#if defined(__native_client__)
308  // As Native Client does not support signal handling, profiling
309  // is disabled.
310  return;
311#else
312  USE(info);
313  if (signal != SIGPROF) return;
314  Isolate* isolate = Isolate::UncheckedCurrent();
315  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
316    // We require a fully initialized and entered isolate.
317    return;
318  }
319  if (v8::Locker::IsActive() &&
320      !isolate->thread_manager()->IsLockedByCurrentThread()) {
321    return;
322  }
323
324  Sampler* sampler = isolate->logger()->sampler();
325  if (sampler == NULL || !sampler->IsActive()) return;
326
327  RegisterState state;
328
329#if defined(USE_SIMULATOR)
330  SimulatorHelper helper;
331  if (!helper.Init(sampler, isolate)) return;
332  helper.FillRegisters(&state);
333#else
334  // Extracting the sample from the context is extremely machine dependent.
335  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
336#if !defined(__OpenBSD__)
337  mcontext_t& mcontext = ucontext->uc_mcontext;
338#endif
339#if defined(__linux__) || defined(__ANDROID__)
340#if V8_HOST_ARCH_IA32
341  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
342  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
343  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
344#elif V8_HOST_ARCH_X64
345  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
346  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
347  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
348#elif V8_HOST_ARCH_ARM
349#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
350    (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
351  // Old GLibc ARM versions used a gregs[] array to access the register
352  // values from mcontext_t.
353  state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
354  state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
355  state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
356#else
357  state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
358  state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
359  state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
360#endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
361        // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
362#elif V8_HOST_ARCH_MIPS
363  state.pc = reinterpret_cast<Address>(mcontext.pc);
364  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
365  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
366#endif  // V8_HOST_ARCH_*
367#elif defined(__FreeBSD__)
368#if V8_HOST_ARCH_IA32
369  state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
370  state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
371  state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
372#elif V8_HOST_ARCH_X64
373  state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
374  state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
375  state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
376#elif V8_HOST_ARCH_ARM
377  state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
378  state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
379  state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
380#endif  // V8_HOST_ARCH_*
381#elif defined(__NetBSD__)
382#if V8_HOST_ARCH_IA32
383  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
384  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
385  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
386#elif V8_HOST_ARCH_X64
387  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
388  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
389  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
390#endif  // V8_HOST_ARCH_*
391#elif defined(__OpenBSD__)
392#if V8_HOST_ARCH_IA32
393  state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
394  state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
395  state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
396#elif V8_HOST_ARCH_X64
397  state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
398  state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
399  state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
400#endif  // V8_HOST_ARCH_*
401#elif defined(__sun)
402  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
403  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
404  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
405#endif  // __sun
406#endif  // USE_SIMULATOR
407  sampler->SampleStack(state);
408#endif  // __native_client__
409}
410
411#endif
412
413
414class SamplerThread : public Thread {
415 public:
416  static const int kSamplerThreadStackSize = 64 * KB;
417
418  explicit SamplerThread(int interval)
419      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
420        interval_(interval) {}
421
422  static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
423  static void TearDown() { delete mutex_; }
424
425  static void AddActiveSampler(Sampler* sampler) {
426    bool need_to_start = false;
427    ScopedLock lock(mutex_);
428    if (instance_ == NULL) {
429      // Start a thread that will send SIGPROF signal to VM threads,
430      // when CPU profiling will be enabled.
431      instance_ = new SamplerThread(sampler->interval());
432      need_to_start = true;
433    }
434
435    ASSERT(sampler->IsActive());
436    ASSERT(!instance_->active_samplers_.Contains(sampler));
437    ASSERT(instance_->interval_ == sampler->interval());
438    instance_->active_samplers_.Add(sampler);
439
440#if defined(USE_SIGNALS)
441    SignalHandler::EnsureInstalled();
442#endif
443    if (need_to_start) instance_->StartSynchronously();
444  }
445
446  static void RemoveActiveSampler(Sampler* sampler) {
447    SamplerThread* instance_to_remove = NULL;
448    {
449      ScopedLock lock(mutex_);
450
451      ASSERT(sampler->IsActive());
452      bool removed = instance_->active_samplers_.RemoveElement(sampler);
453      ASSERT(removed);
454      USE(removed);
455
456      // We cannot delete the instance immediately as we need to Join() the
457      // thread but we are holding mutex_ and the thread may try to acquire it.
458      if (instance_->active_samplers_.is_empty()) {
459        instance_to_remove = instance_;
460        instance_ = NULL;
461#if defined(USE_SIGNALS)
462        SignalHandler::Restore();
463#endif
464      }
465    }
466
467    if (!instance_to_remove) return;
468    instance_to_remove->Join();
469    delete instance_to_remove;
470  }
471
472  // Implement Thread::Run().
473  virtual void Run() {
474    while (true) {
475      {
476        ScopedLock lock(mutex_);
477        if (active_samplers_.is_empty()) break;
478        // When CPU profiling is enabled both JavaScript and C++ code is
479        // profiled. We must not suspend.
480        for (int i = 0; i < active_samplers_.length(); ++i) {
481          Sampler* sampler = active_samplers_.at(i);
482          if (!sampler->isolate()->IsInitialized()) continue;
483          if (!sampler->IsProfiling()) continue;
484          SampleContext(sampler);
485        }
486      }
487      OS::Sleep(interval_);
488    }
489  }
490
491 private:
492#if defined(USE_SIGNALS)
493
494  void SampleContext(Sampler* sampler) {
495    if (!SignalHandler::Installed()) return;
496    pthread_t tid = sampler->platform_data()->vm_tid();
497    pthread_kill(tid, SIGPROF);
498  }
499
500#elif defined(__MACH__)
501
502  void SampleContext(Sampler* sampler) {
503    thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
504
505#if defined(USE_SIMULATOR)
506    SimulatorHelper helper;
507    Isolate* isolate = sampler->isolate();
508    if (!helper.Init(sampler, isolate)) return;
509#endif
510
511    if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
512
513#if V8_HOST_ARCH_X64
514    thread_state_flavor_t flavor = x86_THREAD_STATE64;
515    x86_thread_state64_t thread_state;
516    mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
517#if __DARWIN_UNIX03
518#define REGISTER_FIELD(name) __r ## name
519#else
520#define REGISTER_FIELD(name) r ## name
521#endif  // __DARWIN_UNIX03
522#elif V8_HOST_ARCH_IA32
523    thread_state_flavor_t flavor = i386_THREAD_STATE;
524    i386_thread_state_t thread_state;
525    mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
526#if __DARWIN_UNIX03
527#define REGISTER_FIELD(name) __e ## name
528#else
529#define REGISTER_FIELD(name) e ## name
530#endif  // __DARWIN_UNIX03
531#else
532#error Unsupported Mac OS X host architecture.
533#endif  // V8_HOST_ARCH
534
535    if (thread_get_state(profiled_thread,
536                         flavor,
537                         reinterpret_cast<natural_t*>(&thread_state),
538                         &count) == KERN_SUCCESS) {
539      RegisterState state;
540#if defined(USE_SIMULATOR)
541      helper.FillRegisters(&state);
542#else
543      state.pc = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(ip));
544      state.sp = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(sp));
545      state.fp = reinterpret_cast<Address>(thread_state.REGISTER_FIELD(bp));
546#endif  // USE_SIMULATOR
547#undef REGISTER_FIELD
548      sampler->SampleStack(state);
549    }
550    thread_resume(profiled_thread);
551  }
552
553#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
554
555  void SampleContext(Sampler* sampler) {
556    HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
557    if (profiled_thread == NULL) return;
558
559    Isolate* isolate = sampler->isolate();
560#if defined(USE_SIMULATOR)
561    SimulatorHelper helper;
562    if (!helper.Init(sampler, isolate)) return;
563#endif
564
565    const DWORD kSuspendFailed = static_cast<DWORD>(-1);
566    if (SuspendThread(profiled_thread) == kSuspendFailed) return;
567
568    // Context used for sampling the register state of the profiled thread.
569    CONTEXT context;
570    memset(&context, 0, sizeof(context));
571    context.ContextFlags = CONTEXT_FULL;
572    if (GetThreadContext(profiled_thread, &context) != 0) {
573      RegisterState state;
574#if defined(USE_SIMULATOR)
575      helper.FillRegisters(&state);
576#else
577#if V8_HOST_ARCH_X64
578      state.pc = reinterpret_cast<Address>(context.Rip);
579      state.sp = reinterpret_cast<Address>(context.Rsp);
580      state.fp = reinterpret_cast<Address>(context.Rbp);
581#else
582      state.pc = reinterpret_cast<Address>(context.Eip);
583      state.sp = reinterpret_cast<Address>(context.Esp);
584      state.fp = reinterpret_cast<Address>(context.Ebp);
585#endif
586#endif  // USE_SIMULATOR
587      sampler->SampleStack(state);
588    }
589    ResumeThread(profiled_thread);
590  }
591
592#endif  // USE_SIGNALS
593
594
595  // Protects the process wide state below.
596  static Mutex* mutex_;
597  static SamplerThread* instance_;
598
599  const int interval_;
600  List<Sampler*> active_samplers_;
601
602  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
603};
604
605
606Mutex* SamplerThread::mutex_ = NULL;
607SamplerThread* SamplerThread::instance_ = NULL;
608
609
610//
611// StackTracer implementation
612//
613DISABLE_ASAN void TickSample::Init(Isolate* isolate,
614                                   const RegisterState& regs) {
615  ASSERT(isolate->IsInitialized());
616  pc = regs.pc;
617  state = isolate->current_vm_state();
618
619  // Avoid collecting traces while doing GC.
620  if (state == GC) return;
621
622  Address js_entry_sp = isolate->js_entry_sp();
623  if (js_entry_sp == 0) {
624    // Not executing JS now.
625    return;
626  }
627
628  ExternalCallbackScope* scope = isolate->external_callback_scope();
629  Address handler = Isolate::handler(isolate->thread_local_top());
630  // If there is a handler on top of the external callback scope then
631  // we have already entrered JavaScript again and the external callback
632  // is not the top function.
633  if (scope && scope->scope_address() < handler) {
634    external_callback = scope->callback();
635    has_external_callback = true;
636  } else {
637    // Sample potential return address value for frameless invocation of
638    // stubs (we'll figure out later, if this value makes sense).
639    tos = Memory::Address_at(regs.sp);
640    has_external_callback = false;
641  }
642
643  SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
644  top_frame_type = it.top_frame_type();
645  int i = 0;
646  while (!it.done() && i < TickSample::kMaxFramesCount) {
647    stack[i++] = it.frame()->pc();
648    it.Advance();
649  }
650  frames_count = i;
651}
652
653
654void Sampler::SetUp() {
655  SamplerThread::SetUp();
656}
657
658
659void Sampler::TearDown() {
660  SamplerThread::TearDown();
661}
662
663
664Sampler::Sampler(Isolate* isolate, int interval)
665    : isolate_(isolate),
666      interval_(interval),
667      profiling_(false),
668      active_(false),
669      is_counting_samples_(false),
670      js_and_external_sample_count_(0) {
671  data_ = new PlatformData;
672}
673
674
675Sampler::~Sampler() {
676  ASSERT(!IsActive());
677  delete data_;
678}
679
680
681void Sampler::Start() {
682  ASSERT(!IsActive());
683  SetActive(true);
684  SamplerThread::AddActiveSampler(this);
685}
686
687
688void Sampler::Stop() {
689  ASSERT(IsActive());
690  SamplerThread::RemoveActiveSampler(this);
691  SetActive(false);
692}
693
694
695void Sampler::SampleStack(const RegisterState& state) {
696  TickSample* sample = isolate_->cpu_profiler()->TickSampleEvent();
697  TickSample sample_obj;
698  if (sample == NULL) sample = &sample_obj;
699  sample->Init(isolate_, state);
700  if (is_counting_samples_) {
701    if (sample->state == JS || sample->state == EXTERNAL) {
702      ++js_and_external_sample_count_;
703    }
704  }
705  Tick(sample);
706}
707
708} }  // namespace v8::internal
709