LCOV - code coverage report
Current view: top level - test/cctest - test-js-weak-refs.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 364 366 99.5 %
Date: 2019-04-17 Functions: 25 25 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/handles-inl.h"
       6             : #include "src/heap/factory-inl.h"
       7             : #include "src/isolate.h"
       8             : #include "src/microtask-queue.h"
       9             : #include "src/objects/js-objects.h"
      10             : #include "src/objects/js-weak-refs-inl.h"
      11             : #include "test/cctest/cctest.h"
      12             : #include "test/cctest/heap/heap-utils.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : namespace {
      18             : 
      19          55 : Handle<JSFinalizationGroup> ConstructJSFinalizationGroup(Isolate* isolate) {
      20             :   Factory* factory = isolate->factory();
      21             :   Handle<String> finalization_group_name =
      22          55 :       factory->NewStringFromStaticChars("FinalizationGroup");
      23             :   Handle<Object> global =
      24         165 :       handle(isolate->native_context()->global_object(), isolate);
      25             :   Handle<JSFunction> finalization_group_fun = Handle<JSFunction>::cast(
      26         110 :       Object::GetProperty(isolate, global, finalization_group_name)
      27             :           .ToHandleChecked());
      28             :   auto finalization_group = Handle<JSFinalizationGroup>::cast(
      29         110 :       JSObject::New(finalization_group_fun, finalization_group_fun,
      30          55 :                     Handle<AllocationSite>::null())
      31             :           .ToHandleChecked());
      32             : #ifdef VERIFY_HEAP
      33             :   finalization_group->JSFinalizationGroupVerify(isolate);
      34             : #endif  // VERIFY_HEAP
      35          55 :   return finalization_group;
      36             : }
      37             : 
      38          20 : Handle<JSWeakRef> ConstructJSWeakRef(Handle<JSReceiver> target,
      39             :                                      Isolate* isolate) {
      40             :   Factory* factory = isolate->factory();
      41             :   Handle<String> weak_ref_name = factory->WeakRef_string();
      42             :   Handle<Object> global =
      43          60 :       handle(isolate->native_context()->global_object(), isolate);
      44             :   Handle<JSFunction> weak_ref_fun = Handle<JSFunction>::cast(
      45          40 :       Object::GetProperty(isolate, global, weak_ref_name).ToHandleChecked());
      46             :   auto weak_ref = Handle<JSWeakRef>::cast(
      47          40 :       JSObject::New(weak_ref_fun, weak_ref_fun, Handle<AllocationSite>::null())
      48             :           .ToHandleChecked());
      49          40 :   weak_ref->set_target(*target);
      50             : #ifdef VERIFY_HEAP
      51             :   weak_ref->JSWeakRefVerify(isolate);
      52             : #endif  // VERIFY_HEAP
      53          20 :   return weak_ref;
      54             : }
      55             : 
      56          50 : Handle<JSObject> CreateKey(const char* key_prop_value, Isolate* isolate) {
      57             :   Factory* factory = isolate->factory();
      58          50 :   Handle<String> key_string = factory->NewStringFromStaticChars("key_string");
      59             :   Handle<JSObject> key =
      60          50 :       isolate->factory()->NewJSObject(isolate->object_function());
      61         100 :   JSObject::AddProperty(isolate, key, key_string,
      62             :                         factory->NewStringFromAsciiChecked(key_prop_value),
      63          50 :                         NONE);
      64          50 :   return key;
      65             : }
      66             : 
      67         120 : Handle<WeakCell> FinalizationGroupRegister(
      68             :     Handle<JSFinalizationGroup> finalization_group, Handle<JSObject> target,
      69             :     Handle<Object> holdings, Handle<Object> key, Isolate* isolate) {
      70         120 :   JSFinalizationGroup::Register(finalization_group, target, holdings, key,
      71         120 :                                 isolate);
      72         120 :   CHECK(finalization_group->active_cells()->IsWeakCell());
      73             :   Handle<WeakCell> weak_cell =
      74             :       handle(WeakCell::cast(finalization_group->active_cells()), isolate);
      75             : #ifdef VERIFY_HEAP
      76             :   weak_cell->WeakCellVerify(isolate);
      77             : #endif  // VERIFY_HEAP
      78         120 :   return weak_cell;
      79             : }
      80             : 
      81          30 : Handle<WeakCell> FinalizationGroupRegister(
      82             :     Handle<JSFinalizationGroup> finalization_group, Handle<JSObject> target,
      83             :     Isolate* isolate) {
      84             :   Handle<Object> undefined =
      85             :       handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
      86             :   return FinalizationGroupRegister(finalization_group, target, undefined,
      87          30 :                                    undefined, isolate);
      88             : }
      89             : 
      90          55 : void NullifyWeakCell(Handle<WeakCell> weak_cell, Isolate* isolate) {
      91             :   auto empty_func = [](HeapObject object, ObjectSlot slot, Object target) {};
      92         110 :   weak_cell->Nullify(isolate, empty_func);
      93             : #ifdef VERIFY_HEAP
      94             :   weak_cell->WeakCellVerify(isolate);
      95             : #endif  // VERIFY_HEAP
      96          55 : }
      97             : 
      98             : // Usage: VerifyWeakCellChain(isolate, list_head, n, cell1, cell2, ..., celln);
      99             : // verifies that list_head == cell1 and cell1, cell2, ..., celln. form a list.
     100         100 : void VerifyWeakCellChain(Isolate* isolate, Object list_head, int n_args, ...) {
     101         100 :   CHECK_GE(n_args, 0);
     102             : 
     103             :   va_list args;
     104         100 :   va_start(args, n_args);
     105             : 
     106         100 :   if (n_args == 0) {
     107             :     // Verify empty list
     108          60 :     CHECK(list_head->IsUndefined(isolate));
     109             :   } else {
     110          40 :     WeakCell current = WeakCell::cast(Object(va_arg(args, Address)));
     111          40 :     CHECK_EQ(current, list_head);
     112          40 :     CHECK(current->prev()->IsUndefined(isolate));
     113             : 
     114         120 :     for (int i = 1; i < n_args; i++) {
     115          40 :       WeakCell next = WeakCell::cast(Object(va_arg(args, Address)));
     116          40 :       CHECK_EQ(current->next(), next);
     117          40 :       CHECK_EQ(next->prev(), current);
     118             :       current = next;
     119             :     }
     120          40 :     CHECK(current->next()->IsUndefined(isolate));
     121             :   }
     122         100 :   va_end(args);
     123         100 : }
     124             : 
     125             : // Like VerifyWeakCellChain but verifies the chain created with key_list_prev
     126             : // and key_list_next instead of prev and next.
     127         110 : void VerifyWeakCellKeyChain(Isolate* isolate, Object list_head, int n_args,
     128             :                             ...) {
     129         110 :   CHECK_GE(n_args, 0);
     130             : 
     131             :   va_list args;
     132         110 :   va_start(args, n_args);
     133             : 
     134         110 :   if (n_args == 0) {
     135             :     // Verify empty list
     136          40 :     CHECK(list_head->IsTheHole(isolate));
     137             :   } else {
     138          70 :     WeakCell current = WeakCell::cast(Object(va_arg(args, Address)));
     139          70 :     CHECK_EQ(current, list_head);
     140          70 :     CHECK(current->key_list_prev()->IsUndefined(isolate));
     141             : 
     142         150 :     for (int i = 1; i < n_args; i++) {
     143          40 :       WeakCell next = WeakCell::cast(Object(va_arg(args, Address)));
     144          40 :       CHECK_EQ(current->key_list_next(), next);
     145          40 :       CHECK_EQ(next->key_list_prev(), current);
     146             :       current = next;
     147             :     }
     148          70 :     CHECK(current->key_list_next()->IsUndefined(isolate));
     149             :   }
     150         110 :   va_end(args);
     151         110 : }
     152             : 
     153             : }  // namespace
     154             : 
     155       26644 : TEST(TestRegister) {
     156           5 :   FLAG_harmony_weak_refs = true;
     157           5 :   CcTest::InitializeVM();
     158           5 :   LocalContext context;
     159             :   Isolate* isolate = CcTest::i_isolate();
     160             :   HandleScope outer_scope(isolate);
     161             :   Handle<JSFinalizationGroup> finalization_group =
     162           5 :       ConstructJSFinalizationGroup(isolate);
     163             :   Handle<JSObject> js_object =
     164           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     165             : 
     166             :   // Register a weak reference and verify internal data structures.
     167             :   Handle<WeakCell> weak_cell1 =
     168           5 :       FinalizationGroupRegister(finalization_group, js_object, isolate);
     169             : 
     170             :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 1,
     171           5 :                       *weak_cell1);
     172           5 :   CHECK(weak_cell1->key_list_prev()->IsUndefined(isolate));
     173           5 :   CHECK(weak_cell1->key_list_next()->IsUndefined(isolate));
     174             : 
     175           5 :   CHECK(finalization_group->cleared_cells()->IsUndefined(isolate));
     176             : 
     177             :   // No key was used during registration, key-based map stays uninitialized.
     178           5 :   CHECK(finalization_group->key_map()->IsUndefined(isolate));
     179             : 
     180             :   // Register another weak reference and verify internal data structures.
     181             :   Handle<WeakCell> weak_cell2 =
     182           5 :       FinalizationGroupRegister(finalization_group, js_object, isolate);
     183             : 
     184             :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 2,
     185           5 :                       *weak_cell2, *weak_cell1);
     186           5 :   CHECK(weak_cell2->key_list_prev()->IsUndefined(isolate));
     187           5 :   CHECK(weak_cell2->key_list_next()->IsUndefined(isolate));
     188             : 
     189           5 :   CHECK(finalization_group->cleared_cells()->IsUndefined(isolate));
     190           5 :   CHECK(finalization_group->key_map()->IsUndefined(isolate));
     191           5 : }
     192             : 
     193       26644 : TEST(TestRegisterWithKey) {
     194           5 :   FLAG_harmony_weak_refs = true;
     195           5 :   CcTest::InitializeVM();
     196           5 :   LocalContext context;
     197             :   Isolate* isolate = CcTest::i_isolate();
     198             :   HandleScope outer_scope(isolate);
     199             :   Handle<JSFinalizationGroup> finalization_group =
     200           5 :       ConstructJSFinalizationGroup(isolate);
     201             :   Handle<JSObject> js_object =
     202           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     203             : 
     204           5 :   Handle<JSObject> key1 = CreateKey("key1", isolate);
     205           5 :   Handle<JSObject> key2 = CreateKey("key2", isolate);
     206             :   Handle<Object> undefined =
     207             :       handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
     208             : 
     209             :   // Register a weak reference with a key and verify internal data structures.
     210             :   Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
     211           5 :       finalization_group, js_object, undefined, key1, isolate);
     212             : 
     213             :   {
     214           5 :     CHECK(finalization_group->key_map()->IsObjectHashTable());
     215             :     Handle<ObjectHashTable> key_map =
     216             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     217           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 1, *weak_cell1);
     218           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key2), 0);
     219             :   }
     220             : 
     221             :   // Register another weak reference with a different key and verify internal
     222             :   // data structures.
     223             :   Handle<WeakCell> weak_cell2 = FinalizationGroupRegister(
     224           5 :       finalization_group, js_object, undefined, key2, isolate);
     225             : 
     226             :   {
     227           5 :     CHECK(finalization_group->key_map()->IsObjectHashTable());
     228             :     Handle<ObjectHashTable> key_map =
     229             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     230           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 1, *weak_cell1);
     231           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key2), 1, *weak_cell2);
     232             :   }
     233             : 
     234             :   // Register another weak reference with key1 and verify internal data
     235             :   // structures.
     236             :   Handle<WeakCell> weak_cell3 = FinalizationGroupRegister(
     237           5 :       finalization_group, js_object, undefined, key1, isolate);
     238             : 
     239             :   {
     240           5 :     CHECK(finalization_group->key_map()->IsObjectHashTable());
     241             :     Handle<ObjectHashTable> key_map =
     242             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     243          10 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 2, *weak_cell3,
     244           5 :                            *weak_cell1);
     245           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key2), 1, *weak_cell2);
     246             :   }
     247           5 : }
     248             : 
     249       26644 : TEST(TestWeakCellNullify1) {
     250           5 :   FLAG_harmony_weak_refs = true;
     251           5 :   CcTest::InitializeVM();
     252           5 :   LocalContext context;
     253             :   Isolate* isolate = CcTest::i_isolate();
     254             :   HandleScope outer_scope(isolate);
     255             :   Handle<JSFinalizationGroup> finalization_group =
     256           5 :       ConstructJSFinalizationGroup(isolate);
     257             :   Handle<JSObject> js_object =
     258           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     259             : 
     260             :   Handle<WeakCell> weak_cell1 =
     261           5 :       FinalizationGroupRegister(finalization_group, js_object, isolate);
     262             :   Handle<WeakCell> weak_cell2 =
     263           5 :       FinalizationGroupRegister(finalization_group, js_object, isolate);
     264             : 
     265             :   // Nullify the first WeakCell and verify internal data structures.
     266           5 :   NullifyWeakCell(weak_cell1, isolate);
     267           5 :   CHECK_EQ(finalization_group->active_cells(), *weak_cell2);
     268           5 :   CHECK(weak_cell2->prev()->IsUndefined(isolate));
     269           5 :   CHECK(weak_cell2->next()->IsUndefined(isolate));
     270           5 :   CHECK_EQ(finalization_group->cleared_cells(), *weak_cell1);
     271           5 :   CHECK(weak_cell1->prev()->IsUndefined(isolate));
     272           5 :   CHECK(weak_cell1->next()->IsUndefined(isolate));
     273             : 
     274             :   // Nullify the second WeakCell and verify internal data structures.
     275           5 :   NullifyWeakCell(weak_cell2, isolate);
     276           5 :   CHECK(finalization_group->active_cells()->IsUndefined(isolate));
     277           5 :   CHECK_EQ(finalization_group->cleared_cells(), *weak_cell2);
     278           5 :   CHECK_EQ(weak_cell2->next(), *weak_cell1);
     279           5 :   CHECK(weak_cell2->prev()->IsUndefined(isolate));
     280           5 :   CHECK_EQ(weak_cell1->prev(), *weak_cell2);
     281           5 :   CHECK(weak_cell1->next()->IsUndefined(isolate));
     282           5 : }
     283             : 
     284       26644 : TEST(TestWeakCellNullify2) {
     285           5 :   FLAG_harmony_weak_refs = true;
     286           5 :   CcTest::InitializeVM();
     287           5 :   LocalContext context;
     288             :   Isolate* isolate = CcTest::i_isolate();
     289             :   HandleScope outer_scope(isolate);
     290             :   Handle<JSFinalizationGroup> finalization_group =
     291           5 :       ConstructJSFinalizationGroup(isolate);
     292             :   Handle<JSObject> js_object =
     293           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     294             : 
     295             :   Handle<WeakCell> weak_cell1 =
     296           5 :       FinalizationGroupRegister(finalization_group, js_object, isolate);
     297             :   Handle<WeakCell> weak_cell2 =
     298           5 :       FinalizationGroupRegister(finalization_group, js_object, isolate);
     299             : 
     300             :   // Like TestWeakCellNullify1 but nullify the WeakCells in opposite order.
     301           5 :   NullifyWeakCell(weak_cell2, isolate);
     302           5 :   CHECK_EQ(finalization_group->active_cells(), *weak_cell1);
     303           5 :   CHECK(weak_cell1->prev()->IsUndefined(isolate));
     304           5 :   CHECK(weak_cell1->next()->IsUndefined(isolate));
     305           5 :   CHECK_EQ(finalization_group->cleared_cells(), *weak_cell2);
     306           5 :   CHECK(weak_cell2->prev()->IsUndefined(isolate));
     307           5 :   CHECK(weak_cell2->next()->IsUndefined(isolate));
     308             : 
     309           5 :   NullifyWeakCell(weak_cell1, isolate);
     310           5 :   CHECK(finalization_group->active_cells()->IsUndefined(isolate));
     311           5 :   CHECK_EQ(finalization_group->cleared_cells(), *weak_cell1);
     312           5 :   CHECK_EQ(weak_cell1->next(), *weak_cell2);
     313           5 :   CHECK(weak_cell1->prev()->IsUndefined(isolate));
     314           5 :   CHECK_EQ(weak_cell2->prev(), *weak_cell1);
     315           5 :   CHECK(weak_cell2->next()->IsUndefined(isolate));
     316           5 : }
     317             : 
     318       26644 : TEST(TestJSFinalizationGroupPopClearedCellHoldings1) {
     319           5 :   FLAG_harmony_weak_refs = true;
     320           5 :   CcTest::InitializeVM();
     321           5 :   LocalContext context;
     322             :   Isolate* isolate = CcTest::i_isolate();
     323             :   Factory* factory = isolate->factory();
     324             :   HandleScope outer_scope(isolate);
     325             :   Handle<JSFinalizationGroup> finalization_group =
     326           5 :       ConstructJSFinalizationGroup(isolate);
     327             :   Handle<JSObject> js_object =
     328           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     329             :   Handle<Object> undefined =
     330             :       handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
     331             : 
     332           5 :   Handle<Object> holdings1 = factory->NewStringFromAsciiChecked("holdings1");
     333             :   Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
     334           5 :       finalization_group, js_object, holdings1, undefined, isolate);
     335           5 :   Handle<Object> holdings2 = factory->NewStringFromAsciiChecked("holdings2");
     336             :   Handle<WeakCell> weak_cell2 = FinalizationGroupRegister(
     337           5 :       finalization_group, js_object, holdings2, undefined, isolate);
     338           5 :   Handle<Object> holdings3 = factory->NewStringFromAsciiChecked("holdings3");
     339             :   Handle<WeakCell> weak_cell3 = FinalizationGroupRegister(
     340           5 :       finalization_group, js_object, holdings3, undefined, isolate);
     341             : 
     342           5 :   NullifyWeakCell(weak_cell2, isolate);
     343           5 :   NullifyWeakCell(weak_cell3, isolate);
     344             : 
     345           5 :   CHECK(finalization_group->NeedsCleanup());
     346             :   Object cleared1 =
     347           5 :       JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
     348           5 :   CHECK_EQ(cleared1, *holdings3);
     349           5 :   CHECK(weak_cell3->prev()->IsUndefined(isolate));
     350           5 :   CHECK(weak_cell3->next()->IsUndefined(isolate));
     351             : 
     352           5 :   CHECK(finalization_group->NeedsCleanup());
     353             :   Object cleared2 =
     354           5 :       JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
     355           5 :   CHECK_EQ(cleared2, *holdings2);
     356           5 :   CHECK(weak_cell2->prev()->IsUndefined(isolate));
     357           5 :   CHECK(weak_cell2->next()->IsUndefined(isolate));
     358             : 
     359           5 :   CHECK(!finalization_group->NeedsCleanup());
     360             : 
     361           5 :   NullifyWeakCell(weak_cell1, isolate);
     362             : 
     363           5 :   CHECK(finalization_group->NeedsCleanup());
     364             :   Object cleared3 =
     365           5 :       JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
     366           5 :   CHECK_EQ(cleared3, *holdings1);
     367           5 :   CHECK(weak_cell1->prev()->IsUndefined(isolate));
     368           5 :   CHECK(weak_cell1->next()->IsUndefined(isolate));
     369             : 
     370           5 :   CHECK(!finalization_group->NeedsCleanup());
     371           5 :   CHECK(finalization_group->active_cells()->IsUndefined(isolate));
     372           5 :   CHECK(finalization_group->cleared_cells()->IsUndefined(isolate));
     373           5 : }
     374             : 
     375       26644 : TEST(TestJSFinalizationGroupPopClearedCellHoldings2) {
     376             :   // Test that when all WeakCells for a key are popped, the key is removed from
     377             :   // the key map.
     378           5 :   FLAG_harmony_weak_refs = true;
     379           5 :   CcTest::InitializeVM();
     380           5 :   LocalContext context;
     381             :   Isolate* isolate = CcTest::i_isolate();
     382             :   Factory* factory = isolate->factory();
     383             :   HandleScope outer_scope(isolate);
     384             :   Handle<JSFinalizationGroup> finalization_group =
     385           5 :       ConstructJSFinalizationGroup(isolate);
     386             :   Handle<JSObject> js_object =
     387           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     388           5 :   Handle<JSObject> key1 = CreateKey("key1", isolate);
     389             : 
     390           5 :   Handle<Object> holdings1 = factory->NewStringFromAsciiChecked("holdings1");
     391             :   Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
     392           5 :       finalization_group, js_object, holdings1, key1, isolate);
     393           5 :   Handle<Object> holdings2 = factory->NewStringFromAsciiChecked("holdings2");
     394             :   Handle<WeakCell> weak_cell2 = FinalizationGroupRegister(
     395           5 :       finalization_group, js_object, holdings2, key1, isolate);
     396             : 
     397           5 :   NullifyWeakCell(weak_cell1, isolate);
     398           5 :   NullifyWeakCell(weak_cell2, isolate);
     399             : 
     400             :   // Nullifying doesn't affect the key chains (just moves WeakCells from
     401             :   // active_cells to cleared_cells).
     402             :   {
     403             :     Handle<ObjectHashTable> key_map =
     404             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     405          10 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 2, *weak_cell2,
     406           5 :                            *weak_cell1);
     407             :   }
     408             : 
     409             :   Object cleared1 =
     410           5 :       JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
     411           5 :   CHECK_EQ(cleared1, *holdings2);
     412             : 
     413             :   {
     414             :     Handle<ObjectHashTable> key_map =
     415             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     416           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 1, *weak_cell1);
     417             :   }
     418             : 
     419             :   Object cleared2 =
     420           5 :       JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
     421           5 :   CHECK_EQ(cleared2, *holdings1);
     422             : 
     423             :   {
     424             :     Handle<ObjectHashTable> key_map =
     425             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     426           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 0);
     427             :   }
     428           5 : }
     429             : 
     430       26644 : TEST(TestUnregisterActiveCells) {
     431           5 :   FLAG_harmony_weak_refs = true;
     432           5 :   CcTest::InitializeVM();
     433           5 :   LocalContext context;
     434             :   Isolate* isolate = CcTest::i_isolate();
     435             :   HandleScope outer_scope(isolate);
     436             :   Handle<JSFinalizationGroup> finalization_group =
     437           5 :       ConstructJSFinalizationGroup(isolate);
     438             :   Handle<JSObject> js_object =
     439           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     440             : 
     441           5 :   Handle<JSObject> key1 = CreateKey("key1", isolate);
     442           5 :   Handle<JSObject> key2 = CreateKey("key2", isolate);
     443             :   Handle<Object> undefined =
     444             :       handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
     445             : 
     446             :   Handle<WeakCell> weak_cell1a = FinalizationGroupRegister(
     447           5 :       finalization_group, js_object, undefined, key1, isolate);
     448             :   Handle<WeakCell> weak_cell1b = FinalizationGroupRegister(
     449           5 :       finalization_group, js_object, undefined, key1, isolate);
     450             : 
     451             :   Handle<WeakCell> weak_cell2a = FinalizationGroupRegister(
     452           5 :       finalization_group, js_object, undefined, key2, isolate);
     453             :   Handle<WeakCell> weak_cell2b = FinalizationGroupRegister(
     454           5 :       finalization_group, js_object, undefined, key2, isolate);
     455             : 
     456             :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 4,
     457           5 :                       *weak_cell2b, *weak_cell2a, *weak_cell1b, *weak_cell1a);
     458           5 :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
     459             :   {
     460             :     Handle<ObjectHashTable> key_map =
     461             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     462          10 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 2, *weak_cell1b,
     463           5 :                            *weak_cell1a);
     464          10 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key2), 2, *weak_cell2b,
     465           5 :                            *weak_cell2a);
     466             :   }
     467             : 
     468           5 :   JSFinalizationGroup::Unregister(finalization_group, key1, isolate);
     469             :   {
     470             :     Handle<ObjectHashTable> key_map =
     471             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     472           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 0);
     473          10 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key2), 2, *weak_cell2b,
     474           5 :                            *weak_cell2a);
     475             :   }
     476             : 
     477             :   // Both weak_cell1a and weak_cell1b removed from active_cells.
     478             :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 2,
     479           5 :                       *weak_cell2b, *weak_cell2a);
     480           5 :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
     481           5 : }
     482             : 
     483       26644 : TEST(TestUnregisterActiveAndClearedCells) {
     484           5 :   FLAG_harmony_weak_refs = true;
     485           5 :   CcTest::InitializeVM();
     486           5 :   LocalContext context;
     487             :   Isolate* isolate = CcTest::i_isolate();
     488             :   HandleScope outer_scope(isolate);
     489             :   Handle<JSFinalizationGroup> finalization_group =
     490           5 :       ConstructJSFinalizationGroup(isolate);
     491             :   Handle<JSObject> js_object =
     492           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     493             : 
     494           5 :   Handle<JSObject> key1 = CreateKey("key1", isolate);
     495           5 :   Handle<JSObject> key2 = CreateKey("key2", isolate);
     496             :   Handle<Object> undefined =
     497             :       handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
     498             : 
     499             :   Handle<WeakCell> weak_cell1a = FinalizationGroupRegister(
     500           5 :       finalization_group, js_object, undefined, key1, isolate);
     501             :   Handle<WeakCell> weak_cell1b = FinalizationGroupRegister(
     502           5 :       finalization_group, js_object, undefined, key1, isolate);
     503             : 
     504             :   Handle<WeakCell> weak_cell2a = FinalizationGroupRegister(
     505           5 :       finalization_group, js_object, undefined, key2, isolate);
     506             :   Handle<WeakCell> weak_cell2b = FinalizationGroupRegister(
     507           5 :       finalization_group, js_object, undefined, key2, isolate);
     508             : 
     509           5 :   NullifyWeakCell(weak_cell2a, isolate);
     510             : 
     511             :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 3,
     512           5 :                       *weak_cell2b, *weak_cell1b, *weak_cell1a);
     513             :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 1,
     514           5 :                       *weak_cell2a);
     515             :   {
     516             :     Handle<ObjectHashTable> key_map =
     517             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     518          10 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 2, *weak_cell1b,
     519           5 :                            *weak_cell1a);
     520          10 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key2), 2, *weak_cell2b,
     521           5 :                            *weak_cell2a);
     522             :   }
     523             : 
     524           5 :   JSFinalizationGroup::Unregister(finalization_group, key2, isolate);
     525             : 
     526             :   // Both weak_cell2a and weak_cell2b removed.
     527             :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 2,
     528           5 :                       *weak_cell1b, *weak_cell1a);
     529           5 :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
     530             :   {
     531             :     Handle<ObjectHashTable> key_map =
     532             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     533          10 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 2, *weak_cell1b,
     534           5 :                            *weak_cell1a);
     535           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key2), 0);
     536             :   }
     537           5 : }
     538             : 
     539       26644 : TEST(TestWeakCellUnregisterTwice) {
     540           5 :   FLAG_harmony_weak_refs = true;
     541           5 :   CcTest::InitializeVM();
     542           5 :   LocalContext context;
     543             :   Isolate* isolate = CcTest::i_isolate();
     544             :   HandleScope outer_scope(isolate);
     545             :   Handle<JSFinalizationGroup> finalization_group =
     546           5 :       ConstructJSFinalizationGroup(isolate);
     547             :   Handle<JSObject> js_object =
     548           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     549             : 
     550           5 :   Handle<JSObject> key1 = CreateKey("key1", isolate);
     551             :   Handle<Object> undefined =
     552             :       handle(ReadOnlyRoots(isolate).undefined_value(), isolate);
     553             : 
     554             :   Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
     555           5 :       finalization_group, js_object, undefined, key1, isolate);
     556             : 
     557             :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 1,
     558           5 :                       *weak_cell1);
     559           5 :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
     560             :   {
     561             :     Handle<ObjectHashTable> key_map =
     562             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     563           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 1, *weak_cell1);
     564             :   }
     565             : 
     566           5 :   JSFinalizationGroup::Unregister(finalization_group, key1, isolate);
     567             : 
     568           5 :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 0);
     569           5 :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
     570             :   {
     571             :     Handle<ObjectHashTable> key_map =
     572             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     573           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 0);
     574             :   }
     575             : 
     576           5 :   JSFinalizationGroup::Unregister(finalization_group, key1, isolate);
     577             : 
     578           5 :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 0);
     579           5 :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
     580             :   {
     581             :     Handle<ObjectHashTable> key_map =
     582             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     583           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 0);
     584             :   }
     585           5 : }
     586             : 
     587       26644 : TEST(TestWeakCellUnregisterPopped) {
     588           5 :   FLAG_harmony_weak_refs = true;
     589           5 :   CcTest::InitializeVM();
     590           5 :   LocalContext context;
     591             :   Isolate* isolate = CcTest::i_isolate();
     592             :   Factory* factory = isolate->factory();
     593             :   HandleScope outer_scope(isolate);
     594             :   Handle<JSFinalizationGroup> finalization_group =
     595           5 :       ConstructJSFinalizationGroup(isolate);
     596             :   Handle<JSObject> js_object =
     597           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     598           5 :   Handle<JSObject> key1 = CreateKey("key1", isolate);
     599           5 :   Handle<Object> holdings1 = factory->NewStringFromAsciiChecked("holdings1");
     600             :   Handle<WeakCell> weak_cell1 = FinalizationGroupRegister(
     601           5 :       finalization_group, js_object, holdings1, key1, isolate);
     602             : 
     603           5 :   NullifyWeakCell(weak_cell1, isolate);
     604             : 
     605           5 :   CHECK(finalization_group->NeedsCleanup());
     606             :   Object cleared1 =
     607           5 :       JSFinalizationGroup::PopClearedCellHoldings(finalization_group, isolate);
     608           5 :   CHECK_EQ(cleared1, *holdings1);
     609             : 
     610           5 :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 0);
     611           5 :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
     612             :   {
     613             :     Handle<ObjectHashTable> key_map =
     614             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     615           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 0);
     616             :   }
     617             : 
     618           5 :   JSFinalizationGroup::Unregister(finalization_group, key1, isolate);
     619             : 
     620           5 :   VerifyWeakCellChain(isolate, finalization_group->active_cells(), 0);
     621           5 :   VerifyWeakCellChain(isolate, finalization_group->cleared_cells(), 0);
     622             :   {
     623             :     Handle<ObjectHashTable> key_map =
     624             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     625           5 :     VerifyWeakCellKeyChain(isolate, key_map->Lookup(key1), 0);
     626             :   }
     627           5 : }
     628             : 
     629       26644 : TEST(TestWeakCellUnregisterNonexistentKey) {
     630           5 :   FLAG_harmony_weak_refs = true;
     631           5 :   CcTest::InitializeVM();
     632           5 :   LocalContext context;
     633             :   Isolate* isolate = CcTest::i_isolate();
     634             :   HandleScope outer_scope(isolate);
     635             :   Handle<JSFinalizationGroup> finalization_group =
     636           5 :       ConstructJSFinalizationGroup(isolate);
     637           5 :   Handle<JSObject> key1 = CreateKey("key1", isolate);
     638             : 
     639           5 :   JSFinalizationGroup::Unregister(finalization_group, key1, isolate);
     640           5 : }
     641             : 
     642       26644 : TEST(TestJSWeakRef) {
     643           5 :   FLAG_harmony_weak_refs = true;
     644           5 :   CcTest::InitializeVM();
     645           5 :   LocalContext context;
     646             : 
     647             :   Isolate* isolate = CcTest::i_isolate();
     648             :   HandleScope outer_scope(isolate);
     649             :   Handle<JSWeakRef> weak_ref;
     650             :   {
     651             :     HandleScope inner_scope(isolate);
     652             : 
     653             :     Handle<JSObject> js_object =
     654           5 :         isolate->factory()->NewJSObject(isolate->object_function());
     655             :     // This doesn't add the target into the KeepDuringJob set.
     656           5 :     Handle<JSWeakRef> inner_weak_ref = ConstructJSWeakRef(js_object, isolate);
     657             : 
     658           5 :     CcTest::CollectAllGarbage();
     659           5 :     CHECK(!inner_weak_ref->target()->IsUndefined(isolate));
     660             : 
     661           5 :     weak_ref = inner_scope.CloseAndEscape(inner_weak_ref);
     662             :   }
     663             : 
     664           5 :   CHECK(!weak_ref->target()->IsUndefined(isolate));
     665             : 
     666           5 :   CcTest::CollectAllGarbage();
     667             : 
     668           5 :   CHECK(weak_ref->target()->IsUndefined(isolate));
     669           5 : }
     670             : 
     671       26644 : TEST(TestJSWeakRefIncrementalMarking) {
     672           5 :   FLAG_harmony_weak_refs = true;
     673           5 :   if (!FLAG_incremental_marking) {
     674           0 :     return;
     675             :   }
     676             :   ManualGCScope manual_gc_scope;
     677           5 :   CcTest::InitializeVM();
     678           5 :   LocalContext context;
     679             : 
     680             :   Isolate* isolate = CcTest::i_isolate();
     681             :   Heap* heap = isolate->heap();
     682             :   HandleScope outer_scope(isolate);
     683             :   Handle<JSWeakRef> weak_ref;
     684             :   {
     685             :     HandleScope inner_scope(isolate);
     686             : 
     687             :     Handle<JSObject> js_object =
     688           5 :         isolate->factory()->NewJSObject(isolate->object_function());
     689             :     // This doesn't add the target into the KeepDuringJob set.
     690           5 :     Handle<JSWeakRef> inner_weak_ref = ConstructJSWeakRef(js_object, isolate);
     691             : 
     692           5 :     heap::SimulateIncrementalMarking(heap, true);
     693           5 :     CcTest::CollectAllGarbage();
     694           5 :     CHECK(!inner_weak_ref->target()->IsUndefined(isolate));
     695             : 
     696           5 :     weak_ref = inner_scope.CloseAndEscape(inner_weak_ref);
     697             :   }
     698             : 
     699           5 :   CHECK(!weak_ref->target()->IsUndefined(isolate));
     700             : 
     701           5 :   heap::SimulateIncrementalMarking(heap, true);
     702           5 :   CcTest::CollectAllGarbage();
     703             : 
     704           5 :   CHECK(weak_ref->target()->IsUndefined(isolate));
     705             : }
     706             : 
     707       26644 : TEST(TestJSWeakRefKeepDuringJob) {
     708           5 :   FLAG_harmony_weak_refs = true;
     709           5 :   CcTest::InitializeVM();
     710           5 :   LocalContext context;
     711             : 
     712             :   Isolate* isolate = CcTest::i_isolate();
     713             :   Heap* heap = isolate->heap();
     714             :   HandleScope outer_scope(isolate);
     715             :   Handle<JSWeakRef> weak_ref;
     716             :   {
     717             :     HandleScope inner_scope(isolate);
     718             : 
     719             :     Handle<JSObject> js_object =
     720           5 :         isolate->factory()->NewJSObject(isolate->object_function());
     721           5 :     Handle<JSWeakRef> inner_weak_ref = ConstructJSWeakRef(js_object, isolate);
     722           5 :     heap->AddKeepDuringJobTarget(js_object);
     723             : 
     724           5 :     weak_ref = inner_scope.CloseAndEscape(inner_weak_ref);
     725             :   }
     726             : 
     727           5 :   CHECK(!weak_ref->target()->IsUndefined(isolate));
     728             : 
     729           5 :   CcTest::CollectAllGarbage();
     730             : 
     731           5 :   CHECK(!weak_ref->target()->IsUndefined(isolate));
     732             : 
     733             :   // Clears the KeepDuringJob set.
     734           5 :   isolate->default_microtask_queue()->RunMicrotasks(isolate);
     735           5 :   CcTest::CollectAllGarbage();
     736             : 
     737           5 :   CHECK(weak_ref->target()->IsUndefined(isolate));
     738           5 : }
     739             : 
     740       26644 : TEST(TestJSWeakRefKeepDuringJobIncrementalMarking) {
     741           5 :   FLAG_harmony_weak_refs = true;
     742           5 :   if (!FLAG_incremental_marking) {
     743           0 :     return;
     744             :   }
     745             :   ManualGCScope manual_gc_scope;
     746           5 :   CcTest::InitializeVM();
     747           5 :   LocalContext context;
     748             : 
     749             :   Isolate* isolate = CcTest::i_isolate();
     750             :   Heap* heap = isolate->heap();
     751             :   HandleScope outer_scope(isolate);
     752             :   Handle<JSWeakRef> weak_ref;
     753             :   {
     754             :     HandleScope inner_scope(isolate);
     755             : 
     756             :     Handle<JSObject> js_object =
     757           5 :         isolate->factory()->NewJSObject(isolate->object_function());
     758           5 :     Handle<JSWeakRef> inner_weak_ref = ConstructJSWeakRef(js_object, isolate);
     759           5 :     heap->AddKeepDuringJobTarget(js_object);
     760             : 
     761           5 :     weak_ref = inner_scope.CloseAndEscape(inner_weak_ref);
     762             :   }
     763             : 
     764           5 :   CHECK(!weak_ref->target()->IsUndefined(isolate));
     765             : 
     766           5 :   heap::SimulateIncrementalMarking(heap, true);
     767           5 :   CcTest::CollectAllGarbage();
     768             : 
     769           5 :   CHECK(!weak_ref->target()->IsUndefined(isolate));
     770             : 
     771             :   // Clears the KeepDuringJob set.
     772           5 :   isolate->default_microtask_queue()->RunMicrotasks(isolate);
     773           5 :   heap::SimulateIncrementalMarking(heap, true);
     774           5 :   CcTest::CollectAllGarbage();
     775             : 
     776           5 :   CHECK(weak_ref->target()->IsUndefined(isolate));
     777             : }
     778             : 
     779             : }  // namespace internal
     780       79917 : }  // namespace v8

Generated by: LCOV version 1.10