]> git.saurik.com Git - apple/javascriptcore.git/blame - heap/MachineStackMarker.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / heap / MachineStackMarker.cpp
CommitLineData
14957cd0 1/*
ed1e77d3 2 * Copyright (C) 2003-2009, 2015 Apple Inc. All rights reserved.
14957cd0
A
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 "Heap.h"
27#include "JSArray.h"
81345200 28#include "JSCInlines.h"
93a37866 29#include "VM.h"
14957cd0
A
30#include <setjmp.h>
31#include <stdlib.h>
32#include <wtf/StdLibExtras.h>
33
14957cd0
A
34#if OS(DARWIN)
35
36#include <mach/mach_init.h>
37#include <mach/mach_port.h>
38#include <mach/task.h>
39#include <mach/thread_act.h>
40#include <mach/vm_map.h>
41
42#elif OS(WINDOWS)
43
44#include <windows.h>
45#include <malloc.h>
46
14957cd0
A
47#elif OS(UNIX)
48
14957cd0 49#include <sys/mman.h>
14957cd0
A
50#include <unistd.h>
51
52#if OS(SOLARIS)
53#include <thread.h>
54#else
55#include <pthread.h>
56#endif
57
58#if HAVE(PTHREAD_NP_H)
59#include <pthread_np.h>
60#endif
61
14957cd0
A
62#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
63#include <signal.h>
14957cd0
A
64#endif
65
66#endif
67
68using namespace WTF;
69
70namespace JSC {
71
14957cd0
A
72#if OS(DARWIN)
73typedef mach_port_t PlatformThread;
74#elif OS(WINDOWS)
ed1e77d3 75typedef DWORD PlatformThread;
14957cd0
A
76#elif USE(PTHREADS)
77typedef pthread_t PlatformThread;
78static const int SigThreadSuspendResume = SIGUSR2;
79
6fe7ccc8 80#if defined(SA_RESTART)
93a37866 81static void pthreadSignalHandlerSuspendResume(int)
14957cd0
A
82{
83 sigset_t signalSet;
84 sigemptyset(&signalSet);
85 sigaddset(&signalSet, SigThreadSuspendResume);
86 sigsuspend(&signalSet);
87}
88#endif
6fe7ccc8 89#endif
14957cd0 90
ed1e77d3
A
91class ActiveMachineThreadsManager;
92static ActiveMachineThreadsManager& activeMachineThreadsManager();
93
94class ActiveMachineThreadsManager {
95 WTF_MAKE_NONCOPYABLE(ActiveMachineThreadsManager);
96public:
97
98 class Locker {
99 public:
100 Locker(ActiveMachineThreadsManager& manager)
101 : m_locker(manager.m_lock)
102 {
103 }
104
105 private:
106 MutexLocker m_locker;
107 };
108
109 void add(MachineThreads* machineThreads)
110 {
111 MutexLocker managerLock(m_lock);
112 m_set.add(machineThreads);
113 }
114
115 void remove(MachineThreads* machineThreads)
116 {
117 MutexLocker managerLock(m_lock);
118 auto recordedMachineThreads = m_set.take(machineThreads);
119 RELEASE_ASSERT(recordedMachineThreads = machineThreads);
120 }
121
122 bool contains(MachineThreads* machineThreads)
123 {
124 return m_set.contains(machineThreads);
125 }
126
127private:
128 typedef HashSet<MachineThreads*> MachineThreadsSet;
129
130 ActiveMachineThreadsManager() { }
131
132 Mutex m_lock;
133 MachineThreadsSet m_set;
134
135 friend ActiveMachineThreadsManager& activeMachineThreadsManager();
136};
137
138static ActiveMachineThreadsManager& activeMachineThreadsManager()
139{
140 static std::once_flag initializeManagerOnceFlag;
141 static ActiveMachineThreadsManager* manager = nullptr;
142
143 std::call_once(initializeManagerOnceFlag, [] {
144 manager = new ActiveMachineThreadsManager();
145 });
146 return *manager;
147}
148
149static inline PlatformThread getCurrentPlatformThread()
150{
151#if OS(DARWIN)
152 return pthread_mach_thread_np(pthread_self());
153#elif OS(WINDOWS)
154 return GetCurrentThreadId();
155#elif USE(PTHREADS)
156 return pthread_self();
157#endif
158}
159
14957cd0 160class MachineThreads::Thread {
93a37866 161 WTF_MAKE_FAST_ALLOCATED;
ed1e77d3 162
6fe7ccc8
A
163 Thread(const PlatformThread& platThread, void* base)
164 : platformThread(platThread)
14957cd0
A
165 , stackBase(base)
166 {
6fe7ccc8
A
167#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) && defined(SA_RESTART)
168 // if we have SA_RESTART, enable SIGUSR2 debugging mechanism
14957cd0
A
169 struct sigaction action;
170 action.sa_handler = pthreadSignalHandlerSuspendResume;
171 sigemptyset(&action.sa_mask);
172 action.sa_flags = SA_RESTART;
173 sigaction(SigThreadSuspendResume, &action, 0);
174
175 sigset_t mask;
176 sigemptyset(&mask);
177 sigaddset(&mask, SigThreadSuspendResume);
178 pthread_sigmask(SIG_UNBLOCK, &mask, 0);
ed1e77d3
A
179#elif OS(WINDOWS)
180 ASSERT(platformThread == GetCurrentThreadId());
181 bool isSuccessful =
182 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
183 &platformThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
184 RELEASE_ASSERT(isSuccessful);
185#endif
186 }
187
188public:
189 ~Thread()
190 {
191#if OS(WINDOWS)
192 CloseHandle(platformThreadHandle);
14957cd0
A
193#endif
194 }
195
ed1e77d3
A
196 static Thread* createForCurrentThread()
197 {
198 return new Thread(getCurrentPlatformThread(), wtfThreadData().stack().origin());
199 }
200
201 struct Registers {
202 inline void* stackPointer() const;
203
204#if OS(DARWIN)
205#if CPU(X86)
206 typedef i386_thread_state_t PlatformRegisters;
207#elif CPU(X86_64)
208 typedef x86_thread_state64_t PlatformRegisters;
209#elif CPU(PPC)
210 typedef ppc_thread_state_t PlatformRegisters;
211#elif CPU(PPC64)
212 typedef ppc_thread_state64_t PlatformRegisters;
213#elif CPU(ARM)
214 typedef arm_thread_state_t PlatformRegisters;
215#elif CPU(ARM64)
216 typedef arm_thread_state64_t PlatformRegisters;
217#else
218#error Unknown Architecture
219#endif
220
221#elif OS(WINDOWS)
222 typedef CONTEXT PlatformRegisters;
223#elif USE(PTHREADS)
224 typedef pthread_attr_t PlatformRegisters;
225#else
226#error Need a thread register struct for this platform
227#endif
228
229 PlatformRegisters regs;
230 };
231
232 inline bool operator==(const PlatformThread& other) const;
233 inline bool operator!=(const PlatformThread& other) const { return !(*this == other); }
234
235 inline bool suspend();
236 inline void resume();
237 size_t getRegisters(Registers&);
238 void freeRegisters(Registers&);
239 std::pair<void*, size_t> captureStack(void* stackTop);
240
14957cd0 241 Thread* next;
14957cd0
A
242 PlatformThread platformThread;
243 void* stackBase;
ed1e77d3
A
244#if OS(WINDOWS)
245 HANDLE platformThreadHandle;
246#endif
14957cd0
A
247};
248
14957cd0 249MachineThreads::MachineThreads(Heap* heap)
93a37866 250 : m_registeredThreads(0)
14957cd0 251 , m_threadSpecific(0)
93a37866
A
252#if !ASSERT_DISABLED
253 , m_heap(heap)
254#endif
14957cd0 255{
93a37866 256 UNUSED_PARAM(heap);
ed1e77d3
A
257 threadSpecificKeyCreate(&m_threadSpecific, removeThread);
258 activeMachineThreadsManager().add(this);
14957cd0
A
259}
260
261MachineThreads::~MachineThreads()
262{
ed1e77d3
A
263 activeMachineThreadsManager().remove(this);
264 threadSpecificKeyDelete(m_threadSpecific);
14957cd0
A
265
266 MutexLocker registeredThreadsLock(m_registeredThreadsMutex);
267 for (Thread* t = m_registeredThreads; t;) {
268 Thread* next = t->next;
269 delete t;
270 t = next;
271 }
14957cd0
A
272}
273
ed1e77d3 274inline bool MachineThreads::Thread::operator==(const PlatformThread& other) const
6fe7ccc8
A
275{
276#if OS(DARWIN) || OS(WINDOWS)
ed1e77d3 277 return platformThread == other;
6fe7ccc8 278#elif USE(PTHREADS)
ed1e77d3 279 return !!pthread_equal(platformThread, other);
6fe7ccc8
A
280#else
281#error Need a way to compare threads on this platform
282#endif
283}
284
14957cd0
A
285void MachineThreads::addCurrentThread()
286{
81345200 287 ASSERT(!m_heap->vm()->hasExclusiveThread() || m_heap->vm()->exclusiveThread() == std::this_thread::get_id());
14957cd0 288
ed1e77d3
A
289 if (threadSpecificGet(m_threadSpecific)) {
290 ASSERT(threadSpecificGet(m_threadSpecific) == this);
14957cd0 291 return;
ed1e77d3 292 }
14957cd0 293
93a37866 294 threadSpecificSet(m_threadSpecific, this);
ed1e77d3 295 Thread* thread = Thread::createForCurrentThread();
14957cd0
A
296
297 MutexLocker lock(m_registeredThreadsMutex);
298
299 thread->next = m_registeredThreads;
300 m_registeredThreads = thread;
301}
302
303void MachineThreads::removeThread(void* p)
304{
ed1e77d3
A
305 auto& manager = activeMachineThreadsManager();
306 ActiveMachineThreadsManager::Locker lock(manager);
307 auto machineThreads = static_cast<MachineThreads*>(p);
308 if (manager.contains(machineThreads)) {
309 // There's a chance that the MachineThreads registry that this thread
310 // was registered with was already destructed, and another one happened
311 // to be instantiated at the same address. Hence, this thread may or
312 // may not be found in this MachineThreads registry. We only need to
313 // do a removal if this thread is found in it.
314 machineThreads->removeThreadIfFound(getCurrentPlatformThread());
315 }
14957cd0
A
316}
317
ed1e77d3
A
318template<typename PlatformThread>
319void MachineThreads::removeThreadIfFound(PlatformThread platformThread)
14957cd0 320{
14957cd0 321 MutexLocker lock(m_registeredThreadsMutex);
ed1e77d3
A
322 Thread* t = m_registeredThreads;
323 if (*t == platformThread) {
14957cd0
A
324 m_registeredThreads = m_registeredThreads->next;
325 delete t;
326 } else {
327 Thread* last = m_registeredThreads;
14957cd0 328 for (t = m_registeredThreads->next; t; t = t->next) {
ed1e77d3 329 if (*t == platformThread) {
14957cd0
A
330 last->next = t->next;
331 break;
332 }
333 last = t;
334 }
14957cd0
A
335 delete t;
336 }
337}
ed1e77d3
A
338
339void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters)
14957cd0 340{
ed1e77d3
A
341 void* registersBegin = &calleeSavedRegisters;
342 void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(&calleeSavedRegisters + 1)));
81345200 343 conservativeRoots.add(registersBegin, registersEnd, jitStubRoutines, codeBlocks);
14957cd0 344
ed1e77d3 345 conservativeRoots.add(stackTop, stackOrigin, jitStubRoutines, codeBlocks);
14957cd0
A
346}
347
ed1e77d3 348inline bool MachineThreads::Thread::suspend()
14957cd0
A
349{
350#if OS(DARWIN)
40a37d08
A
351 kern_return_t result = thread_suspend(platformThread);
352 return result == KERN_SUCCESS;
14957cd0 353#elif OS(WINDOWS)
ed1e77d3 354 bool threadIsSuspended = (SuspendThread(platformThreadHandle) != (DWORD)-1);
40a37d08
A
355 ASSERT(threadIsSuspended);
356 return threadIsSuspended;
14957cd0
A
357#elif USE(PTHREADS)
358 pthread_kill(platformThread, SigThreadSuspendResume);
40a37d08 359 return true;
14957cd0
A
360#else
361#error Need a way to suspend threads on this platform
362#endif
363}
364
ed1e77d3 365inline void MachineThreads::Thread::resume()
14957cd0
A
366{
367#if OS(DARWIN)
368 thread_resume(platformThread);
369#elif OS(WINDOWS)
ed1e77d3 370 ResumeThread(platformThreadHandle);
14957cd0
A
371#elif USE(PTHREADS)
372 pthread_kill(platformThread, SigThreadSuspendResume);
373#else
374#error Need a way to resume threads on this platform
375#endif
376}
377
ed1e77d3 378size_t MachineThreads::Thread::getRegisters(MachineThreads::Thread::Registers& registers)
14957cd0 379{
ed1e77d3 380 Thread::Registers::PlatformRegisters& regs = registers.regs;
14957cd0 381#if OS(DARWIN)
14957cd0
A
382#if CPU(X86)
383 unsigned user_count = sizeof(regs)/sizeof(int);
384 thread_state_flavor_t flavor = i386_THREAD_STATE;
385#elif CPU(X86_64)
386 unsigned user_count = x86_THREAD_STATE64_COUNT;
387 thread_state_flavor_t flavor = x86_THREAD_STATE64;
388#elif CPU(PPC)
389 unsigned user_count = PPC_THREAD_STATE_COUNT;
390 thread_state_flavor_t flavor = PPC_THREAD_STATE;
391#elif CPU(PPC64)
392 unsigned user_count = PPC_THREAD_STATE64_COUNT;
393 thread_state_flavor_t flavor = PPC_THREAD_STATE64;
394#elif CPU(ARM)
395 unsigned user_count = ARM_THREAD_STATE_COUNT;
396 thread_state_flavor_t flavor = ARM_THREAD_STATE;
93a37866
A
397#elif CPU(ARM64)
398 unsigned user_count = ARM_THREAD_STATE64_COUNT;
399 thread_state_flavor_t flavor = ARM_THREAD_STATE64;
14957cd0
A
400#else
401#error Unknown Architecture
402#endif
403
404 kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)&regs, &user_count);
405 if (result != KERN_SUCCESS) {
406 WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
407 "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);
408 CRASH();
409 }
ed1e77d3 410 return user_count * sizeof(uintptr_t);
14957cd0
A
411// end OS(DARWIN)
412
413#elif OS(WINDOWS)
6fe7ccc8 414 regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
ed1e77d3 415 GetThreadContext(platformThreadHandle, &regs);
14957cd0
A
416 return sizeof(CONTEXT);
417#elif USE(PTHREADS)
418 pthread_attr_init(&regs);
419#if HAVE(PTHREAD_NP_H) || OS(NETBSD)
81345200 420#if !OS(OPENBSD)
14957cd0
A
421 // e.g. on FreeBSD 5.4, neundorf@kde.org
422 pthread_attr_get_np(platformThread, &regs);
81345200 423#endif
14957cd0
A
424#else
425 // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
426 pthread_getattr_np(platformThread, &regs);
427#endif
428 return 0;
429#else
430#error Need a way to get thread registers on this platform
431#endif
432}
433
ed1e77d3 434inline void* MachineThreads::Thread::Registers::stackPointer() const
14957cd0
A
435{
436#if OS(DARWIN)
437
438#if __DARWIN_UNIX03
439
440#if CPU(X86)
441 return reinterpret_cast<void*>(regs.__esp);
442#elif CPU(X86_64)
443 return reinterpret_cast<void*>(regs.__rsp);
444#elif CPU(PPC) || CPU(PPC64)
445 return reinterpret_cast<void*>(regs.__r1);
446#elif CPU(ARM)
447 return reinterpret_cast<void*>(regs.__sp);
93a37866
A
448#elif CPU(ARM64)
449 return reinterpret_cast<void*>(regs.__sp);
14957cd0
A
450#else
451#error Unknown Architecture
452#endif
453
454#else // !__DARWIN_UNIX03
455
456#if CPU(X86)
457 return reinterpret_cast<void*>(regs.esp);
458#elif CPU(X86_64)
459 return reinterpret_cast<void*>(regs.rsp);
460#elif CPU(PPC) || CPU(PPC64)
461 return reinterpret_cast<void*>(regs.r1);
462#else
463#error Unknown Architecture
464#endif
465
466#endif // __DARWIN_UNIX03
467
468// end OS(DARWIN)
6fe7ccc8
A
469#elif OS(WINDOWS)
470
471#if CPU(ARM)
472 return reinterpret_cast<void*>((uintptr_t) regs.Sp);
473#elif CPU(MIPS)
474 return reinterpret_cast<void*>((uintptr_t) regs.IntSp);
475#elif CPU(X86)
14957cd0 476 return reinterpret_cast<void*>((uintptr_t) regs.Esp);
6fe7ccc8 477#elif CPU(X86_64)
14957cd0 478 return reinterpret_cast<void*>((uintptr_t) regs.Rsp);
6fe7ccc8
A
479#else
480#error Unknown Architecture
481#endif
482
14957cd0
A
483#elif USE(PTHREADS)
484 void* stackBase = 0;
485 size_t stackSize = 0;
81345200
A
486#if OS(OPENBSD)
487 stack_t ss;
488 int rc = pthread_stackseg_np(pthread_self(), &ss);
489 stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size);
490 stackSize = ss.ss_size;
491#else
14957cd0 492 int rc = pthread_attr_getstack(&regs, &stackBase, &stackSize);
81345200 493#endif
14957cd0
A
494 (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
495 ASSERT(stackBase);
496 return static_cast<char*>(stackBase) + stackSize;
497#else
498#error Need a way to get the stack pointer for another thread on this platform
499#endif
500}
501
ed1e77d3 502void MachineThreads::Thread::freeRegisters(MachineThreads::Thread::Registers& registers)
14957cd0 503{
ed1e77d3 504 Thread::Registers::PlatformRegisters& regs = registers.regs;
81345200 505#if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
14957cd0
A
506 pthread_attr_destroy(&regs);
507#else
508 UNUSED_PARAM(regs);
509#endif
510}
511
ed1e77d3 512std::pair<void*, size_t> MachineThreads::Thread::captureStack(void* stackTop)
14957cd0 513{
ed1e77d3
A
514 void* begin = stackBase;
515 void* end = reinterpret_cast<void*>(
516 WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackTop)));
517 if (begin > end)
518 std::swap(begin, end);
519 return std::make_pair(begin, static_cast<char*>(end) - static_cast<char*>(begin));
520}
14957cd0 521
ed1e77d3
A
522static void copyMemory(void* dst, const void* src, size_t size)
523{
524 size_t dstAsSize = reinterpret_cast<size_t>(dst);
525 size_t srcAsSize = reinterpret_cast<size_t>(src);
526 RELEASE_ASSERT(dstAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(dstAsSize));
527 RELEASE_ASSERT(srcAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(srcAsSize));
528 RELEASE_ASSERT(size == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(size));
529
530 intptr_t* dstPtr = reinterpret_cast<intptr_t*>(dst);
531 const intptr_t* srcPtr = reinterpret_cast<const intptr_t*>(src);
532 size /= sizeof(intptr_t);
533 while (size--)
534 *dstPtr++ = *srcPtr++;
535}
536
537
538
539// This function must not call malloc(), free(), or any other function that might
540// acquire a lock. Since 'thread' is suspended, trying to acquire a lock
541// will deadlock if 'thread' holds that lock.
542// This function, specifically the memory copying, was causing problems with Address Sanitizer in
543// apps. Since we cannot blacklist the system memcpy we must use our own naive implementation,
544// copyMemory, for ASan to work on either instrumented or non-instrumented builds. This is not a
545// significant performance loss as tryCopyOtherThreadStack is only called as part of an O(heapsize)
546// operation. As the heap is generally much larger than the stack the performance hit is minimal.
547// See: https://bugs.webkit.org/show_bug.cgi?id=146297
548void MachineThreads::tryCopyOtherThreadStack(Thread* thread, void* buffer, size_t capacity, size_t* size)
549{
550 Thread::Registers registers;
551 size_t registersSize = thread->getRegisters(registers);
552 std::pair<void*, size_t> stack = thread->captureStack(registers.stackPointer());
14957cd0 553
ed1e77d3 554 bool canCopy = *size + registersSize + stack.second <= capacity;
14957cd0 555
ed1e77d3
A
556 if (canCopy)
557 copyMemory(static_cast<char*>(buffer) + *size, &registers, registersSize);
558 *size += registersSize;
14957cd0 559
ed1e77d3
A
560 if (canCopy)
561 copyMemory(static_cast<char*>(buffer) + *size, stack.first, stack.second);
562 *size += stack.second;
14957cd0 563
ed1e77d3
A
564 thread->freeRegisters(registers);
565}
14957cd0 566
ed1e77d3
A
567bool MachineThreads::tryCopyOtherThreadStacks(MutexLocker&, void* buffer, size_t capacity, size_t* size)
568{
569 // Prevent two VMs from suspending each other's threads at the same time,
570 // which can cause deadlock: <rdar://problem/20300842>.
571 static StaticSpinLock mutex;
572 std::lock_guard<StaticSpinLock> lock(mutex);
14957cd0 573
ed1e77d3 574 *size = 0;
40a37d08 575
ed1e77d3
A
576 PlatformThread currentPlatformThread = getCurrentPlatformThread();
577 int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet.
578 int index = 1;
579 Thread* threadsToBeDeleted = nullptr;
580
581 Thread* previousThread = nullptr;
582 for (Thread* thread = m_registeredThreads; thread; index++) {
583 if (*thread != currentPlatformThread) {
584 bool success = thread->suspend();
40a37d08 585#if OS(DARWIN)
ed1e77d3
A
586 if (!success) {
587 if (!numberOfThreads) {
588 for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next)
589 numberOfThreads++;
40a37d08 590 }
ed1e77d3
A
591
592 // Re-do the suspension to get the actual failure result for logging.
593 kern_return_t error = thread_suspend(thread->platformThread);
594 ASSERT(error != KERN_SUCCESS);
595
596 WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
597 "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.",
598 error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread));
599
600 // Put the invalid thread on the threadsToBeDeleted list.
601 // We can't just delete it here because we have suspended other
602 // threads, and they may still be holding the C heap lock which
603 // we need for deleting the invalid thread. Hence, we need to
604 // defer the deletion till after we have resumed all threads.
605 Thread* nextThread = thread->next;
606 thread->next = threadsToBeDeleted;
607 threadsToBeDeleted = thread;
608
609 if (previousThread)
610 previousThread->next = nextThread;
611 else
612 m_registeredThreads = nextThread;
613 thread = nextThread;
614 continue;
615 }
40a37d08 616#else
ed1e77d3
A
617 UNUSED_PARAM(numberOfThreads);
618 UNUSED_PARAM(previousThread);
619 ASSERT_UNUSED(success, success);
40a37d08 620#endif
93a37866 621 }
ed1e77d3
A
622 previousThread = thread;
623 thread = thread->next;
624 }
93a37866 625
ed1e77d3
A
626 for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
627 if (*thread != currentPlatformThread)
628 tryCopyOtherThreadStack(thread, buffer, capacity, size);
629 }
93a37866 630
ed1e77d3
A
631 for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
632 if (*thread != currentPlatformThread)
633 thread->resume();
634 }
93a37866 635
ed1e77d3
A
636 for (Thread* thread = threadsToBeDeleted; thread; ) {
637 Thread* nextThread = thread->next;
638 delete thread;
639 thread = nextThread;
14957cd0 640 }
ed1e77d3
A
641
642 return *size <= capacity;
643}
644
645static void growBuffer(size_t size, void** buffer, size_t* capacity)
646{
647 if (*buffer)
648 fastFree(*buffer);
649
650 *capacity = WTF::roundUpToMultipleOf(WTF::pageSize(), size * 2);
651 *buffer = fastMalloc(*capacity);
652}
653
654void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters)
655{
656 gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, stackOrigin, stackTop, calleeSavedRegisters);
657
658 size_t size;
659 size_t capacity = 0;
660 void* buffer = nullptr;
661 MutexLocker lock(m_registeredThreadsMutex);
662 while (!tryCopyOtherThreadStacks(lock, buffer, capacity, &size))
663 growBuffer(size, &buffer, &capacity);
664
665 if (!buffer)
666 return;
667
668 conservativeRoots.add(buffer, static_cast<char*>(buffer) + size, jitStubRoutines, codeBlocks);
669 fastFree(buffer);
14957cd0
A
670}
671
672} // namespace JSC