Bug 714264 - Part b: Move CompartmentStats to MemoryMetrics.h; r=njn
authorMs2ger <ms2ger@gmail.com>
Wed, 11 Jan 2012 09:23:08 +0100
changeset 84167 b9077aadd3d745c00159ac95aedc2402d94c7d39
parent 84166 6324ddbe266839db9a2395a13064857e20f44940
child 84168 2e7afd15d01a48fcdd692fc8543c9d1541ac25bf
push id21829
push userMs2ger@gmail.com
push dateWed, 11 Jan 2012 08:25:20 +0000
treeherdermozilla-central@c42d08fdec34 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs714264
milestone12.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 714264 - Part b: Move CompartmentStats to MemoryMetrics.h; r=njn The name member is implemented as a void*, because it needs to remain an nsCString, and as such the logic to get the name also remains in XPConnect.
js/public/MemoryMetrics.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcpublic.h
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -37,31 +37,86 @@
 #ifndef js_MemoryMetrics_h
 #define js_MemoryMetrics_h
 
 /*
  * These declarations are not within jsapi.h because they are highly likely
  * to change in the future. Depend on them at your own risk.
  */
 
+#include <string.h>
+
 #include "jspubtd.h"
 
 #include "js/Utility.h"
 
 namespace JS {
 
 /* Data for tracking analysis/inference memory usage. */
 struct TypeInferenceMemoryStats
 {
     int64_t scripts;
     int64_t objects;
     int64_t tables;
     int64_t temporary;
 };
 
+typedef void (* DestroyNameCallback)(void *string);
+
+struct CompartmentStats
+{
+    CompartmentStats()
+    {
+        memset(this, 0, sizeof(*this));
+    }
+
+    void init(void *name_, DestroyNameCallback destroyName)
+    {
+        name = name_;
+        destroyNameCb = destroyName;
+    }
+
+    ~CompartmentStats()
+    {
+        destroyNameCb(name);
+    }
+
+    // Pointer to an nsCString, which we can't use here.
+    void *name;
+    DestroyNameCallback destroyNameCb;
+
+    int64_t gcHeapArenaHeaders;
+    int64_t gcHeapArenaPadding;
+    int64_t gcHeapArenaUnused;
+
+    int64_t gcHeapObjectsNonFunction;
+    int64_t gcHeapObjectsFunction;
+    int64_t gcHeapStrings;
+    int64_t gcHeapShapesTree;
+    int64_t gcHeapShapesDict;
+    int64_t gcHeapShapesBase;
+    int64_t gcHeapScripts;
+    int64_t gcHeapTypeObjects;
+    int64_t gcHeapXML;
+
+    int64_t objectSlots;
+    int64_t stringChars;
+    int64_t shapesExtraTreeTables;
+    int64_t shapesExtraDictTables;
+    int64_t shapesExtraTreeShapeKids;
+    int64_t shapesCompartmentTables;
+    int64_t scriptData;
+
+#ifdef JS_METHODJIT
+    int64_t mjitCode;
+    int64_t mjitData;
+#endif
+    TypeInferenceMemoryStats typeInferenceMemory;
+};
+
 extern JS_PUBLIC_API(void)
 SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
                                    TypeInferenceMemoryStats *stats,
                                    JSMallocSizeOfFun mallocSizeOf);
 
 extern JS_PUBLIC_API(void)
 SizeOfObjectTypeInferenceData(/*TypeObject*/ void *object,
                               TypeInferenceMemoryStats *stats,
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -192,16 +192,22 @@ AutoSwitchCompartment::~AutoSwitchCompar
 
 JS_FRIEND_API(bool)
 js::IsSystemCompartment(const JSCompartment *c)
 {
     return c->isSystemCompartment;
 }
 
 JS_FRIEND_API(bool)
+js::IsAtomsCompartmentFor(const JSContext *cx, const JSCompartment *c)
+{
+    return c == cx->runtime->atomsCompartment;
+}
+
+JS_FRIEND_API(bool)
 js::IsScopeObject(JSObject *obj)
 {
     return obj->isScope();
 }
 
 JS_FRIEND_API(JSObject *)
 js::GetObjectParentMaybeScope(JSObject *obj)
 {
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -191,16 +191,19 @@ class JS_FRIEND_API(AutoSwitchCompartmen
 #ifdef OLD_GETTER_SETTER_METHODS
 JS_FRIEND_API(JSBool) obj_defineGetter(JSContext *cx, uintN argc, js::Value *vp);
 JS_FRIEND_API(JSBool) obj_defineSetter(JSContext *cx, uintN argc, js::Value *vp);
 #endif
 
 extern JS_FRIEND_API(bool)
 IsSystemCompartment(const JSCompartment *compartment);
 
+extern JS_FRIEND_API(bool)
+IsAtomsCompartmentFor(const JSContext *cx, const JSCompartment *c);
+
 /*
  * Check whether it is OK to assign an undeclared property with name
  * propname of the global object in the current script on cx.  Reports
  * an error if one needs to be reported (in particular in all cases
  * when it returns false).
  */
 extern JS_FRIEND_API(bool)
 CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname);
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -52,16 +52,17 @@
 #include "nsPrintfCString.h"
 #include "mozilla/FunctionTimer.h"
 #include "prsystem.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsContentUtils.h"
 
+#include "jsfriendapi.h"
 #include "js/MemoryMetrics.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #include "jscntxt.h"
 #if 0
@@ -72,17 +73,16 @@
             while ((acx = JS_ContextIterator(cx->runtime, &iter))) {
                 if (!acx->hasRunOption(JSOPTION_UNROOTED_GLOBAL))
                     JS_ToggleOptions(acx, JSOPTION_UNROOTED_GLOBAL);
 
 JS_LOCK_GC, JS_UNLOCK_GC
 
 js_NextActiveContext, js::TriggerOperationCallback
 JSString::charsHeapSize
-c == cx->runtime->atomsCompartment
 CollectCompartmentStatsForRuntime
         mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock);
         mJSRuntime->setActivityCallback(ActivityCallback, this);
 #endif
 
 using namespace mozilla;
 using namespace mozilla::xpconnect::memory;
 
@@ -1249,28 +1249,75 @@ XPCJSRuntime::~XPCJSRuntime()
 #ifdef DEBUG_shaver_off
         fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
 #endif
     }
 
     XPCPerThreadData::ShutDown();
 }
 
