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"
12 #include "gc/ZoneAllocator.h"
13 #include "js/GCHashTable.h"
14 #include "js/GCVector.h"
15 
16 namespace js {
17 
18 class FinalizationRegistryObject;
19 class FinalizationRecordObject;
20 class WeakRefObject;
21 
22 namespace gc {
23 
24 // Per-zone data structures to support FinalizationRegistry and WeakRef.
25 class FinalizationObservers {
26   Zone* const zone;
27 
28   // The set of all finalization registries in the associated zone. These are
29   // direct pointers and are not wrapped.
30   using RegistrySet = GCHashSet<HeapPtrObject, MovableCellHasher<HeapPtrObject>,
31                                 ZoneAllocPolicy>;
32   RegistrySet registries;
33 
34   // A vector of FinalizationRecord objects, or CCWs to them.
35   using RecordVector = GCVector<HeapPtrObject, 1, ZoneAllocPolicy>;
36 
37   // A map from finalization registry targets to a vector of finalization
38   // records representing registries that the target is registered with and
39   // their associated held values. The records may be in other zones and are
40   // wrapped appropriately.
41   using RecordMap =
42       GCHashMap<HeapPtrObject, RecordVector, MovableCellHasher<HeapPtrObject>,
43                 ZoneAllocPolicy>;
44   RecordMap recordMap;
45 
46   // A weak map used as a set of cross-zone wrappers. This is used for both
47   // finalization registries and weak refs. For the former it has wrappers to
48   // finalization record objects and for the latter wrappers to weak refs.
49   //
50   // The weak map marking rules keep the wrappers alive while their targets are
51   // alive and ensure that they are both swept in the same sweep group.
52   using WrapperWeakSet = ObjectValueWeakMap;
53   WrapperWeakSet crossZoneRecords;
54 
55   // A map of weak ref targets to a vector of weak refs that are observing the
56   // target. The weak refs may be in other zones and are wrapped appropriately.
57   using WeakRefHeapPtrVector =
58       GCVector<js::HeapPtrObject, 1, js::ZoneAllocPolicy>;
59   using WeakRefMap =
60       GCHashMap<HeapPtrObject, WeakRefHeapPtrVector,
61                 MovableCellHasher<HeapPtrObject>, ZoneAllocPolicy>;
62   WeakRefMap weakRefMap;
63 
64   // A weak map used as a set of cross-zone weak refs wrappers.
65   WrapperWeakSet crossZoneWeakRefs;
66 
67  public:
68   explicit FinalizationObservers(Zone* zone);
69   ~FinalizationObservers();
70 
71   // FinalizationRegistry support:
72   bool addRegistry(Handle<FinalizationRegistryObject*> registry);
73   bool addRecord(HandleObject target, HandleObject record);
74   void clearRecords();
75 
76   void updateForRemovedRecord(JSObject* wrapper,
77                               FinalizationRecordObject* record);
78 
79   // WeakRef support:
80   bool addWeakRefTarget(HandleObject target, HandleObject weakRef);
81 
82   void unregisterWeakRefWrapper(JSObject* wrapper, WeakRefObject* weakRef);
83 
84   void traceRoots(JSTracer* trc);
85   void traceWeakEdges(JSTracer* trc);
86 
87 #ifdef DEBUG
88   void checkTables() const;
89 #endif
90 
91  private:
92   bool addCrossZoneWrapper(WrapperWeakSet& weakSet, JSObject* wrapper);
93   void removeCrossZoneWrapper(WrapperWeakSet& weakSet, JSObject* wrapper);
94 
95   void updateForRemovedWeakRef(JSObject* wrapper, WeakRefObject* weakRef);
96 
97   void traceWeakFinalizationRegistryEdges(JSTracer* trc);
98   void traceWeakWeakRefEdges(JSTracer* trc);
99   void traceWeakWeakRefVector(JSTracer* trc, WeakRefHeapPtrVector& weakRefs,
100                               JSObject* target);
101 
102   static bool shouldRemoveRecord(FinalizationRecordObject* record);
103 };
104 
105 // Per-global data structures to support FinalizationRegistry.
106 class FinalizationRegistryGlobalData {
107   // Set of finalization records for finalization registries in this
108   // realm. These are traced as part of the realm's global.
109   using RecordSet = GCHashSet<HeapPtrObject, MovableCellHasher<HeapPtrObject>,
110                               ZoneAllocPolicy>;
111   RecordSet recordSet;
112 
113  public:
114   explicit FinalizationRegistryGlobalData(Zone* zone);
115 
116   bool addRecord(FinalizationRecordObject* record);
117   void removeRecord(FinalizationRecordObject* record);
118 
119   void trace(JSTracer* trc);
120 };
121 
122 }  // namespace gc
123 }  // namespace js
124 
125 #endif  // gc_FinalizationObservers_h
126