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

Generated by: LCOV version 1.10