1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "platform/heap/ThreadState.h"
33
34 #include "platform/TraceEvent.h"
35 #include "platform/heap/AddressSanitizer.h"
36 #include "platform/heap/Handle.h"
37 #include "platform/heap/Heap.h"
38 #include "public/platform/Platform.h"
39 #include "wtf/ThreadingPrimitives.h"
40
41 #if OS(WIN)
42 #include <stddef.h>
43 #include <windows.h>
44 #include <winnt.h>
45 #elif defined(__GLIBC__)
46 extern "C" void* __libc_stack_end; // NOLINT
47 #endif
48
49 #if defined(MEMORY_SANITIZER)
50 #include <sanitizer/msan_interface.h>
51 #endif
52
53 namespace WebCore {
54
getStackStart()55 static void* getStackStart()
56 {
57 #if defined(__GLIBC__) || OS(ANDROID)
58 pthread_attr_t attr;
59 if (!pthread_getattr_np(pthread_self(), &attr)) {
60 void* base;
61 size_t size;
62 int error = pthread_attr_getstack(&attr, &base, &size);
63 RELEASE_ASSERT(!error);
64 pthread_attr_destroy(&attr);
65 return reinterpret_cast<Address>(base) + size;
66 }
67 #if defined(__GLIBC__)
68 // pthread_getattr_np can fail for the main thread. In this case
69 // just like NaCl we rely on the __libc_stack_end to give us
70 // the start of the stack.
71 // See https://code.google.com/p/nativeclient/issues/detail?id=3431.
72 return __libc_stack_end;
73 #else
74 ASSERT_NOT_REACHED();
75 return 0;
76 #endif
77 #elif OS(MACOSX)
78 return pthread_get_stackaddr_np(pthread_self());
79 #elif OS(WIN) && COMPILER(MSVC)
80 // On Windows stack limits for the current thread are available in
81 // the thread information block (TIB). Its fields can be accessed through
82 // FS segment register on x86 and GS segment register on x86_64.
83 #ifdef _WIN64
84 return reinterpret_cast<void*>(__readgsqword(offsetof(NT_TIB64, StackBase)));
85 #else
86 return reinterpret_cast<void*>(__readfsdword(offsetof(NT_TIB, StackBase)));
87 #endif
88 #else
89 #error Unsupported getStackStart on this platform.
90 #endif
91 }
92
93
94 WTF::ThreadSpecific<ThreadState*>* ThreadState::s_threadSpecific = 0;
95 uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)];
96 SafePointBarrier* ThreadState::s_safePointBarrier = 0;
97 bool ThreadState::s_inGC = false;
98
threadAttachMutex()99 static Mutex& threadAttachMutex()
100 {
101 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
102 return mutex;
103 }
104
lockingTimeout()105 static double lockingTimeout()
106 {
107 // Wait time for parking all threads is at most 100 MS.
108 return 0.100;
109 }
110
111
112 typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr_t*);
113 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegistersCallback);
114
115 class SafePointBarrier {
116 public:
SafePointBarrier()117 SafePointBarrier() : m_canResume(1), m_unparkedThreadCount(0) { }
~SafePointBarrier()118 ~SafePointBarrier() { }
119
120 // Request other attached threads that are not at safe points to park themselves on safepoints.
parkOthers()121 bool parkOthers()
122 {
123 ASSERT(ThreadState::current()->isAtSafePoint());
124
125 // Lock threadAttachMutex() to prevent threads from attaching.
126 threadAttachMutex().lock();
127
128 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
129
130 MutexLocker locker(m_mutex);
131 atomicAdd(&m_unparkedThreadCount, threads.size());
132 releaseStore(&m_canResume, 0);
133
134 ThreadState* current = ThreadState::current();
135 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
136 if (*it == current)
137 continue;
138
139 const Vector<ThreadState::Interruptor*>& interruptors = (*it)->interruptors();
140 for (size_t i = 0; i < interruptors.size(); i++)
141 interruptors[i]->requestInterrupt();
142 }
143
144 while (acquireLoad(&m_unparkedThreadCount) > 0) {
145 double expirationTime = currentTime() + lockingTimeout();
146 if (!m_parked.timedWait(m_mutex, expirationTime)) {
147 // One of the other threads did not return to a safepoint within the maximum
148 // time we allow for threads to be parked. Abandon the GC and resume the
149 // currently parked threads.
150 resumeOthers(true);
151 return false;
152 }
153 }
154 return true;
155 }
156
resumeOthers(bool barrierLocked=false)157 void resumeOthers(bool barrierLocked = false)
158 {
159 ThreadState::AttachedThreadStateSet& threads = ThreadState::attachedThreads();
160 atomicSubtract(&m_unparkedThreadCount, threads.size());
161 releaseStore(&m_canResume, 1);
162
163 // FIXME: Resumed threads will all contend for m_mutex just to unlock it
164 // later which is a waste of resources.
165 if (UNLIKELY(barrierLocked)) {
166 m_resume.broadcast();
167 } else {
168 // FIXME: Resumed threads will all contend for
169 // m_mutex just to unlock it later which is a waste of
170 // resources.
171 MutexLocker locker(m_mutex);
172 m_resume.broadcast();
173 }
174
175 ThreadState* current = ThreadState::current();
176 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
177 if (*it == current)
178 continue;
179
180 const Vector<ThreadState::Interruptor*>& interruptors = (*it)->interruptors();
181 for (size_t i = 0; i < interruptors.size(); i++)
182 interruptors[i]->clearInterrupt();
183 }
184
185 threadAttachMutex().unlock();
186 ASSERT(ThreadState::current()->isAtSafePoint());
187 }
188
checkAndPark(ThreadState * state,SafePointAwareMutexLocker * locker=0)189 void checkAndPark(ThreadState* state, SafePointAwareMutexLocker* locker = 0)
190 {
191 ASSERT(!state->isSweepInProgress());
192 if (!acquireLoad(&m_canResume)) {
193 // If we are leaving the safepoint from a SafePointAwareMutexLocker
194 // call out to release the lock before going to sleep. This enables the
195 // lock to be acquired in the sweep phase, e.g. during weak processing
196 // or finalization. The SafePointAwareLocker will reenter the safepoint
197 // and reacquire the lock after leaving this safepoint.
198 if (locker)
199 locker->reset();
200 pushAllRegisters(this, state, parkAfterPushRegisters);
201 state->performPendingSweep();
202 }
203 }
204
enterSafePoint(ThreadState * state)205 void enterSafePoint(ThreadState* state)
206 {
207 ASSERT(!state->isSweepInProgress());
208 pushAllRegisters(this, state, enterSafePointAfterPushRegisters);
209 }
210
leaveSafePoint(ThreadState * state,SafePointAwareMutexLocker * locker=0)211 void leaveSafePoint(ThreadState* state, SafePointAwareMutexLocker* locker = 0)
212 {
213 if (atomicIncrement(&m_unparkedThreadCount) > 0)
214 checkAndPark(state, locker);
215 }
216
217 private:
doPark(ThreadState * state,intptr_t * stackEnd)218 void doPark(ThreadState* state, intptr_t* stackEnd)
219 {
220 state->recordStackEnd(stackEnd);
221 MutexLocker locker(m_mutex);
222 if (!atomicDecrement(&m_unparkedThreadCount))
223 m_parked.signal();
224 while (!acquireLoad(&m_canResume))
225 m_resume.wait(m_mutex);
226 atomicIncrement(&m_unparkedThreadCount);
227 }
228
parkAfterPushRegisters(SafePointBarrier * barrier,ThreadState * state,intptr_t * stackEnd)229 static void parkAfterPushRegisters(SafePointBarrier* barrier, ThreadState* state, intptr_t* stackEnd)
230 {
231 barrier->doPark(state, stackEnd);
232 }
233
doEnterSafePoint(ThreadState * state,intptr_t * stackEnd)234 void doEnterSafePoint(ThreadState* state, intptr_t* stackEnd)
235 {
236 state->recordStackEnd(stackEnd);
237 state->copyStackUntilSafePointScope();
238 // m_unparkedThreadCount tracks amount of unparked threads. It is
239 // positive if and only if we have requested other threads to park
240 // at safe-points in preparation for GC. The last thread to park
241 // itself will make the counter hit zero and should notify GC thread
242 // that it is safe to proceed.
243 // If no other thread is waiting for other threads to park then
244 // this counter can be negative: if N threads are at safe-points
245 // the counter will be -N.
246 if (!atomicDecrement(&m_unparkedThreadCount)) {
247 MutexLocker locker(m_mutex);
248 m_parked.signal(); // Safe point reached.
249 }
250 }
251
enterSafePointAfterPushRegisters(SafePointBarrier * barrier,ThreadState * state,intptr_t * stackEnd)252 static void enterSafePointAfterPushRegisters(SafePointBarrier* barrier, ThreadState* state, intptr_t* stackEnd)
253 {
254 barrier->doEnterSafePoint(state, stackEnd);
255 }
256
257 volatile int m_canResume;
258 volatile int m_unparkedThreadCount;
259 Mutex m_mutex;
260 ThreadCondition m_parked;
261 ThreadCondition m_resume;
262 };
263
ThreadState()264 ThreadState::ThreadState()
265 : m_thread(currentThread())
266 , m_persistents(adoptPtr(new PersistentAnchor()))
267 , m_startOfStack(reinterpret_cast<intptr_t*>(getStackStart()))
268 , m_endOfStack(reinterpret_cast<intptr_t*>(getStackStart()))
269 , m_safePointScopeMarker(0)
270 , m_atSafePoint(false)
271 , m_interruptors()
272 , m_gcRequested(false)
273 , m_forcePreciseGCForTesting(false)
274 , m_sweepRequested(0)
275 , m_sweepInProgress(false)
276 , m_noAllocationCount(0)
277 , m_inGC(false)
278 , m_heapContainsCache(adoptPtr(new HeapContainsCache()))
279 , m_isCleaningUp(false)
280 #if defined(ADDRESS_SANITIZER)
281 , m_asanFakeStack(__asan_get_current_fake_stack())
282 #endif
283 {
284 ASSERT(!**s_threadSpecific);
285 **s_threadSpecific = this;
286
287 m_stats.clear();
288 m_statsAfterLastGC.clear();
289 // First allocate the general heap, second iterate through to
290 // allocate the type specific heaps
291 m_heaps[GeneralHeap] = new ThreadHeap<FinalizedHeapObjectHeader>(this);
292 for (int i = GeneralHeap + 1; i < NumberOfHeaps; i++)
293 m_heaps[i] = new ThreadHeap<HeapObjectHeader>(this);
294
295 CallbackStack::init(&m_weakCallbackStack);
296 }
297
~ThreadState()298 ThreadState::~ThreadState()
299 {
300 checkThread();
301 CallbackStack::shutdown(&m_weakCallbackStack);
302 for (int i = GeneralHeap; i < NumberOfHeaps; i++)
303 delete m_heaps[i];
304 deleteAllValues(m_interruptors);
305 **s_threadSpecific = 0;
306 }
307
init()308 void ThreadState::init()
309 {
310 s_threadSpecific = new WTF::ThreadSpecific<ThreadState*>();
311 s_safePointBarrier = new SafePointBarrier;
312 }
313
shutdown()314 void ThreadState::shutdown()
315 {
316 delete s_safePointBarrier;
317 s_safePointBarrier = 0;
318
319 // Thread-local storage shouldn't be disposed, so we don't call ~ThreadSpecific().
320 }
321
attachMainThread()322 void ThreadState::attachMainThread()
323 {
324 RELEASE_ASSERT(!Heap::s_shutdownCalled);
325 MutexLocker locker(threadAttachMutex());
326 ThreadState* state = new(s_mainThreadStateStorage) ThreadState();
327 attachedThreads().add(state);
328 }
329
detachMainThread()330 void ThreadState::detachMainThread()
331 {
332 // Enter a safe point before trying to acquire threadAttachMutex
333 // to avoid dead lock if another thread is preparing for GC, has acquired
334 // threadAttachMutex and waiting for other threads to pause or reach a
335 // safepoint.
336 ThreadState* state = mainThreadState();
337 if (!state->isAtSafePoint())
338 state->enterSafePointWithoutPointers();
339
340 {
341 MutexLocker locker(threadAttachMutex());
342 state->leaveSafePoint();
343 ASSERT(attachedThreads().contains(state));
344 attachedThreads().remove(state);
345 state->~ThreadState();
346 }
347 shutdownHeapIfNecessary();
348 }
349
shutdownHeapIfNecessary()350 void ThreadState::shutdownHeapIfNecessary()
351 {
352 // We don't need to enter a safe point before acquiring threadAttachMutex
353 // because this thread is already detached.
354
355 MutexLocker locker(threadAttachMutex());
356 // We start shutting down the heap if there is no running thread
357 // and Heap::shutdown() is already called.
358 if (!attachedThreads().size() && Heap::s_shutdownCalled)
359 Heap::doShutdown();
360 }
361
attach()362 void ThreadState::attach()
363 {
364 RELEASE_ASSERT(!Heap::s_shutdownCalled);
365 MutexLocker locker(threadAttachMutex());
366 ThreadState* state = new ThreadState();
367 attachedThreads().add(state);
368 }
369
cleanup()370 void ThreadState::cleanup()
371 {
372 // From here on ignore all conservatively discovered
373 // pointers into the heap owned by this thread.
374 m_isCleaningUp = true;
375
376 // After this GC we expect heap to be empty because
377 // preCleanup tasks should have cleared all persistent
378 // handles that were externally owned.
379 Heap::collectAllGarbage();
380
381 // Verify that all heaps are empty now.
382 for (int i = 0; i < NumberOfHeaps; i++)
383 m_heaps[i]->assertEmpty();
384 }
385
preCleanup()386 void ThreadState::preCleanup()
387 {
388 for (size_t i = 0; i < m_cleanupTasks.size(); i++)
389 m_cleanupTasks[i]->preCleanup();
390 }
391
postCleanup()392 void ThreadState::postCleanup()
393 {
394 for (size_t i = 0; i < m_cleanupTasks.size(); i++)
395 m_cleanupTasks[i]->postCleanup();
396 m_cleanupTasks.clear();
397 }
398
detach()399 void ThreadState::detach()
400 {
401 ThreadState* state = current();
402 state->preCleanup();
403 state->cleanup();
404
405 // Enter a safe point before trying to acquire threadAttachMutex
406 // to avoid dead lock if another thread is preparing for GC, has acquired
407 // threadAttachMutex and waiting for other threads to pause or reach a
408 // safepoint.
409 if (!state->isAtSafePoint())
410 state->enterSafePointWithoutPointers();
411
412 {
413 MutexLocker locker(threadAttachMutex());
414 state->leaveSafePoint();
415 state->postCleanup();
416 ASSERT(attachedThreads().contains(state));
417 attachedThreads().remove(state);
418 delete state;
419 }
420 shutdownHeapIfNecessary();
421 }
422
visitRoots(Visitor * visitor)423 void ThreadState::visitRoots(Visitor* visitor)
424 {
425 {
426 // All threads are at safepoints so this is not strictly necessary.
427 // However we acquire the mutex to make mutation and traversal of this
428 // list symmetrical.
429 MutexLocker locker(globalRootsMutex());
430 globalRoots()->trace(visitor);
431 }
432
433 AttachedThreadStateSet& threads = attachedThreads();
434 for (AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it)
435 (*it)->trace(visitor);
436 }
437
438 NO_SANITIZE_ADDRESS
visitAsanFakeStackForPointer(Visitor * visitor,Address ptr)439 void ThreadState::visitAsanFakeStackForPointer(Visitor* visitor, Address ptr)
440 {
441 #if defined(ADDRESS_SANITIZER)
442 Address* start = reinterpret_cast<Address*>(m_startOfStack);
443 Address* end = reinterpret_cast<Address*>(m_endOfStack);
444 Address* fakeFrameStart = 0;
445 Address* fakeFrameEnd = 0;
446 Address* maybeFakeFrame = reinterpret_cast<Address*>(ptr);
447 Address* realFrameForFakeFrame =
448 reinterpret_cast<Address*>(
449 __asan_addr_is_in_fake_stack(
450 m_asanFakeStack, maybeFakeFrame,
451 reinterpret_cast<void**>(&fakeFrameStart),
452 reinterpret_cast<void**>(&fakeFrameEnd)));
453 if (realFrameForFakeFrame) {
454 // This is a fake frame from the asan fake stack.
455 if (realFrameForFakeFrame > end && start > realFrameForFakeFrame) {
456 // The real stack address for the asan fake frame is
457 // within the stack range that we need to scan so we need
458 // to visit the values in the fake frame.
459 for (Address* p = fakeFrameStart; p < fakeFrameEnd; p++)
460 Heap::checkAndMarkPointer(visitor, *p);
461 }
462 }
463 #endif
464 }
465
466 NO_SANITIZE_ADDRESS
visitStack(Visitor * visitor)467 void ThreadState::visitStack(Visitor* visitor)
468 {
469 Address* start = reinterpret_cast<Address*>(m_startOfStack);
470 // If there is a safepoint scope marker we should stop the stack
471 // scanning there to not touch active parts of the stack. Anything
472 // interesting beyond that point is in the safepoint stack copy.
473 // If there is no scope marker the thread is blocked and we should
474 // scan all the way to the recorded end stack pointer.
475 Address* end = reinterpret_cast<Address*>(m_endOfStack);
476 Address* safePointScopeMarker = reinterpret_cast<Address*>(m_safePointScopeMarker);
477 Address* current = safePointScopeMarker ? safePointScopeMarker : end;
478
479 // Ensure that current is aligned by address size otherwise the loop below
480 // will read past start address.
481 current = reinterpret_cast<Address*>(reinterpret_cast<intptr_t>(current) & ~(sizeof(Address) - 1));
482
483 for (; current < start; ++current) {
484 Address ptr = *current;
485 #if defined(MEMORY_SANITIZER)
486 // |ptr| may be uninitialized by design. Mark it as initialized to keep
487 // MSan from complaining.
488 // Note: it may be tempting to get rid of |ptr| and simply use |current|
489 // here, but that would be incorrect. We intentionally use a local
490 // variable because we don't want to unpoison the original stack.
491 __msan_unpoison(&ptr, sizeof(ptr));
492 #endif
493 Heap::checkAndMarkPointer(visitor, ptr);
494 visitAsanFakeStackForPointer(visitor, ptr);
495 }
496
497 for (Vector<Address>::iterator it = m_safePointStackCopy.begin(); it != m_safePointStackCopy.end(); ++it) {
498 Address ptr = *it;
499 #if defined(MEMORY_SANITIZER)
500 // See the comment above.
501 __msan_unpoison(&ptr, sizeof(ptr));
502 #endif
503 Heap::checkAndMarkPointer(visitor, ptr);
504 visitAsanFakeStackForPointer(visitor, ptr);
505 }
506 }
507
visitPersistents(Visitor * visitor)508 void ThreadState::visitPersistents(Visitor* visitor)
509 {
510 m_persistents->trace(visitor);
511 }
512
trace(Visitor * visitor)513 void ThreadState::trace(Visitor* visitor)
514 {
515 if (m_stackState == HeapPointersOnStack)
516 visitStack(visitor);
517 visitPersistents(visitor);
518 }
519
checkAndMarkPointer(Visitor * visitor,Address address)520 bool ThreadState::checkAndMarkPointer(Visitor* visitor, Address address)
521 {
522 // If thread is cleaning up ignore conservative pointers.
523 if (m_isCleaningUp)
524 return false;
525
526 // This checks for normal pages and for large objects which span the extent
527 // of several normal pages.
528 BaseHeapPage* page = heapPageFromAddress(address);
529 if (page) {
530 page->checkAndMarkPointer(visitor, address);
531 // Whether or not the pointer was within an object it was certainly
532 // within a page that is part of the heap, so we don't want to ask the
533 // other other heaps or put this address in the
534 // HeapDoesNotContainCache.
535 return true;
536 }
537
538 return false;
539 }
540
541 #if ENABLE(GC_TRACING)
findGCInfo(Address address)542 const GCInfo* ThreadState::findGCInfo(Address address)
543 {
544 BaseHeapPage* page = heapPageFromAddress(address);
545 if (page) {
546 return page->findGCInfo(address);
547 }
548 return 0;
549 }
550 #endif
551
pushWeakObjectPointerCallback(void * object,WeakPointerCallback callback)552 void ThreadState::pushWeakObjectPointerCallback(void* object, WeakPointerCallback callback)
553 {
554 CallbackStack::Item* slot = m_weakCallbackStack->allocateEntry(&m_weakCallbackStack);
555 *slot = CallbackStack::Item(object, callback);
556 }
557
popAndInvokeWeakPointerCallback(Visitor * visitor)558 bool ThreadState::popAndInvokeWeakPointerCallback(Visitor* visitor)
559 {
560 return m_weakCallbackStack->popAndInvokeCallback(&m_weakCallbackStack, visitor);
561 }
562
globalRoots()563 PersistentNode* ThreadState::globalRoots()
564 {
565 AtomicallyInitializedStatic(PersistentNode*, anchor = new PersistentAnchor);
566 return anchor;
567 }
568
globalRootsMutex()569 Mutex& ThreadState::globalRootsMutex()
570 {
571 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
572 return mutex;
573 }
574
575 // Trigger garbage collection on a 50% increase in size, but not for
576 // less than 512kbytes.
increasedEnoughToGC(size_t newSize,size_t oldSize)577 static bool increasedEnoughToGC(size_t newSize, size_t oldSize)
578 {
579 if (newSize < 1 << 19)
580 return false;
581 return newSize > oldSize + (oldSize >> 1);
582 }
583
584 // FIXME: The heuristics are local for a thread at this
585 // point. Consider using heuristics that take memory for all threads
586 // into account.
shouldGC()587 bool ThreadState::shouldGC()
588 {
589 // Do not GC during sweeping. We allow allocation during
590 // finalization, but those allocations are not allowed
591 // to lead to nested garbage collections.
592 return !m_sweepInProgress && increasedEnoughToGC(m_stats.totalObjectSpace(), m_statsAfterLastGC.totalObjectSpace());
593 }
594
595 // Trigger conservative garbage collection on a 100% increase in size,
596 // but not for less than 4Mbytes.
increasedEnoughToForceConservativeGC(size_t newSize,size_t oldSize)597 static bool increasedEnoughToForceConservativeGC(size_t newSize, size_t oldSize)
598 {
599 if (newSize < 1 << 22)
600 return false;
601 return newSize > 2 * oldSize;
602 }
603
604 // FIXME: The heuristics are local for a thread at this
605 // point. Consider using heuristics that take memory for all threads
606 // into account.
shouldForceConservativeGC()607 bool ThreadState::shouldForceConservativeGC()
608 {
609 // Do not GC during sweeping. We allow allocation during
610 // finalization, but those allocations are not allowed
611 // to lead to nested garbage collections.
612 return !m_sweepInProgress && increasedEnoughToForceConservativeGC(m_stats.totalObjectSpace(), m_statsAfterLastGC.totalObjectSpace());
613 }
614
sweepRequested()615 bool ThreadState::sweepRequested()
616 {
617 ASSERT(isAnyThreadInGC() || checkThread());
618 return m_sweepRequested;
619 }
620
setSweepRequested()621 void ThreadState::setSweepRequested()
622 {
623 // Sweep requested is set from the thread that initiates garbage
624 // collection which could be different from the thread for this
625 // thread state. Therefore the setting of m_sweepRequested needs a
626 // barrier.
627 atomicTestAndSetToOne(&m_sweepRequested);
628 }
629
clearSweepRequested()630 void ThreadState::clearSweepRequested()
631 {
632 checkThread();
633 m_sweepRequested = 0;
634 }
635
gcRequested()636 bool ThreadState::gcRequested()
637 {
638 checkThread();
639 return m_gcRequested;
640 }
641
setGCRequested()642 void ThreadState::setGCRequested()
643 {
644 checkThread();
645 m_gcRequested = true;
646 }
647
clearGCRequested()648 void ThreadState::clearGCRequested()
649 {
650 checkThread();
651 m_gcRequested = false;
652 }
653
performPendingGC(StackState stackState)654 void ThreadState::performPendingGC(StackState stackState)
655 {
656 if (stackState == NoHeapPointersOnStack) {
657 if (forcePreciseGCForTesting()) {
658 setForcePreciseGCForTesting(false);
659 Heap::collectAllGarbage();
660 } else if (gcRequested()) {
661 Heap::collectGarbage(NoHeapPointersOnStack);
662 }
663 }
664 }
665
setForcePreciseGCForTesting(bool value)666 void ThreadState::setForcePreciseGCForTesting(bool value)
667 {
668 checkThread();
669 m_forcePreciseGCForTesting = value;
670 }
671
forcePreciseGCForTesting()672 bool ThreadState::forcePreciseGCForTesting()
673 {
674 checkThread();
675 return m_forcePreciseGCForTesting;
676 }
677
isConsistentForGC()678 bool ThreadState::isConsistentForGC()
679 {
680 for (int i = 0; i < NumberOfHeaps; i++) {
681 if (!m_heaps[i]->isConsistentForGC())
682 return false;
683 }
684 return true;
685 }
686
makeConsistentForGC()687 void ThreadState::makeConsistentForGC()
688 {
689 for (int i = 0; i < NumberOfHeaps; i++)
690 m_heaps[i]->makeConsistentForGC();
691 }
692
prepareForGC()693 void ThreadState::prepareForGC()
694 {
695 for (int i = 0; i < NumberOfHeaps; i++) {
696 BaseHeap* heap = m_heaps[i];
697 heap->makeConsistentForGC();
698 // If there are parked threads with outstanding sweep requests, clear their mark bits.
699 // This happens if a thread did not have time to wake up and sweep,
700 // before the next GC arrived.
701 if (sweepRequested())
702 heap->clearMarks();
703 }
704 setSweepRequested();
705 }
706
heapPageFromAddress(Address address)707 BaseHeapPage* ThreadState::heapPageFromAddress(Address address)
708 {
709 BaseHeapPage* cachedPage = heapContainsCache()->lookup(address);
710 #ifdef NDEBUG
711 if (cachedPage)
712 return cachedPage;
713 #endif
714
715 for (int i = 0; i < NumberOfHeaps; i++) {
716 BaseHeapPage* page = m_heaps[i]->heapPageFromAddress(address);
717 if (page) {
718 // Asserts that make sure heapPageFromAddress takes addresses from
719 // the whole aligned blinkPageSize memory area. This is necessary
720 // for the negative cache to work.
721 ASSERT(page->isLargeObject() || page == m_heaps[i]->heapPageFromAddress(roundToBlinkPageStart(address)));
722 if (roundToBlinkPageStart(address) != roundToBlinkPageEnd(address))
723 ASSERT(page->isLargeObject() || page == m_heaps[i]->heapPageFromAddress(roundToBlinkPageEnd(address) - 1));
724 ASSERT(!cachedPage || page == cachedPage);
725 if (!cachedPage)
726 heapContainsCache()->addEntry(address, page);
727 return page;
728 }
729 }
730 ASSERT(!cachedPage);
731 return 0;
732 }
733
getStats(HeapStats & stats)734 void ThreadState::getStats(HeapStats& stats)
735 {
736 stats = m_stats;
737 #ifndef NDEBUG
738 if (isConsistentForGC()) {
739 HeapStats scannedStats;
740 scannedStats.clear();
741 for (int i = 0; i < NumberOfHeaps; i++)
742 m_heaps[i]->getScannedStats(scannedStats);
743 ASSERT(scannedStats == stats);
744 }
745 #endif
746 }
747
stopThreads()748 bool ThreadState::stopThreads()
749 {
750 return s_safePointBarrier->parkOthers();
751 }
752
resumeThreads()753 void ThreadState::resumeThreads()
754 {
755 s_safePointBarrier->resumeOthers();
756 }
757
safePoint(StackState stackState)758 void ThreadState::safePoint(StackState stackState)
759 {
760 checkThread();
761 performPendingGC(stackState);
762 ASSERT(!m_atSafePoint);
763 m_stackState = stackState;
764 m_atSafePoint = true;
765 s_safePointBarrier->checkAndPark(this);
766 m_atSafePoint = false;
767 m_stackState = HeapPointersOnStack;
768 }
769
770 #ifdef ADDRESS_SANITIZER
771 // When we are running under AddressSanitizer with detect_stack_use_after_return=1
772 // then stack marker obtained from SafePointScope will point into a fake stack.
773 // Detect this case by checking if it falls in between current stack frame
774 // and stack start and use an arbitrary high enough value for it.
775 // Don't adjust stack marker in any other case to match behavior of code running
776 // without AddressSanitizer.
adjustScopeMarkerForAdressSanitizer(void * scopeMarker)777 NO_SANITIZE_ADDRESS static void* adjustScopeMarkerForAdressSanitizer(void* scopeMarker)
778 {
779 Address start = reinterpret_cast<Address>(getStackStart());
780 Address end = reinterpret_cast<Address>(&start);
781 RELEASE_ASSERT(end < start);
782
783 if (end <= scopeMarker && scopeMarker < start)
784 return scopeMarker;
785
786 // 256 is as good an approximation as any else.
787 const size_t bytesToCopy = sizeof(Address) * 256;
788 if (static_cast<size_t>(start - end) < bytesToCopy)
789 return start;
790
791 return end + bytesToCopy;
792 }
793 #endif
794
enterSafePoint(StackState stackState,void * scopeMarker)795 void ThreadState::enterSafePoint(StackState stackState, void* scopeMarker)
796 {
797 #ifdef ADDRESS_SANITIZER
798 if (stackState == HeapPointersOnStack)
799 scopeMarker = adjustScopeMarkerForAdressSanitizer(scopeMarker);
800 #endif
801 ASSERT(stackState == NoHeapPointersOnStack || scopeMarker);
802 performPendingGC(stackState);
803 checkThread();
804 ASSERT(!m_atSafePoint);
805 m_atSafePoint = true;
806 m_stackState = stackState;
807 m_safePointScopeMarker = scopeMarker;
808 s_safePointBarrier->enterSafePoint(this);
809 }
810
leaveSafePoint(SafePointAwareMutexLocker * locker)811 void ThreadState::leaveSafePoint(SafePointAwareMutexLocker* locker)
812 {
813 checkThread();
814 ASSERT(m_atSafePoint);
815 s_safePointBarrier->leaveSafePoint(this, locker);
816 m_atSafePoint = false;
817 m_stackState = HeapPointersOnStack;
818 clearSafePointScopeMarker();
819 performPendingSweep();
820 }
821
copyStackUntilSafePointScope()822 void ThreadState::copyStackUntilSafePointScope()
823 {
824 if (!m_safePointScopeMarker || m_stackState == NoHeapPointersOnStack)
825 return;
826
827 Address* to = reinterpret_cast<Address*>(m_safePointScopeMarker);
828 Address* from = reinterpret_cast<Address*>(m_endOfStack);
829 RELEASE_ASSERT(from < to);
830 RELEASE_ASSERT(to <= reinterpret_cast<Address*>(m_startOfStack));
831 size_t slotCount = static_cast<size_t>(to - from);
832 ASSERT(slotCount < 1024); // Catch potential performance issues.
833
834 ASSERT(!m_safePointStackCopy.size());
835 m_safePointStackCopy.resize(slotCount);
836 for (size_t i = 0; i < slotCount; ++i) {
837 m_safePointStackCopy[i] = from[i];
838 }
839 }
840
performPendingSweep()841 void ThreadState::performPendingSweep()
842 {
843 if (!sweepRequested())
844 return;
845
846 TRACE_EVENT0("Blink", "ThreadState::performPendingSweep");
847 double timeStamp = WTF::currentTimeMS();
848 const char* samplingState = TRACE_EVENT_GET_SAMPLING_STATE();
849 if (isMainThread())
850 TRACE_EVENT_SET_SAMPLING_STATE("Blink", "BlinkGCSweeping");
851
852 m_sweepInProgress = true;
853 // Disallow allocation during weak processing.
854 enterNoAllocationScope();
855 // Perform thread-specific weak processing.
856 while (popAndInvokeWeakPointerCallback(Heap::s_markingVisitor)) { }
857 leaveNoAllocationScope();
858 // Perform sweeping and finalization.
859 m_stats.clear(); // Sweeping will recalculate the stats
860 for (int i = 0; i < NumberOfHeaps; i++)
861 m_heaps[i]->sweep();
862 getStats(m_statsAfterLastGC);
863 m_sweepInProgress = false;
864 clearGCRequested();
865 clearSweepRequested();
866
867 if (blink::Platform::current()) {
868 blink::Platform::current()->histogramCustomCounts("BlinkGC.PerformPendingSweep", WTF::currentTimeMS() - timeStamp, 0, 10 * 1000, 50);
869 }
870
871 if (isMainThread())
872 TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(samplingState);
873 }
874
addInterruptor(Interruptor * interruptor)875 void ThreadState::addInterruptor(Interruptor* interruptor)
876 {
877 SafePointScope scope(HeapPointersOnStack, SafePointScope::AllowNesting);
878
879 {
880 MutexLocker locker(threadAttachMutex());
881 m_interruptors.append(interruptor);
882 }
883 }
884
removeInterruptor(Interruptor * interruptor)885 void ThreadState::removeInterruptor(Interruptor* interruptor)
886 {
887 SafePointScope scope(HeapPointersOnStack, SafePointScope::AllowNesting);
888
889 {
890 MutexLocker locker(threadAttachMutex());
891 size_t index = m_interruptors.find(interruptor);
892 RELEASE_ASSERT(index >= 0);
893 m_interruptors.remove(index);
894 }
895 }
896
onInterrupted()897 void ThreadState::Interruptor::onInterrupted()
898 {
899 ThreadState* state = ThreadState::current();
900 ASSERT(state);
901 ASSERT(!state->isAtSafePoint());
902 state->safePoint(HeapPointersOnStack);
903 }
904
attachedThreads()905 ThreadState::AttachedThreadStateSet& ThreadState::attachedThreads()
906 {
907 DEFINE_STATIC_LOCAL(AttachedThreadStateSet, threads, ());
908 return threads;
909 }
910
911 #if ENABLE(GC_TRACING)
findGCInfoFromAllThreads(Address address)912 const GCInfo* ThreadState::findGCInfoFromAllThreads(Address address)
913 {
914 bool needLockForIteration = !isAnyThreadInGC();
915 if (needLockForIteration)
916 threadAttachMutex().lock();
917
918 ThreadState::AttachedThreadStateSet& threads = attachedThreads();
919 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
920 if (const GCInfo* gcInfo = (*it)->findGCInfo(address)) {
921 if (needLockForIteration)
922 threadAttachMutex().unlock();
923 return gcInfo;
924 }
925 }
926 if (needLockForIteration)
927 threadAttachMutex().unlock();
928 return 0;
929 }
930 #endif
931 }
932