sampler.cc 26.3 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/profiler/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/base/platform/platform.h"
46 47 48
#include "src/flags.h"
#include "src/frames-inl.h"
#include "src/log.h"
49
#include "src/profiler/cpu-profiler-inl.h"
50 51 52
#include "src/simulator.h"
#include "src/v8threads.h"
#include "src/vm-state-inl.h"
53 54


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

// 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

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

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;

76 77 78 79 80 81 82 83 84 85 86 87
#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;

88
#elif defined(__mips__)
89 90 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
// 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;

119
#elif defined(__i386__)
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
// 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 };
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

#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 };
154 155
#endif

156
#endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
157 158


159 160 161
namespace v8 {
namespace internal {

162
namespace {
163

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

 protected:
  ~PlatformDataCommon() {}

 private:
  ThreadId profiled_thread_id_;
};

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 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 227 228 229 230 231 232 233 234 235 236 237 238

bool IsSamePage(byte* ptr1, byte* ptr2) {
  const uint32_t kPageSize = 4096;
  uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1);
  return (reinterpret_cast<uintptr_t>(ptr1) & mask) ==
         (reinterpret_cast<uintptr_t>(ptr2) & mask);
}


// Check if the code at specified address could potentially be a
// frame setup code.
bool IsNoFrameRegion(Address address) {
  struct Pattern {
    int bytes_count;
    byte bytes[8];
    int offsets[4];
  };
  byte* pc = reinterpret_cast<byte*>(address);
  static Pattern patterns[] = {
#if V8_HOST_ARCH_IA32
    // push %ebp
    // mov %esp,%ebp
    {3, {0x55, 0x89, 0xe5}, {0, 1, -1}},
    // pop %ebp
    // ret N
    {2, {0x5d, 0xc2}, {0, 1, -1}},
    // pop %ebp
    // ret
    {2, {0x5d, 0xc3}, {0, 1, -1}},
#elif V8_HOST_ARCH_X64
    // pushq %rbp
    // movq %rsp,%rbp
    {4, {0x55, 0x48, 0x89, 0xe5}, {0, 1, -1}},
    // popq %rbp
    // ret N
    {2, {0x5d, 0xc2}, {0, 1, -1}},
    // popq %rbp
    // ret
    {2, {0x5d, 0xc3}, {0, 1, -1}},
#endif
    {0, {}, {}}
  };
  for (Pattern* pattern = patterns; pattern->bytes_count; ++pattern) {
    for (int* offset_ptr = pattern->offsets; *offset_ptr != -1; ++offset_ptr) {
      int offset = *offset_ptr;
      if (!offset || IsSamePage(pc, pc - offset)) {
        MSAN_MEMORY_IS_INITIALIZED(pc - offset, pattern->bytes_count);
        if (!memcmp(pc - offset, pattern->bytes, pattern->bytes_count))
          return true;
      } else {
        // It is not safe to examine bytes on another page as it might not be
        // allocated thus causing a SEGFAULT.
        // Check the pattern part that's on the same page and
        // pessimistically assume it could be the entire pattern match.
        MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset);
        if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset))
          return true;
      }
    }
  }
  return false;
}

239
}  // namespace
240

241 242 243 244 245
#if defined(USE_SIGNALS)

class Sampler::PlatformData : public PlatformDataCommon {
 public:
  PlatformData() : vm_tid_(pthread_self()) {}
246
  pthread_t vm_tid() const { return vm_tid_; }
247 248 249

 private:
  pthread_t vm_tid_;
250 251
};

252
#elif V8_OS_WIN || V8_OS_CYGWIN
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287

