/src/mozilla-central/js/src/vm/Compartment.cpp
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 | | #include "vm/Compartment-inl.h" |
8 | | |
9 | | #include "mozilla/MemoryReporting.h" |
10 | | |
11 | | #include <stddef.h> |
12 | | |
13 | | #include "jsfriendapi.h" |
14 | | |
15 | | #include "gc/Policy.h" |
16 | | #include "gc/PublicIterators.h" |
17 | | #include "js/Date.h" |
18 | | #include "js/Proxy.h" |
19 | | #include "js/RootingAPI.h" |
20 | | #include "js/StableStringChars.h" |
21 | | #include "js/Wrapper.h" |
22 | | #include "proxy/DeadObjectProxy.h" |
23 | | #include "vm/Debugger.h" |
24 | | #include "vm/Iteration.h" |
25 | | #include "vm/JSContext.h" |
26 | | #include "vm/WrapperObject.h" |
27 | | |
28 | | #include "gc/GC-inl.h" |
29 | | #include "gc/Marking-inl.h" |
30 | | #include "vm/JSAtom-inl.h" |
31 | | #include "vm/JSFunction-inl.h" |
32 | | #include "vm/JSObject-inl.h" |
33 | | #include "vm/JSScript-inl.h" |
34 | | #include "vm/NativeObject-inl.h" |
35 | | #include "vm/UnboxedObject-inl.h" |
36 | | |
37 | | using namespace js; |
38 | | |
39 | | using JS::AutoStableStringChars; |
40 | | |
41 | | Compartment::Compartment(Zone* zone) |
42 | | : zone_(zone), |
43 | | runtime_(zone->runtimeFromAnyThread()), |
44 | | crossCompartmentWrappers(0) |
45 | 9 | {} |
46 | | |
47 | | #ifdef JSGC_HASH_TABLE_CHECKS |
48 | | |
49 | | namespace { |
50 | | struct CheckGCThingAfterMovingGCFunctor { |
51 | | template <class T> void operator()(T* t) { CheckGCThingAfterMovingGC(*t); } |
52 | | }; |
53 | | } // namespace (anonymous) |
54 | | |
55 | | void |
56 | | Compartment::checkWrapperMapAfterMovingGC() |
57 | | { |
58 | | /* |
59 | | * Assert that the postbarriers have worked and that nothing is left in |
60 | | * wrapperMap that points into the nursery, and that the hash table entries |
61 | | * are discoverable. |
62 | | */ |
63 | | for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { |
64 | | e.front().mutableKey().applyToWrapped(CheckGCThingAfterMovingGCFunctor()); |
65 | | e.front().mutableKey().applyToDebugger(CheckGCThingAfterMovingGCFunctor()); |
66 | | |
67 | | WrapperMap::Ptr ptr = crossCompartmentWrappers.lookup(e.front().key()); |
68 | | MOZ_RELEASE_ASSERT(ptr.found() && &*ptr == &e.front()); |
69 | | } |
70 | | } |
71 | | |
72 | | #endif // JSGC_HASH_TABLE_CHECKS |
73 | | |
74 | | bool |
75 | | Compartment::putWrapper(JSContext* cx, const CrossCompartmentKey& wrapped, |
76 | | const js::Value& wrapper) |
77 | 0 | { |
78 | 0 | MOZ_ASSERT(wrapped.is<JSString*>() == wrapper.isString()); |
79 | 0 | MOZ_ASSERT_IF(!wrapped.is<JSString*>(), wrapper.isObject()); |
80 | 0 |
|
81 | 0 | if (!crossCompartmentWrappers.put(wrapped, wrapper)) { |
82 | 0 | ReportOutOfMemory(cx); |
83 | 0 | return false; |
84 | 0 | } |
85 | 0 | |
86 | 0 | return true; |
87 | 0 | } |
88 | | |
89 | | static JSString* |
90 | | CopyStringPure(JSContext* cx, JSString* str) |
91 | 0 | { |
92 | 0 | /* |
93 | 0 | * Directly allocate the copy in the destination compartment, rather than |
94 | 0 | * first flattening it (and possibly allocating in source compartment), |
95 | 0 | * because we don't know whether the flattening will pay off later. |
96 | 0 | */ |
97 | 0 |
|
98 | 0 | size_t len = str->length(); |
99 | 0 | JSString* copy; |
100 | 0 | if (str->isLinear()) { |
101 | 0 | /* Only use AutoStableStringChars if the NoGC allocation fails. */ |
102 | 0 | if (str->hasLatin1Chars()) { |
103 | 0 | JS::AutoCheckCannotGC nogc; |
104 | 0 | copy = NewStringCopyN<NoGC>(cx, str->asLinear().latin1Chars(nogc), len); |
105 | 0 | } else { |
106 | 0 | JS::AutoCheckCannotGC nogc; |
107 | 0 | copy = NewStringCopyNDontDeflate<NoGC>(cx, str->asLinear().twoByteChars(nogc), len); |
108 | 0 | } |
109 | 0 | if (copy) { |
110 | 0 | return copy; |
111 | 0 | } |
112 | 0 | |
113 | 0 | AutoStableStringChars chars(cx); |
114 | 0 | if (!chars.init(cx, str)) { |
115 | 0 | return nullptr; |
116 | 0 | } |
117 | 0 | |
118 | 0 | return chars.isLatin1() |
119 | 0 | ? NewStringCopyN<CanGC>(cx, chars.latin1Range().begin().get(), len) |
120 | 0 | : NewStringCopyNDontDeflate<CanGC>(cx, chars.twoByteRange().begin().get(), len); |
121 | 0 | } |
122 | 0 |
|
123 | 0 | if (str->hasLatin1Chars()) { |
124 | 0 | UniquePtr<Latin1Char[], JS::FreePolicy> copiedChars = str->asRope().copyLatin1CharsZ(cx); |
125 | 0 | if (!copiedChars) { |
126 | 0 | return nullptr; |
127 | 0 | } |
128 | 0 | |
129 | 0 | return NewString<CanGC>(cx, std::move(copiedChars), len); |
130 | 0 | } |
131 | 0 | |
132 | 0 | UniqueTwoByteChars copiedChars = str->asRope().copyTwoByteCharsZ(cx); |
133 | 0 | if (!copiedChars) { |
134 | 0 | return nullptr; |
135 | 0 | } |
136 | 0 | |
137 | 0 | return NewStringDontDeflate<CanGC>(cx, std::move(copiedChars), len); |
138 | 0 | } |
139 | | |
140 | | bool |
141 | | Compartment::wrap(JSContext* cx, MutableHandleString strp) |
142 | 0 | { |
143 | 0 | MOZ_ASSERT(cx->compartment() == this); |
144 | 0 |
|
145 | 0 | /* If the string is already in this compartment, we are done. */ |
146 | 0 | JSString* str = strp; |
147 | 0 | if (str->zoneFromAnyThread() == zone()) { |
148 | 0 | return true; |
149 | 0 | } |
150 | 0 | |
151 | 0 | /* |
152 | 0 | * If the string is an atom, we don't have to copy, but we do need to mark |
153 | 0 | * the atom as being in use by the new zone. |
154 | 0 | */ |
155 | 0 | if (str->isAtom()) { |
156 | 0 | cx->markAtom(&str->asAtom()); |
157 | 0 | return true; |
158 | 0 | } |
159 | 0 | |
160 | 0 | /* Check the cache. */ |
161 | 0 | RootedValue key(cx, StringValue(str)); |
162 | 0 | if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(CrossCompartmentKey(key))) { |
163 | 0 | strp.set(p->value().get().toString()); |
164 | 0 | return true; |
165 | 0 | } |
166 | 0 | |
167 | 0 | /* No dice. Make a copy, and cache it. */ |
168 | 0 | JSString* copy = CopyStringPure(cx, str); |
169 | 0 | if (!copy) { |
170 | 0 | return false; |
171 | 0 | } |
172 | 0 | if (!putWrapper(cx, CrossCompartmentKey(key), StringValue(copy))) { |
173 | 0 | return false; |
174 | 0 | } |
175 | 0 | |
176 | 0 | strp.set(copy); |
177 | 0 | return true; |
178 | 0 | } |
179 | | |
180 | | #ifdef ENABLE_BIGINT |
181 | | bool |
182 | | Compartment::wrap(JSContext* cx, MutableHandleBigInt bi) |
183 | | { |
184 | | MOZ_ASSERT(cx->compartment() == this); |
185 | | |
186 | | if (bi->zone() == cx->zone()) { |
187 | | return true; |
188 | | } |
189 | | |
190 | | BigInt* copy = BigInt::copy(cx, bi); |
191 | | if (!copy) { |
192 | | return false; |
193 | | } |
194 | | bi.set(copy); |
195 | | return true; |
196 | | } |
197 | | #endif |
198 | | |
199 | | bool |
200 | | Compartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj) |
201 | 8.11M | { |
202 | 8.11M | // Ensure that we have entered a realm. |
203 | 8.11M | MOZ_ASSERT(cx->global()); |
204 | 8.11M | |
205 | 8.11M | // If we have a cross-compartment wrapper, make sure that the cx isn't |
206 | 8.11M | // associated with the self-hosting zone. We don't want to create |
207 | 8.11M | // wrappers for objects in other runtimes, which may be the case for the |
208 | 8.11M | // self-hosting zone. |
209 | 8.11M | MOZ_ASSERT(!cx->runtime()->isSelfHostingZone(cx->zone())); |
210 | 8.11M | MOZ_ASSERT(!cx->runtime()->isSelfHostingZone(obj->zone())); |
211 | 8.11M | |
212 | 8.11M | // The object is already in the right compartment. Normally same- |
213 | 8.11M | // compartment returns the object itself, however, windows are always |
214 | 8.11M | // wrapped by a proxy, so we have to check for that case here manually. |
215 | 8.11M | if (obj->compartment() == this) { |
216 | 8.11M | obj.set(ToWindowProxyIfWindow(obj)); |
217 | 8.11M | return true; |
218 | 8.11M | } |
219 | 0 | |
220 | 0 | // Note that if the object is same-compartment, but has been wrapped into a |
221 | 0 | // different compartment, we need to unwrap it and return the bare same- |
222 | 0 | // compartment object. Note again that windows are always wrapped by a |
223 | 0 | // WindowProxy even when same-compartment so take care not to strip this |
224 | 0 | // particular wrapper. |
225 | 0 | RootedObject objectPassedToWrap(cx, obj); |
226 | 0 | obj.set(UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true)); |
227 | 0 | if (obj->compartment() == this) { |
228 | 0 | MOZ_ASSERT(!IsWindow(obj)); |
229 | 0 | return true; |
230 | 0 | } |
231 | 0 |
|
232 | 0 | // Invoke the prewrap callback. The prewrap callback is responsible for |
233 | 0 | // doing similar reification as above, but can account for any additional |
234 | 0 | // embedder requirements. |
235 | 0 | // |
236 | 0 | // We're a bit worried about infinite recursion here, so we do a check - |
237 | 0 | // see bug 809295. |
238 | 0 | auto preWrap = cx->runtime()->wrapObjectCallbacks->preWrap; |
239 | 0 | if (!CheckSystemRecursionLimit(cx)) { |
240 | 0 | if (obj->getClass()->isDOMClass()) { |
241 | 0 | MOZ_CRASH("Looks like bug 1488480/1405521, with system recursion limit failing in getNonWrapperObjectForCurrentCompartment"); |
242 | 0 | } |
243 | 0 | return false; |
244 | 0 | } |
245 | 0 | if (preWrap) { |
246 | 0 | preWrap(cx, cx->global(), obj, objectPassedToWrap, obj); |
247 | 0 | if (!obj) { |
248 | 0 | if (UncheckedUnwrap(objectPassedToWrap)->getClass()->isDOMClass()) { |
249 | 0 | MOZ_CRASH("Looks like bug 1488480/1405521, with preWrap failing in getNonWrapperObjectForCurrentCompartment"); |
250 | 0 | } |
251 | 0 | return false; |
252 | 0 | } |
253 | 0 | } |
254 | 0 | MOZ_ASSERT(!IsWindow(obj)); |
255 | 0 |
|
256 | 0 | return true; |
257 | 0 | } |
258 | | |
259 | | bool |
260 | | Compartment::getOrCreateWrapper(JSContext* cx, HandleObject existing, MutableHandleObject obj) |
261 | 0 | { |
262 | 0 | // If we already have a wrapper for this value, use it. |
263 | 0 | RootedValue key(cx, ObjectValue(*obj)); |
264 | 0 | if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(CrossCompartmentKey(key))) { |
265 | 0 | obj.set(&p->value().get().toObject()); |
266 | 0 | MOZ_ASSERT(obj->is<CrossCompartmentWrapperObject>()); |
267 | 0 | return true; |
268 | 0 | } |
269 | 0 |
|
270 | 0 | // Ensure that the wrappee is exposed in case we are creating a new wrapper |
271 | 0 | // for a gray object. |
272 | 0 | ExposeObjectToActiveJS(obj); |
273 | 0 |
|
274 | 0 | // Create a new wrapper for the object. |
275 | 0 | auto wrap = cx->runtime()->wrapObjectCallbacks->wrap; |
276 | 0 | RootedObject wrapper(cx, wrap(cx, existing, obj)); |
277 | 0 | if (!wrapper) { |
278 | 0 | if (key.toObject().getClass()->isDOMClass()) { |
279 | 0 | MOZ_CRASH("Looks like bug 1488480/1405521, with wrap() call failing in Compartment::getOrCreateWrapper"); |
280 | 0 | } |
281 | 0 | return false; |
282 | 0 | } |
283 | 0 | |
284 | 0 | // We maintain the invariant that the key in the cross-compartment wrapper |
285 | 0 | // map is always directly wrapped by the value. |
286 | 0 | MOZ_ASSERT(Wrapper::wrappedObject(wrapper) == &key.get().toObject()); |
287 | 0 |
|
288 | 0 | if (!putWrapper(cx, CrossCompartmentKey(key), ObjectValue(*wrapper))) { |
289 | 0 | // Enforce the invariant that all cross-compartment wrapper object are |
290 | 0 | // in the map by nuking the wrapper if we couldn't add it. |
291 | 0 | // Unfortunately it's possible for the wrapper to still be marked if we |
292 | 0 | // took this path, for example if the object metadata callback stashes a |
293 | 0 | // reference to it. |
294 | 0 | if (wrapper->is<CrossCompartmentWrapperObject>()) { |
295 | 0 | NukeCrossCompartmentWrapper(cx, wrapper); |
296 | 0 | } |
297 | 0 | if (obj->getClass()->isDOMClass()) { |
298 | 0 | MOZ_CRASH("Looks like bug 1488480/1405521, with hashtable ops failing in Compartment::getOrCreateWrapper"); |
299 | 0 | } |
300 | 0 | return false; |
301 | 0 | } |
302 | 0 | |
303 | 0 | obj.set(wrapper); |
304 | 0 | return true; |
305 | 0 | } |
306 | | |
307 | | bool |
308 | | Compartment::wrap(JSContext* cx, MutableHandleObject obj) |
309 | 8.11M | { |
310 | 8.11M | MOZ_ASSERT(cx->compartment() == this); |
311 | 8.11M | |
312 | 8.11M | if (!obj) { |
313 | 0 | return true; |
314 | 0 | } |
315 | 8.11M | |
316 | 8.11M | AutoDisableProxyCheck adpc; |
317 | 8.11M | |
318 | 8.11M | // Anything we're wrapping has already escaped into script, so must have |
319 | 8.11M | // been unmarked-gray at some point in the past. |
320 | 8.11M | MOZ_ASSERT(JS::ObjectIsNotGray(obj)); |
321 | 8.11M | |
322 | 8.11M | // The passed object may already be wrapped, or may fit a number of special |
323 | 8.11M | // cases that we need to check for and manually correct. |
324 | 8.11M | if (!getNonWrapperObjectForCurrentCompartment(cx, obj)) { |
325 | 0 | return false; |
326 | 0 | } |
327 | 8.11M | |
328 | 8.11M | // If the reification above did not result in a same-compartment object, |
329 | 8.11M | // get or create a new wrapper object in this compartment for it. |
330 | 8.11M | if (obj->compartment() != this) { |
331 | 0 | if (!getOrCreateWrapper(cx, nullptr, obj)) { |
332 | 0 | return false; |
333 | 0 | } |
334 | 8.11M | } |
335 | 8.11M | |
336 | 8.11M | // Ensure that the wrapper is also exposed. |
337 | 8.11M | ExposeObjectToActiveJS(obj); |
338 | 8.11M | return true; |
339 | 8.11M | } |
340 | | |
341 | | bool |
342 | | Compartment::rewrap(JSContext* cx, MutableHandleObject obj, HandleObject existingArg) |
343 | 0 | { |
344 | 0 | MOZ_ASSERT(cx->compartment() == this); |
345 | 0 | MOZ_ASSERT(obj); |
346 | 0 | MOZ_ASSERT(existingArg); |
347 | 0 | MOZ_ASSERT(existingArg->compartment() == cx->compartment()); |
348 | 0 | MOZ_ASSERT(IsDeadProxyObject(existingArg)); |
349 | 0 |
|
350 | 0 | AutoDisableProxyCheck adpc; |
351 | 0 |
|
352 | 0 | // It may not be possible to re-use existing; if so, clear it so that we |
353 | 0 | // are forced to create a new wrapper. Note that this cannot call out to |
354 | 0 | // |wrap| because of the different gray unmarking semantics. |
355 | 0 | RootedObject existing(cx, existingArg); |
356 | 0 | if (existing->hasStaticPrototype() || |
357 | 0 | // Note: Class asserted above, so all that's left to check is callability |
358 | 0 | existing->isCallable() || |
359 | 0 | obj->isCallable()) |
360 | 0 | { |
361 | 0 | existing.set(nullptr); |
362 | 0 | } |
363 | 0 |
|
364 | 0 | // The passed object may already be wrapped, or may fit a number of special |
365 | 0 | // cases that we need to check for and manually correct. |
366 | 0 | if (!getNonWrapperObjectForCurrentCompartment(cx, obj)) { |
367 | 0 | return false; |
368 | 0 | } |
369 | 0 | |
370 | 0 | // If the reification above resulted in a same-compartment object, we do |
371 | 0 | // not need to create or return an existing wrapper. |
372 | 0 | if (obj->compartment() == this) { |
373 | 0 | return true; |
374 | 0 | } |
375 | 0 | |
376 | 0 | return getOrCreateWrapper(cx, existing, obj); |
377 | 0 | } |
378 | | |
379 | | bool |
380 | | Compartment::wrap(JSContext* cx, MutableHandle<JS::PropertyDescriptor> desc) |
381 | 0 | { |
382 | 0 | if (!wrap(cx, desc.object())) { |
383 | 0 | return false; |
384 | 0 | } |
385 | 0 | |
386 | 0 | if (desc.hasGetterObject()) { |
387 | 0 | if (!wrap(cx, desc.getterObject())) { |
388 | 0 | return false; |
389 | 0 | } |
390 | 0 | } |
391 | 0 | if (desc.hasSetterObject()) { |
392 | 0 | if (!wrap(cx, desc.setterObject())) { |
393 | 0 | return false; |
394 | 0 | } |
395 | 0 | } |
396 | 0 | |
397 | 0 | return wrap(cx, desc.value()); |
398 | 0 | } |
399 | | |
400 | | bool |
401 | | Compartment::wrap(JSContext* cx, MutableHandle<GCVector<Value>> vec) |
402 | 0 | { |
403 | 0 | for (size_t i = 0; i < vec.length(); ++i) { |
404 | 0 | if (!wrap(cx, vec[i])) { |
405 | 0 | return false; |
406 | 0 | } |
407 | 0 | } |
408 | 0 | return true; |
409 | 0 | } |
410 | | |
411 | | void |
412 | | Compartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc) |
413 | 18 | { |
414 | 18 | MOZ_ASSERT(JS::RuntimeHeapIsMajorCollecting()); |
415 | 18 | MOZ_ASSERT(!zone()->isCollectingFromAnyThread() || trc->runtime()->gc.isHeapCompacting()); |
416 | 18 | |
417 | 18 | for (NonStringWrapperEnum e(this); !e.empty(); e.popFront()) { |
418 | 0 | if (e.front().key().is<JSObject*>()) { |
419 | 0 | Value v = e.front().value().unbarrieredGet(); |
420 | 0 | ProxyObject* wrapper = &v.toObject().as<ProxyObject>(); |
421 | 0 |
|
422 | 0 | /* |
423 | 0 | * We have a cross-compartment wrapper. Its private pointer may |
424 | 0 | * point into the compartment being collected, so we should mark it. |
425 | 0 | */ |
426 | 0 | ProxyObject::traceEdgeToTarget(trc, wrapper); |
427 | 0 | } |
428 | 0 | } |
429 | 18 | } |
430 | | |
431 | | /* static */ void |
432 | | Compartment::traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc) |
433 | 18 | { |
434 | 18 | gcstats::AutoPhase ap(trc->runtime()->gc.stats(), gcstats::PhaseKind::MARK_CCWS); |
435 | 18 | MOZ_ASSERT(JS::RuntimeHeapIsMajorCollecting()); |
436 | 72 | for (CompartmentsIter c(trc->runtime()); !c.done(); c.next()) { |
437 | 54 | if (!c->zone()->isCollecting()) { |
438 | 18 | c->traceOutgoingCrossCompartmentWrappers(trc); |
439 | 18 | } |
440 | 54 | } |
441 | 18 | Debugger::traceIncomingCrossCompartmentEdges(trc); |
442 | 18 | } |
443 | | |
444 | | void |
445 | | Compartment::sweepAfterMinorGC(JSTracer* trc) |
446 | 3 | { |
447 | 3 | crossCompartmentWrappers.sweepAfterMinorGC(trc); |
448 | 3 | |
449 | 6 | for (RealmsInCompartmentIter r(this); !r.done(); r.next()) { |
450 | 3 | r->sweepAfterMinorGC(); |
451 | 3 | } |
452 | 3 | } |
453 | | |
454 | | /* |
455 | | * Remove dead wrappers from the table. We must sweep all compartments, since |
456 | | * string entries in the crossCompartmentWrappers table are not marked during |
457 | | * markCrossCompartmentWrappers. |
458 | | */ |
459 | | void |
460 | | Compartment::sweepCrossCompartmentWrappers() |
461 | 36 | { |
462 | 36 | crossCompartmentWrappers.sweep(); |
463 | 36 | } |
464 | | |
465 | | namespace { |
466 | | struct TraceRootFunctor { |
467 | | JSTracer* trc; |
468 | | const char* name; |
469 | 0 | TraceRootFunctor(JSTracer* trc, const char* name) : trc(trc), name(name) {} |
470 | 0 | template <class T> void operator()(T* t) { return TraceRoot(trc, t, name); } Unexecuted instantiation: Unified_cpp_js_src33.cpp:void (anonymous namespace)::TraceRootFunctor::operator()<JSObject*>(JSObject**) Unexecuted instantiation: Unified_cpp_js_src33.cpp:void (anonymous namespace)::TraceRootFunctor::operator()<JSString*>(JSString**) Unexecuted instantiation: Unified_cpp_js_src33.cpp:void (anonymous namespace)::TraceRootFunctor::operator()<JSScript*>(JSScript**) Unexecuted instantiation: Unified_cpp_js_src33.cpp:void (anonymous namespace)::TraceRootFunctor::operator()<js::LazyScript*>(js::LazyScript**) Unexecuted instantiation: Unified_cpp_js_src33.cpp:void (anonymous namespace)::TraceRootFunctor::operator()<js::NativeObject*>(js::NativeObject**) |
471 | | }; |
472 | | struct NeedsSweepUnbarrieredFunctor { |
473 | 0 | template <class T> bool operator()(T* t) const { return IsAboutToBeFinalizedUnbarriered(t); } Unexecuted instantiation: Unified_cpp_js_src33.cpp:bool (anonymous namespace)::NeedsSweepUnbarrieredFunctor::operator()<JSObject*>(JSObject**) const Unexecuted instantiation: Unified_cpp_js_src33.cpp:bool (anonymous namespace)::NeedsSweepUnbarrieredFunctor::operator()<JSString*>(JSString**) const Unexecuted instantiation: Unified_cpp_js_src33.cpp:bool (anonymous namespace)::NeedsSweepUnbarrieredFunctor::operator()<JSScript*>(JSScript**) const Unexecuted instantiation: Unified_cpp_js_src33.cpp:bool (anonymous namespace)::NeedsSweepUnbarrieredFunctor::operator()<js::LazyScript*>(js::LazyScript**) const Unexecuted instantiation: Unified_cpp_js_src33.cpp:bool (anonymous namespace)::NeedsSweepUnbarrieredFunctor::operator()<js::NativeObject*>(js::NativeObject**) const |
474 | | }; |
475 | | } // namespace (anonymous) |
476 | | |
477 | | void |
478 | | CrossCompartmentKey::trace(JSTracer* trc) |
479 | 0 | { |
480 | 0 | applyToWrapped(TraceRootFunctor(trc, "CrossCompartmentKey::wrapped")); |
481 | 0 | applyToDebugger(TraceRootFunctor(trc, "CrossCompartmentKey::debugger")); |
482 | 0 | } |
483 | | |
484 | | bool |
485 | | CrossCompartmentKey::needsSweep() |
486 | 0 | { |
487 | 0 | return applyToWrapped(NeedsSweepUnbarrieredFunctor()) || |
488 | 0 | applyToDebugger(NeedsSweepUnbarrieredFunctor()); |
489 | 0 | } |
490 | | |
491 | | /* static */ void |
492 | | Compartment::fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc) |
493 | 0 | { |
494 | 0 | MOZ_ASSERT(trc->runtime()->gc.isHeapCompacting()); |
495 | 0 |
|
496 | 0 | for (CompartmentsIter comp(trc->runtime()); !comp.done(); comp.next()) { |
497 | 0 | // Sweep the wrapper map to update keys (wrapped values) in other |
498 | 0 | // compartments that may have been moved. |
499 | 0 | comp->sweepCrossCompartmentWrappers(); |
500 | 0 | // Trace the wrappers in the map to update their cross-compartment edges |
501 | 0 | // to wrapped values in other compartments that may have been moved. |
502 | 0 | comp->traceOutgoingCrossCompartmentWrappers(trc); |
503 | 0 | } |
504 | 0 | } |
505 | | |
506 | | void |
507 | | Compartment::fixupAfterMovingGC() |
508 | 0 | { |
509 | 0 | MOZ_ASSERT(zone()->isGCCompacting()); |
510 | 0 |
|
511 | 0 | for (RealmsInCompartmentIter r(this); !r.done(); r.next()) { |
512 | 0 | r->fixupAfterMovingGC(); |
513 | 0 | } |
514 | 0 |
|
515 | 0 | // Sweep the wrapper map to update values (wrapper objects) in this |
516 | 0 | // compartment that may have been moved. |
517 | 0 | sweepCrossCompartmentWrappers(); |
518 | 0 | } |
519 | | |
520 | | void |
521 | | Compartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, |
522 | | size_t* compartmentObjects, |
523 | | size_t* crossCompartmentWrappersTables, |
524 | | size_t* compartmentsPrivateData) |
525 | 0 | { |
526 | 0 | *compartmentObjects += mallocSizeOf(this); |
527 | 0 | *crossCompartmentWrappersTables += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf); |
528 | 0 |
|
529 | 0 | if (auto callback = runtime_->sizeOfIncludingThisCompartmentCallback) { |
530 | 0 | *compartmentsPrivateData += callback(mallocSizeOf, this); |
531 | 0 | } |
532 | 0 | } |