+static void*
+GetCompartmentName(JSContext *cx, JSCompartment *c)
+{
+    nsCString* name = new nsCString();
+    if (js::IsAtomsCompartmentFor(cx, c)) {
+        name->AssignLiteral("atoms");
+    } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
+        if (principals->codebase) {
+            name->Assign(principals->codebase);
+
+            // If it's the system compartment, append the address.
+            // This means that multiple system compartments (and there
+            // can be many) can be distinguished.
+            if (js::IsSystemCompartment(c)) {
+                xpc::CompartmentPrivate *compartmentPrivate =
+                    static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(cx, c));
+                if (compartmentPrivate &&
+                    !compartmentPrivate->location.IsEmpty()) {
+                    name->AppendLiteral(", ");
+                    name->Append(compartmentPrivate->location);
+                }
+
+                // ample; 64-bit address max is 18 chars
+                static const int maxLength = 31;
+                nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
+                name->Append(address);
+            }
+
+            // A hack: replace forward slashes with '\\' so they aren't
+            // treated as path separators.  Users of the reporters
+            // (such as about:memory) have to undo this change.
+            name->ReplaceChar('/', '\\');
+        } else {
+            name->AssignLiteral("null-codebase");
+        }
+    } else {
+        name->AssignLiteral("null-principal");
+    }
+    return name;
+}
+
+static void
+DestroyCompartmentName(void *string)
+{
+    delete static_cast<nsCString*>(string);
+}
+
 namespace {
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
 
 void
 CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
 {
     // Append a new CompartmentStats to the vector.
     IterateData *data = static_cast<IterateData *>(vdata);
-    CompartmentStats compartmentStats(cx, compartment);
-    CompartmentStats *curr =
-        data->compartmentStatsVector.AppendElement(compartmentStats);
+    JS::CompartmentStats *curr =
+        data->compartmentStatsVector.AppendElement();
+    curr->init(GetCompartmentName(cx, compartment), DestroyCompartmentName);
     data->currCompartmentStats = curr;
 
     // Get the compartment-level numbers.
 #ifdef JS_METHODJIT
     curr->mjitCode = JS::SizeOfCompartmentMjitCode(compartment);
 #endif
     JS::SizeOfCompartmentTypeInferenceData(cx, compartment,
                                            &curr->typeInferenceMemory,
@@ -1317,17 +1364,17 @@ ArenaCallback(JSContext *cx, void *vdata
     data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
 }
 
 void
 CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
              size_t thingSize)
 {
     IterateData *data = static_cast<IterateData *>(vdata);
-    CompartmentStats *curr = data->currCompartmentStats;
+    JS::CompartmentStats *curr = data->currCompartmentStats;
     switch (traceKind) {
         case JSTRACE_OBJECT:
         {
             JSObject *obj = static_cast<JSObject *>(thing);
             if (JS_ObjectIsFunction(cx, obj)) {
                 curr->gcHeapObjectsFunction += thingSize;
             } else {
                 curr->gcHeapObjectsNonFunction += thingSize;
@@ -1454,20 +1501,21 @@ ReportMemoryPercentage(const nsACString 
 {
     ReportMemory(path, kind, nsIMemoryReporter::UNITS_PERCENTAGE, amount, desc,
                  callback, closure);
 }
 
 template <int N>
 inline const nsCString
 MakeMemoryReporterPath(const nsACString &pathPrefix,
-                       const nsACString &compartmentName,
+                       const JS::CompartmentStats &compartmentStats,
                        const char (&reporterName)[N])
 {
-  return pathPrefix + NS_LITERAL_CSTRING("compartment(") + compartmentName +
+  return pathPrefix + NS_LITERAL_CSTRING("compartment(") +
+         *static_cast<nsCString*>(compartmentStats.name) +
          NS_LITERAL_CSTRING(")/") + nsDependentCString(reporterName);
 }
 
 } // anonymous namespace
 
 // We have per-compartment GC heap totals, so we can't put the total GC heap
 // size in the explicit allocations tree.  But it's a useful figure, so put it
 // in the "others" list.
@@ -1524,56 +1572,16 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJS
                              "and 'js-compartments-system' might not match the number of "
                              "compartments listed under 'js' if a garbage collection occurs at an "
                              "inopportune time, but such cases should be rare.")
 
 namespace mozilla {
 namespace xpconnect {
 namespace memory {
 
-CompartmentStats::CompartmentStats(JSContext *cx, JSCompartment *c)
-{
-    memset(this, 0, sizeof(*this));
-
-    if (c == cx->runtime->atomsCompartment) {
-        name.AssignLiteral("atoms");
-    } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
-        if (principals->codebase) {
-            name.Assign(principals->codebase);
-
-            // If it's the system compartment, append the address.
-            // This means that multiple system compartments (and there
-            // can be many) can be distinguished.
-            if (js::IsSystemCompartment(c)) {
-                xpc::CompartmentPrivate *compartmentPrivate =
-                        static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(cx, c));
-                if (compartmentPrivate &&
-                    !compartmentPrivate->location.IsEmpty()) {
-                    name.AppendLiteral(", ");
-                    name.Append(compartmentPrivate->location);
-                }
-
-                // ample; 64-bit address max is 18 chars
-                static const int maxLength = 31;
-                nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
-                name.Append(address);
-            }
-
-            // A hack: replace forward slashes with '\\' so they aren't
-            // treated as path separators.  Users of the reporters
-            // (such as about:memory) have to undo this change.
-            name.ReplaceChar('/', '\\');
-        } else {
-            name.AssignLiteral("null-codebase");
-        }
-    } else {
-        name.AssignLiteral("null-principal");
-    }
-}
-
 JSBool
 CollectCompartmentStatsForRuntime(JSRuntime *rt, void *vdata)
 {
     IterateData *data = (IterateData *)vdata;
     JSContext *cx = JS_NewContext(rt, 0);
     if (!cx) {
         NS_ERROR("couldn't create context for memory tracing");
         return false;
@@ -1651,17 +1659,17 @@ CollectCompartmentStatsForRuntime(JSRunt
     data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
                                    data->gcHeapChunkCleanUnused -
                                    data->gcHeapChunkCleanDecommitted -
                                    data->gcHeapChunkDirtyDecommitted;
 
     for (PRUint32 index = 0;
          index < data->compartmentStatsVector.Length();
          index++) {
-        CompartmentStats &stats = data->compartmentStatsVector[index];
+        JS::CompartmentStats &stats = data->compartmentStatsVector[index];
 
         PRInt64 used = stats.gcHeapArenaHeaders +
                        stats.gcHeapArenaPadding +
                        stats.gcHeapArenaUnused +
                        stats.gcHeapObjectsNonFunction +
                        stats.gcHeapObjectsFunction +
                        stats.gcHeapStrings +
                        stats.gcHeapShapesTree +
@@ -1771,206 +1779,206 @@ GetExplicitNonHeapForRuntime(JSRuntime *
 
     return true;
 }
 
 #define SLOP_BYTES_STRING \
     " The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
 
 static PRInt64
-ReportCompartmentStats(const CompartmentStats &stats,
+ReportCompartmentStats(const JS::CompartmentStats &stats,
                        const nsACString &pathPrefix,
                        nsIMemoryMultiReporterCallback *callback,
                        nsISupports *closure)
 {
     PRInt64 gcTotal = 0;
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/arena/headers"),
                        &gcTotal, stats.gcHeapArenaHeaders,
                        "Memory on the compartment's garbage-collected JavaScript heap, within "
                        "arenas, that is used to hold internal book-keeping information.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/arena/padding"),
                        &gcTotal, stats.gcHeapArenaPadding,
                        "Memory on the compartment's garbage-collected JavaScript heap, within "
                        "arenas, that is unused and present only so that other data is aligned. "
                        "This constitutes internal fragmentation.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/arena/unused"),
                        &gcTotal, stats.gcHeapArenaUnused,
                        "Memory on the compartment's garbage-collected JavaScript heap, within "
                        "arenas, that could be holding useful data but currently isn't.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/objects/non-function"),
                        &gcTotal, stats.gcHeapObjectsNonFunction,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "non-function objects.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/objects/function"),
                        &gcTotal, stats.gcHeapObjectsFunction,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "function objects.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/strings"),
                        &gcTotal, stats.gcHeapStrings,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "string headers.  String headers contain various pieces of information "
                        "about a string, but do not contain (except in the case of very short "
                        "strings) the string characters;  characters in longer strings are counted "
                        "under 'gc-heap/string-chars' instead.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/scripts"),
                        &gcTotal, stats.gcHeapScripts,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "JSScript instances. A JSScript is created for each user-defined function "
                        "in a script. One is also created for the top-level code in a script.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/shapes/tree"),
                        &gcTotal, stats.gcHeapShapesTree,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "shapes that are in a property tree.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/shapes/dict"),
                        &gcTotal, stats.gcHeapShapesDict,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "shapes that are in dictionary mode.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/shapes/base"),
                        &gcTotal, stats.gcHeapShapesBase,
                        "Memory on the compartment's garbage-collected JavaScript heap that collates "
                        "data common to many shapes.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/type-objects"),
                        &gcTotal, stats.gcHeapTypeObjects,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "type inference information.",
                        callback, closure);
 
-    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "gc-heap/xml"),
                        &gcTotal, stats.gcHeapXML,
                        "Memory on the compartment's garbage-collected JavaScript heap that holds "
                        "E4X XML objects.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "object-slots"),
                        nsIMemoryReporter::KIND_HEAP, stats.objectSlots,
                        "Memory allocated for the compartment's non-fixed object slot arrays, "
                        "which are used to represent object properties.  Some objects also "
                        "contain a fixed number of slots which are stored on the compartment's "
                        "JavaScript heap; those slots are not counted here, but in "
                        "'gc-heap/objects' instead." SLOP_BYTES_STRING,
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "string-chars"),
                        nsIMemoryReporter::KIND_HEAP, stats.stringChars,
                        "Memory allocated to hold the compartment's string characters.  Sometimes "
                        "more memory is allocated than necessary, to simplify string "
                        "concatenation.  Each string also includes a header which is stored on the "
                        "compartment's JavaScript heap;  that header is not counted here, but in "
                        "'gc-heap/strings' instead.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "shapes-extra/tree-tables"),
                        nsIMemoryReporter::KIND_HEAP, stats.shapesExtraTreeTables,
                        "Memory allocated for the compartment's property tables that belong to "
                        "shapes that are in a property tree." SLOP_BYTES_STRING,
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "shapes-extra/dict-tables"),
                        nsIMemoryReporter::KIND_HEAP, stats.shapesExtraDictTables,
                        "Memory allocated for the compartment's property tables that belong to "
                        "shapes that are in dictionary mode." SLOP_BYTES_STRING,
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "shapes-extra/tree-shape-kids"),
                        nsIMemoryReporter::KIND_HEAP, stats.shapesExtraTreeShapeKids,
                        "Memory allocated for the compartment's kid hashes that belong to shapes "
                        "that are in a property tree.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "shapes-extra/compartment-tables"),
                        nsIMemoryReporter::KIND_HEAP, stats.shapesCompartmentTables,
                        "Memory used by compartment wide tables storing shape information "
                        "for use during object construction.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "script-data"),
                        nsIMemoryReporter::KIND_HEAP, stats.scriptData,
                        "Memory allocated for JSScript bytecode and various variable-length "
                        "tables." SLOP_BYTES_STRING,
                        callback, closure);
 
 #ifdef JS_METHODJIT
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "mjit-code"),
                        nsIMemoryReporter::KIND_NONHEAP, stats.mjitCode,
                        "Memory used by the method JIT to hold the compartment's generated code.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "mjit-data"),
                        nsIMemoryReporter::KIND_HEAP, stats.mjitData,
                        "Memory used by the method JIT for the compartment's compilation data: "
                        "JITScripts, native maps, and inline cache structs." SLOP_BYTES_STRING,
                        callback, closure);
 #endif
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "type-inference/script-main"),
                        nsIMemoryReporter::KIND_HEAP,
                        stats.typeInferenceMemory.scripts,
                        "Memory used during type inference to store type sets of variables "
                        "and dynamically observed types.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "type-inference/object-main"),
                        nsIMemoryReporter::KIND_HEAP,
                        stats.typeInferenceMemory.objects,
                        "Memory used during type inference to store types and possible "
                        "property types of JS objects.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "type-inference/tables"),
                        nsIMemoryReporter::KIND_HEAP,
                        stats.typeInferenceMemory.tables,
                        "Memory used during type inference for compartment-wide tables.",
                        callback, closure);
 
