5#ifndef V8_HEAP_BASE_WORKLIST_H_
6#define V8_HEAP_BASE_WORKLIST_H_
23 explicit constexpr SegmentBase(uint16_t capacity) : capacity_(capacity) {}
40 static void EnforcePredictableOrder();
56template <
typename EntryType, u
int16_t MinSegmentSize>
89 template <
typename Callback>
93 template <
typename Callback>
97 void Push(Segment* segment);
98 bool Pop(Segment** segment);
105template <
typename EntryType, u
int16_t MinSegmentSize>
111 size_.fetch_add(1, std::memory_order_relaxed);
114template <
typename EntryType, u
int16_t MinSegmentSize>
117 if (top_ ==
nullptr)
return false;
119 size_.fetch_sub(1, std::memory_order_relaxed);
125template <
typename EntryType, u
int16_t MinSegmentSize>
130template <
typename EntryType, u
int16_t MinSegmentSize>
135 return size_.load(std::memory_order_relaxed);
138template <
typename EntryType, u
int16_t MinSegmentSize>
141 size_.store(0, std::memory_order_relaxed);
143 while (current !=
nullptr) {
145 current = current->
next();
146 Segment::Delete(tmp);
151template <
typename EntryType, u
int16_t MinSegmentSize>
152template <
typename Callback>
157 size_t num_deleted = 0;
158 while (current !=
nullptr) {
160 if (current->IsEmpty()) {
163 if (prev ==
nullptr) {
164 top_ = current->next();
169 current = current->
next();
170 Segment::Delete(tmp);
173 current = current->
next();
176 size_.fetch_sub(num_deleted, std::memory_order_relaxed);
179template <
typename EntryType, u
int16_t MinSegmentSize>
180template <
typename Callback>
183 for (
Segment* current = top_; current !=
nullptr; current = current->
next()) {
188template <
typename EntryType, u
int16_t MinSegmentSize>
195 if (!other.top_)
return;
197 other_top = std::exchange(other.top_,
nullptr);
198 other_size = other.size_.exchange(0, std::memory_order_relaxed);
208 size_.fetch_add(other_size, std::memory_order_relaxed);
214template <
typename EntryType, u
int16_t MinSegmentSize>
219 const auto wanted_bytes = MallocSizeForCapacity(min_segment_size);
223 result.count = wanted_bytes;
229 "Worklist::Segment::Create");
240 template <
typename Callback>
242 template <
typename Callback>
250 return sizeof(
Segment) +
sizeof(EntryType) * num_entries;
253 return (malloc_size -
sizeof(
Segment)) /
sizeof(EntryType);
257 : internal::SegmentBase(capacity) {}
260 return reinterpret_cast<EntryType*
>(
this + 1)[index];
262 const EntryType&
entry(
size_t index)
const {
263 return reinterpret_cast<const EntryType*
>(
this + 1)[index];
269template <
typename EntryType, u
int16_t MinSegmentSize>
275template <
typename EntryType, u
int16_t MinSegmentSize>
281template <
typename EntryType, u
int16_t MinSegmentSize>
282template <
typename Callback>
284 size_t new_index = 0;
286 if (
callback(entry(
i), &entry(new_index))) {
293template <
typename EntryType, u
int16_t MinSegmentSize>
294template <
typename Callback>
303template <
typename EntryType, u
int16_t MinSegmentSize>
314 std::swap(push_segment_, other.push_segment_);
315 std::swap(pop_segment_, other.pop_segment_);
326 bool IsLocalAndGlobalEmpty() const;
327 bool IsLocalEmpty() const;
328 bool IsGlobalEmpty() const;
330 size_t PushSegmentSize()
const {
return push_segment_->Size(); }
339 void PublishPushSegment();
340 void PublishPopSegment();
341 bool StealPopSegment();
355 return static_cast<Segment*
>(push_segment_);
360 return static_cast<const Segment*
>(push_segment_);
365 return static_cast<Segment*
>(pop_segment_);
369 return static_cast<const Segment*
>(pop_segment_);
377template <
typename EntryType, u
int16_t MinSegmentSize>
380 : worklist_(worklist),
381 push_segment_(internal::SegmentBase::GetSentinelSegmentAddress()),
382 pop_segment_(internal::SegmentBase::GetSentinelSegmentAddress()) {}
384template <
typename EntryType, u
int16_t MinSegmentSize>
388 DeleteSegment(push_segment_);
389 DeleteSegment(pop_segment_);
392template <
typename EntryType, u
int16_t MinSegmentSize>
395 PublishPushSegment();
396 push_segment_ = NewSegment();
398 push_segment()->Push(entry);
401template <
typename EntryType, u
int16_t MinSegmentSize>
403 if (pop_segment_->IsEmpty()) {
404 if (!push_segment_->IsEmpty()) {
405 std::swap(push_segment_, pop_segment_);
406 }
else if (!StealPopSegment()) {
410 pop_segment()->Pop(entry);
414template <
typename EntryType, u
int16_t MinSegmentSize>
416 return IsLocalEmpty() && IsGlobalEmpty();
419template <
typename EntryType, u
int16_t MinSegmentSize>
421 return push_segment_->IsEmpty() && pop_segment_->IsEmpty();
424template <
typename EntryType, u
int16_t MinSegmentSize>
426 return worklist_.IsEmpty();
429template <
typename EntryType, u
int16_t MinSegmentSize>
431 if (!push_segment_->IsEmpty()) {
432 PublishPushSegment();
435 if (!pop_segment_->IsEmpty()) {
441template <
typename EntryType, u
int16_t MinSegmentSize>
444 worklist_.Merge(other.worklist_);
447template <
typename EntryType, u
int16_t MinSegmentSize>
450 worklist_.Push(push_segment());
453template <
typename EntryType, u
int16_t MinSegmentSize>
456 worklist_.Push(pop_segment());
459template <
typename EntryType, u
int16_t MinSegmentSize>
461 if (worklist_.IsEmpty())
return false;
462 Segment* new_segment =
nullptr;
463 if (worklist_.Pop(&new_segment)) {
464 DeleteSegment(pop_segment_);
465 pop_segment_ = new_segment;
471template <
typename EntryType, u
int16_t MinSegmentSize>
473 push_segment_->Clear();
474 pop_segment_->Clear();
static bool predictable_order_
static bool PredictableOrder()
Local(Worklist< EntryType, MinSegmentSize > &worklist)
void DeleteSegment(internal::SegmentBase *segment) const
bool IsLocalAndGlobalEmpty() const
void Merge(Worklist< EntryType, MinSegmentSize >::Local &other)
Worklist< EntryType, MinSegmentSize > & worklist_
Local & operator=(Local &&) V8_NOEXCEPT=delete
V8_INLINE void Push(EntryType entry)
Segment * NewSegment() const
Local(Local &&other) V8_NOEXCEPT
bool IsGlobalEmpty() const
bool IsLocalEmpty() const
const Segment * pop_segment() const
V8_INLINE bool Pop(EntryType *entry)
void PublishPushSegment()
const Segment * push_segment() const
void set_next(Segment *segment)
static void Delete(Segment *segment)
void Iterate(Callback callback) const
static constexpr size_t CapacityForMallocSize(size_t malloc_size)
constexpr Segment(size_t capacity)
static Segment * Create(uint16_t min_segment_size)
V8_INLINE void Pop(EntryType *entry)
const EntryType & entry(size_t index) const
void Update(Callback callback)
V8_INLINE void Push(EntryType entry)
EntryType & entry(size_t index)
static constexpr size_t MallocSizeForCapacity(size_t num_entries)
static constexpr int kMinSegmentSize
Worklist(const Worklist &)=delete
void Iterate(Callback callback) const
Worklist & operator=(const Worklist &)=delete
std::atomic< size_t > size_
void Update(Callback callback)
void Push(Segment *segment)
void Merge(Worklist< EntryType, MinSegmentSize > &other)
bool Pop(Segment **segment)
constexpr SegmentBase(uint16_t capacity)
static SegmentBase * GetSentinelSegmentAddress()
ZoneVector< RpoNumber > & result
V8_NODISCARD AllocationResult< T * > AllocateAtLeast(size_t n)
void FatalOOM(OOMType type, const char *msg)
void * Malloc(size_t size)
#define CHECK_IMPLIES(lhs, rhs)
#define DCHECK_NE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define V8_EXPORT_PRIVATE
#define V8_UNLIKELY(condition)