Home | History | Annotate | Download | only in heap
      1 // Copyright 2016 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 #ifndef V8_HEAP_ARRAY_BUFFER_TRACKER_INL_H_
      6 #define V8_HEAP_ARRAY_BUFFER_TRACKER_INL_H_
      7 
      8 #include "src/conversions-inl.h"
      9 #include "src/heap/array-buffer-tracker.h"
     10 #include "src/heap/heap.h"
     11 #include "src/heap/spaces.h"
     12 #include "src/objects.h"
     13 #include "src/objects/js-array-buffer-inl.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 void ArrayBufferTracker::RegisterNew(Heap* heap, JSArrayBuffer* buffer) {
     19   if (buffer->backing_store() == nullptr) return;
     20 
     21   const size_t length = NumberToSize(buffer->byte_length());
     22   Page* page = Page::FromAddress(buffer->address());
     23   {
     24     base::LockGuard<base::Mutex> guard(page->mutex());
     25     LocalArrayBufferTracker* tracker = page->local_tracker();
     26     if (tracker == nullptr) {
     27       page->AllocateLocalTracker();
     28       tracker = page->local_tracker();
     29     }
     30     DCHECK_NOT_NULL(tracker);
     31     tracker->Add(buffer, length);
     32   }
     33 
     34   // TODO(wez): Remove backing-store from external memory accounting.
     35   // We may go over the limit of externally allocated memory here. We call the
     36   // api function to trigger a GC in this case.
     37   reinterpret_cast<v8::Isolate*>(heap->isolate())
     38       ->AdjustAmountOfExternalAllocatedMemory(length);
     39 }
     40 
     41 void ArrayBufferTracker::Unregister(Heap* heap, JSArrayBuffer* buffer) {
     42   if (buffer->backing_store() == nullptr) return;
     43 
     44   Page* page = Page::FromAddress(buffer->address());
     45   const size_t length = NumberToSize(buffer->byte_length());
     46   {
     47     base::LockGuard<base::Mutex> guard(page->mutex());
     48     LocalArrayBufferTracker* tracker = page->local_tracker();
     49     DCHECK_NOT_NULL(tracker);
     50     tracker->Remove(buffer, length);
     51   }
     52 
     53   // TODO(wez): Remove backing-store from external memory accounting.
     54   heap->update_external_memory(-static_cast<intptr_t>(length));
     55 }
     56 
     57 Space* LocalArrayBufferTracker::space() { return page_->owner(); }
     58 
     59 template <typename Callback>
     60 void LocalArrayBufferTracker::Free(Callback should_free) {
     61   size_t freed_memory = 0;
     62   Isolate* isolate = page_->heap()->isolate();
     63   for (TrackingData::iterator it = array_buffers_.begin();
     64        it != array_buffers_.end();) {
     65     JSArrayBuffer* buffer = reinterpret_cast<JSArrayBuffer*>(it->first);
     66     const size_t length = it->second.length;
     67 
     68     if (should_free(buffer)) {
     69       JSArrayBuffer::FreeBackingStore(isolate, it->second);
     70       it = array_buffers_.erase(it);
     71       freed_memory += length;
     72     } else {
     73       ++it;
     74     }
     75   }
     76   if (freed_memory > 0) {
     77     page_->DecrementExternalBackingStoreBytes(
     78         ExternalBackingStoreType::kArrayBuffer, freed_memory);
     79 
     80     // TODO(wez): Remove backing-store from external memory accounting.
     81     page_->heap()->update_external_memory_concurrently_freed(
     82         static_cast<intptr_t>(freed_memory));
     83   }
     84 }
     85 
     86 template <typename MarkingState>
     87 void ArrayBufferTracker::FreeDead(Page* page, MarkingState* marking_state) {
     88   // Callers need to ensure having the page lock.
     89   LocalArrayBufferTracker* tracker = page->local_tracker();
     90   if (tracker == nullptr) return;
     91   tracker->Free([marking_state](JSArrayBuffer* buffer) {
     92     return marking_state->IsWhite(buffer);
     93   });
     94   if (tracker->IsEmpty()) {
     95     page->ReleaseLocalTracker();
     96   }
     97 }
     98 
     99 void LocalArrayBufferTracker::Add(JSArrayBuffer* buffer, size_t length) {
    100   page_->IncrementExternalBackingStoreBytes(
    101       ExternalBackingStoreType::kArrayBuffer, length);
    102 
    103   auto ret = array_buffers_.insert(
    104       {buffer,
    105        {buffer->backing_store(), length, buffer->backing_store(),
    106         buffer->is_wasm_memory()}});
    107   USE(ret);
    108   // Check that we indeed inserted a new value and did not overwrite an existing
    109   // one (which would be a bug).
    110   DCHECK(ret.second);
    111 }
    112 
    113 void LocalArrayBufferTracker::Remove(JSArrayBuffer* buffer, size_t length) {
    114   page_->DecrementExternalBackingStoreBytes(
    115       ExternalBackingStoreType::kArrayBuffer, length);
    116 
    117   TrackingData::iterator it = array_buffers_.find(buffer);
    118   // Check that we indeed find a key to remove.
    119   DCHECK(it != array_buffers_.end());
    120   DCHECK_EQ(length, it->second.length);
    121   array_buffers_.erase(it);
    122 }
    123 
    124 }  // namespace internal
    125 }  // namespace v8
    126 
    127 #endif  // V8_HEAP_ARRAY_BUFFER_TRACKER_INL_H_
    128