Home | History | Annotate | Download | only in profiler
      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:
    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 
    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.
    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:
    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 
    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.
    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)
    288 class 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 
    350 class 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 
    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
    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 
    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 
    651 base::Mutex* SamplerThread::mutex_ = NULL;
    652 SamplerThread* SamplerThread::instance_ = NULL;
    653 
    654 
    655 //
    656 // StackTracer implementation
    657 //
    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 
    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 
    731 void Sampler::SetUp() {
    732 #if defined(USE_SIGNALS)
    733   SignalHandler::SetUp();
    734 #endif
    735   SamplerThread::SetUp();
    736 }
    737 
    738 
    739 void Sampler::TearDown() {
    740   SamplerThread::TearDown();
    741 #if defined(USE_SIGNALS)
    742   SignalHandler::TearDown();
    743 #endif
    744 }
    745 
    746 
    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 
    759 Sampler::~Sampler() {
    760   DCHECK(!IsActive());
    761   delete data_;
    762 }
    763 
    764 
    765 void Sampler::Start() {
    766   DCHECK(!IsActive());
    767   SetActive(true);
    768   SamplerThread::AddActiveSampler(this);
    769 }
    770 
    771 
    772 void Sampler::Stop() {
    773   DCHECK(IsActive());
    774   SamplerThread::RemoveActiveSampler(this);
    775   SetActive(false);
    776 }
    777 
    778 
    779 void Sampler::IncreaseProfilingDepth() {
    780   base::NoBarrier_AtomicIncrement(&profiling_, 1);
    781 #if defined(USE_SIGNALS)
    782   SignalHandler::IncreaseSamplerCount();
    783 #endif
    784 }
    785 
    786 
    787 void Sampler::DecreaseProfilingDepth() {
    788 #if defined(USE_SIGNALS)
    789   SignalHandler::DecreaseSamplerCount();
    790 #endif
    791   base::NoBarrier_AtomicIncrement(&profiling_, -1);
    792 }
    793 
    794 
    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 
    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 
    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