// ----------------------------------------------------------------------------
// 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)
288 289
class SimulatorHelper {
 public:
290
  inline bool Init(Isolate* isolate) {
291
    simulator_ = isolate->thread_local_top()->simulator_;
292 293
    // Check if there is active simulator.
    return simulator_ != NULL;
294 295
  }

296
  inline void FillRegisters(v8::RegisterState* state) {
297
#if V8_TARGET_ARCH_ARM
298 299 300
    if (!simulator_->has_bad_pc()) {
      state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    }
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 313 314 315 316 317
      //
      // FIXME: The above doesn't really solve the issue.
      // If a 64-bit target is executed on a 32-bit host even the final
      // write is non-atomic, so it might obtain a half of the result.
      // Moreover as long as the register set code uses memcpy (as of now),
      // it is not guaranteed to be atomic even when both host and target
      // are of same bitness.
318 319 320 321 322
      return;
    }
    state->pc = reinterpret_cast<Address>(simulator_->pc());
    state->sp = reinterpret_cast<Address>(simulator_->sp());
    state->fp = reinterpret_cast<Address>(simulator_->fp());
323
#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
324 325 326
    if (!simulator_->has_bad_pc()) {
      state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    }
327 328 329 330
    state->sp = reinterpret_cast<Address>(simulator_->get_register(
        Simulator::sp));
    state->fp = reinterpret_cast<Address>(simulator_->get_register(
        Simulator::fp));
331
#elif V8_TARGET_ARCH_PPC
332 333 334
    if (!simulator_->has_bad_pc()) {
      state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    }
335 336 337 338
    state->sp =
        reinterpret_cast<Address>(simulator_->get_register(Simulator::sp));
    state->fp =
        reinterpret_cast<Address>(simulator_->get_register(Simulator::fp));
339 340 341 342 343
#endif
  }

 private:
  Simulator* simulator_;
344
};
345
#endif  // USE_SIMULATOR
346 347


348 349
#if defined(USE_SIGNALS)

350 351
class SignalHandler : public AllStatic {
 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 358 359 360
    if (++client_count_ == 1) Install();
  }

  static void DecreaseSamplerCount() {
361
    base::LockGuard<base::Mutex> lock_guard(mutex_);
362 363 364 365 366 367 368 369 370
    if (--client_count_ == 0) Restore();
  }

  static bool Installed() {
    return signal_handler_installed_;
  }

 private:
  static void Install() {
371
#if !V8_OS_NACL
372 373 374
    struct sigaction sa;
    sa.sa_sigaction = &HandleProfilerSignal;
    sigemptyset(&sa.sa_mask);
375 376 377
#if V8_OS_QNX
    sa.sa_flags = SA_SIGINFO;
#else
378
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
379
#endif
380 381
    signal_handler_installed_ =
        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
382
#endif
383 384
  }

385
  static void Restore() {
386
#if !V8_OS_NACL
387 388 389 390
    if (signal_handler_installed_) {
      sigaction(SIGPROF, &old_signal_handler_, 0);
      signal_handler_installed_ = false;
    }
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 401 402 403
  static bool signal_handler_installed_;
  static struct sigaction old_signal_handler_;
};

404

405
base::Mutex* SignalHandler::mutex_ = NULL;
406
int SignalHandler::client_count_ = 0;
407 408 409 410
struct sigaction SignalHandler::old_signal_handler_;
bool SignalHandler::signal_handler_installed_ = false;


411 412
// As Native Client does not support signal handling, profiling is disabled.
#if !V8_OS_NACL
413 414
void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
                                         void* context) {
415 416
  USE(info);
  if (signal != SIGPROF) return;
417
  Isolate* isolate = Isolate::UnsafeCurrent();
418
  if (isolate == NULL || !isolate->IsInUse()) {
419 420 421 422 423 424 425 426 427
    // We require a fully initialized and entered isolate.
    return;
  }
  if (v8::Locker::IsActive() &&
      !isolate->thread_manager()->IsLockedByCurrentThread()) {
    return;
  }

  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 439 440
  // 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;
441 442 443
#else
  // Extracting the sample from the context is extremely machine dependent.
  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 450 451
  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]);
452
#elif V8_HOST_ARCH_X64
453 454 455
  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]);
456
#elif V8_HOST_ARCH_ARM
457
#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
458 459
  // Old GLibc ARM versions used a gregs[] array to access the register
  // values from mcontext_t.
460 461 462
  state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
463
#else
464 465 466
  state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
  state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
  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 470 471 472
  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]);
