1/*
2 * Copyright (C) 2003-2009, 2015 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
4 * Copyright (C) 2009 Acision BV. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22#include "config.h"
23#include "MachineStackMarker.h"
24
25#include "ConservativeRoots.h"
26#include "GPRInfo.h"
27#include "Heap.h"
28#include "JSArray.h"
29#include "JSCInlines.h"
30#include "LLIntPCRanges.h"
31#include "MacroAssembler.h"
32#include "VM.h"
33#include <setjmp.h>
34#include <stdlib.h>
35#include <wtf/StdLibExtras.h>
36
37#if OS(DARWIN)
38
39#include <mach/mach_init.h>
40#include <mach/mach_port.h>
41#include <mach/task.h>
42#include <mach/thread_act.h>
43#include <mach/vm_map.h>
44
45#elif OS(WINDOWS)
46
47#include <windows.h>
48#include <malloc.h>
49
50#elif OS(UNIX)
51
52#include <sys/mman.h>
53#include <unistd.h>
54
55#if OS(SOLARIS)
56#include <thread.h>
57#else
58#include <pthread.h>
59#endif
60
61#if HAVE(PTHREAD_NP_H)
62#include <pthread_np.h>
63#endif
64
65#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
66#include <signal.h>
67
68// We use SIGUSR2 to suspend and resume machine threads in JavaScriptCore.
69static const int SigThreadSuspendResume = SIGUSR2;
70static StaticLock globalSignalLock;
71thread_local static std::atomic<JSC::MachineThreads::Thread*> threadLocalCurrentThread;
72
73static void pthreadSignalHandlerSuspendResume(int, siginfo_t*, void* ucontext)
74{
75 // Touching thread local atomic types from signal handlers is allowed.
76 JSC::MachineThreads::Thread* thread = threadLocalCurrentThread.load();
77
78 if (thread->suspended.load(std::memory_order_acquire)) {
79 // This is signal handler invocation that is intended to be used to resume sigsuspend.
80 // So this handler invocation itself should not process.
81 //
82 // When signal comes, first, the system calls signal handler. And later, sigsuspend will be resumed. Signal handler invocation always precedes.
83 // So, the problem never happens that suspended.store(true, ...) will be executed before the handler is called.
84 // http://pubs.opengroup.org/onlinepubs/009695399/functions/sigsuspend.html
85 return;
86 }
87
88 ucontext_t* userContext = static_cast<ucontext_t*>(ucontext);
89#if CPU(PPC)
90 thread->suspendedMachineContext = *userContext->uc_mcontext.uc_regs;
91#else
92 thread->suspendedMachineContext = userContext->uc_mcontext;
93#endif
94
95 // Allow suspend caller to see that this thread is suspended.
96 // sem_post is async-signal-safe function. It means that we can call this from a signal handler.
97 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03
98 //
99 // And sem_post emits memory barrier that ensures that suspendedMachineContext is correctly saved.
100 // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11
101 sem_post(&thread->semaphoreForSuspendResume);
102
103 // Reaching here, SigThreadSuspendResume is blocked in this handler (this is configured by sigaction's sa_mask).
104 // So before calling sigsuspend, SigThreadSuspendResume to this thread is deferred. This ensures that the handler is not executed recursively.
105 sigset_t blockedSignalSet;
106 sigfillset(&blockedSignalSet);
107 sigdelset(&blockedSignalSet, SigThreadSuspendResume);
108 sigsuspend(&blockedSignalSet);
109
110 // Allow resume caller to see that this thread is resumed.
111 sem_post(&thread->semaphoreForSuspendResume);
112}
113#endif // USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
114
115#endif
116
117using namespace WTF;
118
119namespace JSC {
120
121using Thread = MachineThreads::Thread;
122
123class ActiveMachineThreadsManager;
124static ActiveMachineThreadsManager& activeMachineThreadsManager();
125
126class ActiveMachineThreadsManager {
127 WTF_MAKE_NONCOPYABLE(ActiveMachineThreadsManager);
128public:
129
130 class Locker {
131 public:
132 Locker(ActiveMachineThreadsManager& manager)
133 : m_locker(manager.m_lock)
134 {
135 }
136
137 private:
138 LockHolder m_locker;
139 };
140
141 void add(MachineThreads* machineThreads)
142 {
143 LockHolder managerLock(m_lock);
144 m_set.add(machineThreads);
145 }
146
147 void remove(MachineThreads* machineThreads)
148 {
149 LockHolder managerLock(m_lock);
150 auto recordedMachineThreads = m_set.take(machineThreads);
151 RELEASE_ASSERT(recordedMachineThreads = machineThreads);
152 }
153
154 bool contains(MachineThreads* machineThreads)
155 {
156 return m_set.contains(machineThreads);
157 }
158
159private:
160 typedef HashSet<MachineThreads*> MachineThreadsSet;
161
162 ActiveMachineThreadsManager() { }
163
164 Lock m_lock;
165 MachineThreadsSet m_set;
166
167 friend ActiveMachineThreadsManager& activeMachineThreadsManager();
168};
169
170static ActiveMachineThreadsManager& activeMachineThreadsManager()
171{
172 static std::once_flag initializeManagerOnceFlag;
173 static ActiveMachineThreadsManager* manager = nullptr;
174
175 std::call_once(initializeManagerOnceFlag, [] {
176 manager = new ActiveMachineThreadsManager();
177 });
178 return *manager;
179}
180
181static inline PlatformThread getCurrentPlatformThread()
182{
183#if OS(DARWIN)
184 return pthread_mach_thread_np(pthread_self());
185#elif OS(WINDOWS)
186 return GetCurrentThreadId();
187#elif USE(PTHREADS)
188 return pthread_self();
189#endif
190}
191
192MachineThreads::MachineThreads(Heap* heap)
193 : m_registeredThreads(0)
194 , m_threadSpecificForMachineThreads(0)
195 , m_threadSpecificForThread(0)
196#if !ASSERT_DISABLED
197 , m_heap(heap)
198#endif
199{
200 UNUSED_PARAM(heap);
201 threadSpecificKeyCreate(&m_threadSpecificForMachineThreads, removeThread);
202 threadSpecificKeyCreate(&m_threadSpecificForThread, nullptr);
203 activeMachineThreadsManager().add(this);
204}
205
206MachineThreads::~MachineThreads()
207{
208 activeMachineThreadsManager().remove(this);
209 threadSpecificKeyDelete(m_threadSpecificForMachineThreads);
210 threadSpecificKeyDelete(m_threadSpecificForThread);
211
212 LockHolder registeredThreadsLock(m_registeredThreadsMutex);
213 for (Thread* t = m_registeredThreads; t;) {
214 Thread* next = t->next;
215 delete t;
216 t = next;
217 }
218}
219
220Thread* MachineThreads::Thread::createForCurrentThread()
221{
222 auto stackBounds = wtfThreadData().stack();
223 return new Thread(getCurrentPlatformThread(), stackBounds.origin(), stackBounds.end());
224}
225
226bool MachineThreads::Thread::operator==(const PlatformThread& other) const
227{
228#if OS(DARWIN) || OS(WINDOWS)
229 return platformThread == other;
230#elif USE(PTHREADS)
231 return !!pthread_equal(platformThread, other);
232#else
233#error Need a way to compare threads on this platform
234#endif
235}
236
237#ifndef NDEBUG
238static bool isThreadInList(Thread* listHead, Thread* target)
239{
240 for (Thread* thread = listHead; thread; thread = thread->next) {
241 if (thread == target)
242 return true;
243 }
244
245 return false;
246}
247#endif
248
249void MachineThreads::addCurrentThread()
250{
251 ASSERT(!m_heap->vm()->hasExclusiveThread() || m_heap->vm()->exclusiveThread() == std::this_thread::get_id());
252
253 if (threadSpecificGet(m_threadSpecificForMachineThreads)) {
254#ifndef NDEBUG
255 LockHolder lock(m_registeredThreadsMutex);
256 ASSERT(threadSpecificGet(m_threadSpecificForMachineThreads) == this);
257 ASSERT(threadSpecificGet(m_threadSpecificForThread));
258 ASSERT(isThreadInList(m_registeredThreads, static_cast<Thread*>(threadSpecificGet(m_threadSpecificForThread))));
259#endif
260 return;
261 }
262
263 Thread* thread = Thread::createForCurrentThread();
264 threadSpecificSet(m_threadSpecificForMachineThreads, this);
265 threadSpecificSet(m_threadSpecificForThread, thread);
266
267 LockHolder lock(m_registeredThreadsMutex);
268
269 thread->next = m_registeredThreads;
270 m_registeredThreads = thread;
271}
272
273Thread* MachineThreads::machineThreadForCurrentThread()
274{
275 Thread* result = static_cast<Thread*>(threadSpecificGet(m_threadSpecificForThread));
276 RELEASE_ASSERT(result);
277#ifndef NDEBUG
278 LockHolder lock(m_registeredThreadsMutex);
279 ASSERT(isThreadInList(m_registeredThreads, result));
280#endif
281
282 return result;
283}
284
285void MachineThreads::removeThread(void* p)
286{
287 auto& manager = activeMachineThreadsManager();
288 ActiveMachineThreadsManager::Locker lock(manager);
289 auto machineThreads = static_cast<MachineThreads*>(p);
290 if (manager.contains(machineThreads)) {
291 // There's a chance that the MachineThreads registry that this thread
292 // was registered with was already destructed, and another one happened
293 // to be instantiated at the same address. Hence, this thread may or
294 // may not be found in this MachineThreads registry. We only need to
295 // do a removal if this thread is found in it.
296 machineThreads->removeThreadIfFound(getCurrentPlatformThread());
297 }
298}
299
300template<typename PlatformThread>
301void MachineThreads::removeThreadIfFound(PlatformThread platformThread)
302{
303 LockHolder lock(m_registeredThreadsMutex);
304 Thread* t = m_registeredThreads;
305 if (*t == platformThread) {
306 m_registeredThreads = m_registeredThreads->next;
307 delete t;
308 } else {
309 Thread* last = m_registeredThreads;
310 for (t = m_registeredThreads->next; t; t = t->next) {
311 if (*t == platformThread) {
312 last->next = t->next;
313 break;
314 }
315 last = t;
316 }
317 delete t;
318 }
319}
320
321SUPPRESS_ASAN
322void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters)
323{
324 void* registersBegin = &calleeSavedRegisters;
325 void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(&calleeSavedRegisters + 1)));
326 conservativeRoots.add(registersBegin, registersEnd, jitStubRoutines, codeBlocks);
327
328 conservativeRoots.add(stackTop, stackOrigin, jitStubRoutines, codeBlocks);
329}
330
331MachineThreads::Thread::Thread(const PlatformThread& platThread, void* base, void* end)
332 : platformThread(platThread)
333 , stackBase(base)
334 , stackEnd(end)
335{
336#if OS(WINDOWS)
337 ASSERT(platformThread == GetCurrentThreadId());
338 bool isSuccessful =
339 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
340 &platformThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
341 RELEASE_ASSERT(isSuccessful);
342#elif USE(PTHREADS) && !OS(DARWIN)
343 threadLocalCurrentThread.store(this);
344
345 // Signal handlers are process global configuration.
346 static std::once_flag initializeSignalHandler;
347 std::call_once(initializeSignalHandler, [] {
348 // Intentionally block SigThreadSuspendResume in the handler.
349 // SigThreadSuspendResume will be allowed in the handler by sigsuspend.
350 struct sigaction action;
351 sigemptyset(&action.sa_mask);
352 sigaddset(&action.sa_mask, SigThreadSuspendResume);
353
354 action.sa_sigaction = pthreadSignalHandlerSuspendResume;
355 action.sa_flags = SA_RESTART | SA_SIGINFO;
356 sigaction(SigThreadSuspendResume, &action, 0);
357 });
358
359 sigset_t mask;
360 sigemptyset(&mask);
361 sigaddset(&mask, SigThreadSuspendResume);
362 pthread_sigmask(SIG_UNBLOCK, &mask, 0);
363
364 sem_init(&semaphoreForSuspendResume, /* Only available in this process. */ 0, /* Initial value for the semaphore. */ 0);
365#endif
366}
367
368MachineThreads::Thread::~Thread()
369{
370#if OS(WINDOWS)
371 CloseHandle(platformThreadHandle);
372#elif USE(PTHREADS) && !OS(DARWIN)
373 sem_destroy(&semaphoreForSuspendResume);
374#endif
375}
376
377bool MachineThreads::Thread::suspend()
378{
379#if OS(DARWIN)
380 kern_return_t result = thread_suspend(platformThread);
381 return result == KERN_SUCCESS;
382#elif OS(WINDOWS)
383 bool threadIsSuspended = (SuspendThread(platformThreadHandle) != (DWORD)-1);
384 ASSERT(threadIsSuspended);
385 return threadIsSuspended;
386#elif USE(PTHREADS)
387 ASSERT_WITH_MESSAGE(getCurrentPlatformThread() != platformThread, "Currently we don't support suspend the current thread itself.");
388 {
389 // During suspend, suspend or resume should not be executed from the other threads.
390 // We use global lock instead of per thread lock.
391 // Consider the following case, there are threads A and B.
392 // And A attempt to suspend B and B attempt to suspend A.
393 // A and B send signals. And later, signals are delivered to A and B.
394 // In that case, both will be suspended.
395 LockHolder lock(globalSignalLock);
396 if (!suspendCount) {
397 // Ideally, we would like to use pthread_sigqueue. It allows us to pass the argument to the signal handler.
398 // But it can be used in a few platforms, like Linux.
399 // Instead, we use Thread* stored in the thread local storage to pass it to the signal handler.
400 if (pthread_kill(platformThread, SigThreadSuspendResume) == ESRCH)
401 return false;
402 sem_wait(&semaphoreForSuspendResume);
403 // Release barrier ensures that this operation is always executed after all the above processing is done.
404 suspended.store(true, std::memory_order_release);
405 }
406 ++suspendCount;
407 }
408 return true;
409#else
410#error Need a way to suspend threads on this platform
411#endif
412}
413
414void MachineThreads::Thread::resume()
415{
416#if OS(DARWIN)
417 thread_resume(platformThread);
418#elif OS(WINDOWS)
419 ResumeThread(platformThreadHandle);
420#elif USE(PTHREADS)
421 {
422 // During resume, suspend or resume should not be executed from the other threads.
423 LockHolder lock(globalSignalLock);
424 if (suspendCount == 1) {
425 // When allowing SigThreadSuspendResume interrupt in the signal handler by sigsuspend and SigThreadSuspendResume is actually issued,
426 // the signal handler itself will be called once again.
427 // There are several ways to distinguish the handler invocation for suspend and resume.
428 // 1. Use different signal numbers. And check the signal number in the handler.
429 // 2. Use some arguments to distinguish suspend and resume in the handler. If pthread_sigqueue can be used, we can take this.
430 // 3. Use thread local storage with atomic variables in the signal handler.
431 // In this implementaiton, we take (3). suspended flag is used to distinguish it.
432 if (pthread_kill(platformThread, SigThreadSuspendResume) == ESRCH)
433 return;
434 sem_wait(&semaphoreForSuspendResume);
435 // Release barrier ensures that this operation is always executed after all the above processing is done.
436 suspended.store(false, std::memory_order_release);
437 }
438 --suspendCount;
439 }
440#else
441#error Need a way to resume threads on this platform
442#endif
443}
444
445size_t MachineThreads::Thread::getRegisters(Thread::Registers& registers)
446{
447 Thread::Registers::PlatformRegisters& regs = registers.regs;
448#if OS(DARWIN)
449#if CPU(X86)
450 unsigned user_count = sizeof(regs)/sizeof(int);
451 thread_state_flavor_t flavor = i386_THREAD_STATE;
452#elif CPU(X86_64)
453 unsigned user_count = x86_THREAD_STATE64_COUNT;
454 thread_state_flavor_t flavor = x86_THREAD_STATE64;
455#elif CPU(PPC)
456 unsigned user_count = PPC_THREAD_STATE_COUNT;
457 thread_state_flavor_t flavor = PPC_THREAD_STATE;
458#elif CPU(PPC64)
459 unsigned user_count = PPC_THREAD_STATE64_COUNT;
460 thread_state_flavor_t flavor = PPC_THREAD_STATE64;
461#elif CPU(ARM)
462 unsigned user_count = ARM_THREAD_STATE_COUNT;
463 thread_state_flavor_t flavor = ARM_THREAD_STATE;
464#elif CPU(ARM64)
465 unsigned user_count = ARM_THREAD_STATE64_COUNT;
466 thread_state_flavor_t flavor = ARM_THREAD_STATE64;
467#else
468#error Unknown Architecture
469#endif
470
471 kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)&regs, &user_count);
472 if (result != KERN_SUCCESS) {
473 WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
474 "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result);
475 CRASH();
476 }
477 return user_count * sizeof(uintptr_t);
478// end OS(DARWIN)
479
480#elif OS(WINDOWS)
481 regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
482 GetThreadContext(platformThreadHandle, &regs);
483 return sizeof(CONTEXT);
484#elif USE(PTHREADS)
485 pthread_attr_init(&regs.attribute);
486#if HAVE(PTHREAD_NP_H) || OS(NETBSD)
487#if !OS(OPENBSD)
488 // e.g. on FreeBSD 5.4, neundorf@kde.org
489 pthread_attr_get_np(platformThread, &regs.attribute);
490#endif
491#else
492 // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
493 pthread_getattr_np(platformThread, &regs.attribute);
494#endif
495 regs.machineContext = suspendedMachineContext;
496 return 0;
497#else
498#error Need a way to get thread registers on this platform
499#endif
500}
501
502void* MachineThreads::Thread::Registers::stackPointer() const
503{
504#if OS(DARWIN)
505
506#if __DARWIN_UNIX03
507
508#if CPU(X86)
509 return reinterpret_cast<void*>(regs.__esp);
510#elif CPU(X86_64)
511 return reinterpret_cast<void*>(regs.__rsp);
512#elif CPU(PPC) || CPU(PPC64)
513 return reinterpret_cast<void*>(regs.__r1);
514#elif CPU(ARM)
515 return reinterpret_cast<void*>(regs.__sp);
516#elif CPU(ARM64)
517 return reinterpret_cast<void*>(regs.__sp);
518#else
519#error Unknown Architecture
520#endif
521
522#else // !__DARWIN_UNIX03
523
524#if CPU(X86)
525 return reinterpret_cast<void*>(regs.esp);
526#elif CPU(X86_64)
527 return reinterpret_cast<void*>(regs.rsp);
528#elif CPU(PPC) || CPU(PPC64)
529 return reinterpret_cast<void*>(regs.r1);
530#else
531#error Unknown Architecture
532#endif
533
534#endif // __DARWIN_UNIX03
535
536// end OS(DARWIN)
537#elif OS(WINDOWS)
538
539#if CPU(ARM)
540 return reinterpret_cast<void*>((uintptr_t) regs.Sp);
541#elif CPU(MIPS)
542 return reinterpret_cast<void*>((uintptr_t) regs.IntSp);
543#elif CPU(X86)
544 return reinterpret_cast<void*>((uintptr_t) regs.Esp);
545#elif CPU(X86_64)
546 return reinterpret_cast<void*>((uintptr_t) regs.Rsp);
547#else
548#error Unknown Architecture
549#endif
550
551#elif USE(PTHREADS)
552
553#if OS(FREEBSD) && ENABLE(JIT)
554
555#if CPU(X86)
556 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_esp);
557#elif CPU(X86_64)
558 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_rsp);
559#elif CPU(ARM)
560 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.__gregs[_REG_SP]);
561#elif CPU(ARM64)
562 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_gpregs.gp_sp);
563#elif CPU(MIPS)
564 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_regs[29]);
565#else
566#error Unknown Architecture
567#endif
568
569#elif defined(__GLIBC__) && ENABLE(JIT)
570
571#if CPU(X86)
572 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[REG_ESP]);
573#elif CPU(X86_64)
574 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[REG_RSP]);
575#elif CPU(ARM)
576 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.arm_sp);
577#elif CPU(ARM64)
578 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.sp);
579#elif CPU(MIPS)
580 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[29]);
581#else
582#error Unknown Architecture
583#endif
584
585#else
586 void* stackBase = 0;
587 size_t stackSize = 0;
588#if OS(OPENBSD)
589 stack_t ss;
590 int rc = pthread_stackseg_np(pthread_self(), &ss);
591 stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size);
592 stackSize = ss.ss_size;
593#else
594 int rc = pthread_attr_getstack(&regs.attribute, &stackBase, &stackSize);
595#endif
596 (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
597 ASSERT(stackBase);
598 return static_cast<char*>(stackBase) + stackSize;
599#endif
600
601#else
602#error Need a way to get the stack pointer for another thread on this platform
603#endif
604}
605
606#if ENABLE(SAMPLING_PROFILER)
607void* MachineThreads::Thread::Registers::framePointer() const
608{
609#if OS(DARWIN)
610
611#if __DARWIN_UNIX03
612
613#if CPU(X86)
614 return reinterpret_cast<void*>(regs.__ebp);
615#elif CPU(X86_64)
616 return reinterpret_cast<void*>(regs.__rbp);
617#elif CPU(ARM)
618 return reinterpret_cast<void*>(regs.__r[11]);
619#elif CPU(ARM64)
620 return reinterpret_cast<void*>(regs.__x[29]);
621#else
622#error Unknown Architecture
623#endif
624
625#else // !__DARWIN_UNIX03
626
627#if CPU(X86)
628 return reinterpret_cast<void*>(regs.esp);
629#elif CPU(X86_64)
630 return reinterpret_cast<void*>(regs.rsp);
631#else
632#error Unknown Architecture
633#endif
634
635#endif // __DARWIN_UNIX03
636
637// end OS(DARWIN)
638#elif OS(WINDOWS)
639
640#if CPU(ARM)
641 return reinterpret_cast<void*>((uintptr_t) regs.R11);
642#elif CPU(MIPS)
643#error Dont know what to do with mips. Do we even need this?
644#elif CPU(X86)
645 return reinterpret_cast<void*>((uintptr_t) regs.Ebp);
646#elif CPU(X86_64)
647 return reinterpret_cast<void*>((uintptr_t) regs.Rbp);
648#else
649#error Unknown Architecture
650#endif
651
652#elif OS(FREEBSD)
653
654#if CPU(X86)
655 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_ebp);
656#elif CPU(X86_64)
657 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_rbp);
658#elif CPU(ARM)
659 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.__gregs[_REG_FP]);
660#elif CPU(ARM64)
661 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_gpregs.gp_x[29]);
662#elif CPU(MIPS)
663 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_regs[30]);
664#else
665#error Unknown Architecture
666#endif
667
668#elif defined(__GLIBC__)
669
670// The following sequence depends on glibc's sys/ucontext.h.
671#if CPU(X86)
672 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[REG_EBP]);
673#elif CPU(X86_64)
674 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[REG_RBP]);
675#elif CPU(ARM)
676 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.arm_fp);
677#elif CPU(ARM64)
678 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.regs[29]);
679#elif CPU(MIPS)
680 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[30]);
681#else
682#error Unknown Architecture
683#endif
684
685#else
686#error Need a way to get the frame pointer for another thread on this platform
687#endif
688}
689
690void* MachineThreads::Thread::Registers::instructionPointer() const
691{
692#if OS(DARWIN)
693
694#if __DARWIN_UNIX03
695
696#if CPU(X86)
697 return reinterpret_cast<void*>(regs.__eip);
698#elif CPU(X86_64)
699 return reinterpret_cast<void*>(regs.__rip);
700#elif CPU(ARM)
701 return reinterpret_cast<void*>(regs.__pc);
702#elif CPU(ARM64)
703 return reinterpret_cast<void*>(regs.__pc);
704#else
705#error Unknown Architecture
706#endif
707
708#else // !__DARWIN_UNIX03
709#if CPU(X86)
710 return reinterpret_cast<void*>(regs.eip);
711#elif CPU(X86_64)
712 return reinterpret_cast<void*>(regs.rip);
713#else
714#error Unknown Architecture
715#endif
716
717#endif // __DARWIN_UNIX03
718
719// end OS(DARWIN)
720#elif OS(WINDOWS)
721
722#if CPU(ARM)
723 return reinterpret_cast<void*>((uintptr_t) regs.Pc);
724#elif CPU(MIPS)
725#error Dont know what to do with mips. Do we even need this?
726#elif CPU(X86)
727 return reinterpret_cast<void*>((uintptr_t) regs.Eip);
728#elif CPU(X86_64)
729 return reinterpret_cast<void*>((uintptr_t) regs.Rip);
730#else
731#error Unknown Architecture
732#endif
733
734#elif OS(FREEBSD)
735
736#if CPU(X86)
737 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_eip);
738#elif CPU(X86_64)
739 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_rip);
740#elif CPU(ARM)
741 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.__gregs[_REG_PC]);
742#elif CPU(ARM64)
743 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_gpregs.gp_elr);
744#elif CPU(MIPS)
745 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_pc);
746#else
747#error Unknown Architecture
748#endif
749
750#elif defined(__GLIBC__)
751
752// The following sequence depends on glibc's sys/ucontext.h.
753#if CPU(X86)
754 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[REG_EIP]);
755#elif CPU(X86_64)
756 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[REG_RIP]);
757#elif CPU(ARM)
758 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.arm_pc);
759#elif CPU(ARM64)
760 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.pc);
761#elif CPU(MIPS)
762 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.pc);
763#else
764#error Unknown Architecture
765#endif
766
767#else
768#error Need a way to get the instruction pointer for another thread on this platform
769#endif
770}
771void* MachineThreads::Thread::Registers::llintPC() const
772{
773 // LLInt uses regT4 as PC.
774#if OS(DARWIN)
775
776#if __DARWIN_UNIX03
777
778#if CPU(X86)
779 static_assert(LLInt::LLIntPC == X86Registers::esi, "Wrong LLInt PC.");
780 return reinterpret_cast<void*>(regs.__esi);
781#elif CPU(X86_64)
782 static_assert(LLInt::LLIntPC == X86Registers::r8, "Wrong LLInt PC.");
783 return reinterpret_cast<void*>(regs.__r8);
784#elif CPU(ARM)
785 static_assert(LLInt::LLIntPC == ARMRegisters::r8, "Wrong LLInt PC.");
786 return reinterpret_cast<void*>(regs.__r[8]);
787#elif CPU(ARM64)
788 static_assert(LLInt::LLIntPC == ARM64Registers::x4, "Wrong LLInt PC.");
789 return reinterpret_cast<void*>(regs.__x[4]);
790#else
791#error Unknown Architecture
792#endif
793
794#else // !__DARWIN_UNIX03
795#if CPU(X86)
796 static_assert(LLInt::LLIntPC == X86Registers::esi, "Wrong LLInt PC.");
797 return reinterpret_cast<void*>(regs.esi);
798#elif CPU(X86_64)
799 static_assert(LLInt::LLIntPC == X86Registers::r8, "Wrong LLInt PC.");
800 return reinterpret_cast<void*>(regs.r8);
801#else
802#error Unknown Architecture
803#endif
804
805#endif // __DARWIN_UNIX03
806
807// end OS(DARWIN)
808#elif OS(WINDOWS)
809
810#if CPU(ARM)
811 static_assert(LLInt::LLIntPC == ARMRegisters::r8, "Wrong LLInt PC.");
812 return reinterpret_cast<void*>((uintptr_t) regs.R8);
813#elif CPU(MIPS)
814#error Dont know what to do with mips. Do we even need this?
815#elif CPU(X86)
816 static_assert(LLInt::LLIntPC == X86Registers::esi, "Wrong LLInt PC.");
817 return reinterpret_cast<void*>((uintptr_t) regs.Esi);
818#elif CPU(X86_64)
819 static_assert(LLInt::LLIntPC == X86Registers::r10, "Wrong LLInt PC.");
820 return reinterpret_cast<void*>((uintptr_t) regs.R10);
821#else
822#error Unknown Architecture
823#endif
824
825#elif OS(FREEBSD)
826
827#if CPU(X86)
828 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_esi);
829#elif CPU(X86_64)
830 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_r8);
831#elif CPU(ARM)
832 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.__gregs[_REG_R8]);
833#elif CPU(ARM64)
834 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_gpregs.gp_x[4]);
835#elif CPU(MIPS)
836 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.mc_regs[12]);
837#else
838#error Unknown Architecture
839#endif
840
841#elif defined(__GLIBC__)
842
843// The following sequence depends on glibc's sys/ucontext.h.
844#if CPU(X86)
845 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[REG_ESI]);
846#elif CPU(X86_64)
847 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[REG_R8]);
848#elif CPU(ARM)
849 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.arm_r8);
850#elif CPU(ARM64)
851 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.regs[4]);
852#elif CPU(MIPS)
853 return reinterpret_cast<void*>((uintptr_t) regs.machineContext.gregs[12]);
854#else
855#error Unknown Architecture
856#endif
857
858#else
859#error Need a way to get the LLIntPC for another thread on this platform
860#endif
861}
862#endif // ENABLE(SAMPLING_PROFILER)
863
864void MachineThreads::Thread::freeRegisters(Thread::Registers& registers)
865{
866 Thread::Registers::PlatformRegisters& regs = registers.regs;
867#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
868 pthread_attr_destroy(&regs.attribute);
869#else
870 UNUSED_PARAM(regs);
871#endif
872}
873
874static inline int osRedZoneAdjustment()
875{
876 int redZoneAdjustment = 0;
877#if !OS(WINDOWS)
878#if CPU(X86_64)
879 // See http://people.freebsd.org/~obrien/amd64-elf-abi.pdf Section 3.2.2.
880 redZoneAdjustment = -128;
881#elif CPU(ARM64)
882 // See https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html#//apple_ref/doc/uid/TP40013702-SW7
883 redZoneAdjustment = -128;
884#endif
885#endif // !OS(WINDOWS)
886 return redZoneAdjustment;
887}
888
889std::pair<void*, size_t> MachineThreads::Thread::captureStack(void* stackTop)
890{
891 char* begin = reinterpret_cast_ptr<char*>(stackBase);
892 char* end = bitwise_cast<char*>(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackTop)));
893 ASSERT(begin >= end);
894
895 char* endWithRedZone = end + osRedZoneAdjustment();
896 ASSERT(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(endWithRedZone)) == reinterpret_cast<uintptr_t>(endWithRedZone));
897
898 if (endWithRedZone < stackEnd)
899 endWithRedZone = reinterpret_cast_ptr<char*>(stackEnd);
900
901 std::swap(begin, endWithRedZone);
902 return std::make_pair(begin, endWithRedZone - begin);
903}
904
905SUPPRESS_ASAN
906static void copyMemory(void* dst, const void* src, size_t size)
907{
908 size_t dstAsSize = reinterpret_cast<size_t>(dst);
909 size_t srcAsSize = reinterpret_cast<size_t>(src);
910 RELEASE_ASSERT(dstAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(dstAsSize));
911 RELEASE_ASSERT(srcAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(srcAsSize));
912 RELEASE_ASSERT(size == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(size));
913
914 intptr_t* dstPtr = reinterpret_cast<intptr_t*>(dst);
915 const intptr_t* srcPtr = reinterpret_cast<const intptr_t*>(src);
916 size /= sizeof(intptr_t);
917 while (size--)
918 *dstPtr++ = *srcPtr++;
919}
920
921
922
923// This function must not call malloc(), free(), or any other function that might
924// acquire a lock. Since 'thread' is suspended, trying to acquire a lock
925// will deadlock if 'thread' holds that lock.
926// This function, specifically the memory copying, was causing problems with Address Sanitizer in
927// apps. Since we cannot blacklist the system memcpy we must use our own naive implementation,
928// copyMemory, for ASan to work on either instrumented or non-instrumented builds. This is not a
929// significant performance loss as tryCopyOtherThreadStack is only called as part of an O(heapsize)
930// operation. As the heap is generally much larger than the stack the performance hit is minimal.
931// See: https://bugs.webkit.org/show_bug.cgi?id=146297
932void MachineThreads::tryCopyOtherThreadStack(Thread* thread, void* buffer, size_t capacity, size_t* size)
933{
934 Thread::Registers registers;
935 size_t registersSize = thread->getRegisters(registers);
936 std::pair<void*, size_t> stack = thread->captureStack(registers.stackPointer());
937
938 bool canCopy = *size + registersSize + stack.second <= capacity;
939
940 if (canCopy)
941 copyMemory(static_cast<char*>(buffer) + *size, &registers, registersSize);
942 *size += registersSize;
943
944 if (canCopy)
945 copyMemory(static_cast<char*>(buffer) + *size, stack.first, stack.second);
946 *size += stack.second;
947
948 thread->freeRegisters(registers);
949}
950
951bool MachineThreads::tryCopyOtherThreadStacks(LockHolder&, void* buffer, size_t capacity, size_t* size)
952{
953 // Prevent two VMs from suspending each other's threads at the same time,
954 // which can cause deadlock: <rdar://problem/20300842>.
955 static StaticLock mutex;
956 std::lock_guard<StaticLock> lock(mutex);
957
958 *size = 0;
959
960 PlatformThread currentPlatformThread = getCurrentPlatformThread();
961 int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet.
962 int index = 1;
963 Thread* threadsToBeDeleted = nullptr;
964
965 Thread* previousThread = nullptr;
966 for (Thread* thread = m_registeredThreads; thread; index++) {
967 if (*thread != currentPlatformThread) {
968 bool success = thread->suspend();
969#if OS(DARWIN)
970 if (!success) {
971 if (!numberOfThreads) {
972 for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next)
973 numberOfThreads++;
974 }
975
976 // Re-do the suspension to get the actual failure result for logging.
977 kern_return_t error = thread_suspend(thread->platformThread);
978 ASSERT(error != KERN_SUCCESS);
979
980 WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
981 "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.",
982 error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread));
983
984 // Put the invalid thread on the threadsToBeDeleted list.
985 // We can't just delete it here because we have suspended other
986 // threads, and they may still be holding the C heap lock which
987 // we need for deleting the invalid thread. Hence, we need to
988 // defer the deletion till after we have resumed all threads.
989 Thread* nextThread = thread->next;
990 thread->next = threadsToBeDeleted;
991 threadsToBeDeleted = thread;
992
993 if (previousThread)
994 previousThread->next = nextThread;
995 else
996 m_registeredThreads = nextThread;
997 thread = nextThread;
998 continue;
999 }
1000#else
1001 UNUSED_PARAM(numberOfThreads);
1002 UNUSED_PARAM(previousThread);
1003 ASSERT_UNUSED(success, success);
1004#endif
1005 }
1006 previousThread = thread;
1007 thread = thread->next;
1008 }
1009
1010 for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
1011 if (*thread != currentPlatformThread)
1012 tryCopyOtherThreadStack(thread, buffer, capacity, size);
1013 }
1014
1015 for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
1016 if (*thread != currentPlatformThread)
1017 thread->resume();
1018 }
1019
1020 for (Thread* thread = threadsToBeDeleted; thread; ) {
1021 Thread* nextThread = thread->next;
1022 delete thread;
1023 thread = nextThread;
1024 }
1025
1026 return *size <= capacity;
1027}
1028
1029static void growBuffer(size_t size, void** buffer, size_t* capacity)
1030{
1031 if (*buffer)
1032 fastFree(*buffer);
1033
1034 *capacity = WTF::roundUpToMultipleOf(WTF::pageSize(), size * 2);
1035 *buffer = fastMalloc(*capacity);
1036}
1037
1038void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters)
1039{
1040 gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, stackOrigin, stackTop, calleeSavedRegisters);
1041
1042 size_t size;
1043 size_t capacity = 0;
1044 void* buffer = nullptr;
1045 LockHolder lock(m_registeredThreadsMutex);
1046 while (!tryCopyOtherThreadStacks(lock, buffer, capacity, &size))
1047 growBuffer(size, &buffer, &capacity);
1048
1049 if (!buffer)
1050 return;
1051
1052 conservativeRoots.add(buffer, static_cast<char*>(buffer) + size, jitStubRoutines, codeBlocks);
1053 fastFree(buffer);
1054}
1055
1056} // namespace JSC
1057