tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FinalizationObservers.h (7342B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef gc_FinalizationObservers_h
      8 #define gc_FinalizationObservers_h
      9 
     10 #include "gc/Barrier.h"
     11 #include "gc/WeakMap.h"  // For GetSymbolHash.
     12 #include "gc/ZoneAllocator.h"
     13 #include "js/GCHashTable.h"
     14 #include "js/GCVector.h"
     15 #include "js/Value.h"
     16 #include "vm/NativeObject.h"
     17 
     18 namespace js {
     19 
     20 class FinalizationRegistryObject;
     21 class FinalizationRecordObject;
     22 class FinalizationQueueObject;
     23 class WeakRefObject;
     24 
     25 namespace gc {
     26 
     27 JS::Zone* GetWeakTargetZone(const Value& value);
     28 
     29 // ObserverList
     30 //
     31 // The following classes provide ObserverList, a circular doubly linked list of
     32 // ObserverListObjects with weak, possibly-cross-zone pointers between the
     33 // elements. Despite how bad this sounds this is OK because:
     34 //
     35 //   1) The list is only accessed from the main thread (no races)
     36 //   2) The link pointers are weak (no pre barriers are required on update)
     37 //   3) The elements don't escape
     38 //
     39 // These lists are used to hold the WeakRefObjects and FinalizationRecordObjects
     40 // associated with a WeakRef or FinalizationRegistry target. They live in the
     41 // target's zone although the elements themselves may be in any zone.
     42 
     43 class ObserverListObject;
     44 class ObserverList;
     45 
     46 // Link pointers in a ObserverList. These are encoded as PrivateValues to allow
     47 // storing them in object slots. They contain a tagged pointer to either an
     48 // ObserverListObject or an ObserverList (the list head).
     49 class ObserverListPtr {
     50  Value value;
     51 
     52  enum Kind : uintptr_t { ElementKind = 0, ListHeadKind = 1, KindMask = 1 };
     53 
     54  explicit ObserverListPtr(Value value);
     55  ObserverListPtr(void* ptr, Kind kind);
     56 
     57  Kind kind() const;
     58  void* ptr() const;
     59 
     60  template <typename F>
     61  auto map(F&& func) const;
     62 
     63 public:
     64  MOZ_IMPLICIT ObserverListPtr(ObserverListObject* element);
     65  MOZ_IMPLICIT ObserverListPtr(ObserverList* list);
     66 
     67  static ObserverListPtr fromValue(Value value);
     68 
     69  bool operator==(const ObserverListPtr& other) const {
     70    return value == other.value;
     71  }
     72  bool operator!=(const ObserverListPtr& other) const {
     73    return !(*this == other);
     74  }
     75 
     76  Value asValue() const { return value; }
     77 
     78  bool isElement() const;
     79  ObserverListObject* asElement() const;
     80  ObserverList* asList() const;
     81 
     82  ObserverListPtr getNext() const;
     83  ObserverListPtr getPrev() const;
     84  void setNext(ObserverListPtr next);
     85  void setPrev(ObserverListPtr prev);
     86 };
     87 
     88 // Base class for the elements of an ObserverList.
     89 class ObserverListObject : public NativeObject {
     90  using Ptr = ObserverListPtr;
     91 
     92  Ptr getNext() const;
     93  Ptr getPrev() const;
     94  void setNext(Ptr next);
     95  void setPrev(Ptr prev);
     96  friend class ObserverListPtr;
     97  friend class ObserverList;
     98 
     99  static size_t objectMoved(JSObject* obj, JSObject* old);
    100  void objectMovedFrom(ObserverListObject* old);
    101 
    102 protected:
    103  // These fields are weak and possibly cross-zone pointers. They must not be
    104  // allowed to escape.
    105  enum { NextSlot, PrevSlot, SlotCount };
    106 
    107  static const ClassExtension classExtension_;
    108 
    109 public:
    110  void unlink();
    111  bool isInList() const;
    112 };
    113 
    114 // A circular doubly linked list of ObserverListObjects with weak references
    115 // between them.
    116 class ObserverList {
    117  using Ptr = ObserverListPtr;
    118 
    119  // These fields are weak and possibly cross-zone pointers. They must not be
    120  // allowed to escape.
    121  Ptr next;
    122  Ptr prev;
    123 
    124  Ptr getNext() const { return next; }
    125  Ptr getPrev() const { return prev; }
    126  void setNext(Ptr link);
    127  void setPrev(Ptr link);
    128  friend class ObserverListPtr;
    129 
    130 public:
    131  class Iter;
    132 
    133  ObserverList();
    134  ~ObserverList();
    135 
    136  // The list must be relinked on move.
    137  ObserverList(const ObserverList& other) = delete;
    138  ObserverList& operator=(const ObserverList& other) = delete;
    139  ObserverList(ObserverList&& other);
    140  ObserverList& operator=(ObserverList&& other);
    141 
    142  bool isEmpty() const;
    143  ObserverListObject* getFirst() const;
    144 
    145  Iter iter();
    146 
    147  void insertFront(ObserverListObject* obj);
    148 };
    149 
    150 // A hasher for GC things used as WeakRef and FinalizationRegistry targets. Uses
    151 // stable cell hashing, except for symbols where it uses the symbol's stored
    152 // hash.
    153 struct WeakTargetHasher {
    154  using Key = HeapPtr<Value>;
    155  using Lookup = Value;
    156 
    157  static bool maybeGetHash(const Lookup& l, HashNumber* hashOut) {
    158    if (l.isSymbol()) {
    159      *hashOut = GetSymbolHash(l.toSymbol());
    160      return true;
    161    }
    162    return StableCellHasher<Cell*>::maybeGetHash(l.toGCThing(), hashOut);
    163  }
    164  static bool ensureHash(const Lookup& l, HashNumber* hashOut) {
    165    if (l.isSymbol()) {
    166      *hashOut = GetSymbolHash(l.toSymbol());
    167      return true;
    168    }
    169    return StableCellHasher<Cell*>::ensureHash(l.toGCThing(), hashOut);
    170  }
    171  static HashNumber hash(const Lookup& l) {
    172    if (l.isSymbol()) {
    173      return GetSymbolHash(l.toSymbol());
    174    }
    175    return StableCellHasher<Cell*>::hash(l.toGCThing());
    176  }
    177  static bool match(const Key& k, const Lookup& l) {
    178    if (l.isSymbol()) {
    179      return k.toSymbol() == l.toSymbol();
    180    }
    181    return StableCellHasher<Cell*>::match(k.toGCThing(), l.toGCThing());
    182  }
    183 };
    184 
    185 // Per-zone data structures to support FinalizationRegistry and WeakRef.
    186 class FinalizationObservers {
    187  // The set of all finalization registries in the associated zone.
    188  using RegistrySet =
    189      GCHashSet<HeapPtr<FinalizationRegistryObject*>,
    190                StableCellHasher<HeapPtr<FinalizationRegistryObject*>>,
    191                ZoneAllocPolicy>;
    192  RegistrySet registries;
    193 
    194  // A map from finalization registry targets in the associated zone to a list
    195  // of finalization records representing registries that the target is
    196  // registered with and their associated held values. The records may be in
    197  // other zones. They are direct pointers and are not wrapped.
    198  using RecordMap = GCHashMap<HeapPtr<Value>, ObserverList, WeakTargetHasher,
    199                              ZoneAllocPolicy>;
    200  RecordMap recordMap;
    201 
    202  using WeakRefMap = GCHashMap<HeapPtr<Value>, ObserverList, WeakTargetHasher,
    203                               ZoneAllocPolicy>;
    204  WeakRefMap weakRefMap;
    205 
    206 public:
    207  explicit FinalizationObservers(Zone* zone);
    208  ~FinalizationObservers();
    209 
    210  // FinalizationRegistry support:
    211  bool addRegistry(Handle<FinalizationRegistryObject*> registry);
    212  bool addRecord(HandleValue target, Handle<FinalizationRecordObject*> record);
    213  void clearRecords();
    214 
    215  // WeakRef support:
    216  bool addWeakRefTarget(Handle<Value> target, Handle<WeakRefObject*> weakRef);
    217  void removeWeakRefTarget(Handle<Value> target,
    218                           Handle<WeakRefObject*> weakRef);
    219 
    220  void traceWeakEdges(JSTracer* trc);
    221 
    222 private:
    223  void traceWeakFinalizationRegistryEdges(JSTracer* trc);
    224  void traceWeakWeakRefEdges(JSTracer* trc);
    225  void traceWeakWeakRefList(JSTracer* trc, ObserverList& weakRefs,
    226                            Value target);
    227  bool shouldQueueFinalizationRegistryForCleanup(FinalizationQueueObject*);
    228 };
    229 
    230 }  // namespace gc
    231 }  // namespace js
    232 
    233 namespace mozilla {
    234 template <>
    235 struct FallibleHashMethods<js::gc::WeakTargetHasher>
    236    : public js::gc::WeakTargetHasher {};
    237 }  // namespace mozilla
    238 
    239 #endif  // gc_FinalizationObservers_h