1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/libsampler/sampler.h"
6
7 #if V8_OS_POSIX && !V8_OS_CYGWIN
8
9 #define USE_SIGNALS
10
11 #include <errno.h>
12 #include <pthread.h>
13 #include <signal.h>
14 #include <sys/time.h>
15
16 #if !V8_OS_QNX && !V8_OS_AIX
17 #include <sys/syscall.h> // NOLINT
18 #endif
19
20 #if V8_OS_MACOSX
21 #include <mach/mach.h>
22 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
23 // and is a typedef for struct sigcontext. There is no uc_mcontext.
24 #elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && !V8_OS_OPENBSD
25 #include <ucontext.h>
26 #endif
27
28 #include <unistd.h>
29
30 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
31 // Old versions of the C library <signal.h> didn't define the type.
32 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \
33 (defined(__arm__) || defined(__aarch64__)) && \
34 !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT)
35 #include <asm/sigcontext.h> // NOLINT
36 #endif
37
38 #elif V8_OS_WIN || V8_OS_CYGWIN
39
40 #include "src/base/win32-headers.h"
41
42 #endif
43
44 #include <algorithm>
45 #include <vector>
46 #include <map>
47
48 #include "src/base/atomic-utils.h"
49 #include "src/base/hashmap.h"
50 #include "src/base/platform/platform.h"
51
52 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
53
54 // Not all versions of Android's C library provide ucontext_t.
55 // Detect this and provide custom but compatible definitions. Note that these
56 // follow the GLibc naming convention to access register values from
57 // mcontext_t.
58 //
59 // See http://code.google.com/p/android/issues/detail?id=34784
60
61 #if defined(__arm__)
62
63 typedef struct sigcontext mcontext_t;
64
65 typedef struct ucontext {
66 uint32_t uc_flags;
67 struct ucontext* uc_link;
68 stack_t uc_stack;
69 mcontext_t uc_mcontext;
70 // Other fields are not used by V8, don't define them here.
71 } ucontext_t;
72
73 #elif defined(__aarch64__)
74
75 typedef struct sigcontext mcontext_t;
76
77 typedef struct ucontext {
78 uint64_t uc_flags;
79 struct ucontext *uc_link;
80 stack_t uc_stack;
81 mcontext_t uc_mcontext;
82 // Other fields are not used by V8, don't define them here.
83 } ucontext_t;
84
85 #elif defined(__mips__)
86 // MIPS version of sigcontext, for Android bionic.
87 typedef struct {
88 uint32_t regmask;
89 uint32_t status;
90 uint64_t pc;
91 uint64_t gregs[32];
92 uint64_t fpregs[32];
93 uint32_t acx;
94 uint32_t fpc_csr;
95 uint32_t fpc_eir;
96 uint32_t used_math;
97 uint32_t dsp;
98 uint64_t mdhi;
99 uint64_t mdlo;
100 uint32_t hi1;
101 uint32_t lo1;
102 uint32_t hi2;
103 uint32_t lo2;
104 uint32_t hi3;
105 uint32_t lo3;
106 } mcontext_t;
107
108 typedef struct ucontext {
109 uint32_t uc_flags;
110 struct ucontext* uc_link;
111 stack_t uc_stack;
112 mcontext_t uc_mcontext;
113 // Other fields are not used by V8, don't define them here.
114 } ucontext_t;
115
116 #elif defined(__i386__)
117 // x86 version for Android.
118 typedef struct {
119 uint32_t gregs[19];
120 void* fpregs;
121 uint32_t oldmask;
122 uint32_t cr2;
123 } mcontext_t;
124
125 typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks
126 typedef struct ucontext {
127 uint32_t uc_flags;
128 struct ucontext* uc_link;
129 stack_t uc_stack;
130 mcontext_t uc_mcontext;
131 // Other fields are not used by V8, don't define them here.
132 } ucontext_t;
133 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 };
134
135 #elif defined(__x86_64__)
136 // x64 version for Android.
137 typedef struct {
138 uint64_t gregs[23];
139 void* fpregs;
140 uint64_t __reserved1[8];
141 } mcontext_t;
142
143 typedef struct ucontext {
144 uint64_t uc_flags;
145 struct ucontext *uc_link;
146 stack_t uc_stack;
147 mcontext_t uc_mcontext;
148 // Other fields are not used by V8, don't define them here.
149 } ucontext_t;
150 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 };
151 #endif
152
153 #endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T)
154
155
156 namespace v8 {
157 namespace sampler {
158
159 namespace {
160
161 #if defined(USE_SIGNALS)
162 typedef std::vector<Sampler*> SamplerList;
163 typedef SamplerList::iterator SamplerListIterator;
164 typedef base::AtomicValue<bool> AtomicMutex;
165
166 class AtomicGuard {
167 public:
AtomicGuard(AtomicMutex * atomic,bool is_blocking=true)168 explicit AtomicGuard(AtomicMutex* atomic, bool is_blocking = true)
169 : atomic_(atomic), is_success_(false) {
170 do {
171 // Use Acquire_Load to gain mutual exclusion.
172 USE(atomic_->Value());
173 is_success_ = atomic_->TrySetValue(false, true);
174 } while (is_blocking && !is_success_);
175 }
176
is_success() const177 bool is_success() const { return is_success_; }
178
~AtomicGuard()179 ~AtomicGuard() {
180 if (!is_success_) return;
181 atomic_->SetValue(false);
182 }
183
184 private:
185 AtomicMutex* const atomic_;
186 bool is_success_;
187 };
188
189 // Returns key for hash map.
ThreadKey(pthread_t thread_id)190 void* ThreadKey(pthread_t thread_id) {
191 return reinterpret_cast<void*>(thread_id);
192 }
193
194 // Returns hash value for hash map.
ThreadHash(pthread_t thread_id)195 uint32_t ThreadHash(pthread_t thread_id) {
196 #if V8_OS_BSD
197 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(thread_id));
198 #else
199 return static_cast<uint32_t>(thread_id);
200 #endif
201 }
202
203 #endif // USE_SIGNALS
204
205 } // namespace
206
207 #if defined(USE_SIGNALS)
208
209 class Sampler::PlatformData {
210 public:
PlatformData()211 PlatformData() : vm_tid_(pthread_self()) {}
vm_tid() const212 pthread_t vm_tid() const { return vm_tid_; }
213
214 private:
215 pthread_t vm_tid_;
216 };
217
218 class SamplerManager {
219 public:
SamplerManager()220 SamplerManager() : sampler_map_() {}
221
AddSampler(Sampler * sampler)222 void AddSampler(Sampler* sampler) {
223 AtomicGuard atomic_guard(&samplers_access_counter_);
224 DCHECK(sampler->IsActive() || !sampler->IsRegistered());
225 // Add sampler into map if needed.
226 pthread_t thread_id = sampler->platform_data()->vm_tid();
227 base::HashMap::Entry* entry =
228 sampler_map_.LookupOrInsert(ThreadKey(thread_id),
229 ThreadHash(thread_id));
230 DCHECK(entry != nullptr);
231 if (entry->value == nullptr) {
232 SamplerList* samplers = new SamplerList();
233 samplers->push_back(sampler);
234 entry->value = samplers;
235 } else {
236 SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
237 bool exists = false;
238 for (SamplerListIterator iter = samplers->begin();
239 iter != samplers->end(); ++iter) {
240 if (*iter == sampler) {
241 exists = true;
242 break;
243 }
244 }
245 if (!exists) {
246 samplers->push_back(sampler);
247 }
248 }
249 }
250
RemoveSampler(Sampler * sampler)251 void RemoveSampler(Sampler* sampler) {
252 AtomicGuard atomic_guard(&samplers_access_counter_);
253 DCHECK(sampler->IsActive() || sampler->IsRegistered());
254 // Remove sampler from map.
255 pthread_t thread_id = sampler->platform_data()->vm_tid();
256 void* thread_key = ThreadKey(thread_id);
257 uint32_t thread_hash = ThreadHash(thread_id);
258 base::HashMap::Entry* entry = sampler_map_.Lookup(thread_key, thread_hash);
259 DCHECK(entry != nullptr);
260 SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
261 for (SamplerListIterator iter = samplers->begin(); iter != samplers->end();
262 ++iter) {
263 if (*iter == sampler) {
264 samplers->erase(iter);
265 break;
266 }
267 }
268 if (samplers->empty()) {
269 sampler_map_.Remove(thread_key, thread_hash);
270 delete samplers;
271 }
272 }
273
274 #if defined(USE_SIGNALS)
DoSample(const v8::RegisterState & state)275 void DoSample(const v8::RegisterState& state) {
276 AtomicGuard atomic_guard(&SamplerManager::samplers_access_counter_, false);
277 if (!atomic_guard.is_success()) return;
278 pthread_t thread_id = pthread_self();
279 base::HashMap::Entry* entry =
280 sampler_map_.Lookup(ThreadKey(thread_id), ThreadHash(thread_id));
281 if (!entry) return;
282 SamplerList& samplers = *static_cast<SamplerList*>(entry->value);
283
284 for (size_t i = 0; i < samplers.size(); ++i) {
285 Sampler* sampler = samplers[i];
286 Isolate* isolate = sampler->isolate();
287 // We require a fully initialized and entered isolate.
288 if (isolate == nullptr || !isolate->IsInUse()) continue;
289 if (v8::Locker::IsActive() && !Locker::IsLocked(isolate)) continue;
290 sampler->SampleStack(state);
291 }
292 }
293 #endif
294
instance()295 static SamplerManager* instance() { return instance_.Pointer(); }
296
297 private:
298 base::HashMap sampler_map_;
299 static AtomicMutex samplers_access_counter_;
300 static base::LazyInstance<SamplerManager>::type instance_;
301 };
302
303 AtomicMutex SamplerManager::samplers_access_counter_;
304 base::LazyInstance<SamplerManager>::type SamplerManager::instance_ =
305 LAZY_INSTANCE_INITIALIZER;
306
307 #elif V8_OS_WIN || V8_OS_CYGWIN
308
309 // ----------------------------------------------------------------------------
310 // Win32 profiler support. On Cygwin we use the same sampler implementation as
311 // on Win32.
312
313 class Sampler::PlatformData {
314 public:
315 // Get a handle to the calling thread. This is the thread that we are
316 // going to profile. We need to make a copy of the handle because we are
317 // going to use it in the sampler thread. Using GetThreadHandle() will
318 // not work in this case. We're using OpenThread because DuplicateHandle
319 // for some reason doesn't work in Chrome's sandbox.
PlatformData()320 PlatformData()
321 : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
322 THREAD_SUSPEND_RESUME |
323 THREAD_QUERY_INFORMATION,
324 false,
325 GetCurrentThreadId())) {}
326
~PlatformData()327 ~PlatformData() {
328 if (profiled_thread_ != nullptr) {
329 CloseHandle(profiled_thread_);
330 profiled_thread_ = nullptr;
331 }
332 }
333
profiled_thread()334 HANDLE profiled_thread() { return profiled_thread_; }
335
336 private:
337 HANDLE profiled_thread_;
338 };
339 #endif // USE_SIGNALS
340
341
342 #if defined(USE_SIGNALS)
343 class SignalHandler {
344 public:
SetUp()345 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
TearDown()346 static void TearDown() {
347 delete mutex_;
348 mutex_ = nullptr;
349 }
350
IncreaseSamplerCount()351 static void IncreaseSamplerCount() {
352 base::LockGuard<base::Mutex> lock_guard(mutex_);
353 if (++client_count_ == 1) Install();
354 }
355
DecreaseSamplerCount()356 static void DecreaseSamplerCount() {
357 base::LockGuard<base::Mutex> lock_guard(mutex_);
358 if (--client_count_ == 0) Restore();
359 }
360
Installed()361 static bool Installed() {
362 base::LockGuard<base::Mutex> lock_guard(mutex_);
363 return signal_handler_installed_;
364 }
365
366 private:
Install()367 static void Install() {
368 struct sigaction sa;
369 sa.sa_sigaction = &HandleProfilerSignal;
370 sigemptyset(&sa.sa_mask);
371 #if V8_OS_QNX
372 sa.sa_flags = SA_SIGINFO;
373 #else
374 sa.sa_flags = SA_RESTART | SA_SIGINFO;
375 #endif
376 signal_handler_installed_ =
377 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
378 }
379
Restore()380 static void Restore() {
381 if (signal_handler_installed_) {
382 sigaction(SIGPROF, &old_signal_handler_, 0);
383 signal_handler_installed_ = false;
384 }
385 }
386
387 static void FillRegisterState(void* context, RegisterState* regs);
388 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context);
389
390 // Protects the process wide state below.
391 static base::Mutex* mutex_;
392 static int client_count_;
393 static bool signal_handler_installed_;
394 static struct sigaction old_signal_handler_;
395 };
396
397 base::Mutex* SignalHandler::mutex_ = nullptr;
398 int SignalHandler::client_count_ = 0;
399 struct sigaction SignalHandler::old_signal_handler_;
400 bool SignalHandler::signal_handler_installed_ = false;
401
402
HandleProfilerSignal(int signal,siginfo_t * info,void * context)403 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
404 void* context) {
405 USE(info);
406 if (signal != SIGPROF) return;
407 v8::RegisterState state;
408 FillRegisterState(context, &state);
409 SamplerManager::instance()->DoSample(state);
410 }
411
FillRegisterState(void * context,RegisterState * state)412 void SignalHandler::FillRegisterState(void* context, RegisterState* state) {
413 // Extracting the sample from the context is extremely machine dependent.
414 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
415 #if !(V8_OS_OPENBSD || (V8_OS_LINUX && (V8_HOST_ARCH_PPC || V8_HOST_ARCH_S390)))
416 mcontext_t& mcontext = ucontext->uc_mcontext;
417 #endif
418 #if V8_OS_LINUX
419 #if V8_HOST_ARCH_IA32
420 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]);
421 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]);
422 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]);
423 #elif V8_HOST_ARCH_X64
424 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
425 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
426 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
427 #elif V8_HOST_ARCH_ARM
428 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
429 // Old GLibc ARM versions used a gregs[] array to access the register
430 // values from mcontext_t.
431 state->pc = reinterpret_cast<void*>(mcontext.gregs[R15]);
432 state->sp = reinterpret_cast<void*>(mcontext.gregs[R13]);
433 state->fp = reinterpret_cast<void*>(mcontext.gregs[R11]);
434 #else
435 state->pc = reinterpret_cast<void*>(mcontext.arm_pc);
436 state->sp = reinterpret_cast<void*>(mcontext.arm_sp);
437 state->fp = reinterpret_cast<void*>(mcontext.arm_fp);
438 #endif // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
439 #elif V8_HOST_ARCH_ARM64
440 state->pc = reinterpret_cast<void*>(mcontext.pc);
441 state->sp = reinterpret_cast<void*>(mcontext.sp);
442 // FP is an alias for x29.
443 state->fp = reinterpret_cast<void*>(mcontext.regs[29]);
444 #elif V8_HOST_ARCH_MIPS
445 state->pc = reinterpret_cast<void*>(mcontext.pc);
446 state->sp = reinterpret_cast<void*>(mcontext.gregs[29]);
447 state->fp = reinterpret_cast<void*>(mcontext.gregs[30]);
448 #elif V8_HOST_ARCH_MIPS64
449 state->pc = reinterpret_cast<void*>(mcontext.pc);
450 state->sp = reinterpret_cast<void*>(mcontext.gregs[29]);
451 state->fp = reinterpret_cast<void*>(mcontext.gregs[30]);
452 #elif V8_HOST_ARCH_PPC
453 state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.regs->nip);
454 state->sp =
455 reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R1]);
456 state->fp =
457 reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R31]);
458 #elif V8_HOST_ARCH_S390
459 #if V8_TARGET_ARCH_32_BIT
460 // 31-bit target will have bit 0 (MSB) of the PSW set to denote addressing
461 // mode. This bit needs to be masked out to resolve actual address.
462 state->pc =
463 reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr & 0x7FFFFFFF);
464 #else
465 state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr);
466 #endif // V8_TARGET_ARCH_32_BIT
467 state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[15]);
468 state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[11]);
469 #endif // V8_HOST_ARCH_*
470 #elif V8_OS_MACOSX
471 #if V8_HOST_ARCH_X64
472 #if __DARWIN_UNIX03
473 state->pc = reinterpret_cast<void*>(mcontext->__ss.__rip);
474 state->sp = reinterpret_cast<void*>(mcontext->__ss.__rsp);
475 state->fp = reinterpret_cast<void*>(mcontext->__ss.__rbp);
476 #else // !__DARWIN_UNIX03
477 state->pc = reinterpret_cast<void*>(mcontext->ss.rip);
478 state->sp = reinterpret_cast<void*>(mcontext->ss.rsp);
479 state->fp = reinterpret_cast<void*>(mcontext->ss.rbp);
480 #endif // __DARWIN_UNIX03
481 #elif V8_HOST_ARCH_IA32
482 #if __DARWIN_UNIX03
483 state->pc = reinterpret_cast<void*>(mcontext->__ss.__eip);
484 state->sp = reinterpret_cast<void*>(mcontext->__ss.__esp);
485 state->fp = reinterpret_cast<void*>(mcontext->__ss.__ebp);
486 #else // !__DARWIN_UNIX03
487 state->pc = reinterpret_cast<void*>(mcontext->ss.eip);
488 state->sp = reinterpret_cast<void*>(mcontext->ss.esp);
489 state->fp = reinterpret_cast<void*>(mcontext->ss.ebp);
490 #endif // __DARWIN_UNIX03
491 #endif // V8_HOST_ARCH_IA32
492 #elif V8_OS_FREEBSD
493 #if V8_HOST_ARCH_IA32
494 state->pc = reinterpret_cast<void*>(mcontext.mc_eip);
495 state->sp = reinterpret_cast<void*>(mcontext.mc_esp);
496 state->fp = reinterpret_cast<void*>(mcontext.mc_ebp);
497 #elif V8_HOST_ARCH_X64
498 state->pc = reinterpret_cast<void*>(mcontext.mc_rip);
499 state->sp = reinterpret_cast<void*>(mcontext.mc_rsp);
500 state->fp = reinterpret_cast<void*>(mcontext.mc_rbp);
501 #elif V8_HOST_ARCH_ARM
502 state->pc = reinterpret_cast<void*>(mcontext.mc_r15);
503 state->sp = reinterpret_cast<void*>(mcontext.mc_r13);
504 state->fp = reinterpret_cast<void*>(mcontext.mc_r11);
505 #endif // V8_HOST_ARCH_*
506 #elif V8_OS_NETBSD
507 #if V8_HOST_ARCH_IA32
508 state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]);
509 state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]);
510 state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]);
511 #elif V8_HOST_ARCH_X64
512 state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]);
513 state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]);
514 state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]);
515 #endif // V8_HOST_ARCH_*
516 #elif V8_OS_OPENBSD
517 #if V8_HOST_ARCH_IA32
518 state->pc = reinterpret_cast<void*>(ucontext->sc_eip);
519 state->sp = reinterpret_cast<void*>(ucontext->sc_esp);
520 state->fp = reinterpret_cast<void*>(ucontext->sc_ebp);
521 #elif V8_HOST_ARCH_X64
522 state->pc = reinterpret_cast<void*>(ucontext->sc_rip);
523 state->sp = reinterpret_cast<void*>(ucontext->sc_rsp);
524 state->fp = reinterpret_cast<void*>(ucontext->sc_rbp);
525 #endif // V8_HOST_ARCH_*
526 #elif V8_OS_SOLARIS
527 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]);
528 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]);
529 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]);
530 #elif V8_OS_QNX
531 #if V8_HOST_ARCH_IA32
532 state->pc = reinterpret_cast<void*>(mcontext.cpu.eip);
533 state->sp = reinterpret_cast<void*>(mcontext.cpu.esp);
534 state->fp = reinterpret_cast<void*>(mcontext.cpu.ebp);
535 #elif V8_HOST_ARCH_ARM
536 state->pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]);
537 state->sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]);
538 state->fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]);
539 #endif // V8_HOST_ARCH_*
540 #elif V8_OS_AIX
541 state->pc = reinterpret_cast<void*>(mcontext.jmp_context.iar);
542 state->sp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[1]);
543 state->fp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[31]);
544 #endif // V8_OS_AIX
545 }
546
547 #endif // USE_SIGNALS
548
549
SetUp()550 void Sampler::SetUp() {
551 #if defined(USE_SIGNALS)
552 SignalHandler::SetUp();
553 #endif
554 }
555
556
TearDown()557 void Sampler::TearDown() {
558 #if defined(USE_SIGNALS)
559 SignalHandler::TearDown();
560 #endif
561 }
562
Sampler(Isolate * isolate)563 Sampler::Sampler(Isolate* isolate)
564 : is_counting_samples_(false),
565 js_sample_count_(0),
566 external_sample_count_(0),
567 isolate_(isolate),
568 profiling_(false),
569 has_processing_thread_(false),
570 active_(false),
571 registered_(false) {
572 data_ = new PlatformData;
573 }
574
~Sampler()575 Sampler::~Sampler() {
576 DCHECK(!IsActive());
577 #if defined(USE_SIGNALS)
578 if (IsRegistered()) {
579 SamplerManager::instance()->RemoveSampler(this);
580 }
581 #endif
582 delete data_;
583 }
584
Start()585 void Sampler::Start() {
586 DCHECK(!IsActive());
587 SetActive(true);
588 #if defined(USE_SIGNALS)
589 SamplerManager::instance()->AddSampler(this);
590 #endif
591 }
592
593
Stop()594 void Sampler::Stop() {
595 #if defined(USE_SIGNALS)
596 SamplerManager::instance()->RemoveSampler(this);
597 #endif
598 DCHECK(IsActive());
599 SetActive(false);
600 SetRegistered(false);
601 }
602
603
IncreaseProfilingDepth()604 void Sampler::IncreaseProfilingDepth() {
605 base::NoBarrier_AtomicIncrement(&profiling_, 1);
606 #if defined(USE_SIGNALS)
607 SignalHandler::IncreaseSamplerCount();
608 #endif
609 }
610
611
DecreaseProfilingDepth()612 void Sampler::DecreaseProfilingDepth() {
613 #if defined(USE_SIGNALS)
614 SignalHandler::DecreaseSamplerCount();
615 #endif
616 base::NoBarrier_AtomicIncrement(&profiling_, -1);
617 }
618
619
620 #if defined(USE_SIGNALS)
621
DoSample()622 void Sampler::DoSample() {
623 if (!SignalHandler::Installed()) return;
624 if (!IsActive() && !IsRegistered()) {
625 SamplerManager::instance()->AddSampler(this);
626 SetRegistered(true);
627 }
628 pthread_kill(platform_data()->vm_tid(), SIGPROF);
629 }
630
631 #elif V8_OS_WIN || V8_OS_CYGWIN
632
DoSample()633 void Sampler::DoSample() {
634 HANDLE profiled_thread = platform_data()->profiled_thread();
635 if (profiled_thread == nullptr) return;
636
637 const DWORD kSuspendFailed = static_cast<DWORD>(-1);
638 if (SuspendThread(profiled_thread) == kSuspendFailed) return;
639
640 // Context used for sampling the register state of the profiled thread.
641 CONTEXT context;
642 memset(&context, 0, sizeof(context));
643 context.ContextFlags = CONTEXT_FULL;
644 if (GetThreadContext(profiled_thread, &context) != 0) {
645 v8::RegisterState state;
646 #if V8_HOST_ARCH_X64
647 state.pc = reinterpret_cast<void*>(context.Rip);
648 state.sp = reinterpret_cast<void*>(context.Rsp);
649 state.fp = reinterpret_cast<void*>(context.Rbp);
650 #else
651 state.pc = reinterpret_cast<void*>(context.Eip);
652 state.sp = reinterpret_cast<void*>(context.Esp);
653 state.fp = reinterpret_cast<void*>(context.Ebp);
654 #endif
655 SampleStack(state);
656 }
657 ResumeThread(profiled_thread);
658 }
659
660 #endif // USE_SIGNALS
661
662 } // namespace sampler
663 } // namespace v8
664