Home | History | Annotate | Download | only in heap
      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 
     15 ArrayBufferTracker::~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 
     38 void 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 
     57 void 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 ? &not_yet_discovered_array_buffers_for_scavenge_
     66                    : &not_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 
     79 void 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 
     92 void 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 
    119 void ArrayBufferTracker::PrepareDiscoveryInNewSpace() {
    120   not_yet_discovered_array_buffers_for_scavenge_ =
    121       live_array_buffers_for_scavenge_;
    122 }
    123 
    124 
    125 void 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