sampler.cc 23.5 KB
Newer Older
1
// Copyright 2013 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// 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 12 13 14

#include <errno.h>
#include <pthread.h>
#include <signal.h>
#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 23
// OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
// and is a typedef for struct sigcontext. There is no uc_mcontext.
24 25
#elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && \
    !V8_OS_OPENBSD && !V8_OS_NACL
26 27
#include <ucontext.h>
#endif
28

29
#include <unistd.h>
30 31 32

// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
// Old versions of the C library <signal.h> didn't define the type.
33
#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
34 35
    (defined(__arm__) || defined(__aarch64__)) && \
    !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
36
#include <asm/sigcontext.h>  // NOLINT
37 38
#endif

39
#elif V8_OS_WIN || V8_OS_CYGWIN
40

41
#include "src/base/win32-headers.h"
42 43 44

#endif

45
#include "src/v8.h"
46

47
#include "src/base/platform/platform.h"
48 49 50 51 52 53 54
#include "src/cpu-profiler-inl.h"
#include "src/flags.h"
#include "src/frames-inl.h"
#include "src/log.h"
#include "src/simulator.h"
#include "src/v8threads.h"
#include "src/vm-state-inl.h"
55 56


57
#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
58 59 60 61 62 63 64 65

// Not all versions of Android's C library provide ucontext_t.
// Detect this and provide custom but compatible definitions. Note that these
// follow the GLibc naming convention to access register values from
// mcontext_t.
//
// See http://code.google.com/p/android/issues/detail?id=34784

66
#if defined(__arm__)
67 68 69 70 71 72 73 74 75 76 77

typedef struct sigcontext mcontext_t;

typedef struct ucontext {
  uint32_t uc_flags;
  struct ucontext* uc_link;
  stack_t uc_stack;
  mcontext_t uc_mcontext;
  // Other fields are not used by V8, don't define them here.
} ucontext_t;

78 79 80 81 82 83 84 85 86 87 88 89
#elif defined(__aarch64__)

typedef struct sigcontext mcontext_t;

typedef struct ucontext {
  uint64_t uc_flags;
  struct ucontext *uc_link;
  stack_t uc_stack;
  mcontext_t uc_mcontext;
  // Other fields are not used by V8, don't define them here.
} ucontext_t;

90
#elif defined(__mips__)
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
// MIPS version of sigcontext, for Android bionic.
typedef struct {
  uint32_t regmask;
  uint32_t status;
  uint64_t pc;
  uint64_t gregs[32];
  uint64_t fpregs[32];
  uint32_t acx;
  uint32_t fpc_csr;
  uint32_t fpc_eir;
  uint32_t used_math;
  uint32_t dsp;
  uint64_t mdhi;
  uint64_t mdlo;
  uint32_t hi1;
  uint32_t lo1;
  uint32_t hi2;
  uint32_t lo2;
  uint32_t hi3;
  uint32_t lo3;
} mcontext_t;

typedef struct ucontext {
  uint32_t uc_flags;
  struct ucontext* uc_link;
  stack_t uc_stack;
  mcontext_t uc_mcontext;
  // Other fields are not used by V8, don't define them here.
} ucontext_t;

121
#elif defined(__i386__)
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
// x86 version for Android.
typedef struct {
  uint32_t gregs[19];
  void* fpregs;
  uint32_t oldmask;
  uint32_t cr2;
} mcontext_t;

typedef uint32_t kernel_sigset_t[2];  // x86 kernel uses 64-bit signal masks
typedef struct ucontext {
  uint32_t uc_flags;
  struct ucontext* uc_link;
  stack_t uc_stack;
  mcontext_t uc_mcontext;
  // Other fields are not used by V8, don't define them here.
} ucontext_t;
enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155

#elif defined(__x86_64__)
// x64 version for Android.
typedef struct {
  uint64_t gregs[23];
  void* fpregs;
  uint64_t __reserved1[8];
} mcontext_t;

typedef struct ucontext {
  uint64_t uc_flags;
  struct ucontext *uc_link;
  stack_t uc_stack;
  mcontext_t uc_mcontext;
  // Other fields are not used by V8, don't define them here.
} ucontext_t;
enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
156 157
#endif

