sampler.cc 20.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

28 29
#include "sampler.h"

30
#if V8_OS_POSIX && !V8_OS_CYGWIN
31 32

#define USE_SIGNALS
33 34 35 36 37 38

#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/syscall.h>
39

40
#if V8_OS_MACOSX
41
#include <mach/mach.h>
42 43
// OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
// and is a typedef for struct sigcontext. There is no uc_mcontext.
44 45
#elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) \
    && !V8_OS_OPENBSD
46 47
#include <ucontext.h>
#endif
48
#include <unistd.h>
49 50 51

// 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.
52
#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
53
    defined(__arm__) && !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
54 55 56
#include <asm/sigcontext.h>
#endif

57
#elif V8_OS_WIN || V8_OS_CYGWIN
58 59 60 61 62

#include "win32-headers.h"

#endif

63 64
#include "v8.h"

65
#include "cpu-profiler-inl.h"
66
#include "flags.h"
67
#include "frames-inl.h"
68 69 70 71
#include "log.h"
#include "platform.h"
#include "simulator.h"
#include "v8threads.h"
72
#include "vm-state-inl.h"
73 74


75
#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
76 77 78 79 80 81 82 83

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

84
#if defined(__arm__)
85 86 87 88 89 90 91 92 93 94 95

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;

96
#elif defined(__mips__)
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
// 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;

127
#elif defined(__i386__)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
// 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 };
#endif

147
#endif  // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
148 149


150 151 152
namespace v8 {
namespace internal {

153
namespace {
154

155
class PlatformDataCommon : public Malloced {
156
 public:
157 158 159 160 161 162 163 164 165 166 167
  PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
  ThreadId profiled_thread_id() { return profiled_thread_id_; }

 protected:
  ~PlatformDataCommon() {}

 private:
  ThreadId profiled_thread_id_;
};

}  // namespace
168

169 170 171 172 173
#if defined(USE_SIGNALS)

class Sampler::PlatformData : public PlatformDataCommon {
 public:
  PlatformData() : vm_tid_(pthread_self()) {}
174
  pthread_t vm_tid() const { return vm_tid_; }
175 176 177

 private:
  pthread_t vm_tid_;
178 179
};

180
#elif V8_OS_WIN || V8_OS_CYGWIN
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

// ----------------------------------------------------------------------------
// 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)
216 217 218
class SimulatorHelper {
 public:
  inline bool Init(Sampler* sampler, Isolate* isolate) {
219
    simulator_ = isolate->thread_local_top()->simulator_;
220 221
    // Check if there is active simulator.
    return simulator_ != NULL;
222 223
  }

224 225 226
  inline void FillRegisters(RegisterState* state) {
    state->pc = reinterpret_cast<Address>(simulator_->get_pc());
    state->sp = reinterpret_cast<Address>(simulator_->get_register(
227 228
        Simulator::sp));
#if V8_TARGET_ARCH_ARM
229
    state->fp = reinterpret_cast<Address>(simulator_->get_register(
230 231
        Simulator::r11));
#elif V8_TARGET_ARCH_MIPS
232
    state->fp = reinterpret_cast<Address>(simulator_->get_register(
233 234 235 236 237 238
        Simulator::fp));
#endif
  }

 private:
  Simulator* simulator_;
239
};
240
#endif  // USE_SIMULATOR
241 242


243 244
#if defined(USE_SIGNALS)

245 246
class SignalHandler : public AllStatic {
 public:
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
  static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
  static void TearDown() { delete mutex_; }

  static void IncreaseSamplerCount() {
    LockGuard<Mutex> lock_guard(mutex_);
    if (++client_count_ == 1) Install();
  }

  static void DecreaseSamplerCount() {
    LockGuard<Mutex> lock_guard(mutex_);
    if (--client_count_ == 0) Restore();
  }

  static bool Installed() {
    return signal_handler_installed_;
  }

 private:
  static void Install() {
266 267 268 269 270 271 272 273
    struct sigaction sa;
    sa.sa_sigaction = &HandleProfilerSignal;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_SIGINFO;
    signal_handler_installed_ =
        (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
  }

274
  static void Restore() {
275 276 277 278 279 280 281
    if (signal_handler_installed_) {
      sigaction(SIGPROF, &old_signal_handler_, 0);
      signal_handler_installed_ = false;
    }
  }

  static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
282 283 284
  // Protects the process wide state below.
  static Mutex* mutex_;
  static int client_count_;
285 286 287 288
  static bool signal_handler_installed_;
  static struct sigaction old_signal_handler_;
};

289 290 291

Mutex* SignalHandler::mutex_ = NULL;
int SignalHandler::client_count_ = 0;
292 293 294 295 296 297
struct sigaction SignalHandler::old_signal_handler_;
bool SignalHandler::signal_handler_installed_ = false;


void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
                                         void* context) {
298
#if V8_OS_NACL
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
  // As Native Client does not support signal handling, profiling
  // is disabled.
  return;
#else
  USE(info);
  if (signal != SIGPROF) return;
  Isolate* isolate = Isolate::UncheckedCurrent();
  if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
    // We require a fully initialized and entered isolate.
    return;
  }
  if (v8::Locker::IsActive() &&
      !isolate->thread_manager()->IsLockedByCurrentThread()) {
    return;
  }

