LCOV - code coverage report
Current view: top level - src/heap - array-buffer-tracker.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 61 63 96.8 %
Date: 2019-02-19 Functions: 10 10 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      229811 : LocalArrayBufferTracker::~LocalArrayBufferTracker() {
      18      229811 :   CHECK(array_buffers_.empty());
      19      229816 : }
      20             : 
      21             : template <typename Callback>
      22      168788 : void LocalArrayBufferTracker::Process(Callback callback) {
      23             :   std::vector<JSArrayBuffer::Allocation> backing_stores_to_free;
      24      168823 :   TrackingData kept_array_buffers;
      25             : 
      26      168823 :   JSArrayBuffer new_buffer;
      27             :   JSArrayBuffer old_buffer;
      28             :   size_t freed_memory = 0;
      29      624102 :   for (TrackingData::iterator it = array_buffers_.begin();
      30             :        it != array_buffers_.end(); ++it) {
      31      286453 :     old_buffer = it->first;
      32             :     DCHECK_EQ(page_, Page::FromHeapObject(old_buffer));
      33      286453 :     const CallbackResult result = callback(old_buffer, &new_buffer);
      34      286494 :     if (result == kKeepEntry) {
      35           0 :       kept_array_buffers.insert(*it);
      36      286494 :     } else if (result == kUpdateEntry) {
      37             :       DCHECK(!new_buffer.is_null());
      38      103323 :       Page* target_page = Page::FromHeapObject(new_buffer);
      39             :       {
      40      100827 :         base::MutexGuard guard(target_page->mutex());
      41             :         LocalArrayBufferTracker* tracker = target_page->local_tracker();
      42      100825 :         if (tracker == nullptr) {
      43        2494 :           target_page->AllocateLocalTracker();
      44             :           tracker = target_page->local_tracker();
      45             :         }
      46             :         DCHECK_NOT_NULL(tracker);
      47      100829 :         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      100829 :         tracker->AddInternal(new_buffer, length);
      52      100824 :         MemoryChunk::MoveExternalBackingStoreBytes(
      53             :             ExternalBackingStoreType::kArrayBuffer,
      54             :             static_cast<MemoryChunk*>(page_),
      55      100824 :             static_cast<MemoryChunk*>(target_page), length);
      56             :       }
      57      185667 :     } else if (result == kRemoveEntry) {
      58      185667 :       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      185667 :       backing_stores_to_free.push_back(it->second);
      63             :     } else {
      64           0 :       UNREACHABLE();
      65             :     }
      66             :   }
      67      168826 :   if (freed_memory) {
      68        6433 :     page_->DecrementExternalBackingStoreBytes(
      69      181689 :         ExternalBackingStoreType::kArrayBuffer, freed_memory);
      70             :     // TODO(wez): Remove backing-store from external memory accounting.
      71             :     page_->heap()->update_external_memory_concurrently_freed(
      72        6433 :         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      168823 :   page_->heap()->array_buffer_collector()->QueueOrFreeGarbageAllocations(
      80      337662 :       std::move(backing_stores_to_free));
      81      168837 : }
      82             : 
      83       23490 : void ArrayBufferTracker::PrepareToFreeDeadInNewSpace(Heap* heap) {
      84             :   DCHECK_EQ(heap->gc_state(), Heap::HeapState::SCAVENGE);
      85      111445 :   for (Page* page :
      86             :        PageRange(heap->new_space()->from_space().first_page(), nullptr)) {
      87             :     bool empty = ProcessBuffers(page, kUpdateForwardedRemoveOthers);
      88       87955 :     CHECK(empty);
      89             :   }
      90       23490 : }
      91             : 
      92      280630 : void ArrayBufferTracker::FreeAll(Page* page) {
      93             :   LocalArrayBufferTracker* tracker = page->local_tracker();
      94      561260 :   if (tracker == nullptr) return;
      95      134591 :   tracker->Free([](JSArrayBuffer buffer) { return true; });
      96      134591 :   if (tracker->IsEmpty()) {
      97      134591 :     page->ReleaseLocalTracker();
      98             :   }
      99             : }
     100             : 
     101      171154 : bool ArrayBufferTracker::ProcessBuffers(Page* page, ProcessingMode mode) {
     102             :   LocalArrayBufferTracker* tracker = page->local_tracker();
     103      171154 :   if (tracker == nullptr) return true;
     104             : 
     105             :   DCHECK(page->SweepingDone());
     106      286494 :   tracker->Process([mode](JSArrayBuffer old_buffer, JSArrayBuffer* new_buffer) {
     107             :     MapWord map_word = old_buffer->map_word();
     108      286494 :     if (map_word.IsForwardingAddress()) {
     109      100818 :       *new_buffer = JSArrayBuffer::cast(map_word.ToForwardingAddress());
     110      100818 :       return LocalArrayBufferTracker::kUpdateEntry;
     111             :     }
     112      185670 :     return mode == kUpdateForwardedKeepOthers
     113             :                ? LocalArrayBufferTracker::kKeepEntry
     114      185670 :                : LocalArrayBufferTracker::kRemoveEntry;
     115      168807 :   });
     116       83230 :   return tracker->IsEmpty();
     117             : }
     118             : 
     119         190 : bool ArrayBufferTracker::IsTracked(JSArrayBuffer buffer) {
     120         190 :   Page* page = Page::FromHeapObject(buffer);
     121             :   {
     122         190 :     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      122068 : void ArrayBufferTracker::TearDown(Heap* heap) {
     130             :   // ArrayBuffers can only be found in NEW_SPACE and OLD_SPACE.
     131      205928 :   for (Page* p : *heap->old_space()) {
     132      144894 :     FreeAll(p);
     133             :   }
     134             :   NewSpace* new_space = heap->new_space();
     135       61034 :   if (new_space->to_space().is_committed()) {
     136      191595 :     for (Page* p : new_space->to_space()) {
     137      130561 :       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       61034 : }
     148             : 
     149             : }  // namespace internal
     150      178779 : }  // namespace v8

Generated by: LCOV version 1.10