158
#endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
159 160


161 162 163
namespace v8 {
namespace internal {

164
namespace {
165

166
class PlatformDataCommon : public Malloced {
167
 public:
168 169 170 171 172 173 174 175 176 177 178
  PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
  ThreadId profiled_thread_id() { return profiled_thread_id_; }

 protected:
  ~PlatformDataCommon() {}

 private:
  ThreadId profiled_thread_id_;
};

}  // namespace
179

180 181 182 183 184
#if defined(USE_SIGNALS)

class Sampler::PlatformData : public PlatformDataCommon {
 public:
  PlatformData() : vm_tid_(pthread_self()) {}
185
  pthread_t vm_tid() const { return vm_tid_; }
186 187 188

 private:
  pthread_t vm_tid_;
189 190
};

191
#elif V8_OS_WIN || V8_OS_CYGWIN
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226

// ----------------------------------------------------------------------------
// Win32 profiler support. On Cygwin we use the same sampler implementation as
// on Win32.

class Sampler::PlatformData : public PlatformDataCommon {
 public:
  // Get a handle to the calling thread. This is the thread that we are
  // going to profile. We need to make a copy of the handle because we are
  // going to use it in the sampler thread. Using GetThreadHandle() will
  // not work in this case. We're using OpenThread because DuplicateHandle
  // for some reason doesn't work in Chrome's sandbox.
  PlatformData()
      : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
                                    THREAD_SUSPEND_RESUME |
                                    THREAD_QUERY_INFORMATION,
                                    false,
                                    GetCurrentThreadId())) {}

  ~PlatformData() {
    if (profiled_thread_ != NULL) {
      CloseHandle(profiled_thread_);
      profiled_thread_ = NULL;
    }
  }

  HANDLE profiled_thread() { return profiled_thread_; }

 private:
  HANDLE profiled_thread_;
};
#endif


#if defined(USE_SIMULATOR)
227 228
class SimulatorHelper {
 public:
229
  inline bool Init(Isolate* isolate) {
230
    simulator_ = isolate->thread_local_top()->simulator_;
231 232
    // Check if there is active simulator.
    return simulator_ != NULL;
233 234
  }

235
  inline void FillRegisters(v8::RegisterState* state) {
236
#if V8_TARGET_ARCH_ARM
237 238
    state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    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's 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 a new value.
247 248 249 250 251 252
      // Bailout if sp/fp doesn't contain the new value.
      return;
    }
    state->pc = reinterpret_cast<Address>(simulator_->pc());
    state->sp = reinterpret_cast<Address>(simulator_->sp());
    state->fp = reinterpret_cast<Address>(simulator_->fp());
253
#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
254 255 256 257 258
    state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    state->sp = reinterpret_cast<Address>(simulator_->get_register(
        Simulator::sp));
    state->fp = reinterpret_cast<Address>(simulator_->get_register(
        Simulator::fp));
259 260 261 262 263 264
#elif V8_TARGET_ARCH_PPC
    state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    state->sp =
        reinterpret_cast<Address>(simulator_->get_register(Simulator::sp));
    state->fp =
        reinterpret_cast<Address>(simulator_->get_register(Simulator::fp));
265 266 267 268 269
#endif
  }

 private:
  Simulator* simulator_;
270
};
271
#endif  // USE_SIMULATOR
272 273


274 275
#if defined(USE_SIGNALS)

276 277
class SignalHandler : public AllStatic {
 public:
278
  static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
279
  static void TearDown() { delete mutex_; mutex_ = NULL; }
280 281

  static void IncreaseSamplerCount() {
282
    base::LockGuard<base::Mutex> lock_guard(mutex_);
283 284 285 286
    if (++client_count_ == 1) Install();
  }

  static void DecreaseSamplerCount() {
287
    base::LockGuard<base::Mutex> lock_guard(mutex_);
288 289 290 291 292 293 294 295 296
    if (--client_count_ == 0) Restore();
  }

  static bool Installed() {
    return signal_handler_installed_;
  }

