Bug 714264 - Part c: Move IterateData / CollectCompartmentStatsForRuntime / GetExplicitNonHeapForRuntime to js/MemoryMetrics.h; r=njn
authorMs2ger <ms2ger@gmail.com>
Wed, 11 Jan 2012 09:23:08 +0100
changeset 86610 2e7afd15d01a48fcdd692fc8543c9d1541ac25bf
parent 86609 b9077aadd3d745c00159ac95aedc2402d94c7d39
child 86611 4c85015dc460efd7ec52a5a3068b66d01364f36d
push idunknown
push userunknown
push dateunknown
reviewersnjn
bugs714264
milestone12.0a1
Bug 714264 - Part c: Move IterateData / CollectCompartmentStatsForRuntime / GetExplicitNonHeapForRuntime to js/MemoryMetrics.h; r=njn This patch also removes those APIs exposed in js/MemoryMetrics.h that aren't used anymore.
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
js/public/MemoryMetrics.h
js/src/Makefile.in
js/src/MemoryMetrics.cpp
js/src/jscompartment.cpp
js/src/jsobj.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/methodjit/MethodJIT.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcpublic.h
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -54,16 +54,18 @@
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIXPConnect.h"
 
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jsprf.h"
+#include "js/MemoryMetrics.h"
+
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMJSUtils.h"
 #include "nsGUIEvent.h"
 #include "nsJSEnvironment.h"
 #include "nsJSUtils.h"
 #include "nsNetUtil.h"
@@ -88,17 +90,17 @@
 #if 0 // Define to run GC more often.
 #define EXTRA_GC
 #endif
 
 using mozilla::MutexAutoLock;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 using mozilla::dom::workers::exceptions::ThrowDOMExceptionForCode;
-using mozilla::xpconnect::memory::IterateData;
+using mozilla::xpconnect::memory::ReportJSRuntimeStats;
 
 USING_WORKERS_NAMESPACE
 
 namespace {
 
 const char gErrorChars[] = "error";
 const char gMessageChars[] = "message";
 
@@ -218,17 +220,18 @@ public:
   }
 
   NS_IMETHOD
   CollectReports(nsIMemoryMultiReporterCallback* aCallback,
                  nsISupports* aClosure)
   {
     AssertIsOnMainThread();
 
-    IterateData data;
+    JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
+                         xpc::DestroyCompartmentName);
     nsresult rv = CollectForRuntime(/* isQuick = */false, &data);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     // Always report, even if we're disabled, so that we at least get an entry
     // in about::memory.
     ReportJSRuntimeStats(data, mPathPrefix, aCallback, aClosure);
@@ -1470,19 +1473,19 @@ public:
     return true;
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     JSAutoSuspendRequest asr(aCx);
 
-    *mSucceeded = mIsQuick ?
-      mozilla::xpconnect::memory::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), mData) :
-      mozilla::xpconnect::memory::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), mData);
+    *mSucceeded = mIsQuick
+      ? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), xpc::JsMallocSizeOf)
+      : JS::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), static_cast<JS::IterateData*>(mData));
 
     {
       MutexAutoLock lock(mMutex);
       mDone = true;
       mCondVar.Notify();
     }
 
     return true;
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -64,26 +64,16 @@ class JSAutoStructuredCloneBuffer;
 class nsIDocument;
 class nsIPrincipal;
 class nsIMemoryMultiReporter;
 class nsIScriptContext;
 class nsIURI;
 class nsPIDOMWindow;
 class nsITimer;
 
