| // 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/objects/js-weak-refs.h" |
| |
| #include "src/api-inl.h" |
| #include "src/heap/heap-write-barrier-inl.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 { |
| |
| ACCESSORS2(JSWeakFactory, native_context, Context, kNativeContextOffset) |
| ACCESSORS(JSWeakFactory, cleanup, Object, kCleanupOffset) |
| ACCESSORS(JSWeakFactory, active_cells, Object, kActiveCellsOffset) |
| ACCESSORS(JSWeakFactory, cleared_cells, Object, kClearedCellsOffset) |
| SMI_ACCESSORS(JSWeakFactory, flags, kFlagsOffset) |
| ACCESSORS(JSWeakFactory, next, Object, kNextOffset) |
| CAST_ACCESSOR(JSWeakFactory) |
| |
| ACCESSORS(JSWeakCell, factory, Object, kFactoryOffset) |
| ACCESSORS(JSWeakCell, target, Object, kTargetOffset) |
| ACCESSORS(JSWeakCell, holdings, Object, kHoldingsOffset) |
| ACCESSORS(JSWeakCell, next, Object, kNextOffset) |
| ACCESSORS(JSWeakCell, prev, Object, kPrevOffset) |
| CAST_ACCESSOR(JSWeakCell) |
| |
| CAST_ACCESSOR(JSWeakRef) |
| |
| ACCESSORS(JSWeakFactoryCleanupIterator, factory, JSWeakFactory, kFactoryOffset) |
| CAST_ACCESSOR(JSWeakFactoryCleanupIterator) |
| |
| ACCESSORS(WeakFactoryCleanupJobTask, factory, JSWeakFactory, kFactoryOffset) |
| CAST_ACCESSOR(WeakFactoryCleanupJobTask) |
| |
| void JSWeakFactory::AddWeakCell(JSWeakCell* weak_cell) { |
| weak_cell->set_factory(this); |
| weak_cell->set_next(active_cells()); |
| if (active_cells()->IsJSWeakCell()) { |
| JSWeakCell::cast(active_cells())->set_prev(weak_cell); |
| } |
| set_active_cells(weak_cell); |
| } |
| |
| bool JSWeakFactory::NeedsCleanup() const { |
| return cleared_cells()->IsJSWeakCell(); |
| } |
| |
| bool JSWeakFactory::scheduled_for_cleanup() const { |
| return ScheduledForCleanupField::decode(flags()); |
| } |
| |
| void JSWeakFactory::set_scheduled_for_cleanup(bool scheduled_for_cleanup) { |
| set_flags(ScheduledForCleanupField::update(flags(), scheduled_for_cleanup)); |
| } |
| |
| JSWeakCell* JSWeakFactory::PopClearedCell(Isolate* isolate) { |
| JSWeakCell* weak_cell = JSWeakCell::cast(cleared_cells()); |
| DCHECK(weak_cell->prev()->IsUndefined(isolate)); |
| set_cleared_cells(weak_cell->next()); |
| weak_cell->set_next(ReadOnlyRoots(isolate).undefined_value()); |
| |
| if (cleared_cells()->IsJSWeakCell()) { |
| JSWeakCell* cleared_cells_head = JSWeakCell::cast(cleared_cells()); |
| DCHECK_EQ(cleared_cells_head->prev(), weak_cell); |
| cleared_cells_head->set_prev(ReadOnlyRoots(isolate).undefined_value()); |
| } else { |
| DCHECK(cleared_cells()->IsUndefined(isolate)); |
| } |
| return weak_cell; |
| } |
| |
| void JSWeakCell::Nullify( |
| Isolate* isolate, |
| std::function<void(HeapObject* object, ObjectSlot slot, Object* target)> |
| gc_notify_updated_slot) { |
| DCHECK(target()->IsJSReceiver()); |
| set_target(ReadOnlyRoots(isolate).undefined_value()); |
| |
| JSWeakFactory* weak_factory = JSWeakFactory::cast(factory()); |
| // Remove from the JSWeakCell from the "active_cells" list of its |
| // JSWeakFactory and insert it into the "cleared" list. |
| if (prev()->IsJSWeakCell()) { |
| DCHECK_NE(weak_factory->active_cells(), this); |
| JSWeakCell* prev_cell = JSWeakCell::cast(prev()); |
| prev_cell->set_next(next()); |
| gc_notify_updated_slot( |
| prev_cell, HeapObject::RawField(prev_cell, JSWeakCell::kNextOffset), |
| next()); |
| } else { |
| DCHECK_EQ(weak_factory->active_cells(), this); |
| weak_factory->set_active_cells(next()); |
| gc_notify_updated_slot( |
| weak_factory, |
| HeapObject::RawField(weak_factory, JSWeakFactory::kActiveCellsOffset), |
| next()); |
| } |
| if (next()->IsJSWeakCell()) { |
| JSWeakCell* next_cell = JSWeakCell::cast(next()); |
| next_cell->set_prev(prev()); |
| gc_notify_updated_slot( |
| next_cell, HeapObject::RawField(next_cell, JSWeakCell::kPrevOffset), |
| prev()); |
| } |
| |
| set_prev(ReadOnlyRoots(isolate).undefined_value()); |
| Object* cleared_head = weak_factory->cleared_cells(); |
| if (cleared_head->IsJSWeakCell()) { |
| JSWeakCell* cleared_head_cell = JSWeakCell::cast(cleared_head); |
| cleared_head_cell->set_prev(this); |
| gc_notify_updated_slot( |
| cleared_head_cell, |
| HeapObject::RawField(cleared_head_cell, JSWeakCell::kPrevOffset), this); |
| } |
| set_next(weak_factory->cleared_cells()); |
| gc_notify_updated_slot( |
| this, HeapObject::RawField(this, JSWeakCell::kNextOffset), next()); |
| weak_factory->set_cleared_cells(this); |
| gc_notify_updated_slot( |
| weak_factory, |
| HeapObject::RawField(weak_factory, JSWeakFactory::kClearedCellsOffset), |
| this); |
| } |
| |
| void JSWeakCell::Clear(Isolate* isolate) { |
| // Unlink the JSWeakCell from the list it's in (if any). The JSWeakCell can be |
| // in its JSWeakFactory's active_cells list, cleared_cells list or neither (if |
| // it has been already taken out). |
| |
| DCHECK(target()->IsUndefined() || target()->IsJSReceiver()); |
| set_target(ReadOnlyRoots(isolate).undefined_value()); |
| |
| if (factory()->IsJSWeakFactory()) { |
| JSWeakFactory* weak_factory = JSWeakFactory::cast(factory()); |
| if (weak_factory->active_cells() == this) { |
| DCHECK(!prev()->IsJSWeakCell()); |
| weak_factory->set_active_cells(next()); |
| } else if (weak_factory->cleared_cells() == this) { |
| DCHECK(!prev()->IsJSWeakCell()); |
| weak_factory->set_cleared_cells(next()); |
| } else if (prev()->IsJSWeakCell()) { |
| JSWeakCell* prev_cell = JSWeakCell::cast(prev()); |
| prev_cell->set_next(next()); |
| } |
| if (next()->IsJSWeakCell()) { |
| JSWeakCell* next_cell = JSWeakCell::cast(next()); |
| next_cell->set_prev(prev()); |
| } |
| set_prev(ReadOnlyRoots(isolate).undefined_value()); |
| set_next(ReadOnlyRoots(isolate).undefined_value()); |
| |
| set_holdings(ReadOnlyRoots(isolate).undefined_value()); |
| set_factory(ReadOnlyRoots(isolate).undefined_value()); |
| } else { |
| // Already cleared. |
| DCHECK(next()->IsUndefined(isolate)); |
| DCHECK(prev()->IsUndefined(isolate)); |
| DCHECK(holdings()->IsUndefined(isolate)); |
| DCHECK(factory()->IsUndefined(isolate)); |
| } |
| } |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #include "src/objects/object-macros-undef.h" |
| |
| #endif // V8_OBJECTS_JS_WEAK_REFS_INL_H_ |