 private:
  static void Install() {
297
#if !V8_OS_NACL
298 299 300
    struct sigaction sa;
    sa.sa_sigaction = &HandleProfilerSignal;
    sigemptyset(&sa.sa_mask);
301 302 303
#if V8_OS_QNX
    sa.sa_flags = SA_SIGINFO;
#else
304
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
305
#endif
306 307
    signal_handler_installed_ =
        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
308
#endif
309 310
  }

311
  static void Restore() {
312
#if !V8_OS_NACL
313 314 315 316
    if (signal_handler_installed_) {
      sigaction(SIGPROF, &old_signal_handler_, 0);
      signal_handler_installed_ = false;
    }
317
#endif
318 319
  }

320
#if !V8_OS_NACL
321
  static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
322
#endif
323
  // Protects the process wide state below.
324
  static base::Mutex* mutex_;
325
  static int client_count_;
326 327 328 329
  static bool signal_handler_installed_;
  static struct sigaction old_signal_handler_;
};

330

331
base::Mutex* SignalHandler::mutex_ = NULL;
332
int SignalHandler::client_count_ = 0;
333 334 335 336
struct sigaction SignalHandler::old_signal_handler_;
bool SignalHandler::signal_handler_installed_ = false;


337 338
// As Native Client does not support signal handling, profiling is disabled.
#if !V8_OS_NACL
339 340
void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
                                         void* context) {
341 342
  USE(info);
  if (signal != SIGPROF) return;
343
  Isolate* isolate = Isolate::UnsafeCurrent();
344
  if (isolate == NULL || !isolate->IsInUse()) {
345 346 347 348 349 350 351 352 353
    // We require a fully initialized and entered isolate.
    return;
  }
  if (v8::Locker::IsActive() &&
      !isolate->thread_manager()->IsLockedByCurrentThread()) {
    return;
  }

  Sampler* sampler = isolate->logger()->sampler();
354
  if (sampler == NULL) return;
355

356
  v8::RegisterState state;
357 358

#if defined(USE_SIMULATOR)
359
  SimulatorHelper helper;
360
  if (!helper.Init(isolate)) return;
361
  helper.FillRegisters(&state);
362
  // It possible that the simulator is interrupted while it is updating
363
  // the sp or fp register. ARM64 simulator does this in two steps:
364 365 366
  // first setting it to zero and then setting it to the new value.
  // Bailout if sp/fp doesn't contain the new value.
  if (state.sp == 0 || state.fp == 0) return;
367 368 369
#else
  // Extracting the sample from the context is extremely machine dependent.
  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
370
#if !(V8_OS_OPENBSD || (V8_OS_LINUX && V8_HOST_ARCH_PPC))
371
  mcontext_t& mcontext = ucontext->uc_mcontext;
372
#endif
373
#if V8_OS_LINUX
374
#if V8_HOST_ARCH_IA32
375 376 377
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
378
#elif V8_HOST_ARCH_X64
379 380 381
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
382
#elif V8_HOST_ARCH_ARM
383
#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
384 385
  // Old GLibc ARM versions used a gregs[] array to access the register
  // values from mcontext_t.
386 387 388
  state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
389
#else
390 391 392
  state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
  state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
  state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
393
#endif  // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
394
#elif V8_HOST_ARCH_ARM64
395 396 397 398
  state.pc = reinterpret_cast<Address>(mcontext.pc);
  state.sp = reinterpret_cast<Address>(mcontext.sp);
  // FP is an alias for x29.
  state.fp = reinterpret_cast<Address>(mcontext.regs[29]);
399
#elif V8_HOST_ARCH_MIPS
400 401 402
  state.pc = reinterpret_cast<Address>(mcontext.pc);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
403 404 405 406
#elif V8_HOST_ARCH_MIPS64
  state.pc = reinterpret_cast<Address>(mcontext.pc);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
407 408 409 410
#elif V8_HOST_ARCH_PPC
  state.pc = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->nip);
  state.sp = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->gpr[PT_R1]);
  state.fp = reinterpret_cast<Address>(ucontext->uc_mcontext.regs->gpr[PT_R31]);
411
#endif  // V8_HOST_ARCH_*
412
#elif V8_OS_MACOSX
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
#if V8_HOST_ARCH_X64
#if __DARWIN_UNIX03
  state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
  state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
  state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