-namespace mozilla {
-namespace xpconnect {
-namespace memory {
-
-struct IterateData;
-
-} // namespace memory
-} // namespace xpconnect
-} // namespace mozilla
-
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerPrivate;
 
 class WorkerRunnable : public nsIRunnable
 {
 public:
   enum Target { ParentThread, WorkerThread };
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -39,31 +39,34 @@
 
 /*
  * 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 "jsalloc.h"
 #include "jspubtd.h"
 
 #include "js/Utility.h"
+#include "js/Vector.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* (* GetNameCallback)(JSContext *cx, JSCompartment *c);
 typedef void (* DestroyNameCallback)(void *string);
 
 struct CompartmentStats
 {
     CompartmentStats()
     {
         memset(this, 0, sizeof(*this));
     }
@@ -107,53 +110,105 @@ struct CompartmentStats
 
 #ifdef JS_METHODJIT
     int64_t mjitCode;
     int64_t mjitData;
 #endif
     TypeInferenceMemoryStats typeInferenceMemory;
 };
 
+struct IterateData
+{
+    IterateData(JSMallocSizeOfFun mallocSizeOf, GetNameCallback getNameCb,
+                DestroyNameCallback destroyNameCb)
+      : runtimeObject(0)
+      , runtimeAtomsTable(0)
+      , runtimeContexts(0)
+      , runtimeThreadsNormal(0)
+      , runtimeThreadsTemporary(0)
+      , runtimeThreadsRegexpCode(0)
+      , runtimeThreadsStackCommitted(0)
+      , gcHeapChunkTotal(0)
+      , gcHeapChunkCleanUnused(0)
+      , gcHeapChunkDirtyUnused(0)
+      , gcHeapChunkCleanDecommitted(0)
+      , gcHeapChunkDirtyDecommitted(0)
+      , gcHeapArenaUnused(0)
+      , gcHeapChunkAdmin(0)
+      , gcHeapUnusedPercentage(0)
+      , totalObjects(0)
+      , totalShapes(0)
+      , totalScripts(0)
+      , totalStrings(0)
+#ifdef JS_METHODJIT
+      , totalMjit(0)
+#endif
+      , totalTypeInference(0)
+      , totalAnalysisTemp(0)
+      , compartmentStatsVector()
+      , currCompartmentStats(NULL)
+      , mallocSizeOf(mallocSizeOf)
+      , getNameCb(getNameCb)
+      , destroyNameCb(destroyNameCb)
+    {}
+
+    int64_t runtimeObject;
+    int64_t runtimeAtomsTable;
+    int64_t runtimeContexts;
+    int64_t runtimeThreadsNormal;
+    int64_t runtimeThreadsTemporary;
+    int64_t runtimeThreadsRegexpCode;
+    int64_t runtimeThreadsStackCommitted;
+    int64_t gcHeapChunkTotal;
+    int64_t gcHeapChunkCleanUnused;
+    int64_t gcHeapChunkDirtyUnused;
+    int64_t gcHeapChunkCleanDecommitted;
+    int64_t gcHeapChunkDirtyDecommitted;
+    int64_t gcHeapArenaUnused;
+    int64_t gcHeapChunkAdmin;
+    int64_t gcHeapUnusedPercentage;
+    int64_t totalObjects;
+    int64_t totalShapes;
+    int64_t totalScripts;
+    int64_t totalStrings;
+#ifdef JS_METHODJIT
+    int64_t totalMjit;
+#endif
+    int64_t totalTypeInference;
+    int64_t totalAnalysisTemp;
+
+    js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
+    CompartmentStats *currCompartmentStats;
+
+    JSMallocSizeOfFun mallocSizeOf;
+    GetNameCallback getNameCb;
+    DestroyNameCallback destroyNameCb;
+};
+
+extern JS_PUBLIC_API(bool)
+CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data);
+
+extern JS_PUBLIC_API(bool)
+GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
+                             JSMallocSizeOfFun mallocSizeOf);
+
 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,
                               JSMallocSizeOfFun mallocSizeOf);
 
 extern JS_PUBLIC_API(size_t)
-SizeOfObjectDynamicSlots(JSObject *obj, JSMallocSizeOfFun mallocSizeOf);
-
-extern JS_PUBLIC_API(size_t)
 SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf);
 
 extern JS_PUBLIC_API(size_t)
-SizeOfCompartmentMjitCode(const JSCompartment *c);
-
-extern JS_PUBLIC_API(bool)
-IsShapeInDictionary(const void *shape);
-
-extern JS_PUBLIC_API(size_t)
-SizeOfShapePropertyTable(const void *shape, JSMallocSizeOfFun mallocSizeOf);
-
-extern JS_PUBLIC_API(size_t)
-SizeOfShapeKids(const void *shape, JSMallocSizeOfFun mallocSizeOf);
-
-extern JS_PUBLIC_API(size_t)
-SizeOfScriptData(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
-
-#ifdef JS_METHODJIT
-extern JS_PUBLIC_API(size_t)
-SizeOfScriptJitData(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
-#endif
-
-extern JS_PUBLIC_API(size_t)
 SystemCompartmentCount(const JSRuntime *rt);
 
 extern JS_PUBLIC_API(size_t)
 UserCompartmentCount(const JSRuntime *rt);
 
 } // namespace JS
 
 #endif // js_MemoryMetrics_h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -166,16 +166,17 @@ CPPSRCS		= \
 		BytecodeEmitter.cpp \
 		FoldConstants.cpp \
 		ParseMaps.cpp \
 		ParseNode.cpp \
 		Parser.cpp \
 		SemanticAnalysis.cpp \
 		TokenStream.cpp \
 		LifoAlloc.cpp \
+		MemoryMetrics.cpp \
 		RegExpObject.cpp \
 		RegExpStatics.cpp \
 		RegExp.cpp \
 		Statistics.cpp \
 		Unicode.cpp \
 		$(NULL)
 
 # Changes to internal header files, used externally, massively slow down
new file mode 100644
--- /dev/null
+++ b/js/src/MemoryMetrics.cpp
@@ -0,0 +1,382 @@
+/* ***** 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/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is about:memory glue.
+ *
+ * The Initial Developer of the Original Code is
+ * Ms2ger <ms2ger@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "js/MemoryMetrics.h"
+
+#include "mozilla/Assertions.h"
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsgc.h"
+#include "jsobj.h"
+#include "jsscope.h"
+#include "jsscript.h"
+
+#include "jsobjinlines.h"
+
+namespace JS {
+
+using namespace js;
+
+static void
+CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
+{
+    // Append a new CompartmentStats to the vector.
+    IterateData *data = static_cast<IterateData *>(vdata);
+
+    // CollectCompartmentStatsForRuntime reserves enough space.
+    MOZ_ALWAYS_TRUE(data->compartmentStatsVector.growBy(1));
+    CompartmentStats &curr = data->compartmentStatsVector.back();
+    curr.init(data->getNameCb(cx, compartment), data->destroyNameCb);
+    data->currCompartmentStats = &curr;
+
+    // Get the compartment-level numbers.
+#ifdef JS_METHODJIT
+    curr.mjitCode = compartment->sizeOfMjitCode();
+#endif
+    SizeOfCompartmentTypeInferenceData(cx, compartment,
+                                       &curr.typeInferenceMemory,
+                                       data->mallocSizeOf);
+    curr.shapesCompartmentTables =
+        SizeOfCompartmentShapeTable(compartment, data->mallocSizeOf);
+}
+
+static void
+ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
+{
+#ifdef JS_METHODJIT
+    size_t *n = static_cast<size_t *>(data);
+    *n += compartment->sizeOfMjitCode();
+#endif
+}
+
+static void
+ChunkCallback(JSContext *cx, void *vdata, gc::Chunk *chunk)
+{
+    // Nb: This function is only called for dirty chunks, which is why we
+    // increment gcHeapChunkDirtyDecommitted.
+    IterateData *data = static_cast<IterateData *>(vdata);
+    for (size_t i = 0; i < gc::ArenasPerChunk; i++)
+        if (chunk->decommittedArenas.get(i))
+            data->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
+}
+
+static void
+ArenaCallback(JSContext *cx, void *vdata, gc::Arena *arena,
+              JSGCTraceKind traceKind, size_t thingSize)
+{
+    IterateData *data = static_cast<IterateData *>(vdata);
+
+    data->currCompartmentStats->gcHeapArenaHeaders +=
+        sizeof(gc::ArenaHeader);
+    size_t allocationSpace = arena->thingsSpan(thingSize);
+    data->currCompartmentStats->gcHeapArenaPadding +=
+        gc::ArenaSize - allocationSpace - sizeof(gc::ArenaHeader);
+    // We don't call the callback on unused things.  So we compute the
+    // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
+    // We do this by setting arenaUnused to maxArenaUnused here, and then
+    // subtracting thingSize for every used cell, in CellCallback().
+    data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
+}
+
+static void
+CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
+             size_t thingSize)
+{
+    IterateData *data = static_cast<IterateData *>(vdata);
+    CompartmentStats *curr = data->currCompartmentStats;
+    switch (traceKind) {
+    case JSTRACE_OBJECT:
+    {
+        JSObject *obj = static_cast<JSObject *>(thing);
+        if (obj->isFunction()) {
+            curr->gcHeapObjectsFunction += thingSize;
+        } else {
+            curr->gcHeapObjectsNonFunction += thingSize;
+        }
+        curr->objectSlots += obj->dynamicSlotSize(data->mallocSizeOf);
+        break;
+    }
+    case JSTRACE_STRING:
+    {
+        JSString *str = static_cast<JSString *>(thing);
+        curr->gcHeapStrings += thingSize;
+        curr->stringChars += str->charsHeapSize(data->mallocSizeOf);
+        break;
+    }
+    case JSTRACE_SHAPE:
+    {
+        Shape *shape = static_cast<Shape*>(thing);
+        if (shape->inDictionary()) {
+            curr->gcHeapShapesDict += thingSize;
+            curr->shapesExtraDictTables +=
+                shape->sizeOfPropertyTable(data->mallocSizeOf);
+        } else {
+            curr->gcHeapShapesTree += thingSize;
+            curr->shapesExtraTreeTables +=
+                shape->sizeOfPropertyTable(data->mallocSizeOf);
+            curr->shapesExtraTreeShapeKids +=
+                shape->sizeOfKids(data->mallocSizeOf);
+        }
+        break;
+    }
+    case JSTRACE_BASE_SHAPE:
+    {
+        curr->gcHeapShapesBase += thingSize;
+        break;
+    }
+    case JSTRACE_SCRIPT:
+    {
+        JSScript *script = static_cast<JSScript *>(thing);
+        curr->gcHeapScripts += thingSize;
+        curr->scriptData += script->dataSize(data->mallocSizeOf);
+#ifdef JS_METHODJIT
+        curr->mjitData += script->jitDataSize(data->mallocSizeOf);
+#endif
+        break;
+    }
+    case JSTRACE_TYPE_OBJECT:
+    {
+        types::TypeObject *obj = static_cast<types::TypeObject *>(thing);
+        curr->gcHeapTypeObjects += thingSize;
+        SizeOfObjectTypeInferenceData(obj, &curr->typeInferenceMemory,
+                                      data->mallocSizeOf);
+        break;
+    }
+    case JSTRACE_XML:
+    {
+        curr->gcHeapXML += thingSize;
+        break;
+    }
+    }
+    // Yes, this is a subtraction:  see ArenaCallback() for details.
+    curr->gcHeapArenaUnused -= thingSize;
+}
+
+JS_PUBLIC_API(bool)
+CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
+{
+    JSContext *cx = JS_NewContext(rt, 0);
+    if (!cx)
+        return false;
+
+    {
+        JSAutoRequest ar(cx);
+
+        if (!data->compartmentStatsVector.reserve(rt->compartments.length()))
+            return false;
+
+        data->gcHeapChunkCleanDecommitted =
+            rt->gcChunkPool.countCleanDecommittedArenas(rt) *
+            gc::ArenaSize;
+        data->gcHeapChunkCleanUnused =
+            int64_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
+            gc::ChunkSize -
+            data->gcHeapChunkCleanDecommitted;
+        data->gcHeapChunkTotal =
+            int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
+            gc::ChunkSize;
+
+        IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
+                                       ArenaCallback, CellCallback);
+        IterateChunks(cx, data, ChunkCallback);
+
+        data->runtimeObject = data->mallocSizeOf(rt, sizeof(JSRuntime));
+
+        // Nb: we use sizeOfExcludingThis() because atomState.atoms is within
+        // JSRuntime, and so counted when JSRuntime is counted.
+        data->runtimeAtomsTable =
+            rt->atomState.atoms.sizeOfExcludingThis(data->mallocSizeOf);
+
+        {
+#ifndef JS_THREADSAFE
+#error "This code assumes JS_THREADSAFE is defined"
+#endif
+
+            // Need the GC lock to call JS_ContextIteratorUnlocked() and to
+            // access rt->threads.
+            AutoLockGC lock(rt);
+
+            JSContext *acx, *iter = NULL;
+            while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL) {
+                data->runtimeContexts +=
+                    acx->sizeOfIncludingThis(data->mallocSizeOf);
+            }
+
+            for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
+                JSThread *thread = r.front().value;
+                size_t normal, temporary, regexpCode, stackCommitted;
+                thread->sizeOfIncludingThis(data->mallocSizeOf,
+                                            &normal,
+                                            &temporary,
+                                            &regexpCode,
+                                            &stackCommitted);
+
+                data->runtimeThreadsNormal         += normal;
+                data->runtimeThreadsTemporary      += temporary;
+                data->runtimeThreadsRegexpCode     += regexpCode;
+                data->runtimeThreadsStackCommitted += stackCommitted;
+            }
+        }
+    }
+
+    JS_DestroyContextNoGC(cx);
+
+    // This is initialized to all bytes stored in used chunks, and then we
+    // subtract used space from it each time around the loop.
+    data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
+                                   data->gcHeapChunkCleanUnused -
+                                   data->gcHeapChunkCleanDecommitted -
+                                   data->gcHeapChunkDirtyDecommitted;
+
+    for (size_t index = 0;
+         index < data->compartmentStatsVector.length();
+         index++) {
+        CompartmentStats &stats = data->compartmentStatsVector[index];
+
+        int64_t used = stats.gcHeapArenaHeaders +
+                       stats.gcHeapArenaPadding +
+                       stats.gcHeapArenaUnused +
+                       stats.gcHeapObjectsNonFunction +
+                       stats.gcHeapObjectsFunction +
+                       stats.gcHeapStrings +
+                       stats.gcHeapShapesTree +
+                       stats.gcHeapShapesDict +
+                       stats.gcHeapShapesBase +
+                       stats.gcHeapScripts +
+                       stats.gcHeapTypeObjects +
+                       stats.gcHeapXML;
+
+        data->gcHeapChunkDirtyUnused -= used;
+        data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
+        data->totalObjects += stats.gcHeapObjectsNonFunction +
+                              stats.gcHeapObjectsFunction +
+                              stats.objectSlots;
+        data->totalShapes  += stats.gcHeapShapesTree +
+                              stats.gcHeapShapesDict +
+                              stats.gcHeapShapesBase +
+                              stats.shapesExtraTreeTables +
+                              stats.shapesExtraDictTables +
+                              stats.shapesCompartmentTables;
+        data->totalScripts += stats.gcHeapScripts +
+                              stats.scriptData;
+        data->totalStrings += stats.gcHeapStrings +
+                              stats.stringChars;
+#ifdef JS_METHODJIT
+        data->totalMjit    += stats.mjitCode +
+                              stats.mjitData;
+#endif
+        data->totalTypeInference += stats.gcHeapTypeObjects +
+                                    stats.typeInferenceMemory.objects +
+                                    stats.typeInferenceMemory.scripts +
+                                    stats.typeInferenceMemory.tables;
+        data->totalAnalysisTemp  += stats.typeInferenceMemory.temporary;
+    }
+
+    size_t numDirtyChunks = (data->gcHeapChunkTotal -
+                             data->gcHeapChunkCleanUnused) /
+                            gc::ChunkSize;
+    int64_t perChunkAdmin =
+        sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk);
+    data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
+    data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
+
+    // Why 10000x?  100x because it's a percentage, and another 100x
+    // because nsIMemoryReporter requires that for percentage amounts so
+    // they can be fractional.
+    data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
+                                    data->gcHeapChunkDirtyUnused +
+                                    data->gcHeapChunkCleanDecommitted +
+                                    data->gcHeapChunkDirtyDecommitted +
+                                    data->gcHeapArenaUnused) * 10000 /
+                                   data->gcHeapChunkTotal;
+
+    return true;
+}
+
+JS_PUBLIC_API(bool)
+GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
+                             JSMallocSizeOfFun mallocSizeOf)
+{
+    JSContext *cx = JS_NewContext(rt, 0);
+    if (!cx)
+        return false;
+
+    // explicit/<compartment>/gc-heap/*
+    *amount = int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
+              gc::ChunkSize;
+
+    {
+        JSAutoRequest ar(cx);
+
+        // explicit/<compartment>/mjit-code
+        size_t n = 0;
+        IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
+        *amount += n;
+
+        {
+#ifndef JS_THREADSAFE
+#error "This code assumes JS_THREADSAFE is defined"
+#endif
+
+            // Need the GC lock to call JS_ContextIteratorUnlocked() and to
+            // access rt->threads.
+            AutoLockGC lock(rt);
+
+            // explicit/runtime/threads/regexp-code
+            // explicit/runtime/threads/stack-committed
+            for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
+                JSThread *thread = r.front().value;
+                size_t regexpCode, stackCommitted;
+                thread->sizeOfIncludingThis(mallocSizeOf,
+                                            NULL,
+                                            NULL,
+                                            &regexpCode,
+                                            &stackCommitted);
+
+                *amount += regexpCode;
+                *amount += stackCommitted;
+            }
+        }
+    }
+
+    JS_DestroyContextNoGC(cx);
+
+    return true;
+}
+
+} // namespace JS
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -151,22 +151,16 @@ JSCompartment::sizeOfMjitCode() const
         return 0;
 
     size_t method, regexp, unused;
     jaegerCompartment_->execAlloc()->sizeOfCode(&method, &regexp, &unused);
     JS_ASSERT(regexp == 0);
     return method + unused;
 }
 
-JS_PUBLIC_API(size_t)
-JS::SizeOfCompartmentMjitCode(const JSCompartment *c)
-{
-    return c->sizeOfMjitCode();
-}
-
 #endif
 
 bool
 JSCompartment::wrap(JSContext *cx, Value *vp)
 {
     JS_ASSERT(cx->compartment == this);
 
     uintN flags = 0;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -6594,22 +6594,16 @@ js::HandleNonGenericMethodClassMismatch(
         if (thisObj.isProxy())
             return Proxy::nativeCall(cx, &thisObj, clasp, native, args);
     }
 
     ReportIncompatibleMethod(cx, args, clasp);
     return false;
 }
 
-JS_PUBLIC_API(size_t)
-JS::SizeOfObjectDynamicSlots(JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
-{
-    return obj->dynamicSlotSize(mallocSizeOf);
-}
-
 #ifdef DEBUG
 
 /*
  * Routines to print out values during debugging.  These are FRIEND_API to help
  * the debugger find them and to support temporarily hacking js_Dump* calls
  * into other code.
  */
 
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -1517,26 +1517,8 @@ JSCompartment::sweepInitialShapeTable(JS
     if (initialShapes.initialized()) {
         for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
             const InitialShapeEntry &entry = e.front();
             if (!entry.shape->isMarked() || (entry.proto && !entry.proto->isMarked()))
                 e.removeFront();
         }
     }
 }
