| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_HEAP_CPPGC_MARKING_WORKLISTS_H_ |
| #define V8_HEAP_CPPGC_MARKING_WORKLISTS_H_ |
| |
| #include <unordered_set> |
| |
| #include "include/cppgc/visitor.h" |
| #include "src/base/platform/mutex.h" |
| #include "src/heap/base/worklist.h" |
| #include "src/heap/cppgc/heap-object-header.h" |
| |
| namespace cppgc { |
| namespace internal { |
| |
| class MarkingWorklists { |
| private: |
| class V8_EXPORT_PRIVATE ExternalMarkingWorklist { |
| public: |
| template <AccessMode = AccessMode::kNonAtomic> |
| void Push(HeapObjectHeader*); |
| template <AccessMode = AccessMode::kNonAtomic> |
| void Erase(HeapObjectHeader*); |
| template <AccessMode = AccessMode::kNonAtomic> |
| bool Contains(HeapObjectHeader*); |
| template <AccessMode = AccessMode::kNonAtomic> |
| std::unordered_set<HeapObjectHeader*> Extract(); |
| template <AccessMode = AccessMode::kNonAtomic> |
| void Clear(); |
| template <AccessMode = AccessMode::kNonAtomic> |
| bool IsEmpty(); |
| |
| ~ExternalMarkingWorklist(); |
| |
| private: |
| template <AccessMode> |
| struct ConditionalMutexGuard; |
| |
| void* operator new(size_t) = delete; |
| void* operator new[](size_t) = delete; |
| void operator delete(void*) = delete; |
| void operator delete[](void*) = delete; |
| |
| v8::base::Mutex lock_; |
| std::unordered_set<HeapObjectHeader*> objects_; |
| }; |
| |
| public: |
| static constexpr int kMutatorThreadId = 0; |
| |
| using MarkingItem = cppgc::TraceDescriptor; |
| |
| struct WeakCallbackItem { |
| cppgc::WeakCallback callback; |
| const void* parameter; |
| }; |
| |
| struct ConcurrentMarkingBailoutItem { |
| const void* parameter; |
| TraceCallback callback; |
| size_t bailedout_size; |
| }; |
| |
| struct EphemeronPairItem { |
| const void* key; |
| TraceDescriptor value_desc; |
| }; |
| |
| // Segment size of 512 entries necessary to avoid throughput regressions. |
| // Since the work list is currently a temporary object this is not a problem. |
| using MarkingWorklist = |
| heap::base::Worklist<MarkingItem, 512 /* local entries */>; |
| using NotFullyConstructedWorklist = ExternalMarkingWorklist; |
| using PreviouslyNotFullyConstructedWorklist = |
| heap::base::Worklist<HeapObjectHeader*, 16 /* local entries */>; |
| using WeakCallbackWorklist = |
| heap::base::Worklist<WeakCallbackItem, 64 /* local entries */>; |
| using WriteBarrierWorklist = |
| heap::base::Worklist<HeapObjectHeader*, 64 /*local entries */>; |
| using ConcurrentMarkingBailoutWorklist = |
| heap::base::Worklist<ConcurrentMarkingBailoutItem, |
| 64 /* local entries */>; |
| using EphemeronPairsWorklist = |
| heap::base::Worklist<EphemeronPairItem, 64 /* local entries */>; |
| using WeakContainersWorklist = ExternalMarkingWorklist; |
| |
| MarkingWorklist* marking_worklist() { return &marking_worklist_; } |
| NotFullyConstructedWorklist* not_fully_constructed_worklist() { |
| return ¬_fully_constructed_worklist_; |
| } |
| PreviouslyNotFullyConstructedWorklist* |
| previously_not_fully_constructed_worklist() { |
| return &previously_not_fully_constructed_worklist_; |
| } |
| WriteBarrierWorklist* write_barrier_worklist() { |
| return &write_barrier_worklist_; |
| } |
| WeakCallbackWorklist* weak_callback_worklist() { |
| return &weak_callback_worklist_; |
| } |
| ConcurrentMarkingBailoutWorklist* concurrent_marking_bailout_worklist() { |
| return &concurrent_marking_bailout_worklist_; |
| } |
| EphemeronPairsWorklist* discovered_ephemeron_pairs_worklist() { |
| return &discovered_ephemeron_pairs_worklist_; |
| } |
| EphemeronPairsWorklist* ephemeron_pairs_for_processing_worklist() { |
| return &ephemeron_pairs_for_processing_worklist_; |
| } |
| WeakContainersWorklist* weak_containers_worklist() { |
| return &weak_containers_worklist_; |
| } |
| |
| void ClearForTesting(); |
| |
| private: |
| MarkingWorklist marking_worklist_; |
| NotFullyConstructedWorklist not_fully_constructed_worklist_; |
| PreviouslyNotFullyConstructedWorklist |
| previously_not_fully_constructed_worklist_; |
| WriteBarrierWorklist write_barrier_worklist_; |
| WeakCallbackWorklist weak_callback_worklist_; |
| ConcurrentMarkingBailoutWorklist concurrent_marking_bailout_worklist_; |
| EphemeronPairsWorklist discovered_ephemeron_pairs_worklist_; |
| EphemeronPairsWorklist ephemeron_pairs_for_processing_worklist_; |
| WeakContainersWorklist weak_containers_worklist_; |
| }; |
| |
| template <> |
| struct MarkingWorklists::ExternalMarkingWorklist::ConditionalMutexGuard< |
| AccessMode::kNonAtomic> { |
| explicit ConditionalMutexGuard(v8::base::Mutex*) {} |
| }; |
| |
| template <> |
| struct MarkingWorklists::ExternalMarkingWorklist::ConditionalMutexGuard< |
| AccessMode::kAtomic> { |
| explicit ConditionalMutexGuard(v8::base::Mutex* lock) : guard_(lock) {} |
| |
| private: |
| v8::base::MutexGuard guard_; |
| }; |
| |
| template <AccessMode mode> |
| void MarkingWorklists::ExternalMarkingWorklist::Push(HeapObjectHeader* object) { |
| DCHECK_NOT_NULL(object); |
| ConditionalMutexGuard<mode> guard(&lock_); |
| objects_.insert(object); |
| } |
| |
| template <AccessMode mode> |
| void MarkingWorklists::ExternalMarkingWorklist::Erase( |
| HeapObjectHeader* object) { |
| DCHECK_NOT_NULL(object); |
| ConditionalMutexGuard<mode> guard(&lock_); |
| objects_.erase(object); |
| } |
| |
| template <AccessMode mode> |
| bool MarkingWorklists::ExternalMarkingWorklist::Contains( |
| HeapObjectHeader* object) { |
| ConditionalMutexGuard<mode> guard(&lock_); |
| return objects_.find(object) != objects_.end(); |
| } |
| |
| template <AccessMode mode> |
| std::unordered_set<HeapObjectHeader*> |
| MarkingWorklists::ExternalMarkingWorklist::Extract() { |
| ConditionalMutexGuard<mode> guard(&lock_); |
| std::unordered_set<HeapObjectHeader*> extracted; |
| std::swap(extracted, objects_); |
| DCHECK(objects_.empty()); |
| return extracted; |
| } |
| |
| template <AccessMode mode> |
| void MarkingWorklists::ExternalMarkingWorklist::Clear() { |
| ConditionalMutexGuard<mode> guard(&lock_); |
| objects_.clear(); |
| } |
| |
| template <AccessMode mode> |
| bool MarkingWorklists::ExternalMarkingWorklist::IsEmpty() { |
| ConditionalMutexGuard<mode> guard(&lock_); |
| return objects_.empty(); |
| } |
| |
| } // namespace internal |
| } // namespace cppgc |
| |
| #endif // V8_HEAP_CPPGC_MARKING_WORKLISTS_H_ |