OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/heap/array-buffer-tracker.h" | 5 #include "src/heap/array-buffer-tracker.h" |
6 #include "src/heap/array-buffer-tracker-inl.h" | 6 #include "src/heap/array-buffer-tracker-inl.h" |
7 #include "src/heap/heap.h" | 7 #include "src/heap/heap.h" |
8 | 8 |
9 namespace v8 { | 9 namespace v8 { |
10 namespace internal { | 10 namespace internal { |
11 | 11 |
12 LocalArrayBufferTracker::~LocalArrayBufferTracker() { | 12 LocalArrayBufferTracker::~LocalArrayBufferTracker() { |
13 CHECK(array_buffers_.empty()); | 13 CHECK(array_buffers_.empty()); |
14 } | 14 } |
15 | 15 |
16 template <LocalArrayBufferTracker::FreeMode free_mode> | 16 template <LocalArrayBufferTracker::FreeMode free_mode> |
17 void LocalArrayBufferTracker::Free() { | 17 LocalArrayBufferTracker::ProcessResult LocalArrayBufferTracker::Free() { |
18 size_t freed_memory = 0; | 18 size_t freed_memory = 0; |
19 size_t live_memory = 0; | |
19 for (TrackingData::iterator it = array_buffers_.begin(); | 20 for (TrackingData::iterator it = array_buffers_.begin(); |
20 it != array_buffers_.end();) { | 21 it != array_buffers_.end();) { |
21 JSArrayBuffer* buffer = reinterpret_cast<JSArrayBuffer*>(it->first); | 22 JSArrayBuffer* buffer = reinterpret_cast<JSArrayBuffer*>(it->first); |
22 if ((free_mode == kFreeAll) || | 23 if ((free_mode == kFreeAll) || |
23 Marking::IsWhite(ObjectMarking::MarkBitFrom(buffer))) { | 24 Marking::IsWhite(ObjectMarking::MarkBitFrom(buffer))) { |
24 const size_t len = it->second; | 25 const size_t len = it->second; |
25 heap_->isolate()->array_buffer_allocator()->Free(buffer->backing_store(), | 26 heap_->isolate()->array_buffer_allocator()->Free(buffer->backing_store(), |
26 len); | 27 len); |
27 freed_memory += len; | 28 freed_memory += len; |
28 it = array_buffers_.erase(it); | 29 it = array_buffers_.erase(it); |
29 } else { | 30 } else { |
31 live_memory += it->second; | |
30 ++it; | 32 ++it; |
31 } | 33 } |
32 } | 34 } |
33 if (freed_memory > 0) { | 35 return ProcessResult(freed_memory, live_memory, 0); |
34 heap_->update_external_memory_concurrently_freed( | |
35 static_cast<intptr_t>(freed_memory)); | |
36 } | |
37 } | 36 } |
38 | 37 |
39 template <typename Callback> | 38 template <typename Callback> |
40 void LocalArrayBufferTracker::Process(Callback callback) { | 39 LocalArrayBufferTracker::ProcessResult LocalArrayBufferTracker::Process( |
40 Callback callback) { | |
41 JSArrayBuffer* new_buffer = nullptr; | 41 JSArrayBuffer* new_buffer = nullptr; |
42 size_t freed_memory = 0; | 42 size_t freed_memory = 0; |
43 size_t live_memory = 0; | |
44 size_t promoted_memory = 0; | |
43 for (TrackingData::iterator it = array_buffers_.begin(); | 45 for (TrackingData::iterator it = array_buffers_.begin(); |
44 it != array_buffers_.end();) { | 46 it != array_buffers_.end();) { |
45 const CallbackResult result = callback(it->first, &new_buffer); | 47 const CallbackResult result = callback(it->first, &new_buffer); |
46 if (result == kKeepEntry) { | 48 if (result == kKeepEntry) { |
49 live_memory += it->second; | |
47 ++it; | 50 ++it; |
48 } else if (result == kUpdateEntry) { | 51 } else if (result == kUpdateEntry) { |
49 DCHECK_NOT_NULL(new_buffer); | 52 DCHECK_NOT_NULL(new_buffer); |
50 Page* target_page = Page::FromAddress(new_buffer->address()); | 53 Page* target_page = Page::FromAddress(new_buffer->address()); |
51 // We need to lock the target page because we cannot guarantee | 54 // We need to lock the target page because we cannot guarantee |
52 // exclusive access to new space pages. | 55 // exclusive access to new space pages. |
53 if (target_page->InNewSpace()) target_page->mutex()->Lock(); | 56 if (target_page->InNewSpace()) target_page->mutex()->Lock(); |
54 LocalArrayBufferTracker* tracker = target_page->local_tracker(); | 57 LocalArrayBufferTracker* tracker = target_page->local_tracker(); |
55 if (tracker == nullptr) { | 58 if (tracker == nullptr) { |
56 target_page->AllocateLocalTracker(); | 59 target_page->AllocateLocalTracker(); |
57 tracker = target_page->local_tracker(); | 60 tracker = target_page->local_tracker(); |
58 } | 61 } |
59 DCHECK_NOT_NULL(tracker); | 62 DCHECK_NOT_NULL(tracker); |
60 tracker->Add(new_buffer, it->second); | 63 tracker->Add(new_buffer, it->second); |
61 if (target_page->InNewSpace()) target_page->mutex()->Unlock(); | 64 if (target_page->InNewSpace()) { |
65 target_page->mutex()->Unlock(); | |
66 live_memory += it->second; | |
67 } else { | |
68 promoted_memory += it->second; | |
69 } | |
62 it = array_buffers_.erase(it); | 70 it = array_buffers_.erase(it); |
63 } else if (result == kRemoveEntry) { | 71 } else if (result == kRemoveEntry) { |
64 const size_t len = it->second; | 72 const size_t len = it->second; |
65 heap_->isolate()->array_buffer_allocator()->Free( | 73 heap_->isolate()->array_buffer_allocator()->Free( |
66 it->first->backing_store(), len); | 74 it->first->backing_store(), len); |
67 freed_memory += len; | 75 freed_memory += len; |
68 it = array_buffers_.erase(it); | 76 it = array_buffers_.erase(it); |
69 } else { | 77 } else { |
70 UNREACHABLE(); | 78 UNREACHABLE(); |
71 } | 79 } |
72 } | 80 } |
73 if (freed_memory > 0) { | 81 return ProcessResult(freed_memory, live_memory, promoted_memory); |
74 heap_->update_external_memory_concurrently_freed( | 82 } |
75 static_cast<intptr_t>(freed_memory)); | 83 |
76 } | 84 void ArrayBufferTracker::AccountForConcurrentlyFreedMemory() { |
85 heap_->update_external_memory( | |
86 static_cast<int64_t>(concurrently_freed_.Value())); | |
87 concurrently_freed_.SetValue(0); | |
77 } | 88 } |
78 | 89 |
79 void ArrayBufferTracker::FreeDeadInNewSpace(Heap* heap) { | 90 void ArrayBufferTracker::FreeDeadInNewSpace(Heap* heap) { |
80 DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE); | 91 DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE); |
81 for (Page* page : NewSpacePageRange(heap->new_space()->FromSpaceStart(), | 92 for (Page* page : NewSpacePageRange(heap->new_space()->FromSpaceStart(), |
82 heap->new_space()->FromSpaceEnd())) { | 93 heap->new_space()->FromSpaceEnd())) { |
83 bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers); | 94 bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers); |
84 CHECK(empty); | 95 CHECK(empty); |
85 } | 96 } |
86 heap->account_external_memory_concurrently_freed(); | 97 AccountForConcurrentlyFreedMemory(); |
87 } | 98 } |
88 | 99 |
89 void ArrayBufferTracker::FreeDead(Page* page) { | 100 void ArrayBufferTracker::FreeDead(Page* page) { |
90 // Callers need to ensure having the page lock. | 101 // Callers need to ensure having the page lock. |
91 LocalArrayBufferTracker* tracker = page->local_tracker(); | 102 LocalArrayBufferTracker* tracker = page->local_tracker(); |
92 if (tracker == nullptr) return; | 103 if (tracker == nullptr) return; |
93 DCHECK(!page->SweepingDone()); | 104 DCHECK(!page->SweepingDone()); |
94 tracker->Free<LocalArrayBufferTracker::kFreeDead>(); | 105 LocalArrayBufferTracker::ProcessResult result = |
106 tracker->Free<LocalArrayBufferTracker::kFreeDead>(); | |
107 if (page->InNewSpace()) { | |
108 retained_from_new_space_.Increment(-static_cast<intptr_t>(result.freed)); | |
109 } else { | |
110 retained_from_old_space_.Increment(-static_cast<intptr_t>(result.freed)); | |
111 } | |
95 if (tracker->IsEmpty()) { | 112 if (tracker->IsEmpty()) { |
96 page->ReleaseLocalTracker(); | 113 page->ReleaseLocalTracker(); |
97 } | 114 } |
98 } | 115 } |
99 | 116 |
100 void ArrayBufferTracker::FreeAll(Page* page) { | 117 void ArrayBufferTracker::FreeAll(Page* page) { |
101 LocalArrayBufferTracker* tracker = page->local_tracker(); | 118 LocalArrayBufferTracker* tracker = page->local_tracker(); |
102 if (tracker == nullptr) return; | 119 if (tracker == nullptr) return; |
103 tracker->Free<LocalArrayBufferTracker::kFreeAll>(); | 120 LocalArrayBufferTracker::ProcessResult result = |
121 tracker->Free<LocalArrayBufferTracker::kFreeAll>(); | |
122 concurrently_freed_.Increment(static_cast<intptr_t>(result.freed)); | |
123 if (page->InNewSpace()) { | |
124 retained_from_new_space_.Increment(-static_cast<intptr_t>(result.freed)); | |
125 } else { | |
126 retained_from_old_space_.Increment(-static_cast<intptr_t>(result.freed)); | |
127 } | |
104 if (tracker->IsEmpty()) { | 128 if (tracker->IsEmpty()) { |
105 page->ReleaseLocalTracker(); | 129 page->ReleaseLocalTracker(); |
106 } | 130 } |
107 } | 131 } |
108 | 132 |
109 bool ArrayBufferTracker::ProcessBuffers(Page* page, ProcessingMode mode) { | 133 bool ArrayBufferTracker::ProcessBuffers(Page* page, ProcessingMode mode) { |
110 LocalArrayBufferTracker* tracker = page->local_tracker(); | 134 LocalArrayBufferTracker* tracker = page->local_tracker(); |
111 if (tracker == nullptr) return true; | 135 if (tracker == nullptr) return true; |
112 | 136 |
113 DCHECK(page->SweepingDone()); | 137 DCHECK(page->SweepingDone()); |
114 tracker->Process( | 138 LocalArrayBufferTracker::ProcessResult result = tracker->Process( |
115 [mode](JSArrayBuffer* old_buffer, JSArrayBuffer** new_buffer) { | 139 [mode](JSArrayBuffer* old_buffer, JSArrayBuffer** new_buffer) { |
116 MapWord map_word = old_buffer->map_word(); | 140 MapWord map_word = old_buffer->map_word(); |
117 if (map_word.IsForwardingAddress()) { | 141 if (map_word.IsForwardingAddress()) { |
118 *new_buffer = JSArrayBuffer::cast(map_word.ToForwardingAddress()); | 142 *new_buffer = JSArrayBuffer::cast(map_word.ToForwardingAddress()); |
119 return LocalArrayBufferTracker::kUpdateEntry; | 143 return LocalArrayBufferTracker::kUpdateEntry; |
120 } | 144 } |
121 return mode == kUpdateForwardedKeepOthers | 145 return mode == kUpdateForwardedKeepOthers |
122 ? LocalArrayBufferTracker::kKeepEntry | 146 ? LocalArrayBufferTracker::kKeepEntry |
123 : LocalArrayBufferTracker::kRemoveEntry; | 147 : LocalArrayBufferTracker::kRemoveEntry; |
124 }); | 148 }); |
149 concurrently_freed_.Increment(static_cast<intptr_t>(result.freed)); | |
150 if (page->InNewSpace()) { | |
151 retained_from_new_space_.Increment( | |
Michael Lippautz
2016/08/04 11:50:02
General: When (and if) https://codereview.chromium
Hannes Payer (out of office)
2016/08/05 12:14:13
Nice, please do that.
Michael Lippautz
2016/08/08 08:34:46
Done.
| |
152 -(static_cast<intptr_t>(result.freed) + | |
153 static_cast<intptr_t>(result.promoted))); | |
154 } else { | |
155 retained_from_old_space_.Increment(-static_cast<intptr_t>(result.freed)); | |
156 } | |
157 retained_from_old_space_.Increment(static_cast<intptr_t>(result.promoted)); | |
125 return tracker->IsEmpty(); | 158 return tracker->IsEmpty(); |
126 } | 159 } |
127 | 160 |
128 bool ArrayBufferTracker::IsTracked(JSArrayBuffer* buffer) { | 161 bool ArrayBufferTracker::IsTracked(JSArrayBuffer* buffer) { |
129 Page* page = Page::FromAddress(buffer->address()); | 162 Page* page = Page::FromAddress(buffer->address()); |
130 { | 163 { |
131 base::LockGuard<base::Mutex> guard(page->mutex()); | 164 base::LockGuard<base::Mutex> guard(page->mutex()); |
132 LocalArrayBufferTracker* tracker = page->local_tracker(); | 165 LocalArrayBufferTracker* tracker = page->local_tracker(); |
133 if (tracker == nullptr) return false; | 166 if (tracker == nullptr) return false; |
134 return tracker->IsTracked(buffer); | 167 return tracker->IsTracked(buffer); |
135 } | 168 } |
136 } | 169 } |
137 | 170 |
138 } // namespace internal | 171 } // namespace internal |
139 } // namespace v8 | 172 } // namespace v8 |
OLD | NEW |