Bug 1301301, part 4 - Make calls to JS::TraceChildren go through a single method on CCJSContext. r=smaug
☠☠ backed out by d217f8dd78d6 ☠ ☠
authorAndrew McCreight <continuation@gmail.com>
Mon, 26 Sep 2016 10:19:07 -0700
changeset 315393 6186eae0c2b78f1bbfc9e450dacac6db4bf8e7e0
parent 315392 45fb9c1ce63a643916ccf0b4bcd0364970392cb8
child 315394 da70c5abd73a184954fde0bef6f01f9c0208e01d
push id82153
push useramccreight@mozilla.com
push dateTue, 27 Sep 2016 20:17:48 +0000
treeherdermozilla-inbound@da70c5abd73a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1301301
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);
@@ -625,21 +645,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);
@@ -728,17 +748,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);
@@ -1207,17 +1227,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
 {
@@ -1675,16 +1695,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
@@ -171,17 +171,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
@@ -390,16 +390,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);