#else  // !__DARWIN_UNIX03
  state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
  state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
  state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
#endif  // __DARWIN_UNIX03
#elif V8_HOST_ARCH_IA32
#if __DARWIN_UNIX03
  state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
  state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
  state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
#else  // !__DARWIN_UNIX03
  state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
  state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
  state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
#endif  // __DARWIN_UNIX03
#endif  // V8_HOST_ARCH_IA32
434
#elif V8_OS_FREEBSD
435
#if V8_HOST_ARCH_IA32
436 437 438
  state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
  state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
  state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
439
#elif V8_HOST_ARCH_X64
440 441 442
  state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
  state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
  state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
443
#elif V8_HOST_ARCH_ARM
444 445 446
  state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
  state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
  state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
447
#endif  // V8_HOST_ARCH_*
448
#elif V8_OS_NETBSD
449
#if V8_HOST_ARCH_IA32
450 451 452
  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
453
#elif V8_HOST_ARCH_X64
454 455 456
  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RBP]);
457
#endif  // V8_HOST_ARCH_*
458
#elif V8_OS_OPENBSD
459
#if V8_HOST_ARCH_IA32
460 461 462
  state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
  state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
  state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
463
#elif V8_HOST_ARCH_X64
464 465 466
  state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
  state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
  state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
467
#endif  // V8_HOST_ARCH_*
468
#elif V8_OS_SOLARIS
469 470 471
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
472 473 474 475 476 477 478 479 480 481
#elif V8_OS_QNX
#if V8_HOST_ARCH_IA32
  state.pc = reinterpret_cast<Address>(mcontext.cpu.eip);
  state.sp = reinterpret_cast<Address>(mcontext.cpu.esp);
  state.fp = reinterpret_cast<Address>(mcontext.cpu.ebp);
#elif V8_HOST_ARCH_ARM
  state.pc = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_PC]);
  state.sp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_SP]);
  state.fp = reinterpret_cast<Address>(mcontext.cpu.gpr[ARM_REG_FP]);
#endif  // V8_HOST_ARCH_*
482 483 484 485 486
#elif V8_OS_AIX
  state.pc = reinterpret_cast<Address>(mcontext.jmp_context.iar);
  state.sp = reinterpret_cast<Address>(mcontext.jmp_context.gpr[1]);
  state.fp = reinterpret_cast<Address>(mcontext.jmp_context.gpr[31]);
#endif  // V8_OS_AIX
487
#endif  // USE_SIMULATOR
488
  sampler->SampleStack(state);
489
}
490
#endif  // V8_OS_NACL
491

492 493 494
#endif


495
class SamplerThread : public base::Thread {
496 497 498 499
 public:
  static const int kSamplerThreadStackSize = 64 * KB;

  explicit SamplerThread(int interval)
500
      : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)),
501 502
        interval_(interval) {}

503
  static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
504
  static void TearDown() { delete mutex_; mutex_ = NULL; }
505 506

  static void AddActiveSampler(Sampler* sampler) {
507
    bool need_to_start = false;
508
    base::LockGuard<base::Mutex> lock_guard(mutex_);
509 510 511
    if (instance_ == NULL) {
      // Start a thread that will send SIGPROF signal to VM threads,
      // when CPU profiling will be enabled.
512
      instance_ = new SamplerThread(sampler->interval());
513
      need_to_start = true;
514
    }
515

516 517 518
    DCHECK(sampler->IsActive());
    DCHECK(!instance_->active_samplers_.Contains(sampler));
    DCHECK(instance_->interval_ == sampler->interval());
519 520 521
    instance_->active_samplers_.Add(sampler);

    if (need_to_start) instance_->StartSynchronously();
522 523 524
  }

  static void RemoveActiveSampler(Sampler* sampler) {
525 526
    SamplerThread* instance_to_remove = NULL;
    {
527
      base::LockGuard<base::Mutex> lock_guard(mutex_);
528

529
      DCHECK(sampler->IsActive());
530
      bool removed = instance_->active_samplers_.RemoveElement(sampler);
531
      DCHECK(removed);
532 533 534 535 536 537 538 539
      USE(removed);

      // We cannot delete the instance immediately as we need to Join() the
      // thread but we are holding mutex_ and the thread may try to acquire it.
      if (instance_->active_samplers_.is_empty()) {
        instance_to_remove = instance_;
        instance_ = NULL;
      }
540
    }
541 542 543 544

    if (!instance_to_remove) return;
    instance_to_remove->Join();
    delete instance_to_remove;
545 546 547 548
  }

  // Implement Thread::Run().
  virtual void Run() {
549 550
    while (true) {
      {
551
        base::LockGuard<base::Mutex> lock_guard(mutex_);
552 553 554 555 556 557
        if (active_samplers_.is_empty()) break;
        // When CPU profiling is enabled both JavaScript and C++ code is
        // profiled. We must not suspend.
        for (int i = 0; i < active_samplers_.length(); ++i) {
          Sampler* sampler = active_samplers_.at(i);
          if (!sampler->IsProfiling()) continue;
558
          sampler->DoSample();
559
        }
560
      }
561
      base::OS::Sleep(interval_);
562 563 564
    }
  }