-
-JS_PUBLIC_API(bool)
-JS::IsShapeInDictionary(const void *shape)
-{
-    return static_cast<const Shape*>(shape)->inDictionary();
-}
-
-JS_PUBLIC_API(size_t)
-JS::SizeOfShapePropertyTable(const void *shape, JSMallocSizeOfFun mallocSizeOf)
-{
-    return static_cast<const Shape*>(shape)->sizeOfPropertyTable(mallocSizeOf);
-}
-
-JS_PUBLIC_API(size_t)
-JS::SizeOfShapeKids(const void *shape, JSMallocSizeOfFun mallocSizeOf)
-{
-    return static_cast<const Shape*>(shape)->sizeOfKids(mallocSizeOf);
-}
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1309,22 +1309,16 @@ JSScript::dataSize(JSMallocSizeOfFun mal
 #if JS_SCRIPT_INLINE_DATA_LIMIT
     if (data == inlineData)
         return 0;
 #endif
 
     return mallocSizeOf(data, dataSize());
 }
 
-JS_PUBLIC_API(size_t)
-JS::SizeOfScriptData(JSScript *script, JSMallocSizeOfFun mallocSizeOf)
-{
-    return script->dataSize(mallocSizeOf);
-}
-
 /*
  * Nb: srcnotes are variable-length.  This function computes the number of
  * srcnote *slots*, which may be greater than the number of srcnotes.
  */
 uint32_t
 JSScript::numNotes()
 {
     jssrcnote *sn;
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -1292,22 +1292,16 @@ JSScript::jitDataSize(JSMallocSizeOfFun 
     size_t n = 0;
     if (jitNormal)
         n += jitNormal->scriptDataSize(mallocSizeOf); 
     if (jitCtor)
         n += jitCtor->scriptDataSize(mallocSizeOf); 
     return n;
 }
 
-JS_PUBLIC_API(size_t)
-JS::SizeOfScriptJitData(JSScript *script, JSMallocSizeOfFun mallocSizeOf)
-{
-    return script->jitDataSize(mallocSizeOf);
-}
-
 /* Please keep in sync with Compiler::finishThisUp! */
 size_t
 mjit::JITScript::scriptDataSize(JSMallocSizeOfFun mallocSizeOf)
 {
     size_t computedSize =
         sizeof(JITScript) +
         sizeof(NativeMapEntry) * nNmapPairs +
         sizeof(InlineFrame) * nInlineFrames +
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -72,18 +72,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
-CollectCompartmentStatsForRuntime
         mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock);
         mJSRuntime->setActivityCallback(ActivityCallback, this);
 #endif
 
 using namespace mozilla;
 using namespace mozilla::xpconnect::memory;
 
 /***************************************************************************/
@@ -1249,17 +1247,19 @@ XPCJSRuntime::~XPCJSRuntime()
 #ifdef DEBUG_shaver_off
         fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
 #endif
     }
 
     XPCPerThreadData::ShutDown();
 }
 
