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