565
 private:
566
  // Protects the process wide state below.
567
  static base::Mutex* mutex_;
568
  static SamplerThread* instance_;
569

570 571 572
  const int interval_;
  List<Sampler*> active_samplers_;

573
  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
574 575 576
};


577
base::Mutex* SamplerThread::mutex_ = NULL;
578
SamplerThread* SamplerThread::instance_ = NULL;
579 580


581 582 583
//
// StackTracer implementation
//
584
DISABLE_ASAN void TickSample::Init(Isolate* isolate,
585 586
                                   const v8::RegisterState& regs,
                                   RecordCEntryFrame record_c_entry_frame) {
587
  timestamp = base::TimeTicks::HighResolutionNow();
588
  pc = reinterpret_cast<Address>(regs.pc);
589
  state = isolate->current_vm_state();
590 591 592 593

  // Avoid collecting traces while doing GC.
  if (state == GC) return;

594
  Address js_entry_sp = isolate->js_entry_sp();
595
  if (js_entry_sp == 0) return;  // Not executing JS now.
596

597 598 599 600 601 602 603
  ExternalCallbackScope* scope = isolate->external_callback_scope();
  Address handler = Isolate::handler(isolate->thread_local_top());
  // If there is a handler on top of the external callback scope then
  // we have already entrered JavaScript again and the external callback
  // is not the top function.
  if (scope && scope->scope_address() < handler) {
    external_callback = scope->callback();
604 605 606 607
    has_external_callback = true;
  } else {
    // Sample potential return address value for frameless invocation of
    // stubs (we'll figure out later, if this value makes sense).
608
    tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp));
609 610
    has_external_callback = false;
  }
611

612 613
  SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
                            reinterpret_cast<Address>(regs.sp), js_entry_sp);
614
  top_frame_type = it.top_frame_type();
615 616

  SampleInfo info;
617 618
  GetStackSample(isolate, regs, record_c_entry_frame,
                 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info);
619 620 621 622 623
  frames_count = static_cast<unsigned>(info.frames_count);
}


void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs,
624
                                RecordCEntryFrame record_c_entry_frame,
625 626 627 628 629 630 631 632 633 634 635 636
                                void** frames, size_t frames_limit,
                                v8::SampleInfo* sample_info) {
  sample_info->frames_count = 0;
  sample_info->vm_state = isolate->current_vm_state();
  if (sample_info->vm_state == GC) return;

  Address js_entry_sp = isolate->js_entry_sp();
  if (js_entry_sp == 0) return;  // Not executing JS now.

  SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
                            reinterpret_cast<Address>(regs.sp), js_entry_sp);
  size_t i = 0;
637 638 639 640
  if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() &&
      it.top_frame_type() == StackFrame::EXIT) {
    frames[i++] = isolate->c_function();
  }
641 642
  while (!it.done() && i < frames_limit) {
    frames[i++] = it.frame()->pc();
643 644
    it.Advance();
  }
645
  sample_info->frames_count = i;
646 647 648
}


649
void Sampler::SetUp() {
650 651 652
#if defined(USE_SIGNALS)
  SignalHandler::SetUp();
#endif
653
  SamplerThread::SetUp();
654 655 656 657
}


