OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)]; | 96 uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)]; |
97 SafePointBarrier* ThreadState::s_safePointBarrier = 0; | 97 SafePointBarrier* ThreadState::s_safePointBarrier = 0; |
98 bool ThreadState::s_inGC = false; | 98 bool ThreadState::s_inGC = false; |
99 | 99 |
100 static Mutex& threadAttachMutex() | 100 static Mutex& threadAttachMutex() |
101 { | 101 { |
102 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); | 102 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); |
103 return mutex; | 103 return mutex; |
104 } | 104 } |
105 | 105 |
| 106 // The threadShutdownMutex is used to synchronize thread shutdown |
| 107 // since the thread local GC, as of now, cannot run in parallel |
| 108 // with other thread local GCs since it is using the global marking |
| 109 // stack. It can also not run in parallel with a global GC, but |
| 110 // that is honored by not entering a safepoint while doing the |
| 111 // thread local GC, meaning a request for a global GC would time |
| 112 // out. |
| 113 static Mutex& threadShutdownMutex() |
| 114 { |
| 115 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); |
| 116 return mutex; |
| 117 } |
| 118 |
106 static double lockingTimeout() | 119 static double lockingTimeout() |
107 { | 120 { |
108 // Wait time for parking all threads is at most 100 MS. | 121 // Wait time for parking all threads is at most 100 MS. |
109 return 0.100; | 122 return 0.100; |
110 } | 123 } |
111 | 124 |
112 | 125 |
113 typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr
_t*); | 126 typedef void (*PushAllRegistersCallback)(SafePointBarrier*, ThreadState*, intptr
_t*); |
114 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste
rsCallback); | 127 extern "C" void pushAllRegisters(SafePointBarrier*, ThreadState*, PushAllRegiste
rsCallback); |
115 | 128 |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 barrier->doEnterSafePoint(state, stackEnd); | 267 barrier->doEnterSafePoint(state, stackEnd); |
255 } | 268 } |
256 | 269 |
257 volatile int m_canResume; | 270 volatile int m_canResume; |
258 volatile int m_unparkedThreadCount; | 271 volatile int m_unparkedThreadCount; |
259 Mutex m_mutex; | 272 Mutex m_mutex; |
260 ThreadCondition m_parked; | 273 ThreadCondition m_parked; |
261 ThreadCondition m_resume; | 274 ThreadCondition m_resume; |
262 }; | 275 }; |
263 | 276 |
| 277 |
| 278 BaseHeapPage::BaseHeapPage(PageMemory* storage, const GCInfo* gcInfo, ThreadStat
e* state) |
| 279 : m_storage(storage) |
| 280 , m_gcInfo(gcInfo) |
| 281 , m_threadState(state) |
| 282 , m_terminating(false) |
| 283 , m_tracedAfterOrphaned(false) |
| 284 { |
| 285 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); |
| 286 } |
| 287 |
264 ThreadState::ThreadState() | 288 ThreadState::ThreadState() |
265 : m_thread(currentThread()) | 289 : m_thread(currentThread()) |
266 , m_persistents(adoptPtr(new PersistentAnchor())) | 290 , m_persistents(adoptPtr(new PersistentAnchor())) |
267 , m_startOfStack(reinterpret_cast<intptr_t*>(getStackStart())) | 291 , m_startOfStack(reinterpret_cast<intptr_t*>(getStackStart())) |
268 , m_endOfStack(reinterpret_cast<intptr_t*>(getStackStart())) | 292 , m_endOfStack(reinterpret_cast<intptr_t*>(getStackStart())) |
269 , m_safePointScopeMarker(0) | 293 , m_safePointScopeMarker(0) |
270 , m_atSafePoint(false) | 294 , m_atSafePoint(false) |
271 , m_interruptors() | 295 , m_interruptors() |
272 , m_gcRequested(false) | 296 , m_gcRequested(false) |
273 , m_forcePreciseGCForTesting(false) | 297 , m_forcePreciseGCForTesting(false) |
274 , m_sweepRequested(0) | 298 , m_sweepRequested(0) |
275 , m_sweepInProgress(false) | 299 , m_sweepInProgress(false) |
276 , m_noAllocationCount(0) | 300 , m_noAllocationCount(0) |
277 , m_inGC(false) | 301 , m_inGC(false) |
278 , m_heapContainsCache(adoptPtr(new HeapContainsCache())) | 302 , m_heapContainsCache(adoptPtr(new HeapContainsCache())) |
279 , m_isCleaningUp(false) | 303 , m_isTerminating(false) |
280 #if defined(ADDRESS_SANITIZER) | 304 #if defined(ADDRESS_SANITIZER) |
281 , m_asanFakeStack(__asan_get_current_fake_stack()) | 305 , m_asanFakeStack(__asan_get_current_fake_stack()) |
282 #endif | 306 #endif |
283 { | 307 { |
284 ASSERT(!**s_threadSpecific); | 308 ASSERT(!**s_threadSpecific); |
285 **s_threadSpecific = this; | 309 **s_threadSpecific = this; |
286 | 310 |
287 m_stats.clear(); | 311 m_stats.clear(); |
288 m_statsAfterLastGC.clear(); | 312 m_statsAfterLastGC.clear(); |
289 // First allocate the general heap, second iterate through to | 313 // First allocate the general heap, second iterate through to |
290 // allocate the type specific heaps | 314 // allocate the type specific heaps |
291 m_heaps[GeneralHeap] = new ThreadHeap<FinalizedHeapObjectHeader>(this); | 315 m_heaps[GeneralHeap] = new ThreadHeap<FinalizedHeapObjectHeader>(this, Gener
alHeap); |
292 for (int i = GeneralHeap + 1; i < NumberOfHeaps; i++) | 316 for (int i = GeneralHeap + 1; i < NumberOfHeaps; i++) |
293 m_heaps[i] = new ThreadHeap<HeapObjectHeader>(this); | 317 m_heaps[i] = new ThreadHeap<HeapObjectHeader>(this, i); |
294 | 318 |
295 CallbackStack::init(&m_weakCallbackStack); | 319 CallbackStack::init(&m_weakCallbackStack); |
296 } | 320 } |
297 | 321 |
298 ThreadState::~ThreadState() | 322 ThreadState::~ThreadState() |
299 { | 323 { |
300 checkThread(); | 324 checkThread(); |
301 CallbackStack::shutdown(&m_weakCallbackStack); | 325 CallbackStack::shutdown(&m_weakCallbackStack); |
302 for (int i = GeneralHeap; i < NumberOfHeaps; i++) | 326 for (int i = GeneralHeap; i < NumberOfHeaps; i++) |
303 delete m_heaps[i]; | 327 delete m_heaps[i]; |
(...skipping 23 matching lines...) Expand all Loading... |
327 attachedThreads().add(state); | 351 attachedThreads().add(state); |
328 } | 352 } |
329 | 353 |
330 void ThreadState::detachMainThread() | 354 void ThreadState::detachMainThread() |
331 { | 355 { |
332 // Enter a safe point before trying to acquire threadAttachMutex | 356 // Enter a safe point before trying to acquire threadAttachMutex |
333 // to avoid dead lock if another thread is preparing for GC, has acquired | 357 // 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 | 358 // threadAttachMutex and waiting for other threads to pause or reach a |
335 // safepoint. | 359 // safepoint. |
336 ThreadState* state = mainThreadState(); | 360 ThreadState* state = mainThreadState(); |
337 if (!state->isAtSafePoint()) | |
338 state->enterSafePointWithoutPointers(); | |
339 | 361 |
340 { | 362 { |
341 MutexLocker locker(threadAttachMutex()); | 363 // We enter a safepoint while waiting for the thread shutdown mutex. |
342 state->leaveSafePoint(); | 364 SafePointAwareMutexLocker locker(threadShutdownMutex(), NoHeapPointersOn
Stack); |
| 365 |
| 366 // First add the main thread's heap pages to the orphaned pool. |
| 367 state->cleanupPages(); |
| 368 } |
| 369 { |
| 370 SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnSt
ack); |
343 ASSERT(attachedThreads().contains(state)); | 371 ASSERT(attachedThreads().contains(state)); |
344 attachedThreads().remove(state); | 372 attachedThreads().remove(state); |
345 state->~ThreadState(); | 373 state->~ThreadState(); |
346 } | 374 } |
347 shutdownHeapIfNecessary(); | 375 shutdownHeapIfNecessary(); |
348 } | 376 } |
349 | 377 |
350 void ThreadState::shutdownHeapIfNecessary() | 378 void ThreadState::shutdownHeapIfNecessary() |
351 { | 379 { |
352 // We don't need to enter a safe point before acquiring threadAttachMutex | 380 // We don't need to enter a safe point before acquiring threadAttachMutex |
353 // because this thread is already detached. | 381 // because this thread is already detached. |
354 | 382 |
355 MutexLocker locker(threadAttachMutex()); | 383 MutexLocker locker(threadAttachMutex()); |
356 // We start shutting down the heap if there is no running thread | 384 // We start shutting down the heap if there is no running thread |
357 // and Heap::shutdown() is already called. | 385 // and Heap::shutdown() is already called. |
358 if (!attachedThreads().size() && Heap::s_shutdownCalled) | 386 if (!attachedThreads().size() && Heap::s_shutdownCalled) |
359 Heap::doShutdown(); | 387 Heap::doShutdown(); |
360 } | 388 } |
361 | 389 |
362 void ThreadState::attach() | 390 void ThreadState::attach() |
363 { | 391 { |
364 RELEASE_ASSERT(!Heap::s_shutdownCalled); | 392 RELEASE_ASSERT(!Heap::s_shutdownCalled); |
365 MutexLocker locker(threadAttachMutex()); | 393 MutexLocker locker(threadAttachMutex()); |
366 ThreadState* state = new ThreadState(); | 394 ThreadState* state = new ThreadState(); |
367 attachedThreads().add(state); | 395 attachedThreads().add(state); |
368 } | 396 } |
369 | 397 |
| 398 void ThreadState::cleanupPages() |
| 399 { |
| 400 for (int i = GeneralHeap; i < NumberOfHeaps; ++i) |
| 401 m_heaps[i]->cleanupPages(); |
| 402 } |
| 403 |
370 void ThreadState::cleanup() | 404 void ThreadState::cleanup() |
371 { | 405 { |
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 | |
386 void ThreadState::preCleanup() | |
387 { | |
388 for (size_t i = 0; i < m_cleanupTasks.size(); i++) | 406 for (size_t i = 0; i < m_cleanupTasks.size(); i++) |
389 m_cleanupTasks[i]->preCleanup(); | 407 m_cleanupTasks[i]->preCleanup(); |
390 } | |
391 | 408 |
392 void ThreadState::postCleanup() | 409 { |
393 { | 410 // We enter a safepoint while waiting for the thread shutdown mutex. |
| 411 SafePointAwareMutexLocker locker(threadShutdownMutex(), NoHeapPointersOn
Stack); |
| 412 |
| 413 // From here on ignore all conservatively discovered |
| 414 // pointers into the heap owned by this thread. |
| 415 m_isTerminating = true; |
| 416 |
| 417 // Set the terminate flag on all heap pages of this thread. This is used
to |
| 418 // ensure we don't trace pages on other threads that are not part of the |
| 419 // thread local GC. |
| 420 setupHeapsForTermination(); |
| 421 |
| 422 // Do thread local GC's as long as the count of thread local Persistents |
| 423 // changes and is above zero. |
| 424 PersistentAnchor* anchor = static_cast<PersistentAnchor*>(m_persistents.
get()); |
| 425 int oldCount = -1; |
| 426 int currentCount = anchor->numberOfPersistents(); |
| 427 ASSERT(currentCount >= 0); |
| 428 while (currentCount != oldCount) { |
| 429 Heap::collectGarbageForTerminatingThread(this); |
| 430 oldCount = currentCount; |
| 431 currentCount = anchor->numberOfPersistents(); |
| 432 } |
| 433 // We should not have any persistents left when getting to this point, |
| 434 // if we have it is probably a bug so adding a debug ASSERT to catch thi
s. |
| 435 ASSERT(!currentCount); |
| 436 |
| 437 // Add pages to the orphaned page pool to ensure any global GCs from thi
s point |
| 438 // on will not trace objects on this thread's heaps. |
| 439 cleanupPages(); |
| 440 } |
| 441 |
| 442 { |
| 443 // Enter a safe point while trying to acquire threadAttachMutex |
| 444 // to avoid dead lock if another thread is preparing for GC, has acquire
d |
| 445 // threadAttachMutex and waiting for other threads to pause or reach a |
| 446 // safepoint. |
| 447 SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnSt
ack); |
| 448 ASSERT(attachedThreads().contains(this)); |
| 449 attachedThreads().remove(this); |
| 450 } |
| 451 |
394 for (size_t i = 0; i < m_cleanupTasks.size(); i++) | 452 for (size_t i = 0; i < m_cleanupTasks.size(); i++) |
395 m_cleanupTasks[i]->postCleanup(); | 453 m_cleanupTasks[i]->postCleanup(); |
396 m_cleanupTasks.clear(); | 454 m_cleanupTasks.clear(); |
397 } | 455 } |
398 | 456 |
| 457 |
399 void ThreadState::detach() | 458 void ThreadState::detach() |
400 { | 459 { |
401 ThreadState* state = current(); | 460 ThreadState* state = current(); |
402 state->preCleanup(); | |
403 state->cleanup(); | 461 state->cleanup(); |
404 | 462 delete state; |
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(); | 463 shutdownHeapIfNecessary(); |
421 } | 464 } |
422 | 465 |
423 void ThreadState::visitRoots(Visitor* visitor) | 466 void ThreadState::visitRoots(Visitor* visitor) |
424 { | 467 { |
425 { | 468 { |
426 // All threads are at safepoints so this is not strictly necessary. | 469 // All threads are at safepoints so this is not strictly necessary. |
427 // However we acquire the mutex to make mutation and traversal of this | 470 // However we acquire the mutex to make mutation and traversal of this |
428 // list symmetrical. | 471 // list symmetrical. |
429 MutexLocker locker(globalRootsMutex()); | 472 MutexLocker locker(globalRootsMutex()); |
430 globalRoots()->trace(visitor); | 473 globalRoots()->trace(visitor); |
431 } | 474 } |
432 | 475 |
433 AttachedThreadStateSet& threads = attachedThreads(); | 476 AttachedThreadStateSet& threads = attachedThreads(); |
434 for (AttachedThreadStateSet::iterator it = threads.begin(), end = threads.en
d(); it != end; ++it) | 477 for (AttachedThreadStateSet::iterator it = threads.begin(), end = threads.en
d(); it != end; ++it) |
435 (*it)->trace(visitor); | 478 (*it)->trace(visitor); |
436 } | 479 } |
437 | 480 |
| 481 void ThreadState::visitLocalRoots(Visitor* visitor) |
| 482 { |
| 483 // We assume that orphaned pages have no objects reachable from persistent |
| 484 // handles on other threads or CrossThreadPersistents. The only cases where |
| 485 // this could happen is if a global conservative GC finds a "pointer" on |
| 486 // the stack or due to a programming error where an object has a dangling |
| 487 // cross-thread pointer to an object on this heap. |
| 488 m_persistents->trace(visitor); |
| 489 } |
| 490 |
438 NO_SANITIZE_ADDRESS | 491 NO_SANITIZE_ADDRESS |
439 void ThreadState::visitAsanFakeStackForPointer(Visitor* visitor, Address ptr) | 492 void ThreadState::visitAsanFakeStackForPointer(Visitor* visitor, Address ptr) |
440 { | 493 { |
441 #if defined(ADDRESS_SANITIZER) | 494 #if defined(ADDRESS_SANITIZER) |
442 Address* start = reinterpret_cast<Address*>(m_startOfStack); | 495 Address* start = reinterpret_cast<Address*>(m_startOfStack); |
443 Address* end = reinterpret_cast<Address*>(m_endOfStack); | 496 Address* end = reinterpret_cast<Address*>(m_endOfStack); |
444 Address* fakeFrameStart = 0; | 497 Address* fakeFrameStart = 0; |
445 Address* fakeFrameEnd = 0; | 498 Address* fakeFrameEnd = 0; |
446 Address* maybeFakeFrame = reinterpret_cast<Address*>(ptr); | 499 Address* maybeFakeFrame = reinterpret_cast<Address*>(ptr); |
447 Address* realFrameForFakeFrame = | 500 Address* realFrameForFakeFrame = |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 | 565 |
513 void ThreadState::trace(Visitor* visitor) | 566 void ThreadState::trace(Visitor* visitor) |
514 { | 567 { |
515 if (m_stackState == HeapPointersOnStack) | 568 if (m_stackState == HeapPointersOnStack) |
516 visitStack(visitor); | 569 visitStack(visitor); |
517 visitPersistents(visitor); | 570 visitPersistents(visitor); |
518 } | 571 } |
519 | 572 |
520 bool ThreadState::checkAndMarkPointer(Visitor* visitor, Address address) | 573 bool ThreadState::checkAndMarkPointer(Visitor* visitor, Address address) |
521 { | 574 { |
522 // If thread is cleaning up ignore conservative pointers. | 575 // If thread is terminating ignore conservative pointers. |
523 if (m_isCleaningUp) | 576 if (m_isTerminating) |
524 return false; | 577 return false; |
525 | 578 |
526 // This checks for normal pages and for large objects which span the extent | 579 // This checks for normal pages and for large objects which span the extent |
527 // of several normal pages. | 580 // of several normal pages. |
528 BaseHeapPage* page = heapPageFromAddress(address); | 581 BaseHeapPage* page = heapPageFromAddress(address); |
529 if (page) { | 582 if (page) { |
530 page->checkAndMarkPointer(visitor, address); | 583 page->checkAndMarkPointer(visitor, address); |
531 // Whether or not the pointer was within an object it was certainly | 584 // 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 | 585 // 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 | 586 // other other heaps or put this address in the |
(...skipping 16 matching lines...) Expand all Loading... |
550 #endif | 603 #endif |
551 | 604 |
552 void ThreadState::pushWeakObjectPointerCallback(void* object, WeakPointerCallbac
k callback) | 605 void ThreadState::pushWeakObjectPointerCallback(void* object, WeakPointerCallbac
k callback) |
553 { | 606 { |
554 CallbackStack::Item* slot = m_weakCallbackStack->allocateEntry(&m_weakCallba
ckStack); | 607 CallbackStack::Item* slot = m_weakCallbackStack->allocateEntry(&m_weakCallba
ckStack); |
555 *slot = CallbackStack::Item(object, callback); | 608 *slot = CallbackStack::Item(object, callback); |
556 } | 609 } |
557 | 610 |
558 bool ThreadState::popAndInvokeWeakPointerCallback(Visitor* visitor) | 611 bool ThreadState::popAndInvokeWeakPointerCallback(Visitor* visitor) |
559 { | 612 { |
560 return m_weakCallbackStack->popAndInvokeCallback(&m_weakCallbackStack, visit
or); | 613 return m_weakCallbackStack->popAndInvokeCallback<WeaknessProcessing>(&m_weak
CallbackStack, visitor); |
561 } | 614 } |
562 | 615 |
563 PersistentNode* ThreadState::globalRoots() | 616 PersistentNode* ThreadState::globalRoots() |
564 { | 617 { |
565 AtomicallyInitializedStatic(PersistentNode*, anchor = new PersistentAnchor); | 618 AtomicallyInitializedStatic(PersistentNode*, anchor = new PersistentAnchor); |
566 return anchor; | 619 return anchor; |
567 } | 620 } |
568 | 621 |
569 Mutex& ThreadState::globalRootsMutex() | 622 Mutex& ThreadState::globalRootsMutex() |
570 { | 623 { |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 { | 741 { |
689 for (int i = 0; i < NumberOfHeaps; i++) | 742 for (int i = 0; i < NumberOfHeaps; i++) |
690 m_heaps[i]->makeConsistentForGC(); | 743 m_heaps[i]->makeConsistentForGC(); |
691 } | 744 } |
692 | 745 |
693 void ThreadState::prepareForGC() | 746 void ThreadState::prepareForGC() |
694 { | 747 { |
695 for (int i = 0; i < NumberOfHeaps; i++) { | 748 for (int i = 0; i < NumberOfHeaps; i++) { |
696 BaseHeap* heap = m_heaps[i]; | 749 BaseHeap* heap = m_heaps[i]; |
697 heap->makeConsistentForGC(); | 750 heap->makeConsistentForGC(); |
698 // If there are parked threads with outstanding sweep requests, clear th
eir mark bits. | 751 // If a new GC is requested before this thread got around to sweep, ie.
due to the |
699 // This happens if a thread did not have time to wake up and sweep, | 752 // thread doing a long running operation, we clear the mark bits and mar
k any of |
700 // before the next GC arrived. | 753 // the dead objects as dead. The latter is used to ensure the next GC ma
rking does |
| 754 // not trace already dead objects. If we trace a dead object we could en
d up tracing |
| 755 // into garbage or the middle of another object via the newly conservati
vely found |
| 756 // object. |
701 if (sweepRequested()) | 757 if (sweepRequested()) |
702 heap->clearMarks(); | 758 heap->clearLiveAndMarkDead(); |
703 } | 759 } |
704 setSweepRequested(); | 760 setSweepRequested(); |
705 } | 761 } |
706 | 762 |
| 763 void ThreadState::setupHeapsForTermination() |
| 764 { |
| 765 for (int i = 0; i < NumberOfHeaps; i++) |
| 766 m_heaps[i]->prepareHeapForTermination(); |
| 767 } |
| 768 |
707 BaseHeapPage* ThreadState::heapPageFromAddress(Address address) | 769 BaseHeapPage* ThreadState::heapPageFromAddress(Address address) |
708 { | 770 { |
709 BaseHeapPage* cachedPage = heapContainsCache()->lookup(address); | 771 BaseHeapPage* cachedPage = heapContainsCache()->lookup(address); |
710 #ifdef NDEBUG | 772 #ifdef NDEBUG |
711 if (cachedPage) | 773 if (cachedPage) |
712 return cachedPage; | 774 return cachedPage; |
713 #endif | 775 #endif |
714 | 776 |
715 for (int i = 0; i < NumberOfHeaps; i++) { | 777 for (int i = 0; i < NumberOfHeaps; i++) { |
716 BaseHeapPage* page = m_heaps[i]->heapPageFromAddress(address); | 778 BaseHeapPage* page = m_heaps[i]->heapPageFromAddress(address); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
925 threadAttachMutex().unlock(); | 987 threadAttachMutex().unlock(); |
926 return gcInfo; | 988 return gcInfo; |
927 } | 989 } |
928 } | 990 } |
929 if (needLockForIteration) | 991 if (needLockForIteration) |
930 threadAttachMutex().unlock(); | 992 threadAttachMutex().unlock(); |
931 return 0; | 993 return 0; |
932 } | 994 } |
933 #endif | 995 #endif |
934 } | 996 } |
OLD | NEW |