Coverage Report

Created: 2018-09-25 14:53

/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 */