The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / sampler.cc @ f230a1cf

History | View | Annotate | Download (20.1 KB)

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

    
28
#include "sampler.h"
29

    
30
#if V8_OS_POSIX && !V8_OS_CYGWIN
31

    
32
#define USE_SIGNALS
33

    
34
#include <errno.h>
35
#include <pthread.h>
36
#include <signal.h>
37
#include <sys/time.h>
38
#include <sys/syscall.h>
39

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

    
50
// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
51
// 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
#include <asm/sigcontext.h>
55
#endif
56

    
57
#elif V8_OS_WIN || V8_OS_CYGWIN
58

    
59
#include "win32-headers.h"
60

    
61
#endif
62

    
63
#include "v8.h"
64

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

    
74

    
75
#if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
76

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

    
84
#if defined(__arm__)
85

    
86
typedef struct sigcontext mcontext_t;
87

    
88
typedef struct ucontext {
89
  uint32_t uc_flags;
90
  struct ucontext* uc_link;
91
  stack_t uc_stack;
92
  mcontext_t uc_mcontext;
93
  // Other fields are not used by V8, don't define them here.
94
} ucontext_t;
95

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

    
119
typedef struct ucontext {
120
  uint32_t uc_flags;
121
  struct ucontext* uc_link;
122
  stack_t uc_stack;
123
  mcontext_t uc_mcontext;
124
  // Other fields are not used by V8, don't define them here.
125
} ucontext_t;
126

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

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

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

    
149

    
150
namespace v8 {
151
namespace internal {
152

    
153
namespace {
154

    
155
class PlatformDataCommon : public Malloced {
156
 public:
157
  PlatformDataCommon() : profiled_thread_id_(ThreadId::Current()) {}
158
  ThreadId profiled_thread_id() { return profiled_thread_id_; }
159

    
160
 protected:
161
  ~PlatformDataCommon() {}
162

    
163
 private:
164
  ThreadId profiled_thread_id_;
165
};
166

    
167
}  // namespace
168

    
169
#if defined(USE_SIGNALS)
170

    
171
class Sampler::PlatformData : public PlatformDataCommon {
172
 public:
173
  PlatformData() : vm_tid_(pthread_self()) {}
174
  pthread_t vm_tid() const { return vm_tid_; }
175

    
176
 private:
177
  pthread_t vm_tid_;
178
};
179

    
180
#elif V8_OS_WIN || V8_OS_CYGWIN
181

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

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

    
200
  ~PlatformData() {
201
    if (profiled_thread_ != NULL) {
202
      CloseHandle(profiled_thread_);
203
      profiled_thread_ = NULL;
204
    }
205
  }
206

    
207
  HANDLE profiled_thread() { return profiled_thread_; }
208

    
209
 private:
210
  HANDLE profiled_thread_;
211
};
212
#endif
213

    
214

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

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

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

    
242

    
243
#if defined(USE_SIGNALS)
244

    
245
class SignalHandler : public AllStatic {
246
 public:
247
  static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
248
  static void TearDown() { delete mutex_; }
249

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

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

    
260
  static bool Installed() {
261
    return signal_handler_installed_;
262
  }
263

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

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

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

    
289

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

    
295

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

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

    
318
  RegisterState state;
319

    
320
#if defined(USE_SIMULATOR)
321
  SimulatorHelper helper;
322
  if (!helper.Init(sampler, isolate)) return;
323
  helper.FillRegisters(&state);
324
#else
325
  // Extracting the sample from the context is extremely machine dependent.
326
  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
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
333
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
334
  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
335
#elif V8_HOST_ARCH_X64
336
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
337
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
338
  state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
339
#elif V8_HOST_ARCH_ARM
340
#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
341
    (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
342
  // Old GLibc ARM versions used a gregs[] array to access the register
343
  // values from mcontext_t.
344
  state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
345
  state.sp = reinterpret_cast<Address>(mcontext.gregs[R13]);
346
  state.fp = reinterpret_cast<Address>(mcontext.gregs[R11]);
347
#else
348
  state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
349
  state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
350
  state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
351
#endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
352
        // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
353
#elif V8_HOST_ARCH_MIPS
354
  state.pc = reinterpret_cast<Address>(mcontext.pc);
355
  state.sp = reinterpret_cast<Address>(mcontext.gregs[29]);
356
  state.fp = reinterpret_cast<Address>(mcontext.gregs[30]);
357
#endif  // V8_HOST_ARCH_*
358
#elif V8_OS_MACOSX
359
#if V8_HOST_ARCH_X64
360
#if __DARWIN_UNIX03
361
  state.pc = reinterpret_cast<Address>(mcontext->__ss.__rip);
362
  state.sp = reinterpret_cast<Address>(mcontext->__ss.__rsp);
363
  state.fp = reinterpret_cast<Address>(mcontext->__ss.__rbp);
364
#else  // !__DARWIN_UNIX03
365
  state.pc = reinterpret_cast<Address>(mcontext->ss.rip);
366
  state.sp = reinterpret_cast<Address>(mcontext->ss.rsp);
367
  state.fp = reinterpret_cast<Address>(mcontext->ss.rbp);
368
#endif  // __DARWIN_UNIX03
369
#elif V8_HOST_ARCH_IA32
370
#if __DARWIN_UNIX03
371
  state.pc = reinterpret_cast<Address>(mcontext->__ss.__eip);
372
  state.sp = reinterpret_cast<Address>(mcontext->__ss.__esp);
373
  state.fp = reinterpret_cast<Address>(mcontext->__ss.__ebp);
374
#else  // !__DARWIN_UNIX03
375
  state.pc = reinterpret_cast<Address>(mcontext->ss.eip);
376
  state.sp = reinterpret_cast<Address>(mcontext->ss.esp);
377
  state.fp = reinterpret_cast<Address>(mcontext->ss.ebp);
378
#endif  // __DARWIN_UNIX03
379
#endif  // V8_HOST_ARCH_IA32
380
#elif V8_OS_FREEBSD
381
#if V8_HOST_ARCH_IA32
382
  state.pc = reinterpret_cast<Address>(mcontext.mc_eip);
383
  state.sp = reinterpret_cast<Address>(mcontext.mc_esp);
384
  state.fp = reinterpret_cast<Address>(mcontext.mc_ebp);
385
#elif V8_HOST_ARCH_X64
386
  state.pc = reinterpret_cast<Address>(mcontext.mc_rip);
387
  state.sp = reinterpret_cast<Address>(mcontext.mc_rsp);
388
  state.fp = reinterpret_cast<Address>(mcontext.mc_rbp);
389
#elif V8_HOST_ARCH_ARM
390
  state.pc = reinterpret_cast<Address>(mcontext.mc_r15);
391
  state.sp = reinterpret_cast<Address>(mcontext.mc_r13);
392
  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
  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_EIP]);
397
  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_ESP]);
