V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
array-buffer-tracker.cc
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/heap/array-buffer-tracker.h"
6 
7 #include <vector>
8 
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"
13 
14 namespace v8 {
15 namespace internal {
16 
17 LocalArrayBufferTracker::~LocalArrayBufferTracker() {
18  CHECK(array_buffers_.empty());
19 }
20 
21 template <typename Callback>
22 void LocalArrayBufferTracker::Process(Callback callback) {
23  std::vector<JSArrayBuffer::Allocation> backing_stores_to_free;
24  TrackingData kept_array_buffers;
25 
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());
39  {
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();
45  }
46  DCHECK_NOT_NULL(tracker);
47  const size_t length = it->second.length;
48  // We should decrement before adding to avoid potential overflows in
49  // the external memory counters.
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);
56  }
57  } else if (result == kRemoveEntry) {
58  freed_memory += it->second.length;
59  // We pass backing_store() and stored length to the collector for freeing
60  // the backing store. Wasm allocations will go through their own tracker
61  // based on the backing store.
62  backing_stores_to_free.push_back(it->second);
63  } else {
64  UNREACHABLE();
65  }
66  }
67  if (freed_memory) {
68  page_->DecrementExternalBackingStoreBytes(
69  ExternalBackingStoreType::kArrayBuffer, freed_memory);
70  // TODO(wez): Remove backing-store from external memory accounting.
71  page_->heap()->update_external_memory_concurrently_freed(
72  static_cast<intptr_t>(freed_memory));
73  }
74 
75  array_buffers_.swap(kept_array_buffers);
76 
77  // Pass the backing stores that need to be freed to the main thread for
78  // potential later distribution.
79  page_->heap()->array_buffer_collector()->QueueOrFreeGarbageAllocations(
80  std::move(backing_stores_to_free));
81 }
82 
83 void ArrayBufferTracker::PrepareToFreeDeadInNewSpace(Heap* heap) {
84  DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE);
85  for (Page* page :
86  PageRange(heap->new_space()->from_space().first_page(), nullptr)) {
87  bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers);
88  CHECK(empty);
89  }
90 }
91 
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();
98  }
99 }
100 
101 bool ArrayBufferTracker::ProcessBuffers(Page* page, ProcessingMode mode) {
102  LocalArrayBufferTracker* tracker = page->local_tracker();
103  if (tracker == nullptr) return true;
104 
105  DCHECK(page->SweepingDone());
106  tracker->Process(
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;
112  }
113  return mode == kUpdateForwardedKeepOthers
114  ? LocalArrayBufferTracker::kKeepEntry
115  : LocalArrayBufferTracker::kRemoveEntry;
116  });
117  return tracker->IsEmpty();
118 }
119 
120 bool ArrayBufferTracker::IsTracked(JSArrayBuffer* buffer) {
121  Page* page = Page::FromAddress(buffer->address());
122  {
123  base::MutexGuard guard(page->mutex());
124  LocalArrayBufferTracker* tracker = page->local_tracker();
125  if (tracker == nullptr) return false;
126  return tracker->IsTracked(buffer);
127  }
128 }
129 
130 void ArrayBufferTracker::TearDown(Heap* heap) {
131  // ArrayBuffers can only be found in NEW_SPACE and OLD_SPACE.
132  for (Page* p : *heap->old_space()) {
133  FreeAll(p);
134  }
135  NewSpace* new_space = heap->new_space();
136  if (new_space->to_space().is_committed()) {
137  for (Page* p : new_space->to_space()) {
138  FreeAll(p);
139  }
140  }
141 #ifdef DEBUG
142  if (new_space->from_space().is_committed()) {
143  for (Page* p : new_space->from_space()) {
144  DCHECK(!p->contains_array_buffers());
145  }
146  }
147 #endif // DEBUG
148 }
149 
150 } // namespace internal
151 } // namespace v8
Definition: libplatform.h:13