blob: a870b35ec50fa5db2b0c7adc23e9a3ef58859e70 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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"
Ben Murdoch61f157c2016-09-16 13:49:30 +01006#include "src/heap/array-buffer-tracker-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include "src/heap/heap.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008
9namespace v8 {
10namespace internal {
11
Ben Murdoch61f157c2016-09-16 13:49:30 +010012LocalArrayBufferTracker::~LocalArrayBufferTracker() {
13 CHECK(array_buffers_.empty());
14}
15
16template <LocalArrayBufferTracker::FreeMode free_mode>
17void LocalArrayBufferTracker::Free() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018 size_t freed_memory = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +010019 for (TrackingMap::iterator it = array_buffers_.begin();
20 it != array_buffers_.end();) {
21 if ((free_mode == kFreeAll) ||
22 Marking::IsWhite(Marking::MarkBitFrom(it->first))) {
23 heap_->isolate()->array_buffer_allocator()->Free(it->second.first,
24 it->second.second);
25 freed_memory += it->second.second;
26 it = array_buffers_.erase(it);
27 } else {
28 it++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029 }
30 }
Ben Murdoch61f157c2016-09-16 13:49:30 +010031 if (freed_memory > 0) {
32 heap_->update_external_memory_concurrently_freed(
33 static_cast<intptr_t>(freed_memory));
34 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035}
36
Ben Murdoch61f157c2016-09-16 13:49:30 +010037template <typename Callback>
38void LocalArrayBufferTracker::Process(Callback callback) {
39 JSArrayBuffer* new_buffer = nullptr;
40 size_t freed_memory = 0;
41 for (TrackingMap::iterator it = array_buffers_.begin();
42 it != array_buffers_.end();) {
43 const CallbackResult result = callback(it->first, &new_buffer);
44 if (result == kKeepEntry) {
45 it++;
46 } else if (result == kUpdateEntry) {
47 DCHECK_NOT_NULL(new_buffer);
48 Page* target_page = Page::FromAddress(new_buffer->address());
49 // We need to lock the target page because we cannot guarantee
50 // exclusive access to new space pages.
51 if (target_page->InNewSpace()) target_page->mutex()->Lock();
52 LocalArrayBufferTracker* tracker = target_page->local_tracker();
53 if (tracker == nullptr) {
54 target_page->AllocateLocalTracker();
55 tracker = target_page->local_tracker();
56 }
57 DCHECK_NOT_NULL(tracker);
58 tracker->Add(new_buffer, it->second);
59 if (target_page->InNewSpace()) target_page->mutex()->Unlock();
60 it = array_buffers_.erase(it);
61 } else if (result == kRemoveEntry) {
62 heap_->isolate()->array_buffer_allocator()->Free(it->second.first,
63 it->second.second);
64 freed_memory += it->second.second;
65 it = array_buffers_.erase(it);
66 } else {
67 UNREACHABLE();
68 }
69 }
70 if (freed_memory > 0) {
71 heap_->update_external_memory_concurrently_freed(
72 static_cast<intptr_t>(freed_memory));
73 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074}
75
Ben Murdoch61f157c2016-09-16 13:49:30 +010076void ArrayBufferTracker::FreeDeadInNewSpace(Heap* heap) {
77 DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE);
78 for (Page* page : NewSpacePageRange(heap->new_space()->FromSpaceStart(),
79 heap->new_space()->FromSpaceEnd())) {
80 bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers);
81 CHECK(empty);
82 }
83 heap->account_external_memory_concurrently_freed();
84}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085
Ben Murdoch61f157c2016-09-16 13:49:30 +010086void ArrayBufferTracker::FreeDead(Page* page) {
87 // Callers need to ensure having the page lock.
88 LocalArrayBufferTracker* tracker = page->local_tracker();
89 if (tracker == nullptr) return;
90 DCHECK(!page->SweepingDone());
91 tracker->Free<LocalArrayBufferTracker::kFreeDead>();
92 if (tracker->IsEmpty()) {
93 page->ReleaseLocalTracker();
94 }
95}
Ben Murdoch097c5b22016-05-18 11:27:45 +010096
Ben Murdoch61f157c2016-09-16 13:49:30 +010097void ArrayBufferTracker::FreeAll(Page* page) {
98 LocalArrayBufferTracker* tracker = page->local_tracker();
99 if (tracker == nullptr) return;
100 tracker->Free<LocalArrayBufferTracker::kFreeAll>();
101 if (tracker->IsEmpty()) {
102 page->ReleaseLocalTracker();
103 }
104}
105
106bool ArrayBufferTracker::ProcessBuffers(Page* page, ProcessingMode mode) {
107 LocalArrayBufferTracker* tracker = page->local_tracker();
108 if (tracker == nullptr) return true;
109
110 DCHECK(page->SweepingDone());
111 tracker->Process(
112 [mode](JSArrayBuffer* old_buffer, JSArrayBuffer** new_buffer) {
113 MapWord map_word = old_buffer->map_word();
114 if (map_word.IsForwardingAddress()) {
115 *new_buffer = JSArrayBuffer::cast(map_word.ToForwardingAddress());
116 return LocalArrayBufferTracker::kUpdateEntry;
117 }
118 return mode == kUpdateForwardedKeepOthers
119 ? LocalArrayBufferTracker::kKeepEntry
120 : LocalArrayBufferTracker::kRemoveEntry;
121 });
122 return tracker->IsEmpty();
123}
124
125bool ArrayBufferTracker::IsTracked(JSArrayBuffer* buffer) {
126 Page* page = Page::FromAddress(buffer->address());
127 {
128 base::LockGuard<base::Mutex> guard(page->mutex());
129 LocalArrayBufferTracker* tracker = page->local_tracker();
130 if (tracker == nullptr) return false;
131 return tracker->IsTracked(buffer);
132 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133}
134
135} // namespace internal
136} // namespace v8