blob: c769a14fb7849901c8a872084cda29201b3a2bb4 [file] [log] [blame]
// 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 &not_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_