LCOV - code coverage report
Current view: top level - test/cctest/heap - test-weak-references.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 373 375 99.5 %
Date: 2019-01-20 Functions: 21 21 100.0 %

          Line data    Source code
       1             : // Copyright 2018 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-inl.h"
       6             : #include "src/assembler-inl.h"
       7             : #include "src/heap/factory.h"
       8             : #include "src/isolate.h"
       9             : #include "src/objects/smi.h"
      10             : #include "test/cctest/cctest.h"
      11             : #include "test/cctest/heap/heap-tester.h"
      12             : #include "test/cctest/heap/heap-utils.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : namespace heap {
      17             : 
      18          50 : Handle<FeedbackVector> CreateFeedbackVectorForTest(
      19             :     v8::Isolate* isolate, Factory* factory,
      20             :     PretenureFlag pretenure_flag = NOT_TENURED) {
      21             :   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
      22             :   v8::Local<v8::Script> script =
      23             :       v8::Script::Compile(isolate->GetCurrentContext(),
      24             :                           v8::String::NewFromUtf8(isolate, "function foo() {}",
      25             :                                                   v8::NewStringType::kNormal)
      26         100 :                               .ToLocalChecked())
      27          50 :           .ToLocalChecked();
      28             :   Handle<Object> obj = v8::Utils::OpenHandle(*script);
      29             :   Handle<SharedFunctionInfo> shared_function =
      30         100 :       Handle<SharedFunctionInfo>(JSFunction::cast(*obj)->shared(), i_isolate);
      31             :   Handle<FeedbackVector> fv =
      32          50 :       factory->NewFeedbackVector(shared_function, pretenure_flag);
      33          50 :   return fv;
      34             : }
      35             : 
      36       28342 : TEST(WeakReferencesBasic) {
      37           5 :   CcTest::InitializeVM();
      38             :   Isolate* isolate = CcTest::i_isolate();
      39             :   Factory* factory = isolate->factory();
      40             :   HandleScope outer_scope(isolate);
      41             : 
      42             :   Handle<FeedbackVector> fv =
      43           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory);
      44           5 :   CHECK(Heap::InNewSpace(*fv));
      45             : 
      46           5 :   MaybeObject code_object = fv->optimized_code_weak_or_smi();
      47           5 :   CHECK(code_object->IsSmi());
      48           5 :   CcTest::CollectAllGarbage();
      49           5 :   CHECK(Heap::InNewSpace(*fv));
      50          10 :   CHECK_EQ(code_object, fv->optimized_code_weak_or_smi());
      51             : 
      52             :   {
      53             :     HandleScope inner_scope(isolate);
      54             : 
      55             :     // Create a new Code.
      56          20 :     Assembler assm(AssemblerOptions{});
      57           5 :     assm.nop();  // supported on all architectures
      58           5 :     CodeDesc desc;
      59           5 :     assm.GetCode(isolate, &desc);
      60             :     Handle<Code> code =
      61          10 :         isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
      62          10 :     CHECK(code->IsCode());
      63             : 
      64          10 :     fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
      65           5 :     HeapObject code_heap_object;
      66           5 :     CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(
      67             :         &code_heap_object));
      68          10 :     CHECK_EQ(*code, code_heap_object);
      69             : 
      70           5 :     CcTest::CollectAllGarbage();
      71             : 
      72           5 :     CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(
      73             :         &code_heap_object));
      74          10 :     CHECK_EQ(*code, code_heap_object);
      75             :   }  // code will go out of scope.
      76             : 
      77           5 :   CcTest::CollectAllGarbage();
      78           5 :   CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
      79           5 : }
      80             : 
      81       28342 : TEST(WeakReferencesOldToOld) {
      82             :   // Like WeakReferencesBasic, but the updated weak slot is in the old space,
      83             :   // and referring to an old space object.
      84             :   ManualGCScope manual_gc_scope;
      85           5 :   FLAG_manual_evacuation_candidates_selection = true;
      86           5 :   CcTest::InitializeVM();
      87             :   Isolate* isolate = CcTest::i_isolate();
      88             :   Factory* factory = isolate->factory();
      89          15 :   Heap* heap = isolate->heap();
      90             : 
      91             :   HandleScope outer_scope(isolate);
      92             :   Handle<FeedbackVector> fv =
      93           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory, TENURED);
      94           5 :   CHECK(heap->InOldSpace(*fv));
      95             : 
      96             :   // Create a new FixedArray which the FeedbackVector will point to.
      97           5 :   Handle<FixedArray> fixed_array = factory->NewFixedArray(1, TENURED);
      98           5 :   CHECK(heap->InOldSpace(*fixed_array));
      99          10 :   fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
     100             : 
     101             :   Page* page_before_gc = Page::FromHeapObject(*fixed_array);
     102           5 :   heap::ForceEvacuationCandidate(page_before_gc);
     103           5 :   CcTest::CollectAllGarbage();
     104           5 :   CHECK(heap->InOldSpace(*fixed_array));
     105             : 
     106           5 :   HeapObject heap_object;
     107           5 :   CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(&heap_object));
     108          10 :   CHECK_EQ(heap_object, *fixed_array);
     109           5 : }
     110             : 
     111       28342 : TEST(WeakReferencesOldToNew) {
     112             :   // Like WeakReferencesBasic, but the updated weak slot is in the old space,
     113             :   // and referring to an new space object.
     114           5 :   CcTest::InitializeVM();
     115             :   Isolate* isolate = CcTest::i_isolate();
     116             :   Factory* factory = isolate->factory();
     117           5 :   Heap* heap = isolate->heap();
     118             : 
     119             :   HandleScope outer_scope(isolate);
     120             :   Handle<FeedbackVector> fv =
     121           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory, TENURED);
     122           5 :   CHECK(heap->InOldSpace(*fv));
     123             : 
     124             :   // Create a new FixedArray which the FeedbackVector will point to.
     125           5 :   Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
     126           5 :   CHECK(Heap::InNewSpace(*fixed_array));
     127          10 :   fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
     128             : 
     129           5 :   CcTest::CollectAllGarbage();
     130             : 
     131           5 :   HeapObject heap_object;
     132           5 :   CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(&heap_object));
     133          10 :   CHECK_EQ(heap_object, *fixed_array);
     134           5 : }
     135             : 
     136       28342 : TEST(WeakReferencesOldToNewScavenged) {
     137             :   // Like WeakReferencesBasic, but the updated weak slot is in the old space,
     138             :   // and referring to an new space object, which is then scavenged.
     139           5 :   CcTest::InitializeVM();
     140             :   Isolate* isolate = CcTest::i_isolate();
     141             :   Factory* factory = isolate->factory();
     142           5 :   Heap* heap = isolate->heap();
     143             : 
     144             :   HandleScope outer_scope(isolate);
     145             :   Handle<FeedbackVector> fv =
     146           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory, TENURED);
     147           5 :   CHECK(heap->InOldSpace(*fv));
     148             : 
     149             :   // Create a new FixedArray which the FeedbackVector will point to.
     150           5 :   Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
     151           5 :   CHECK(Heap::InNewSpace(*fixed_array));
     152          10 :   fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
     153             : 
     154           5 :   CcTest::CollectGarbage(NEW_SPACE);
     155             : 
     156           5 :   HeapObject heap_object;
     157           5 :   CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(&heap_object));
     158          10 :   CHECK_EQ(heap_object, *fixed_array);
     159           5 : }
     160             : 
     161       28342 : TEST(WeakReferencesOldToCleared) {
     162             :   // Like WeakReferencesBasic, but the updated weak slot is in the old space,
     163             :   // and is cleared.
     164             :   ManualGCScope manual_gc_scope;
     165           5 :   FLAG_manual_evacuation_candidates_selection = true;
     166           5 :   CcTest::InitializeVM();
     167             :   Isolate* isolate = CcTest::i_isolate();
     168             :   Factory* factory = isolate->factory();
     169           5 :   Heap* heap = isolate->heap();
     170             : 
     171             :   HandleScope outer_scope(isolate);
     172             :   Handle<FeedbackVector> fv =
     173           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory, TENURED);
     174           5 :   CHECK(heap->InOldSpace(*fv));
     175             :   fv->set_optimized_code_weak_or_smi(
     176          10 :       HeapObjectReference::ClearedValue(isolate));
     177             : 
     178           5 :   CcTest::CollectAllGarbage();
     179           5 :   CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
     180           5 : }
     181             : 
     182       28342 : TEST(ObjectMovesBeforeClearingWeakField) {
     183           5 :   if (!FLAG_incremental_marking) {
     184           0 :     return;
     185             :   }
     186             :   ManualGCScope manual_gc_scope;
     187           5 :   CcTest::InitializeVM();
     188             :   Isolate* isolate = CcTest::i_isolate();
     189             :   Factory* factory = isolate->factory();
     190           5 :   Heap* heap = isolate->heap();
     191             : 
     192             :   HandleScope outer_scope(isolate);
     193             :   Handle<FeedbackVector> fv =
     194           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory);
     195           5 :   CHECK(Heap::InNewSpace(*fv));
     196           5 :   FeedbackVector fv_location = *fv;
     197             :   {
     198             :     HandleScope inner_scope(isolate);
     199             :     // Create a new FixedArray which the FeedbackVector will point to.
     200           5 :     Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
     201           5 :     CHECK(Heap::InNewSpace(*fixed_array));
     202          10 :     fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
     203             :     // inner_scope will go out of scope, so when marking the next time,
     204             :     // *fixed_array will stay white.
     205             :   }
     206             : 
     207             :   // Do marking steps; this will store *fv into the list for later processing
     208             :   // (since it points to a white object).
     209           5 :   SimulateIncrementalMarking(heap, true);
     210             : 
     211             :   // Scavenger will move *fv.
     212           5 :   CcTest::CollectGarbage(NEW_SPACE);
     213           5 :   FeedbackVector new_fv_location = *fv;
     214           5 :   CHECK_NE(fv_location, new_fv_location);
     215           5 :   CHECK(fv->optimized_code_weak_or_smi()->IsWeak());
     216             : 
     217             :   // Now we try to clear *fv.
     218           5 :   CcTest::CollectAllGarbage();
     219           5 :   CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
     220             : }
     221             : 
     222       28342 : TEST(ObjectWithWeakFieldDies) {
     223           5 :   if (!FLAG_incremental_marking) {
     224           5 :     return;
     225             :   }
     226             :   ManualGCScope manual_gc_scope;
     227           5 :   CcTest::InitializeVM();
     228             :   Isolate* isolate = CcTest::i_isolate();
     229             :   Factory* factory = isolate->factory();
     230           5 :   Heap* heap = isolate->heap();
     231             : 
     232             :   {
     233             :     HandleScope outer_scope(isolate);
     234             :     Handle<FeedbackVector> fv =
     235           5 :         CreateFeedbackVectorForTest(CcTest::isolate(), factory);
     236           5 :     CHECK(Heap::InNewSpace(*fv));
     237             :     {
     238             :       HandleScope inner_scope(isolate);
     239             :       // Create a new FixedArray which the FeedbackVector will point to.
     240           5 :       Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
     241           5 :       CHECK(Heap::InNewSpace(*fixed_array));
     242             :       fv->set_optimized_code_weak_or_smi(
     243          10 :           HeapObjectReference::Weak(*fixed_array));
     244             :       // inner_scope will go out of scope, so when marking the next time,
     245             :       // *fixed_array will stay white.
     246             :     }
     247             : 
     248             :     // Do marking steps; this will store *fv into the list for later processing
     249             :     // (since it points to a white object).
     250           5 :     SimulateIncrementalMarking(heap, true);
     251             :   }  // outer_scope goes out of scope
     252             : 
     253             :   // fv will die
     254           5 :   CcTest::CollectGarbage(NEW_SPACE);
     255             : 
     256             :   // This used to crash when processing the dead weak reference.
     257           5 :   CcTest::CollectAllGarbage();
     258             : }
     259             : 
     260       28342 : TEST(ObjectWithWeakReferencePromoted) {
     261           5 :   CcTest::InitializeVM();
     262             :   Isolate* isolate = CcTest::i_isolate();
     263             :   Factory* factory = isolate->factory();
     264          10 :   Heap* heap = isolate->heap();
     265             : 
     266             :   HandleScope outer_scope(isolate);
     267             :   Handle<FeedbackVector> fv =
     268           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory);
     269           5 :   CHECK(Heap::InNewSpace(*fv));
     270             : 
     271             :   // Create a new FixedArray which the FeedbackVector will point to.
     272           5 :   Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
     273           5 :   CHECK(Heap::InNewSpace(*fixed_array));
     274          10 :   fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
     275             : 
     276           5 :   CcTest::CollectGarbage(NEW_SPACE);
     277           5 :   CcTest::CollectGarbage(NEW_SPACE);
     278           5 :   CHECK(heap->InOldSpace(*fv));
     279           5 :   CHECK(heap->InOldSpace(*fixed_array));
     280             : 
     281           5 :   HeapObject heap_object;
     282           5 :   CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(&heap_object));
     283          10 :   CHECK_EQ(heap_object, *fixed_array);
     284           5 : }
     285             : 
     286       28342 : TEST(ObjectWithClearedWeakReferencePromoted) {
     287           5 :   CcTest::InitializeVM();
     288             :   Isolate* isolate = CcTest::i_isolate();
     289             :   Factory* factory = isolate->factory();
     290           5 :   Heap* heap = isolate->heap();
     291             : 
     292             :   HandleScope outer_scope(isolate);
     293             :   Handle<FeedbackVector> fv =
     294           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory);
     295           5 :   CHECK(Heap::InNewSpace(*fv));
     296             : 
     297             :   fv->set_optimized_code_weak_or_smi(
     298          10 :       HeapObjectReference::ClearedValue(isolate));
     299             : 
     300           5 :   CcTest::CollectGarbage(NEW_SPACE);
     301           5 :   CHECK(Heap::InNewSpace(*fv));
     302           5 :   CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
     303             : 
     304           5 :   CcTest::CollectGarbage(NEW_SPACE);
     305           5 :   CHECK(heap->InOldSpace(*fv));
     306           5 :   CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
     307             : 
     308           5 :   CcTest::CollectAllGarbage();
     309           5 :   CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
     310           5 : }
     311             : 
     312       28342 : TEST(WeakReferenceWriteBarrier) {
     313           5 :   if (!FLAG_incremental_marking) {
     314           5 :     return;
     315             :   }
     316             : 
     317             :   ManualGCScope manual_gc_scope;
     318           5 :   CcTest::InitializeVM();
     319             :   Isolate* isolate = CcTest::i_isolate();
     320             :   Factory* factory = isolate->factory();
     321           5 :   Heap* heap = isolate->heap();
     322             : 
     323             :   HandleScope outer_scope(isolate);
     324             :   Handle<FeedbackVector> fv =
     325           5 :       CreateFeedbackVectorForTest(CcTest::isolate(), factory);
     326           5 :   CHECK(Heap::InNewSpace(*fv));
     327             : 
     328             :   {
     329             :     HandleScope inner_scope(isolate);
     330             : 
     331             :     // Create a new FixedArray which the FeedbackVector will point to.
     332           5 :     Handle<FixedArray> fixed_array1 = factory->NewFixedArray(1);
     333           5 :     CHECK(Heap::InNewSpace(*fixed_array1));
     334             :     fv->set_optimized_code_weak_or_smi(
     335          10 :         HeapObjectReference::Weak(*fixed_array1));
     336             : 
     337           5 :     SimulateIncrementalMarking(heap, true);
     338             : 
     339           5 :     Handle<FixedArray> fixed_array2 = factory->NewFixedArray(1);
     340           5 :     CHECK(Heap::InNewSpace(*fixed_array2));
     341             :     // This write will trigger the write barrier.
     342             :     fv->set_optimized_code_weak_or_smi(
     343          10 :         HeapObjectReference::Weak(*fixed_array2));
     344             :   }
     345             : 
     346           5 :   CcTest::CollectAllGarbage();
     347             : 
     348             :   // Check that the write barrier treated the weak reference as strong.
     349           5 :   CHECK(fv->optimized_code_weak_or_smi()->IsWeak());
     350             : }
     351             : 
     352       28342 : TEST(EmptyWeakArray) {
     353           5 :   CcTest::InitializeVM();
     354             :   Isolate* isolate = CcTest::i_isolate();
     355             :   Factory* factory = isolate->factory();
     356             :   HandleScope outer_scope(isolate);
     357             : 
     358             :   Handle<WeakFixedArray> array = factory->empty_weak_fixed_array();
     359          10 :   CHECK(array->IsWeakFixedArray());
     360          10 :   CHECK(!array->IsFixedArray());
     361           5 :   CHECK_EQ(array->length(), 0);
     362           5 : }
     363             : 
     364       28342 : TEST(WeakArraysBasic) {
     365             :   ManualGCScope manual_gc_scope;
     366           5 :   CcTest::InitializeVM();
     367             :   Isolate* isolate = CcTest::i_isolate();
     368             :   Factory* factory = isolate->factory();
     369          10 :   Heap* heap = isolate->heap();
     370             :   HandleScope outer_scope(isolate);
     371             : 
     372             :   const int length = 4;
     373           5 :   Handle<WeakFixedArray> array = factory->NewWeakFixedArray(length);
     374          10 :   CHECK(array->IsWeakFixedArray());
     375          10 :   CHECK(!array->IsFixedArray());
     376           5 :   CHECK_EQ(array->length(), length);
     377           5 :   CHECK(Heap::InNewSpace(*array));
     378             : 
     379          20 :   for (int i = 0; i < length; ++i) {
     380          20 :     HeapObject heap_object;
     381          20 :     CHECK(array->Get(i)->GetHeapObjectIfStrong(&heap_object));
     382          40 :     CHECK_EQ(heap_object, ReadOnlyRoots(heap).undefined_value());
     383             :   }
     384             : 
     385             :   Handle<HeapObject> saved;
     386             :   {
     387             :     HandleScope inner_scope(isolate);
     388           5 :     Handle<FixedArray> index0 = factory->NewFixedArray(1);
     389             :     index0->set(0, Smi::FromInt(2016));
     390           5 :     Handle<FixedArray> index1 = factory->NewFixedArray(1);
     391             :     index1->set(0, Smi::FromInt(2017));
     392             : 
     393           5 :     Handle<FixedArray> index2 = factory->NewFixedArray(1);
     394             :     index2->set(0, Smi::FromInt(2018));
     395           5 :     Handle<FixedArray> index3 = factory->NewFixedArray(1);
     396             :     index3->set(0, Smi::FromInt(2019));
     397             : 
     398          10 :     array->Set(0, HeapObjectReference::Weak(*index0));
     399          10 :     array->Set(1, HeapObjectReference::Weak(*index1));
     400          10 :     array->Set(2, HeapObjectReference::Strong(*index2));
     401          10 :     array->Set(3, HeapObjectReference::Weak(*index3));
     402           5 :     saved = inner_scope.CloseAndEscape(index1);
     403             :   }  // inner_scope goes out of scope.
     404             : 
     405             :   // The references are only cleared by the mark-compact (scavenger treats weak
     406             :   // references as strong). Thus we need to GC until the array reaches old
     407             :   // space.
     408             : 
     409             :   // TODO(marja): update this when/if we do handle weak references in the new
     410             :   // space.
     411           5 :   CcTest::CollectGarbage(NEW_SPACE);
     412           5 :   HeapObject heap_object;
     413           5 :   CHECK(array->Get(0)->GetHeapObjectIfWeak(&heap_object));
     414           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2016);
     415           5 :   CHECK(array->Get(1)->GetHeapObjectIfWeak(&heap_object));
     416           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017);
     417           5 :   CHECK(array->Get(2)->GetHeapObjectIfStrong(&heap_object));
     418           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2018);
     419           5 :   CHECK(array->Get(3)->GetHeapObjectIfWeak(&heap_object));
     420           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2019);
     421             : 
     422           5 :   CcTest::CollectAllGarbage();
     423           5 :   CHECK(heap->InOldSpace(*array));
     424          10 :   CHECK(array->Get(0)->IsCleared());
     425           5 :   CHECK(array->Get(1)->GetHeapObjectIfWeak(&heap_object));
     426           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017);
     427           5 :   CHECK(array->Get(2)->GetHeapObjectIfStrong(&heap_object));
     428           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2018);
     429          10 :   CHECK(array->Get(3)->IsCleared());
     430           5 : }
     431             : 
     432       28342 : TEST(WeakArrayListBasic) {
     433             :   ManualGCScope manual_gc_scope;
     434           5 :   CcTest::InitializeVM();
     435             :   Isolate* isolate = CcTest::i_isolate();
     436             :   Factory* factory = isolate->factory();
     437          10 :   Heap* heap = isolate->heap();
     438             :   HandleScope outer_scope(isolate);
     439             : 
     440             :   Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(),
     441             :                               isolate);
     442          10 :   CHECK(array->IsWeakArrayList());
     443          10 :   CHECK(!array->IsFixedArray());
     444          10 :   CHECK(!array->IsWeakFixedArray());
     445           5 :   CHECK_EQ(array->length(), 0);
     446             : 
     447           5 :   Handle<FixedArray> index2 = factory->NewFixedArray(1);
     448             :   index2->set(0, Smi::FromInt(2017));
     449             : 
     450             :   Handle<HeapObject> saved;
     451             :   {
     452             :     HandleScope inner_scope(isolate);
     453           5 :     Handle<FixedArray> index0 = factory->NewFixedArray(1);
     454             :     index0->set(0, Smi::FromInt(2016));
     455           5 :     Handle<FixedArray> index4 = factory->NewFixedArray(1);
     456             :     index4->set(0, Smi::FromInt(2018));
     457           5 :     Handle<FixedArray> index6 = factory->NewFixedArray(1);
     458             :     index6->set(0, Smi::FromInt(2019));
     459             : 
     460             :     array = WeakArrayList::AddToEnd(isolate, array,
     461           5 :                                     MaybeObjectHandle::Weak(index0));
     462             :     array = WeakArrayList::AddToEnd(
     463           5 :         isolate, array, MaybeObjectHandle(Smi::FromInt(1), isolate));
     464           5 :     CHECK_EQ(array->length(), 2);
     465             : 
     466             :     array = WeakArrayList::AddToEnd(isolate, array,
     467           5 :                                     MaybeObjectHandle::Weak(index2));
     468             :     array = WeakArrayList::AddToEnd(
     469           5 :         isolate, array, MaybeObjectHandle(Smi::FromInt(3), isolate));
     470           5 :     CHECK_EQ(array->length(), 4);
     471             : 
     472             :     array = WeakArrayList::AddToEnd(isolate, array,
     473           5 :                                     MaybeObjectHandle::Weak(index4));
     474             :     array = WeakArrayList::AddToEnd(
     475           5 :         isolate, array, MaybeObjectHandle(Smi::FromInt(5), isolate));
     476           5 :     CHECK_EQ(array->length(), 6);
     477             : 
     478             :     array = WeakArrayList::AddToEnd(isolate, array,
     479           5 :                                     MaybeObjectHandle::Weak(index6));
     480             :     array = WeakArrayList::AddToEnd(
     481           5 :         isolate, array, MaybeObjectHandle(Smi::FromInt(7), isolate));
     482           5 :     CHECK_EQ(array->length(), 8);
     483             : 
     484           5 :     CHECK(Heap::InNewSpace(*array));
     485             : 
     486          15 :     CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*index0));
     487          10 :     CHECK_EQ(array->Get(1).ToSmi().value(), 1);
     488             : 
     489          15 :     CHECK_EQ(array->Get(2), HeapObjectReference::Weak(*index2));
     490          10 :     CHECK_EQ(array->Get(3).ToSmi().value(), 3);
     491             : 
     492          15 :     CHECK_EQ(array->Get(4), HeapObjectReference::Weak(*index4));
     493          10 :     CHECK_EQ(array->Get(5).ToSmi().value(), 5);
     494             : 
     495          15 :     CHECK_EQ(array->Get(6), HeapObjectReference::Weak(*index6));
     496           5 :     array = inner_scope.CloseAndEscape(array);
     497             :   }  // inner_scope goes out of scope.
     498             : 
     499             :   // The references are only cleared by the mark-compact (scavenger treats weak
     500             :   // references as strong). Thus we need to GC until the array reaches old
     501             :   // space.
     502             : 
     503             :   // TODO(marja): update this when/if we do handle weak references in the new
     504             :   // space.
     505           5 :   CcTest::CollectGarbage(NEW_SPACE);
     506           5 :   HeapObject heap_object;
     507           5 :   CHECK_EQ(array->length(), 8);
     508           5 :   CHECK(array->Get(0)->GetHeapObjectIfWeak(&heap_object));
     509           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2016);
     510          10 :   CHECK_EQ(array->Get(1).ToSmi().value(), 1);
     511             : 
     512           5 :   CHECK(array->Get(2)->GetHeapObjectIfWeak(&heap_object));
     513           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017);
     514          10 :   CHECK_EQ(array->Get(3).ToSmi().value(), 3);
     515             : 
     516           5 :   CHECK(array->Get(4)->GetHeapObjectIfWeak(&heap_object));
     517           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2018);
     518          10 :   CHECK_EQ(array->Get(5).ToSmi().value(), 5);
     519             : 
     520           5 :   CHECK(array->Get(6)->GetHeapObjectIfWeak(&heap_object));
     521           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2019);
     522          10 :   CHECK_EQ(array->Get(7).ToSmi().value(), 7);
     523             : 
     524           5 :   CcTest::CollectAllGarbage();
     525           5 :   CHECK(heap->InOldSpace(*array));
     526           5 :   CHECK_EQ(array->length(), 8);
     527          10 :   CHECK(array->Get(0)->IsCleared());
     528          10 :   CHECK_EQ(array->Get(1).ToSmi().value(), 1);
     529             : 
     530           5 :   CHECK(array->Get(2)->GetHeapObjectIfWeak(&heap_object));
     531           5 :   CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017);
     532          10 :   CHECK_EQ(array->Get(3).ToSmi().value(), 3);
     533             : 
     534          10 :   CHECK(array->Get(4)->IsCleared());
     535          10 :   CHECK_EQ(array->Get(5).ToSmi().value(), 5);
     536             : 
     537          10 :   CHECK(array->Get(6)->IsCleared());
     538          10 :   CHECK_EQ(array->Get(7).ToSmi().value(), 7);
     539           5 : }
     540             : 
     541       28342 : TEST(WeakArrayListRemove) {
     542             :   ManualGCScope manual_gc_scope;
     543           5 :   CcTest::InitializeVM();
     544             :   Isolate* isolate = CcTest::i_isolate();
     545             :   Factory* factory = isolate->factory();
     546           5 :   Heap* heap = isolate->heap();
     547             :   HandleScope outer_scope(isolate);
     548             : 
     549             :   Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(),
     550             :                               isolate);
     551             : 
     552           5 :   Handle<FixedArray> elem0 = factory->NewFixedArray(1);
     553           5 :   Handle<FixedArray> elem1 = factory->NewFixedArray(1);
     554           5 :   Handle<FixedArray> elem2 = factory->NewFixedArray(1);
     555             : 
     556             :   array =
     557           5 :       WeakArrayList::AddToEnd(isolate, array, MaybeObjectHandle::Weak(elem0));
     558             :   array =
     559           5 :       WeakArrayList::AddToEnd(isolate, array, MaybeObjectHandle::Weak(elem1));
     560             :   array =
     561           5 :       WeakArrayList::AddToEnd(isolate, array, MaybeObjectHandle::Weak(elem2));
     562             : 
     563           5 :   CHECK_EQ(array->length(), 3);
     564          15 :   CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*elem0));
     565          15 :   CHECK_EQ(array->Get(1), HeapObjectReference::Weak(*elem1));
     566          15 :   CHECK_EQ(array->Get(2), HeapObjectReference::Weak(*elem2));
     567             : 
     568          10 :   CHECK(array->RemoveOne(MaybeObjectHandle::Weak(elem1)));
     569             : 
     570           5 :   CHECK_EQ(array->length(), 2);
     571          15 :   CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*elem0));
     572          15 :   CHECK_EQ(array->Get(1), HeapObjectReference::Weak(*elem2));
     573             : 
     574          10 :   CHECK(!array->RemoveOne(MaybeObjectHandle::Weak(elem1)));
     575             : 
     576           5 :   CHECK_EQ(array->length(), 2);
     577          15 :   CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*elem0));
     578          15 :   CHECK_EQ(array->Get(1), HeapObjectReference::Weak(*elem2));
     579             : 
     580          10 :   CHECK(array->RemoveOne(MaybeObjectHandle::Weak(elem0)));
     581             : 
     582           5 :   CHECK_EQ(array->length(), 1);
     583          15 :   CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*elem2));
     584             : 
     585          10 :   CHECK(array->RemoveOne(MaybeObjectHandle::Weak(elem2)));
     586             : 
     587           5 :   CHECK_EQ(array->length(), 0);
     588           5 : }
     589             : 
     590       28342 : TEST(Regress7768) {
     591           5 :   i::FLAG_allow_natives_syntax = true;
     592           5 :   i::FLAG_turbo_inlining = false;
     593           5 :   if (!FLAG_incremental_marking) {
     594           0 :     return;
     595             :   }
     596             :   ManualGCScope manual_gc_scope;
     597           5 :   CcTest::InitializeVM();
     598          10 :   LocalContext context;
     599             :   Isolate* isolate = CcTest::i_isolate();
     600           5 :   Heap* heap = isolate->heap();
     601             :   HandleScope outer_scope(isolate);
     602             :   // Create an optimized code which will contain a weak reference to another
     603             :   // function ("f"). The weak reference is the only reference to the function.
     604             :   CompileRun(
     605             :       "function myfunc(f) { f(); } "
     606             :       "(function wrapper() { "
     607             :       "   function f() {}; myfunc(f); myfunc(f); "
     608             :       "   %OptimizeFunctionOnNextCall(myfunc); myfunc(f); "
     609             :       "   %ClearFunctionFeedback(wrapper);"
     610             :       "})(); "
     611             :       "%ClearFunctionFeedback(myfunc);");
     612             : 
     613             :   // Do marking steps; this will store the objects pointed by myfunc for later
     614             :   // processing.
     615           5 :   SimulateIncrementalMarking(heap, true);
     616             : 
     617             :   // Deoptimize the code; now the pointers inside it will be replaced with
     618             :   // undefined, and the weak_objects_in_code is the only place pointing to the
     619             :   // function f.
     620             :   CompileRun("%DeoptimizeFunction(myfunc);");
     621             : 
     622             :   // The object pointed to by the weak reference won't be scavenged.
     623           5 :   CcTest::CollectGarbage(NEW_SPACE);
     624             : 
     625             :   // Make sure the memory where it's stored is invalidated, so that we'll crash
     626             :   // if we try to access it.
     627           5 :   HeapTester::UncommitFromSpace(heap);
     628             : 
     629             :   // This used to crash when processing the dead weak reference.
     630           5 :   CcTest::CollectAllGarbage();
     631             : }
     632             : 
     633       28342 : TEST(PrototypeUsersBasic) {
     634           5 :   CcTest::InitializeVM();
     635           5 :   LocalContext context;
     636             :   Isolate* isolate = CcTest::i_isolate();
     637             :   Factory* factory = isolate->factory();
     638           5 :   Heap* heap = isolate->heap();
     639             :   HandleScope outer_scope(isolate);
     640             : 
     641             :   Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(),
     642             :                               isolate);
     643             : 
     644             :   // Add some objects into the array.
     645           5 :   int index = -1;
     646             :   {
     647           5 :     Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     648           5 :     array = PrototypeUsers::Add(isolate, array, map, &index);
     649          10 :     CHECK_EQ(array->length(), index + 1);
     650             :   }
     651           5 :   CHECK_EQ(index, 1);
     652             : 
     653             :   int empty_index = index;
     654           5 :   PrototypeUsers::MarkSlotEmpty(*array, empty_index);
     655             : 
     656             :   // Even though we have an empty slot, we still add to the end.
     657           5 :   int last_index = index;
     658             :   int old_capacity = array->capacity();
     659          20 :   while (!array->IsFull()) {
     660          10 :     Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     661          10 :     array = PrototypeUsers::Add(isolate, array, map, &index);
     662          10 :     CHECK_EQ(index, last_index + 1);
     663          20 :     CHECK_EQ(array->length(), index + 1);
     664          10 :     last_index = index;
     665             :   }
     666             : 
     667             :   // The next addition will fill the empty slot.
     668             :   {
     669           5 :     Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     670           5 :     array = PrototypeUsers::Add(isolate, array, map, &index);
     671             :   }
     672           5 :   CHECK_EQ(index, empty_index);
     673             : 
     674             :   // The next addition will make the arrow grow again.
     675             :   {
     676           5 :     Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     677           5 :     array = PrototypeUsers::Add(isolate, array, map, &index);
     678          10 :     CHECK_EQ(array->length(), index + 1);
     679           5 :     last_index = index;
     680             :   }
     681           5 :   CHECK_GT(array->capacity(), old_capacity);
     682             : 
     683             :   // Make multiple slots empty.
     684             :   int empty_index1 = 1;
     685             :   int empty_index2 = 2;
     686           5 :   PrototypeUsers::MarkSlotEmpty(*array, empty_index1);
     687           5 :   PrototypeUsers::MarkSlotEmpty(*array, empty_index2);
     688             : 
     689             :   // Fill the array (still adding to the end)
     690             :   old_capacity = array->capacity();
     691          20 :   while (!array->IsFull()) {
     692          10 :     Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     693          10 :     array = PrototypeUsers::Add(isolate, array, map, &index);
     694          10 :     CHECK_EQ(index, last_index + 1);
     695          20 :     CHECK_EQ(array->length(), index + 1);
     696          10 :     last_index = index;
     697             :   }
     698             : 
     699             :   // Make sure we use the empty slots in (reverse) order.
     700             :   {
     701           5 :     Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     702           5 :     array = PrototypeUsers::Add(isolate, array, map, &index);
     703             :   }
     704           5 :   CHECK_EQ(index, empty_index2);
     705             : 
     706             :   {
     707           5 :     Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     708           5 :     array = PrototypeUsers::Add(isolate, array, map, &index);
     709             :   }
     710          10 :   CHECK_EQ(index, empty_index1);
     711           5 : }
     712             : 
     713             : namespace {
     714             : 
     715             : HeapObject saved_heap_object;
     716             : 
     717           5 : static void TestCompactCallback(HeapObject value, int old_index,
     718             :                                 int new_index) {
     719           5 :   saved_heap_object = value;
     720           5 :   CHECK_EQ(old_index, 2);
     721           5 :   CHECK_EQ(new_index, 1);
     722           5 : }
     723             : 
     724             : }  // namespace
     725             : 
     726       28342 : TEST(PrototypeUsersCompacted) {
     727             :   ManualGCScope manual_gc_scope;
     728           5 :   CcTest::InitializeVM();
     729          10 :   LocalContext context;
     730             :   Isolate* isolate = CcTest::i_isolate();
     731             :   Factory* factory = isolate->factory();
     732           5 :   Heap* heap = isolate->heap();
     733             :   HandleScope outer_scope(isolate);
     734             : 
     735             :   Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(),
     736             :                               isolate);
     737             : 
     738             :   // Add some objects into the array.
     739           5 :   int index = -1;
     740             :   Handle<Map> map_cleared_by_user =
     741           5 :       factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     742           5 :   array = PrototypeUsers::Add(isolate, array, map_cleared_by_user, &index);
     743           5 :   CHECK_EQ(index, 1);
     744           5 :   Handle<Map> live_map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     745           5 :   array = PrototypeUsers::Add(isolate, array, live_map, &index);
     746           5 :   CHECK_EQ(index, 2);
     747             :   {
     748             :     HandleScope inner_scope(isolate);
     749             :     Handle<Map> soon_dead_map =
     750           5 :         factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     751           5 :     array = PrototypeUsers::Add(isolate, array, soon_dead_map, &index);
     752           5 :     CHECK_EQ(index, 3);
     753             : 
     754           5 :     array = inner_scope.CloseAndEscape(array);
     755             :   }
     756             : 
     757           5 :   PrototypeUsers::MarkSlotEmpty(*array, 1);
     758           5 :   CcTest::CollectAllGarbage();
     759          10 :   CHECK(array->Get(3)->IsCleared());
     760             : 
     761           5 :   CHECK_EQ(array->length(), 3 + PrototypeUsers::kFirstIndex);
     762             :   WeakArrayList new_array =
     763           5 :       PrototypeUsers::Compact(array, heap, TestCompactCallback);
     764           5 :   CHECK_EQ(new_array->length(), 1 + PrototypeUsers::kFirstIndex);
     765          10 :   CHECK_EQ(saved_heap_object, *live_map);
     766           5 : }
     767             : 
     768             : }  // namespace heap
     769             : }  // namespace internal
     770       85011 : }  // namespace v8

Generated by: LCOV version 1.10