LCOV - code coverage report
Current view: top level - src/heap - array-buffer-tracker.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 52 53 98.1 %
Date: 2019-03-21 Functions: 9 9 100.0 %

          Line data    Source code
       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             : 
       7             : #include <vector>
       8             : 
       9             : #include "src/heap/array-buffer-collector.h"
      10             : #include "src/heap/array-buffer-tracker-inl.h"
      11             : #include "src/heap/heap.h"
      12             : #include "src/heap/spaces.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17      891598 : LocalArrayBufferTracker::~LocalArrayBufferTracker() {
      18      445800 :   CHECK(array_buffers_.empty());
      19      445798 : }
      20             : 
      21             : template <typename Callback>
      22      237913 : void LocalArrayBufferTracker::Process(Callback callback) {
      23             :   std::vector<JSArrayBuffer::Allocation> backing_stores_to_free;
      24             :   TrackingData kept_array_buffers;
      25             : 
      26      237913 :   JSArrayBuffer new_buffer;
      27             :   JSArrayBuffer old_buffer;
      28             :   size_t freed_memory = 0;
      29      514940 :   for (TrackingData::iterator it = array_buffers_.begin();
      30             :        it != array_buffers_.end(); ++it) {
      31      277007 :     old_buffer = it->first;
      32             :     DCHECK_EQ(page_, Page::FromHeapObject(old_buffer));
      33      277007 :     const CallbackResult result = callback(old_buffer, &new_buffer);
      34      277126 :     if (result == kKeepEntry) {
      35             :       kept_array_buffers.insert(*it);
      36      277126 :     } else if (result == kUpdateEntry) {
      37             :       DCHECK(!new_buffer.is_null());
      38             :       Page* target_page = Page::FromHeapObject(new_buffer);
      39             :       {
      40             :         base::MutexGuard guard(target_page->mutex());
      41             :         LocalArrayBufferTracker* tracker = target_page->local_tracker();
      42       28095 :         if (tracker == nullptr) {
      43        1215 :           target_page->AllocateLocalTracker();
      44             :           tracker = target_page->local_tracker();
      45             :         }
      46             :         DCHECK_NOT_NULL(tracker);
      47       28095 :         const size_t length = it->second.length;
      48             :         // We should decrement before adding to avoid potential overflows in
      49             :         // the external memory counters.
      50             :         DCHECK_EQ(it->first->is_wasm_memory(), it->second.is_wasm_memory);
      51       28095 :         tracker->AddInternal(new_buffer, length);
      52       28091 :         MemoryChunk::MoveExternalBackingStoreBytes(
      53             :             ExternalBackingStoreType::kArrayBuffer,
      54             :             static_cast<MemoryChunk*>(page_),
      55             :             static_cast<MemoryChunk*>(target_page), length);
      56             :       }
      57      249034 :     } else if (result == kRemoveEntry) {
      58      249034 :       freed_memory += it->second.length;
      59             :       // We pass backing_store() and stored length to the collector for freeing
      60             :       // the backing store. Wasm allocations will go through their own tracker
      61             :       // based on the backing store.
      62      249034 :       backing_stores_to_free.push_back(it->second);
      63             :     } else {
      64           0 :       UNREACHABLE();
      65             :     }
      66             :   }
      67      237933 :   if (freed_memory) {
      68        6250 :     page_->DecrementExternalBackingStoreBytes(
      69             :         ExternalBackingStoreType::kArrayBuffer, freed_memory);
      70             :     // TODO(wez): Remove backing-store from external memory accounting.
      71        6251 :     page_->heap()->update_external_memory_concurrently_freed(
      72             :         static_cast<intptr_t>(freed_memory));
      73             :   }
      74             : 
      75             :   array_buffers_.swap(kept_array_buffers);
      76             : 
      77             :   // Pass the backing stores that need to be freed to the main thread for
      78             :   // potential later distribution.
      79      713788 :   page_->heap()->array_buffer_collector()->QueueOrFreeGarbageAllocations(
      80             :       std::move(backing_stores_to_free));
      81      237957 : }
      82             : 
      83       20973 : void ArrayBufferTracker::PrepareToFreeDeadInNewSpace(Heap* heap) {
      84             :   DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE);
      85      172893 :   for (Page* page :
      86             :        PageRange(heap->new_space()->from_space().first_page(), nullptr)) {
      87             :     bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers);
      88      151920 :     CHECK(empty);
      89             :   }
      90       20973 : }
      91             : 
      92      407333 : void ArrayBufferTracker::FreeAll(Page* page) {
      93             :   LocalArrayBufferTracker* tracker = page->local_tracker();
      94      407333 :   if (tracker == nullptr) return;
      95      264463 :   tracker->Free([](JSArrayBuffer buffer) { return true; });
      96      264463 :   if (tracker->IsEmpty()) {
      97      264463 :     page->ReleaseLocalTracker();
      98             :   }
      99             : }
     100             : 
     101       86645 : bool ArrayBufferTracker::ProcessBuffers(Page* page, ProcessingMode mode) {
     102             :   LocalArrayBufferTracker* tracker = page->local_tracker();
     103      238565 :   if (tracker == nullptr) return true;
     104             : 
     105             :   DCHECK(page->SweepingDone());
     106      526192 :   tracker->Process([mode](JSArrayBuffer old_buffer, JSArrayBuffer* new_buffer) {
     107             :     MapWord map_word = old_buffer->map_word();
     108      277142 :     if (map_word.IsForwardingAddress()) {
     109       28092 :       *new_buffer = JSArrayBuffer::cast(map_word.ToForwardingAddress());
     110       28092 :       return LocalArrayBufferTracker::kUpdateEntry;
     111             :     }
     112             :     return mode == kUpdateForwardedKeepOthers
     113             :                ? LocalArrayBufferTracker::kKeepEntry
     114      249050 :                : LocalArrayBufferTracker::kRemoveEntry;
     115      237923 :   });
     116       86679 :   return tracker->IsEmpty();
     117             : }
     118             : 
     119         190 : bool ArrayBufferTracker::IsTracked(JSArrayBuffer buffer) {
     120             :   Page* page = Page::FromHeapObject(buffer);
     121             :   {
     122             :     base::MutexGuard guard(page->mutex());
     123             :     LocalArrayBufferTracker* tracker = page->local_tracker();
     124         190 :     if (tracker == nullptr) return false;
     125         170 :     return tracker->IsTracked(buffer);
     126             :   }
     127             : }
     128             : 
     129       61517 : void ArrayBufferTracker::TearDown(Heap* heap) {
     130             :   // ArrayBuffers can only be found in NEW_SPACE and OLD_SPACE.
     131      206248 :   for (Page* p : *heap->old_space()) {
     132      144730 :     FreeAll(p);
     133             :   }
     134             :   NewSpace* new_space = heap->new_space();
     135       61518 :   if (new_space->to_space().is_committed()) {
     136      321394 :     for (Page* p : new_space->to_space()) {
     137      259875 :       FreeAll(p);
     138             :     }
     139             :   }
     140             : #ifdef DEBUG
     141             :   if (new_space->from_space().is_committed()) {
     142             :     for (Page* p : new_space->from_space()) {
     143             :       DCHECK(!p->contains_array_buffers());
     144             :     }
     145             :   }
     146             : #endif  // DEBUG
     147       61519 : }
     148             : 
     149             : }  // namespace internal
     150      120216 : }  // namespace v8

Generated by: LCOV version 1.10