Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Side by Side Diff: sky/engine/platform/heap/ThreadState.cpp

Issue 681963002: Remove heap/*.cpp files (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/engine/platform/heap/ThreadState.h ('k') | sky/engine/platform/heap/Visitor.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/ScriptForbiddenScope.h"
35 #include "platform/TraceEvent.h"
36 #include "platform/heap/AddressSanitizer.h"
37 #include "platform/heap/Handle.h"
38 #include "platform/heap/Heap.h"
39 #include "public/platform/Platform.h"
40 #include "public/platform/WebThread.h"
41 #include "wtf/ThreadingPrimitives.h"
42 #if ENABLE(GC_PROFILE_HEAP)
43 #include "platform/TracedValue.h"
44 #endif
45
46 #if defined(__GLIBC__)
47 extern "C" void* __libc_stack_end; // NOLINT
48 #endif
49
50 #if defined(MEMORY_SANITIZER)
51 #include <sanitizer/msan_interface.h>
52 #endif
53
54 namespace blink {
55
56 static void* getStackStart()
57 {
58 #if defined(__GLIBC__) || OS(ANDROID)
59 pthread_attr_t attr;
60 if (!pthread_getattr_np(pthread_self(), &attr)) {
61 void* base;
62 size_t size;
63 int error = pthread_attr_getstack(&attr, &base, &size);
64 RELEASE_ASSERT(!error);
65 pthread_attr_destroy(&attr);
66 return reinterpret_cast<Address>(base) + size;
67 }
68 #if defined(__GLIBC__)
69 // pthread_getattr_np can fail for the main thread. In this case
70 // just like NaCl we rely on the __libc_stack_end to give us
71 // the start of the stack.
72 // See https://code.google.com/p/nativeclient/issues/detail?id=3431.
73 return __libc_stack_end;
74 #else
75 ASSERT_NOT_REACHED();
76 return 0;
77 #endif
78 #elif OS(MACOSX)
79 return pthread_get_stackaddr_np(pthread_self());
80 #else
81 #error Unsupported getStackStart on this platform.
82 #endif
83 }
84
85 WTF::ThreadSpecific<ThreadState*>* ThreadState::s_threadSpecific = 0;
86 uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)];
87 SafePointBarrier* ThreadState::s_safePointBarrier = 0;
88 bool ThreadState::s_inGC = false;
89
90 static Mutex& threadAttachMutex()
91 {
92 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
93 return mutex;
94 }
95
96 class SafePointBarrier {
97 public:
98 SafePointBarrier() : m_canResume(1), m_unparkedThreadCount(0) { }
99 ~SafePointBarrier() { }
100
101 // Request other attached threads that are not at safe points to park themse lves on safepoints.
102 bool parkOthers()
103 {
104 return true;
105 }
106
107 void resumeOthers(bool barrierLocked = false)
108 {
109 }
110
111 void checkAndPark(ThreadState* state, SafePointAwareMutexLocker* locker = 0)
112 {
113 }
114
115 void enterSafePoint(ThreadState* state)
116 {
117 }
118
119 void leaveSafePoint(ThreadState* state, SafePointAwareMutexLocker* locker = 0)
120 {
121 }
122
123 private:
124 void doPark(ThreadState* state, intptr_t* stackEnd)
125 {
126 state->recordStackEnd(stackEnd);
127 MutexLocker locker(m_mutex);
128 if (!atomicDecrement(&m_unparkedThreadCount))
129 m_parked.signal();
130 while (!acquireLoad(&m_canResume))
131 m_resume.wait(m_mutex);
132 atomicIncrement(&m_unparkedThreadCount);
133 }
134
135 static void parkAfterPushRegisters(SafePointBarrier* barrier, ThreadState* s tate, intptr_t* stackEnd)
136 {
137 barrier->doPark(state, stackEnd);
138 }
139
140 void doEnterSafePoint(ThreadState* state, intptr_t* stackEnd)
141 {
142 state->recordStackEnd(stackEnd);
143 state->copyStackUntilSafePointScope();
144 // m_unparkedThreadCount tracks amount of unparked threads. It is
145 // positive if and only if we have requested other threads to park
146 // at safe-points in preparation for GC. The last thread to park
147 // itself will make the counter hit zero and should notify GC thread
148 // that it is safe to proceed.
149 // If no other thread is waiting for other threads to park then
150 // this counter can be negative: if N threads are at safe-points
151 // the counter will be -N.
152 if (!atomicDecrement(&m_unparkedThreadCount)) {
153 MutexLocker locker(m_mutex);
154 m_parked.signal(); // Safe point reached.
155 }
156 }
157
158 static void enterSafePointAfterPushRegisters(SafePointBarrier* barrier, Thre adState* state, intptr_t* stackEnd)
159 {
160 barrier->doEnterSafePoint(state, stackEnd);
161 }
162
163 volatile int m_canResume;
164 volatile int m_unparkedThreadCount;
165 Mutex m_mutex;
166 ThreadCondition m_parked;
167 ThreadCondition m_resume;
168 };
169
170 BaseHeapPage::BaseHeapPage(PageMemory* storage, const GCInfo* gcInfo, ThreadStat e* state)
171 : m_storage(storage)
172 , m_gcInfo(gcInfo)
173 , m_threadState(state)
174 , m_terminating(false)
175 , m_tracedAfterOrphaned(false)
176 {
177 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this)));
178 }
179
180 // Statically unfold the heap initialization loop so the compiler statically
181 // knows the heap index when using HeapIndexTrait.
182 template<int num> struct InitializeHeaps {
183 static const int index = num - 1;
184 static void init(BaseHeap** heaps, ThreadState* state)
185 {
186 InitializeHeaps<index>::init(heaps, state);
187 heaps[index] = new typename HeapIndexTrait<index>::HeapType(state, index );
188 }
189 };
190 template<> struct InitializeHeaps<0> {
191 static void init(BaseHeap** heaps, ThreadState* state) { }
192 };
193
194 ThreadState::ThreadState()
195 : m_thread(currentThread())
196 , m_persistents(adoptPtr(new PersistentAnchor()))
197 , m_startOfStack(reinterpret_cast<intptr_t*>(getStackStart()))
198 , m_endOfStack(reinterpret_cast<intptr_t*>(getStackStart()))
199 , m_safePointScopeMarker(0)
200 , m_atSafePoint(false)
201 , m_interruptors()
202 , m_gcRequested(false)
203 , m_forcePreciseGCForTesting(false)
204 , m_sweepRequested(0)
205 , m_sweepInProgress(false)
206 , m_noAllocationCount(0)
207 , m_inGC(false)
208 , m_heapContainsCache(adoptPtr(new HeapContainsCache()))
209 , m_isTerminating(false)
210 , m_lowCollectionRate(false)
211 , m_numberOfSweeperTasks(0)
212 #if defined(ADDRESS_SANITIZER)
213 , m_asanFakeStack(__asan_get_current_fake_stack())
214 #endif
215 {
216 ASSERT(!**s_threadSpecific);
217 **s_threadSpecific = this;
218
219 InitializeHeaps<NumberOfHeaps>::init(m_heaps, this);
220
221 CallbackStack::init(&m_weakCallbackStack);
222 }
223
224 ThreadState::~ThreadState()
225 {
226 checkThread();
227 CallbackStack::shutdown(&m_weakCallbackStack);
228 for (int i = 0; i < NumberOfHeaps; i++)
229 delete m_heaps[i];
230 deleteAllValues(m_interruptors);
231 **s_threadSpecific = 0;
232 }
233
234 void ThreadState::attach()
235 {
236 RELEASE_ASSERT(!Heap::s_shutdownCalled);
237 MutexLocker locker(threadAttachMutex());
238 ThreadState* state = new ThreadState();
239 attachedThreads().add(state);
240 }
241
242 void ThreadState::cleanupPages()
243 {
244 for (int i = 0; i < NumberOfHeaps; ++i)
245 m_heaps[i]->cleanupPages();
246 }
247
248 void ThreadState::cleanup()
249 {
250 for (size_t i = 0; i < m_cleanupTasks.size(); i++)
251 m_cleanupTasks[i]->preCleanup();
252
253 {
254 // Grab the threadAttachMutex to ensure only one thread can shutdown at
255 // a time and that no other thread can do a global GC. It also allows
256 // safe iteration of the attachedThreads set which happens as part of
257 // thread local GC asserts. We enter a safepoint while waiting for the
258 // lock to avoid a dead-lock where another thread has already requested
259 // GC.
260 SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnSt ack);
261
262 // From here on ignore all conservatively discovered
263 // pointers into the heap owned by this thread.
264 m_isTerminating = true;
265
266 // Set the terminate flag on all heap pages of this thread. This is used to
267 // ensure we don't trace pages on other threads that are not part of the
268 // thread local GC.
269 setupHeapsForTermination();
270
271 // Do thread local GC's as long as the count of thread local Persistents
272 // changes and is above zero.
273 PersistentAnchor* anchor = static_cast<PersistentAnchor*>(m_persistents. get());
274 int oldCount = -1;
275 int currentCount = anchor->numberOfPersistents();
276 ASSERT(currentCount >= 0);
277 while (currentCount != oldCount) {
278 Heap::collectGarbageForTerminatingThread(this);
279 oldCount = currentCount;
280 currentCount = anchor->numberOfPersistents();
281 }
282 // We should not have any persistents left when getting to this point,
283 // if we have it is probably a bug so adding a debug ASSERT to catch thi s.
284 ASSERT(!currentCount);
285
286 // Add pages to the orphaned page pool to ensure any global GCs from thi s point
287 // on will not trace objects on this thread's heaps.
288 cleanupPages();
289
290 ASSERT(attachedThreads().contains(this));
291 attachedThreads().remove(this);
292 }
293
294 for (size_t i = 0; i < m_cleanupTasks.size(); i++)
295 m_cleanupTasks[i]->postCleanup();
296 m_cleanupTasks.clear();
297 }
298
299
300 void ThreadState::visitPersistentRoots(Visitor* visitor)
301 {
302 {
303 // All threads are at safepoints so this is not strictly necessary.
304 // However we acquire the mutex to make mutation and traversal of this
305 // list symmetrical.
306 MutexLocker locker(globalRootsMutex());
307 globalRoots()->trace(visitor);
308 }
309
310 AttachedThreadStateSet& threads = attachedThreads();
311 for (AttachedThreadStateSet::iterator it = threads.begin(), end = threads.en d(); it != end; ++it)
312 (*it)->visitPersistents(visitor);
313 }
314
315 void ThreadState::visitStackRoots(Visitor* visitor)
316 {
317 AttachedThreadStateSet& threads = attachedThreads();
318 for (AttachedThreadStateSet::iterator it = threads.begin(), end = threads.en d(); it != end; ++it)
319 (*it)->visitStack(visitor);
320 }
321
322 NO_SANITIZE_ADDRESS
323 void ThreadState::visitAsanFakeStackForPointer(Visitor* visitor, Address ptr)
324 {
325 #if defined(ADDRESS_SANITIZER)
326 Address* start = reinterpret_cast<Address*>(m_startOfStack);
327 Address* end = reinterpret_cast<Address*>(m_endOfStack);
328 Address* fakeFrameStart = 0;
329 Address* fakeFrameEnd = 0;
330 Address* maybeFakeFrame = reinterpret_cast<Address*>(ptr);
331 Address* realFrameForFakeFrame =
332 reinterpret_cast<Address*>(
333 __asan_addr_is_in_fake_stack(
334 m_asanFakeStack, maybeFakeFrame,
335 reinterpret_cast<void**>(&fakeFrameStart),
336 reinterpret_cast<void**>(&fakeFrameEnd)));
337 if (realFrameForFakeFrame) {
338 // This is a fake frame from the asan fake stack.
339 if (realFrameForFakeFrame > end && start > realFrameForFakeFrame) {
340 // The real stack address for the asan fake frame is
341 // within the stack range that we need to scan so we need
342 // to visit the values in the fake frame.
343 for (Address* p = fakeFrameStart; p < fakeFrameEnd; p++)
344 Heap::checkAndMarkPointer(visitor, *p);
345 }
346 }
347 #endif
348 }
349
350 NO_SANITIZE_ADDRESS
351 void ThreadState::visitStack(Visitor* visitor)
352 {
353 if (m_stackState == NoHeapPointersOnStack)
354 return;
355
356 Address* start = reinterpret_cast<Address*>(m_startOfStack);
357 // If there is a safepoint scope marker we should stop the stack
358 // scanning there to not touch active parts of the stack. Anything
359 // interesting beyond that point is in the safepoint stack copy.
360 // If there is no scope marker the thread is blocked and we should
361 // scan all the way to the recorded end stack pointer.
362 Address* end = reinterpret_cast<Address*>(m_endOfStack);
363 Address* safePointScopeMarker = reinterpret_cast<Address*>(m_safePointScopeM arker);
364 Address* current = safePointScopeMarker ? safePointScopeMarker : end;
365
366 // Ensure that current is aligned by address size otherwise the loop below
367 // will read past start address.
368 current = reinterpret_cast<Address*>(reinterpret_cast<intptr_t>(current) & ~ (sizeof(Address) - 1));
369
370 for (; current < start; ++current) {
371 Address ptr = *current;
372 #if defined(MEMORY_SANITIZER)
373 // |ptr| may be uninitialized by design. Mark it as initialized to keep
374 // MSan from complaining.
375 // Note: it may be tempting to get rid of |ptr| and simply use |current|
376 // here, but that would be incorrect. We intentionally use a local
377 // variable because we don't want to unpoison the original stack.
378 __msan_unpoison(&ptr, sizeof(ptr));
379 #endif
380 Heap::checkAndMarkPointer(visitor, ptr);
381 visitAsanFakeStackForPointer(visitor, ptr);
382 }
383
384 for (Vector<Address>::iterator it = m_safePointStackCopy.begin(); it != m_sa fePointStackCopy.end(); ++it) {
385 Address ptr = *it;
386 #if defined(MEMORY_SANITIZER)
387 // See the comment above.
388 __msan_unpoison(&ptr, sizeof(ptr));
389 #endif
390 Heap::checkAndMarkPointer(visitor, ptr);
391 visitAsanFakeStackForPointer(visitor, ptr);
392 }
393 }
394
395 void ThreadState::visitPersistents(Visitor* visitor)
396 {
397 m_persistents->trace(visitor);
398 }
399
400 bool ThreadState::checkAndMarkPointer(Visitor* visitor, Address address)
401 {
402 // If thread is terminating ignore conservative pointers.
403 if (m_isTerminating)
404 return false;
405
406 // This checks for normal pages and for large objects which span the extent
407 // of several normal pages.
408 BaseHeapPage* page = heapPageFromAddress(address);
409 if (page) {
410 page->checkAndMarkPointer(visitor, address);
411 // Whether or not the pointer was within an object it was certainly
412 // within a page that is part of the heap, so we don't want to ask the
413 // other other heaps or put this address in the
414 // HeapDoesNotContainCache.
415 return true;
416 }
417
418 return false;
419 }
420
421 #if ENABLE(GC_PROFILE_MARKING)
422 const GCInfo* ThreadState::findGCInfo(Address address)
423 {
424 BaseHeapPage* page = heapPageFromAddress(address);
425 if (page) {
426 return page->findGCInfo(address);
427 }
428 return 0;
429 }
430 #endif
431
432 #if ENABLE(GC_PROFILE_HEAP)
433 size_t ThreadState::SnapshotInfo::getClassTag(const GCInfo* gcinfo)
434 {
435 HashMap<const GCInfo*, size_t>::AddResult result = classTags.add(gcinfo, cla ssTags.size());
436 if (result.isNewEntry) {
437 liveCount.append(0);
438 deadCount.append(0);
439 liveSize.append(0);
440 deadSize.append(0);
441 generations.append(Vector<int, 8>());
442 generations.last().fill(0, 8);
443 }
444 return result.storedValue->value;
445 }
446
447 void ThreadState::snapshot()
448 {
449 SnapshotInfo info(this);
450 RefPtr<TracedValue> json = TracedValue::create();
451
452 #define SNAPSHOT_HEAP(HeapType) \
453 { \
454 json->beginDictionary(); \
455 json->setString("name", #HeapType); \
456 m_heaps[HeapType##Heap]->snapshot(json.get(), &info); \
457 json->endDictionary(); \
458 json->beginDictionary(); \
459 json->setString("name", #HeapType"NonFinalized"); \
460 m_heaps[HeapType##HeapNonFinalized]->snapshot(json.get(), &info); \
461 json->endDictionary(); \
462 }
463 json->beginArray("heaps");
464 SNAPSHOT_HEAP(General);
465 SNAPSHOT_HEAP(CollectionBacking);
466 FOR_EACH_TYPED_HEAP(SNAPSHOT_HEAP);
467 json->endArray();
468 #undef SNAPSHOT_HEAP
469
470 json->setInteger("allocatedSpace", m_stats.totalAllocatedSpace());
471 json->setInteger("objectSpace", m_stats.totalObjectSpace());
472 json->setInteger("pageCount", info.pageCount);
473 json->setInteger("freeSize", info.freeSize);
474
475 Vector<String> classNameVector(info.classTags.size());
476 for (HashMap<const GCInfo*, size_t>::iterator it = info.classTags.begin(); i t != info.classTags.end(); ++it)
477 classNameVector[it->value] = it->key->m_className;
478
479 size_t liveSize = 0;
480 size_t deadSize = 0;
481 json->beginArray("classes");
482 for (size_t i = 0; i < classNameVector.size(); ++i) {
483 json->beginDictionary();
484 json->setString("name", classNameVector[i]);
485 json->setInteger("liveCount", info.liveCount[i]);
486 json->setInteger("deadCount", info.deadCount[i]);
487 json->setInteger("liveSize", info.liveSize[i]);
488 json->setInteger("deadSize", info.deadSize[i]);
489 liveSize += info.liveSize[i];
490 deadSize += info.deadSize[i];
491
492 json->beginArray("generations");
493 for (size_t j = 0; j < heapObjectGenerations; ++j)
494 json->pushInteger(info.generations[i][j]);
495 json->endArray();
496 json->endDictionary();
497 }
498 json->endArray();
499 json->setInteger("liveSize", liveSize);
500 json->setInteger("deadSize", deadSize);
501
502 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID("blink_gc", "ThreadState", this, json.re lease());
503 }
504 #endif
505
506 void ThreadState::pushWeakObjectPointerCallback(void* object, WeakPointerCallbac k callback)
507 {
508 CallbackStack::Item* slot = m_weakCallbackStack->allocateEntry(&m_weakCallba ckStack);
509 *slot = CallbackStack::Item(object, callback);
510 }
511
512 bool ThreadState::popAndInvokeWeakPointerCallback(Visitor* visitor)
513 {
514 return m_weakCallbackStack->popAndInvokeCallback<WeaknessProcessing>(&m_weak CallbackStack, visitor);
515 }
516
517 PersistentNode* ThreadState::globalRoots()
518 {
519 AtomicallyInitializedStatic(PersistentNode*, anchor = new PersistentAnchor);
520 return anchor;
521 }
522
523 Mutex& ThreadState::globalRootsMutex()
524 {
525 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
526 return mutex;
527 }
528
529 // Trigger garbage collection on a 50% increase in size, but not for
530 // less than 512kbytes.
531 bool ThreadState::increasedEnoughToGC(size_t newSize, size_t oldSize)
532 {
533 if (newSize < 1 << 19)
534 return false;
535 size_t limit = oldSize + (oldSize >> 1);
536 return newSize > limit;
537 }
538
539 // FIXME: The heuristics are local for a thread at this
540 // point. Consider using heuristics that take memory for all threads
541 // into account.
542 bool ThreadState::shouldGC()
543 {
544 // Do not GC during sweeping. We allow allocation during
545 // finalization, but those allocations are not allowed
546 // to lead to nested garbage collections.
547 return !m_sweepInProgress && increasedEnoughToGC(m_stats.totalObjectSpace(), m_statsAfterLastGC.totalObjectSpace());
548 }
549
550 // Trigger conservative garbage collection on a 100% increase in size,
551 // but not for less than 4Mbytes. If the system currently has a low
552 // collection rate, then require a 300% increase in size.
553 bool ThreadState::increasedEnoughToForceConservativeGC(size_t newSize, size_t ol dSize)
554 {
555 if (newSize < 1 << 22)
556 return false;
557 size_t limit = (m_lowCollectionRate ? 4 : 2) * oldSize;
558 return newSize > limit;
559 }
560
561 // FIXME: The heuristics are local for a thread at this
562 // point. Consider using heuristics that take memory for all threads
563 // into account.
564 bool ThreadState::shouldForceConservativeGC()
565 {
566 // Do not GC during sweeping. We allow allocation during
567 // finalization, but those allocations are not allowed
568 // to lead to nested garbage collections.
569 return !m_sweepInProgress && increasedEnoughToForceConservativeGC(m_stats.to talObjectSpace(), m_statsAfterLastGC.totalObjectSpace());
570 }
571
572 bool ThreadState::sweepRequested()
573 {
574 ASSERT(isAnyThreadInGC() || checkThread());
575 return m_sweepRequested;
576 }
577
578 void ThreadState::setSweepRequested()
579 {
580 // Sweep requested is set from the thread that initiates garbage
581 // collection which could be different from the thread for this
582 // thread state. Therefore the setting of m_sweepRequested needs a
583 // barrier.
584 atomicTestAndSetToOne(&m_sweepRequested);
585 }
586
587 void ThreadState::clearSweepRequested()
588 {
589 checkThread();
590 m_sweepRequested = 0;
591 }
592
593 bool ThreadState::gcRequested()
594 {
595 checkThread();
596 return m_gcRequested;
597 }
598
599 void ThreadState::setGCRequested()
600 {
601 checkThread();
602 m_gcRequested = true;
603 }
604
605 void ThreadState::clearGCRequested()
606 {
607 checkThread();
608 m_gcRequested = false;
609 }
610
611 void ThreadState::performPendingGC(StackState stackState)
612 {
613 if (stackState == NoHeapPointersOnStack) {
614 if (forcePreciseGCForTesting()) {
615 setForcePreciseGCForTesting(false);
616 Heap::collectAllGarbage();
617 } else if (gcRequested()) {
618 Heap::collectGarbage(NoHeapPointersOnStack);
619 }
620 }
621 }
622
623 void ThreadState::setForcePreciseGCForTesting(bool value)
624 {
625 checkThread();
626 m_forcePreciseGCForTesting = value;
627 }
628
629 bool ThreadState::forcePreciseGCForTesting()
630 {
631 checkThread();
632 return m_forcePreciseGCForTesting;
633 }
634
635 void ThreadState::makeConsistentForSweeping()
636 {
637 for (int i = 0; i < NumberOfHeaps; i++)
638 m_heaps[i]->makeConsistentForSweeping();
639 }
640
641 #if ENABLE(ASSERT)
642 bool ThreadState::isConsistentForSweeping()
643 {
644 for (int i = 0; i < NumberOfHeaps; i++) {
645 if (!m_heaps[i]->isConsistentForSweeping())
646 return false;
647 }
648 return true;
649 }
650 #endif
651
652 void ThreadState::prepareForGC()
653 {
654 for (int i = 0; i < NumberOfHeaps; i++) {
655 BaseHeap* heap = m_heaps[i];
656 heap->makeConsistentForSweeping();
657 // If a new GC is requested before this thread got around to sweep, ie. due to the
658 // thread doing a long running operation, we clear the mark bits and mar k any of
659 // the dead objects as dead. The latter is used to ensure the next GC ma rking does
660 // not trace already dead objects. If we trace a dead object we could en d up tracing
661 // into garbage or the middle of another object via the newly conservati vely found
662 // object.
663 if (sweepRequested())
664 heap->clearLiveAndMarkDead();
665 }
666 setSweepRequested();
667 }
668
669 void ThreadState::setupHeapsForTermination()
670 {
671 for (int i = 0; i < NumberOfHeaps; i++)
672 m_heaps[i]->prepareHeapForTermination();
673 }
674
675 BaseHeapPage* ThreadState::heapPageFromAddress(Address address)
676 {
677 BaseHeapPage* cachedPage = heapContainsCache()->lookup(address);
678 #if !ENABLE(ASSERT)
679 if (cachedPage)
680 return cachedPage;
681 #endif
682
683 for (int i = 0; i < NumberOfHeaps; i++) {
684 BaseHeapPage* page = m_heaps[i]->heapPageFromAddress(address);
685 if (page) {
686 // Asserts that make sure heapPageFromAddress takes addresses from
687 // the whole aligned blinkPageSize memory area. This is necessary
688 // for the negative cache to work.
689 ASSERT(page->isLargeObject() || page == m_heaps[i]->heapPageFromAddr ess(roundToBlinkPageStart(address)));
690 if (roundToBlinkPageStart(address) != roundToBlinkPageEnd(address))
691 ASSERT(page->isLargeObject() || page == m_heaps[i]->heapPageFrom Address(roundToBlinkPageEnd(address) - 1));
692 ASSERT(!cachedPage || page == cachedPage);
693 if (!cachedPage)
694 heapContainsCache()->addEntry(address, page);
695 return page;
696 }
697 }
698 ASSERT(!cachedPage);
699 return 0;
700 }
701
702 void ThreadState::getStats(HeapStats& stats)
703 {
704 stats = m_stats;
705 #if ENABLE(ASSERT)
706 if (isConsistentForSweeping()) {
707 HeapStats scannedStats;
708 for (int i = 0; i < NumberOfHeaps; i++)
709 m_heaps[i]->getScannedStats(scannedStats);
710 ASSERT(scannedStats == stats);
711 }
712 #endif
713 }
714
715 bool ThreadState::stopThreads()
716 {
717 return s_safePointBarrier->parkOthers();
718 }
719
720 void ThreadState::resumeThreads()
721 {
722 s_safePointBarrier->resumeOthers();
723 }
724
725 void ThreadState::safePoint(StackState stackState)
726 {
727 checkThread();
728 performPendingGC(stackState);
729 ASSERT(!m_atSafePoint);
730 m_stackState = stackState;
731 m_atSafePoint = true;
732 s_safePointBarrier->checkAndPark(this);
733 m_atSafePoint = false;
734 m_stackState = HeapPointersOnStack;
735 performPendingSweep();
736 }
737
738 #ifdef ADDRESS_SANITIZER
739 // When we are running under AddressSanitizer with detect_stack_use_after_return =1
740 // then stack marker obtained from SafePointScope will point into a fake stack.
741 // Detect this case by checking if it falls in between current stack frame
742 // and stack start and use an arbitrary high enough value for it.
743 // Don't adjust stack marker in any other case to match behavior of code running
744 // without AddressSanitizer.
745 NO_SANITIZE_ADDRESS static void* adjustScopeMarkerForAdressSanitizer(void* scope Marker)
746 {
747 Address start = reinterpret_cast<Address>(getStackStart());
748 Address end = reinterpret_cast<Address>(&start);
749 RELEASE_ASSERT(end < start);
750
751 if (end <= scopeMarker && scopeMarker < start)
752 return scopeMarker;
753
754 // 256 is as good an approximation as any else.
755 const size_t bytesToCopy = sizeof(Address) * 256;
756 if (static_cast<size_t>(start - end) < bytesToCopy)
757 return start;
758
759 return end + bytesToCopy;
760 }
761 #endif
762
763 void ThreadState::enterSafePoint(StackState stackState, void* scopeMarker)
764 {
765 #ifdef ADDRESS_SANITIZER
766 if (stackState == HeapPointersOnStack)
767 scopeMarker = adjustScopeMarkerForAdressSanitizer(scopeMarker);
768 #endif
769 ASSERT(stackState == NoHeapPointersOnStack || scopeMarker);
770 performPendingGC(stackState);
771 checkThread();
772 ASSERT(!m_atSafePoint);
773 m_atSafePoint = true;
774 m_stackState = stackState;
775 m_safePointScopeMarker = scopeMarker;
776 s_safePointBarrier->enterSafePoint(this);
777 }
778
779 void ThreadState::leaveSafePoint(SafePointAwareMutexLocker* locker)
780 {
781 checkThread();
782 ASSERT(m_atSafePoint);
783 s_safePointBarrier->leaveSafePoint(this, locker);
784 m_atSafePoint = false;
785 m_stackState = HeapPointersOnStack;
786 clearSafePointScopeMarker();
787 performPendingSweep();
788 }
789
790 void ThreadState::copyStackUntilSafePointScope()
791 {
792 if (!m_safePointScopeMarker || m_stackState == NoHeapPointersOnStack)
793 return;
794
795 Address* to = reinterpret_cast<Address*>(m_safePointScopeMarker);
796 Address* from = reinterpret_cast<Address*>(m_endOfStack);
797 RELEASE_ASSERT(from < to);
798 RELEASE_ASSERT(to <= reinterpret_cast<Address*>(m_startOfStack));
799 size_t slotCount = static_cast<size_t>(to - from);
800 // Catch potential performance issues.
801 #if defined(LEAK_SANITIZER) || defined(ADDRESS_SANITIZER)
802 // ASan/LSan use more space on the stack and we therefore
803 // increase the allowed stack copying for those builds.
804 ASSERT(slotCount < 2048);
805 #else
806 ASSERT(slotCount < 1024);
807 #endif
808
809 ASSERT(!m_safePointStackCopy.size());
810 m_safePointStackCopy.resize(slotCount);
811 for (size_t i = 0; i < slotCount; ++i) {
812 m_safePointStackCopy[i] = from[i];
813 }
814 }
815
816 void ThreadState::registerSweepingTask()
817 {
818 MutexLocker locker(m_sweepMutex);
819 ++m_numberOfSweeperTasks;
820 }
821
822 void ThreadState::unregisterSweepingTask()
823 {
824 MutexLocker locker(m_sweepMutex);
825 ASSERT(m_numberOfSweeperTasks > 0);
826 if (!--m_numberOfSweeperTasks)
827 m_sweepThreadCondition.signal();
828 }
829
830 void ThreadState::waitUntilSweepersDone()
831 {
832 MutexLocker locker(m_sweepMutex);
833 while (m_numberOfSweeperTasks > 0)
834 m_sweepThreadCondition.wait(m_sweepMutex);
835 }
836
837 void ThreadState::performPendingSweep()
838 {
839 }
840
841 void ThreadState::addInterruptor(Interruptor* interruptor)
842 {
843 SafePointScope scope(HeapPointersOnStack, SafePointScope::AllowNesting);
844
845 {
846 MutexLocker locker(threadAttachMutex());
847 m_interruptors.append(interruptor);
848 }
849 }
850
851 void ThreadState::removeInterruptor(Interruptor* interruptor)
852 {
853 SafePointScope scope(HeapPointersOnStack, SafePointScope::AllowNesting);
854
855 {
856 MutexLocker locker(threadAttachMutex());
857 size_t index = m_interruptors.find(interruptor);
858 RELEASE_ASSERT(index >= 0);
859 m_interruptors.remove(index);
860 }
861 }
862
863 void ThreadState::Interruptor::onInterrupted()
864 {
865 ThreadState* state = ThreadState::current();
866 ASSERT(state);
867 ASSERT(!state->isAtSafePoint());
868 state->safePoint(HeapPointersOnStack);
869 }
870
871 ThreadState::AttachedThreadStateSet& ThreadState::attachedThreads()
872 {
873 DEFINE_STATIC_LOCAL(AttachedThreadStateSet, threads, ());
874 return threads;
875 }
876
877 #if ENABLE(GC_PROFILE_MARKING)
878 const GCInfo* ThreadState::findGCInfoFromAllThreads(Address address)
879 {
880 bool needLockForIteration = !isAnyThreadInGC();
881 if (needLockForIteration)
882 threadAttachMutex().lock();
883
884 ThreadState::AttachedThreadStateSet& threads = attachedThreads();
885 for (ThreadState::AttachedThreadStateSet::iterator it = threads.begin(), end = threads.end(); it != end; ++it) {
886 if (const GCInfo* gcInfo = (*it)->findGCInfo(address)) {
887 if (needLockForIteration)
888 threadAttachMutex().unlock();
889 return gcInfo;
890 }
891 }
892 if (needLockForIteration)
893 threadAttachMutex().unlock();
894 return 0;
895 }
896 #endif
897
898 }
OLDNEW
« no previous file with comments | « sky/engine/platform/heap/ThreadState.h ('k') | sky/engine/platform/heap/Visitor.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698