Use WTF::Lock and WTF::Condition instead of WTF::Mutex, WTF::ThreadCondition, std...
[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         LockHolder m_locker;
107     };
108
109     void add(MachineThreads* machineThreads)
110     {
111         LockHolder managerLock(m_lock);
112         m_set.add(machineThreads);
113     }
114
115     void remove(MachineThreads* machineThreads)
116     {
117         LockHolder 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     Lock 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     LockHolder 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     LockHolder 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     LockHolder 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 SUPPRESS_ASAN
340 void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters)
341 {
342     void* registersBegin = &calleeSavedRegisters;
343     void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(&calleeSavedRegisters + 1)));
344     conservativeRoots.add(registersBegin, registersEnd, jitStubRoutines, codeBlocks);
345
346     conservativeRoots.add(stackTop, stackOrigin, jitStubRoutines, codeBlocks);
347 }
348
349 inline bool MachineThreads::Thread::suspend()
350 {
351 #if OS(DARWIN)
352     kern_return_t result = thread_suspend(platformThread);
353     return result == KERN_SUCCESS;
354 #elif OS(WINDOWS)
355     bool threadIsSuspended = (SuspendThread(platformThreadHandle) != (DWORD)-1);
356     ASSERT(threadIsSuspended);
357     return threadIsSuspended;
358 #elif USE(PTHREADS)
359     pthread_kill(platformThread, SigThreadSuspendResume);
360     return true;
361 #else
362 #error Need a way to suspend threads on this platform
363 #endif
364 }
365
366 inline void MachineThreads::Thread::resume()
367 {
368 #if OS(DARWIN)
369     thread_resume(platformThread);
370 #elif OS(WINDOWS)
371     ResumeThread(platformThreadHandle);
372 #elif USE(PTHREADS)
373     pthread_kill(platformThread, SigThreadSuspendResume);
374 #else
375 #error Need a way to resume threads on this platform
376 #endif
377 }
378
379 size_t MachineThreads::Thread::getRegisters(MachineThreads::Thread::Registers& registers)
380 {
381     Thread::Registers::PlatformRegisters& regs = registers.regs;
382 #if OS(DARWIN)
383 #if CPU(X86)
384     unsigned user_count = sizeof(regs)/sizeof(int);
385     thread_state_flavor_t flavor = i386_THREAD_STATE;
386 #elif CPU(X86_64)
387     unsigned user_count = x86_THREAD_STATE64_COUNT;
388     thread_state_flavor_t flavor = x86_THREAD_STATE64;
389 #elif CPU(PPC) 
390     unsigned user_count = PPC_THREAD_STATE_COUNT;
391     thread_state_flavor_t flavor = PPC_THREAD_STATE;
392 #elif CPU(PPC64)
393     unsigned user_count = PPC_THREAD_STATE64_COUNT;
394     thread_state_flavor_t flavor = PPC_THREAD_STATE64;
395 #elif CPU(ARM)
396     unsigned user_count = ARM_THREAD_STATE_COUNT;
397     thread_state_flavor_t flavor = ARM_THREAD_STATE;
398 #elif CPU(ARM64)
399     unsigned user_count = ARM_THREAD_STATE64_COUNT;
400     thread_state_flavor_t flavor = ARM_THREAD_STATE64;
401 #else
402 #error Unknown Architecture
403 #endif
404
405     kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)&regs, &user_count);
406     if (result != KERN_SUCCESS) {
407         WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 
408                             "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);
409         CRASH();
410     }
411     return user_count * sizeof(uintptr_t);
412 // end OS(DARWIN)
413
414 #elif OS(WINDOWS)
415     regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
416     GetThreadContext(platformThreadHandle, &regs);
417     return sizeof(CONTEXT);
418 #elif USE(PTHREADS)
419     pthread_attr_init(&regs);
420 #if HAVE(PTHREAD_NP_H) || OS(NETBSD)
421 #if !OS(OPENBSD)
422     // e.g. on FreeBSD 5.4, neundorf@kde.org
423     pthread_attr_get_np(platformThread, &regs);
424 #endif
425 #else
426     // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
427     pthread_getattr_np(platformThread, &regs);
428 #endif
429     return 0;
430 #else
431 #error Need a way to get thread registers on this platform
432 #endif
433 }
434
435 inline void* MachineThreads::Thread::Registers::stackPointer() const
436 {
437 #if OS(DARWIN)
438
439 #if __DARWIN_UNIX03
440
441 #if CPU(X86)
442     return reinterpret_cast<void*>(regs.__esp);
443 #elif CPU(X86_64)
444     return reinterpret_cast<void*>(regs.__rsp);
445 #elif CPU(PPC) || CPU(PPC64)
446     return reinterpret_cast<void*>(regs.__r1);
447 #elif CPU(ARM)
448     return reinterpret_cast<void*>(regs.__sp);
449 #elif CPU(ARM64)
450     return reinterpret_cast<void*>(regs.__sp);
451 #else
452 #error Unknown Architecture
453 #endif
454
455 #else // !__DARWIN_UNIX03
456
457 #if CPU(X86)
458     return reinterpret_cast<void*>(regs.esp);
459 #elif CPU(X86_64)
460     return reinterpret_cast<void*>(regs.rsp);
461 #elif CPU(PPC) || CPU(PPC64)
462     return reinterpret_cast<void*>(regs.r1);
463 #else
464 #error Unknown Architecture
465 #endif
466
467 #endif // __DARWIN_UNIX03
468
469 // end OS(DARWIN)
470 #elif OS(WINDOWS)
471
472 #if CPU(ARM)
473     return reinterpret_cast<void*>((uintptr_t) regs.Sp);
474 #elif CPU(MIPS)
475     return reinterpret_cast<void*>((uintptr_t) regs.IntSp);
476 #elif CPU(X86)
477     return reinterpret_cast<void*>((uintptr_t) regs.Esp);
478 #elif CPU(X86_64)
479     return reinterpret_cast<void*>((uintptr_t) regs.Rsp);
480 #else
481 #error Unknown Architecture
482 #endif
483
484 #elif USE(PTHREADS)
485     void* stackBase = 0;
486     size_t stackSize = 0;
487 #if OS(OPENBSD)
488     stack_t ss;
489     int rc = pthread_stackseg_np(pthread_self(), &ss);
490     stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size);
491     stackSize = ss.ss_size;
492 #else
493     int rc = pthread_attr_getstack(&regs, &stackBase, &stackSize);
494 #endif
495     (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
496     ASSERT(stackBase);
497     return static_cast<char*>(stackBase) + stackSize;
498 #else
499 #error Need a way to get the stack pointer for another thread on this platform
500 #endif
501 }
502
503 void MachineThreads::Thread::freeRegisters(MachineThreads::Thread::Registers& registers)
504 {
505     Thread::Registers::PlatformRegisters& regs = registers.regs;
506 #if USE(PTHREADS) && !OS(WINDOWS) && !OS(DARWIN)
507     pthread_attr_destroy(&regs);
508 #else
509     UNUSED_PARAM(regs);
510 #endif
511 }
512
513 std::pair<void*, size_t> MachineThreads::Thread::captureStack(void* stackTop)
514 {
515     void* begin = stackBase;
516     void* end = reinterpret_cast<void*>(
517         WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackTop)));
518     if (begin > end)
519         std::swap(begin, end);
520     return std::make_pair(begin, static_cast<char*>(end) - static_cast<char*>(begin));
521 }
522
523 SUPPRESS_ASAN
524 static void copyMemory(void* dst, const void* src, size_t size)
525 {
526     size_t dstAsSize = reinterpret_cast<size_t>(dst);
527     size_t srcAsSize = reinterpret_cast<size_t>(src);
528     RELEASE_ASSERT(dstAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(dstAsSize));
529     RELEASE_ASSERT(srcAsSize == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(srcAsSize));
530     RELEASE_ASSERT(size == WTF::roundUpToMultipleOf<sizeof(intptr_t)>(size));
531
532     intptr_t* dstPtr = reinterpret_cast<intptr_t*>(dst);
533     const intptr_t* srcPtr = reinterpret_cast<const intptr_t*>(src);
534     size /= sizeof(intptr_t);
535     while (size--)
536         *dstPtr++ = *srcPtr++;
537 }
538     
539
540
541 // This function must not call malloc(), free(), or any other function that might
542 // acquire a lock. Since 'thread' is suspended, trying to acquire a lock
543 // will deadlock if 'thread' holds that lock.
544 // This function, specifically the memory copying, was causing problems with Address Sanitizer in
545 // apps. Since we cannot blacklist the system memcpy we must use our own naive implementation,
546 // copyMemory, for ASan to work on either instrumented or non-instrumented builds. This is not a
547 // significant performance loss as tryCopyOtherThreadStack is only called as part of an O(heapsize)
548 // operation. As the heap is generally much larger than the stack the performance hit is minimal.
549 // See: https://bugs.webkit.org/show_bug.cgi?id=146297
550 void MachineThreads::tryCopyOtherThreadStack(Thread* thread, void* buffer, size_t capacity, size_t* size)
551 {
552     Thread::Registers registers;
553     size_t registersSize = thread->getRegisters(registers);
554     std::pair<void*, size_t> stack = thread->captureStack(registers.stackPointer());
555
556     bool canCopy = *size + registersSize + stack.second <= capacity;
557
558     if (canCopy)
559         copyMemory(static_cast<char*>(buffer) + *size, &registers, registersSize);
560     *size += registersSize;
561
562     if (canCopy)
563         copyMemory(static_cast<char*>(buffer) + *size, stack.first, stack.second);
564     *size += stack.second;
565
566     thread->freeRegisters(registers);
567 }
568
569 bool MachineThreads::tryCopyOtherThreadStacks(LockHolder&, void* buffer, size_t capacity, size_t* size)
570 {
571     // Prevent two VMs from suspending each other's threads at the same time,
572     // which can cause deadlock: <rdar://problem/20300842>.
573     static StaticLock mutex;
574     std::lock_guard<StaticLock> lock(mutex);
575
576     *size = 0;
577
578     PlatformThread currentPlatformThread = getCurrentPlatformThread();
579     int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet.
580     int index = 1;
581     Thread* threadsToBeDeleted = nullptr;
582
583     Thread* previousThread = nullptr;
584     for (Thread* thread = m_registeredThreads; thread; index++) {
585         if (*thread != currentPlatformThread) {
586             bool success = thread->suspend();
587 #if OS(DARWIN)
588             if (!success) {
589                 if (!numberOfThreads) {
590                     for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next)
591                         numberOfThreads++;
592                 }
593                 
594                 // Re-do the suspension to get the actual failure result for logging.
595                 kern_return_t error = thread_suspend(thread->platformThread);
596                 ASSERT(error != KERN_SUCCESS);
597
598                 WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
599                     "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.",
600                     error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread));
601
602                 // Put the invalid thread on the threadsToBeDeleted list.
603                 // We can't just delete it here because we have suspended other
604                 // threads, and they may still be holding the C heap lock which
605                 // we need for deleting the invalid thread. Hence, we need to
606                 // defer the deletion till after we have resumed all threads.
607                 Thread* nextThread = thread->next;
608                 thread->next = threadsToBeDeleted;
609                 threadsToBeDeleted = thread;
610
611                 if (previousThread)
612                     previousThread->next = nextThread;
613                 else
614                     m_registeredThreads = nextThread;
615                 thread = nextThread;
616                 continue;
617             }
618 #else
619             UNUSED_PARAM(numberOfThreads);
620             UNUSED_PARAM(previousThread);
621             ASSERT_UNUSED(success, success);
622 #endif
623         }
624         previousThread = thread;
625         thread = thread->next;
626     }
627
628     for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
629         if (*thread != currentPlatformThread)
630             tryCopyOtherThreadStack(thread, buffer, capacity, size);
631     }
632
633     for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
634         if (*thread != currentPlatformThread)
635             thread->resume();
636     }
637
638     for (Thread* thread = threadsToBeDeleted; thread; ) {
639         Thread* nextThread = thread->next;
640         delete thread;
641         thread = nextThread;
642     }
643     
644     return *size <= capacity;
645 }
646
647 static void growBuffer(size_t size, void** buffer, size_t* capacity)
648 {
649     if (*buffer)
650         fastFree(*buffer);
651
652     *capacity = WTF::roundUpToMultipleOf(WTF::pageSize(), size * 2);
653     *buffer = fastMalloc(*capacity);
654 }
655
656 void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackOrigin, void* stackTop, RegisterState& calleeSavedRegisters)
657 {
658     gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, stackOrigin, stackTop, calleeSavedRegisters);
659
660     size_t size;
661     size_t capacity = 0;
662     void* buffer = nullptr;
663     LockHolder lock(m_registeredThreadsMutex);
664     while (!tryCopyOtherThreadStacks(lock, buffer, capacity, &size))
665         growBuffer(size, &buffer, &capacity);
666
667     if (!buffer)
668         return;
669
670     conservativeRoots.add(buffer, static_cast<char*>(buffer) + size, jitStubRoutines, codeBlocks);
671     fastFree(buffer);
672 }
673
674 } // namespace JSC