Unreviewed, roll out http://trac.webkit.org/changeset/187972.
[WebKit-https.git] / Source / JavaScriptCore / heap / MachineStackMarker.cpp
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 "Heap.h"
27 #include "JSArray.h"
28 #include "JSCInlines.h"
29 #include "VM.h"
30 #include <setjmp.h>
31 #include <stdlib.h>
32 #include <wtf/StdLibExtras.h>
33
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
47 #elif OS(UNIX)
48
49 #include <sys/mman.h>
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
62 #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
63 #include <signal.h>
64 #endif
65
66 #endif
67
68 using namespace WTF;
69
70 namespace JSC {
71
72 #if OS(DARWIN)
73 typedef mach_port_t PlatformThread;
74 #elif OS(WINDOWS)
75 typedef DWORD PlatformThread;
76 #elif USE(PTHREADS)
77 typedef pthread_t PlatformThread;
78 static const int SigThreadSuspendResume = SIGUSR2;
79
80 #if defined(SA_RESTART)
81 static void pthreadSignalHandlerSuspendResume(int)
82 {
83     sigset_t signalSet;
84     sigemptyset(&signalSet);
85     sigaddset(&signalSet, SigThreadSuspendResume);
86     sigsuspend(&signalSet);
87 }
88 #endif
89 #endif
90
91 class ActiveMachineThreadsManager;
92 static ActiveMachineThreadsManager& activeMachineThreadsManager();
93
94 class ActiveMachineThreadsManager {
95     WTF_MAKE_NONCOPYABLE(ActiveMachineThreadsManager);
96 public:
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
127 private:
128     typedef HashSet<MachineThreads*> MachineThreadsSet;
129
130     ActiveMachineThreadsManager() { }
131     
132     Mutex m_lock;
133     MachineThreadsSet m_set;
134
135     friend ActiveMachineThreadsManager& activeMachineThreadsManager();
136 };
137
138 static 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     
149 static 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
160 class MachineThreads::Thread {
161     WTF_MAKE_FAST_ALLOCATED;
162
163     Thread(const PlatformThread& platThread, void* base)
164         : platformThread(platThread)
165         , stackBase(base)
166     {
167 #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN) && defined(SA_RESTART)
168         // if we have SA_RESTART, enable SIGUSR2 debugging mechanism
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);
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
188 public:
189     ~Thread()
190     {
191 #if OS(WINDOWS)
192         CloseHandle(platformThreadHandle);
193 #endif
194     }
195
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
241     Thread* next;
242     PlatformThread platformThread;
243     void* stackBase;
244 #if OS(WINDOWS)
245     HANDLE platformThreadHandle;
246 #endif
247 };
248
249 MachineThreads::MachineThreads(Heap* heap)
250     : m_registeredThreads(0)
251     , m_threadSpecific(0)
252 #if !ASSERT_DISABLED
253     , m_heap(heap)
254 #endif
255 {
256     UNUSED_PARAM(heap);
257     threadSpecificKeyCreate(&m_threadSpecific, removeThread);
258     activeMachineThreadsManager().add(this);
259 }
260
261 MachineThreads::~MachineThreads()
262 {
263     activeMachineThreadsManager().remove(this);
264     threadSpecificKeyDelete(m_threadSpecific);
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     }
272 }
273
274 inline bool MachineThreads::Thread::operator==(const PlatformThread& other) const
275 {
276 #if OS(DARWIN) || OS(WINDOWS)
277     return platformThread == other;
278 #elif USE(PTHREADS)
279     return !!pthread_equal(platformThread, other);
280 #else
281 #error Need a way to compare threads on this platform
282 #endif
283 }
284
285 void MachineThreads::addCurrentThread()
286 {
287     ASSERT(!m_heap->vm()->hasExclusiveThread() || m_heap->vm()->exclusiveThread() == std::this_thread::get_id());
288
289     if (threadSpecificGet(m_threadSpecific)) {
290         ASSERT(threadSpecificGet(m_threadSpecific) == this);
291         return;
292     }
293
294     threadSpecificSet(m_threadSpecific, this);
295     Thread* thread = Thread::createForCurrentThread();
296
297     MutexLocker lock(m_registeredThreadsMutex);
298
299     thread->next = m_registeredThreads;
300     m_registeredThreads = thread;
301 }
302
303 void MachineThreads::removeThread(void* p)
304 {
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     }
316 }
317
318 template<typename PlatformThread>
319 void MachineThreads::removeThreadIfFound(PlatformThread platformThread)
320 {
321     MutexLocker lock(m_registeredThreadsMutex);
322     Thread* t = m_registeredThreads;
323     if (*t == platformThread) {
324         m_registeredThreads = m_registeredThreads->next;
325         delete t;
326     } else {
327         Thread* last = m_registeredThreads;
328         for (t = m_registeredThreads->next; t; t = t->next) {
329             if (*t == platformThread) {
330                 last->next = t->next;
331                 break;
332             }
333             last = t;
334         }
335         delete t;
336     }
337 }
338     
339 void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters)
340 {
341     void* registersBegin = &calleeSavedRegisters;
342     void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(&calleeSavedRegisters + 1)));
343     conservativeRoots.add(registersBegin, registersEnd, jitStubRoutines, codeBlocks);
344
345     conservativeRoots.add(stackTop, stackOrigin, jitStubRoutines, codeBlocks);
346 }
347
348 inline bool MachineThreads::Thread::suspend()
349 {
350 #if OS(DARWIN)
351     kern_return_t result = thread_suspend(platformThread);
352     return result == KERN_SUCCESS;
353 #elif OS(WINDOWS)
354     bool threadIsSuspended = (SuspendThread(platformThreadHandle) != (DWORD)-1);
355     ASSERT(threadIsSuspended);
356     return threadIsSuspended;
357 #elif USE(PTHREADS)
358     pthread_kill(platformThread, SigThreadSuspendResume);
359     return true;
360 #else
361 #error Need a way to suspend threads on this platform
362 #endif
363 }
364
365 inline void MachineThreads::Thread::resume()
366 {
367 #if OS(DARWIN)
368     thread_resume(platformThread);
369 #elif OS(WINDOWS)
370     ResumeThread(platformThreadHandle);
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
378 size_t MachineThreads::Thread::getRegisters(MachineThreads::Thread::Registers& registers)
379 {
380     Thread::Registers::PlatformRegisters& regs = registers.regs;
381 #if OS(DARWIN)
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;
397 #elif CPU(ARM64)
398     unsigned user_count = ARM_THREAD_STATE64_COUNT;
399     thread_state_flavor_t flavor = ARM_THREAD_STATE64;
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     }
410     return user_count * sizeof(uintptr_t);
411 // end OS(DARWIN)
412
413 #elif OS(WINDOWS)
414     regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
415     GetThreadContext(platformThreadHandle, &regs);
416     return sizeof(CONTEXT);
417 #elif USE(PTHREADS)
418     pthread_attr_init(&regs);
419 #if HAVE(PTHREAD_NP_H) || OS(NETBSD)
420 #if !OS(OPENBSD)
421     // e.g. on FreeBSD 5.4, neundorf@kde.org
422     pthread_attr_get_np(platformThread, &regs);
423 #endif
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
434 inline void* MachineThreads::Thread::Registers::stackPointer() const
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);
448 #elif CPU(ARM64)
449     return reinterpret_cast<void*>(regs.__sp);
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)
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)
476     return reinterpret_cast<void*>((uintptr_t) regs.Esp);
477 #elif CPU(X86_64)
478     return reinterpret_cast<void*>((uintptr_t) regs.Rsp);
479 #else
480 #error Unknown Architecture
481 #endif
482
483 #elif USE(PTHREADS)
484     void* stackBase = 0;
485     size_t stackSize = 0;
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
492     int rc = pthread_attr_getstack(&regs, &stackBase, &stackSize);
493 #endif
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
502 void MachineThreads::Thread::freeRegisters(MachineThreads::Thread::Registers& registers)
503 {
504     Thread::Registers::PlatformRegisters& regs = registers.regs;
505 #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
506     pthread_attr_destroy(&regs);
507 #else
508     UNUSED_PARAM(regs);
509 #endif
510 }
511
512 std::pair<void*, size_t> MachineThreads::Thread::captureStack(void* stackTop)
513 {
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 }
521
522 static 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
548 void 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());
553
554     bool canCopy = *size + registersSize + stack.second <= capacity;
555
556     if (canCopy)
557         copyMemory(static_cast<char*>(buffer) + *size, &registers, registersSize);
558     *size += registersSize;
559
560     if (canCopy)
561         copyMemory(static_cast<char*>(buffer) + *size, stack.first, stack.second);
562     *size += stack.second;
563
564     thread->freeRegisters(registers);
565 }
566
567 bool 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);
573
574     *size = 0;
575
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();
585 #if OS(DARWIN)
586             if (!success) {
587                 if (!numberOfThreads) {
588                     for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next)
589                         numberOfThreads++;
590                 }
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             }
616 #else
617             UNUSED_PARAM(numberOfThreads);
618             UNUSED_PARAM(previousThread);
619             ASSERT_UNUSED(success, success);
620 #endif
621         }
622         previousThread = thread;
623         thread = thread->next;
624     }
625
626     for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
627         if (*thread != currentPlatformThread)
628             tryCopyOtherThreadStack(thread, buffer, capacity, size);
629     }
630
631     for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
632         if (*thread != currentPlatformThread)
633             thread->resume();
634     }
635
636     for (Thread* thread = threadsToBeDeleted; thread; ) {
637         Thread* nextThread = thread->next;
638         delete thread;
639         thread = nextThread;
640     }
641     
642     return *size <= capacity;
643 }
644
645 static 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
654 void 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);
670 }
671
672 } // namespace JSC