/src/mozilla-central/js/src/gc/WeakMap.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=8 sts=4 et sw=4 tw=99: |
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_WeakMap_h |
8 | | #define gc_WeakMap_h |
9 | | |
10 | | #include "mozilla/LinkedList.h" |
11 | | |
12 | | #include "gc/Barrier.h" |
13 | | #include "gc/DeletePolicy.h" |
14 | | #include "gc/Zone.h" |
15 | | #include "js/HashTable.h" |
16 | | |
17 | | namespace JS { |
18 | | class Zone; |
19 | | } // namespace JS |
20 | | |
21 | | namespace js { |
22 | | |
23 | | class GCMarker; |
24 | | class WeakMapBase; |
25 | | struct WeakMapTracer; |
26 | | |
27 | | namespace gc { |
28 | | struct WeakMarkable; |
29 | | } // namespace gc |
30 | | |
31 | | // A subclass template of js::HashMap whose keys and values may be garbage-collected. When |
32 | | // a key is collected, the table entry disappears, dropping its reference to the value. |
33 | | // |
34 | | // More precisely: |
35 | | // |
36 | | // A WeakMap entry is live if and only if both the WeakMap and the entry's key |
37 | | // are live. An entry holds a strong reference to its value. |
38 | | // |
39 | | // You must call this table's 'trace' method when its owning object is reached |
40 | | // by the garbage collection tracer. Once a table is known to be live, the |
41 | | // implementation takes care of the special weak marking (ie, marking through |
42 | | // the implicit edges stored in the map) and of removing (sweeping) table |
43 | | // entries when collection is complete. |
44 | | |
45 | | typedef HashSet<WeakMapBase*, DefaultHasher<WeakMapBase*>, SystemAllocPolicy> WeakMapSet; |
46 | | |
47 | | // Common base class for all WeakMap specializations, used for calling |
48 | | // subclasses' GC-related methods. |
49 | | class WeakMapBase : public mozilla::LinkedListElement<WeakMapBase> |
50 | | { |
51 | | friend class js::GCMarker; |
52 | | |
53 | | public: |
54 | | WeakMapBase(JSObject* memOf, JS::Zone* zone); |
55 | | virtual ~WeakMapBase(); |
56 | | |
57 | 1 | JS::Zone* zone() const { return zone_; } |
58 | | |
59 | | // Garbage collector entry points. |
60 | | |
61 | | // Unmark all weak maps in a zone. |
62 | | static void unmarkZone(JS::Zone* zone); |
63 | | |
64 | | // Mark all the weakmaps in a zone. |
65 | | static void traceZone(JS::Zone* zone, JSTracer* tracer); |
66 | | |
67 | | // Check all weak maps in a zone that have been marked as live in this garbage |
68 | | // collection, and mark the values of all entries that have become strong references |
69 | | // to them. Return true if we marked any new values, indicating that we need to make |
70 | | // another pass. In other words, mark my marked maps' marked members' mid-collection. |
71 | | static bool markZoneIteratively(JS::Zone* zone, GCMarker* marker); |
72 | | |
73 | | // Add zone edges for weakmaps with key delegates in a different zone. |
74 | | static bool findInterZoneEdges(JS::Zone* zone); |
75 | | |
76 | | // Sweep the weak maps in a zone, removing dead weak maps and removing |
77 | | // entries of live weak maps whose keys are dead. |
78 | | static void sweepZone(JS::Zone* zone); |
79 | | |
80 | | // Trace all delayed weak map bindings. Used by the cycle collector. |
81 | | static void traceAllMappings(WeakMapTracer* tracer); |
82 | | |
83 | | // Save information about which weak maps are marked for a zone. |
84 | | static bool saveZoneMarkedWeakMaps(JS::Zone* zone, WeakMapSet& markedWeakMaps); |
85 | | |
86 | | // Restore information about which weak maps are marked for many zones. |
87 | | static void restoreMarkedWeakMaps(WeakMapSet& markedWeakMaps); |
88 | | |
89 | | protected: |
90 | | // Instance member functions called by the above. Instantiations of WeakMap override |
91 | | // these with definitions appropriate for their Key and Value types. |
92 | | virtual void trace(JSTracer* tracer) = 0; |
93 | | virtual bool findZoneEdges() = 0; |
94 | | virtual void sweep() = 0; |
95 | | virtual void traceMappings(WeakMapTracer* tracer) = 0; |
96 | | virtual void clearAndCompact() = 0; |
97 | | |
98 | | // Any weakmap key types that want to participate in the non-iterative |
99 | | // ephemeron marking must override this method. |
100 | | virtual void markEntry(GCMarker* marker, gc::Cell* markedCell, JS::GCCellPtr l) = 0; |
101 | | |
102 | | virtual bool markIteratively(GCMarker* marker) = 0; |
103 | | |
104 | | protected: |
105 | | // Object that this weak map is part of, if any. |
106 | | GCPtrObject memberOf; |
107 | | |
108 | | // Zone containing this weak map. |
109 | | JS::Zone* zone_; |
110 | | |
111 | | // Whether this object has been traced during garbage collection. |
112 | | bool marked; |
113 | | }; |
114 | | |
115 | | template <class Key, class Value> |
116 | | class WeakMap : public HashMap<Key, Value, MovableCellHasher<Key>, ZoneAllocPolicy>, |
117 | | public WeakMapBase |
118 | | { |
119 | | public: |
120 | | typedef HashMap<Key, Value, MovableCellHasher<Key>, ZoneAllocPolicy> Base; |
121 | | typedef typename Base::Enum Enum; |
122 | | typedef typename Base::Lookup Lookup; |
123 | | typedef typename Base::Entry Entry; |
124 | | typedef typename Base::Range Range; |
125 | | typedef typename Base::Ptr Ptr; |
126 | | typedef typename Base::AddPtr AddPtr; |
127 | | |
128 | | explicit WeakMap(JSContext* cx, JSObject* memOf = nullptr); |
129 | | |
130 | | // Overwritten to add a read barrier to prevent an incorrectly gray value |
131 | | // from escaping the weak map. See the UnmarkGrayTracer::onChild comment in |
132 | | // gc/Marking.cpp. |
133 | 28 | Ptr lookup(const Lookup& l) const { |
134 | 28 | Ptr p = Base::lookup(l); |
135 | 28 | if (p) { |
136 | 23 | exposeGCThingToActiveJS(p->value()); |
137 | 23 | } |
138 | 28 | return p; |
139 | 28 | } js::WeakMap<js::HeapPtr<JSObject*>, js::HeapPtr<JS::Value> >::lookup(JSObject* const&) const Line | Count | Source | 133 | 28 | Ptr lookup(const Lookup& l) const { | 134 | 28 | Ptr p = Base::lookup(l); | 135 | 28 | if (p) { | 136 | 23 | exposeGCThingToActiveJS(p->value()); | 137 | 23 | } | 138 | 28 | return p; | 139 | 28 | } |
Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSObject*>, js::HeapPtr<JSObject*> >::lookup(JSObject* const&) const |
140 | | |
141 | 0 | AddPtr lookupForAdd(const Lookup& l) { |
142 | 0 | AddPtr p = Base::lookupForAdd(l); |
143 | 0 | if (p) { |
144 | 0 | exposeGCThingToActiveJS(p->value()); |
145 | 0 | } |
146 | 0 | return p; |
147 | 0 | } Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSObject*>, js::HeapPtr<JSObject*> >::lookupForAdd(JSObject* const&) Unexecuted instantiation: js::WeakMap<js::HeapPtr<js::LazyScript*>, js::HeapPtr<JSObject*> >::lookupForAdd(js::LazyScript* const&) Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSScript*>, js::HeapPtr<JSObject*> >::lookupForAdd(JSScript* const&) Unexecuted instantiation: js::WeakMap<js::HeapPtr<js::WasmInstanceObject*>, js::HeapPtr<JSObject*> >::lookupForAdd(js::WasmInstanceObject* const&) |
148 | | |
149 | | // Resolve ambiguity with LinkedListElement<>::remove. |
150 | | using Base::remove; |
151 | | |
152 | | void markEntry(GCMarker* marker, gc::Cell* markedCell, JS::GCCellPtr origKey) override; |
153 | | |
154 | | void trace(JSTracer* trc) override; |
155 | | |
156 | | protected: |
157 | | static void addWeakEntry(GCMarker* marker, JS::GCCellPtr key, |
158 | | const gc::WeakMarkable& markable); |
159 | | |
160 | | bool markIteratively(GCMarker* marker) override; |
161 | | |
162 | | JSObject* getDelegate(JSObject* key) const; |
163 | | JSObject* getDelegate(JSScript* script) const; |
164 | | JSObject* getDelegate(LazyScript* script) const; |
165 | | |
166 | | private: |
167 | 23 | void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); } |
168 | 0 | void exposeGCThingToActiveJS(JSObject* obj) const { JS::ExposeObjectToActiveJS(obj); } Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSObject*>, js::HeapPtr<JSObject*> >::exposeGCThingToActiveJS(JSObject*) const Unexecuted instantiation: js::WeakMap<js::HeapPtr<js::LazyScript*>, js::HeapPtr<JSObject*> >::exposeGCThingToActiveJS(JSObject*) const Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSScript*>, js::HeapPtr<JSObject*> >::exposeGCThingToActiveJS(JSObject*) const Unexecuted instantiation: js::WeakMap<js::HeapPtr<js::WasmInstanceObject*>, js::HeapPtr<JSObject*> >::exposeGCThingToActiveJS(JSObject*) const |
169 | | |
170 | | bool keyNeedsMark(JSObject* key) const; |
171 | | bool keyNeedsMark(JSScript* script) const; |
172 | | bool keyNeedsMark(LazyScript* script) const; |
173 | | |
174 | 0 | bool findZoneEdges() override { |
175 | 0 | // This is overridden by ObjectValueMap. |
176 | 0 | return true; |
177 | 0 | } Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSObject*>, js::HeapPtr<JS::Value> >::findZoneEdges() Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSObject*>, js::HeapPtr<JSObject*> >::findZoneEdges() Unexecuted instantiation: js::WeakMap<js::HeapPtr<js::WasmInstanceObject*>, js::HeapPtr<JSObject*> >::findZoneEdges() Unexecuted instantiation: js::WeakMap<js::HeapPtr<js::LazyScript*>, js::HeapPtr<JSObject*> >::findZoneEdges() Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSScript*>, js::HeapPtr<JSObject*> >::findZoneEdges() |
178 | | |
179 | | void sweep() override; |
180 | | |
181 | 0 | void clearAndCompact() override { |
182 | 0 | Base::clear(); |
183 | 0 | Base::compact(); |
184 | 0 | } Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSObject*>, js::HeapPtr<JS::Value> >::clearAndCompact() Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSObject*>, js::HeapPtr<JSObject*> >::clearAndCompact() Unexecuted instantiation: js::WeakMap<js::HeapPtr<js::WasmInstanceObject*>, js::HeapPtr<JSObject*> >::clearAndCompact() Unexecuted instantiation: js::WeakMap<js::HeapPtr<js::LazyScript*>, js::HeapPtr<JSObject*> >::clearAndCompact() Unexecuted instantiation: js::WeakMap<js::HeapPtr<JSScript*>, js::HeapPtr<JSObject*> >::clearAndCompact() |
185 | | |
186 | | /* memberOf can be nullptr, which means that the map is not part of a JSObject. */ |
187 | | void traceMappings(WeakMapTracer* tracer) override; |
188 | | |
189 | | protected: |
190 | | #if DEBUG |
191 | | void assertEntriesNotAboutToBeFinalized(); |
192 | | #endif |
193 | | }; |
194 | | |
195 | | |
196 | | class ObjectValueMap : public WeakMap<HeapPtr<JSObject*>, HeapPtr<Value>> |
197 | | { |
198 | | public: |
199 | | ObjectValueMap(JSContext* cx, JSObject* obj) |
200 | | : WeakMap(cx, obj) |
201 | 1 | {} |
202 | | |
203 | | bool findZoneEdges() override; |
204 | | }; |
205 | | |
206 | | |
207 | | // Generic weak map for mapping objects to other objects. |
208 | | class ObjectWeakMap |
209 | | { |
210 | | ObjectValueMap map; |
211 | | |
212 | | public: |
213 | | explicit ObjectWeakMap(JSContext* cx); |
214 | | |
215 | 0 | JS::Zone* zone() const { return map.zone(); } |
216 | | |
217 | | JSObject* lookup(const JSObject* obj); |
218 | | bool add(JSContext* cx, JSObject* obj, JSObject* target); |
219 | | void clear(); |
220 | | |
221 | | void trace(JSTracer* trc); |
222 | | size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); |
223 | 0 | size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) { |
224 | 0 | return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf); |
225 | 0 | } |
226 | | |
227 | | #ifdef JSGC_HASH_TABLE_CHECKS |
228 | | void checkAfterMovingGC(); |
229 | | #endif |
230 | | }; |
231 | | |
232 | | } /* namespace js */ |
233 | | |
234 | | namespace JS { |
235 | | |
236 | | template <> |
237 | | struct DeletePolicy<js::ObjectValueMap> : public js::GCManagedDeletePolicy<js::ObjectValueMap> |
238 | | {}; |
239 | | |
240 | | } /* namespace JS */ |
241 | | |
242 | | #endif /* gc_WeakMap_h */ |