current commit
261004.7 · deps: update V8 to 15.2.124.38
// 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_