// 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_ARRAY_BUFFER_SWEEPER_H_ #define V8_HEAP_ARRAY_BUFFER_SWEEPER_H_ #include "src/base/platform/mutex.h" #include "src/objects/js-array-buffer.h" #include "src/tasks/cancelable-task.h" namespace v8 { namespace internal { class ArrayBufferExtension; class Heap; // Singly linked-list of ArrayBufferExtensions that stores head and tail of the // list to allow for concatenation of lists. struct ArrayBufferList { ArrayBufferList() : head_(nullptr), tail_(nullptr), bytes_(0) {} ArrayBufferExtension* head_; ArrayBufferExtension* tail_; size_t bytes_; bool IsEmpty() { DCHECK_IMPLIES(head_, tail_); return head_ == nullptr; } size_t Bytes() { return bytes_; } size_t BytesSlow(); void Reset() { head_ = tail_ = nullptr; bytes_ = 0; } void Append(ArrayBufferExtension* extension); void Append(ArrayBufferList* list); V8_EXPORT_PRIVATE bool Contains(ArrayBufferExtension* extension); }; // The ArrayBufferSweeper iterates and deletes ArrayBufferExtensions // concurrently to the application. class ArrayBufferSweeper { public: explicit ArrayBufferSweeper(Heap* heap) : heap_(heap), sweeping_in_progress_(false), freed_bytes_(0), young_bytes_(0), old_bytes_(0) {} ~ArrayBufferSweeper() { ReleaseAll(); } void EnsureFinished(); void RequestSweepYoung(); void RequestSweepFull(); void Append(JSArrayBuffer object, ArrayBufferExtension* extension); ArrayBufferList young() { return young_; } ArrayBufferList old() { return old_; } size_t YoungBytes(); size_t OldBytes(); private: enum class SweepingScope { kYoung, kFull }; enum class SweepingState { kInProgress, kDone }; struct SweepingJob { ArrayBufferSweeper* sweeper_; CancelableTaskManager::Id id_; std::atomic<SweepingState> state_; ArrayBufferList young_; ArrayBufferList old_; SweepingScope scope_; SweepingJob(ArrayBufferSweeper* sweeper, ArrayBufferList young, ArrayBufferList old, SweepingScope scope) : sweeper_(sweeper), id_(0), state_(SweepingState::kInProgress), young_(young), old_(old), scope_(scope) {} void Sweep(); void SweepYoung(); void SweepFull(); ArrayBufferList SweepListFull(ArrayBufferList* list); }; base::Optional<SweepingJob> job_; void Merge(); void AdjustCountersAndMergeIfPossible(); void DecrementExternalMemoryCounters(); void IncrementExternalMemoryCounters(size_t bytes); void IncrementFreedBytes(size_t bytes); void RequestSweep(SweepingScope sweeping_task); void Prepare(SweepingScope sweeping_task); ArrayBufferList SweepYoungGen(); void SweepOldGen(ArrayBufferExtension* extension); void ReleaseAll(); void ReleaseAll(ArrayBufferList* extension); Heap* const heap_; bool sweeping_in_progress_; base::Mutex sweeping_mutex_; base::ConditionVariable job_finished_; std::atomic<size_t> freed_bytes_; ArrayBufferList young_; ArrayBufferList old_; size_t young_bytes_; size_t old_bytes_; }; } // namespace internal } // namespace v8 #endif // V8_HEAP_ARRAY_BUFFER_SWEEPER_H_