LCOV - code coverage report
Current view: top level - test/cctest/heap - test-array-buffer-tracker.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 204 204 100.0 %
Date: 2017-10-20 Functions: 13 13 100.0 %

          Line data    Source code
       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             : #include "src/api.h"
       6             : #include "src/heap/array-buffer-tracker.h"
       7             : #include "src/heap/spaces.h"
       8             : #include "src/isolate.h"
       9             : #include "src/objects-inl.h"
      10             : #include "test/cctest/cctest.h"
      11             : #include "test/cctest/heap/heap-utils.h"
      12             : 
      13             : namespace {
      14             : 
      15             : typedef i::LocalArrayBufferTracker LocalTracker;
      16             : 
      17             : bool IsTracked(i::JSArrayBuffer* buf) {
      18         204 :   return i::ArrayBufferTracker::IsTracked(buf);
      19             : }
      20             : 
      21             : }  // namespace
      22             : 
      23             : namespace v8 {
      24             : namespace internal {
      25             : namespace heap {
      26             : 
      27             : // The following tests make sure that JSArrayBuffer tracking works expected when
      28             : // moving the objects through various spaces during GC phases.
      29             : 
      30       23724 : TEST(ArrayBuffer_OnlyMC) {
      31             :   ManualGCScope manual_gc_scope;
      32           6 :   CcTest::InitializeVM();
      33          12 :   LocalContext env;
      34           6 :   v8::Isolate* isolate = env->GetIsolate();
      35           6 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
      36             : 
      37             :   JSArrayBuffer* raw_ab = nullptr;
      38             :   {
      39           6 :     v8::HandleScope handle_scope(isolate);
      40           6 :     Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100);
      41             :     Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
      42           6 :     CHECK(IsTracked(*buf));
      43           6 :     heap::GcAndSweep(heap, OLD_SPACE);
      44           6 :     CHECK(IsTracked(*buf));
      45           6 :     heap::GcAndSweep(heap, OLD_SPACE);
      46           6 :     CHECK(IsTracked(*buf));
      47             :     raw_ab = *buf;
      48             :     // Prohibit page from being released.
      49          12 :     Page::FromAddress(buf->address())->MarkNeverEvacuate();
      50             :   }
      51             :   // 2 GCs are needed because we promote to old space as live, meaning that
      52             :   // we will survive one GC.
      53           6 :   heap::GcAndSweep(heap, OLD_SPACE);
      54           6 :   heap::GcAndSweep(heap, OLD_SPACE);
      55           6 :   CHECK(!IsTracked(raw_ab));
      56           6 : }
      57             : 
      58       23724 : TEST(ArrayBuffer_OnlyScavenge) {
      59             :   ManualGCScope manual_gc_scope;
      60           6 :   CcTest::InitializeVM();
      61          12 :   LocalContext env;
      62           6 :   v8::Isolate* isolate = env->GetIsolate();
      63           6 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
      64             : 
      65             :   JSArrayBuffer* raw_ab = nullptr;
      66             :   {
      67           6 :     v8::HandleScope handle_scope(isolate);
      68           6 :     Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100);
      69             :     Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
      70           6 :     CHECK(IsTracked(*buf));
      71           6 :     heap::GcAndSweep(heap, NEW_SPACE);
      72           6 :     CHECK(IsTracked(*buf));
      73           6 :     heap::GcAndSweep(heap, NEW_SPACE);
      74           6 :     CHECK(IsTracked(*buf));
      75           6 :     heap::GcAndSweep(heap, NEW_SPACE);
      76           6 :     CHECK(IsTracked(*buf));
      77             :     raw_ab = *buf;
      78             :     // Prohibit page from being released.
      79          12 :     Page::FromAddress(buf->address())->MarkNeverEvacuate();
      80             :   }
      81             :   // 2 GCs are needed because we promote to old space as live, meaning that
      82             :   // we will survive one GC.
      83           6 :   heap::GcAndSweep(heap, OLD_SPACE);
      84           6 :   heap::GcAndSweep(heap, OLD_SPACE);
      85           6 :   CHECK(!IsTracked(raw_ab));
      86           6 : }
      87             : 
      88       23724 : TEST(ArrayBuffer_ScavengeAndMC) {
      89             :   ManualGCScope manual_gc_scope;
      90           6 :   CcTest::InitializeVM();
      91          12 :   LocalContext env;
      92           6 :   v8::Isolate* isolate = env->GetIsolate();
      93           6 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
      94             : 
      95             :   JSArrayBuffer* raw_ab = nullptr;
      96             :   {
      97           6 :     v8::HandleScope handle_scope(isolate);
      98           6 :     Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100);
      99             :     Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
     100           6 :     CHECK(IsTracked(*buf));
     101           6 :     heap::GcAndSweep(heap, NEW_SPACE);
     102           6 :     CHECK(IsTracked(*buf));
     103           6 :     heap::GcAndSweep(heap, NEW_SPACE);
     104           6 :     CHECK(IsTracked(*buf));
     105           6 :     heap::GcAndSweep(heap, OLD_SPACE);
     106           6 :     CHECK(IsTracked(*buf));
     107           6 :     heap::GcAndSweep(heap, NEW_SPACE);
     108           6 :     CHECK(IsTracked(*buf));
     109             :     raw_ab = *buf;
     110             :     // Prohibit page from being released.
     111          12 :     Page::FromAddress(buf->address())->MarkNeverEvacuate();
     112             :   }
     113             :   // 2 GCs are needed because we promote to old space as live, meaning that
     114             :   // we will survive one GC.
     115           6 :   heap::GcAndSweep(heap, OLD_SPACE);
     116           6 :   heap::GcAndSweep(heap, OLD_SPACE);
     117           6 :   CHECK(!IsTracked(raw_ab));
     118           6 : }
     119             : 
     120       23724 : TEST(ArrayBuffer_Compaction) {
     121           6 :   if (FLAG_never_compact) return;
     122             :   ManualGCScope manual_gc_scope;
     123           6 :   FLAG_manual_evacuation_candidates_selection = true;
     124           6 :   CcTest::InitializeVM();
     125          12 :   LocalContext env;
     126           6 :   v8::Isolate* isolate = env->GetIsolate();
     127           6 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
     128           6 :   heap::AbandonCurrentlyFreeMemory(heap->old_space());
     129             : 
     130          12 :   v8::HandleScope handle_scope(isolate);
     131           6 :   Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(isolate, 100);
     132             :   Handle<JSArrayBuffer> buf1 = v8::Utils::OpenHandle(*ab1);
     133           6 :   CHECK(IsTracked(*buf1));
     134           6 :   heap::GcAndSweep(heap, NEW_SPACE);
     135           6 :   heap::GcAndSweep(heap, NEW_SPACE);
     136             : 
     137           6 :   Page* page_before_gc = Page::FromAddress(buf1->address());
     138           6 :   heap::ForceEvacuationCandidate(page_before_gc);
     139           6 :   CHECK(IsTracked(*buf1));
     140             : 
     141           6 :   CcTest::CollectAllGarbage();
     142             : 
     143           6 :   Page* page_after_gc = Page::FromAddress(buf1->address());
     144           6 :   CHECK(IsTracked(*buf1));
     145             : 
     146           6 :   CHECK_NE(page_before_gc, page_after_gc);
     147             : }
     148             : 
     149       23724 : TEST(ArrayBuffer_UnregisterDuringSweep) {
     150             : // Regular pages in old space (without compaction) are processed concurrently
     151             : // in the sweeper. If we happen to unregister a buffer (either explicitly, or
     152             : // implicitly through e.g. |Externalize|) we need to sync with the sweeper
     153             : // task.
     154             : //
     155             : // Note: This test will will only fail on TSAN configurations.
     156             : 
     157             : // Disable verify-heap since it forces sweeping to be completed in the
     158             : // epilogue of the GC.
     159             : #ifdef VERIFY_HEAP
     160             :   i::FLAG_verify_heap = false;
     161             : #endif  // VERIFY_HEAP
     162             :   ManualGCScope manual_gc_scope;
     163             : 
     164           6 :   CcTest::InitializeVM();
     165          12 :   LocalContext env;
     166           6 :   v8::Isolate* isolate = env->GetIsolate();
     167           6 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
     168             :   {
     169           6 :     v8::HandleScope handle_scope(isolate);
     170           6 :     Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100);
     171             :     Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
     172             : 
     173             :     {
     174           6 :       v8::HandleScope handle_scope(isolate);
     175             :       // Allocate another buffer on the same page to force processing a
     176             :       // non-empty set of buffers in the last GC.
     177           6 :       Local<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(isolate, 100);
     178             :       Handle<JSArrayBuffer> buf2 = v8::Utils::OpenHandle(*ab2);
     179           6 :       CHECK(IsTracked(*buf));
     180           6 :       CHECK(IsTracked(*buf));
     181           6 :       heap::GcAndSweep(heap, NEW_SPACE);
     182           6 :       CHECK(IsTracked(*buf));
     183           6 :       CHECK(IsTracked(*buf));
     184           6 :       heap::GcAndSweep(heap, NEW_SPACE);
     185           6 :       CHECK(IsTracked(*buf));
     186           6 :       CHECK(IsTracked(*buf2));
     187             :     }
     188             : 
     189           6 :     CcTest::CollectGarbage(OLD_SPACE);
     190             :     // |Externalize| will cause the buffer to be |Unregister|ed. Without
     191             :     // barriers and proper synchronization this will trigger a data race on
     192             :     // TSAN.
     193           6 :     v8::ArrayBuffer::Contents contents = ab->Externalize();
     194           6 :     heap->isolate()->array_buffer_allocator()->Free(contents.Data(),
     195           6 :                                                     contents.ByteLength());
     196             :   }
     197           6 : }
     198             : 
     199       23724 : TEST(ArrayBuffer_NonLivePromotion) {
     200           6 :   if (!FLAG_incremental_marking) return;
     201             :   ManualGCScope manual_gc_scope;
     202             :   // The test verifies that the marking state is preserved when promoting
     203             :   // a buffer to old space.
     204           6 :   CcTest::InitializeVM();
     205          12 :   LocalContext env;
     206           6 :   v8::Isolate* isolate = env->GetIsolate();
     207          12 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
     208             : 
     209             :   JSArrayBuffer* raw_ab = nullptr;
     210             :   {
     211           6 :     v8::HandleScope handle_scope(isolate);
     212             :     Handle<FixedArray> root =
     213           6 :         heap->isolate()->factory()->NewFixedArray(1, TENURED);
     214             :     {
     215           6 :       v8::HandleScope handle_scope(isolate);
     216           6 :       Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100);
     217             :       Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
     218           6 :       root->set(0, *buf);  // Buffer that should not be promoted as live.
     219             :     }
     220           6 :     heap::SimulateIncrementalMarking(heap, false);
     221           6 :     CHECK(IsTracked(JSArrayBuffer::cast(root->get(0))));
     222           6 :     heap::GcAndSweep(heap, NEW_SPACE);
     223           6 :     CHECK(IsTracked(JSArrayBuffer::cast(root->get(0))));
     224           6 :     heap::GcAndSweep(heap, NEW_SPACE);
     225           6 :     CHECK(IsTracked(JSArrayBuffer::cast(root->get(0))));
     226             :     raw_ab = JSArrayBuffer::cast(root->get(0));
     227           6 :     root->set(0, heap->undefined_value());
     228           6 :     heap::SimulateIncrementalMarking(heap, true);
     229             :     // Prohibit page from being released.
     230           6 :     Page::FromAddress(raw_ab->address())->MarkNeverEvacuate();
     231           6 :     heap::GcAndSweep(heap, OLD_SPACE);
     232           6 :     CHECK(!IsTracked(raw_ab));
     233             :   }
     234             : }
     235             : 
     236       23724 : TEST(ArrayBuffer_LivePromotion) {
     237           6 :   if (!FLAG_incremental_marking) return;
     238             :   ManualGCScope manual_gc_scope;
     239             :   // The test verifies that the marking state is preserved when promoting
     240             :   // a buffer to old space.
     241           6 :   CcTest::InitializeVM();
     242          12 :   LocalContext env;
     243           6 :   v8::Isolate* isolate = env->GetIsolate();
     244          12 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
     245             : 
     246             :   JSArrayBuffer* raw_ab = nullptr;
     247             :   {
     248           6 :     v8::HandleScope handle_scope(isolate);
     249             :     Handle<FixedArray> root =
     250           6 :         heap->isolate()->factory()->NewFixedArray(1, TENURED);
     251             :     {
     252           6 :       v8::HandleScope handle_scope(isolate);
     253           6 :       Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100);
     254             :       Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
     255           6 :       root->set(0, *buf);  // Buffer that should be promoted as live.
     256             :     }
     257           6 :     heap::SimulateIncrementalMarking(heap, true);
     258           6 :     CHECK(IsTracked(JSArrayBuffer::cast(root->get(0))));
     259           6 :     heap::GcAndSweep(heap, NEW_SPACE);
     260           6 :     CHECK(IsTracked(JSArrayBuffer::cast(root->get(0))));
     261           6 :     heap::GcAndSweep(heap, NEW_SPACE);
     262           6 :     CHECK(IsTracked(JSArrayBuffer::cast(root->get(0))));
     263             :     raw_ab = JSArrayBuffer::cast(root->get(0));
     264           6 :     root->set(0, heap->undefined_value());
     265             :     // Prohibit page from being released.
     266           6 :     Page::FromAddress(raw_ab->address())->MarkNeverEvacuate();
     267           6 :     heap::GcAndSweep(heap, OLD_SPACE);
     268           6 :     CHECK(IsTracked(raw_ab));
     269             :   }
     270             : }
     271             : 
     272       23724 : TEST(ArrayBuffer_SemiSpaceCopyThenPagePromotion) {
     273           6 :   if (!i::FLAG_incremental_marking) return;
     274             :   ManualGCScope manual_gc_scope;
     275             :   // The test verifies that the marking state is preserved across semispace
     276             :   // copy.
     277           6 :   CcTest::InitializeVM();
     278          12 :   LocalContext env;
     279           6 :   v8::Isolate* isolate = env->GetIsolate();
     280          12 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
     281             : 
     282           6 :   heap::SealCurrentObjects(heap);
     283             :   {
     284           6 :     v8::HandleScope handle_scope(isolate);
     285             :     Handle<FixedArray> root =
     286           6 :         heap->isolate()->factory()->NewFixedArray(1, TENURED);
     287             :     {
     288           6 :       v8::HandleScope handle_scope(isolate);
     289           6 :       Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 100);
     290             :       Handle<JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
     291           6 :       root->set(0, *buf);  // Buffer that should be promoted as live.
     292          12 :       Page::FromAddress(buf->address())->MarkNeverEvacuate();
     293             :     }
     294             :     std::vector<Handle<FixedArray>> handles;
     295             :     // Make the whole page transition from new->old, getting the buffers
     296             :     // processed in the sweeper (relying on marking information) instead of
     297             :     // processing during newspace evacuation.
     298           6 :     heap::FillCurrentPage(heap->new_space(), &handles);
     299           6 :     CHECK(IsTracked(JSArrayBuffer::cast(root->get(0))));
     300           6 :     heap::GcAndSweep(heap, NEW_SPACE);
     301           6 :     heap::SimulateIncrementalMarking(heap, true);
     302           6 :     heap::GcAndSweep(heap, OLD_SPACE);
     303          12 :     CHECK(IsTracked(JSArrayBuffer::cast(root->get(0))));
     304             :   }
     305             : }
     306             : 
     307       23724 : UNINITIALIZED_TEST(ArrayBuffer_SemiSpaceCopyMultipleTasks) {
     308           6 :   if (FLAG_optimize_for_size) return;
     309             :   // Test allocates JSArrayBuffer on different pages before triggering a
     310             :   // full GC that performs the semispace copy. If parallelized, this test
     311             :   // ensures proper synchronization in TSAN configurations.
     312           6 :   FLAG_min_semi_space_size = 2 * Page::kPageSize / MB;
     313             :   v8::Isolate::CreateParams create_params;
     314           6 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     315           6 :   v8::Isolate* isolate = v8::Isolate::New(create_params);
     316             :   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
     317             :   {
     318             :     v8::Isolate::Scope isolate_scope(isolate);
     319          12 :     v8::HandleScope handle_scope(isolate);
     320          12 :     v8::Context::New(isolate)->Enter();
     321          12 :     Heap* heap = i_isolate->heap();
     322             : 
     323             :     // Ensure heap is in a clean state.
     324             :     heap->CollectAllGarbage(Heap::kFinalizeIncrementalMarkingMask,
     325           6 :                             GarbageCollectionReason::kTesting);
     326             :     heap->CollectAllGarbage(Heap::kFinalizeIncrementalMarkingMask,
     327           6 :                             GarbageCollectionReason::kTesting);
     328             : 
     329           6 :     Local<v8::ArrayBuffer> ab1 = v8::ArrayBuffer::New(isolate, 100);
     330             :     Handle<JSArrayBuffer> buf1 = v8::Utils::OpenHandle(*ab1);
     331           6 :     heap::FillCurrentPage(heap->new_space());
     332           6 :     Local<v8::ArrayBuffer> ab2 = v8::ArrayBuffer::New(isolate, 100);
     333             :     Handle<JSArrayBuffer> buf2 = v8::Utils::OpenHandle(*ab2);
     334          18 :     CHECK_NE(Page::FromAddress(buf1->address()),
     335             :              Page::FromAddress(buf2->address()));
     336           6 :     heap::GcAndSweep(heap, OLD_SPACE);
     337             :   }
     338           6 :   isolate->Dispose();
     339             : }
     340             : 
     341       23724 : TEST(ArrayBuffer_RetainedSizeIncreases) {
     342           6 :   CcTest::InitializeVM();
     343           6 :   LocalContext env;
     344           6 :   v8::Isolate* isolate = env->GetIsolate();
     345           6 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
     346             : 
     347           6 :   const size_t retained_before = ArrayBufferTracker::RetainedInNewSpace(heap);
     348             :   {
     349             :     const size_t kArraybufferSize = 117;
     350           6 :     v8::HandleScope handle_scope(isolate);
     351           6 :     Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, kArraybufferSize);
     352             :     USE(ab);
     353           6 :     const size_t retained_after = ArrayBufferTracker::RetainedInNewSpace(heap);
     354           6 :     CHECK_EQ(kArraybufferSize, retained_after - retained_before);
     355           6 :   }
     356           6 : }
     357             : 
     358       23724 : TEST(ArrayBuffer_RetainedSizeDecreases) {
     359           6 :   CcTest::InitializeVM();
     360           6 :   LocalContext env;
     361           6 :   v8::Isolate* isolate = env->GetIsolate();
     362           6 :   Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
     363             : 
     364           6 :   const size_t retained_before = ArrayBufferTracker::RetainedInNewSpace(heap);
     365             :   {
     366             :     const size_t kArraybufferSize = 117;
     367           6 :     v8::HandleScope handle_scope(isolate);
     368           6 :     Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, kArraybufferSize);
     369           6 :     USE(ab);
     370             :   }
     371           6 :   heap::GcAndSweep(heap, OLD_SPACE);
     372           6 :   const size_t retained_after = ArrayBufferTracker::RetainedInNewSpace(heap);
     373           6 :   CHECK_EQ(0, retained_after - retained_before);
     374           6 : }
     375             : 
     376             : }  // namespace heap
     377             : }  // namespace internal
     378       71154 : }  // namespace v8

Generated by: LCOV version 1.10