398
  state.fp = reinterpret_cast<Address>(mcontext.__gregs[_REG_EBP]);
399
#elif V8_HOST_ARCH_X64
400
  state.pc = reinterpret_cast<Address>(mcontext.__gregs[_REG_RIP]);
401
  state.sp = reinterpret_cast<Address>(mcontext.__gregs[_REG_RSP]);
402
  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
  state.pc = reinterpret_cast<Address>(ucontext->sc_eip);
407
  state.sp = reinterpret_cast<Address>(ucontext->sc_esp);
408
  state.fp = reinterpret_cast<Address>(ucontext->sc_ebp);
409
#elif V8_HOST_ARCH_X64
410
  state.pc = reinterpret_cast<Address>(ucontext->sc_rip);
411
  state.sp = reinterpret_cast<Address>(ucontext->sc_rsp);
412
  state.fp = reinterpret_cast<Address>(ucontext->sc_rbp);
413
#endif  // V8_HOST_ARCH_*
414
#elif V8_OS_SOLARIS
415
  state.pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
416
  state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
417
  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
#endif
425

    
426

    
427
class SamplerThread : public Thread {
428
 public:
429
  static const int kSamplerThreadStackSize = 64 * KB;
430

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

    
435
  static void SetUp() { if (!mutex_) mutex_ = new Mutex(); }
436
  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
    if (instance_ == NULL) {
442
      // Start a thread that will send SIGPROF signal to VM threads,
443
      // when CPU profiling will be enabled.
444
      instance_ = new SamplerThread(sampler->interval());
445
      need_to_start = true;
446
    }
447

    
448
    ASSERT(sampler->IsActive());
449
    ASSERT(!instance_->active_samplers_.Contains(sampler));
450
    ASSERT(instance_->interval_ == sampler->interval());
451
    instance_->active_samplers_.Add(sampler);
452

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

    
456
  static void RemoveActiveSampler(Sampler* sampler) {
457
    SamplerThread* instance_to_remove = NULL;
458
    {
459
      LockGuard<Mutex> lock_guard(mutex_);
460

    
461
      ASSERT(sampler->IsActive());
462
      bool removed = instance_->active_samplers_.RemoveElement(sampler);
463
      ASSERT(removed);
464
      USE(removed);
465

    
466
      // We cannot delete the instance immediately as we need to Join() the
467
      // thread but we are holding mutex_ and the thread may try to acquire it.
468
      if (instance_->active_samplers_.is_empty()) {
469
        instance_to_remove = instance_;
470
        instance_ = NULL;
471
      }
472
    }
473

    
474
    if (!instance_to_remove) return;
475
    instance_to_remove->Join();
476
    delete instance_to_remove;
477
  }
478

    
479
  // Implement Thread::Run().
480
  virtual void Run() {
481
    while (true) {
482
      {
483
        LockGuard<Mutex> lock_guard(mutex_);
484
        if (active_samplers_.is_empty()) break;
485
        // When CPU profiling is enabled both JavaScript and C++ code is
486
        // profiled. We must not suspend.
487
        for (int i = 0; i < active_samplers_.length(); ++i) {
488
          Sampler* sampler = active_samplers_.at(i);
489
          if (!sampler->isolate()->IsInitialized()) continue;
490
          if (!sampler->IsProfiling()) continue;
491
          sampler->DoSample();
492
        }
493
      }
494
      OS::Sleep(interval_);
495
    }
496
  }
497

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

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

    
506
  DISALLOW_COPY_AND_ASSIGN(SamplerThread);
507
};
508

    
509

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

    
513

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

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

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

    
532
  ExternalCallbackScope* scope = isolate->external_callback_scope();
