Bug 1301301, part 4 - Make calls to JS::TraceChildren go through a single method on CCJSContext. r=smaug draft
authorAndrew McCreight <continuation@gmail.com>
Tue, 20 Sep 2016 11:10:02 -0700
changeset 417104 21ddb51f72fe3271d9cc3684fe763ca4abe14f18
parent 416239 de59145ee9354492529e69aa3cfea749827df0dc
child 417105 23d451b4cf6f0fa67e0805bad6f2e2bbbec3b607
push id30342
push userbmo:continuation@gmail.com
push dateFri, 23 Sep 2016 17:39:31 +0000
reviewerssmaug
bugs1301301
milestone52.0a1
Bug 1301301, part 4 - Make calls to JS::TraceChildren go through a single method on CCJSContext. r=smaug In this patch I add a new tracer base class, CCJSTracer, and make all of the code in CycleCollectedJSContext that used to do JS::TraceChildren depend on it. This will let me record the number of calls to JS::TraceChildren in one place, in a later patch. This should not change any behavior. MozReview-Commit-ID: LdDu5rnpvX0
xpcom/base/CycleCollectedJSContext.cpp
xpcom/base/CycleCollectedJSContext.h
--- 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);