LCOV - code coverage report
Current view: top level - js/src/gc - RootMarking.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 19 222 8.6 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
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             : #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         142 :     for (RealmsIter r(rt); !r.done(); r.next())
     386          67 :         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             : }

Generated by: LCOV version 1.13-14-ga5dd952