  Sampler* sampler = isolate->logger()->sampler();
316
  if (sampler == NULL) return;
317

318
  RegisterState state;
319 320

#if defined(USE_SIMULATOR)
321 322 323
  SimulatorHelper helper;
  if (!helper.Init(sampler, isolate)) return;
  helper.FillRegisters(&state);
324 325 326
#else
  // Extracting the sample from the context is extremely machine dependent.
  ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
327
#if !V8_OS_OPENBSD
328
  mcontext_t& mcontext = ucontext->uc_mcontext;
329
#endif
330
#if V8_OS_LINUX
331
#if V8_HOST_ARCH_IA32
332 333 334
  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]);
335
#elif V8_HOST_ARCH_X64
336 337 338
  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]);
339 340 341 342 343
#elif V8_HOST_ARCH_ARM
#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
    (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
  // Old GLibc ARM versions used a gregs[] array to access the register
  // values from mcontext_t.
344 345 346
  state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
347
#else
348 349 350
  state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
  state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
  state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
351 352 353
#endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
        // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
#elif V8_HOST_ARCH_MIPS
354 355 356
  state.pc = reinterpret_cast<Address>(mcontext.pc);
  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
357
#endif  // V8_HOST_ARCH_*
358
#elif V8_OS_MACOSX
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
#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
380
#elif V8_OS_FREEBSD
381
#if V8_HOST_ARCH_IA32
382 383 384
  state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
  state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
  state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
385
#elif V8_HOST_ARCH_X64
386 387 388
  state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
  state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
  state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
389
#elif V8_HOST_ARCH_ARM
390 391 392
  state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
  state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
  state.fp = reinterpret_cast<Address>(mcontext.mc_r11);
393
#endif  // V8_HOST_ARCH_*
394
#elif V8_OS_NETBSD
395
#if V8_HOST_ARCH_IA32
396 397 398
  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]);
399
#elif V8_HOST_ARCH_X64
400 401 402
  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]);
403
#endif  // V8_HOST_ARCH_*
404
#elif V8_OS_OPENBSD
405
#if V8_HOST_ARCH_IA32
406 407 408
  state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
  state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
  state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
409
#elif V8_HOST_ARCH_X64
410 411 412
  state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
  state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
  state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
413
#endif  // V8_HOST_ARCH_*
414
#elif V8_OS_SOLARIS
415 416 417
  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]);
418
#endif  // V8_OS_SOLARIS
419
#endif  // USE_SIMULATOR
420
  sampler->SampleStack(state);
421
#endif  // V8_OS_NACL
422 423
}

424 425 426 427 428 429 430 431 432
#endif


class SamplerThread : public Thread {
 public:
  static const int kSamplerThreadStackSize = 64 * KB;

  explicit SamplerThread(int interval)
      : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
433 434
        interval_(interval) {}

435 436
  static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
  static void TearDown() { delete mutex_; mutex_ = NULL; }
437 438

  static void AddActiveSampler(Sampler* sampler) {
439
    bool need_to_start = false;
440
    LockGuard<Mutex> lock_guard(mutex_);
441 442 443
    if (instance_ == NULL) {
      // Start a thread that will send SIGPROF signal to VM threads,
      // when CPU profiling will be enabled.
444
      instance_ = new SamplerThread(sampler->interval());
445
      need_to_start = true;
446
    }
447 448 449 450 451 452 453

    ASSERT(sampler->IsActive());
    ASSERT(!instance_->active_samplers_.Contains(sampler));
    ASSERT(instance_->interval_ == sampler->interval());
    instance_->active_samplers_.Add(sampler);

    if (need_to_start) instance_->StartSynchronously();
454 455 456
  }

  static void RemoveActiveSampler(Sampler* sampler) {
457 458
    SamplerThread* instance_to_remove = NULL;
    {
459
      LockGuard<Mutex> lock_guard(mutex_);
460 461 462 463 464 465 466 467 468 469 470 471

      ASSERT(sampler->IsActive());
      bool removed = instance_->active_samplers_.RemoveElement(sampler);
      ASSERT(removed);
      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;
      }
472
    }
473 474 475 476

