Bug 857690 - Introduce xpc::ZoneStatsExtras and xpc::CompartmentStatsExtras. r=njn
authorNils Maier <maierman@web.de>
Thu, 04 Apr 2013 11:55:56 -0400
changeset 127672 9be5069796d7e647001c77fe659c50b3fa28411c
parent 127671 12554c928f609720def90615003c0f04e99086a5
child 127673 d26881860f30ddce639b470694e63d62d477d7b0
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersnjn
bugs857690
milestone23.0a1
Bug 857690 - Introduce xpc::ZoneStatsExtras and xpc::CompartmentStatsExtras. r=njn
dom/workers/WorkerPrivate.cpp
js/public/MemoryMetrics.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcpublic.h
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1407,64 +1407,63 @@ class WorkerJSRuntimeStats : public JS::
 public:
   WorkerJSRuntimeStats(const nsACString& aRtPath)
   : JS::RuntimeStats(JsWorkerMallocSizeOf), mRtPath(aRtPath)
   { }
 
   ~WorkerJSRuntimeStats()
   {
     for (size_t i = 0; i != zoneStatsVector.length(); i++) {
-      free(zoneStatsVector[i].extra1);
+      delete static_cast<xpc::ZoneStatsExtras*>(zoneStatsVector[i].extra);
     }
 
     for (size_t i = 0; i != compartmentStatsVector.length(); i++) {
-      free(compartmentStatsVector[i].extra1);
-      // No need to free |extra2| because it's a static string.
+      delete static_cast<xpc::CompartmentStatsExtras*>(compartmentStatsVector[i].extra);
     }
   }
 
   virtual void
   initExtraZoneStats(JS::Zone* aZone,
                      JS::ZoneStats* aZoneStats)
                      MOZ_OVERRIDE
   {
-    MOZ_ASSERT(!aZoneStats->extra1);
+    MOZ_ASSERT(!aZoneStats->extra);
 
     // ReportJSRuntimeExplicitTreeStats expects that
-    // aZoneStats->extra1 is a char pointer.
-
-    nsAutoCString pathPrefix(mRtPath);
-    pathPrefix += nsPrintfCString("zone(%p)/", (void *)aZone);
-    aZoneStats->extra1 = strdup(pathPrefix.get());
+    // aZoneStats->extra is a xpc::ZoneStatsExtras pointer.
+    xpc::ZoneStatsExtras* extras = new xpc::ZoneStatsExtras;
+    extras->pathPrefix = mRtPath;
+    extras->pathPrefix += nsPrintfCString("zone(%p)/", (void *)aZone);
+    aZoneStats->extra = extras;
   }
 
   virtual void
   initExtraCompartmentStats(JSCompartment* aCompartment,
                             JS::CompartmentStats* aCompartmentStats)
                             MOZ_OVERRIDE
   {
-    MOZ_ASSERT(!aCompartmentStats->extra1);
-    MOZ_ASSERT(!aCompartmentStats->extra2);
+    MOZ_ASSERT(!aCompartmentStats->extra);
 
     // ReportJSRuntimeExplicitTreeStats expects that
-    // aCompartmentStats->{extra1,extra2} are char pointers.
-
-    // This is the |cJSPathPrefix|.  Each worker has exactly two compartments:
+    // aCompartmentStats->extra is a xpc::CompartmentStatsExtras pointer.
+    xpc::CompartmentStatsExtras* extras = new xpc::CompartmentStatsExtras;
+
+    // This is the |jsPathPrefix|.  Each worker has exactly two compartments:
     // one for atoms, and one for everything else.
-    nsAutoCString cJSPathPrefix(mRtPath);
-    cJSPathPrefix += nsPrintfCString("zone(%p)/",
-                                     (void *)js::GetCompartmentZone(aCompartment));
-    cJSPathPrefix += js::IsAtomsCompartment(aCompartment)
-                   ? NS_LITERAL_CSTRING("compartment(web-worker-atoms)/")
-                   : NS_LITERAL_CSTRING("compartment(web-worker)/");
-    aCompartmentStats->extra1 = strdup(cJSPathPrefix.get());
+    extras->jsPathPrefix.Assign(mRtPath);
+    extras->jsPathPrefix += nsPrintfCString("zone(%p)/",
+                                            (void *)js::GetCompartmentZone(aCompartment));
+    extras->jsPathPrefix += js::IsAtomsCompartment(aCompartment)
+                            ? NS_LITERAL_CSTRING("compartment(web-worker-atoms)/")
+                            : NS_LITERAL_CSTRING("compartment(web-worker)/");
 
     // This should never be used when reporting with workers (hence the "?!").
-    static const char bogusMemoryReporterPath[] = "explicit/workers/?!/";
-    aCompartmentStats->extra2 = const_cast<char*>(bogusMemoryReporterPath);
+    extras->domPathPrefix.AssignLiteral("explicit/workers/?!/");
+
+    aCompartmentStats->extra = extras;
   }
 };
 
 } /* anonymous namespace */
 
 #ifdef DEBUG
 void
 mozilla::dom::workers::AssertIsOnMainThread()
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -144,31 +144,31 @@ struct RuntimeSizes
     size_t scriptSources;
 
     CodeSizes code;
 };
 
 struct ZoneStats
 {
     ZoneStats()
-      : extra1(0),
+      : extra(NULL),
         gcHeapArenaAdmin(0),
         gcHeapUnusedGcThings(0),
         gcHeapStringsNormal(0),
         gcHeapStringsShort(0),
         gcHeapTypeObjects(0),
         gcHeapIonCodes(0),
         stringCharsNonHuge(0),
         typeObjects(0),
         typePool(0),
         hugeStrings()
     {}
 
     ZoneStats(const ZoneStats &other)
-      : extra1(other.extra1),
+      : extra(other.extra),
         gcHeapArenaAdmin(other.gcHeapArenaAdmin),
         gcHeapUnusedGcThings(other.gcHeapUnusedGcThings),
         gcHeapStringsNormal(other.gcHeapStringsNormal),
         gcHeapStringsShort(other.gcHeapStringsShort),
         gcHeapTypeObjects(other.gcHeapTypeObjects),
         gcHeapIonCodes(other.gcHeapIonCodes),
         stringCharsNonHuge(other.stringCharsNonHuge),
         typeObjects(other.typeObjects),
@@ -195,17 +195,17 @@ struct ZoneStats
         ADD(typePool);
 
         #undef ADD
 
         hugeStrings.append(other.hugeStrings);
     }
 
     // This field can be used by embedders.
