• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 #ifndef V8_HEAP_ARRAY_BUFFER_TRACKER_INL_H_
6 #define V8_HEAP_ARRAY_BUFFER_TRACKER_INL_H_
7 
8 #include "src/conversions-inl.h"
9 #include "src/heap/array-buffer-tracker.h"
10 #include "src/heap/heap.h"
11 #include "src/heap/spaces.h"
12 #include "src/objects.h"
13 #include "src/objects/js-array-buffer-inl.h"
14 
15 namespace v8 {
16 namespace internal {
17 
RegisterNew(Heap * heap,JSArrayBuffer * buffer)18 void ArrayBufferTracker::RegisterNew(Heap* heap, JSArrayBuffer* buffer) {
19   if (buffer->backing_store() == nullptr) return;
20 
21   const size_t length = NumberToSize(buffer->byte_length());
22   Page* page = Page::FromAddress(buffer->address());
23   {
24     base::LockGuard<base::Mutex> guard(page->mutex());
25     LocalArrayBufferTracker* tracker = page->local_tracker();
26     if (tracker == nullptr) {
27       page->AllocateLocalTracker();
28       tracker = page->local_tracker();
29     }
30     DCHECK_NOT_NULL(tracker);
31     tracker->Add(buffer, length);
32   }
33 
34   // TODO(wez): Remove backing-store from external memory accounting.
35   // We may go over the limit of externally allocated memory here. We call the
36   // api function to trigger a GC in this case.
37   reinterpret_cast<v8::Isolate*>(heap->isolate())
38       ->AdjustAmountOfExternalAllocatedMemory(length);
39 }
40 
Unregister(Heap * heap,JSArrayBuffer * buffer)41 void ArrayBufferTracker::Unregister(Heap* heap, JSArrayBuffer* buffer) {
42   if (buffer->backing_store() == nullptr) return;
43 
44   Page* page = Page::FromAddress(buffer->address());
45   const size_t length = NumberToSize(buffer->byte_length());
46   {
47     base::LockGuard<base::Mutex> guard(page->mutex());
48     LocalArrayBufferTracker* tracker = page->local_tracker();
49     DCHECK_NOT_NULL(tracker);
50     tracker->Remove(buffer, length);
51   }
52 
53   // TODO(wez): Remove backing-store from external memory accounting.
54   heap->update_external_memory(-static_cast<intptr_t>(length));
55 }
56 
space()57 Space* LocalArrayBufferTracker::space() { return page_->owner(); }
58 
59 template <typename Callback>
Free(Callback should_free)60 void LocalArrayBufferTracker::Free(Callback should_free) {
61   size_t freed_memory = 0;
62   Isolate* isolate = page_->heap()->isolate();
63   for (TrackingData::iterator it = array_buffers_.begin();
64        it != array_buffers_.end();) {
65     JSArrayBuffer* buffer = reinterpret_cast<JSArrayBuffer*>(it->first);
66     const size_t length = it->second.length;
67 
68     if (should_free(buffer)) {
69       JSArrayBuffer::FreeBackingStore(isolate, it->second);
70       it = array_buffers_.erase(it);
71       freed_memory += length;
72     } else {
73       ++it;
74     }
75   }
76   if (freed_memory > 0) {
77     page_->DecrementExternalBackingStoreBytes(
78         ExternalBackingStoreType::kArrayBuffer, freed_memory);
79 
80     // TODO(wez): Remove backing-store from external memory accounting.
81     page_->heap()->update_external_memory_concurrently_freed(
82         static_cast<intptr_t>(freed_memory));
83   }
84 }
85 
86 template <typename MarkingState>
FreeDead(Page * page,MarkingState * marking_state)87 void ArrayBufferTracker::FreeDead(Page* page, MarkingState* marking_state) {
88   // Callers need to ensure having the page lock.
89   LocalArrayBufferTracker* tracker = page->local_tracker();
90   if (tracker == nullptr) return;
91   tracker->Free([marking_state](JSArrayBuffer* buffer) {
92     return marking_state->IsWhite(buffer);
93   });
94   if (tracker->IsEmpty()) {
95     page->ReleaseLocalTracker();
96   }
97 }
98 
Add(JSArrayBuffer * buffer,size_t length)99 void LocalArrayBufferTracker::Add(JSArrayBuffer* buffer, size_t length) {
100   page_->IncrementExternalBackingStoreBytes(
101       ExternalBackingStoreType::kArrayBuffer, length);
102 
103   auto ret = array_buffers_.insert(
104       {buffer,
105        {buffer->backing_store(), length, buffer->backing_store(),
106         buffer->is_wasm_memory()}});
107   USE(ret);
108   // Check that we indeed inserted a new value and did not overwrite an existing
109   // one (which would be a bug).
110   DCHECK(ret.second);
111 }
112 
Remove(JSArrayBuffer * buffer,size_t length)113 void LocalArrayBufferTracker::Remove(JSArrayBuffer* buffer, size_t length) {
114   page_->DecrementExternalBackingStoreBytes(
115       ExternalBackingStoreType::kArrayBuffer, length);
116 
117   TrackingData::iterator it = array_buffers_.find(buffer);
118   // Check that we indeed find a key to remove.
119   DCHECK(it != array_buffers_.end());
120   DCHECK_EQ(length, it->second.length);
121   array_buffers_.erase(it);
122 }
123 
124 }  // namespace internal
125 }  // namespace v8
126 
127 #endif  // V8_HEAP_ARRAY_BUFFER_TRACKER_INL_H_
128