--- a/xpcom/base/CycleCollectedJSContext.cpp
+++ b/xpcom/base/CycleCollectedJSContext.cpp
@@ -122,21 +122,39 @@ public:
void ReleaseNow(bool aLimited);
NS_DECL_NSIRUNNABLE
};
} // namespace mozilla
-struct NoteWeakMapChildrenTracer : public JS::CallbackTracer
+struct CCJSTracer : public JS::CallbackTracer
{
- NoteWeakMapChildrenTracer(JSContext* aCx,
+protected:
+ CCJSTracer(CycleCollectedJSContext* aCx,
+ WeakMapTraceKind aWeakTraceKind = TraceWeakMapValues)
+ : JS::CallbackTracer(aCx->Context(), aWeakTraceKind)
+ , mCx(aCx)
+ {}
+
+public:
+ void TraceChildren(JS::GCCellPtr aThing)
+ {
+ mCx->TraceJSChildren(this, aThing);
+ }
+
+ CycleCollectedJSContext* mCx;
+};
+
+struct NoteWeakMapChildrenTracer : public CCJSTracer
+{
+ NoteWeakMapChildrenTracer(CycleCollectedJSContext* aCx,
nsCycleCollectionNoteRootCallback& aCb)
- : JS::CallbackTracer(aCx), mCb(aCb), mTracedAny(false), mMap(nullptr),
+ : CCJSTracer(aCx), mCb(aCb), mTracedAny(false), mMap(nullptr),
mKey(nullptr), mKeyDelegate(nullptr)
{
}
void onChild(const JS::GCCellPtr& aThing) override;
nsCycleCollectionNoteRootCallback& mCb;
bool mTracedAny;
JSObject* mMap;
JS::GCCellPtr mKey;
@@ -153,24 +171,25 @@ NoteWeakMapChildrenTracer::onChild(const
if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) {
return;
}
if (AddToCCKind(aThing.kind())) {
mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing);
mTracedAny = true;
} else {
- JS::TraceChildren(this, aThing);
+ TraceChildren(aThing);
}
}
struct NoteWeakMapsTracer : public js::WeakMapTracer
{
- NoteWeakMapsTracer(JSContext* aCx, nsCycleCollectionNoteRootCallback& aCccb)
- : js::WeakMapTracer(aCx), mCb(aCccb), mChildTracer(aCx, aCccb)
+ NoteWeakMapsTracer(CycleCollectedJSContext* aCx,
+ nsCycleCollectionNoteRootCallback& aCccb)
+ : js::WeakMapTracer(aCx->Context()), mCb(aCccb), mChildTracer(aCx, aCccb)
{
}
void trace(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr aValue) override;
nsCycleCollectionNoteRootCallback& mCb;
NoteWeakMapChildrenTracer mChildTracer;
};
void
@@ -208,17 +227,17 @@ NoteWeakMapsTracer::trace(JSObject* aMap
mCb.NoteWeakMapping(aMap, aKey, kdelegate, aValue);
} else {
mChildTracer.mTracedAny = false;
mChildTracer.mMap = aMap;
mChildTracer.mKey = aKey;
mChildTracer.mKeyDelegate = kdelegate;
if (!aValue.is<JSString>()) {
- JS::TraceChildren(&mChildTracer, aValue);
+ mChildTracer.TraceChildren(aValue);
}
// The delegate could hold alive the key, so report something to the CC
// if we haven't already.
if (!mChildTracer.mTracedAny &&
aKey && JS::GCThingIsMarkedGray(aKey) && kdelegate) {
mCb.NoteWeakMapping(aMap, aKey, kdelegate, nullptr);
}
@@ -319,22 +338,23 @@ JSZoneParticipant::Traverse(void* aPtr,
MOZ_ASSERT(!aCb.WantAllTraces());
JS::Zone* zone = static_cast<JS::Zone*>(aPtr);
runtime->TraverseZone(zone, aCb);
return NS_OK;
}
-struct TraversalTracer : public JS::CallbackTracer
+struct TraversalTracer : public CCJSTracer
{
- TraversalTracer(JSContext* aCx, nsCycleCollectionTraversalCallback& aCb)
- : JS::CallbackTracer(aCx, DoNotTraceWeakMaps), mCb(aCb)
- {
- }
+ TraversalTracer(CycleCollectedJSContext* aCx,
+ nsCycleCollectionTraversalCallback& aCb)
+ : CCJSTracer(aCx, DoNotTraceWeakMaps)
+ , mCb(aCb)
+ {}
void onChild(const JS::GCCellPtr& aThing) override;
nsCycleCollectionTraversalCallback& mCb;
};
void
TraversalTracer::onChild(const JS::GCCellPtr& aThing)
{
// Don't traverse non-gray objects, unless we want all traces.
@@ -361,17 +381,17 @@ TraversalTracer::onChild(const JS::GCCel
// the parent pointers on the shape.
JS_TraceShapeCycleCollectorChildren(this, aThing);
} else if (aThing.is<js::ObjectGroup>()) {
// The maximum depth of traversal when tracing an ObjectGroup is unbounded,
// due to information attached to the groups which can lead other groups to
// be traced.
JS_TraceObjectGroupCycleCollectorChildren(this, aThing);
} else if (!aThing.is<JSString>()) {
- JS::TraceChildren(this, aThing);
+ TraceChildren(aThing);
}
}
static void
NoteJSChildGrayWrapperShim(void* aData, JS::GCCellPtr aThing)
{
TraversalTracer* trc = static_cast<TraversalTracer*>(aData);
trc->onChild(aThing);
@@ -623,21 +643,21 @@ CycleCollectedJSContext::DescribeGCThing
}
// Disable printing global for objects while we figure out ObjShrink fallout.
aCb.DescribeGCedNode(aIsMarked, name, compartmentAddress);
}
void
CycleCollectedJSContext::NoteGCThingJSChildren(JS::GCCellPtr aThing,
- nsCycleCollectionTraversalCallback& aCb) const
+ nsCycleCollectionTraversalCallback& aCb)
{
MOZ_ASSERT(mJSContext);
- TraversalTracer trc(mJSContext, aCb);
- JS::TraceChildren(&trc, aThing);
+ TraversalTracer trc(this, aCb);
+ trc.TraceChildren(aThing);
}
void
CycleCollectedJSContext::NoteGCThingXPCOMChildren(const js::Class* aClasp,
JSObject* aObj,
nsCycleCollectionTraversalCallback& aCb) const
{
MOZ_ASSERT(aClasp);
@@ -726,17 +746,17 @@ CycleCollectedJSContext::TraverseZone(JS
/*
* Every JS child of everything in the zone is either in the zone
* or is a cross-compartment wrapper. In the former case, we don't need to
* represent these edges in the CC graph because JS objects are not ref counted.
* In the latter case, the JS engine keeps a map of these wrappers, which we
* iterate over. Edges between compartments in the same zone will add
* unnecessary loop edges to the graph (bug 842137).
*/
- TraversalTracer trc(mJSContext, aCb);
+ TraversalTracer trc(this, aCb);
js::VisitGrayWrapperTargets(aZone, NoteJSChildGrayWrapperShim, &trc);
/*
* To find C++ children of things in the zone, we scan every JS Object in
* the zone. Only JS Objects can have C++ children.
*/
TraverseObjectShimClosure closure = { aCb, this };
js::IterateGrayObjects(aZone, TraverseObjectShim, &closure);
@@ -1205,17 +1225,17 @@ CycleCollectedJSContext::ZoneParticipant
nsresult
CycleCollectedJSContext::TraverseRoots(nsCycleCollectionNoteRootCallback& aCb)
{
MOZ_ASSERT(mJSContext);
TraverseNativeRoots(aCb);
- NoteWeakMapsTracer trc(mJSContext, aCb);
+ NoteWeakMapsTracer trc(this, aCb);
js::TraceWeakMaps(&trc);
return NS_OK;
}
bool
CycleCollectedJSContext::UsefulToMergeZones() const
{
@@ -1673,16 +1693,22 @@ CycleCollectedJSContext::OnLargeAllocati
MOZ_ASSERT(mJSContext);
AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reporting);
CustomLargeAllocationFailureCallback();
AnnotateAndSetOutOfMemory(&mLargeAllocationFailureState, OOMState::Reported);
}
void
+CycleCollectedJSContext::TraceJSChildren(JSTracer* aTrc, JS::GCCellPtr aThing)
+{
+ JS::TraceChildren(aTrc, aThing);
+}
+
+void
CycleCollectedJSContext::PrepareWaitingZonesForGC()
{
if (mZonesWaitingForGC.Count() == 0) {
JS::PrepareForFullGC(Context());
} else {
for (auto iter = mZonesWaitingForGC.Iter(); !iter.Done(); iter.Next()) {
JS::PrepareZoneForGC(iter.Get()->GetKey());
}
--- a/xpcom/base/CycleCollectedJSContext.h
+++ b/xpcom/base/CycleCollectedJSContext.h
@@ -170,17 +170,17 @@ private:
DescribeCustomObjects(JSObject* aObject, const js::Class* aClasp,
char (&aName)[72]) const
{
return false; // We did nothing.
}
void
NoteGCThingJSChildren(JS::GCCellPtr aThing,
- nsCycleCollectionTraversalCallback& aCb) const;
+ nsCycleCollectionTraversalCallback& aCb);
void
NoteGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj,
nsCycleCollectionTraversalCallback& aCb) const;
virtual bool
NoteCustomGCThingXPCOMChildren(const js::Class* aClasp, JSObject* aObj,
nsCycleCollectionTraversalCallback& aCb) const
@@ -389,16 +389,18 @@ public:
static CycleCollectedJSContext* Get();
// Add aZone to the set of zones waiting for a GC.
void AddZoneWaitingForGC(JS::Zone* aZone)
{
mZonesWaitingForGC.PutEntry(aZone);
}
+ void TraceJSChildren(JSTracer* aTrc, JS::GCCellPtr aThing);
+
// Prepare any zones for GC that have been passed to AddZoneWaitingForGC()
// since the last GC or since the last call to PrepareWaitingZonesForGC(),
// whichever was most recent. If there were no such zones, prepare for a
// full GC.
void PrepareWaitingZonesForGC();
// Queue an async microtask to the current main or worker thread.
virtual void DispatchToMicroTask(already_AddRefed<nsIRunnable> aRunnable);