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/heap.h" 7 #include "src/isolate.h" 8 #include "src/objects.h" 9 #include "src/objects-inl.h" 10 #include "src/v8.h" 11 12 namespace v8 { 13 namespace internal { 14 ~ArrayBufferTracker()15ArrayBufferTracker::~ArrayBufferTracker() { 16 Isolate* isolate = heap()->isolate(); 17 size_t freed_memory = 0; 18 for (auto& buffer : live_array_buffers_) { 19 isolate->array_buffer_allocator()->Free(buffer.first, buffer.second); 20 freed_memory += buffer.second; 21 } 22 for (auto& buffer : live_array_buffers_for_scavenge_) { 23 isolate->array_buffer_allocator()->Free(buffer.first, buffer.second); 24 freed_memory += buffer.second; 25 } 26 live_array_buffers_.clear(); 27 live_array_buffers_for_scavenge_.clear(); 28 not_yet_discovered_array_buffers_.clear(); 29 not_yet_discovered_array_buffers_for_scavenge_.clear(); 30 31 if (freed_memory > 0) { 32 heap()->update_amount_of_external_allocated_memory( 33 -static_cast<int64_t>(freed_memory)); 34 } 35 } 36 37 RegisterNew(JSArrayBuffer * buffer)38void ArrayBufferTracker::RegisterNew(JSArrayBuffer* buffer) { 39 void* data = buffer->backing_store(); 40 if (!data) return; 41 42 bool in_new_space = heap()->InNewSpace(buffer); 43 size_t length = NumberToSize(heap()->isolate(), buffer->byte_length()); 44 if (in_new_space) { 45 live_array_buffers_for_scavenge_[data] = length; 46 } else { 47 live_array_buffers_[data] = length; 48 } 49 50 // We may go over the limit of externally allocated memory here. We call the 51 // api function to trigger a GC in this case. 52 reinterpret_cast<v8::Isolate*>(heap()->isolate()) 53 ->AdjustAmountOfExternalAllocatedMemory(length); 54 } 55 56 Unregister(JSArrayBuffer * buffer)57void ArrayBufferTracker::Unregister(JSArrayBuffer* buffer) { 58 void* data = buffer->backing_store(); 59 if (!data) return; 60 61 bool in_new_space = heap()->InNewSpace(buffer); 62 std::map<void*, size_t>* live_buffers = 63 in_new_space ? &live_array_buffers_for_scavenge_ : &live_array_buffers_; 64 std::map<void*, size_t>* not_yet_discovered_buffers = 65 in_new_space ? ¬_yet_discovered_array_buffers_for_scavenge_ 66 : ¬_yet_discovered_array_buffers_; 67 68 DCHECK(live_buffers->count(data) > 0); 69 70 size_t length = (*live_buffers)[data]; 71 live_buffers->erase(data); 72 not_yet_discovered_buffers->erase(data); 73 74 heap()->update_amount_of_external_allocated_memory( 75 -static_cast<int64_t>(length)); 76 } 77 78 MarkLive(JSArrayBuffer * buffer)79void ArrayBufferTracker::MarkLive(JSArrayBuffer* buffer) { 80 void* data = buffer->backing_store(); 81 82 // ArrayBuffer might be in the middle of being constructed. 83 if (data == heap()->undefined_value()) return; 84 if (heap()->InNewSpace(buffer)) { 85 not_yet_discovered_array_buffers_for_scavenge_.erase(data); 86 } else { 87 not_yet_discovered_array_buffers_.erase(data); 88 } 89 } 90 91 FreeDead(bool from_scavenge)92void ArrayBufferTracker::FreeDead(bool from_scavenge) { 93 size_t freed_memory = 0; 94 Isolate* isolate = heap()->isolate(); 95 for (auto& buffer : not_yet_discovered_array_buffers_for_scavenge_) { 96 isolate->array_buffer_allocator()->Free(buffer.first, buffer.second); 97 freed_memory += buffer.second; 98 live_array_buffers_for_scavenge_.erase(buffer.first); 99 } 100 101 if (!from_scavenge) { 102 for (auto& buffer : not_yet_discovered_array_buffers_) { 103 isolate->array_buffer_allocator()->Free(buffer.first, buffer.second); 104 freed_memory += buffer.second; 105 live_array_buffers_.erase(buffer.first); 106 } 107 } 108 109 not_yet_discovered_array_buffers_for_scavenge_ = 110 live_array_buffers_for_scavenge_; 111 if (!from_scavenge) not_yet_discovered_array_buffers_ = live_array_buffers_; 112 113 // Do not call through the api as this code is triggered while doing a GC. 114 heap()->update_amount_of_external_allocated_memory( 115 -static_cast<int64_t>(freed_memory)); 116 } 117 118 PrepareDiscoveryInNewSpace()119void ArrayBufferTracker::PrepareDiscoveryInNewSpace() { 120 not_yet_discovered_array_buffers_for_scavenge_ = 121 live_array_buffers_for_scavenge_; 122 } 123 124 Promote(JSArrayBuffer * buffer)125void ArrayBufferTracker::Promote(JSArrayBuffer* buffer) { 126 if (buffer->is_external()) return; 127 void* data = buffer->backing_store(); 128 if (!data) return; 129 // ArrayBuffer might be in the middle of being constructed. 130 if (data == heap()->undefined_value()) return; 131 DCHECK(live_array_buffers_for_scavenge_.count(data) > 0); 132 live_array_buffers_[data] = live_array_buffers_for_scavenge_[data]; 133 live_array_buffers_for_scavenge_.erase(data); 134 not_yet_discovered_array_buffers_for_scavenge_.erase(data); 135 } 136 137 } // namespace internal 138 } // namespace v8 139