void Sampler::TearDown() {
658
  SamplerThread::TearDown();
659 660 661
#if defined(USE_SIGNALS)
  SignalHandler::TearDown();
#endif
662 663 664 665 666 667 668
}


Sampler::Sampler(Isolate* isolate, int interval)
    : isolate_(isolate),
      interval_(interval),
      profiling_(false),
669
      has_processing_thread_(false),
670
      active_(false),
671 672
      is_counting_samples_(false),
      js_and_external_sample_count_(0) {
673 674 675 676 677
  data_ = new PlatformData;
}


Sampler::~Sampler() {
678
  DCHECK(!IsActive());
679 680 681
  delete data_;
}

682

683
void Sampler::Start() {
684
  DCHECK(!IsActive());
685
  SetActive(true);
686
  SamplerThread::AddActiveSampler(this);
687 688 689 690
}


void Sampler::Stop() {
691
  DCHECK(IsActive());
692
  SamplerThread::RemoveActiveSampler(this);
693 694 695
  SetActive(false);
}

696

697
void Sampler::IncreaseProfilingDepth() {
698
  base::NoBarrier_AtomicIncrement(&profiling_, 1);
699 700 701 702 703 704 705 706 707 708
#if defined(USE_SIGNALS)
  SignalHandler::IncreaseSamplerCount();
#endif
}


void Sampler::DecreaseProfilingDepth() {
#if defined(USE_SIGNALS)
  SignalHandler::DecreaseSamplerCount();
#endif
709
  base::NoBarrier_AtomicIncrement(&profiling_, -1);
710 711 712
}


713
void Sampler::SampleStack(const v8::RegisterState& state) {
714
  TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
715 716
  TickSample sample_obj;
  if (sample == NULL) sample = &sample_obj;
717
  sample->Init(isolate_, state, TickSample::kIncludeCEntryFrame);
718 719 720 721 722
  if (is_counting_samples_) {
    if (sample->state == JS || sample->state == EXTERNAL) {
      ++js_and_external_sample_count_;
    }
  }
723
  Tick(sample);
724 725 726
  if (sample != &sample_obj) {
    isolate_->cpu_profiler()->FinishTickSample();
  }
727 728
}

729 730

#if defined(USE_SIGNALS)
731 732 733 734 735 736

void Sampler::DoSample() {
  if (!SignalHandler::Installed()) return;
  pthread_kill(platform_data()->vm_tid(), SIGPROF);
}

737
#elif V8_OS_WIN || V8_OS_CYGWIN
738 739 740 741 742 743 744

void Sampler::DoSample() {
  HANDLE profiled_thread = platform_data()->profiled_thread();
  if (profiled_thread == NULL) return;

#if defined(USE_SIMULATOR)
  SimulatorHelper helper;
745
  if (!helper.Init(isolate())) return;
746
#endif
747 748 749 750 751 752 753 754 755

  const DWORD kSuspendFailed = static_cast<DWORD>(-1);
  if (SuspendThread(profiled_thread) == kSuspendFailed) return;

  // Context used for sampling the register state of the profiled thread.
  CONTEXT context;
  memset(&context, 0, sizeof(context));
  context.ContextFlags = CONTEXT_FULL;
  if (GetThreadContext(profiled_thread, &context) != 0) {
756
    v8::RegisterState state;
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
#if defined(USE_SIMULATOR)
    helper.FillRegisters(&state);
#else
#if V8_HOST_ARCH_X64
    state.pc = reinterpret_cast<Address>(context.Rip);
    state.sp = reinterpret_cast<Address>(context.Rsp);
    state.fp = reinterpret_cast<Address>(context.Rbp);
#else
    state.pc = reinterpret_cast<Address>(context.Eip);
    state.sp = reinterpret_cast<Address>(context.Esp);
    state.fp = reinterpret_cast<Address>(context.Ebp);
#endif
#endif  // USE_SIMULATOR
    SampleStack(state);
  }
  ResumeThread(profiled_thread);
773 774
}

775 776 777
#endif  // USE_SIGNALS


778
} }  // namespace v8::internal