LCOV - code coverage report
Current view: top level - src/objects - js-weak-refs-inl.h (source / functions) Hit Total Coverage
Test: app.info Lines: 131 136 96.3 %
Date: 2019-02-19 Functions: 34 34 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             : #ifndef V8_OBJECTS_JS_WEAK_REFS_INL_H_
       6             : #define V8_OBJECTS_JS_WEAK_REFS_INL_H_
       7             : 
       8             : #include "src/objects/js-weak-refs.h"
       9             : 
      10             : #include "src/api-inl.h"
      11             : #include "src/heap/heap-write-barrier-inl.h"
      12             : #include "src/objects/microtask-inl.h"
      13             : #include "src/objects/smi-inl.h"
      14             : 
      15             : // Has to be the last include (doesn't have include guards):
      16             : #include "src/objects/object-macros.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : 
      21        3790 : OBJECT_CONSTRUCTORS_IMPL(WeakCell, HeapObject)
      22         876 : OBJECT_CONSTRUCTORS_IMPL(JSWeakRef, JSObject)
      23        4720 : OBJECT_CONSTRUCTORS_IMPL(JSFinalizationGroup, JSObject)
      24        1116 : OBJECT_CONSTRUCTORS_IMPL(JSFinalizationGroupCleanupIterator, JSObject)
      25         414 : OBJECT_CONSTRUCTORS_IMPL(FinalizationGroupCleanupJobTask, Microtask)
      26             : 
      27        2111 : ACCESSORS(JSFinalizationGroup, native_context, NativeContext,
      28             :           kNativeContextOffset)
      29        1679 : ACCESSORS(JSFinalizationGroup, cleanup, Object, kCleanupOffset)
      30        5094 : ACCESSORS(JSFinalizationGroup, active_cells, Object, kActiveCellsOffset)
      31        4949 : ACCESSORS(JSFinalizationGroup, cleared_cells, Object, kClearedCellsOffset)
      32        2566 : ACCESSORS(JSFinalizationGroup, key_map, Object, kKeyMapOffset)
      33        2062 : SMI_ACCESSORS(JSFinalizationGroup, flags, kFlagsOffset)
      34        2277 : ACCESSORS(JSFinalizationGroup, next, Object, kNextOffset)
      35        2360 : CAST_ACCESSOR(JSFinalizationGroup)
      36             : 
      37        2894 : ACCESSORS(WeakCell, finalization_group, Object, kFinalizationGroupOffset)
      38        7279 : ACCESSORS(WeakCell, target, HeapObject, kTargetOffset)
      39        2457 : ACCESSORS(WeakCell, holdings, Object, kHoldingsOffset)
      40        9975 : ACCESSORS(WeakCell, next, Object, kNextOffset)
      41        6480 : ACCESSORS(WeakCell, prev, Object, kPrevOffset)
      42        2517 : ACCESSORS(WeakCell, key, Object, kKeyOffset)
      43        3207 : ACCESSORS(WeakCell, key_list_next, Object, kKeyListNextOffset)
      44        3110 : ACCESSORS(WeakCell, key_list_prev, Object, kKeyListPrevOffset)
      45        1895 : CAST_ACCESSOR(WeakCell)
      46             : 
      47         438 : CAST_ACCESSOR(JSWeakRef)
      48        3734 : ACCESSORS(JSWeakRef, target, HeapObject, kTargetOffset)
      49             : 
      50        2052 : ACCESSORS(JSFinalizationGroupCleanupIterator, finalization_group,
      51             :           JSFinalizationGroup, kFinalizationGroupOffset)
      52         558 : CAST_ACCESSOR(JSFinalizationGroupCleanupIterator)
      53             : 
      54        1035 : ACCESSORS(FinalizationGroupCleanupJobTask, finalization_group,
      55             :           JSFinalizationGroup, kFinalizationGroupOffset)
      56         207 : CAST_ACCESSOR(FinalizationGroupCleanupJobTask)
      57             : 
      58         444 : void JSFinalizationGroup::Register(
      59             :     Handle<JSFinalizationGroup> finalization_group, Handle<JSReceiver> target,
      60             :     Handle<Object> holdings, Handle<Object> key, Isolate* isolate) {
      61         444 :   Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell();
      62         888 :   weak_cell->set_finalization_group(*finalization_group);
      63         888 :   weak_cell->set_target(*target);
      64         444 :   weak_cell->set_holdings(*holdings);
      65         888 :   weak_cell->set_prev(ReadOnlyRoots(isolate).undefined_value());
      66         888 :   weak_cell->set_next(ReadOnlyRoots(isolate).undefined_value());
      67         444 :   weak_cell->set_key(*key);
      68         888 :   weak_cell->set_key_list_prev(ReadOnlyRoots(isolate).undefined_value());
      69         888 :   weak_cell->set_key_list_next(ReadOnlyRoots(isolate).undefined_value());
      70             : 
      71             :   // Add to active_cells.
      72         444 :   weak_cell->set_next(finalization_group->active_cells());
      73         888 :   if (finalization_group->active_cells()->IsWeakCell()) {
      74         248 :     WeakCell::cast(finalization_group->active_cells())->set_prev(*weak_cell);
      75             :   }
      76         888 :   finalization_group->set_active_cells(*weak_cell);
      77             : 
      78         888 :   if (!key->IsUndefined(isolate)) {
      79             :     Handle<ObjectHashTable> key_map;
      80         384 :     if (finalization_group->key_map()->IsUndefined(isolate)) {
      81         120 :       key_map = ObjectHashTable::New(isolate, 1);
      82             :     } else {
      83             :       key_map =
      84             :           handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
      85             :     }
      86             : 
      87         192 :     Object value = key_map->Lookup(key);
      88         192 :     if (value->IsWeakCell()) {
      89          39 :       WeakCell existing_weak_cell = WeakCell::cast(value);
      90          39 :       existing_weak_cell->set_key_list_prev(*weak_cell);
      91          39 :       weak_cell->set_key_list_next(existing_weak_cell);
      92             :     } else {
      93             :       DCHECK(value->IsTheHole(isolate));
      94             :     }
      95         192 :     key_map = ObjectHashTable::Put(key_map, key, weak_cell);
      96         384 :     finalization_group->set_key_map(*key_map);
      97             :   }
      98         444 : }
      99             : 
     100         138 : void JSFinalizationGroup::Unregister(
     101             :     Handle<JSFinalizationGroup> finalization_group, Handle<Object> key,
     102             :     Isolate* isolate) {
     103             :   // Iterate through the doubly linked list of WeakCells associated with the
     104             :   // key. Each WeakCell will be in the "active_cells" or "cleared_cells" list of
     105             :   // its FinalizationGroup; remove it from there.
     106         276 :   if (!finalization_group->key_map()->IsUndefined(isolate)) {
     107             :     Handle<ObjectHashTable> key_map =
     108             :         handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     109         124 :     Object value = key_map->Lookup(key);
     110         124 :     Object undefined = ReadOnlyRoots(isolate).undefined_value();
     111         345 :     while (value->IsWeakCell()) {
     112          97 :       WeakCell weak_cell = WeakCell::cast(value);
     113          97 :       weak_cell->RemoveFromFinalizationGroupCells(isolate);
     114          97 :       value = weak_cell->key_list_next();
     115          97 :       weak_cell->set_key_list_prev(undefined);
     116          97 :       weak_cell->set_key_list_next(undefined);
     117             :     }
     118             :     bool was_present;
     119         124 :     key_map = ObjectHashTable::Remove(isolate, key_map, key, &was_present);
     120         248 :     finalization_group->set_key_map(*key_map);
     121             :   }
     122         138 : }
     123             : 
     124         399 : bool JSFinalizationGroup::NeedsCleanup() const {
     125         798 :   return cleared_cells()->IsWeakCell();
     126             : }
     127             : 
     128         261 : bool JSFinalizationGroup::scheduled_for_cleanup() const {
     129         522 :   return ScheduledForCleanupField::decode(flags());
     130             : }
     131             : 
     132         414 : void JSFinalizationGroup::set_scheduled_for_cleanup(
     133             :     bool scheduled_for_cleanup) {
     134         828 :   set_flags(ScheduledForCleanupField::update(flags(), scheduled_for_cleanup));
     135         414 : }
     136             : 
     137         237 : Object JSFinalizationGroup::PopClearedCellHoldings(
     138             :     Handle<JSFinalizationGroup> finalization_group, Isolate* isolate) {
     139             :   Handle<WeakCell> weak_cell =
     140             :       handle(WeakCell::cast(finalization_group->cleared_cells()), isolate);
     141             :   DCHECK(weak_cell->prev()->IsUndefined(isolate));
     142         237 :   finalization_group->set_cleared_cells(weak_cell->next());
     143         474 :   weak_cell->set_next(ReadOnlyRoots(isolate).undefined_value());
     144             : 
     145         474 :   if (finalization_group->cleared_cells()->IsWeakCell()) {
     146             :     WeakCell cleared_cells_head =
     147          73 :         WeakCell::cast(finalization_group->cleared_cells());
     148             :     DCHECK_EQ(cleared_cells_head->prev(), *weak_cell);
     149          73 :     cleared_cells_head->set_prev(ReadOnlyRoots(isolate).undefined_value());
     150             :   } else {
     151             :     DCHECK(finalization_group->cleared_cells()->IsUndefined(isolate));
     152             :   }
     153             : 
     154             :   // Also remove the WeakCell from the key_map (if it's there).
     155         474 :   if (!weak_cell->key()->IsUndefined(isolate)) {
     156         240 :     if (weak_cell->key_list_prev()->IsUndefined(isolate) &&
     157         120 :         weak_cell->key_list_next()->IsUndefined(isolate)) {
     158             :       // weak_cell is the only one associated with its key; remove the key
     159             :       // from the hash table.
     160             :       Handle<ObjectHashTable> key_map =
     161             :           handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     162          55 :       Handle<Object> key = handle(weak_cell->key(), isolate);
     163             :       bool was_present;
     164          55 :       key_map = ObjectHashTable::Remove(isolate, key_map, key, &was_present);
     165             :       DCHECK(was_present);
     166         110 :       finalization_group->set_key_map(*key_map);
     167          10 :     } else if (weak_cell->key_list_prev()->IsUndefined()) {
     168             :       // weak_cell is the list head for its key; we need to change the value of
     169             :       // the key in the hash table.
     170             :       Handle<ObjectHashTable> key_map =
     171             :           handle(ObjectHashTable::cast(finalization_group->key_map()), isolate);
     172           5 :       Handle<Object> key = handle(weak_cell->key(), isolate);
     173             :       Handle<WeakCell> next =
     174             :           handle(WeakCell::cast(weak_cell->key_list_next()), isolate);
     175             :       DCHECK_EQ(next->key_list_prev(), *weak_cell);
     176          10 :       next->set_key_list_prev(ReadOnlyRoots(isolate).undefined_value());
     177          10 :       weak_cell->set_key_list_next(ReadOnlyRoots(isolate).undefined_value());
     178           5 :       key_map = ObjectHashTable::Put(key_map, key, next);
     179          10 :       finalization_group->set_key_map(*key_map);
     180             :     } else {
     181             :       // weak_cell is somewhere in the middle of its key list.
     182           0 :       WeakCell prev = WeakCell::cast(weak_cell->key_list_prev());
     183           0 :       prev->set_key_list_next(weak_cell->key_list_next());
     184           0 :       if (!weak_cell->key_list_next()->IsUndefined()) {
     185           0 :         WeakCell next = WeakCell::cast(weak_cell->key_list_next());
     186           0 :         next->set_key_list_prev(weak_cell->key_list_prev());
     187             :       }
     188             :     }
     189             :   }
     190             : 
     191         237 :   return weak_cell->holdings();
     192             : }
     193             : 
     194         316 : void WeakCell::Nullify(
     195             :     Isolate* isolate,
     196             :     std::function<void(HeapObject object, ObjectSlot slot, Object target)>
     197             :         gc_notify_updated_slot) {
     198             :   // Remove from the WeakCell from the "active_cells" list of its
     199             :   // JSFinalizationGroup and insert it into the "cleared_cells" list. This is
     200             :   // only called for WeakCells which haven't been unregistered yet, so they will
     201             :   // be in the active_cells list. (The caller must guard against calling this
     202             :   // for unregistered WeakCells by checking that the target is not undefined.)
     203             :   DCHECK(target()->IsJSReceiver());
     204         316 :   set_target(ReadOnlyRoots(isolate).undefined_value());
     205             : 
     206         316 :   JSFinalizationGroup fg = JSFinalizationGroup::cast(finalization_group());
     207         632 :   if (prev()->IsWeakCell()) {
     208             :     DCHECK_NE(fg->active_cells(), *this);
     209          55 :     WeakCell prev_cell = WeakCell::cast(prev());
     210          55 :     prev_cell->set_next(next());
     211             :     gc_notify_updated_slot(prev_cell, prev_cell.RawField(WeakCell::kNextOffset),
     212          55 :                            next());
     213             :   } else {
     214             :     DCHECK_EQ(fg->active_cells(), *this);
     215         261 :     fg->set_active_cells(next());
     216             :     gc_notify_updated_slot(
     217         261 :         fg, fg.RawField(JSFinalizationGroup::kActiveCellsOffset), next());
     218             :   }
     219         632 :   if (next()->IsWeakCell()) {
     220          21 :     WeakCell next_cell = WeakCell::cast(next());
     221          21 :     next_cell->set_prev(prev());
     222             :     gc_notify_updated_slot(next_cell, next_cell.RawField(WeakCell::kPrevOffset),
     223          21 :                            prev());
     224             :   }
     225             : 
     226         316 :   set_prev(ReadOnlyRoots(isolate).undefined_value());
     227         316 :   Object cleared_head = fg->cleared_cells();
     228         316 :   if (cleared_head->IsWeakCell()) {
     229          83 :     WeakCell cleared_head_cell = WeakCell::cast(cleared_head);
     230          83 :     cleared_head_cell->set_prev(*this);
     231             :     gc_notify_updated_slot(cleared_head_cell,
     232             :                            cleared_head_cell.RawField(WeakCell::kPrevOffset),
     233          83 :                            *this);
     234             :   }
     235         316 :   set_next(fg->cleared_cells());
     236         316 :   gc_notify_updated_slot(*this, RawField(WeakCell::kNextOffset), next());
     237         316 :   fg->set_cleared_cells(*this);
     238             :   gc_notify_updated_slot(
     239         316 :       fg, fg.RawField(JSFinalizationGroup::kClearedCellsOffset), *this);
     240         316 : }
     241             : 
     242          97 : void WeakCell::RemoveFromFinalizationGroupCells(Isolate* isolate) {
     243             :   // Remove the WeakCell from the list it's in (either "active_cells" or
     244             :   // "cleared_cells" of its JSFinalizationGroup).
     245             : 
     246             :   // It's important to set_target to undefined here. This guards that we won't
     247             :   // call Nullify (which assumes that the WeakCell is in active_cells).
     248             :   DCHECK(target()->IsUndefined() || target()->IsJSReceiver());
     249          97 :   set_target(ReadOnlyRoots(isolate).undefined_value());
     250             : 
     251          97 :   JSFinalizationGroup fg = JSFinalizationGroup::cast(finalization_group());
     252          97 :   if (fg->active_cells() == *this) {
     253             :     DCHECK(prev()->IsUndefined(isolate));
     254          28 :     fg->set_active_cells(next());
     255          69 :   } else if (fg->cleared_cells() == *this) {
     256             :     DCHECK(!prev()->IsWeakCell());
     257          41 :     fg->set_cleared_cells(next());
     258             :   } else {
     259             :     DCHECK(prev()->IsWeakCell());
     260          28 :     WeakCell prev_cell = WeakCell::cast(prev());
     261          28 :     prev_cell->set_next(next());
     262             :   }
     263         194 :   if (next()->IsWeakCell()) {
     264          19 :     WeakCell next_cell = WeakCell::cast(next());
     265          19 :     next_cell->set_prev(prev());
     266             :   }
     267          97 :   set_prev(ReadOnlyRoots(isolate).undefined_value());
     268          97 :   set_next(ReadOnlyRoots(isolate).undefined_value());
     269          97 : }
     270             : 
     271             : }  // namespace internal
     272             : }  // namespace v8
     273             : 
     274             : #include "src/objects/object-macros-undef.h"
     275             : 
     276             : #endif  // V8_OBJECTS_JS_WEAK_REFS_INL_H_

Generated by: LCOV version 1.10