473
#elif V8_HOST_ARCH_MIPS
474 475 476
  state.pc = reinterpret_cast<Address>(mcontext.pc);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
477 478 479 480
#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]);
481 482 483 484
#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]);
485
#endif  // V8_HOST_ARCH_*
486
#elif V8_OS_MACOSX
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
#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
508
#elif V8_OS_FREEBSD
509
#if V8_HOST_ARCH_IA32
510 511 512
  state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
  state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
  state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
513
#elif V8_HOST_ARCH_X64
514 515 516
  state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
  state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
  state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
517
#elif V8_HOST_ARCH_ARM
518 519 520
  state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
  state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
  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 525 526
  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]);
527
#elif V8_HOST_ARCH_X64
528 529 530
  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]);
531
#endif  // V8_HOST_ARCH_*
532
#elif V8_OS_OPENBSD
533
#if V8_HOST_ARCH_IA32
534 535 536
  state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
  state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
  state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
537
#elif V8_HOST_ARCH_X64
538 539 540
  state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
  state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
  state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
541
#endif  // V8_HOST_ARCH_*
542
#elif V8_OS_SOLARIS
543 544 545
  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]);
546 547 548 549 550 551 552 553 554 555
#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_*
556 557 558 559 560
#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
561
#endif  // USE_SIMULATOR
562
  sampler->SampleStack(state);
563
}
564
#endif  // V8_OS_NACL
565

566 567 568
#endif


569
class SamplerThread : public base::Thread {
570 571 572 573
 public:
  static const int kSamplerThreadStackSize = 64 * KB;

  explicit SamplerThread(int interval)
574
      : Thread(base::Thread::Options("SamplerThread", kSamplerThreadStackSize)),
575 576
        interval_(interval) {}

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 584 585
    if (instance_ == NULL) {
      // Start a thread that will send SIGPROF signal to VM threads,
      // when CPU profiling will be enabled.
586
      instance_ = new SamplerThread(sampler->interval());
587
      need_to_start = true;
588
    }
589

590 591 592
    DCHECK(sampler->IsActive());
    DCHECK(!instance_->active_samplers_.Contains(sampler));
    DCHECK(instance_->interval_ == sampler->interval());
593 594 595
    instance_->active_samplers_.Add(sampler);

    if (need_to_start) instance_->StartSynchronously();
596 597 598
  }

  static void RemoveActiveSampler(Sampler* sampler) {
599 600
    SamplerThread* instance_to_remove = NULL;
    {
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 607 608 609 610 611 612 613
      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;
      }
614
    }
615 616 617 618

    if (!instance_to_remove) return;
    instance_to_remove->Join();
    delete instance_to_remove;
619 620 621 622
  }

  // Implement Thread::Run().
  virtual void Run() {
623 624
    while (true) {
      {
625
        base::LockGuard<base::Mutex> lock_guard(mutex_);
626 627 628 629 630 631
        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;
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 645 646
  const int interval_;
  List<Sampler*> active_samplers_;

647
  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
648 649 650
};


651
base::Mutex* SamplerThread::mutex_ = NULL;
652
SamplerThread* SamplerThread::instance_ = NULL;
653 654


655 656 657
//
// StackTracer implementation
//
658
DISABLE_ASAN void TickSample::Init(Isolate* isolate,
659
                                   const v8::RegisterState& regs,
660 661
                                   RecordCEntryFrame record_c_entry_frame,
                                   bool update_stats) {
662
  timestamp = base::TimeTicks::HighResolutionNow();
663
  pc = reinterpret_cast<Address>(regs.pc);
664
  state = isolate->current_vm_state();
665
  this->update_stats = update_stats;
666 667 668 669

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

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

673 674 675 676 677
  if (pc && IsNoFrameRegion(pc)) {
    pc = 0;
    return;
  }

678 679 680 681 682 683 684
  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();
685 686
    has_external_callback = true;
  } else {
687 688 689
    // sp register may point at an arbitrary place in memory, make
    // sure MSAN doesn't complain about it.
    MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address));
690 691
    // Sample potential return address value for frameless invocation of
    // stubs (we'll figure out later, if this value makes sense).
692
    tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp));