533
  Address handler = Isolate::handler(isolate->thread_local_top());
534
  // If there is a handler on top of the external callback scope then
535
  // we have already entrered JavaScript again and the external callback
536
  // is not the top function.
537
  if (scope && scope->scope_address() < handler) {
538
    external_callback = scope->callback();
539
    has_external_callback = true;
540
  } else {
541
    // Sample potential return address value for frameless invocation of
542
    // stubs (we'll figure out later, if this value makes sense).
543
    tos = Memory::Address_at(regs.sp);
544
    has_external_callback = false;
545
  }
546

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

    
557

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

    
565

    
566
void Sampler::TearDown() {
567
  SamplerThread::TearDown();
568
#if defined(USE_SIGNALS)
569
  SignalHandler::TearDown();
570
#endif
571
}
572

    
573

    
574
Sampler::Sampler(Isolate* isolate, int interval)
575
    : isolate_(isolate),
576
      interval_(interval),
577
      profiling_(false),
578
      has_processing_thread_(false),
579
      active_(false),
580
      is_counting_samples_(false),
581
      js_and_external_sample_count_(0) {
582
  data_ = new PlatformData;
583
}
584

    
585

    
586
Sampler::~Sampler() {
587
  ASSERT(!IsActive());
588
  delete data_;
589
}
590

    
591

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

    
598

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

    
605

    
606
void Sampler::IncreaseProfilingDepth() {
607
  NoBarrier_AtomicIncrement(&profiling_, 1);
608
#if defined(USE_SIGNALS)
609
  SignalHandler::IncreaseSamplerCount();
610
#endif
611
}
612

    
613

    
614
void Sampler::DecreaseProfilingDepth() {
615
#if defined(USE_SIGNALS)
616
  SignalHandler::DecreaseSamplerCount();
617
#endif
618
  NoBarrier_AtomicIncrement(&profiling_, -1);
619
}
620

    
621

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

    
638

    
639
#if defined(USE_SIGNALS)
640

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

    
646
#elif V8_OS_WIN || V8_OS_CYGWIN
647

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

    
652
#if defined(USE_SIMULATOR)
653
  SimulatorHelper helper;
654
  if (!helper.Init(this, isolate())) return;
655
#endif
656

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

    
660
  // Context used for sampling the register state of the profiled thread.
661
  CONTEXT context;
662
  memset(&context, 0, sizeof(context));
663
  context.ContextFlags = CONTEXT_FULL;
664
  if (GetThreadContext(profiled_thread, &context) != 0) {
665
    RegisterState state;
666
#if defined(USE_SIMULATOR)
667
    helper.FillRegisters(&state);
668
#else
669
#if V8_HOST_ARCH_X64
670
    state.pc = reinterpret_cast<Address>(context.Rip);
671
    state.sp = reinterpret_cast<Address>(context.Rsp);
672
    state.fp = reinterpret_cast<Address>(context.Rbp);
673
#else
674
    state.pc = reinterpret_cast<Address>(context.Eip);
675
    state.sp = reinterpret_cast<Address>(context.Esp);
676
    state.fp = reinterpret_cast<Address>(context.Ebp);
677
#endif
678
#endif  // USE_SIMULATOR
679
    SampleStack(state);
680
  }
681
  ResumeThread(profiled_thread);
682
}
683

    
684
#endif  // USE_SIGNALS
685

    
686

    
687
} }  // namespace v8::internal