Line data Source code
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 : #include "src/heap/array-buffer-tracker-inl.h"
7 : #include "src/heap/heap.h"
8 : #include "src/heap/spaces.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 185433 : LocalArrayBufferTracker::~LocalArrayBufferTracker() {
14 185433 : CHECK(array_buffers_.empty());
15 185435 : }
16 :
17 : template <typename Callback>
18 168410 : void LocalArrayBufferTracker::Process(Callback callback) {
19 168410 : JSArrayBuffer* new_buffer = nullptr;
20 : JSArrayBuffer* old_buffer = nullptr;
21 : size_t new_retained_size = 0;
22 : size_t moved_size = 0;
23 543433 : for (TrackingData::iterator it = array_buffers_.begin();
24 : it != array_buffers_.end();) {
25 206614 : old_buffer = reinterpret_cast<JSArrayBuffer*>(*it);
26 206614 : const CallbackResult result = callback(old_buffer, &new_buffer);
27 206646 : if (result == kKeepEntry) {
28 0 : new_retained_size += NumberToSize(old_buffer->byte_length());
29 : ++it;
30 206646 : } else if (result == kUpdateEntry) {
31 : DCHECK_NOT_NULL(new_buffer);
32 22229 : Page* target_page = Page::FromAddress(new_buffer->address());
33 : {
34 45161 : base::LockGuard<base::RecursiveMutex> guard(target_page->mutex());
35 : LocalArrayBufferTracker* tracker = target_page->local_tracker();
36 22230 : if (tracker == nullptr) {
37 702 : target_page->AllocateLocalTracker();
38 : tracker = target_page->local_tracker();
39 : }
40 : DCHECK_NOT_NULL(tracker);
41 44460 : const size_t size = NumberToSize(new_buffer->byte_length());
42 22230 : moved_size += size;
43 : tracker->Add(new_buffer, size);
44 : }
45 : it = array_buffers_.erase(it);
46 184417 : } else if (result == kRemoveEntry) {
47 : // Size of freed memory is computed to avoid looking at dead objects.
48 184417 : old_buffer->FreeBackingStore();
49 : it = array_buffers_.erase(it);
50 : } else {
51 0 : UNREACHABLE();
52 : }
53 : }
54 168409 : const size_t freed_memory = retained_size_ - new_retained_size - moved_size;
55 168409 : if (freed_memory > 0) {
56 : heap_->update_external_memory_concurrently_freed(
57 2466 : static_cast<intptr_t>(freed_memory));
58 : }
59 168409 : retained_size_ = new_retained_size;
60 168409 : }
61 :
62 59304 : void ArrayBufferTracker::FreeDeadInNewSpace(Heap* heap) {
63 : DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE);
64 236556 : for (Page* page : PageRange(heap->new_space()->FromSpaceStart(),
65 59304 : heap->new_space()->FromSpaceEnd())) {
66 : bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers);
67 103452 : CHECK(empty);
68 : }
69 29652 : heap->account_external_memory_concurrently_freed();
70 29652 : }
71 :
72 48 : size_t ArrayBufferTracker::RetainedInNewSpace(Heap* heap) {
73 : size_t retained_size = 0;
74 120 : for (Page* page : PageRange(heap->new_space()->ToSpaceStart(),
75 48 : heap->new_space()->ToSpaceEnd())) {
76 96 : LocalArrayBufferTracker* tracker = page->local_tracker();
77 48 : if (tracker == nullptr) continue;
78 48 : retained_size += tracker->retained_size();
79 : }
80 24 : return retained_size;
81 : }
82 :
83 522232 : void ArrayBufferTracker::FreeAll(Page* page) {
84 522232 : LocalArrayBufferTracker* tracker = page->local_tracker();
85 1044464 : if (tracker == nullptr) return;
86 147889 : tracker->Free([](JSArrayBuffer* buffer) { return true; });
87 147889 : if (tracker->IsEmpty()) {
88 147889 : page->ReleaseLocalTracker();
89 : }
90 : }
91 :
92 67228 : bool ArrayBufferTracker::ProcessBuffers(Page* page, ProcessingMode mode) {
93 170680 : LocalArrayBufferTracker* tracker = page->local_tracker();
94 170680 : if (tracker == nullptr) return true;
95 :
96 : DCHECK(page->SweepingDone());
97 : tracker->Process(
98 206591 : [mode](JSArrayBuffer* old_buffer, JSArrayBuffer** new_buffer) {
99 : MapWord map_word = old_buffer->map_word();
100 206591 : if (map_word.IsForwardingAddress()) {
101 22229 : *new_buffer = JSArrayBuffer::cast(map_word.ToForwardingAddress());
102 22229 : return LocalArrayBufferTracker::kUpdateEntry;
103 : }
104 184362 : return mode == kUpdateForwardedKeepOthers
105 : ? LocalArrayBufferTracker::kKeepEntry
106 184362 : : LocalArrayBufferTracker::kRemoveEntry;
107 168415 : });
108 67221 : return tracker->IsEmpty();
109 : }
110 :
111 209 : bool ArrayBufferTracker::IsTracked(JSArrayBuffer* buffer) {
112 209 : Page* page = Page::FromAddress(buffer->address());
113 : {
114 418 : base::LockGuard<base::RecursiveMutex> guard(page->mutex());
115 : LocalArrayBufferTracker* tracker = page->local_tracker();
116 209 : if (tracker == nullptr) return false;
117 185 : return tracker->IsTracked(buffer);
118 : }
119 : }
120 :
121 : } // namespace internal
122 : } // namespace v8
|