11cb0ef41Sopenharmony_ci// Copyright 2018 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_OBJECTS_JS_WEAK_REFS_INL_H_ 61cb0ef41Sopenharmony_ci#define V8_OBJECTS_JS_WEAK_REFS_INL_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "src/api/api-inl.h" 91cb0ef41Sopenharmony_ci#include "src/heap/heap-write-barrier-inl.h" 101cb0ef41Sopenharmony_ci#include "src/objects/js-weak-refs.h" 111cb0ef41Sopenharmony_ci#include "src/objects/smi-inl.h" 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ci// Has to be the last include (doesn't have include guards): 141cb0ef41Sopenharmony_ci#include "src/objects/object-macros.h" 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_cinamespace v8 { 171cb0ef41Sopenharmony_cinamespace internal { 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci#include "torque-generated/src/objects/js-weak-refs-tq-inl.inc" 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ciTQ_OBJECT_CONSTRUCTORS_IMPL(WeakCell) 221cb0ef41Sopenharmony_ciTQ_OBJECT_CONSTRUCTORS_IMPL(JSWeakRef) 231cb0ef41Sopenharmony_ciTQ_OBJECT_CONSTRUCTORS_IMPL(JSFinalizationRegistry) 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciBIT_FIELD_ACCESSORS(JSFinalizationRegistry, flags, scheduled_for_cleanup, 261cb0ef41Sopenharmony_ci JSFinalizationRegistry::ScheduledForCleanupBit) 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_civoid JSFinalizationRegistry::RegisterWeakCellWithUnregisterToken( 291cb0ef41Sopenharmony_ci Handle<JSFinalizationRegistry> finalization_registry, 301cb0ef41Sopenharmony_ci Handle<WeakCell> weak_cell, Isolate* isolate) { 311cb0ef41Sopenharmony_ci Handle<SimpleNumberDictionary> key_map; 321cb0ef41Sopenharmony_ci if (finalization_registry->key_map().IsUndefined(isolate)) { 331cb0ef41Sopenharmony_ci key_map = SimpleNumberDictionary::New(isolate, 1); 341cb0ef41Sopenharmony_ci } else { 351cb0ef41Sopenharmony_ci key_map = 361cb0ef41Sopenharmony_ci handle(SimpleNumberDictionary::cast(finalization_registry->key_map()), 371cb0ef41Sopenharmony_ci isolate); 381cb0ef41Sopenharmony_ci } 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci // Unregister tokens are held weakly as objects are often their own 411cb0ef41Sopenharmony_ci // unregister token. To avoid using an ephemeron map, the map for token 421cb0ef41Sopenharmony_ci // lookup is keyed on the token's identity hash instead of the token itself. 431cb0ef41Sopenharmony_ci uint32_t key = weak_cell->unregister_token().GetOrCreateHash(isolate).value(); 441cb0ef41Sopenharmony_ci InternalIndex entry = key_map->FindEntry(isolate, key); 451cb0ef41Sopenharmony_ci if (entry.is_found()) { 461cb0ef41Sopenharmony_ci Object value = key_map->ValueAt(entry); 471cb0ef41Sopenharmony_ci WeakCell existing_weak_cell = WeakCell::cast(value); 481cb0ef41Sopenharmony_ci existing_weak_cell.set_key_list_prev(*weak_cell); 491cb0ef41Sopenharmony_ci weak_cell->set_key_list_next(existing_weak_cell); 501cb0ef41Sopenharmony_ci } 511cb0ef41Sopenharmony_ci key_map = SimpleNumberDictionary::Set(isolate, key_map, key, weak_cell); 521cb0ef41Sopenharmony_ci finalization_registry->set_key_map(*key_map); 531cb0ef41Sopenharmony_ci} 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_cibool JSFinalizationRegistry::Unregister( 561cb0ef41Sopenharmony_ci Handle<JSFinalizationRegistry> finalization_registry, 571cb0ef41Sopenharmony_ci Handle<HeapObject> unregister_token, Isolate* isolate) { 581cb0ef41Sopenharmony_ci // Iterate through the doubly linked list of WeakCells associated with the 591cb0ef41Sopenharmony_ci // key. Each WeakCell will be in the "active_cells" or "cleared_cells" list of 601cb0ef41Sopenharmony_ci // its FinalizationRegistry; remove it from there. 611cb0ef41Sopenharmony_ci return finalization_registry->RemoveUnregisterToken( 621cb0ef41Sopenharmony_ci *unregister_token, isolate, kRemoveMatchedCellsFromRegistry, 631cb0ef41Sopenharmony_ci [](HeapObject, ObjectSlot, Object) {}); 641cb0ef41Sopenharmony_ci} 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_citemplate <typename GCNotifyUpdatedSlotCallback> 671cb0ef41Sopenharmony_cibool JSFinalizationRegistry::RemoveUnregisterToken( 681cb0ef41Sopenharmony_ci HeapObject unregister_token, Isolate* isolate, 691cb0ef41Sopenharmony_ci RemoveUnregisterTokenMode removal_mode, 701cb0ef41Sopenharmony_ci GCNotifyUpdatedSlotCallback gc_notify_updated_slot) { 711cb0ef41Sopenharmony_ci // This method is called from both FinalizationRegistry#unregister and for 721cb0ef41Sopenharmony_ci // removing weakly-held dead unregister tokens. The latter is during GC so 731cb0ef41Sopenharmony_ci // this function cannot GC. 741cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 751cb0ef41Sopenharmony_ci if (key_map().IsUndefined(isolate)) { 761cb0ef41Sopenharmony_ci return false; 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci SimpleNumberDictionary key_map = 801cb0ef41Sopenharmony_ci SimpleNumberDictionary::cast(this->key_map()); 811cb0ef41Sopenharmony_ci // If the token doesn't have a hash, it was not used as a key inside any hash 821cb0ef41Sopenharmony_ci // tables. 831cb0ef41Sopenharmony_ci Object hash = unregister_token.GetHash(); 841cb0ef41Sopenharmony_ci if (hash.IsUndefined(isolate)) { 851cb0ef41Sopenharmony_ci return false; 861cb0ef41Sopenharmony_ci } 871cb0ef41Sopenharmony_ci uint32_t key = Smi::ToInt(hash); 881cb0ef41Sopenharmony_ci InternalIndex entry = key_map.FindEntry(isolate, key); 891cb0ef41Sopenharmony_ci if (entry.is_not_found()) { 901cb0ef41Sopenharmony_ci return false; 911cb0ef41Sopenharmony_ci } 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci Object value = key_map.ValueAt(entry); 941cb0ef41Sopenharmony_ci bool was_present = false; 951cb0ef41Sopenharmony_ci HeapObject undefined = ReadOnlyRoots(isolate).undefined_value(); 961cb0ef41Sopenharmony_ci HeapObject new_key_list_head = undefined; 971cb0ef41Sopenharmony_ci HeapObject new_key_list_prev = undefined; 981cb0ef41Sopenharmony_ci // Compute a new key list that doesn't have unregister_token. Because 991cb0ef41Sopenharmony_ci // unregister tokens are held weakly, key_map is keyed using the tokens' 1001cb0ef41Sopenharmony_ci // identity hashes, and identity hashes may collide. 1011cb0ef41Sopenharmony_ci while (!value.IsUndefined(isolate)) { 1021cb0ef41Sopenharmony_ci WeakCell weak_cell = WeakCell::cast(value); 1031cb0ef41Sopenharmony_ci DCHECK(!ObjectInYoungGeneration(weak_cell)); 1041cb0ef41Sopenharmony_ci value = weak_cell.key_list_next(); 1051cb0ef41Sopenharmony_ci if (weak_cell.unregister_token() == unregister_token) { 1061cb0ef41Sopenharmony_ci // weak_cell has the same unregister token; remove it from the key list. 1071cb0ef41Sopenharmony_ci switch (removal_mode) { 1081cb0ef41Sopenharmony_ci case kRemoveMatchedCellsFromRegistry: 1091cb0ef41Sopenharmony_ci weak_cell.RemoveFromFinalizationRegistryCells(isolate); 1101cb0ef41Sopenharmony_ci break; 1111cb0ef41Sopenharmony_ci case kKeepMatchedCellsInRegistry: 1121cb0ef41Sopenharmony_ci // Do nothing. 1131cb0ef41Sopenharmony_ci break; 1141cb0ef41Sopenharmony_ci } 1151cb0ef41Sopenharmony_ci // Clear unregister token-related fields. 1161cb0ef41Sopenharmony_ci weak_cell.set_unregister_token(undefined); 1171cb0ef41Sopenharmony_ci weak_cell.set_key_list_prev(undefined); 1181cb0ef41Sopenharmony_ci weak_cell.set_key_list_next(undefined); 1191cb0ef41Sopenharmony_ci was_present = true; 1201cb0ef41Sopenharmony_ci } else { 1211cb0ef41Sopenharmony_ci // weak_cell has a different unregister token with the same key (hash 1221cb0ef41Sopenharmony_ci // collision); fix up the list. 1231cb0ef41Sopenharmony_ci weak_cell.set_key_list_prev(new_key_list_prev); 1241cb0ef41Sopenharmony_ci gc_notify_updated_slot(weak_cell, 1251cb0ef41Sopenharmony_ci weak_cell.RawField(WeakCell::kKeyListPrevOffset), 1261cb0ef41Sopenharmony_ci new_key_list_prev); 1271cb0ef41Sopenharmony_ci weak_cell.set_key_list_next(undefined); 1281cb0ef41Sopenharmony_ci if (new_key_list_prev.IsUndefined(isolate)) { 1291cb0ef41Sopenharmony_ci new_key_list_head = weak_cell; 1301cb0ef41Sopenharmony_ci } else { 1311cb0ef41Sopenharmony_ci DCHECK(new_key_list_head.IsWeakCell()); 1321cb0ef41Sopenharmony_ci WeakCell prev_cell = WeakCell::cast(new_key_list_prev); 1331cb0ef41Sopenharmony_ci prev_cell.set_key_list_next(weak_cell); 1341cb0ef41Sopenharmony_ci gc_notify_updated_slot(prev_cell, 1351cb0ef41Sopenharmony_ci prev_cell.RawField(WeakCell::kKeyListNextOffset), 1361cb0ef41Sopenharmony_ci weak_cell); 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci new_key_list_prev = weak_cell; 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci if (new_key_list_head.IsUndefined(isolate)) { 1421cb0ef41Sopenharmony_ci DCHECK(was_present); 1431cb0ef41Sopenharmony_ci key_map.ClearEntry(entry); 1441cb0ef41Sopenharmony_ci key_map.ElementRemoved(); 1451cb0ef41Sopenharmony_ci } else { 1461cb0ef41Sopenharmony_ci key_map.ValueAtPut(entry, new_key_list_head); 1471cb0ef41Sopenharmony_ci gc_notify_updated_slot(key_map, key_map.RawFieldOfValueAt(entry), 1481cb0ef41Sopenharmony_ci new_key_list_head); 1491cb0ef41Sopenharmony_ci } 1501cb0ef41Sopenharmony_ci return was_present; 1511cb0ef41Sopenharmony_ci} 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_cibool JSFinalizationRegistry::NeedsCleanup() const { 1541cb0ef41Sopenharmony_ci return cleared_cells().IsWeakCell(); 1551cb0ef41Sopenharmony_ci} 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ciHeapObject WeakCell::relaxed_target() const { 1581cb0ef41Sopenharmony_ci return TaggedField<HeapObject>::Relaxed_Load(*this, kTargetOffset); 1591cb0ef41Sopenharmony_ci} 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ciHeapObject WeakCell::relaxed_unregister_token() const { 1621cb0ef41Sopenharmony_ci return TaggedField<HeapObject>::Relaxed_Load(*this, kUnregisterTokenOffset); 1631cb0ef41Sopenharmony_ci} 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_citemplate <typename GCNotifyUpdatedSlotCallback> 1661cb0ef41Sopenharmony_civoid WeakCell::Nullify(Isolate* isolate, 1671cb0ef41Sopenharmony_ci GCNotifyUpdatedSlotCallback gc_notify_updated_slot) { 1681cb0ef41Sopenharmony_ci // Remove from the WeakCell from the "active_cells" list of its 1691cb0ef41Sopenharmony_ci // JSFinalizationRegistry and insert it into the "cleared_cells" list. This is 1701cb0ef41Sopenharmony_ci // only called for WeakCells which haven't been unregistered yet, so they will 1711cb0ef41Sopenharmony_ci // be in the active_cells list. (The caller must guard against calling this 1721cb0ef41Sopenharmony_ci // for unregistered WeakCells by checking that the target is not undefined.) 1731cb0ef41Sopenharmony_ci DCHECK(target().CanBeHeldWeakly()); 1741cb0ef41Sopenharmony_ci set_target(ReadOnlyRoots(isolate).undefined_value()); 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci JSFinalizationRegistry fr = 1771cb0ef41Sopenharmony_ci JSFinalizationRegistry::cast(finalization_registry()); 1781cb0ef41Sopenharmony_ci if (prev().IsWeakCell()) { 1791cb0ef41Sopenharmony_ci DCHECK_NE(fr.active_cells(), *this); 1801cb0ef41Sopenharmony_ci WeakCell prev_cell = WeakCell::cast(prev()); 1811cb0ef41Sopenharmony_ci prev_cell.set_next(next()); 1821cb0ef41Sopenharmony_ci gc_notify_updated_slot(prev_cell, prev_cell.RawField(WeakCell::kNextOffset), 1831cb0ef41Sopenharmony_ci next()); 1841cb0ef41Sopenharmony_ci } else { 1851cb0ef41Sopenharmony_ci DCHECK_EQ(fr.active_cells(), *this); 1861cb0ef41Sopenharmony_ci fr.set_active_cells(next()); 1871cb0ef41Sopenharmony_ci gc_notify_updated_slot( 1881cb0ef41Sopenharmony_ci fr, fr.RawField(JSFinalizationRegistry::kActiveCellsOffset), next()); 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci if (next().IsWeakCell()) { 1911cb0ef41Sopenharmony_ci WeakCell next_cell = WeakCell::cast(next()); 1921cb0ef41Sopenharmony_ci next_cell.set_prev(prev()); 1931cb0ef41Sopenharmony_ci gc_notify_updated_slot(next_cell, next_cell.RawField(WeakCell::kPrevOffset), 1941cb0ef41Sopenharmony_ci prev()); 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci set_prev(ReadOnlyRoots(isolate).undefined_value()); 1981cb0ef41Sopenharmony_ci Object cleared_head = fr.cleared_cells(); 1991cb0ef41Sopenharmony_ci if (cleared_head.IsWeakCell()) { 2001cb0ef41Sopenharmony_ci WeakCell cleared_head_cell = WeakCell::cast(cleared_head); 2011cb0ef41Sopenharmony_ci cleared_head_cell.set_prev(*this); 2021cb0ef41Sopenharmony_ci gc_notify_updated_slot(cleared_head_cell, 2031cb0ef41Sopenharmony_ci cleared_head_cell.RawField(WeakCell::kPrevOffset), 2041cb0ef41Sopenharmony_ci *this); 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci set_next(fr.cleared_cells()); 2071cb0ef41Sopenharmony_ci gc_notify_updated_slot(*this, RawField(WeakCell::kNextOffset), next()); 2081cb0ef41Sopenharmony_ci fr.set_cleared_cells(*this); 2091cb0ef41Sopenharmony_ci gc_notify_updated_slot( 2101cb0ef41Sopenharmony_ci fr, fr.RawField(JSFinalizationRegistry::kClearedCellsOffset), *this); 2111cb0ef41Sopenharmony_ci} 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_civoid WeakCell::RemoveFromFinalizationRegistryCells(Isolate* isolate) { 2141cb0ef41Sopenharmony_ci // Remove the WeakCell from the list it's in (either "active_cells" or 2151cb0ef41Sopenharmony_ci // "cleared_cells" of its JSFinalizationRegistry). 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci // It's important to set_target to undefined here. This guards that we won't 2181cb0ef41Sopenharmony_ci // call Nullify (which assumes that the WeakCell is in active_cells). 2191cb0ef41Sopenharmony_ci DCHECK(target().IsUndefined() || target().CanBeHeldWeakly()); 2201cb0ef41Sopenharmony_ci set_target(ReadOnlyRoots(isolate).undefined_value()); 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci JSFinalizationRegistry fr = 2231cb0ef41Sopenharmony_ci JSFinalizationRegistry::cast(finalization_registry()); 2241cb0ef41Sopenharmony_ci if (fr.active_cells() == *this) { 2251cb0ef41Sopenharmony_ci DCHECK(prev().IsUndefined(isolate)); 2261cb0ef41Sopenharmony_ci fr.set_active_cells(next()); 2271cb0ef41Sopenharmony_ci } else if (fr.cleared_cells() == *this) { 2281cb0ef41Sopenharmony_ci DCHECK(!prev().IsWeakCell()); 2291cb0ef41Sopenharmony_ci fr.set_cleared_cells(next()); 2301cb0ef41Sopenharmony_ci } else { 2311cb0ef41Sopenharmony_ci DCHECK(prev().IsWeakCell()); 2321cb0ef41Sopenharmony_ci WeakCell prev_cell = WeakCell::cast(prev()); 2331cb0ef41Sopenharmony_ci prev_cell.set_next(next()); 2341cb0ef41Sopenharmony_ci } 2351cb0ef41Sopenharmony_ci if (next().IsWeakCell()) { 2361cb0ef41Sopenharmony_ci WeakCell next_cell = WeakCell::cast(next()); 2371cb0ef41Sopenharmony_ci next_cell.set_prev(prev()); 2381cb0ef41Sopenharmony_ci } 2391cb0ef41Sopenharmony_ci set_prev(ReadOnlyRoots(isolate).undefined_value()); 2401cb0ef41Sopenharmony_ci set_next(ReadOnlyRoots(isolate).undefined_value()); 2411cb0ef41Sopenharmony_ci} 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_ci} // namespace internal 2441cb0ef41Sopenharmony_ci} // namespace v8 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci#include "src/objects/object-macros-undef.h" 2471cb0ef41Sopenharmony_ci 2481cb0ef41Sopenharmony_ci#endif // V8_OBJECTS_JS_WEAK_REFS_INL_H_ 249