-static void*
+namespace xpc {
+
+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);
@@ -1290,157 +1290,27 @@ GetCompartmentName(JSContext *cx, JSComp
             name->AssignLiteral("null-codebase");
         }
     } else {
         name->AssignLiteral("null-principal");
     }
     return name;
 }
 
-static void
+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);
-    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,
-                                           JsMallocSizeOf);
-    curr->shapesCompartmentTables =
-        JS::SizeOfCompartmentShapeTable(compartment, JsMallocSizeOf);
-}
-
-void
-ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
-{
-    size_t *n = static_cast<size_t *>(data);
-#ifdef JS_METHODJIT
-    *n += JS::SizeOfCompartmentMjitCode(compartment);
-#endif
-}
-
-void
-ChunkCallback(JSContext *cx, void *vdata, js::gc::Chunk *chunk)
-{
-    // Nb: This function is only called for dirty chunks, which is why we
-    // increment gcHeapChunkDirtyDecommitted.
-    IterateData *data = static_cast<IterateData *>(vdata);
-    for (uint32_t i = 0; i < js::gc::ArenasPerChunk; i++)
-        if (chunk->decommittedArenas.get(i))
-            data->gcHeapChunkDirtyDecommitted += js::gc::ArenaSize;
-}
-
-void
-ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
-              JSGCTraceKind traceKind, size_t thingSize)
-{
-    IterateData *data = static_cast<IterateData *>(vdata);
-
-    data->currCompartmentStats->gcHeapArenaHeaders +=
-        sizeof(js::gc::ArenaHeader);
-    size_t allocationSpace = arena->thingsSpan(thingSize);
-    data->currCompartmentStats->gcHeapArenaPadding +=
-        js::gc::ArenaSize - allocationSpace - sizeof(js::gc::ArenaHeader);
-    // We don't call the callback on unused things.  So we compute the
-    // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
-    // We do this by setting arenaUnused to maxArenaUnused here, and then
-    // subtracting thingSize for every used cell, in CellCallback().
-    data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
-}
+} // namespace xpc
 
