5 #include "src/heap/array-buffer-tracker.h" 9 #include "src/heap/array-buffer-collector.h" 10 #include "src/heap/array-buffer-tracker-inl.h" 11 #include "src/heap/heap.h" 12 #include "src/heap/spaces.h" 17 LocalArrayBufferTracker::~LocalArrayBufferTracker() {
18 CHECK(array_buffers_.empty());
21 template <
typename Callback>
22 void LocalArrayBufferTracker::Process(Callback callback) {
23 std::vector<JSArrayBuffer::Allocation> backing_stores_to_free;
24 TrackingData kept_array_buffers;
26 JSArrayBuffer* new_buffer =
nullptr;
27 JSArrayBuffer* old_buffer =
nullptr;
28 size_t freed_memory = 0;
29 for (TrackingData::iterator it = array_buffers_.begin();
30 it != array_buffers_.end(); ++it) {
31 old_buffer = it->first;
32 DCHECK_EQ(page_, Page::FromAddress(old_buffer->address()));
33 const CallbackResult result = callback(old_buffer, &new_buffer);
34 if (result == kKeepEntry) {
35 kept_array_buffers.insert(*it);
36 }
else if (result == kUpdateEntry) {
37 DCHECK_NOT_NULL(new_buffer);
38 Page* target_page = Page::FromAddress(new_buffer->address());
40 base::MutexGuard guard(target_page->mutex());
41 LocalArrayBufferTracker* tracker = target_page->local_tracker();
42 if (tracker ==
nullptr) {
43 target_page->AllocateLocalTracker();
44 tracker = target_page->local_tracker();
46 DCHECK_NOT_NULL(tracker);
47 const size_t length = it->second.length;
50 DCHECK_EQ(it->first->is_wasm_memory(), it->second.is_wasm_memory);
51 tracker->AddInternal(new_buffer, length);
52 MemoryChunk::MoveExternalBackingStoreBytes(
53 ExternalBackingStoreType::kArrayBuffer,
54 static_cast<MemoryChunk*>(page_),
55 static_cast<MemoryChunk*>(target_page), length);
57 }
else if (result == kRemoveEntry) {
58 freed_memory += it->second.length;
62 backing_stores_to_free.push_back(it->second);
68 page_->DecrementExternalBackingStoreBytes(
69 ExternalBackingStoreType::kArrayBuffer, freed_memory);
71 page_->heap()->update_external_memory_concurrently_freed(
72 static_cast<intptr_t>(freed_memory));
75 array_buffers_.swap(kept_array_buffers);
79 page_->heap()->array_buffer_collector()->QueueOrFreeGarbageAllocations(
80 std::move(backing_stores_to_free));
83 void ArrayBufferTracker::PrepareToFreeDeadInNewSpace(Heap* heap) {
84 DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE);
86 PageRange(heap->new_space()->from_space().first_page(),
nullptr)) {
87 bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers);
92 void ArrayBufferTracker::FreeAll(Page* page) {
93 LocalArrayBufferTracker* tracker = page->local_tracker();
94 if (tracker ==
nullptr)
return;
95 tracker->Free([](JSArrayBuffer* buffer) {
return true; });
96 if (tracker->IsEmpty()) {
97 page->ReleaseLocalTracker();
101 bool ArrayBufferTracker::ProcessBuffers(Page* page, ProcessingMode mode) {
102 LocalArrayBufferTracker* tracker = page->local_tracker();
103 if (tracker ==
nullptr)
return true;
105 DCHECK(page->SweepingDone());
107 [mode](JSArrayBuffer* old_buffer, JSArrayBuffer** new_buffer) {
108 MapWord map_word = old_buffer->map_word();
109 if (map_word.IsForwardingAddress()) {
110 *new_buffer = JSArrayBuffer::cast(map_word.ToForwardingAddress());
111 return LocalArrayBufferTracker::kUpdateEntry;
113 return mode == kUpdateForwardedKeepOthers
114 ? LocalArrayBufferTracker::kKeepEntry
115 : LocalArrayBufferTracker::kRemoveEntry;
117 return tracker->IsEmpty();
120 bool ArrayBufferTracker::IsTracked(JSArrayBuffer* buffer) {
121 Page* page = Page::FromAddress(buffer->address());
123 base::MutexGuard guard(page->mutex());
124 LocalArrayBufferTracker* tracker = page->local_tracker();
125 if (tracker ==
nullptr)
return false;
126 return tracker->IsTracked(buffer);
130 void ArrayBufferTracker::TearDown(Heap* heap) {
132 for (Page* p : *heap->old_space()) {
135 NewSpace* new_space = heap->new_space();
136 if (new_space->to_space().is_committed()) {
137 for (Page* p : new_space->to_space()) {
142 if (new_space->from_space().is_committed()) {
143 for (Page* p : new_space->from_space()) {
144 DCHECK(!p->contains_array_buffers());