693 694
    has_external_callback = false;
  }
695

696 697
  SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
                            reinterpret_cast<Address>(regs.sp), js_entry_sp);
698
  top_frame_type = it.top_frame_type();
699 700

  SampleInfo info;
701 702
  GetStackSample(isolate, regs, record_c_entry_frame,
                 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info);
703 704 705 706 707
  frames_count = static_cast<unsigned>(info.frames_count);
}


void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs,
708
                                RecordCEntryFrame record_c_entry_frame,
709 710 711 712 713 714 715 716 717 718 719 720
                                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;
721 722 723 724
  if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() &&
      it.top_frame_type() == StackFrame::EXIT) {
    frames[i++] = isolate->c_function();
  }
725 726
  while (!it.done() && i < frames_limit) {
    frames[i++] = it.frame()->pc();
727 728
    it.Advance();
  }
729
  sample_info->frames_count = i;
730 731 732
}


733
void Sampler::SetUp() {
734 735 736
#if defined(USE_SIGNALS)
  SignalHandler::SetUp();
#endif
737
  SamplerThread::SetUp();
738 739 740 741
}


void Sampler::TearDown() {
742
  SamplerThread::TearDown();
743 744 745
#if defined(USE_SIGNALS)
  SignalHandler::TearDown();
#endif
746 747 748 749 750 751 752
}


Sampler::Sampler(Isolate* isolate, int interval)
    : isolate_(isolate),
      interval_(interval),
      profiling_(false),
753
      has_processing_thread_(false),
754
      active_(false),
755 756
      is_counting_samples_(false),
      js_and_external_sample_count_(0) {
757 758 759 760 761
  data_ = new PlatformData;
}


Sampler::~Sampler() {
762
  DCHECK(!IsActive());
763 764 765
  delete data_;
}

766

767
void Sampler::Start() {
768
  DCHECK(!IsActive());
769
  SetActive(true);
770
  SamplerThread::AddActiveSampler(this);
771 772 773 774
}


void Sampler::Stop() {
775
  DCHECK(IsActive());
776
  SamplerThread::RemoveActiveSampler(this);
777 778 779
  SetActive(false);
}

780

781
void Sampler::IncreaseProfilingDepth() {
782
  base::NoBarrier_AtomicIncrement(&profiling_, 1);
783 784 785 786 787 788 789 790 791 792
#if defined(USE_SIGNALS)
  SignalHandler::IncreaseSamplerCount();
#endif
}


void Sampler::DecreaseProfilingDepth() {
#if defined(USE_SIGNALS)
  SignalHandler::DecreaseSamplerCount();
#endif
793
  base::NoBarrier_AtomicIncrement(&profiling_, -1);
794 795 796
}


797
void Sampler::SampleStack(const v8::RegisterState& state) {
798
  TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
799 800
  TickSample sample_obj;
  if (sample == NULL) sample = &sample_obj;
801
  sample->Init(isolate_, state, TickSample::kIncludeCEntryFrame, true);
802 803 804 805 806
  if (is_counting_samples_) {
    if (sample->state == JS || sample->state == EXTERNAL) {
      ++js_and_external_sample_count_;
    }
  }
807
  Tick(sample);
808 809 810
  if (sample != &sample_obj) {
    isolate_->cpu_profiler()->FinishTickSample();
  }
811 812
}

813 814

#if defined(USE_SIGNALS)
815 816 817 818 819 820

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

821
#elif V8_OS_WIN || V8_OS_CYGWIN
822 823 824 825 826 827 828

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

#if defined(USE_SIMULATOR)
  SimulatorHelper helper;
829
  if (!helper.Init(isolate())) return;
830
#endif
831 832 833 834 835 836 837 838 839

  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) {
840
    v8::RegisterState state;
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
#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);
857 858
}

859 860 861
#endif  // USE_SIGNALS


862 863
}  // namespace internal
}  // namespace v8