Bug 1460636 - Don't trace jsids on ObjectGroup in the cycle collector. r=jonco,sfink
authorAndrew McCreight <continuation@gmail.com>
Fri, 11 May 2018 11:38:58 -0700
changeset 794492 39c076bf5d77fa66c37d37e6fd6e94a68c493756
parent 794491 30f281e6cd1f5641fe3f2bb468820916c1d8caf2
child 794493 6e55646aad4a8e3ff48167d60beb7c5a8b41be38
push id109697
push userbmo:sledru@mozilla.com
push dateSat, 12 May 2018 10:04:34 +0000
reviewersjonco, sfink
bugs1460636
milestone62.0a1
Bug 1460636 - Don't trace jsids on ObjectGroup in the cycle collector. r=jonco,sfink For some reason, the CC spends a lot of time tracing jsids on ObjectGroups when an addon is installed. This patch avoids that by adding a canSkipJsids flag to JSTracer, and using it in ObjectGroup::traceChildren. If this is true, then the tracer is free to not report every jsid. This flag is set to true for the two CC tracers. MozReview-Commit-ID: CWFqQEr0SxV
js/public/TracingAPI.h
js/src/gc/Marking.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -81,16 +81,17 @@ class JS_PUBLIC_API(JSTracer)
         Callback
     };
     bool isMarkingTracer() const { return tag_ == TracerKindTag::Marking || tag_ == TracerKindTag::WeakMarking; }
     bool isWeakMarkingTracer() const { return tag_ == TracerKindTag::WeakMarking; }
     bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; }
     bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; }
     inline JS::CallbackTracer* asCallbackTracer();
     bool traceWeakEdges() const { return traceWeakEdges_; }
+    bool canSkipJsids() const { return canSkipJsids_; }
 #ifdef DEBUG
     bool checkEdges() { return checkEdges_; }
 #endif
 
     // Get the current GC number. Only call this method if |isMarkingTracer()|
     // is true.
     uint32_t gcNumberForMarking() const;
 
@@ -99,16 +100,17 @@ class JS_PUBLIC_API(JSTracer)
              WeakMapTraceKind weakTraceKind = TraceWeakMapValues)
       : runtime_(rt)
       , weakMapAction_(weakTraceKind)
 #ifdef DEBUG
       , checkEdges_(true)
 #endif
       , tag_(tag)
       , traceWeakEdges_(true)
+      , canSkipJsids_(false)
     {}
 
 #ifdef DEBUG
     // Set whether to check edges are valid in debug builds.
     void setCheckEdges(bool check) {
         checkEdges_ = check;
     }
 #endif
@@ -118,16 +120,17 @@ class JS_PUBLIC_API(JSTracer)
     WeakMapTraceKind weakMapAction_;
 #ifdef DEBUG
     bool checkEdges_;
 #endif
 
   protected:
     TracerKindTag tag_;
     bool traceWeakEdges_;
+    bool canSkipJsids_;
 };
 
 namespace JS {
 
 class AutoTracingName;
 class AutoTracingIndex;
 class AutoTracingCallback;
 
@@ -249,16 +252,22 @@ class JS_PUBLIC_API(CallbackTracer) : pu
     void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); }
     void dispatchToOnEdge(js::RegExpShared** sharedp) { onRegExpSharedEdge(sharedp); }
 
   protected:
     void setTraceWeakEdges(bool value) {
         traceWeakEdges_ = value;
     }
 
+    // If this is set to false, then the tracer will skip some jsids
+    // to improve performance. This is needed for the cycle collector.
+    void setCanSkipJsids(bool value) {
+        canSkipJsids_ = value;
+    }
+
   private:
     friend class AutoTracingName;
     const char* contextName_;
 
     friend class AutoTracingIndex;
     size_t contextIndex_;
 
     friend class AutoTracingDetails;
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1465,20 +1465,23 @@ js::GCMarker::eagerlyMarkChildren(Scope*
             traverseEdge(scope, static_cast<JSString*>(names[i].name()));
     }
 }
 
 void
 js::ObjectGroup::traceChildren(JSTracer* trc)
 {
     AutoSweepObjectGroup sweep(this);
-    unsigned count = getPropertyCount(sweep);
-    for (unsigned i = 0; i < count; i++) {
-        if (ObjectGroup::Property* prop = getProperty(sweep, i))
-            TraceEdge(trc, &prop->id, "group_property");
+
+    if (!trc->canSkipJsids()) {
+        unsigned count = getPropertyCount(sweep);
+        for (unsigned i = 0; i < count; i++) {
+            if (ObjectGroup::Property* prop = getProperty(sweep, i))
+                TraceEdge(trc, &prop->id, "group_property");
+        }
     }
 
     if (proto().isObject())
         TraceEdge(trc, &proto(), "group_proto");
 
     if (trc->isMarkingTracer())
         compartment()->mark();
 
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -138,16 +138,17 @@ public:
 
 struct NoteWeakMapChildrenTracer : public JS::CallbackTracer
 {
   NoteWeakMapChildrenTracer(JSRuntime* aRt,
                             nsCycleCollectionNoteRootCallback& aCb)
     : JS::CallbackTracer(aRt), mCb(aCb), mTracedAny(false), mMap(nullptr),
       mKey(nullptr), mKeyDelegate(nullptr)
   {
+    setCanSkipJsids(true);
   }
   void onChild(const JS::GCCellPtr& aThing) override;
   nsCycleCollectionNoteRootCallback& mCb;
   bool mTracedAny;
   JSObject* mMap;
   JS::GCCellPtr mKey;
   JSObject* mKeyDelegate;
 };
@@ -394,16 +395,17 @@ JSZoneParticipant::TraverseNative(void* 
   return NS_OK;
 }
 
 struct TraversalTracer : public JS::CallbackTracer
 {
   TraversalTracer(JSRuntime* aRt, nsCycleCollectionTraversalCallback& aCb)
     : JS::CallbackTracer(aRt, DoNotTraceWeakMaps), mCb(aCb)
   {
+    setCanSkipJsids(true);
   }
   void onChild(const JS::GCCellPtr& aThing) override;
   nsCycleCollectionTraversalCallback& mCb;
 };
 
 void
 TraversalTracer::onChild(const JS::GCCellPtr& aThing)
 {