    if (!instance_to_remove) return;
    instance_to_remove->Join();
    delete instance_to_remove;
477 478 479 480
  }

  // Implement Thread::Run().
  virtual void Run() {
481 482
    while (true) {
      {
483
        LockGuard<Mutex> lock_guard(mutex_);
484 485 486 487 488 489 490
        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->isolate()->IsInitialized()) continue;
          if (!sampler->IsProfiling()) continue;
491
          sampler->DoSample();
492
        }
493
      }
494
      OS::Sleep(interval_);
495 496 497
    }
  }

498
 private:
499 500
  // Protects the process wide state below.
  static Mutex* mutex_;
501
  static SamplerThread* instance_;
502

503 504 505
  const int interval_;
  List<Sampler*> active_samplers_;

506
  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
507 508 509
};


510 511
Mutex* SamplerThread::mutex_ = NULL;
SamplerThread* SamplerThread::instance_ = NULL;
512 513


514 515 516
//
// StackTracer implementation
//
517 518
DISABLE_ASAN void TickSample::Init(Isolate* isolate,
                                   const RegisterState& regs) {
519
  ASSERT(isolate->IsInitialized());
520 521
  pc = regs.pc;
  state = isolate->current_vm_state();
522 523 524 525

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

526
  Address js_entry_sp = isolate->js_entry_sp();
527 528 529 530 531
  if (js_entry_sp == 0) {
    // Not executing JS now.
    return;
  }

532 533 534 535 536 537 538
  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();
539 540 541 542
    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).
543
    tos = Memory::Address_at(regs.sp);
544 545
    has_external_callback = false;
  }
546

547
  SafeStackFrameIterator it(isolate, regs.fp, regs.sp, js_entry_sp);
548
  top_frame_type = it.top_frame_type();
549 550 551 552 553 554 555 556 557
  int i = 0;
  while (!it.done() && i < TickSample::kMaxFramesCount) {
    stack[i++] = it.frame()->pc();
    it.Advance();
  }
  frames_count = i;
}


558
void Sampler::SetUp() {
559 560 561
#if defined(USE_SIGNALS)
  SignalHandler::SetUp();
#endif
562
  SamplerThread::SetUp();
563 564 565 566
}


void Sampler::TearDown() {
567
  SamplerThread::TearDown();
568 569 570
#if defined(USE_SIGNALS)
  SignalHandler::TearDown();
#endif
571 572 573 574 575 576 577
}


Sampler::Sampler(Isolate* isolate, int interval)
    : isolate_(isolate),
      interval_(interval),
      profiling_(false),
578
      has_processing_thread_(false),
579
      active_(false),
580 581
      is_counting_samples_(false),
      js_and_external_sample_count_(0) {
582 583 584 585 586 587 588 589 590
  data_ = new PlatformData;
}


Sampler::~Sampler() {
  ASSERT(!IsActive());
  delete data_;
}

591

592 593 594
void Sampler::Start() {
  ASSERT(!IsActive());
  SetActive(true);
595
  SamplerThread::AddActiveSampler(this);
596 597 598 599 600
}


void Sampler::Stop() {
  ASSERT(IsActive());
601
  SamplerThread::RemoveActiveSampler(this);
602 603 604
  SetActive(false);
}

605

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
void Sampler::IncreaseProfilingDepth() {
  NoBarrier_AtomicIncrement(&profiling_, 1);
#if defined(USE_SIGNALS)
  SignalHandler::IncreaseSamplerCount();
#endif
}


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


622
void Sampler::SampleStack(const RegisterState& state) {
623
  TickSample* sample = isolate_->cpu_profiler()->StartTickSample();
624 625 626
  TickSample sample_obj;
  if (sample == NULL) sample = &sample_obj;
  sample->Init(isolate_, state);
627 628 629 630 631
  if (is_counting_samples_) {
    if (sample->state == JS || sample->state == EXTERNAL) {
      ++js_and_external_sample_count_;
    }
  }
632
  Tick(sample);
633 634 635
  if (sample != &sample_obj) {
    isolate_->cpu_profiler()->FinishTickSample();
  }
636 637
}

638 639

#if defined(USE_SIGNALS)
640 641 642 643 644 645

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

646
#elif V8_OS_WIN || V8_OS_CYGWIN
647 648 649 650 651 652 653 654

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

#if defined(USE_SIMULATOR)
  SimulatorHelper helper;
  if (!helper.Init(this, isolate())) return;
655
#endif
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681

  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) {
    RegisterState state;
#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);
682 683
}

684 685 686
#endif  // USE_SIGNALS


687
} }  // namespace v8::internal