| // 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_H_ |
| #define V8_OBJECTS_JS_WEAK_REFS_H_ |
| |
| #include "src/base/bit-field.h" |
| #include "src/objects/js-objects.h" |
| #include "src/objects/tagged-field.h" |
| #include "src/objects/union.h" |
| |
| // Has to be the last include (doesn't have include guards): |
| #include "src/objects/object-macros.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| class NativeContext; |
| class WeakCell; |
| |
| // FinalizationRegistry object from the JS Weak Refs spec proposal: |
| // https://github.com/tc39/proposal-weakrefs |
| V8_OBJECT class JSFinalizationRegistry : public JSObject { |
| public: |
| inline Tagged<NativeContext> native_context() const; |
| inline void set_native_context(Tagged<NativeContext> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<JSReceiver> cleanup() const; |
| inline void set_cleanup(Tagged<JSReceiver> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<WeakCell, Undefined>> active_cells() const; |
| inline void set_active_cells(Tagged<UnionOf<WeakCell, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<WeakCell, Undefined>> cleared_cells() const; |
| inline void set_cleared_cells(Tagged<UnionOf<WeakCell, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<Object> key_map() const; |
| inline void set_key_map(Tagged<Object> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<JSFinalizationRegistry, Undefined>> next_dirty() const; |
| inline void set_next_dirty( |
| Tagged<UnionOf<JSFinalizationRegistry, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline int flags() const; |
| inline void set_flags(int value); |
| |
| DECL_PRINTER(JSFinalizationRegistry) |
| EXPORT_DECL_VERIFIER(JSFinalizationRegistry) |
| |
| DECL_BOOLEAN_ACCESSORS(scheduled_for_cleanup) |
| |
| class BodyDescriptor; |
| |
| inline static void RegisterWeakCellWithUnregisterToken( |
| DirectHandle<JSFinalizationRegistry> finalization_registry, |
| DirectHandle<WeakCell> weak_cell, Isolate* isolate); |
| inline static bool Unregister( |
| DirectHandle<JSFinalizationRegistry> finalization_registry, |
| DirectHandle<HeapObject> unregister_token, Isolate* isolate); |
| |
| // RemoveUnregisterToken is called from both Unregister and during GC. Since |
| // it modifies slots in key_map and WeakCells and the normal write barrier is |
| // disabled during GC, we need to tell the GC about the modified slots via the |
| // gc_notify_updated_slot function. |
| enum RemoveUnregisterTokenMode { |
| kRemoveMatchedCellsFromRegistry, |
| kKeepMatchedCellsInRegistry |
| }; |
| template <typename GCNotifyUpdatedSlotCallback> |
| inline bool RemoveUnregisterToken( |
| Tagged<HeapObject> unregister_token, Isolate* isolate, |
| RemoveUnregisterTokenMode removal_mode, |
| GCNotifyUpdatedSlotCallback gc_notify_updated_slot, |
| WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER); |
| |
| // Returns true if the cleared_cells list is non-empty. |
| inline bool NeedsCleanup() const; |
| |
| V8_EXPORT_PRIVATE Tagged<WeakCell> PopClearedCell( |
| Isolate* isolate, bool* key_map_may_need_shrink); |
| |
| static void ShrinkKeyMap( |
| Isolate* isolate, |
| DirectHandle<JSFinalizationRegistry> finalization_registry); |
| |
| // Pop cleared cells and call their finalizers. |
| static Maybe<bool> Cleanup( |
| Isolate* isolate, |
| DirectHandle<JSFinalizationRegistry> finalization_registry); |
| |
| // Remove the already-popped weak_cell from its unregister token linked list, |
| // as well as removing the entry from the key map if it is the only WeakCell |
| // with its unregister token. This method cannot GC and does not shrink the |
| // key map. Asserts that weak_cell has a non-undefined unregister token. |
| V8_EXPORT_PRIVATE void RemoveCellFromUnregisterTokenMap( |
| Isolate* isolate, Tagged<WeakCell> weak_cell); |
| |
| // Bitfields in flags. |
| using ScheduledForCleanupBit = base::BitField<bool, 0, 1, uint32_t>; |
| enum Flag : uint32_t { |
| kNone = 0, |
| kScheduledForCleanup = ScheduledForCleanupBit::kMask, |
| }; |
| using Flags = base::Flags<Flag>; |
| static constexpr int kFlagCount = 1; |
| |
| static const int kHeaderSize; |
| |
| public: |
| TaggedMember<NativeContext> native_context_; |
| TaggedMember<JSReceiver> cleanup_; |
| TaggedMember<UnionOf<WeakCell, Undefined>> active_cells_; |
| TaggedMember<UnionOf<WeakCell, Undefined>> cleared_cells_; |
| TaggedMember<Object> key_map_; |
| TaggedMember<UnionOf<JSFinalizationRegistry, Undefined>> next_dirty_; |
| TaggedMember<Smi> flags_; |
| |
| friend class Heap; |
| friend class TorqueGeneratedJSFinalizationRegistryAsserts; |
| } V8_OBJECT_END; |
| |
| inline constexpr int JSFinalizationRegistry::kHeaderSize = |
| sizeof(JSFinalizationRegistry); |
| |
| // Internal object for storing weak references in JSFinalizationRegistry. |
| V8_OBJECT class WeakCell : public HeapObject { |
| public: |
| inline Tagged<JSFinalizationRegistry> finalization_registry() const; |
| inline void set_finalization_registry( |
| Tagged<JSFinalizationRegistry> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<JSAny> holdings() const; |
| inline void set_holdings(Tagged<JSAny> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<Symbol, JSReceiver, Undefined>> target() const; |
| |
| inline Tagged<UnionOf<Symbol, JSReceiver, Undefined>> unregister_token() |
| const; |
| |
| inline Tagged<UnionOf<WeakCell, Undefined>> prev() const; |
| inline void set_prev(Tagged<UnionOf<WeakCell, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<WeakCell, Undefined>> next() const; |
| inline void set_next(Tagged<UnionOf<WeakCell, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<WeakCell, Undefined>> key_list_prev() const; |
| inline void set_key_list_prev(Tagged<UnionOf<WeakCell, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<WeakCell, Undefined>> key_list_next() const; |
| inline void set_key_list_next(Tagged<UnionOf<WeakCell, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| EXPORT_DECL_VERIFIER(WeakCell) |
| |
| DECL_PRINTER(WeakCell) |
| |
| class BodyDescriptor; |
| |
| // Provide relaxed load access to target field. |
| inline Tagged<HeapObject> relaxed_target() const; |
| |
| // Provide relaxed load access to the unregister token field. |
| inline Tagged<HeapObject> relaxed_unregister_token() const; |
| |
| // Nullify is called during GC and it modifies the pointers in WeakCell and |
| // JSFinalizationRegistry. Thus we need to tell the GC about the modified |
| // slots via the gc_notify_updated_slot function. The normal write barrier is |
| // not enough, since it's disabled before GC. |
| template <typename GCNotifyUpdatedSlotCallback> |
| inline void Nullify(Isolate* isolate, |
| GCNotifyUpdatedSlotCallback gc_notify_updated_slot); |
| |
| inline void RemoveFromFinalizationRegistryCells(Isolate* isolate); |
| |
| private: |
| inline void set_target(Tagged<UnionOf<Symbol, JSReceiver, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| inline void set_unregister_token( |
| Tagged<UnionOf<Symbol, JSReceiver, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| TaggedMember<JSFinalizationRegistry> finalization_registry_; |
| TaggedMember<JSAny> holdings_; |
| TaggedMember<UnionOf<Symbol, JSReceiver, Undefined>> target_; |
| TaggedMember<UnionOf<Symbol, JSReceiver, Undefined>> unregister_token_; |
| TaggedMember<UnionOf<WeakCell, Undefined>> prev_; |
| TaggedMember<UnionOf<WeakCell, Undefined>> next_; |
| TaggedMember<UnionOf<WeakCell, Undefined>> key_list_prev_; |
| TaggedMember<UnionOf<WeakCell, Undefined>> key_list_next_; |
| |
| friend class JSFinalizationRegistry; |
| friend class MarkCompactCollector; |
| template <typename ConcreteVisitor> |
| friend class MarkingVisitorBase; |
| // `Scavenger and `ScavengerCollector` for accessing `set_target` and |
| // `set_unregister_token` for updating references during GC. |
| friend class Scavenger; |
| friend class ScavengerWeakObjectsProcessor; |
| friend class TorqueGeneratedWeakCellAsserts; |
| friend class V8HeapExplorer; |
| } V8_OBJECT_END; |
| |
| V8_OBJECT class JSWeakRef : public JSObject { |
| public: |
| inline Tagged<UnionOf<Symbol, JSReceiver, Undefined>> target() const; |
| inline void set_target(Tagged<UnionOf<Symbol, JSReceiver, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| DECL_PRINTER(JSWeakRef) |
| EXPORT_DECL_VERIFIER(JSWeakRef) |
| |
| class BodyDescriptor; |
| |
| public: |
| TaggedMember<UnionOf<Symbol, JSReceiver, Undefined>> target_; |
| } V8_OBJECT_END; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #include "src/objects/object-macros-undef.h" |
| |
| #endif // V8_OBJECTS_JS_WEAK_REFS_H_ |