LCOV - code coverage report
Current view: top level - js/src/gc - RootMarking.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 150 236 63.6 %
Date: 2017-07-14 16:53:18 Functions: 54 79 68.4 %
Legend: Lines: hit not hit

          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 : }

Generated by: LCOV version 1.13