-void
-CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
-             size_t thingSize)
-{
-    IterateData *data = static_cast<IterateData *>(vdata);
-    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;
-            }
-            curr->objectSlots += JS::SizeOfObjectDynamicSlots(obj, JsMallocSizeOf);
-            break;
-        }
-        case JSTRACE_STRING:
-        {
-            JSString *str = static_cast<JSString *>(thing);
-            curr->gcHeapStrings += thingSize;
-            curr->stringChars += str->charsHeapSize(JsMallocSizeOf);
-            break;
-        }
-        case JSTRACE_SHAPE:
-        {
-            if (JS::IsShapeInDictionary(thing)) {
-                curr->gcHeapShapesDict += thingSize;
-                curr->shapesExtraDictTables +=
-                    JS::SizeOfShapePropertyTable(thing, JsMallocSizeOf);
-            } else {
-                curr->gcHeapShapesTree += thingSize;
-                curr->shapesExtraTreeTables +=
-                    JS::SizeOfShapePropertyTable(thing, JsMallocSizeOf);
-                curr->shapesExtraTreeShapeKids +=
-                    JS::SizeOfShapeKids(thing, JsMallocSizeOf);
-            }
-            break;
-        }
-        case JSTRACE_BASE_SHAPE:
-        {
-            curr->gcHeapShapesBase += thingSize;
-            break;
-        }
-        case JSTRACE_SCRIPT:
-        {
-            JSScript *script = static_cast<JSScript *>(thing);
-            curr->gcHeapScripts += thingSize;
-            curr->scriptData += JS::SizeOfScriptData(script, JsMallocSizeOf);
-#ifdef JS_METHODJIT
-            curr->mjitData += JS::SizeOfScriptJitData(script, JsMallocSizeOf);
-#endif
-            break;
-        }
-        case JSTRACE_TYPE_OBJECT:
-        {
-            js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
-            curr->gcHeapTypeObjects += thingSize;
-            JS::SizeOfObjectTypeInferenceData(obj, &curr->typeInferenceMemory,
-                                              JsMallocSizeOf);
-            break;
-        }
-        case JSTRACE_XML:
-        {
-            curr->gcHeapXML += thingSize;
-            break;
-        }
-    }
-    // Yes, this is a subtraction:  see ArenaCallback() for details.
-    curr->gcHeapArenaUnused -= thingSize;
-}
+namespace {
 
 template <int N>
 inline void
 ReportMemory(const nsACString &path, PRInt32 kind, PRInt32 units,
              PRInt64 amount, const char (&desc)[N],
              nsIMemoryMultiReporterCallback *callback, nsISupports *closure)
 {
     callback->Callback(NS_LITERAL_CSTRING(""), path, kind, units, amount,
@@ -1572,219 +1442,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 {
 
-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;
-    }
-
-    {
-        JSAutoRequest ar(cx);
-
-        data->compartmentStatsVector.SetCapacity(rt->compartments.length());
-
-        data->gcHeapChunkCleanDecommitted =
-            rt->gcChunkPool.countCleanDecommittedArenas(rt) *
-            js::gc::ArenaSize;
-        data->gcHeapChunkCleanUnused =
-            PRInt64(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
-            js::gc::ChunkSize -
-            data->gcHeapChunkCleanDecommitted;
-        data->gcHeapChunkTotal =
-            PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
-            js::gc::ChunkSize;
-
-        js::IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
-                                           ArenaCallback, CellCallback);
-        js::IterateChunks(cx, data, ChunkCallback);
-
-        data->runtimeObject = JsMallocSizeOf(rt, sizeof(JSRuntime));
-
-        // Nb: we use sizeOfExcludingThis() because atomState.atoms is within
-        // JSRuntime, and so counted when JSRuntime is counted.
-        data->runtimeAtomsTable =
-            rt->atomState.atoms.sizeOfExcludingThis(JsMallocSizeOf);
-
-        {
-            #ifndef JS_THREADSAFE
-            #error "This code assumes JS_THREADSAFE is defined"
-            #endif
-
-            // Need the GC lock to call JS_ContextIteratorUnlocked() and to
-            // access rt->threads.
-            js::AutoLockGC lock(rt);
-
-            JSContext *acx, *iter = NULL;
-            while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL) {
-                data->runtimeContexts +=
-                    acx->sizeOfIncludingThis(JsMallocSizeOf);
-            }
-
-            for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
-                JSThread *thread = r.front().value;
-                size_t normal, temporary, regexpCode, stackCommitted;
-                thread->sizeOfIncludingThis(JsMallocSizeOf,
-                                            &normal,
-                                            &temporary,
-                                            &regexpCode,
-                                            &stackCommitted);
-
-                data->runtimeThreadsNormal         += normal;
-                data->runtimeThreadsTemporary      += temporary;
-                data->runtimeThreadsRegexpCode     += regexpCode;
-                data->runtimeThreadsStackCommitted += stackCommitted;
-            }
-        }
-
-        XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
-        data->xpconnect +=
-            xpcrt->SizeOfIncludingThis(JsMallocSizeOf);
-        data->xpconnect +=
-            XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
-    }
-
-    JS_DestroyContextNoGC(cx);
-
-    // This is initialized to all bytes stored in used chunks, and then we
-    // subtract used space from it each time around the loop.
-    data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
-                                   data->gcHeapChunkCleanUnused -
-                                   data->gcHeapChunkCleanDecommitted -
-                                   data->gcHeapChunkDirtyDecommitted;
-
-    for (PRUint32 index = 0;
-         index < data->compartmentStatsVector.Length();
-         index++) {
-        JS::CompartmentStats &stats = data->compartmentStatsVector[index];
-
-        PRInt64 used = stats.gcHeapArenaHeaders +
-                       stats.gcHeapArenaPadding +
-                       stats.gcHeapArenaUnused +
-                       stats.gcHeapObjectsNonFunction +
-                       stats.gcHeapObjectsFunction +
-                       stats.gcHeapStrings +
-                       stats.gcHeapShapesTree +
-                       stats.gcHeapShapesDict +
-                       stats.gcHeapShapesBase +
-                       stats.gcHeapScripts +
-                       stats.gcHeapTypeObjects +
-                       stats.gcHeapXML;
-
-        data->gcHeapChunkDirtyUnused -= used;
-        data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
-        data->totalObjects += stats.gcHeapObjectsNonFunction + 
-                              stats.gcHeapObjectsFunction +
-                              stats.objectSlots;
-        data->totalShapes  += stats.gcHeapShapesTree + 
-                              stats.gcHeapShapesDict +
-                              stats.gcHeapShapesBase +
-                              stats.shapesExtraTreeTables +
-                              stats.shapesExtraDictTables +
-                              stats.shapesCompartmentTables;
-        data->totalScripts += stats.gcHeapScripts + 
-                              stats.scriptData;
-        data->totalStrings += stats.gcHeapStrings + 
-                              stats.stringChars;
-#ifdef JS_METHODJIT
-        data->totalMjit    += stats.mjitCode + 
-                              stats.mjitData;
-#endif
-        data->totalTypeInference += stats.gcHeapTypeObjects +
-                                    stats.typeInferenceMemory.objects +
-                                    stats.typeInferenceMemory.scripts + 
-                                    stats.typeInferenceMemory.tables;
-        data->totalAnalysisTemp  += stats.typeInferenceMemory.temporary;
-    }
-
-    size_t numDirtyChunks = (data->gcHeapChunkTotal -
-                             data->gcHeapChunkCleanUnused) /
-                            js::gc::ChunkSize;
-    PRInt64 perChunkAdmin =
-        sizeof(js::gc::Chunk) - (sizeof(js::gc::Arena) * js::gc::ArenasPerChunk);
-    data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
-    data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
-
-    // Why 10000x?  100x because it's a percentage, and another 100x
-    // because nsIMemoryReporter requires that for percentage amounts so
-    // they can be fractional.
-    data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
-                                    data->gcHeapChunkDirtyUnused +
-                                    data->gcHeapChunkCleanDecommitted +
-                                    data->gcHeapChunkDirtyDecommitted +
-                                    data->gcHeapArenaUnused) * 10000 /
-                                   data->gcHeapChunkTotal;
-
-    return true;
-}
-
-JSBool
-GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data)
-{
-    PRInt64 *amount = (PRInt64 *)data;
-
-    JSContext *cx = JS_NewContext(rt, 0);
-    if (!cx) {
-        NS_ERROR("couldn't create context for memory tracing");
-        return NS_ERROR_ABORT;
-    }
-
-    // explicit/<compartment>/gc-heap/*
-    *amount = PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
-              js::gc::ChunkSize;
-
-    {
-        JSAutoRequest ar(cx);
-
-        // explicit/<compartment>/mjit-code
-        size_t n = 0;
-        js::IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
-        *amount += n;
-
-        {
-            #ifndef JS_THREADSAFE
-            #error "This code assumes JS_THREADSAFE is defined"
-            #endif
-
-            // Need the GC lock to call JS_ContextIteratorUnlocked() and to
-            // access rt->threads.
-            js::AutoLockGC lock(rt);
-
-            // explicit/runtime/threads/regexp-code
-            // explicit/runtime/threads/stack-committed
-            for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
-                JSThread *thread = r.front().value;
-                size_t regexpCode, stackCommitted;
-                thread->sizeOfIncludingThis(JsMallocSizeOf,
-                                            NULL,
-                                            NULL,
-                                            &regexpCode,
-                                            &stackCommitted);
-
-                *amount += regexpCode;
-                *amount += stackCommitted;
-            }
-        }
-    }
-
-    JS_DestroyContextNoGC(cx);
-
-    return true;
-}
-
 #define SLOP_BYTES_STRING \
     " The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
 
 static PRInt64
 ReportCompartmentStats(const JS::CompartmentStats &stats,
                        const nsACString &pathPrefix,
                        nsIMemoryMultiReporterCallback *callback,
                        nsISupports *closure)
