Line data Source code
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:
168 239433 : explicit AtomicGuard(AtomicMutex* atomic, bool is_blocking = true)
169 239433 : : atomic_(atomic), is_success_(false) {
170 239433 : do {
171 : // Use Acquire_Load to gain mutual exclusion.
172 239433 : USE(atomic_->Value());
173 478866 : is_success_ = atomic_->TrySetValue(false, true);
174 474 : } while (is_blocking && !is_success_);
175 239433 : }
176 :
177 : bool is_success() const { return is_success_; }
178 :
179 239433 : ~AtomicGuard() {
180 239433 : if (!is_success_) return;
181 239433 : atomic_->SetValue(false);
182 239433 : }
183 :
184 : private:
185 : AtomicMutex* const atomic_;
186 : bool is_success_;
187 : };
188 :
189 : // Returns key for hash map.
190 : void* ThreadKey(pthread_t thread_id) {
191 239433 : return reinterpret_cast<void*>(thread_id);
192 : }
193 :
194 : // Returns hash value for hash map.
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 239433 : 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:
211 61119 : PlatformData() : vm_tid_(pthread_self()) {}
212 252573 : pthread_t vm_tid() const { return vm_tid_; }
213 :
214 : private:
215 : pthread_t vm_tid_;
216 : };
217 :
218 : class SamplerManager {
219 : public:
220 : SamplerManager() : sampler_map_() {}
221 :
222 237 : void AddSampler(Sampler* sampler) {
223 237 : AtomicGuard atomic_guard(&samplers_access_counter_);
224 : DCHECK(sampler->IsActive() || !sampler->IsRegistered());
225 : // Add sampler into map if needed.
226 237 : pthread_t thread_id = sampler->platform_data()->vm_tid();
227 : base::HashMap::Entry* entry =
228 : sampler_map_.LookupOrInsert(ThreadKey(thread_id),
229 474 : ThreadHash(thread_id));
230 : DCHECK(entry != nullptr);
231 237 : if (entry->value == nullptr) {
232 237 : SamplerList* samplers = new SamplerList();
233 237 : samplers->push_back(sampler);
234 237 : entry->value = samplers;
235 : } else {
236 : SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
237 : bool exists = false;
238 0 : for (SamplerListIterator iter = samplers->begin();
239 : iter != samplers->end(); ++iter) {
240 0 : if (*iter == sampler) {
241 : exists = true;
242 : break;
243 : }
244 : }
245 0 : if (!exists) {
246 0 : samplers->push_back(sampler);
247 : }
248 237 : }
249 237 : }
250 :
251 474 : void RemoveSampler(Sampler* sampler) {
252 237 : 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 237 : void* thread_key = ThreadKey(thread_id);
257 : uint32_t thread_hash = ThreadHash(thread_id);
258 237 : base::HashMap::Entry* entry = sampler_map_.Lookup(thread_key, thread_hash);
259 : DCHECK(entry != nullptr);
260 237 : SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
261 474 : for (SamplerListIterator iter = samplers->begin(); iter != samplers->end();
262 : ++iter) {
263 237 : if (*iter == sampler) {
264 237 : samplers->erase(iter);
265 237 : break;
266 : }
267 : }
268 237 : if (samplers->empty()) {
269 237 : sampler_map_.Remove(thread_key, thread_hash);
270 474 : delete samplers;
271 237 : }
272 237 : }
273 :
274 : #if defined(USE_SIGNALS)
275 238959 : void DoSample(const v8::RegisterState& state) {
276 238959 : AtomicGuard atomic_guard(&SamplerManager::samplers_access_counter_, false);
277 238959 : if (!atomic_guard.is_success()) return;
278 238959 : pthread_t thread_id = pthread_self();
279 : base::HashMap::Entry* entry =
280 238959 : sampler_map_.Lookup(ThreadKey(thread_id), ThreadHash(thread_id));
281 238959 : if (!entry) return;
282 716877 : SamplerList& samplers = *static_cast<SamplerList*>(entry->value);
283 :
284 955836 : for (size_t i = 0; i < samplers.size(); ++i) {
285 238959 : Sampler* sampler = samplers[i];
286 : Isolate* isolate = sampler->isolate();
287 : // We require a fully initialized and entered isolate.
288 238959 : if (isolate == nullptr || !isolate->IsInUse()) continue;
289 238937 : if (v8::Locker::IsActive() && !Locker::IsLocked(isolate)) continue;
290 238937 : sampler->SampleStack(state);
291 238959 : }
292 : }
293 : #endif
294 :
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.
320 : PlatformData()
321 : : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
322 : THREAD_SUSPEND_RESUME |
323 : THREAD_QUERY_INFORMATION,
324 : false,
325 : GetCurrentThreadId())) {}
326 :
327 : ~PlatformData() {
328 : if (profiled_thread_ != nullptr) {
329 : CloseHandle(profiled_thread_);
330 : profiled_thread_ = nullptr;
331 : }
332 : }
333 :
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:
345 59468 : static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
346 32503 : static void TearDown() {
347 32503 : delete mutex_;
348 32503 : mutex_ = nullptr;
349 32503 : }
350 :
351 337 : static void IncreaseSamplerCount() {
352 337 : base::LockGuard<base::Mutex> lock_guard(mutex_);
353 337 : if (++client_count_ == 1) Install();
354 337 : }
355 :
356 337 : static void DecreaseSamplerCount() {
357 337 : base::LockGuard<base::Mutex> lock_guard(mutex_);
358 337 : if (--client_count_ == 0) Restore();
359 337 : }
360 :
361 252099 : static bool Installed() {
362 252099 : base::LockGuard<base::Mutex> lock_guard(mutex_);
363 504198 : return signal_handler_installed_;
364 : }
365 :
366 : private:
367 337 : static void Install() {
368 : struct sigaction sa;
369 337 : sa.sa_sigaction = &HandleProfilerSignal;
370 337 : sigemptyset(&sa.sa_mask);
371 : #if V8_OS_QNX
372 : sa.sa_flags = SA_SIGINFO;
373 : #else
374 337 : sa.sa_flags = SA_RESTART | SA_SIGINFO;
375 : #endif
376 : signal_handler_installed_ =
377 337 : (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
378 337 : }
379 :
380 337 : static void Restore() {
381 337 : if (signal_handler_installed_) {
382 337 : sigaction(SIGPROF, &old_signal_handler_, 0);
383 337 : signal_handler_installed_ = false;
384 : }
385 337 : }
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 :
403 238959 : void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
404 : void* context) {
405 : USE(info);
406 238959 : if (signal != SIGPROF) return;
407 : v8::RegisterState state;
408 : FillRegisterState(context, &state);
409 238959 : SamplerManager::instance()->DoSample(state);
410 : }
411 :
412 0 : 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 238959 : state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
425 238959 : state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
426 238959 : 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 0 : }
546 :
547 : #endif // USE_SIGNALS
548 :
549 :
550 59468 : void Sampler::SetUp() {
551 : #if defined(USE_SIGNALS)
552 59468 : SignalHandler::SetUp();
553 : #endif
554 59468 : }
555 :
556 :
557 32503 : void Sampler::TearDown() {
558 : #if defined(USE_SIGNALS)
559 32503 : SignalHandler::TearDown();
560 : #endif
561 32503 : }
562 :
563 61119 : 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 61119 : registered_(false) {
572 122238 : data_ = new PlatformData;
573 61119 : }
574 :
575 59622 : Sampler::~Sampler() {
576 : DCHECK(!IsActive());
577 : #if defined(USE_SIGNALS)
578 59622 : if (IsRegistered()) {
579 230 : SamplerManager::instance()->RemoveSampler(this);
580 : }
581 : #endif
582 59622 : delete data_;
583 59622 : }
584 :
585 7 : void Sampler::Start() {
586 : DCHECK(!IsActive());
587 : SetActive(true);
588 : #if defined(USE_SIGNALS)
589 7 : SamplerManager::instance()->AddSampler(this);
590 : #endif
591 7 : }
592 :
593 :
594 7 : void Sampler::Stop() {
595 : #if defined(USE_SIGNALS)
596 7 : SamplerManager::instance()->RemoveSampler(this);
597 : #endif
598 : DCHECK(IsActive());
599 : SetActive(false);
600 : SetRegistered(false);
601 7 : }
602 :
603 :
604 337 : void Sampler::IncreaseProfilingDepth() {
605 337 : base::NoBarrier_AtomicIncrement(&profiling_, 1);
606 : #if defined(USE_SIGNALS)
607 337 : SignalHandler::IncreaseSamplerCount();
608 : #endif
609 337 : }
610 :
611 :
612 337 : void Sampler::DecreaseProfilingDepth() {
613 : #if defined(USE_SIGNALS)
614 337 : SignalHandler::DecreaseSamplerCount();
615 : #endif
616 337 : base::NoBarrier_AtomicIncrement(&profiling_, -1);
617 337 : }
618 :
619 :
620 : #if defined(USE_SIGNALS)
621 :
622 504198 : void Sampler::DoSample() {
623 504198 : if (!SignalHandler::Installed()) return;
624 497009 : if (!IsActive() && !IsRegistered()) {
625 230 : SamplerManager::instance()->AddSampler(this);
626 : SetRegistered(true);
627 : }
628 252099 : pthread_kill(platform_data()->vm_tid(), SIGPROF);
629 : }
630 :
631 : #elif V8_OS_WIN || V8_OS_CYGWIN
632 :
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 118934 : } // namespace v8
|