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