| // 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 IncrementFreedYoungBytes(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_ |