| 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 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 | 309 |
| 310 // Associate ThreadState object with the current thread. After this | 310 // Associate ThreadState object with the current thread. After this |
| 311 // call thread can start using the garbage collected heap infrastructure. | 311 // call thread can start using the garbage collected heap infrastructure. |
| 312 // It also has to periodically check for safepoints. | 312 // It also has to periodically check for safepoints. |
| 313 static void attach(); | 313 static void attach(); |
| 314 | 314 |
| 315 // Disassociate attached ThreadState from the current thread. The thread | 315 // Disassociate attached ThreadState from the current thread. The thread |
| 316 // can no longer use the garbage collected heap after this call. | 316 // can no longer use the garbage collected heap after this call. |
| 317 static void detach(); | 317 static void detach(); |
| 318 | 318 |
| 319 static ThreadState* current() { return **s_threadSpecific; } | |
| 320 static ThreadState* mainThreadState() | 319 static ThreadState* mainThreadState() |
| 321 { | 320 { |
| 322 return reinterpret_cast<ThreadState*>(s_mainThreadStateStorage); | 321 return reinterpret_cast<ThreadState*>(s_mainThreadStateStorage); |
| 323 } | 322 } |
| 324 | 323 |
| 325 bool isMainThread() const { return this == mainThreadState(); } | 324 bool isMainThread() const { return this == mainThreadState(); } |
| 326 inline bool checkThread() const | 325 inline bool checkThread() const |
| 327 { | 326 { |
| 328 ASSERT(m_thread == currentThread()); | 327 ASSERT(m_thread == currentThread()); |
| 329 return true; | 328 return true; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 // Check if GC is requested by another thread and pause this thread if this
is the case. | 431 // Check if GC is requested by another thread and pause this thread if this
is the case. |
| 433 // Can only be called when current thread is in a consistent state. | 432 // Can only be called when current thread is in a consistent state. |
| 434 void safePoint(StackState); | 433 void safePoint(StackState); |
| 435 | 434 |
| 436 // Mark current thread as running inside safepoint. | 435 // Mark current thread as running inside safepoint. |
| 437 void enterSafePointWithoutPointers() { enterSafePoint(NoHeapPointersOnStack,
0); } | 436 void enterSafePointWithoutPointers() { enterSafePoint(NoHeapPointersOnStack,
0); } |
| 438 void enterSafePointWithPointers(void* scopeMarker) { enterSafePoint(HeapPoin
tersOnStack, scopeMarker); } | 437 void enterSafePointWithPointers(void* scopeMarker) { enterSafePoint(HeapPoin
tersOnStack, scopeMarker); } |
| 439 void leaveSafePoint(SafePointAwareMutexLocker* = 0); | 438 void leaveSafePoint(SafePointAwareMutexLocker* = 0); |
| 440 bool isAtSafePoint() const { return m_atSafePoint; } | 439 bool isAtSafePoint() const { return m_atSafePoint; } |
| 441 | 440 |
| 442 class SafePointScope { | |
| 443 public: | |
| 444 enum ScopeNesting { | |
| 445 NoNesting, | |
| 446 AllowNesting | |
| 447 }; | |
| 448 | |
| 449 explicit SafePointScope(StackState stackState, ScopeNesting nesting = No
Nesting) | |
| 450 : m_state(ThreadState::current()) | |
| 451 { | |
| 452 if (m_state->isAtSafePoint()) { | |
| 453 RELEASE_ASSERT(nesting == AllowNesting); | |
| 454 // We can ignore stackState because there should be no heap obje
ct | |
| 455 // pointers manipulation after outermost safepoint was entered. | |
| 456 m_state = 0; | |
| 457 } else { | |
| 458 m_state->enterSafePoint(stackState, this); | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 ~SafePointScope() | |
| 463 { | |
| 464 if (m_state) | |
| 465 m_state->leaveSafePoint(); | |
| 466 } | |
| 467 | |
| 468 private: | |
| 469 ThreadState* m_state; | |
| 470 }; | |
| 471 | |
| 472 // If attached thread enters long running loop that can call back | 441 // If attached thread enters long running loop that can call back |
| 473 // into Blink and leaving and reentering safepoint at every | 442 // into Blink and leaving and reentering safepoint at every |
| 474 // transition between this loop and Blink is deemed too expensive | 443 // transition between this loop and Blink is deemed too expensive |
| 475 // then instead of marking this loop as a GC safepoint thread | 444 // then instead of marking this loop as a GC safepoint thread |
| 476 // can provide an interruptor object which would allow GC | 445 // can provide an interruptor object which would allow GC |
| 477 // to temporarily interrupt and pause this long running loop at | 446 // to temporarily interrupt and pause this long running loop at |
| 478 // an arbitrary moment creating a safepoint for a GC. | 447 // an arbitrary moment creating a safepoint for a GC. |
| 479 class PLATFORM_EXPORT Interruptor { | 448 class PLATFORM_EXPORT Interruptor { |
| 480 public: | 449 public: |
| 481 virtual ~Interruptor() { } | 450 virtual ~Interruptor() { } |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 606 void registerSweepingTask(); | 575 void registerSweepingTask(); |
| 607 void unregisterSweepingTask(); | 576 void unregisterSweepingTask(); |
| 608 | 577 |
| 609 Mutex& sweepMutex() { return m_sweepMutex; } | 578 Mutex& sweepMutex() { return m_sweepMutex; } |
| 610 | 579 |
| 611 private: | 580 private: |
| 612 explicit ThreadState(); | 581 explicit ThreadState(); |
| 613 ~ThreadState(); | 582 ~ThreadState(); |
| 614 | 583 |
| 615 friend class SafePointBarrier; | 584 friend class SafePointBarrier; |
| 616 friend class SafePointAwareMutexLocker; | |
| 617 | 585 |
| 618 void enterSafePoint(StackState, void*); | 586 void enterSafePoint(StackState, void*); |
| 619 NO_SANITIZE_ADDRESS void copyStackUntilSafePointScope(); | 587 NO_SANITIZE_ADDRESS void copyStackUntilSafePointScope(); |
| 620 void clearSafePointScopeMarker() | 588 void clearSafePointScopeMarker() |
| 621 { | 589 { |
| 622 m_safePointStackCopy.clear(); | 590 m_safePointStackCopy.clear(); |
| 623 m_safePointScopeMarker = 0; | 591 m_safePointScopeMarker = 0; |
| 624 } | 592 } |
| 625 | 593 |
| 626 void performPendingGC(StackState); | 594 void performPendingGC(StackState); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 #endif | 666 #endif |
| 699 }; | 667 }; |
| 700 | 668 |
| 701 template<ThreadAffinity affinity> class ThreadStateFor; | 669 template<ThreadAffinity affinity> class ThreadStateFor; |
| 702 | 670 |
| 703 template<> class ThreadStateFor<MainThreadOnly> { | 671 template<> class ThreadStateFor<MainThreadOnly> { |
| 704 public: | 672 public: |
| 705 static ThreadState* state() | 673 static ThreadState* state() |
| 706 { | 674 { |
| 707 // This specialization must only be used from the main thread. | 675 // This specialization must only be used from the main thread. |
| 708 ASSERT(ThreadState::current()->isMainThread()); | |
| 709 return ThreadState::mainThreadState(); | 676 return ThreadState::mainThreadState(); |
| 710 } | 677 } |
| 711 }; | 678 }; |
| 712 | 679 |
| 713 template<> class ThreadStateFor<AnyThread> { | 680 template<> class ThreadStateFor<AnyThread> { |
| 714 public: | 681 public: |
| 715 static ThreadState* state() { return ThreadState::current(); } | 682 static ThreadState* state() { return 0; } |
| 716 }; | |
| 717 | |
| 718 // The SafePointAwareMutexLocker is used to enter a safepoint while waiting for | |
| 719 // a mutex lock. It also ensures that the lock is not held while waiting for a G
C | |
| 720 // to complete in the leaveSafePoint method, by releasing the lock if the | |
| 721 // leaveSafePoint method cannot complete without blocking, see | |
| 722 // SafePointBarrier::checkAndPark. | |
| 723 class SafePointAwareMutexLocker { | |
| 724 WTF_MAKE_NONCOPYABLE(SafePointAwareMutexLocker); | |
| 725 public: | |
| 726 explicit SafePointAwareMutexLocker(MutexBase& mutex, ThreadState::StackState
stackState = ThreadState::HeapPointersOnStack) | |
| 727 : m_mutex(mutex) | |
| 728 , m_locked(false) | |
| 729 { | |
| 730 ThreadState* state = ThreadState::current(); | |
| 731 do { | |
| 732 bool leaveSafePoint = false; | |
| 733 // We cannot enter a safepoint if we are currently sweeping. In that | |
| 734 // case we just try to acquire the lock without being at a safepoint
. | |
| 735 // If another thread tries to do a GC at that time it might time out | |
| 736 // due to this thread not being at a safepoint and waiting on the lo
ck. | |
| 737 if (!state->isSweepInProgress() && !state->isAtSafePoint()) { | |
| 738 state->enterSafePoint(stackState, this); | |
| 739 leaveSafePoint = true; | |
| 740 } | |
| 741 m_mutex.lock(); | |
| 742 m_locked = true; | |
| 743 if (leaveSafePoint) { | |
| 744 // When leaving the safepoint we might end up release the mutex | |
| 745 // if another thread is requesting a GC, see | |
| 746 // SafePointBarrier::checkAndPark. This is the case where we | |
| 747 // loop around to reacquire the lock. | |
| 748 state->leaveSafePoint(this); | |
| 749 } | |
| 750 } while (!m_locked); | |
| 751 } | |
| 752 | |
| 753 ~SafePointAwareMutexLocker() | |
| 754 { | |
| 755 ASSERT(m_locked); | |
| 756 m_mutex.unlock(); | |
| 757 } | |
| 758 | |
| 759 private: | |
| 760 friend class SafePointBarrier; | |
| 761 | |
| 762 void reset() | |
| 763 { | |
| 764 ASSERT(m_locked); | |
| 765 m_mutex.unlock(); | |
| 766 m_locked = false; | |
| 767 } | |
| 768 | |
| 769 MutexBase& m_mutex; | |
| 770 bool m_locked; | |
| 771 }; | 683 }; |
| 772 | 684 |
| 773 // Common header for heap pages. Needs to be defined before class Visitor. | 685 // Common header for heap pages. Needs to be defined before class Visitor. |
| 774 class BaseHeapPage { | 686 class BaseHeapPage { |
| 775 public: | 687 public: |
| 776 BaseHeapPage(PageMemory*, const GCInfo*, ThreadState*); | 688 BaseHeapPage(PageMemory*, const GCInfo*, ThreadState*); |
| 777 virtual ~BaseHeapPage() { } | 689 virtual ~BaseHeapPage() { } |
| 778 | 690 |
| 779 // Check if the given address points to an object in this | 691 // Check if the given address points to an object in this |
| 780 // heap page. If so, find the start of that object and mark it | 692 // heap page. If so, find the start of that object and mark it |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 // whether the page is part of a terminting thread or | 733 // whether the page is part of a terminting thread or |
| 822 // if the page is traced after being terminated (orphaned). | 734 // if the page is traced after being terminated (orphaned). |
| 823 uintptr_t m_terminating : 1; | 735 uintptr_t m_terminating : 1; |
| 824 uintptr_t m_tracedAfterOrphaned : 1; | 736 uintptr_t m_tracedAfterOrphaned : 1; |
| 825 uintptr_t m_promptlyFreedSize : 17; // == blinkPageSizeLog2 | 737 uintptr_t m_promptlyFreedSize : 17; // == blinkPageSizeLog2 |
| 826 }; | 738 }; |
| 827 | 739 |
| 828 } | 740 } |
| 829 | 741 |
| 830 #endif // ThreadState_h | 742 #endif // ThreadState_h |
| OLD | NEW |