#include "src/objects/js-weak-refs.h"
#include "src/execution/execution.h"
#include "src/objects/js-weak-refs-inl.h"
namespace v8 {
namespace internal {
Tagged<WeakCell> JSFinalizationRegistry::PopClearedCell(
Isolate* isolate, bool* key_map_may_need_shrink) {
DisallowGarbageCollection no_gc;
Tagged<Undefined> undefined = ReadOnlyRoots(isolate).undefined_value();
Tagged<WeakCell> head = Cast<WeakCell>(cleared_cells());
DCHECK(IsUndefined(head->prev(), isolate));
Tagged<Union<Undefined, WeakCell>> tail = head->next();
head->set_next(undefined);
if (IsWeakCell(tail)) Cast<WeakCell>(tail)->set_prev(undefined);
set_cleared_cells(tail);
if (!IsUndefined(head->unregister_token(), isolate)) {
RemoveCellFromUnregisterTokenMap(isolate, head);
*key_map_may_need_shrink = true;
}
return head;
}
void JSFinalizationRegistry::ShrinkKeyMap(
Isolate* isolate,
DirectHandle<JSFinalizationRegistry> finalization_registry) {
if (!IsUndefined(finalization_registry->key_map(), isolate)) {
Handle<SimpleNumberDictionary> key_map =
handle(Cast<SimpleNumberDictionary>(finalization_registry->key_map()),
isolate);
key_map = SimpleNumberDictionary::Shrink(isolate, key_map);
finalization_registry->set_key_map(*key_map);
}
}
Maybe<bool> JSFinalizationRegistry::Cleanup(
Isolate* isolate,
DirectHandle<JSFinalizationRegistry> finalization_registry) {
DirectHandle<Object> callback(finalization_registry->cleanup(), isolate);
bool key_map_may_need_shrink = false;
while (finalization_registry->NeedsCleanup()) {
HandleScope scope(isolate);
DirectHandle<WeakCell> weak_cell(finalization_registry->PopClearedCell(
isolate, &key_map_may_need_shrink),
isolate);
DirectHandle<Object> args[] = {
direct_handle(weak_cell->holdings(), isolate)};
if (Execution::Call(isolate, callback,
isolate->factory()->undefined_value(),
base::VectorOf(args))
.is_null()) {
if (key_map_may_need_shrink) ShrinkKeyMap(isolate, finalization_registry);
return Nothing<bool>();
}
}
if (key_map_may_need_shrink) ShrinkKeyMap(isolate, finalization_registry);
return Just(true);
}
void JSFinalizationRegistry::RemoveCellFromUnregisterTokenMap(
Isolate* isolate, Tagged<WeakCell> weak_cell) {
DisallowGarbageCollection no_gc;
DCHECK(!IsUndefined(weak_cell->unregister_token(), isolate));
Tagged<Undefined> undefined = ReadOnlyRoots(isolate).undefined_value();
if (IsUndefined(weak_cell->key_list_prev(), isolate)) {
Tagged<SimpleNumberDictionary> key_map =
Cast<SimpleNumberDictionary>(this->key_map());
Tagged<HeapObject> unregister_token = weak_cell->unregister_token();
uint32_t key = Smi::ToInt(Object::GetHash(unregister_token));
InternalIndex entry = key_map->FindEntry(isolate, key);
CHECK(entry.is_found());
if (IsUndefined(weak_cell->key_list_next(), isolate)) {
key_map->ClearEntry(entry);
key_map->ElementRemoved();
} else {
Tagged<WeakCell> next = Cast<WeakCell>(weak_cell->key_list_next());
DCHECK_EQ(next->key_list_prev(), weak_cell);
next->set_key_list_prev(undefined, SKIP_WRITE_BARRIER);
key_map->ValueAtPut(entry, next);
}
} else {
Tagged<WeakCell> prev = Cast<WeakCell>(weak_cell->key_list_prev());
prev->set_key_list_next(weak_cell->key_list_next());
if (!IsUndefined(weak_cell->key_list_next())) {
Tagged<WeakCell> next = Cast<WeakCell>(weak_cell->key_list_next());
next->set_key_list_prev(weak_cell->key_list_prev());
}
}
weak_cell->set_unregister_token(undefined, SKIP_WRITE_BARRIER);
weak_cell->set_key_list_prev(undefined, SKIP_WRITE_BARRIER);
weak_cell->set_key_list_next(undefined, SKIP_WRITE_BARRIER);
}
#ifdef OBJECT_PRINT
void WeakCell::WeakCellPrint(std::ostream& os) {
this->PrintHeader(os, "WeakCell");
os << "\n - finalization_registry: " << Brief(this->finalization_registry());
os << "\n - target: " << Brief(this->target());
os << "\n - unregister_token: " << Brief(this->unregister_token());
os << "\n - holdings: " << Brief(this->holdings());
os << "\n - prev: " << Brief(this->prev());
os << "\n - next: " << Brief(this->next());
os << "\n - key_list_prev: " << Brief(this->key_list_prev());
os << "\n - key_list_next: " << Brief(this->key_list_next());
os << '\n';
}
#endif
}
}