-    void   *extra1;
+    void   *extra;
 
     size_t gcHeapArenaAdmin;
     size_t gcHeapUnusedGcThings;
 
     size_t gcHeapStringsNormal;
     size_t gcHeapStringsShort;
 
     size_t gcHeapTypeObjects;
@@ -220,18 +220,17 @@ struct ZoneStats
     // The size of all the live things in the GC heap that don't belong to any
     // compartment.
     size_t GCHeapThingsSize();
 };
 
 struct CompartmentStats
 {
     CompartmentStats()
-      : extra1(0),
-        extra2(0),
+      : extra(NULL),
         gcHeapObjectsOrdinary(0),
         gcHeapObjectsFunction(0),
         gcHeapObjectsDenseArray(0),
         gcHeapObjectsSlowArray(0),
         gcHeapObjectsCrossCompartmentWrapper(0),
         gcHeapShapesTreeGlobalParented(0),
         gcHeapShapesTreeNonGlobalParented(0),
         gcHeapShapesDict(0),
@@ -251,18 +250,17 @@ struct CompartmentStats
         compartmentObject(0),
         crossCompartmentWrappersTable(0),
         regexpCompartment(0),
         debuggeesSet(0),
         typeInference()
     {}
 
     CompartmentStats(const CompartmentStats &other)
-      : extra1(other.extra1),
-        extra2(other.extra2),
+      : extra(other.extra),
         gcHeapObjectsOrdinary(other.gcHeapObjectsOrdinary),
         gcHeapObjectsFunction(other.gcHeapObjectsFunction),
         gcHeapObjectsDenseArray(other.gcHeapObjectsDenseArray),
         gcHeapObjectsSlowArray(other.gcHeapObjectsSlowArray),
         gcHeapObjectsCrossCompartmentWrapper(other.gcHeapObjectsCrossCompartmentWrapper),
         gcHeapShapesTreeGlobalParented(other.gcHeapShapesTreeGlobalParented),
         gcHeapShapesTreeNonGlobalParented(other.gcHeapShapesTreeNonGlobalParented),
         gcHeapShapesDict(other.gcHeapShapesDict),
@@ -282,19 +280,18 @@ struct CompartmentStats
         compartmentObject(other.compartmentObject),
         crossCompartmentWrappersTable(other.crossCompartmentWrappersTable),
         regexpCompartment(other.regexpCompartment),
         debuggeesSet(other.debuggeesSet),
         typeInference(other.typeInference)
     {
     }
 
-    // These fields can be used by embedders.
-    void   *extra1;
-    void   *extra2;
+    // This field can be used by embedders.
+    void   *extra;
 
     // If you add a new number, remember to update the constructors, add(), and
     // maybe gcHeapThingsSize()!
     size_t gcHeapObjectsOrdinary;
     size_t gcHeapObjectsFunction;
     size_t gcHeapObjectsDenseArray;
     size_t gcHeapObjectsSlowArray;
     size_t gcHeapObjectsCrossCompartmentWrapper;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1591,20 +1591,21 @@ NS_MEMORY_REPORTER_IMPLEMENT(JSMainRunti
     } while (0)
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf)
 
 namespace xpc {
 
 static nsresult
 ReportZoneStats(const JS::ZoneStats &zStats,
-                const nsACString &pathPrefix,
+                const xpc::ZoneStatsExtras &extras,
                 nsIMemoryMultiReporterCallback *cb,
                 nsISupports *closure, size_t *gcTotalOut = NULL)
 {
+    const nsAutoCString& pathPrefix = extras.pathPrefix;
     size_t gcTotal = 0, gcHeapSundries = 0, otherSundries = 0;
 
     ZCREPORT_GC_BYTES(pathPrefix + NS_LITERAL_CSTRING("gc-heap/arena-admin"),
                       zStats.gcHeapArenaAdmin,
                       "Memory on the garbage-collected JavaScript "
                       "heap, within arenas, that is used (a) to hold internal "
                       "bookkeeping information, and (b) to provide padding to "
                       "align GC things.");
@@ -1705,22 +1706,23 @@ ReportZoneStats(const JS::ZoneStats &zSt
     if (gcTotalOut)
         *gcTotalOut += gcTotal;
 
     return NS_OK;
 }
 
 static nsresult
 ReportCompartmentStats(const JS::CompartmentStats &cStats,
-                       const nsACString &cJSPathPrefix,
-                       const nsACString &cDOMPathPrefix,
+                       const xpc::CompartmentStatsExtras &extras,
                        nsIMemoryMultiReporterCallback *cb,
                        nsISupports *closure, size_t *gcTotalOut = NULL)
 {
     size_t gcTotal = 0, gcHeapSundries = 0, otherSundries = 0;
+    const nsACString& cJSPathPrefix = extras.jsPathPrefix;
+    const nsACString& cDOMPathPrefix = extras.domPathPrefix;
 
     ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/objects/ordinary"),
                       cStats.gcHeapObjectsOrdinary,
                       "Memory on the garbage-collected JavaScript "
                       "heap that holds ordinary (i.e. not otherwise distinguished "
                       "my memory reporters) objects.");
 
     ZCREPORT_GC_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("gc-heap/objects/function"),
@@ -1951,28 +1953,27 @@ ReportJSRuntimeExplicitTreeStats(const J
                                  nsISupports *closure, size_t *rtTotalOut)
 {
     nsresult rv;
 
     size_t gcTotal = 0;
 
     for (size_t i = 0; i < rtStats.zoneStatsVector.length(); i++) {
         JS::ZoneStats zStats = rtStats.zoneStatsVector[i];
-        nsCString path(static_cast<char *>(zStats.extra1));
-
-        rv = ReportZoneStats(zStats, path, cb, closure, &gcTotal);
+        const xpc::ZoneStatsExtras *extras =
+          static_cast<const xpc::ZoneStatsExtras*>(zStats.extra);
+        rv = ReportZoneStats(zStats, *extras, cb, closure, &gcTotal);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     for (size_t i = 0; i < rtStats.compartmentStatsVector.length(); i++) {
         JS::CompartmentStats cStats = rtStats.compartmentStatsVector[i];
-        nsCString cJSPathPrefix(static_cast<char *>(cStats.extra1));
-        nsCString cDOMPathPrefix(static_cast<char *>(cStats.extra2));
-
-        rv = ReportCompartmentStats(cStats, cJSPathPrefix, cDOMPathPrefix, cb, closure, &gcTotal);
+        const xpc::CompartmentStatsExtras *extras =
+            static_cast<const xpc::CompartmentStatsExtras*>(cStats.extra);
+        rv = ReportCompartmentStats(cStats, *extras, cb, closure, &gcTotal);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // Report the rtStats.runtime numbers under "runtime/", and compute their
     // total for later.
 
     size_t rtTotal = 0;
 
@@ -2217,104 +2218,106 @@ class XPCJSRuntimeStats : public JS::Run
     WindowPaths *mTopWindowPaths;
 
   public:
     XPCJSRuntimeStats(WindowPaths *windowPaths, WindowPaths *topWindowPaths)
       : JS::RuntimeStats(JsMallocSizeOf), mWindowPaths(windowPaths), mTopWindowPaths(topWindowPaths)
     {}
 
     ~XPCJSRuntimeStats() {
-        for (size_t i = 0; i != compartmentStatsVector.length(); ++i) {
-            free(compartmentStatsVector[i].extra1);
-            free(compartmentStatsVector[i].extra2);
-        }
+        for (size_t i = 0; i != compartmentStatsVector.length(); ++i)
+            delete static_cast<xpc::CompartmentStatsExtras*>(compartmentStatsVector[i].extra);
+
 
         for (size_t i = 0; i != zoneStatsVector.length(); ++i)
-            free(zoneStatsVector[i].extra1);
+            delete static_cast<xpc::ZoneStatsExtras*>(zoneStatsVector[i].extra);
     }
 
     virtual void initExtraZoneStats(JS::Zone *zone, JS::ZoneStats *zStats) MOZ_OVERRIDE {
         // Get the compartment's global.
         nsXPConnect *xpc = nsXPConnect::GetXPConnect();
         JSContext *cx = xpc->GetSafeJSContext();
         JSCompartment *comp = js::GetAnyCompartmentInZone(zone);
-        nsCString pathPrefix("explicit/js-non-window/zones/");
+        xpc::ZoneStatsExtras *extras = new xpc::ZoneStatsExtras;
+        extras->pathPrefix.AssignLiteral("explicit/js-non-window/zones/");
         if (JSObject *global = JS_GetGlobalForCompartmentOrNull(cx, comp)) {
             // Need to enter the compartment, otherwise GetNativeOfWrapper()
             // might crash.
             JSAutoCompartment ac(cx, global);
             nsISupports *native = xpc->GetNativeOfWrapper(cx, global);
             if (nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(native)) {
                 // The global is a |window| object.  Use the path prefix that
                 // we should have already created for it.
-                if (mTopWindowPaths->Get(piwindow->WindowID(), &pathPrefix))
-                    pathPrefix.AppendLiteral("/js-");
+                if (mTopWindowPaths->Get(piwindow->WindowID(),
+                                         &extras->pathPrefix))
+                    extras->pathPrefix.AppendLiteral("/js-");
             }
         }
 
-        pathPrefix += nsPrintfCString("zone(%p)/", (void *)zone);
-
-        zStats->extra1 = strdup(pathPrefix.get());
+        extras->pathPrefix += nsPrintfCString("zone(%p)/", (void *)zone);
+
+        zStats->extra = extras;
     }
 
     virtual void initExtraCompartmentStats(JSCompartment *c,
                                            JS::CompartmentStats *cstats) MOZ_OVERRIDE
     {
-        nsAutoCString cJSPathPrefix, cDOMPathPrefix;
+        xpc::CompartmentStatsExtras *extras = new xpc::CompartmentStatsExtras;
         nsCString cName;
         GetCompartmentName(c, cName, true);
 
         // Get the compartment's global.
         nsXPConnect *xpc = nsXPConnect::GetXPConnect();
         JSContext *cx = xpc->GetSafeJSContext();
         bool needZone = true;
         if (JSObject *global = JS_GetGlobalForCompartmentOrNull(cx, c)) {
             // Need to enter the compartment, otherwise GetNativeOfWrapper()
             // might crash.
             JSAutoCompartment ac(cx, global);
             nsISupports *native = xpc->GetNativeOfWrapper(cx, global);
             if (nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(native)) {
                 // The global is a |window| object.  Use the path prefix that
                 // we should have already created for it.
-                if (mWindowPaths->Get(piwindow->WindowID(), &cJSPathPrefix)) {
-                    cDOMPathPrefix.Assign(cJSPathPrefix);
-                    cDOMPathPrefix.AppendLiteral("/dom/");
-                    cJSPathPrefix.AppendLiteral("/js-");
+                if (mWindowPaths->Get(piwindow->WindowID(),
+                                      &extras->jsPathPrefix)) {
+                    extras->domPathPrefix.Assign(extras->jsPathPrefix);
+                    extras->domPathPrefix.AppendLiteral("/dom/");
+                    extras->jsPathPrefix.AppendLiteral("/js-");
                     needZone = false;
                 } else {
-                    cJSPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
-                    cDOMPathPrefix.AssignLiteral("explicit/dom/unknown-window-global?!/");
+                    extras->jsPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
+                    extras->domPathPrefix.AssignLiteral("explicit/dom/unknown-window-global?!/");
                 }
             } else {
-                cJSPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
-                cDOMPathPrefix.AssignLiteral("explicit/dom/non-window-global?!/");
+                extras->jsPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
+                extras->domPathPrefix.AssignLiteral("explicit/dom/non-window-global?!/");
             }
         } else {
-            cJSPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
-            cDOMPathPrefix.AssignLiteral("explicit/dom/no-global?!/");
+            extras->jsPathPrefix.AssignLiteral("explicit/js-non-window/zones/");
+            extras->domPathPrefix.AssignLiteral("explicit/dom/no-global?!/");
         }
 
         if (needZone)
-            cJSPathPrefix += nsPrintfCString("zone(%p)/", (void *)js::GetCompartmentZone(c));
-
-        cJSPathPrefix += NS_LITERAL_CSTRING("compartment(") + cName + NS_LITERAL_CSTRING(")/");
-
-        // cJSPathPrefix is used for almost all the compartment-specific
-        // reports.  At this point it has the form
-        // "<something>/compartment/(<cname>)/".
+            extras->jsPathPrefix += nsPrintfCString("zone(%p)/", (void *)js::GetCompartmentZone(c));
+
+        extras->jsPathPrefix += NS_LITERAL_CSTRING("compartment(") + cName + NS_LITERAL_CSTRING(")/");
+
+        // extras->jsPathPrefix is used for almost all the compartment-specific
+        // reports. At this point it has the form
+        // "<something>compartment(<cname>)/".
         //
-        // cDOMPathPrefix is used for DOM orphan nodes, which are counted by
-        // the JS multi-reporter but reported as part of the DOM measurements.
-        // At this point it has the form "<something>/dom/" if this compartment
-        // belongs to an nsGlobalWindow, and "explicit/dom/?!/" otherwise (in
-        // which case it shouldn't be used, because non-nsGlobalWindow
-        // compartments shouldn't have orphan DOM nodes).
-
-        cstats->extra1 = strdup(cJSPathPrefix.get());
-        cstats->extra2 = strdup(cDOMPathPrefix.get());
+        // extras->domPathPrefix is used for DOM orphan nodes, which are
+        // counted by the JS multi-reporter but reported as part of the
+        // DOM measurements. At this point it has the form "<something>/dom/"
+        // if this compartment belongs to an nsGlobalWindow, and
+        // "explicit/dom/<something>?!/" otherwise (in which case it shouldn't
+        // be used, because non-nsGlobalWindow compartments shouldn't have
+        // orphan DOM nodes).
+
+        cstats->extra = extras;
     }
 };
 
 nsresult
 JSMemoryMultiReporter::CollectReports(WindowPaths *windowPaths,
                                       WindowPaths *topWindowPaths,
                                       nsIMemoryMultiReporterCallback *cb,
                                       nsISupports *closure)
@@ -2342,23 +2345,25 @@ JSMemoryMultiReporter::CollectReports(Wi
     nsresult rv;
     size_t rtTotal = 0;
     rv = xpc::ReportJSRuntimeExplicitTreeStats(rtStats,
                                                NS_LITERAL_CSTRING("explicit/js-non-window/"),
                                                cb, closure, &rtTotal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Report the sums of the compartment numbers.
-    rv = ReportCompartmentStats(rtStats.cTotals,
-                                NS_LITERAL_CSTRING("js-main-runtime/compartments/"),
-                                NS_LITERAL_CSTRING("window-objects/dom/"),
-                                cb, closure);
-    rv = ReportZoneStats(rtStats.zTotals,
-                         NS_LITERAL_CSTRING("js-main-runtime/zones/"),
-                         cb, closure);
+    xpc::CompartmentStatsExtras cExtrasTotal;
+    cExtrasTotal.jsPathPrefix.AssignLiteral("js-main-runtime/compartments/");
+    cExtrasTotal.domPathPrefix.AssignLiteral("window-objects/dom/");
+    rv = ReportCompartmentStats(rtStats.cTotals, cExtrasTotal, cb, closure);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    xpc::ZoneStatsExtras zExtrasTotal;
+    zExtrasTotal.pathPrefix.AssignLiteral("js-main-runtime/zones/");
+    rv = ReportZoneStats(rtStats.zTotals, zExtrasTotal, cb, closure);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Report the sum of the runtime/ numbers.
     REPORT_BYTES(NS_LITERAL_CSTRING("js-main-runtime/runtime"),
                  nsIMemoryReporter::KIND_OTHER, rtTotal,
                  "The sum of all measurements under 'explicit/js-non-window/runtime/'.");
 
     // Report the numbers for memory outside of compartments.
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -383,18 +383,50 @@ void SetLocationForGlobal(JSObject *glob
  * @param interfaceArray
  *     The interfaces the class implements; interfaceArray and
  *     interfaceCount are like what nsIClassInfo.getInterfaces returns.
  */
 bool
 DOM_DefineQuickStubs(JSContext *cx, JSObject *proto, uint32_t flags,
                      uint32_t interfaceCount, const nsIID **interfaceArray);
 
+
+// ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member
+// of JS::ZoneStats.
+class ZoneStatsExtras {
+public:
+    ZoneStatsExtras()
+    {}
+
+    nsAutoCString pathPrefix;
+
+private:
+    ZoneStatsExtras(const ZoneStatsExtras &other) MOZ_DELETE;
+    ZoneStatsExtras& operator=(const ZoneStatsExtras &other) MOZ_DELETE;
+};
+
+// ReportJSRuntimeExplicitTreeStats will expect this in the |extra| member
+// of JS::CompartmentStats.
+class CompartmentStatsExtras {
+public:
+    CompartmentStatsExtras()
+    {}
+
+    nsAutoCString jsPathPrefix;
+    nsAutoCString domPathPrefix;
+
+private:
+    CompartmentStatsExtras(const CompartmentStatsExtras &other) MOZ_DELETE;
+    CompartmentStatsExtras& operator=(const CompartmentStatsExtras &other) MOZ_DELETE;
+};
+
 // This reports all the stats in |rtStats| that belong in the "explicit" tree,
 // (which isn't all of them).
+// @see ZoneStatsExtras
+// @see CompartmentStatsExtras
 nsresult
 ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
                                  const nsACString &rtPath,
                                  nsIMemoryMultiReporterCallback *cb,
                                  nsISupports *closure, size_t *rtTotal = NULL);
 
 /**
  * Throws an exception on cx and returns false.