%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/objects/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/objects/js-weak-refs-inl.h |
// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_OBJECTS_JS_WEAK_REFS_INL_H_ #define V8_OBJECTS_JS_WEAK_REFS_INL_H_ #include "src/api/api-inl.h" #include "src/heap/heap-write-barrier-inl.h" #include "src/objects/js-weak-refs.h" #include "src/objects/smi-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" namespace v8 { namespace internal { #include "torque-generated/src/objects/js-weak-refs-tq-inl.inc" TQ_OBJECT_CONSTRUCTORS_IMPL(WeakCell) TQ_OBJECT_CONSTRUCTORS_IMPL(JSWeakRef) TQ_OBJECT_CONSTRUCTORS_IMPL(JSFinalizationRegistry) BIT_FIELD_ACCESSORS(JSFinalizationRegistry, flags, scheduled_for_cleanup, JSFinalizationRegistry::ScheduledForCleanupBit) void JSFinalizationRegistry::RegisterWeakCellWithUnregisterToken( Handle<JSFinalizationRegistry> finalization_registry, Handle<WeakCell> weak_cell, Isolate* isolate) { Handle<SimpleNumberDictionary> key_map; if (IsUndefined(finalization_registry->key_map(), isolate)) { key_map = SimpleNumberDictionary::New(isolate, 1); } else { key_map = handle(SimpleNumberDictionary::cast(finalization_registry->key_map()), isolate); } // Unregister tokens are held weakly as objects are often their own // unregister token. To avoid using an ephemeron map, the map for token // lookup is keyed on the token's identity hash instead of the token itself. uint32_t key = Object::GetOrCreateHash(weak_cell->unregister_token(), isolate).value(); InternalIndex entry = key_map->FindEntry(isolate, key); if (entry.is_found()) { Tagged<Object> value = key_map->ValueAt(entry); Tagged<WeakCell> existing_weak_cell = WeakCell::cast(value); existing_weak_cell->set_key_list_prev(*weak_cell); weak_cell->set_key_list_next(existing_weak_cell); } key_map = SimpleNumberDictionary::Set(isolate, key_map, key, weak_cell); finalization_registry->set_key_map(*key_map); } bool JSFinalizationRegistry::Unregister( Handle<JSFinalizationRegistry> finalization_registry, Handle<HeapObject> unregister_token, Isolate* isolate) { // Iterate through the doubly linked list of WeakCells associated with the // key. Each WeakCell will be in the "active_cells" or "cleared_cells" list of // its FinalizationRegistry; remove it from there. return finalization_registry->RemoveUnregisterToken( *unregister_token, isolate, kRemoveMatchedCellsFromRegistry, [](Tagged<HeapObject>, ObjectSlot, Tagged<Object>) {}); } template <typename GCNotifyUpdatedSlotCallback> bool JSFinalizationRegistry::RemoveUnregisterToken( Tagged<HeapObject> unregister_token, Isolate* isolate, RemoveUnregisterTokenMode removal_mode, GCNotifyUpdatedSlotCallback gc_notify_updated_slot) { // This method is called from both FinalizationRegistry#unregister and for // removing weakly-held dead unregister tokens. The latter is during GC so // this function cannot GC. DisallowGarbageCollection no_gc; if (IsUndefined(key_map(), isolate)) { return false; } Tagged<SimpleNumberDictionary> key_map = SimpleNumberDictionary::cast(this->key_map()); // If the token doesn't have a hash, it was not used as a key inside any hash // tables. Tagged<Object> hash = Object::GetHash(unregister_token); if (IsUndefined(hash, isolate)) { return false; } uint32_t key = Smi::ToInt(hash); InternalIndex entry = key_map->FindEntry(isolate, key); if (entry.is_not_found()) { return false; } Tagged<Object> value = key_map->ValueAt(entry); bool was_present = false; Tagged<HeapObject> undefined = ReadOnlyRoots(isolate).undefined_value(); Tagged<HeapObject> new_key_list_head = undefined; Tagged<HeapObject> new_key_list_prev = undefined; // Compute a new key list that doesn't have unregister_token. Because // unregister tokens are held weakly, key_map is keyed using the tokens' // identity hashes, and identity hashes may collide. while (!IsUndefined(value, isolate)) { Tagged<WeakCell> weak_cell = WeakCell::cast(value); DCHECK(!ObjectInYoungGeneration(weak_cell)); value = weak_cell->key_list_next(); if (weak_cell->unregister_token() == unregister_token) { // weak_cell has the same unregister token; remove it from the key list. switch (removal_mode) { case kRemoveMatchedCellsFromRegistry: weak_cell->RemoveFromFinalizationRegistryCells(isolate); break; case kKeepMatchedCellsInRegistry: // Do nothing. break; } // Clear unregister token-related fields. weak_cell->set_unregister_token(undefined); weak_cell->set_key_list_prev(undefined); weak_cell->set_key_list_next(undefined); was_present = true; } else { // weak_cell has a different unregister token with the same key (hash // collision); fix up the list. weak_cell->set_key_list_prev(new_key_list_prev); gc_notify_updated_slot(weak_cell, weak_cell->RawField(WeakCell::kKeyListPrevOffset), new_key_list_prev); weak_cell->set_key_list_next(undefined); if (IsUndefined(new_key_list_prev, isolate)) { new_key_list_head = weak_cell; } else { DCHECK(IsWeakCell(new_key_list_head)); Tagged<WeakCell> prev_cell = WeakCell::cast(new_key_list_prev); prev_cell->set_key_list_next(weak_cell); gc_notify_updated_slot( prev_cell, prev_cell->RawField(WeakCell::kKeyListNextOffset), weak_cell); } new_key_list_prev = weak_cell; } } if (IsUndefined(new_key_list_head, isolate)) { DCHECK(was_present); key_map->ClearEntry(entry); key_map->ElementRemoved(); } else { key_map->ValueAtPut(entry, new_key_list_head); gc_notify_updated_slot(key_map, key_map->RawFieldOfValueAt(entry), new_key_list_head); } return was_present; } bool JSFinalizationRegistry::NeedsCleanup() const { return IsWeakCell(cleared_cells()); } Tagged<HeapObject> WeakCell::relaxed_target() const { return TaggedField<HeapObject>::Relaxed_Load(*this, kTargetOffset); } Tagged<HeapObject> WeakCell::relaxed_unregister_token() const { return TaggedField<HeapObject>::Relaxed_Load(*this, kUnregisterTokenOffset); } template <typename GCNotifyUpdatedSlotCallback> void WeakCell::Nullify(Isolate* isolate, GCNotifyUpdatedSlotCallback gc_notify_updated_slot) { // Remove from the WeakCell from the "active_cells" list of its // JSFinalizationRegistry and insert it into the "cleared_cells" list. This is // only called for WeakCells which haven't been unregistered yet, so they will // be in the active_cells list. (The caller must guard against calling this // for unregistered WeakCells by checking that the target is not undefined.) DCHECK(Object::CanBeHeldWeakly(target())); set_target(ReadOnlyRoots(isolate).undefined_value()); Tagged<JSFinalizationRegistry> fr = JSFinalizationRegistry::cast(finalization_registry()); if (IsWeakCell(prev())) { DCHECK_NE(fr->active_cells(), *this); Tagged<WeakCell> prev_cell = WeakCell::cast(prev()); prev_cell->set_next(next()); gc_notify_updated_slot(prev_cell, prev_cell->RawField(WeakCell::kNextOffset), next()); } else { DCHECK_EQ(fr->active_cells(), *this); fr->set_active_cells(next()); gc_notify_updated_slot( fr, fr->RawField(JSFinalizationRegistry::kActiveCellsOffset), next()); } if (IsWeakCell(next())) { Tagged<WeakCell> next_cell = WeakCell::cast(next()); next_cell->set_prev(prev()); gc_notify_updated_slot(next_cell, next_cell->RawField(WeakCell::kPrevOffset), prev()); } set_prev(ReadOnlyRoots(isolate).undefined_value()); Tagged<Object> cleared_head = fr->cleared_cells(); if (IsWeakCell(cleared_head)) { Tagged<WeakCell> cleared_head_cell = WeakCell::cast(cleared_head); cleared_head_cell->set_prev(*this); gc_notify_updated_slot(cleared_head_cell, cleared_head_cell->RawField(WeakCell::kPrevOffset), *this); } set_next(fr->cleared_cells()); gc_notify_updated_slot(*this, RawField(WeakCell::kNextOffset), next()); fr->set_cleared_cells(*this); gc_notify_updated_slot( fr, fr->RawField(JSFinalizationRegistry::kClearedCellsOffset), *this); } void WeakCell::RemoveFromFinalizationRegistryCells(Isolate* isolate) { // Remove the WeakCell from the list it's in (either "active_cells" or // "cleared_cells" of its JSFinalizationRegistry). // It's important to set_target to undefined here. This guards that we won't // call Nullify (which assumes that the WeakCell is in active_cells). DCHECK(IsUndefined(target()) || Object::CanBeHeldWeakly(target())); set_target(ReadOnlyRoots(isolate).undefined_value()); Tagged<JSFinalizationRegistry> fr = JSFinalizationRegistry::cast(finalization_registry()); if (fr->active_cells() == *this) { DCHECK(IsUndefined(prev(), isolate)); fr->set_active_cells(next()); } else if (fr->cleared_cells() == *this) { DCHECK(!IsWeakCell(prev())); fr->set_cleared_cells(next()); } else { DCHECK(IsWeakCell(prev())); Tagged<WeakCell> prev_cell = WeakCell::cast(prev()); prev_cell->set_next(next()); } if (IsWeakCell(next())) { Tagged<WeakCell> next_cell = WeakCell::cast(next()); next_cell->set_prev(prev()); } set_prev(ReadOnlyRoots(isolate).undefined_value()); set_next(ReadOnlyRoots(isolate).undefined_value()); } } // namespace internal } // namespace v8 #include "src/objects/object-macros-undef.h" #endif // V8_OBJECTS_JS_WEAK_REFS_INL_H_