@@ -1980,23 +1647,23 @@ ReportCompartmentStats(const JS::Compart
                        "Memory used during type inference and compilation to hold transient "
                        "analysis information.  Cleared on GC.",
                        callback, closure);
 
     return gcTotal;
 }
 
 void
-ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
+ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
                      nsIMemoryMultiReporterCallback *callback,
                      nsISupports *closure)
 {
     PRInt64 gcTotal = 0;
-    for (PRUint32 index = 0;
-         index < data.compartmentStatsVector.Length();
+    for (size_t index = 0;
+         index < data.compartmentStatsVector.length();
          index++) {
         gcTotal += ReportCompartmentStats(data.compartmentStatsVector[index], pathPrefix,
                                     callback, closure);
     }
 
     ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
                       nsIMemoryReporter::KIND_HEAP, data.runtimeObject,
                       "Memory used by the JSRuntime object." SLOP_BYTES_STRING,
@@ -2034,21 +1701,16 @@ ReportJSRuntimeStats(const IterateData &
 
     ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/threads/stack-committed"),
                       nsIMemoryReporter::KIND_NONHEAP, data.runtimeThreadsStackCommitted,
                       "Memory used for the thread stacks.  This is the committed portions "
                       "of the stacks; any uncommitted portions are not measured because they "
                       "hardly cost anything.",
                       callback, closure);
 
-    ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
-                      nsIMemoryReporter::KIND_HEAP, data.xpconnect,
-                      "Memory used by XPConnect." SLOP_BYTES_STRING,
-                      callback, closure);
-
     ReportGCHeapBytes(pathPrefix +
                       NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
                       &gcTotal, data.gcHeapChunkDirtyUnused,
                       "Memory on the garbage-collected JavaScript heap, within chunks with at "
                       "least one allocated GC thing, that could be holding useful data but "
                       "currently isn't.  Memory here is mutually exclusive with memory reported"
                       "under 'explicit/js/gc-heap-decommitted'.",
                       callback, closure);
@@ -2089,32 +1751,45 @@ ReportJSRuntimeStats(const IterateData &
 class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
                               nsISupports *closure)
     {
-        JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
+        XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
 
         // In the first step we get all the stats and stash them in a local
         // data structure.  In the second step we pass all the stashed stats to
         // the callback.  Separating these steps is important because the
         // callback may be a JS function, and executing JS while getting these
         // stats seems like a bad idea.
-        IterateData data;
-        if (!CollectCompartmentStatsForRuntime(rt, &data))
+        JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
+                             xpc::DestroyCompartmentName);
+        if (!JS::CollectCompartmentStatsForRuntime(xpcrt->GetJSRuntime(), &data))
             return NS_ERROR_FAILURE;
 
+        uint64_t xpconnect;
+        {
+            xpconnect =
+                xpcrt->SizeOfIncludingThis(xpc::JsMallocSizeOf) +
+                XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(xpc::JsMallocSizeOf);
+        }
+
         NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
 
         // This is the second step (see above).
         ReportJSRuntimeStats(data, pathPrefix, callback, closure);
 
+        ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
+                          nsIMemoryReporter::KIND_HEAP, xpconnect,
+                          "Memory used by XPConnect." SLOP_BYTES_STRING,
+                          callback, closure);
+
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-dirty-unused"),
                           nsIMemoryReporter::KIND_OTHER,
                           data.gcHeapChunkDirtyUnused,
                           "The same as 'explicit/js/gc-heap-chunk-dirty-unused'.  Shown here for "
                           "easy comparison with other 'js-gc' reporters.",
                           callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-clean-unused"),
