]> git.saurik.com Git - apple/javascriptcore.git/blob - heap/MachineStackMarker.cpp
4ae16a9cad9091ea7e178574ae9061ece62bee65
[apple/javascriptcore.git] / 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