Line data Source code
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 : #include "jsweakmap.h"
8 :
9 : #include <string.h>
10 :
11 : #include "jsapi.h"
12 : #include "jscntxt.h"
13 : #include "jsfriendapi.h"
14 : #include "jsobj.h"
15 : #include "jswrapper.h"
16 :
17 : #include "js/GCAPI.h"
18 : #include "vm/GlobalObject.h"
19 :
20 : #include "jsobjinlines.h"
21 :
22 : using namespace js;
23 : using namespace js::gc;
24 :
25 20 : WeakMapBase::WeakMapBase(JSObject* memOf, Zone* zone)
26 : : memberOf(memOf),
27 : zone_(zone),
28 20 : marked(false)
29 : {
30 20 : MOZ_ASSERT_IF(memberOf, memberOf->compartment()->zone() == zone);
31 20 : }
32 :
33 0 : WeakMapBase::~WeakMapBase()
34 : {
35 0 : MOZ_ASSERT(CurrentThreadIsGCSweeping() || CurrentThreadCanAccessZone(zone_));
36 0 : }
37 :
38 : void
39 16 : WeakMapBase::unmarkZone(JS::Zone* zone)
40 : {
41 32 : for (WeakMapBase* m : zone->gcWeakMapList())
42 16 : m->marked = false;
43 16 : }
44 :
45 : void
46 0 : WeakMapBase::traceZone(JS::Zone* zone, JSTracer* tracer)
47 : {
48 0 : MOZ_ASSERT(tracer->weakMapAction() != DoNotTraceWeakMaps);
49 0 : for (WeakMapBase* m : zone->gcWeakMapList()) {
50 0 : m->trace(tracer);
51 0 : TraceNullableEdge(tracer, &m->memberOf, "memberOf");
52 : }
53 0 : }
54 :
55 : bool
56 0 : WeakMapBase::markZoneIteratively(JS::Zone* zone, GCMarker* marker)
57 : {
58 0 : bool markedAny = false;
59 0 : for (WeakMapBase* m : zone->gcWeakMapList()) {
60 0 : if (m->marked && m->markIteratively(marker))
61 0 : markedAny = true;
62 : }
63 0 : return markedAny;
64 : }
65 :
66 : bool
67 0 : WeakMapBase::findInterZoneEdges(JS::Zone* zone)
68 : {
69 0 : for (WeakMapBase* m : zone->gcWeakMapList()) {
70 0 : if (!m->findZoneEdges())
71 0 : return false;
72 : }
73 0 : return true;
74 : }
75 :
76 : void
77 0 : WeakMapBase::sweepZone(JS::Zone* zone)
78 : {
79 0 : for (WeakMapBase* m = zone->gcWeakMapList().getFirst(); m; ) {
80 0 : WeakMapBase* next = m->getNext();
81 0 : if (m->marked) {
82 0 : m->sweep();
83 : } else {
84 : /* Destroy the hash map now to catch any use after this point. */
85 0 : m->finish();
86 0 : m->removeFrom(zone->gcWeakMapList());
87 : }
88 0 : m = next;
89 : }
90 :
91 : #ifdef DEBUG
92 0 : for (WeakMapBase* m : zone->gcWeakMapList())
93 0 : MOZ_ASSERT(m->isInList() && m->marked);
94 : #endif
95 0 : }
96 :
97 : void
98 0 : WeakMapBase::traceAllMappings(WeakMapTracer* tracer)
99 : {
100 0 : JSRuntime* rt = tracer->runtime;
101 0 : for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
102 0 : for (WeakMapBase* m : zone->gcWeakMapList()) {
103 : // The WeakMapTracer callback is not allowed to GC.
104 0 : JS::AutoSuppressGCAnalysis nogc;
105 0 : m->traceMappings(tracer);
106 : }
107 : }
108 0 : }
109 :
110 : bool
111 0 : WeakMapBase::saveZoneMarkedWeakMaps(JS::Zone* zone, WeakMapSet& markedWeakMaps)
112 : {
113 0 : for (WeakMapBase* m : zone->gcWeakMapList()) {
114 0 : if (m->marked && !markedWeakMaps.put(m))
115 0 : return false;
116 : }
117 0 : return true;
118 : }
119 :
120 : void
121 0 : WeakMapBase::restoreMarkedWeakMaps(WeakMapSet& markedWeakMaps)
122 : {
123 0 : for (WeakMapSet::Range r = markedWeakMaps.all(); !r.empty(); r.popFront()) {
124 0 : WeakMapBase* map = r.front();
125 0 : MOZ_ASSERT(map->zone()->isGCMarking());
126 0 : MOZ_ASSERT(!map->marked);
127 0 : map->marked = true;
128 : }
129 0 : }
130 :
131 : bool
132 0 : ObjectValueMap::findZoneEdges()
133 : {
134 : /*
135 : * For unmarked weakmap keys with delegates in a different zone, add a zone
136 : * edge to ensure that the delegate zone finishes marking before the key
137 : * zone.
138 : */
139 0 : JS::AutoSuppressGCAnalysis nogc;
140 0 : for (Range r = all(); !r.empty(); r.popFront()) {
141 0 : JSObject* key = r.front().key();
142 0 : if (key->asTenured().isMarkedBlack())
143 0 : continue;
144 0 : JSObject* delegate = getDelegate(key);
145 0 : if (!delegate)
146 0 : continue;
147 0 : Zone* delegateZone = delegate->zone();
148 0 : if (delegateZone == zone() || !delegateZone->isGCMarking())
149 0 : continue;
150 0 : if (!delegateZone->gcSweepGroupEdges().put(key->zone()))
151 0 : return false;
152 : }
153 0 : return true;
154 : }
155 :
156 3 : ObjectWeakMap::ObjectWeakMap(JSContext* cx)
157 3 : : map(cx, nullptr)
158 3 : {}
159 :
160 : bool
161 3 : ObjectWeakMap::init()
162 : {
163 3 : return map.init();
164 : }
165 :
166 : JSObject*
167 228 : ObjectWeakMap::lookup(const JSObject* obj)
168 : {
169 228 : MOZ_ASSERT(map.initialized());
170 228 : if (ObjectValueMap::Ptr p = map.lookup(const_cast<JSObject*>(obj)))
171 163 : return &p->value().toObject();
172 65 : return nullptr;
173 : }
174 :
175 : bool
176 65 : ObjectWeakMap::add(JSContext* cx, JSObject* obj, JSObject* target)
177 : {
178 65 : MOZ_ASSERT(obj && target);
179 65 : MOZ_ASSERT(map.initialized());
180 :
181 65 : MOZ_ASSERT(!map.has(obj));
182 65 : if (!map.put(obj, ObjectValue(*target))) {
183 0 : ReportOutOfMemory(cx);
184 0 : return false;
185 : }
186 :
187 65 : return true;
188 : }
189 :
190 : void
191 0 : ObjectWeakMap::clear()
192 : {
193 0 : MOZ_ASSERT(map.initialized());
194 0 : map.clear();
195 0 : }
196 :
197 : void
198 15 : ObjectWeakMap::trace(JSTracer* trc)
199 : {
200 15 : map.trace(trc);
201 15 : }
202 :
203 : size_t
204 0 : ObjectWeakMap::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
205 : {
206 0 : MOZ_ASSERT(map.initialized());
207 0 : return map.sizeOfExcludingThis(mallocSizeOf);
208 : }
209 :
210 : #ifdef JSGC_HASH_TABLE_CHECKS
211 : void
212 0 : ObjectWeakMap::checkAfterMovingGC()
213 : {
214 0 : MOZ_ASSERT(map.initialized());
215 0 : for (ObjectValueMap::Range r = map.all(); !r.empty(); r.popFront()) {
216 0 : CheckGCThingAfterMovingGC(r.front().key().get());
217 0 : CheckGCThingAfterMovingGC(&r.front().value().toObject());
218 : }
219 0 : }
220 : #endif // JSGC_HASH_TABLE_CHECKS
|