@@ -2198,17 +1873,17 @@ public:
         return NS_OK;
     }
 
     NS_IMETHOD
     GetExplicitNonHeap(PRInt64 *n)
     {
         JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
 
-        if (!GetExplicitNonHeapForRuntime(rt, n))
+        if (!JS::GetExplicitNonHeapForRuntime(rt, n, xpc::JsMallocSizeOf))
             return NS_ERROR_FAILURE;
 
         return NS_OK;
     }
 };
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(XPConnectJSCompartmentsMultiReporter
                               , nsIMemoryMultiReporter
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -202,92 +202,30 @@ bool Base64Decode(JSContext *cx, JS::Val
 
 /**
  * Convert an nsString to jsval, returning true on success.
  * Note, the ownership of the string buffer may be moved from str to rval.
  * If that happens, str will point to an empty string after this call.
  */
 bool StringToJsval(JSContext *cx, nsString &str, JS::Value *rval);
 
+void *GetCompartmentName(JSContext *cx, JSCompartment *c);
+void DestroyCompartmentName(void *string);
+size_t JsMallocSizeOf(const void *ptr, size_t computedSize);
+
 } // namespace xpc
 
 class nsIMemoryMultiReporterCallback;
 
 namespace mozilla {
 namespace xpconnect {
 namespace memory {
 
-struct IterateData
-{
-    IterateData()
-      : runtimeObject(0),
-        runtimeAtomsTable(0),
-        runtimeContexts(0),
-        runtimeThreadsNormal(0),
-        runtimeThreadsTemporary(0),
-        runtimeThreadsRegexpCode(0),
-        runtimeThreadsStackCommitted(0),
-        xpconnect(0),
-        gcHeapChunkTotal(0),
-        gcHeapChunkCleanUnused(0),
-        gcHeapChunkDirtyUnused(0),
-        gcHeapChunkCleanDecommitted(0),
-        gcHeapChunkDirtyDecommitted(0),
-        gcHeapArenaUnused(0),
-        gcHeapChunkAdmin(0),
-        gcHeapUnusedPercentage(0),
-        totalObjects(0),
-        totalShapes(0),
-        totalScripts(0),
-        totalStrings(0),
-#ifdef JS_METHODJIT
-        totalMjit(0),
-#endif
-        totalTypeInference(0),
-        totalAnalysisTemp(0),
-        compartmentStatsVector(),
-        currCompartmentStats(NULL) { }
-
-    PRInt64 runtimeObject;
-    PRInt64 runtimeAtomsTable;
-    PRInt64 runtimeContexts;
-    PRInt64 runtimeThreadsNormal;
-    PRInt64 runtimeThreadsTemporary;
-    PRInt64 runtimeThreadsRegexpCode;
-    PRInt64 runtimeThreadsStackCommitted;
-    PRInt64 xpconnect;
-    PRInt64 gcHeapChunkTotal;
-    PRInt64 gcHeapChunkCleanUnused;
-    PRInt64 gcHeapChunkDirtyUnused;
-    PRInt64 gcHeapChunkCleanDecommitted;
-    PRInt64 gcHeapChunkDirtyDecommitted;
-    PRInt64 gcHeapArenaUnused;
-    PRInt64 gcHeapChunkAdmin;
-    PRInt64 gcHeapUnusedPercentage;
-    PRInt64 totalObjects;
-    PRInt64 totalShapes;
-    PRInt64 totalScripts;
-    PRInt64 totalStrings;
-#ifdef JS_METHODJIT
-    PRInt64 totalMjit;
-#endif
-    PRInt64 totalTypeInference;
-    PRInt64 totalAnalysisTemp;
-
-    nsTArray<JS::CompartmentStats> compartmentStatsVector;
-    JS::CompartmentStats *currCompartmentStats;
-};
-
-JSBool
-CollectCompartmentStatsForRuntime(JSRuntime *rt, void *data);
-JSBool
-GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data);
-
 void
-ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
+ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
                      nsIMemoryMultiReporterCallback *callback,
                      nsISupports *closure);
 
 } // namespace memory
 } // namespace xpconnect
 
 namespace dom {
 namespace binding {