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 "mozilla/ArrayUtils.h"
8 :
9 : #ifdef MOZ_VALGRIND
10 : # include <valgrind/memcheck.h>
11 : #endif
12 :
13 : #include "jscntxt.h"
14 : #include "jsgc.h"
15 : #include "jsprf.h"
16 : #include "jstypes.h"
17 : #include "jswatchpoint.h"
18 :
19 : #include "builtin/MapObject.h"
20 : #include "frontend/BytecodeCompiler.h"
21 : #include "gc/GCInternals.h"
22 : #include "gc/Marking.h"
23 : #include "jit/MacroAssembler.h"
24 : #include "js/HashTable.h"
25 : #include "vm/Debugger.h"
26 : #include "vm/JSONParser.h"
27 :
28 : #include "jsgcinlines.h"
29 : #include "jsobjinlines.h"
30 :
31 : #include "gc/Nursery-inl.h"
32 :
33 : using namespace js;
34 : using namespace js::gc;
35 :
36 : using mozilla::ArrayEnd;
37 :
38 : using JS::AutoGCRooter;
39 :
40 : typedef RootedValueMap::Range RootRange;
41 : typedef RootedValueMap::Entry RootEntry;
42 : typedef RootedValueMap::Enum RootEnum;
43 :
44 : template <typename T>
45 : using TraceFunction = void (*)(JSTracer* trc, T* ref, const char* name);
46 :
47 : // For more detail see JS::Rooted::ptr and js::DispatchWrapper.
48 : //
49 : // The JS::RootKind::Traceable list contains a bunch of totally disparate
50 : // types, but the instantiations of DispatchWrapper below need /something/ in
51 : // the type field. We use the following type as a compatible stand-in. No
52 : // actual methods from ConcreteTraceable type are actually used at runtime --
53 : // the real trace function has been stored inline in the DispatchWrapper.
54 : struct ConcreteTraceable {
55 : ConcreteTraceable() { MOZ_CRASH("instantiation of ConcreteTraceable"); }
56 : void trace(JSTracer*) {}
57 : };
58 :
59 : template <typename T, TraceFunction<T> TraceFn = TraceNullableRoot>
60 : static inline void
61 2905 : TraceExactStackRootList(JSTracer* trc, JS::Rooted<void*>* rooter, const char* name)
62 : {
63 5502 : while (rooter) {
64 2597 : T* addr = reinterpret_cast<JS::Rooted<T>*>(rooter)->address();
65 2597 : TraceFn(trc, addr, name);
66 2597 : rooter = rooter->previous();
67 : }
68 308 : }
69 :
70 : static inline void
71 22 : TraceStackRoots(JSTracer* trc, JS::RootedListHeads& stackRoots)
72 : {
73 : #define TRACE_ROOTS(name, type, _) \
74 : TraceExactStackRootList<type*>(trc, stackRoots[JS::RootKind::name], "exact-" #name);
75 22 : JS_FOR_EACH_TRACEKIND(TRACE_ROOTS)
76 : #undef TRACE_ROOTS
77 22 : TraceExactStackRootList<jsid>(trc, stackRoots[JS::RootKind::Id], "exact-id");
78 22 : TraceExactStackRootList<Value>(trc, stackRoots[JS::RootKind::Value], "exact-value");
79 : TraceExactStackRootList<ConcreteTraceable,
80 22 : js::DispatchWrapper<ConcreteTraceable>::TraceWrapped>(
81 44 : trc, stackRoots[JS::RootKind::Traceable], "Traceable");
82 22 : }
83 :
84 : void
85 22 : JS::RootingContext::traceStackRoots(JSTracer* trc)
86 : {
87 22 : TraceStackRoots(trc, stackRoots_);
88 22 : }
89 :
90 : static void
91 22 : TraceExactStackRoots(const CooperatingContext& target, JSTracer* trc)
92 : {
93 22 : target.context()->traceStackRoots(trc);
94 22 : }
95 :
96 : template <typename T, TraceFunction<T> TraceFn = TraceNullableRoot>
97 : static inline void
98 308 : TracePersistentRootedList(JSTracer* trc, mozilla::LinkedList<PersistentRooted<void*>>& list,
99 : const char* name)
100 : {
101 4821 : for (PersistentRooted<void*>* r : list)
102 4513 : TraceFn(trc, reinterpret_cast<PersistentRooted<T>*>(r)->address(), name);
103 308 : }
104 :
105 : void
106 22 : JSRuntime::tracePersistentRoots(JSTracer* trc)
107 : {
108 : #define TRACE_ROOTS(name, type, _) \
109 : TracePersistentRootedList<type*>(trc, heapRoots.ref()[JS::RootKind::name], "persistent-" #name);
110 22 : JS_FOR_EACH_TRACEKIND(TRACE_ROOTS)
111 : #undef TRACE_ROOTS
112 22 : TracePersistentRootedList<jsid>(trc, heapRoots.ref()[JS::RootKind::Id], "persistent-id");
113 22 : TracePersistentRootedList<Value>(trc, heapRoots.ref()[JS::RootKind::Value], "persistent-value");
114 : TracePersistentRootedList<ConcreteTraceable,
115 22 : js::DispatchWrapper<ConcreteTraceable>::TraceWrapped>(trc,
116 44 : heapRoots.ref()[JS::RootKind::Traceable], "persistent-traceable");
117 22 : }
118 :
119 : static void
120 22 : TracePersistentRooted(JSRuntime* rt, JSTracer* trc)
121 : {
122 22 : rt->tracePersistentRoots(trc);
123 22 : }
124 :
125 : template <typename T>
126 : static void
127 0 : FinishPersistentRootedChain(mozilla::LinkedList<PersistentRooted<void*>>& listArg)
128 : {
129 0 : auto& list = reinterpret_cast<mozilla::LinkedList<PersistentRooted<T>>&>(listArg);
130 0 : while (!list.isEmpty())
131 0 : list.getFirst()->reset();
132 0 : }
133 :
134 : void
135 0 : JSRuntime::finishPersistentRoots()
136 : {
137 : #define FINISH_ROOT_LIST(name, type, _) \
138 : FinishPersistentRootedChain<type*>(heapRoots.ref()[JS::RootKind::name]);
139 0 : JS_FOR_EACH_TRACEKIND(FINISH_ROOT_LIST)
140 : #undef FINISH_ROOT_LIST
141 0 : FinishPersistentRootedChain<jsid>(heapRoots.ref()[JS::RootKind::Id]);
142 0 : FinishPersistentRootedChain<Value>(heapRoots.ref()[JS::RootKind::Value]);
143 :
144 : // Note that we do not finalize the Traceable list as we do not know how to
145 : // safely clear memebers. We instead assert that none escape the RootLists.
146 : // See the comment on RootLists::~RootLists for details.
147 0 : }
148 :
149 : inline void
150 48 : AutoGCRooter::trace(JSTracer* trc)
151 : {
152 48 : switch (tag_) {
153 : case PARSER:
154 0 : frontend::TraceParser(trc, this);
155 0 : return;
156 :
157 : case VALARRAY: {
158 : /*
159 : * We don't know the template size parameter, but we can safely treat it
160 : * as an AutoValueArray<1> because the length is stored separately.
161 : */
162 18 : AutoValueArray<1>* array = static_cast<AutoValueArray<1>*>(this);
163 18 : TraceRootRange(trc, array->length(), array->begin(), "js::AutoValueArray");
164 18 : return;
165 : }
166 :
167 : case IONMASM: {
168 0 : static_cast<js::jit::MacroAssembler::AutoRooter*>(this)->masm()->trace(trc);
169 0 : return;
170 : }
171 :
172 : case WRAPPER: {
173 : /*
174 : * We need to use TraceManuallyBarrieredEdge here because we trace
175 : * wrapper roots in every slice. This is because of some rule-breaking
176 : * in RemapAllWrappersForObject; see comment there.
177 : */
178 0 : TraceManuallyBarrieredEdge(trc, &static_cast<AutoWrapperRooter*>(this)->value.get(),
179 0 : "JS::AutoWrapperRooter.value");
180 0 : return;
181 : }
182 :
183 : case WRAPVECTOR: {
184 0 : AutoWrapperVector::VectorImpl& vector = static_cast<AutoWrapperVector*>(this)->vector;
185 : /*
186 : * We need to use TraceManuallyBarrieredEdge here because we trace
187 : * wrapper roots in every slice. This is because of some rule-breaking
188 : * in RemapAllWrappersForObject; see comment there.
189 : */
190 0 : for (WrapperValue* p = vector.begin(); p < vector.end(); p++)
191 0 : TraceManuallyBarrieredEdge(trc, &p->get(), "js::AutoWrapperVector.vector");
192 0 : return;
193 : }
194 :
195 : case CUSTOM:
196 16 : static_cast<JS::CustomAutoRooter*>(this)->trace(trc);
197 16 : return;
198 : }
199 :
200 14 : MOZ_ASSERT(tag_ >= 0);
201 14 : if (Value* vp = static_cast<AutoArrayRooter*>(this)->array)
202 14 : TraceRootRange(trc, tag_, vp, "JS::AutoArrayRooter.array");
203 : }
204 :
205 : /* static */ void
206 22 : AutoGCRooter::traceAll(const CooperatingContext& target, JSTracer* trc)
207 : {
208 70 : for (AutoGCRooter* gcr = target.context()->autoGCRooters_; gcr; gcr = gcr->down)
209 48 : gcr->trace(trc);
210 22 : }
211 :
212 : /* static */ void
213 3 : AutoGCRooter::traceAllWrappers(const CooperatingContext& target, JSTracer* trc)
214 : {
215 3 : for (AutoGCRooter* gcr = target.context()->autoGCRooters_; gcr; gcr = gcr->down) {
216 0 : if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
217 0 : gcr->trace(trc);
218 : }
219 3 : }
220 :
221 : void
222 4 : StackShape::trace(JSTracer* trc)
223 : {
224 4 : if (base)
225 4 : TraceRoot(trc, &base, "StackShape base");
226 :
227 4 : TraceRoot(trc, (jsid*) &propid, "StackShape id");
228 :
229 4 : if ((attrs & JSPROP_GETTER) && rawGetter)
230 2 : TraceRoot(trc, (JSObject**)&rawGetter, "StackShape getter");
231 :
232 4 : if ((attrs & JSPROP_SETTER) && rawSetter)
233 0 : TraceRoot(trc, (JSObject**)&rawSetter, "StackShape setter");
234 4 : }
235 :
236 : void
237 9 : PropertyDescriptor::trace(JSTracer* trc)
238 : {
239 9 : if (obj)
240 0 : TraceRoot(trc, &obj, "Descriptor::obj");
241 9 : TraceRoot(trc, &value, "Descriptor::value");
242 9 : if ((attrs & JSPROP_GETTER) && getter) {
243 4 : JSObject* tmp = JS_FUNC_TO_DATA_PTR(JSObject*, getter);
244 4 : TraceRoot(trc, &tmp, "Descriptor::get");
245 4 : getter = JS_DATA_TO_FUNC_PTR(JSGetterOp, tmp);
246 : }
247 9 : if ((attrs & JSPROP_SETTER) && setter) {
248 0 : JSObject* tmp = JS_FUNC_TO_DATA_PTR(JSObject*, setter);
249 0 : TraceRoot(trc, &tmp, "Descriptor::set");
250 0 : setter = JS_DATA_TO_FUNC_PTR(JSSetterOp, tmp);
251 : }
252 9 : }
253 :
254 : void
255 1 : js::gc::GCRuntime::traceRuntimeForMajorGC(JSTracer* trc, AutoLockForExclusiveAccess& lock)
256 : {
257 : // FinishRoots will have asserted that every root that we do not expect
258 : // is gone, so we can simply skip traceRuntime here.
259 1 : if (rt->isBeingDestroyed())
260 0 : return;
261 :
262 2 : gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
263 1 : if (rt->atomsCompartment(lock)->zone()->isCollecting())
264 1 : traceRuntimeAtoms(trc, lock);
265 1 : JSCompartment::traceIncomingCrossCompartmentEdgesForZoneGC(trc);
266 1 : traceRuntimeCommon(trc, MarkRuntime, lock);
267 : }
268 :
269 : void
270 21 : js::gc::GCRuntime::traceRuntimeForMinorGC(JSTracer* trc, AutoLockForExclusiveAccess& lock)
271 : {
272 : // Note that we *must* trace the runtime during the SHUTDOWN_GC's minor GC
273 : // despite having called FinishRoots already. This is because FinishRoots
274 : // does not clear the crossCompartmentWrapper map. It cannot do this
275 : // because Proxy's trace for CrossCompartmentWrappers asserts presence in
276 : // the map. And we can reach its trace function despite having finished the
277 : // roots via the edges stored by the pre-barrier verifier when we finish
278 : // the verifier for the last time.
279 42 : gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
280 :
281 21 : jit::JitRuntime::TraceJitcodeGlobalTableForMinorGC(trc);
282 :
283 21 : traceRuntimeCommon(trc, TraceRuntime, lock);
284 21 : }
285 :
286 : void
287 0 : js::TraceRuntime(JSTracer* trc)
288 : {
289 0 : MOZ_ASSERT(!trc->isMarkingTracer());
290 :
291 0 : JSRuntime* rt = trc->runtime();
292 0 : EvictAllNurseries(rt);
293 0 : AutoPrepareForTracing prep(TlsContext.get(), WithAtoms);
294 0 : gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
295 0 : rt->gc.traceRuntime(trc, prep.session().lock);
296 0 : }
297 :
298 : void
299 0 : js::gc::GCRuntime::traceRuntime(JSTracer* trc, AutoLockForExclusiveAccess& lock)
300 : {
301 0 : MOZ_ASSERT(!rt->isBeingDestroyed());
302 :
303 0 : gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_ROOTS);
304 0 : traceRuntimeAtoms(trc, lock);
305 0 : traceRuntimeCommon(trc, TraceRuntime, lock);
306 0 : }
307 :
308 : void
309 1 : js::gc::GCRuntime::traceRuntimeAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock)
310 : {
311 2 : gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_RUNTIME_DATA);
312 1 : TracePermanentAtoms(trc);
313 1 : TraceAtoms(trc, lock);
314 1 : TraceWellKnownSymbols(trc);
315 1 : jit::JitRuntime::Trace(trc, lock);
316 1 : }
317 :
318 : void
319 22 : js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrMark,
320 : AutoLockForExclusiveAccess& lock)
321 : {
322 22 : MOZ_ASSERT(!TlsContext.get()->suppressGC);
323 :
324 : {
325 44 : gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_STACK);
326 :
327 22 : JSContext* cx = TlsContext.get();
328 44 : for (const CooperatingContext& target : rt->cooperatingContexts()) {
329 : // Trace active interpreter and JIT stack roots.
330 22 : TraceInterpreterActivations(cx, target, trc);
331 22 : jit::TraceJitActivations(cx, target, trc);
332 22 : wasm::TraceActivations(cx, target, trc);
333 :
334 : // Trace legacy C stack roots.
335 22 : AutoGCRooter::traceAll(target, trc);
336 :
337 : // Trace C stack roots.
338 22 : TraceExactStackRoots(target, trc);
339 : }
340 :
341 46 : for (RootRange r = rootsHash.ref().all(); !r.empty(); r.popFront()) {
342 24 : const RootEntry& entry = r.front();
343 24 : TraceRoot(trc, entry.key(), entry.value());
344 : }
345 : }
346 :
347 : // Trace runtime global roots.
348 22 : TracePersistentRooted(rt, trc);
349 :
350 : // Trace the self-hosting global compartment.
351 22 : rt->traceSelfHostingGlobal(trc);
352 :
353 : // Trace the shared Intl data.
354 22 : rt->traceSharedIntlData(trc);
355 :
356 : // Trace anything in any of the cooperating threads.
357 44 : for (const CooperatingContext& target : rt->cooperatingContexts())
358 22 : target.context()->trace(trc);
359 :
360 : // Trace all compartment roots, but not the compartment itself; it is
361 : // traced via the parent pointer if traceRoots actually traces anything.
362 2659 : for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
363 2637 : c->traceRoots(trc, traceOrMark);
364 :
365 : // Trace the Gecko Profiler.
366 22 : rt->geckoProfiler().trace(trc);
367 :
368 : // Trace helper thread roots.
369 22 : HelperThreadState().trace(trc);
370 :
371 : // Trace the embedding's black and gray roots.
372 22 : if (!JS::CurrentThreadIsHeapMinorCollecting()) {
373 2 : gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK_EMBEDDING);
374 :
375 : /*
376 : * The embedding can register additional roots here.
377 : *
378 : * We don't need to trace these in a minor GC because all pointers into
379 : * the nursery should be in the store buffer, and we want to avoid the
380 : * time taken to trace all these roots.
381 : */
382 5 : for (size_t i = 0; i < blackRootTracers.ref().length(); i++) {
383 4 : const Callback<JSTraceDataOp>& e = blackRootTracers.ref()[i];
384 4 : (*e.op)(trc, e.data);
385 : }
386 :
387 : /* During GC, we don't trace gray roots at this stage. */
388 1 : if (JSTraceDataOp op = grayRootTracer.op) {
389 1 : if (traceOrMark == TraceRuntime)
390 0 : (*op)(trc, grayRootTracer.data);
391 : }
392 : }
393 22 : }
394 :
395 : #ifdef DEBUG
396 : class AssertNoRootsTracer : public JS::CallbackTracer
397 : {
398 0 : void onChild(const JS::GCCellPtr& thing) override {
399 0 : MOZ_CRASH("There should not be any roots after finishRoots");
400 : }
401 :
402 : public:
403 0 : AssertNoRootsTracer(JSRuntime* rt, WeakMapTraceKind weakTraceKind)
404 0 : : JS::CallbackTracer(rt, weakTraceKind)
405 0 : {}
406 : };
407 : #endif // DEBUG
408 :
409 : void
410 0 : js::gc::GCRuntime::finishRoots()
411 : {
412 0 : AutoNoteSingleThreadedRegion anstr;
413 :
414 0 : rt->finishAtoms();
415 :
416 0 : if (rootsHash.ref().initialized())
417 0 : rootsHash.ref().clear();
418 :
419 0 : rt->finishPersistentRoots();
420 :
421 0 : rt->finishSelfHosting();
422 :
423 0 : for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
424 0 : c->finishRoots();
425 :
426 : #ifdef DEBUG
427 : // The nsWrapperCache may not be empty before our shutdown GC, so we have
428 : // to skip that table when verifying that we are fully unrooted.
429 0 : auto prior = grayRootTracer;
430 0 : grayRootTracer = Callback<JSTraceDataOp>(nullptr, nullptr);
431 :
432 0 : AssertNoRootsTracer trc(rt, TraceWeakMapKeysValues);
433 0 : AutoPrepareForTracing prep(TlsContext.get(), WithAtoms);
434 0 : gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::TRACE_HEAP);
435 0 : traceRuntime(&trc, prep.session().lock);
436 :
437 : // Restore the wrapper tracing so that we leak instead of leaving dangling
438 : // pointers.
439 0 : grayRootTracer = prior;
440 : #endif // DEBUG
441 0 : }
442 :
443 : // Append traced things to a buffer on the zone for use later in the GC.
444 : // See the comment in GCRuntime.h above grayBufferState for details.
445 : class BufferGrayRootsTracer final : public JS::CallbackTracer
446 : {
447 : // Set to false if we OOM while buffering gray roots.
448 : bool bufferingGrayRootsFailed;
449 :
450 5059 : void onObjectEdge(JSObject** objp) override { bufferRoot(*objp); }
451 4 : void onStringEdge(JSString** stringp) override { bufferRoot(*stringp); }
452 39 : void onScriptEdge(JSScript** scriptp) override { bufferRoot(*scriptp); }
453 0 : void onSymbolEdge(JS::Symbol** symbolp) override { bufferRoot(*symbolp); }
454 :
455 0 : void onChild(const JS::GCCellPtr& thing) override {
456 0 : MOZ_CRASH("Unexpected gray root kind");
457 : }
458 :
459 : template <typename T> inline void bufferRoot(T* thing);
460 :
461 : public:
462 1 : explicit BufferGrayRootsTracer(JSRuntime* rt)
463 1 : : JS::CallbackTracer(rt), bufferingGrayRootsFailed(false)
464 1 : {}
465 :
466 1 : bool failed() const { return bufferingGrayRootsFailed; }
467 :
468 : #ifdef DEBUG
469 20408 : TracerKind getTracerKind() const override { return TracerKind::GrayBuffering; }
470 : #endif
471 : };
472 :
473 : #ifdef DEBUG
474 : // Return true if this trace is happening on behalf of gray buffering during
475 : // the marking phase of incremental GC.
476 : bool
477 51842 : js::IsBufferGrayRootsTracer(JSTracer* trc)
478 : {
479 62146 : return trc->isCallbackTracer() &&
480 62146 : trc->asCallbackTracer()->getTracerKind() == JS::CallbackTracer::TracerKind::GrayBuffering;
481 : }
482 : #endif
483 :
484 : void
485 1 : js::gc::GCRuntime::bufferGrayRoots()
486 : {
487 : // Precondition: the state has been reset to "unused" after the last GC
488 : // and the zone's buffers have been cleared.
489 1 : MOZ_ASSERT(grayBufferState == GrayBufferState::Unused);
490 17 : for (GCZonesIter zone(rt); !zone.done(); zone.next())
491 16 : MOZ_ASSERT(zone->gcGrayRoots().empty());
492 :
493 1 : BufferGrayRootsTracer grayBufferer(rt);
494 1 : if (JSTraceDataOp op = grayRootTracer.op)
495 1 : (*op)(&grayBufferer, grayRootTracer.data);
496 :
497 : // Propagate the failure flag from the marker to the runtime.
498 1 : if (grayBufferer.failed()) {
499 0 : grayBufferState = GrayBufferState::Failed;
500 0 : resetBufferedGrayRoots();
501 : } else {
502 1 : grayBufferState = GrayBufferState::Okay;
503 : }
504 1 : }
505 :
506 : template <typename T>
507 : inline void
508 5102 : BufferGrayRootsTracer::bufferRoot(T* thing)
509 : {
510 5102 : MOZ_ASSERT(JS::CurrentThreadIsHeapBusy());
511 5102 : MOZ_ASSERT(thing);
512 : // Check if |thing| is corrupt by calling a method that touches the heap.
513 5102 : MOZ_ASSERT(thing->getTraceKind() <= JS::TraceKind::Null);
514 :
515 5102 : TenuredCell* tenured = &thing->asTenured();
516 :
517 : // This is run from a helper thread while the mutator is paused so we have
518 : // to use *FromAnyThread methods here.
519 5102 : Zone* zone = tenured->zoneFromAnyThread();
520 5102 : if (zone->isCollectingFromAnyThread()) {
521 : // See the comment on SetMaybeAliveFlag to see why we only do this for
522 : // objects and scripts. We rely on gray root buffering for this to work,
523 : // but we only need to worry about uncollected dead compartments during
524 : // incremental GCs (when we do gray root buffering).
525 5102 : SetMaybeAliveFlag(thing);
526 :
527 5102 : if (!zone->gcGrayRoots().append(tenured))
528 0 : bufferingGrayRootsFailed = true;
529 : }
530 5102 : }
531 :
532 : void
533 0 : GCRuntime::markBufferedGrayRoots(JS::Zone* zone)
534 : {
535 0 : MOZ_ASSERT(grayBufferState == GrayBufferState::Okay);
536 0 : MOZ_ASSERT(zone->isGCMarkingGray() || zone->isGCCompacting());
537 :
538 0 : for (auto cell : zone->gcGrayRoots())
539 0 : TraceManuallyBarrieredGenericPointerEdge(&marker, &cell, "buffered gray root");
540 0 : }
541 :
542 : void
543 0 : GCRuntime::resetBufferedGrayRoots() const
544 : {
545 0 : MOZ_ASSERT(grayBufferState != GrayBufferState::Okay,
546 : "Do not clear the gray buffers unless we are Failed or becoming Unused");
547 0 : for (GCZonesIter zone(rt); !zone.done(); zone.next())
548 0 : zone->gcGrayRoots().clearAndFree();
549 0 : }
550 :
551 : JS_PUBLIC_API(void)
552 633 : JS::AddPersistentRoot(JS::RootingContext* cx, RootKind kind, PersistentRooted<void*>* root)
553 : {
554 633 : static_cast<JSContext*>(cx)->runtime()->heapRoots.ref()[kind].insertBack(root);
555 633 : }
556 :
557 : JS_PUBLIC_API(void)
558 0 : JS::AddPersistentRoot(JSRuntime* rt, RootKind kind, PersistentRooted<void*>* root)
559 : {
560 0 : rt->heapRoots.ref()[kind].insertBack(root);
561 0 : }
|