-    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
                                               "analysis-temporary"),
                        nsIMemoryReporter::KIND_HEAP,
                        stats.typeInferenceMemory.temporary,
                        "Memory used during type inference and compilation to hold transient "
                        "analysis information.  Cleared on GC.",
                        callback, closure);
 
     return gcTotal;
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -210,50 +210,16 @@ bool StringToJsval(JSContext *cx, nsStri
 } // namespace xpc
 
 class nsIMemoryMultiReporterCallback;
 
 namespace mozilla {
 namespace xpconnect {
 namespace memory {
 
-struct CompartmentStats
-{
-    CompartmentStats(JSContext *cx, JSCompartment *c);
-
-    nsCString name;
-    PRInt64 gcHeapArenaHeaders;
-    PRInt64 gcHeapArenaPadding;
-    PRInt64 gcHeapArenaUnused;
-
-    PRInt64 gcHeapObjectsNonFunction;
-    PRInt64 gcHeapObjectsFunction;
-    PRInt64 gcHeapStrings;
-    PRInt64 gcHeapShapesTree;
-    PRInt64 gcHeapShapesDict;
-    PRInt64 gcHeapShapesBase;
-    PRInt64 gcHeapScripts;
-    PRInt64 gcHeapTypeObjects;
-    PRInt64 gcHeapXML;
-
-    PRInt64 objectSlots;
-    PRInt64 stringChars;
-    PRInt64 shapesExtraTreeTables;
-    PRInt64 shapesExtraDictTables;
-    PRInt64 shapesExtraTreeShapeKids;
-    PRInt64 shapesCompartmentTables;
-    PRInt64 scriptData;
-
-#ifdef JS_METHODJIT
-    PRInt64 mjitCode;
-    PRInt64 mjitData;
-#endif
-    JS::TypeInferenceMemoryStats typeInferenceMemory;
-};
-
 struct IterateData
 {
     IterateData()
       : runtimeObject(0),
         runtimeAtomsTable(0),
         runtimeContexts(0),
         runtimeThreadsNormal(0),
         runtimeThreadsTemporary(0),
@@ -301,18 +267,18 @@ struct IterateData
     PRInt64 totalScripts;
     PRInt64 totalStrings;
 #ifdef JS_METHODJIT
     PRInt64 totalMjit;
 #endif
     PRInt64 totalTypeInference;
     PRInt64 totalAnalysisTemp;
 
-    nsTArray<CompartmentStats> compartmentStatsVector;
-    CompartmentStats *currCompartmentStats;
+    nsTArray<JS::CompartmentStats> compartmentStatsVector;
+    JS::CompartmentStats *currCompartmentStats;
 };
 
 JSBool
 CollectCompartmentStatsForRuntime(JSRuntime *rt, void *data);
 JSBool
 GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data);
 
 void