Backed out 9 changesets (bug 943660, bug 936964) because of ASAN use-after-free crashes on browser-chrome and mochitest-other
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 27 Nov 2013 20:05:00 -0500
changeset 172514 190eedf8577ac44ad362192c99c9708ca8098f17
parent 172513 5a2d363a102e5ae630eac6cb95125a0eb4a52b64
child 172515 36b6702581d435354bbda1a58223b3c7230fbfa1
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs943660, 936964
milestone28.0a1
backs out85486c4aa3d8f54d69fa5c4a63098d8e5c347ac7
25312eb719988a0049a704813bb598ed07ed7177
6dbb8333960caaa9aca3dd63d5502025f4f0e9ca
da6465ad476f67251c15564855a639f270716c33
a87ffc992f38c3b17189ab6955e5ba011b977491
4ae3a61182db6365f1aed7145b5a7943b258f0bf
34e9c313780441686e3c2beb273c7fa193f02fc6
fd1459e715850b049ed9e44e7a62073eb8051028
3e8a701d8bdc40469b5a9f7c2eb273e36e97ac0d
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
Backed out 9 changesets (bug 943660, bug 936964) because of ASAN use-after-free crashes on browser-chrome and mochitest-other Backed out changeset 85486c4aa3d8 (bug 936964) Backed out changeset 25312eb71998 (bug 936964) Backed out changeset 6dbb8333960c (bug 936964) Backed out changeset da6465ad476f (bug 936964) Backed out changeset a87ffc992f38 (bug 936964) Backed out changeset 4ae3a61182db (bug 936964) Backed out changeset 34e9c3137804 (bug 936964) Backed out changeset fd1459e71585 (bug 936964) Backed out changeset 3e8a701d8bdc (bug 943660) Landed on a CLOSED TREE
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMFile.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsHostObjectProtocolHandler.cpp
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextReporter.cpp
content/canvas/src/WebGLMemoryReporterWrapper.h
content/canvas/src/WebGLMemoryTracker.h
content/media/MediaDecoder.cpp
content/media/MediaDecoder.h
dom/base/nsScriptNameSpaceManager.cpp
dom/base/nsScriptNameSpaceManager.h
dom/base/nsWindowMemoryReporter.cpp
dom/ipc/ContentParent.cpp
dom/workers/WorkerPrivate.cpp
extensions/spellcheck/hunspell/src/mozHunspell.cpp
extensions/spellcheck/hunspell/src/mozHunspell.h
gfx/gl/GLContext.cpp
gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
gfx/thebes/gfxASurface.cpp
gfx/thebes/gfxAndroidPlatform.cpp
gfx/thebes/gfxAndroidPlatform.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxWindowsPlatform.cpp
gfx/thebes/gfxWindowsPlatform.h
image/src/SurfaceCache.cpp
image/src/imgLoader.cpp
ipc/glue/SharedMemory.cpp
js/xpconnect/src/XPCJSRuntime.cpp
layout/base/nsStyleSheetService.cpp
layout/base/nsStyleSheetService.h
layout/style/nsLayoutStylesheetCache.cpp
layout/style/nsLayoutStylesheetCache.h
modules/libpref/src/Preferences.cpp
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsCacheService.h
netwerk/cache/nsDiskCacheDevice.cpp
netwerk/cache/nsDiskCacheDevice.h
netwerk/cache/nsMemoryCacheDevice.cpp
netwerk/cache/nsMemoryCacheDevice.h
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsDNSService2.h
netwerk/dns/nsEffectiveTLDService.cpp
netwerk/dns/nsEffectiveTLDService.h
startupcache/StartupCache.cpp
startupcache/StartupCache.h
storage/src/mozStorageService.cpp
storage/src/mozStorageService.h
toolkit/components/aboutmemory/tests/test_aboutmemory.xul
toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
toolkit/components/aboutmemory/tests/test_memoryReporters.xul
toolkit/components/places/History.cpp
toolkit/components/places/History.h
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h
xpcom/base/AvailableMemoryTracker.cpp
xpcom/base/nsCycleCollector.cpp
xpcom/base/nsIMemoryReporter.idl
xpcom/base/nsMemoryReporterManager.cpp
xpcom/base/nsMemoryReporterManager.h
xpcom/build/nsXPComInit.cpp
xpcom/components/nsCategoryManager.cpp
xpcom/components/nsCategoryManager.h
xpcom/components/nsComponentManager.cpp
xpcom/components/nsComponentManager.h
xpcom/ds/nsObserverList.h
xpcom/ds/nsObserverService.cpp
xpcom/ds/nsObserverService.h
xpcom/reflect/xptinfo/public/XPTInterfaceInfoManager.h
xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -412,17 +412,17 @@ nsContentUtils::Init()
 
     if (!PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops,
                            nullptr, sizeof(EventListenerManagerMapEntry), 16)) {
       sEventListenerManagersHash.ops = nullptr;
 
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    RegisterStrongMemoryReporter(new DOMEventListenerManagersHashReporter());
+    NS_RegisterMemoryReporter(new DOMEventListenerManagersHashReporter);
   }
 
   sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >;
 
   Preferences::AddBoolVarCache(&sAllowXULXBL_for_file,
                                "dom.allow_XUL_XBL_for_file");
 
   Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled,
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -728,17 +728,19 @@ public:
 /* static */ void
 nsDOMMemoryFile::DataOwner::EnsureMemoryReporterRegistered()
 {
   sDataOwnerMutex.AssertCurrentThreadOwns();
   if (sMemoryReporterRegistered) {
     return;
   }
 
-  RegisterStrongMemoryReporter(new nsDOMMemoryFileDataOwnerMemoryReporter());
+  nsRefPtr<nsDOMMemoryFileDataOwnerMemoryReporter> reporter = new
+    nsDOMMemoryFileDataOwnerMemoryReporter();
+  NS_RegisterMemoryReporter(reporter);
 
   sMemoryReporterRegistered = true;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // nsDOMFileList implementation
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMFileList)
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1295,17 +1295,17 @@ MessageManagerReporter::CollectReports(n
 nsresult
 NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult)
 {
   NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default,
                  NS_ERROR_NOT_AVAILABLE);
   nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr,
                                                         nullptr,
                                                         MM_CHROME | MM_GLOBAL | MM_BROADCASTER);
-  RegisterStrongMemoryReporter(new MessageManagerReporter());
+  NS_RegisterMemoryReporter(new MessageManagerReporter());
   return CallQueryInterface(mm, aResult);
 }
 
 nsDataHashtable<nsStringHashKey, nsFrameJSScriptExecutorHolder*>*
   nsFrameScriptExecutor::sCachedScripts = nullptr;
 nsScriptCacheCleaner* nsFrameScriptExecutor::sScriptCacheCleaner = nullptr;
 
 void
@@ -1830,17 +1830,17 @@ NS_NewChildProcessMessageManager(nsISync
   NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager,
                "Re-creating sChildProcessManager");
 
   MessageManagerCallback* cb;
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     cb = new SameChildProcessMessageManagerCallback();
   } else {
     cb = new ChildProcessMessageManagerCallback();
-    RegisterStrongMemoryReporter(new MessageManagerReporter());
+    NS_RegisterMemoryReporter(new MessageManagerReporter());
   }
   nsFrameMessageManager* mm = new nsFrameMessageManager(cb,
                                                         nullptr,
                                                         MM_PROCESSMANAGER | MM_OWNSCALLBACK);
   nsFrameMessageManager::sChildProcessManager = mm;
   return CallQueryInterface(mm, aResult);
 }
 
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -48,17 +48,17 @@ class HostObjectURLsReporter MOZ_FINAL :
 }
 
 nsHostObjectProtocolHandler::nsHostObjectProtocolHandler()
 {
   static bool initialized = false;
 
   if (!initialized) {
     initialized = true;
-    RegisterStrongMemoryReporter(new mozilla::HostObjectURLsReporter());
+    NS_RegisterMemoryReporter(new mozilla::HostObjectURLsReporter());
   }
 }
 
 nsresult
 nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aScheme,
                                           nsISupports* aObject,
                                           nsIPrincipal* aPrincipal,
                                           nsACString& aUri)
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -883,17 +883,17 @@ CanvasRenderingContext2D::EnsureTarget()
        mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
      }
   }
 
   if (mTarget) {
     static bool registered = false;
     if (!registered) {
       registered = true;
-      RegisterStrongMemoryReporter(new Canvas2dPixelsReporter());
+      NS_RegisterMemoryReporter(new Canvas2dPixelsReporter());
     }
 
     gCanvasAzureMemoryUsed += mWidth * mHeight * 4;
     JSContext* context = nsContentUtils::GetCurrentJSContext();
     if (context) {
       JS_updateMallocCounter(context, mWidth * mHeight * 4);
     }
 
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -5,17 +5,17 @@
 
 #include "WebGLContext.h"
 #include "WebGL1Context.h"
 #include "WebGLObjectModel.h"
 #include "WebGLExtensions.h"
 #include "WebGLContextUtils.h"
 #include "WebGLBuffer.h"
 #include "WebGLVertexAttribData.h"
-#include "WebGLMemoryTracker.h"
+#include "WebGLMemoryReporterWrapper.h"
 #include "WebGLFramebuffer.h"
 #include "WebGLVertexArray.h"
 #include "WebGLQuery.h"
 
 #include "AccessCheck.h"
 #include "nsIConsoleService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIClassInfoImpl.h"
@@ -173,17 +173,17 @@ WebGLContext::WebGLContext()
     mGLMaxColorAttachments = 1;
     mGLMaxDrawBuffers = 1;
     mGLMaxTransformFeedbackSeparateAttribs = 0;
 
     // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
     mPixelStorePackAlignment = 4;
     mPixelStoreUnpackAlignment = 4;
 
-    WebGLMemoryTracker::AddWebGLContext(this);
+    WebGLMemoryReporterWrapper::AddWebGLContext(this);
 
     mAllowRestore = true;
     mContextLossTimerRunning = false;
     mDrawSinceContextLossTimerSet = false;
     mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
     mContextStatus = ContextNotLost;
     mContextLostErrorSet = false;
     mLoseContextOnHeapMinimize = false;
@@ -207,17 +207,17 @@ WebGLContext::WebGLContext()
     mDisableFragHighP = false;
 
     mDrawCallsSinceLastFlush = 0;
 }
 
 WebGLContext::~WebGLContext()
 {
     DestroyResourcesAndContext();
-    WebGLMemoryTracker::RemoveWebGLContext(this);
+    WebGLMemoryReporterWrapper::RemoveWebGLContext(this);
     TerminateContextLossTimer();
     mContextRestorer = nullptr;
 }
 
 void
 WebGLContext::DestroyResourcesAndContext()
 {
     if (mMemoryPressureObserver) {
@@ -664,18 +664,18 @@ void WebGLContext::LoseOldestWebGLContex
 #endif
     MOZ_ASSERT(kMaxWebGLContextsPerPrincipal < kMaxWebGLContexts);
 
     // it's important to update the index on a new context before losing old contexts,
     // otherwise new unused contexts would all have index 0 and we couldn't distinguish older ones
     // when choosing which one to lose first.
     UpdateLastUseIndex();
 
-    WebGLMemoryTracker::ContextsArrayType &contexts
-      = WebGLMemoryTracker::Contexts();
+    WebGLMemoryReporterWrapper::ContextsArrayType &contexts
+      = WebGLMemoryReporterWrapper::Contexts();
 
     // quick exit path, should cover a majority of cases
     if (contexts.Length() <= kMaxWebGLContextsPerPrincipal) {
         return;
     }
 
     // note that here by "context" we mean "non-lost context". See the check for
     // IsContextLost() below. Indeed, the point of this function is to maybe lose
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -117,17 +117,17 @@ class WebGLContext :
     public nsIDOMWebGLRenderingContext,
     public nsICanvasRenderingContextInternal,
     public nsSupportsWeakReference,
     public WebGLRectangleObject,
     public nsWrapperCache
 {
     friend class WebGLContextUserData;
     friend class WebGLMemoryPressureObserver;
-    friend class WebGLMemoryTracker;
+    friend class WebGLMemoryReporterWrapper;
     friend class WebGLExtensionLoseContext;
     friend class WebGLExtensionCompressedTextureS3TC;
     friend class WebGLExtensionCompressedTextureATC;
     friend class WebGLExtensionCompressedTexturePVRTC;
     friend class WebGLExtensionDepthTexture;
     friend class WebGLExtensionDrawBuffers;
     friend class WebGLExtensionVertexArray;
 
--- a/content/canvas/src/WebGLContextReporter.cpp
+++ b/content/canvas/src/WebGLContextReporter.cpp
@@ -1,128 +1,142 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLContext.h"
-#include "WebGLMemoryTracker.h"
+#include "WebGLMemoryReporterWrapper.h"
+#include "nsIMemoryReporter.h"
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS1(WebGLMemoryPressureObserver, nsIObserver)
 
+class WebGLMemoryReporter MOZ_FINAL : public MemoryMultiReporter
+{
+public:
+    WebGLMemoryReporter()
+        : MemoryMultiReporter("webgl")
+    {}
+
+    NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
+                              nsISupports* aClosure);
+};
+
 NS_IMETHODIMP
-WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                   nsISupports* aData)
+WebGLMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
+                                    nsISupports* aClosure)
 {
 #define REPORT(_path, _kind, _units, _amount, _desc)                          \
     do {                                                                      \
       nsresult rv;                                                            \
-      rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
-                                   _kind, _units, _amount,                    \
-                                   NS_LITERAL_CSTRING(_desc), aData);         \
+      rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), _kind,    \
+                         _units, _amount, NS_LITERAL_CSTRING(_desc),          \
+                         aClosure);                                           \
       NS_ENSURE_SUCCESS(rv, rv);                                              \
     } while (0)
 
     REPORT("webgl-texture-memory",
-           KIND_OTHER, UNITS_BYTES, GetTextureMemoryUsed(),
+           nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
+           WebGLMemoryReporterWrapper::GetTextureMemoryUsed(),
            "Memory used by WebGL textures.The OpenGL"
            " implementation is free to store these textures in either video"
            " memory or main memory. This measurement is only a lower bound,"
            " actual memory usage may be higher for example if the storage"
            " is strided.");
 
     REPORT("webgl-texture-count",
-           KIND_OTHER, UNITS_COUNT, GetTextureCount(),
+           nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+           WebGLMemoryReporterWrapper::GetTextureCount(),
            "Number of WebGL textures.");
 
     REPORT("webgl-buffer-memory",
-           KIND_OTHER, UNITS_BYTES, GetBufferMemoryUsed(),
+           nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
+           WebGLMemoryReporterWrapper::GetBufferMemoryUsed(),
            "Memory used by WebGL buffers. The OpenGL"
            " implementation is free to store these buffers in either video"
            " memory or main memory. This measurement is only a lower bound,"
            " actual memory usage may be higher for example if the storage"
            " is strided.");
 
     REPORT("explicit/webgl/buffer-cache-memory",
-           KIND_HEAP, UNITS_BYTES, GetBufferCacheMemoryUsed(),
+           nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
+           WebGLMemoryReporterWrapper::GetBufferCacheMemoryUsed(),
            "Memory used by WebGL buffer caches. The WebGL"
            " implementation caches the contents of element array buffers"
            " only.This adds up with the webgl-buffer-memory value, but"
            " contrary to it, this one represents bytes on the heap,"
            " not managed by OpenGL.");
 
     REPORT("webgl-buffer-count",
-           KIND_OTHER, UNITS_COUNT, GetBufferCount(),
+           nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+           WebGLMemoryReporterWrapper::GetBufferCount(),
            "Number of WebGL buffers.");
 
     REPORT("webgl-renderbuffer-memory",
-           KIND_OTHER, UNITS_BYTES, GetRenderbufferMemoryUsed(),
+           nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_BYTES,
+           WebGLMemoryReporterWrapper::GetRenderbufferMemoryUsed(),
            "Memory used by WebGL renderbuffers. The OpenGL"
            " implementation is free to store these renderbuffers in either"
            " video memory or main memory. This measurement is only a lower"
            " bound, actual memory usage may be higher for example if the"
            " storage is strided.");
 
     REPORT("webgl-renderbuffer-count",
-           KIND_OTHER, UNITS_COUNT, GetRenderbufferCount(),
+           nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+           WebGLMemoryReporterWrapper::GetRenderbufferCount(),
            "Number of WebGL renderbuffers.");
 
     REPORT("explicit/webgl/shader",
-           KIND_HEAP, UNITS_BYTES, GetShaderSize(),
+           nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
+           WebGLMemoryReporterWrapper::GetShaderSize(),
            "Combined size of WebGL shader ASCII sources and translation"
            " logs cached on the heap.");
 
     REPORT("webgl-shader-count",
-           KIND_OTHER, UNITS_COUNT, GetShaderCount(),
+           nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+           WebGLMemoryReporterWrapper::GetShaderCount(),
            "Number of WebGL shaders.");
 
     REPORT("webgl-context-count",
-           KIND_OTHER, UNITS_COUNT, GetContextCount(),
+           nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
+           WebGLMemoryReporterWrapper::GetContextCount(),
            "Number of WebGL contexts.");
 
 #undef REPORT
 
     return NS_OK;
 }
 
-NS_IMPL_ISUPPORTS_INHERITED0(WebGLMemoryTracker, MemoryMultiReporter)
+WebGLMemoryReporterWrapper* WebGLMemoryReporterWrapper::sUniqueInstance = nullptr;
 
-StaticRefPtr<WebGLMemoryTracker> WebGLMemoryTracker::sUniqueInstance;
-
-WebGLMemoryTracker* WebGLMemoryTracker::UniqueInstance()
+WebGLMemoryReporterWrapper* WebGLMemoryReporterWrapper::UniqueInstance()
 {
     if (!sUniqueInstance) {
-        sUniqueInstance = new WebGLMemoryTracker;
-        sUniqueInstance->InitMemoryReporter();
+        sUniqueInstance = new WebGLMemoryReporterWrapper;
     }
     return sUniqueInstance;
 }
 
-WebGLMemoryTracker::WebGLMemoryTracker()
-    : MemoryMultiReporter("webgl")
+WebGLMemoryReporterWrapper::WebGLMemoryReporterWrapper()
 {
+    mReporter = new WebGLMemoryReporter;
+    NS_RegisterMemoryReporter(mReporter);
 }
 
-void
-WebGLMemoryTracker::InitMemoryReporter()
+WebGLMemoryReporterWrapper::~WebGLMemoryReporterWrapper()
 {
-    RegisterWeakMemoryReporter(this);
-}
-
-WebGLMemoryTracker::~WebGLMemoryTracker()
-{
-    UnregisterWeakMemoryReporter(this);
+    NS_UnregisterMemoryReporter(mReporter);
 }
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLBufferMallocSizeOf)
 
 int64_t
-WebGLMemoryTracker::GetBufferCacheMemoryUsed() {
+WebGLMemoryReporterWrapper::GetBufferCacheMemoryUsed() {
     const ContextsArrayType & contexts = Contexts();
     int64_t result = 0;
     for(size_t i = 0; i < contexts.Length(); ++i) {
         for (const WebGLBuffer *buffer = contexts[i]->mBuffers.getFirst();
              buffer;
              buffer = buffer->getNext())
         {
             if (buffer->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
@@ -130,17 +144,17 @@ WebGLMemoryTracker::GetBufferCacheMemory
         }
     }
     return result;
 }
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(WebGLShaderMallocSizeOf)
 
 int64_t
-WebGLMemoryTracker::GetShaderSize() {
+WebGLMemoryReporterWrapper::GetShaderSize() {
     const ContextsArrayType & contexts = Contexts();
     int64_t result = 0;
     for(size_t i = 0; i < contexts.Length(); ++i) {
         for (const WebGLShader *shader = contexts[i]->mShaders.getFirst();
              shader;
              shader = shader->getNext())
         {
             result += shader->SizeOfIncludingThis(WebGLShaderMallocSizeOf);
rename from content/canvas/src/WebGLMemoryTracker.h
rename to content/canvas/src/WebGLMemoryReporterWrapper.h
--- a/content/canvas/src/WebGLMemoryTracker.h
+++ b/content/canvas/src/WebGLMemoryReporterWrapper.h
@@ -1,69 +1,62 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef WEBGLMEMORYTRACKER_H_
-#define WEBGLMEMORYTRACKER_H_
+#ifndef WEBGLMEMORYREPORTERWRAPPER_H_
+#define WEBGLMEMORYREPORTERWRAPPER_H_
 
 #include "WebGLContext.h"
 #include "WebGLBuffer.h"
 #include "WebGLVertexAttribData.h"
 #include "WebGLShader.h"
 #include "WebGLProgram.h"
 #include "WebGLUniformLocation.h"
 #include "WebGLTexture.h"
 #include "WebGLRenderbuffer.h"
-#include "mozilla/StaticPtr.h"
-#include "nsIMemoryReporter.h"
 
 namespace mozilla {
 
-class WebGLMemoryTracker : public MemoryMultiReporter
+class WebGLMemoryReporterWrapper
 {
-    NS_DECL_ISUPPORTS
+    WebGLMemoryReporterWrapper();
+    ~WebGLMemoryReporterWrapper();
+    static WebGLMemoryReporterWrapper* sUniqueInstance;
 
-    WebGLMemoryTracker();
-    virtual ~WebGLMemoryTracker();
-    static StaticRefPtr<WebGLMemoryTracker> sUniqueInstance;
-
-    // Here we store plain pointers, not RefPtrs: we don't want the
-    // WebGLMemoryTracker unique instance to keep alive all
+    // here we store plain pointers, not RefPtrs: we don't want the
+    // WebGLMemoryReporterWrapper unique instance to keep alive all
     // WebGLContexts ever created.
     typedef nsTArray<const WebGLContext*> ContextsArrayType;
     ContextsArrayType mContexts;
 
-    void InitMemoryReporter();
+    nsCOMPtr<nsIMemoryReporter> mReporter;
 
-    static WebGLMemoryTracker* UniqueInstance();
+    static WebGLMemoryReporterWrapper* UniqueInstance();
 
     static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; }
 
     friend class WebGLContext;
 
   public:
 
     static void AddWebGLContext(const WebGLContext* c) {
         Contexts().AppendElement(c);
     }
 
     static void RemoveWebGLContext(const WebGLContext* c) {
         ContextsArrayType & contexts = Contexts();
         contexts.RemoveElement(c);
         if (contexts.IsEmpty()) {
+            delete sUniqueInstance; 
             sUniqueInstance = nullptr;
         }
     }
 
-    NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData);
-
-  private:
     static int64_t GetTextureMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         int64_t result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i) {
             for (const WebGLTexture *texture = contexts[i]->mTextures.getFirst();
                  texture;
                  texture = texture->getNext())
             {
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -13,17 +13,16 @@
 #include "VideoUtils.h"
 #include "MediaDecoderStateMachine.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsContentUtils.h"
 #include "ImageContainer.h"
 #include "MediaResource.h"
 #include "nsError.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/StaticPtr.h"
 #include "nsIMemoryReporter.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include <algorithm>
 
 #ifdef MOZ_WMF
 #include "WMFDecoder.h"
 #endif
@@ -49,63 +48,67 @@ static const int64_t CAN_PLAY_THROUGH_MA
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gMediaDecoderLog;
 #define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #else
 #define DECODER_LOG(type, msg)
 #endif
 
-class MediaMemoryTracker : public MemoryMultiReporter
+class MediaMemoryTracker
 {
-  NS_DECL_ISUPPORTS
-
   MediaMemoryTracker();
-  virtual ~MediaMemoryTracker();
-  void InitMemoryReporter();
-
-  static StaticRefPtr<MediaMemoryTracker> sUniqueInstance;
+  ~MediaMemoryTracker();
+  static MediaMemoryTracker* sUniqueInstance;
 
   static MediaMemoryTracker* UniqueInstance() {
     if (!sUniqueInstance) {
       sUniqueInstance = new MediaMemoryTracker();
-      sUniqueInstance->InitMemoryReporter();
     }
     return sUniqueInstance;
   }
 
   typedef nsTArray<MediaDecoder*> DecodersArray;
   static DecodersArray& Decoders() {
     return UniqueInstance()->mDecoders;
   }
 
   DecodersArray mDecoders;
 
+  nsCOMPtr<nsIMemoryReporter> mReporter;
+
 public:
   static void AddMediaDecoder(MediaDecoder* aDecoder)
   {
     Decoders().AppendElement(aDecoder);
   }
 
   static void RemoveMediaDecoder(MediaDecoder* aDecoder)
   {
     DecodersArray& decoders = Decoders();
     decoders.RemoveElement(aDecoder);
     if (decoders.IsEmpty()) {
+      delete sUniqueInstance;
       sUniqueInstance = nullptr;
     }
   }
 
-  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData);
+  static void GetAmounts(int64_t* aVideo, int64_t* aAudio)
+  {
+    *aVideo = 0;
+    *aAudio = 0;
+    DecodersArray& decoders = Decoders();
+    for (size_t i = 0; i < decoders.Length(); ++i) {
+      *aVideo += decoders[i]->VideoQueueMemoryInUse();
+      *aAudio += decoders[i]->AudioQueueMemoryInUse();
+    }
+  }
 };
 
-StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
-
-NS_IMPL_ISUPPORTS_INHERITED0(MediaMemoryTracker, MemoryMultiReporter)
+MediaMemoryTracker* MediaMemoryTracker::sUniqueInstance = nullptr;
 
 NS_IMPL_ISUPPORTS1(MediaDecoder, nsIObserver)
 
 void MediaDecoder::SetDormantIfNecessary(bool aDormant)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
@@ -1764,62 +1767,61 @@ MediaDecoder::IsWMFEnabled()
 #ifdef MOZ_APPLEMEDIA
 bool
 MediaDecoder::IsAppleMP3Enabled()
 {
   return Preferences::GetBool("media.apple.mp3.enabled");
 }
 #endif
 
-NS_IMETHODIMP
-MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                   nsISupports* aData)
+class MediaReporter MOZ_FINAL : public MemoryMultiReporter
 {
-  int64_t video = 0, audio = 0;
-  DecodersArray& decoders = Decoders();
-  for (size_t i = 0; i < decoders.Length(); ++i) {
-    video += decoders[i]->VideoQueueMemoryInUse();
-    audio += decoders[i]->AudioQueueMemoryInUse();
-  }
+public:
+  MediaReporter()
+    : MemoryMultiReporter("media")
+  {}
+
+  NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
+                            nsISupports* aClosure)
+  {
+    int64_t video, audio;
+    MediaMemoryTracker::GetAmounts(&video, &audio);
 
-#define REPORT(_path, _amount, _desc)                                         \
-  do {                                                                        \
-      nsresult rv;                                                            \
-      rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
-                                   KIND_HEAP, UNITS_BYTES, _amount,           \
-                                   NS_LITERAL_CSTRING(_desc), aData);         \
-      NS_ENSURE_SUCCESS(rv, rv);                                              \
-  } while (0)
+  #define REPORT(_path, _amount, _desc)                                       \
+    do {                                                                      \
+        nsresult rv;                                                          \
+        rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path),         \
+                           nsIMemoryReporter::KIND_HEAP,                      \
+                           nsIMemoryReporter::UNITS_BYTES, _amount,           \
+                           NS_LITERAL_CSTRING(_desc), aClosure);              \
+        NS_ENSURE_SUCCESS(rv, rv);                                            \
+    } while (0)
 
-  REPORT("explicit/media/decoded-video", video,
-         "Memory used by decoded video frames.");
+    REPORT("explicit/media/decoded-video", video,
+           "Memory used by decoded video frames.");
 
-  REPORT("explicit/media/decoded-audio", audio,
-         "Memory used by decoded audio chunks.");
+    REPORT("explicit/media/decoded-audio", audio,
+           "Memory used by decoded audio chunks.");
 
-  return NS_OK;
-}
+    return NS_OK;
+  }
+};
 
 MediaDecoderOwner*
 MediaDecoder::GetOwner()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mOwner;
 }
 
 MediaMemoryTracker::MediaMemoryTracker()
-  : MemoryMultiReporter("media")
+  : mReporter(new MediaReporter())
 {
-}
-
-void
-MediaMemoryTracker::InitMemoryReporter()
-{
-  RegisterWeakMemoryReporter(this);
+  NS_RegisterMemoryReporter(mReporter);
 }
 
 MediaMemoryTracker::~MediaMemoryTracker()
 {
-  UnregisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
 }
 
 } // namespace mozilla
 
--- a/content/media/MediaDecoder.h
+++ b/content/media/MediaDecoder.h
@@ -186,16 +186,17 @@ destroying the MediaDecoder object.
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/TimeStamp.h"
 #include "MediaStreamGraph.h"
 #include "AudioChannelCommon.h"
 #include "AbstractMediaDecoder.h"
 #include "necko-config.h"
 
 class nsIStreamListener;
+class nsIMemoryReporter;
 class nsIPrincipal;
 class nsITimer;
 
 namespace mozilla {
 namespace dom {
 class TimeRanges;
 }
 }
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsScriptNameSpaceManager.h"
 #include "nsCOMPtr.h"
 #include "nsIComponentManager.h"
 #include "nsIComponentRegistrar.h"
 #include "nsICategoryManager.h"
+#include "nsIMemoryReporter.h"
 #include "nsIServiceManager.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIScriptExternalNameSet.h"
 #include "nsIScriptNameSpaceManager.h"
 #include "nsIScriptContext.h"
 #include "nsIInterfaceInfoManager.h"
 #include "nsIInterfaceInfo.h"
@@ -111,35 +112,48 @@ GlobalNameHashInitEntry(PLDHashTable *ta
   new (&e->mKey) nsString(*keyStr);
 
   // This will set e->mGlobalName.mType to
   // nsGlobalNameStruct::eTypeNotInitialized
   memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
   return true;
 }
 
-NS_IMPL_ISUPPORTS_INHERITED2(
-  nsScriptNameSpaceManager,
-  MemoryUniReporter,
-  nsIObserver,
-  nsISupportsWeakReference)
+class ScriptNameSpaceManagerReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+  ScriptNameSpaceManagerReporter(nsScriptNameSpaceManager* aManager)
+    : MemoryUniReporter(
+        "explicit/script-namespace-manager",
+        KIND_HEAP,
+        nsIMemoryReporter::UNITS_BYTES,
+        "Memory used for the script namespace manager.")
+    , mManager(aManager)
+  {}
+
+private:
+  int64_t Amount() { return mManager->SizeOfIncludingThis(MallocSizeOf); }
+
+  nsScriptNameSpaceManager* mManager;
+};
+
+NS_IMPL_ISUPPORTS2(nsScriptNameSpaceManager,
+                   nsIObserver,
+                   nsISupportsWeakReference)
 
 nsScriptNameSpaceManager::nsScriptNameSpaceManager()
-  : MemoryUniReporter("explicit/script-namespace-manager",
-                      KIND_HEAP, UNITS_BYTES,
-                      "Memory used for the script namespace manager.")
-  , mIsInitialized(false)
+  : mIsInitialized(false)
 {
   MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
 }
 
 nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
 {
   if (mIsInitialized) {
-    UnregisterWeakMemoryReporter(this);
+    NS_UnregisterMemoryReporter(mReporter);
     // Destroy the hash
     PL_DHashTableFinish(&mGlobalNames);
     PL_DHashTableFinish(&mNavigatorNames);
   }
   MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
 }
 
 nsGlobalNameStruct *
@@ -344,17 +358,18 @@ nsScriptNameSpaceManager::Init()
                                      sizeof(GlobalNameMapEntry), 
                                      GLOBALNAME_HASHTABLE_INITIAL_SIZE);
   if (!mIsInitialized) {
     PL_DHashTableFinish(&mGlobalNames);
 
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  RegisterWeakMemoryReporter(this);
+  mReporter = new ScriptNameSpaceManagerReporter(this);
+  NS_RegisterMemoryReporter(mReporter);
 
   nsresult rv = NS_OK;
 
   rv = RegisterExternalInterfaces(false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsICategoryManager> cm =
     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
@@ -862,24 +877,18 @@ nsScriptNameSpaceManager::EnumerateNavig
 static size_t
 SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, MallocSizeOf aMallocSizeOf,
                          void *aArg)
 {
     GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr);
     return entry->SizeOfExcludingThis(aMallocSizeOf);
 }
 
-int64_t
-nsScriptNameSpaceManager::Amount()
-{
-  return SizeOfIncludingThis(MallocSizeOf);
-}
-
 size_t
-nsScriptNameSpaceManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+nsScriptNameSpaceManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
 {
   size_t n = 0;
   n += PL_DHashTableSizeOfExcludingThis(&mGlobalNames,
          SizeOfEntryExcludingThis, aMallocSizeOf);
   n += PL_DHashTableSizeOfExcludingThis(&mNavigatorNames,
          SizeOfEntryExcludingThis, aMallocSizeOf);
   return n;
 }
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -17,17 +17,16 @@
  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
  *                               use in OS2
  */
 
 #ifndef nsScriptNameSpaceManager_h__
 #define nsScriptNameSpaceManager_h__
 
 #include "mozilla/MemoryReporting.h"
-#include "nsIMemoryReporter.h"
 #include "nsIScriptNameSpaceManager.h"
 #include "nsString.h"
 #include "nsID.h"
 #include "pldhash.h"
 #include "nsDOMClassInfo.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "xpcpublic.h"
@@ -80,21 +79,21 @@ struct nsGlobalNameStruct
   };
   // May be null if enabled unconditionally
   mozilla::dom::ConstructorEnabled* mConstructorEnabled;
 };
 
 
 class nsIScriptContext;
 class nsICategoryManager;
+class nsIMemoryReporter;
 class GlobalNameMapEntry;
 
 
-class nsScriptNameSpaceManager : public mozilla::MemoryUniReporter,
-                                 public nsIObserver,
+class nsScriptNameSpaceManager : public nsIObserver,
                                  public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   nsScriptNameSpaceManager();
   virtual ~nsScriptNameSpaceManager();
@@ -158,17 +157,16 @@ public:
   typedef PLDHashOperator
   (* NameEnumerator)(const nsAString& aGlobalName, void* aClosure);
 
   void EnumerateGlobalNames(NameEnumerator aEnumerator,
                             void* aClosure);
   void EnumerateNavigatorNames(NameEnumerator aEnumerator,
                                void* aClosure);
 
-  int64_t Amount() MOZ_OVERRIDE;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 private:
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
   nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const nsAString *aKey,
@@ -221,11 +219,13 @@ private:
 
   nsGlobalNameStruct* LookupNameInternal(const nsAString& aName,
                                          const PRUnichar **aClassName = nullptr);
 
   PLDHashTable mGlobalNames;
   PLDHashTable mNavigatorNames;
 
   bool mIsInitialized;
+
+  nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 #endif /* nsScriptNameSpaceManager_h__ */
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -89,30 +89,30 @@ NonJSSizeOfTab(nsPIDOMWindow* aWindow, s
 }
 
 /* static */ void
 nsWindowMemoryReporter::Init()
 {
   MOZ_ASSERT(!sWindowReporter);
   sWindowReporter = new nsWindowMemoryReporter();
   ClearOnShutdown(&sWindowReporter);
-  RegisterStrongMemoryReporter(sWindowReporter);
+  NS_RegisterMemoryReporter(sWindowReporter);
   RegisterNonJSSizeOfTab(NonJSSizeOfTab);
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     // DOM_WINDOW_DESTROYED_TOPIC announces what we call window "detachment",
     // when a window's docshell is set to nullptr.
     os->AddObserver(sWindowReporter, DOM_WINDOW_DESTROYED_TOPIC,
                     /* weakRef = */ true);
     os->AddObserver(sWindowReporter, "after-minimize-memory-usage",
                     /* weakRef = */ true);
   }
 
-  RegisterStrongMemoryReporter(new GhostWindowsReporter());
+  NS_RegisterMemoryReporter(new GhostWindowsReporter());
   RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount);
 }
 
 static already_AddRefed<nsIURI>
 GetWindowURI(nsIDOMWindow *aWindow)
 {
   nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aWindow);
   NS_ENSURE_TRUE(pWindow, nullptr);
@@ -444,16 +444,23 @@ ReportGhostWindowsEnumerator(nsUint64Has
   if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
     data->rv = rv;
   }
 
   return PL_DHASH_NEXT;
 }
 
 NS_IMETHODIMP
+nsWindowMemoryReporter::GetName(nsACString &aName)
+{
+  aName.AssignLiteral("window-objects");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
                                        nsISupports* aClosure)
 {
   nsGlobalWindow::WindowByIdTable* windowsById =
     nsGlobalWindow::GetWindowsTable();
   NS_ENSURE_TRUE(windowsById, NS_OK);
 
   // Hold on to every window in memory so that window objects can't be
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -332,18 +332,17 @@ ContentParent::MaybeTakePreallocatedAppP
 
 /*static*/ void
 ContentParent::StartUp()
 {
     if (XRE_GetProcessType() != GeckoProcessType_Default) {
         return;
     }
 
-    // Note: This reporter measures all ContentParents.
-    RegisterStrongMemoryReporter(new ContentParentsMemoryReporter());
+    NS_RegisterMemoryReporter(new ContentParentsMemoryReporter());
 
     sCanLaunchSubprocesses = true;
 
     // Try to preallocate a process that we can transform into an app later.
     PreallocatedProcessManager::AllocateAfterDelay();
 }
 
 /*static*/ void
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4018,17 +4018,17 @@ void
 WorkerPrivate::EnableMemoryReporter()
 {
   AssertIsOnWorkerThread();
 
   // No need to lock here since the main thread can't race until we've
   // successfully registered the reporter.
   mMemoryReporter = new MemoryReporter(this);
 
-  if (NS_FAILED(RegisterWeakMemoryReporter(mMemoryReporter))) {
+  if (NS_FAILED(NS_RegisterMemoryReporter(mMemoryReporter))) {
     NS_WARNING("Failed to register memory reporter!");
     // No need to lock here since a failed registration means our memory
     // reporter can't start running. Just clean up.
     mMemoryReporter = nullptr;
 
     return;
   }
 }
@@ -4073,17 +4073,17 @@ WorkerPrivate::DisableMemoryReporter()
       }
 
       NS_ASSERTION(mBlockedForMemoryReporter, "Somehow we got unblocked!");
       mBlockedForMemoryReporter = false;
     }
   }
 
   // Finally unregister the memory reporter.
-  if (NS_FAILED(UnregisterWeakMemoryReporter(memoryReporter))) {
+  if (NS_FAILED(NS_UnregisterMemoryReporter(memoryReporter))) {
     NS_WARNING("Failed to unregister memory reporter!");
   }
 }
 
 void
 WorkerPrivate::WaitForWorkerEvents(PRIntervalTime aInterval)
 {
   AssertIsOnWorkerThread();
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -69,81 +69,93 @@
 #include "mozISpellI18NManager.h"
 #include "nsICharsetConverterManager.h"
 #include "nsUnicharUtilCIID.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "mozInlineSpellChecker.h"
 #include "mozilla/Services.h"
 #include <stdlib.h>
+#include "nsIMemoryReporter.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 
 static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell)
 
 NS_INTERFACE_MAP_BEGIN(mozHunspell)
-  NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter)
   NS_INTERFACE_MAP_ENTRY(mozISpellCheckingEngine)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellCheckingEngine)
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozHunspell)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_3(mozHunspell,
                            mPersonalDictionary,
                            mEncoder,
                            mDecoder)
 
-int64_t mozHunspell::sAmount = 0;
+class SpellCheckReporter MOZ_FINAL : public mozilla::MemoryUniReporter
+{
+public:
+  SpellCheckReporter()
+    : MemoryUniReporter("explicit/spell-check", KIND_HEAP, UNITS_BYTES,
+"Memory used by the Hunspell spell checking engine's internal data structures.")
+  {
+#ifdef DEBUG
+    // There must be only one instance of this class, due to |sAmount|
+    // being static.
+    static bool hasRun = false;
+    MOZ_ASSERT(!hasRun);
+    hasRun = true;
+#endif
+  }
+
+  static void OnAlloc(void* ptr) { sAmount += MallocSizeOfOnAlloc(ptr); }
+  static void OnFree (void* ptr) { sAmount -= MallocSizeOfOnFree (ptr); }
+
+private:
+  int64_t Amount() MOZ_OVERRIDE { return sAmount; }
+
+  static int64_t sAmount;
+};
+
+int64_t SpellCheckReporter::sAmount = 0;
 
 // WARNING: hunspell_alloc_hooks.h uses these two functions.
 void HunspellReportMemoryAllocation(void* ptr) {
-  mozHunspell::OnAlloc(ptr);
+  SpellCheckReporter::OnAlloc(ptr);
 }
 void HunspellReportMemoryDeallocation(void* ptr) {
-  mozHunspell::OnFree(ptr);
-}
-
-mozHunspell::mozHunspell()
-  : MemoryUniReporter("explicit/spell-check", KIND_HEAP, UNITS_BYTES,
-"Memory used by the spell-checking engine's internal data structures."),
-    mHunspell(nullptr)
-{
-#ifdef DEBUG
-  // There must be only one instance of this class, due to |sAmount|
-  // being static.
-  static bool hasRun = false;
-  MOZ_ASSERT(!hasRun);
-  hasRun = true;
-#endif
+  SpellCheckReporter::OnFree(ptr);
 }
 
 nsresult
 mozHunspell::Init()
 {
   LoadDictionaryList();
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->AddObserver(this, "profile-do-change", true);
     obs->AddObserver(this, "profile-after-change", true);
   }
 
-  RegisterWeakMemoryReporter(this);
+  mReporter = new SpellCheckReporter();
+  NS_RegisterMemoryReporter(mReporter);
 
   return NS_OK;
 }
 
 mozHunspell::~mozHunspell()
 {
-  UnregisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
 
   mPersonalDictionary = nullptr;
   delete mHunspell;
 }
 
 /* attribute wstring dictionary; */
 NS_IMETHODIMP mozHunspell::GetDictionary(PRUnichar **aDictionary)
 {
--- a/extensions/spellcheck/hunspell/src/mozHunspell.h
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.h
@@ -61,69 +61,64 @@
 #define mozHunspell_h__
 
 #include <hunspell.hxx>
 #include "mozISpellCheckingEngine.h"
 #include "mozIPersonalDictionary.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
-#include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsInterfaceHashtable.h"
 #include "nsWeakReference.h"
 #include "nsCycleCollectionParticipant.h"
 
 #define MOZ_HUNSPELL_CONTRACTID "@mozilla.org/spellchecker/engine;1"
 #define MOZ_HUNSPELL_CID         \
 /* 56c778e4-1bee-45f3-a689-886692a97fe7 */   \
 { 0x56c778e4, 0x1bee, 0x45f3, \
   { 0xa6, 0x89, 0x88, 0x66, 0x92, 0xa9, 0x7f, 0xe7 } }
 
-class mozHunspell : public mozilla::MemoryUniReporter,
-                    public mozISpellCheckingEngine,
-                    public nsIObserver,
-                    public nsSupportsWeakReference
+class nsIMemoryReporter;
+
+class mozHunspell : public mozISpellCheckingEngine,
+                   public nsIObserver,
+                   public nsSupportsWeakReference
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_MOZISPELLCHECKINGENGINE
   NS_DECL_NSIOBSERVER
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozHunspell, mozISpellCheckingEngine)
 
-  mozHunspell();
+  mozHunspell() : mHunspell(nullptr) { }
   virtual ~mozHunspell();
 
   nsresult Init();
 
   void LoadDictionaryList();
 
   // helper method for converting a word to the charset of the dictionary
   nsresult ConvertCharset(const PRUnichar* aStr, char ** aDst);
 
-  static void OnAlloc(void* ptr) { sAmount += MallocSizeOfOnAlloc(ptr); }
-  static void OnFree (void* ptr) { sAmount -= MallocSizeOfOnFree (ptr); }
-
-  int64_t Amount() MOZ_OVERRIDE { return sAmount; }
-
 protected:
-
+ 
   nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
-  nsCOMPtr<nsIUnicodeEncoder>      mEncoder;
-  nsCOMPtr<nsIUnicodeDecoder>      mDecoder;
+  nsCOMPtr<nsIUnicodeEncoder>      mEncoder; 
+  nsCOMPtr<nsIUnicodeDecoder>      mDecoder; 
 
   // Hashtable matches dictionary name to .aff file
   nsInterfaceHashtable<nsStringHashKey, nsIFile> mDictionaries;
   nsString  mDictionary;
   nsString  mLanguage;
   nsCString mAffixFileName;
 
   // dynamic dirs used to search for dictionaries
   nsCOMArray<nsIFile> mDynamicDirectories;
 
   Hunspell  *mHunspell;
 
-  static int64_t sAmount;
+  nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 #endif
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -1232,17 +1232,17 @@ GLContext::CanReadSRGBFromFBOTexture()
 
 bool GLContext::sPowerOfTwoForced = false;
 bool GLContext::sPowerOfTwoPrefCached = false;
 
 void
 GLContext::PlatformStartup()
 {
   CacheCanUploadNPOT();
-  RegisterStrongMemoryReporter(new GfxTexturesReporter());
+  NS_RegisterMemoryReporter(new GfxTexturesReporter());
 }
 
 void
 GLContext::CacheCanUploadNPOT()
 {
     MOZ_ASSERT(NS_IsMainThread(), "Can't cache prefs off the main thread.");
     MOZ_ASSERT(!sPowerOfTwoPrefCached, "Must only call this function once!");
 
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -220,17 +220,17 @@ GrallocBufferActor::GrallocBufferActor()
 : mAllocBytes(0)
 {
   static bool registered;
   if (!registered) {
     // We want to be sure that the first call here will always run on
     // the main thread.
     NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
-    RegisterStrongMemoryReporter(new GrallocReporter());
+    NS_RegisterMemoryReporter(new GrallocReporter());
     registered = true;
   }
 }
 
 GrallocBufferActor::~GrallocBufferActor()
 {
   if (mAllocBytes > 0) {
     GrallocReporter::sAmount -= mAllocBytes;
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -671,17 +671,17 @@ gfxASurface::RecordMemoryUsedForSurfaceT
 {
     if (aType < 0 || aType >= gfxSurfaceTypeMax) {
         NS_WARNING("Invalid type to RecordMemoryUsedForSurfaceType!");
         return;
     }
 
     static bool registered = false;
     if (!registered) {
-        RegisterStrongMemoryReporter(new SurfaceMemoryReporter());
+        NS_RegisterMemoryReporter(new SurfaceMemoryReporter());
         registered = true;
     }
 
     gSurfaceMemoryUsed[aType] += aBytes;
 }
 
 void
 gfxASurface::RecordMemoryUsed(int32_t aBytes)
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -92,17 +92,18 @@ gfxAndroidPlatform::gfxAndroidPlatform()
     sFreetypeMemoryRecord.free    = FreetypeReporter::CountingFree;
     sFreetypeMemoryRecord.realloc = FreetypeReporter::CountingRealloc;
 
     // These two calls are equivalent to FT_Init_FreeType(), but allow us to
     // provide a custom memory allocator.
     FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary);
     FT_Add_Default_Modules(gPlatformFTLibrary);
 
-    RegisterStrongMemoryReporter(new FreetypeReporter());
+    mFreetypeReporter = new FreetypeReporter();
+    NS_RegisterMemoryReporter(mFreetypeReporter);
 
     nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
     nsCOMPtr<nsIScreen> screen;
     screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
     mScreenDepth = 24;
     screen->GetColorDepth(&mScreenDepth);
 
     mOffscreenFormat = mScreenDepth == 16
@@ -114,16 +115,18 @@ gfxAndroidPlatform::gfxAndroidPlatform()
     }
 
 }
 
 gfxAndroidPlatform::~gfxAndroidPlatform()
 {
     cairo_debug_reset_static_data();
 
+    NS_UnregisterMemoryReporter(mFreetypeReporter);
+
     FT_Done_Library(gPlatformFTLibrary);
     gPlatformFTLibrary = nullptr;
 }
 
 already_AddRefed<gfxASurface>
 gfxAndroidPlatform::CreateOffscreenSurface(const gfxIntSize& size,
                                       gfxContentType contentType)
 {
--- a/gfx/thebes/gfxAndroidPlatform.h
+++ b/gfx/thebes/gfxAndroidPlatform.h
@@ -76,12 +76,14 @@ public:
 
     FT_Library GetFTLibrary();
 
     virtual int GetScreenDepth() const;
 
 private:
     int mScreenDepth;
     gfxImageFormat mOffscreenFormat;
+
+    nsCOMPtr<nsIMemoryReporter> mFreetypeReporter;
 };
 
 #endif /* GFX_PLATFORM_ANDROID_H */
 
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1410,17 +1410,17 @@ gfxFontCache::Observer::Observe(nsISuppo
 nsresult
 gfxFontCache::Init()
 {
     NS_ASSERTION(!gGlobalCache, "Where did this come from?");
     gGlobalCache = new gfxFontCache();
     if (!gGlobalCache) {
         return NS_ERROR_OUT_OF_MEMORY;
     }
-    RegisterStrongMemoryReporter(new MemoryReporter());
+    NS_RegisterMemoryReporter(new MemoryReporter);
     return NS_OK;
 }
 
 void
 gfxFontCache::Shutdown()
 {
     delete gGlobalCache;
     gGlobalCache = nullptr;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -497,17 +497,17 @@ gfxPlatform::Init()
 
     // Listen to memory pressure event so we can purge DrawTarget caches
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
         gPlatform->mMemoryPressureObserver = new MemoryPressureObserver();
         obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false);
     }
 
-    RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
+    NS_RegisterMemoryReporter(new GfxMemoryImageReporter());
 }
 
 void
 gfxPlatform::Shutdown()
 {
     // These may be called before the corresponding subsystems have actually
     // started up. That's OK, they can handle it.
     gfxFontCache::Shutdown();
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -132,17 +132,17 @@ gfxPlatformFontList::gfxPlatformFontList
 
     // pref changes notification setup
     NS_ASSERTION(!gFontListPrefObserver,
                  "There has been font list pref observer already");
     gFontListPrefObserver = new gfxFontListPrefObserver();
     NS_ADDREF(gFontListPrefObserver);
     Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
 
-    RegisterStrongMemoryReporter(new MemoryReporter());
+    NS_RegisterMemoryReporter(new MemoryReporter);
 }
 
 gfxPlatformFontList::~gfxPlatformFontList()
 {
     mSharedCmaps.Clear();
     NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
     Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
     NS_RELEASE(gFontListPrefObserver);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -361,32 +361,36 @@ gfxWindowsPlatform::gfxWindowsPlatform()
     /* 
      * Initialize COM 
      */ 
     CoInitialize(nullptr); 
 
     mScreenDC = GetDC(nullptr);
 
 #ifdef CAIRO_HAS_D2D_SURFACE
-    RegisterStrongMemoryReporter(new GfxD2DSurfaceCacheReporter());
-    RegisterStrongMemoryReporter(new GfxD2DSurfaceVramReporter());
+    NS_RegisterMemoryReporter(new GfxD2DSurfaceCacheReporter());
+    NS_RegisterMemoryReporter(new GfxD2DSurfaceVramReporter());
     mD2DDevice = nullptr;
 #endif
-    RegisterStrongMemoryReporter(new GfxD2DVramDrawTargetReporter());
-    RegisterStrongMemoryReporter(new GfxD2DVramSourceSurfaceReporter());
+    NS_RegisterMemoryReporter(new GfxD2DVramDrawTargetReporter());
+    NS_RegisterMemoryReporter(new GfxD2DVramSourceSurfaceReporter());
 
     UpdateRenderMode();
 
     // This reporter is disabled because it frequently gives bogus values.  See
     // bug 917496.
-    //RegisterStrongMemoryReporter(new GPUAdapterReporter());
+    //mGPUAdapterReporter = new GPUAdapterReporter();
+    //NS_RegisterMemoryReporter(mGPUAdapterReporter);
+    mGPUAdapterReporter = nullptr;
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
+    //NS_UnregisterMemoryReporter(mGPUAdapterReporter);
+
     mDeviceManager = nullptr;
 
     ::ReleaseDC(nullptr, mScreenDC);
     // not calling FT_Done_FreeType because cairo may still hold references to
     // these FT_Faces.  See bug 458169.
 #ifdef CAIRO_HAS_D2D_SURFACE
     if (mD2DDevice) {
         cairo_release_device(mD2DDevice);
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -296,11 +296,13 @@ private:
     nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
     mozilla::RefPtr<ID3D11Device> mD3D11Device;
     bool mD3D11DeviceInitialized;
 
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
     // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
     nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
+
+    nsIMemoryReporter* mGPUAdapterReporter;
 };
 
 #endif /* GFX_WINDOWS_PLATFORM_H */
--- a/image/src/SurfaceCache.cpp
+++ b/image/src/SurfaceCache.cpp
@@ -9,17 +9,16 @@
 
 #include "SurfaceCache.h"
 
 #include <algorithm>
 #include "mozilla/Attributes.h"  // for MOZ_THIS_IN_INITIALIZER_LIST
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/RefPtr.h"
-#include "mozilla/StaticPtr.h"
 #include "mozilla/Util.h"  // for Maybe
 #include "gfxASurface.h"
 #include "gfxPattern.h"  // Workaround for flaw in bug 921753 part 2.
 #include "gfxDrawable.h"
 #include "gfxPlatform.h"
 #include "nsAutoPtr.h"
 #include "nsExpirationTracker.h"
 #include "nsHashKeys.h"
@@ -65,17 +64,17 @@ namespace image {
 class CachedSurface;
 class SurfaceCacheImpl;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Static Data
 ///////////////////////////////////////////////////////////////////////////////
 
 // The single surface cache instance.
-static StaticRefPtr<SurfaceCacheImpl> sInstance;
+static SurfaceCacheImpl* sInstance = nullptr;
 
 
 ///////////////////////////////////////////////////////////////////////////////
 // SurfaceCache Implementation
 ///////////////////////////////////////////////////////////////////////////////
 
 /*
  * Cost models the cost of storing a surface in the cache. Right now, this is
@@ -219,48 +218,42 @@ private:
 
 /*
  * SurfaceCacheImpl is responsible for determining which surfaces will be cached
  * and managing the surface cache data structures. Rather than interact with
  * SurfaceCacheImpl directly, client code interacts with SurfaceCache, which
  * maintains high-level invariants and encapsulates the details of the surface
  * cache's implementation.
  */
-class SurfaceCacheImpl : public MemoryUniReporter
+class SurfaceCacheImpl
 {
 public:
-  NS_DECL_ISUPPORTS
-
   SurfaceCacheImpl(uint32_t aSurfaceCacheExpirationTimeMS,
                    uint32_t aSurfaceCacheSize)
-    : MemoryUniReporter("imagelib-surface-cache",
-                        KIND_OTHER, UNITS_BYTES,
-                        "Memory used by the imagelib temporary surface cache.")
-    , mExpirationTracker(MOZ_THIS_IN_INITIALIZER_LIST(),
+    : mExpirationTracker(MOZ_THIS_IN_INITIALIZER_LIST(),
                          aSurfaceCacheExpirationTimeMS)
+    , mReporter(new SurfaceCacheReporter)
     , mMemoryPressureObserver(new MemoryPressureObserver)
     , mMaxCost(aSurfaceCacheSize)
     , mAvailableCost(aSurfaceCacheSize)
   {
+    NS_RegisterMemoryReporter(mReporter);
+
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     if (os)
       os->AddObserver(mMemoryPressureObserver, "memory-pressure", false);
   }
 
-  virtual ~SurfaceCacheImpl()
+  ~SurfaceCacheImpl()
   {
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     if (os)
       os->RemoveObserver(mMemoryPressureObserver, "memory-pressure");
 
-    UnregisterWeakMemoryReporter(this);
-  }
-
-  void InitMemoryReporter() {
-    RegisterWeakMemoryReporter(this);
+    NS_UnregisterMemoryReporter(mReporter);
   }
 
   void Insert(DrawTarget*       aTarget,
               nsIntSize         aTargetSize,
               const Cost        aCost,
               const ImageKey    aImageKey,
               const SurfaceKey& aSurfaceKey)
   {
@@ -384,28 +377,19 @@ public:
   static PLDHashOperator DoStopTracking(const SurfaceKey&,
                                         CachedSurface*    aSurface,
                                         void*             aCache)
   {
     static_cast<SurfaceCacheImpl*>(aCache)->StopTracking(aSurface);
     return PL_DHASH_NEXT;
   }
 
-  int64_t Amount() MOZ_OVERRIDE
+  int64_t SizeOfSurfacesEstimate() const
   {
-    return SizeOfSurfacesEstimate();
-  }
-
-  // XXX(seth): This is currently only an estimate and, since we don't know
-  // which surfaces are in GPU memory and which aren't, it's reported as
-  // KIND_OTHER and will also show up in heap-unclassified. Bug 923302 will
-  // make this nicer.
-  Cost SizeOfSurfacesEstimate() const
-  {
-    return mMaxCost - mAvailableCost;
+    return int64_t(mMaxCost - mAvailableCost);
   }
 
 private:
   already_AddRefed<ImageSurfaceCache> GetImageCache(const ImageKey aImageKey)
   {
     nsRefPtr<ImageSurfaceCache> imageCache;
     mImageCaches.Get(aImageKey, getter_AddRefs(imageCache));
     return imageCache.forget();
@@ -425,16 +409,35 @@ private:
         mCache->Remove(aSurface);
       }
     }
 
   private:
     SurfaceCacheImpl* const mCache;  // Weak pointer to owner.
   };
 
+  // XXX(seth): This is currently only an estimate and, since we don't know which
+  // surfaces are in GPU memory and which aren't, it's reported as KIND_OTHER and
+  // will also show up in heap-unclassified. Bug 923302 will make this nicer.
+  struct SurfaceCacheReporter : public MemoryUniReporter
+  {
+    SurfaceCacheReporter()
+      : MemoryUniReporter("imagelib-surface-cache",
+                          KIND_OTHER,
+                          UNITS_BYTES,
+                          "Memory used by the imagelib temporary surface cache.")
+    { }
+
+  protected:
+    int64_t Amount() MOZ_OVERRIDE
+    {
+      return sInstance ? sInstance->SizeOfSurfacesEstimate() : 0;
+    }
+  };
+
   struct MemoryPressureObserver : public nsIObserver
   {
     NS_DECL_ISUPPORTS
 
     virtual ~MemoryPressureObserver() { }
 
     NS_IMETHOD Observe(nsISupports*, const char* aTopic, const PRUnichar*)
     {
@@ -444,22 +447,22 @@ private:
       return NS_OK;
     }
   };
 
 
   nsTArray<CostEntry>                                       mCosts;
   nsRefPtrHashtable<nsPtrHashKey<Image>, ImageSurfaceCache> mImageCaches;
   SurfaceTracker                                            mExpirationTracker;
+  nsRefPtr<SurfaceCacheReporter>                            mReporter;
   nsRefPtr<MemoryPressureObserver>                          mMemoryPressureObserver;
   const Cost                                                mMaxCost;
   Cost                                                      mAvailableCost;
 };
 
-NS_IMPL_ISUPPORTS_INHERITED0(SurfaceCacheImpl, MemoryUniReporter)
 NS_IMPL_ISUPPORTS1(SurfaceCacheImpl::MemoryPressureObserver, nsIObserver)
 
 ///////////////////////////////////////////////////////////////////////////////
 // Public API
 ///////////////////////////////////////////////////////////////////////////////
 
 /* static */ void
 SurfaceCache::Initialize()
@@ -494,23 +497,23 @@ SurfaceCache::Initialize()
   uint32_t proposedSize = PR_GetPhysicalMemorySize() / surfaceCacheSizeFactor;
   uint32_t surfaceCacheSizeBytes = min(proposedSize, surfaceCacheMaxSizeKB * 1024);
 
   // Create the surface cache singleton with the requested expiration time and
   // size. Note that the size is a limit that the cache may not grow beyond, but
   // we do not actually allocate any storage for surfaces at this time.
   sInstance = new SurfaceCacheImpl(surfaceCacheExpirationTimeMS,
                                    surfaceCacheSizeBytes);
-  sInstance->InitMemoryReporter();
 }
 
 /* static */ void
 SurfaceCache::Shutdown()
 {
   MOZ_ASSERT(sInstance, "No singleton - was Shutdown() called twice?");
+  delete sInstance;
   sInstance = nullptr;
 }
 
 /* static */ already_AddRefed<gfxDrawable>
 SurfaceCache::Lookup(const ImageKey    aImageKey,
                      const SurfaceKey& aSurfaceKey)
 {
   MOZ_ASSERT(sInstance, "Should be initialized");
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -815,17 +815,17 @@ void imgLoader::GlobalInit()
   int32_t cachesize;
   rv = Preferences::GetInt("image.cache.size", &cachesize);
   if (NS_SUCCEEDED(rv))
     sCacheMaxSize = cachesize;
   else
     sCacheMaxSize = 5 * 1024 * 1024;
 
   sMemReporter = new imgMemoryReporter();
-  RegisterStrongMemoryReporter(sMemReporter);
+  NS_RegisterMemoryReporter(sMemReporter);
   RegisterImagesContentUsedUncompressedDistinguishedAmount(imgMemoryReporter::ImagesContentUsedUncompressedDistinguishedAmount);
 }
 
 nsresult imgLoader::InitCache()
 {
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (!os)
     return NS_ERROR_FAILURE;
--- a/ipc/glue/SharedMemory.cpp
+++ b/ipc/glue/SharedMemory.cpp
@@ -41,18 +41,18 @@ private:
 };
 
 SharedMemory::SharedMemory()
   : mAllocSize(0)
   , mMappedSize(0)
 {
   static Atomic<uint32_t> registered;
   if (registered.compareExchange(0, 1)) {
-    RegisterStrongMemoryReporter(new ShmemAllocatedReporter());
-    RegisterStrongMemoryReporter(new ShmemMappedReporter());
+    NS_RegisterMemoryReporter(new ShmemAllocatedReporter());
+    NS_RegisterMemoryReporter(new ShmemMappedReporter());
   }
 }
 
 /*static*/ size_t
 SharedMemory::PageAlignedSize(size_t aSize)
 {
   size_t pageSize = SystemPageSize();
   size_t nPagesNeeded = size_t(ceil(double(aSize) / double(pageSize)));
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -3091,18 +3091,18 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
 
     // Set up locale information and callbacks for the newly-created runtime so
     // that the various toLocaleString() methods, localeCompare(), and other
     // internationalization APIs work as desired.
     if (!xpc_LocalizeRuntime(runtime))
         NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
 
     // Register memory reporters and distinguished amount functions.
-    RegisterStrongMemoryReporter(new JSMainRuntimeCompartmentsReporter());
-    RegisterStrongMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
+    NS_RegisterMemoryReporter(new JSMainRuntimeCompartmentsReporter);
+    NS_RegisterMemoryReporter(new JSMainRuntimeTemporaryPeakReporter());
     RegisterJSMainRuntimeGCHeapDistinguishedAmount(JSMainRuntimeGCHeapDistinguishedAmount);
     RegisterJSMainRuntimeTemporaryPeakDistinguishedAmount(JSMainRuntimeTemporaryPeakDistinguishedAmount);
     RegisterJSMainRuntimeCompartmentsSystemDistinguishedAmount(JSMainRuntimeCompartmentsSystemDistinguishedAmount);
     RegisterJSMainRuntimeCompartmentsUserDistinguishedAmount(JSMainRuntimeCompartmentsUserDistinguishedAmount);
     mozilla::RegisterJSSizeOfTab(JSSizeOfTab);
 
     // Install a JavaScript 'debugger' keyword handler in debug builds only
 #ifdef DEBUG
--- a/layout/base/nsStyleSheetService.cpp
+++ b/layout/base/nsStyleSheetService.cpp
@@ -16,42 +16,60 @@
 #include "nsCSSStyleSheet.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsICategoryManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsNetUtil.h"
 #include "nsIObserverService.h"
 #include "nsLayoutStatics.h"
+#include "nsIMemoryReporter.h"
 
 using namespace mozilla;
 
+class LayoutStyleSheetServiceReporter MOZ_FINAL
+  : public mozilla::MemoryUniReporter
+{
+public:
+  LayoutStyleSheetServiceReporter()
+    : MemoryUniReporter("explicit/layout/style-sheet-service",
+                         KIND_HEAP, UNITS_BYTES,
+"Memory used for style sheets held by the style sheet service.")
+  {}
+private:
+  int64_t Amount() MOZ_OVERRIDE
+  {
+    return nsStyleSheetService::gInstance
+         ? nsStyleSheetService::gInstance->SizeOfIncludingThis(MallocSizeOf)
+         : 0;
+  }
+};
+
 nsStyleSheetService *nsStyleSheetService::gInstance = nullptr;
 
 nsStyleSheetService::nsStyleSheetService()
-  : MemoryUniReporter("explicit/layout/style-sheet-service",
-                       KIND_HEAP, UNITS_BYTES,
-"Memory used for style sheets held by the style sheet service.")
 {
   PR_STATIC_ASSERT(0 == AGENT_SHEET && 1 == USER_SHEET && 2 == AUTHOR_SHEET);
   NS_ASSERTION(!gInstance, "Someone is using CreateInstance instead of GetService");
   gInstance = this;
   nsLayoutStatics::AddRef();
+
+  mReporter = new LayoutStyleSheetServiceReporter();
+  NS_RegisterMemoryReporter(mReporter);
 }
 
 nsStyleSheetService::~nsStyleSheetService()
 {
-  UnregisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
 
   gInstance = nullptr;
   nsLayoutStatics::Release();
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(
-  nsStyleSheetService, MemoryUniReporter, nsIStyleSheetService)
+NS_IMPL_ISUPPORTS1(nsStyleSheetService, nsIStyleSheetService)
 
 void
 nsStyleSheetService::RegisterFromEnumerator(nsICategoryManager  *aManager,
                                             const char          *aCategory,
                                             nsISimpleEnumerator *aEnumerator,
                                             uint32_t             aSheetType)
 {
   if (!aEnumerator)
@@ -118,18 +136,16 @@ nsStyleSheetService::Init()
   RegisterFromEnumerator(catMan, "agent-style-sheets", sheets, AGENT_SHEET);
 
   catMan->EnumerateCategory("user-style-sheets", getter_AddRefs(sheets));
   RegisterFromEnumerator(catMan, "user-style-sheets", sheets, USER_SHEET);
 
   catMan->EnumerateCategory("author-style-sheets", getter_AddRefs(sheets));
   RegisterFromEnumerator(catMan, "author-style-sheets", sheets, AUTHOR_SHEET);
 
-  RegisterWeakMemoryReporter(this);
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStyleSheetService::LoadAndRegisterSheet(nsIURI *aSheetURI,
                                           uint32_t aSheetType)
 {
   nsresult rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType);
@@ -280,24 +296,18 @@ nsStyleSheetService::GetInstance()
 
 static size_t
 SizeOfElementIncludingThis(nsIStyleSheet* aElement,
                            MallocSizeOf aMallocSizeOf, void *aData)
 {
     return aElement->SizeOfIncludingThis(aMallocSizeOf);
 }
 
-int64_t
-nsStyleSheetService::Amount()
-{
-  return SizeOfIncludingThis(MallocSizeOf);
-}
-
 size_t
-nsStyleSheetService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+nsStyleSheetService::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
   n += mSheets[AGENT_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis,
                                                 aMallocSizeOf);
   n += mSheets[USER_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis,
                                                aMallocSizeOf);
   n += mSheets[AUTHOR_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis,
                                                  aMallocSizeOf);
--- a/layout/base/nsStyleSheetService.h
+++ b/layout/base/nsStyleSheetService.h
@@ -6,35 +6,32 @@
 
 /* implementation of interface for managing user and user-agent style sheets */
 
 #ifndef nsStyleSheetService_h_
 #define nsStyleSheetService_h_
 
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
-#include "nsIMemoryReporter.h"
 #include "nsIStyleSheetService.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 
 class nsICategoryManager;
 class nsIMemoryReporter;
 class nsISimpleEnumerator;
 class nsIStyleSheet;
 
 #define NS_STYLESHEETSERVICE_CID \
 {0xfcca6f83, 0x9f7d, 0x44e4, {0xa7, 0x4b, 0xb5, 0x94, 0x33, 0xe6, 0xc8, 0xc3}}
 
 #define NS_STYLESHEETSERVICE_CONTRACTID \
   "@mozilla.org/content/style-sheet-service;1"
 
-class nsStyleSheetService MOZ_FINAL
-  : public mozilla::MemoryUniReporter
-  , public nsIStyleSheetService
+class nsStyleSheetService MOZ_FINAL : public nsIStyleSheetService
 {
  public:
   nsStyleSheetService() NS_HIDDEN;
   ~nsStyleSheetService() NS_HIDDEN;
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTYLESHEETSERVICE
 
@@ -44,29 +41,29 @@ class nsStyleSheetService MOZ_FINAL
   nsCOMArray<nsIStyleSheet>* UserStyleSheets() { return &mSheets[USER_SHEET]; }
   nsCOMArray<nsIStyleSheet>* AuthorStyleSheets() { return &mSheets[AUTHOR_SHEET]; }
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   static nsStyleSheetService *GetInstance();
   static nsStyleSheetService *gInstance;
 
-  int64_t Amount() MOZ_OVERRIDE;
-
  private:
 
   NS_HIDDEN_(void) RegisterFromEnumerator(nsICategoryManager  *aManager,
                                           const char          *aCategory,
                                           nsISimpleEnumerator *aEnumerator,
                                           uint32_t             aSheetType);
 
   NS_HIDDEN_(int32_t) FindSheetByURI(const nsCOMArray<nsIStyleSheet> &sheets,
                                      nsIURI *sheetURI);
 
   // Like LoadAndRegisterSheet, but doesn't notify.  If successful, the
   // new sheet will be the last sheet in mSheets[aSheetType].
   NS_HIDDEN_(nsresult) LoadAndRegisterSheetInternal(nsIURI *aSheetURI,
                                                     uint32_t aSheetType);
 
   nsCOMArray<nsIStyleSheet> mSheets[3];
+
+  nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 #endif
--- a/layout/style/nsLayoutStylesheetCache.cpp
+++ b/layout/style/nsLayoutStylesheetCache.cpp
@@ -5,24 +5,40 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsLayoutStylesheetCache.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/css/Loader.h"
 #include "nsIFile.h"
+#include "nsIMemoryReporter.h"
 #include "nsNetUtil.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIXULRuntime.h"
 #include "nsCSSStyleSheet.h"
 
-NS_IMPL_ISUPPORTS_INHERITED1(
-  nsLayoutStylesheetCache, MemoryUniReporter, nsIObserver)
+class LayoutStyleSheetCacheReporter MOZ_FINAL
+  : public mozilla::MemoryUniReporter
+{
+public:
+  LayoutStyleSheetCacheReporter()
+    : MemoryUniReporter("explicit/layout/style-sheet-cache",
+                         KIND_HEAP, UNITS_BYTES,
+                         "Memory used for some built-in style sheets.")
+  {}
+private:
+  int64_t Amount() MOZ_OVERRIDE
+  {
+    return nsLayoutStylesheetCache::SizeOfIncludingThis(MallocSizeOf);
+  }
+};
+
+NS_IMPL_ISUPPORTS1(nsLayoutStylesheetCache, nsIObserver)
 
 nsresult
 nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
                             const char* aTopic,
                             const PRUnichar* aData)
 {
   if (!strcmp(aTopic, "profile-before-change")) {
     mUserContentSheet = nullptr;
@@ -137,24 +153,27 @@ nsLayoutStylesheetCache::FullScreenOverr
 
 void
 nsLayoutStylesheetCache::Shutdown()
 {
   NS_IF_RELEASE(gCSSLoader);
   NS_IF_RELEASE(gStyleCache);
 }
 
-int64_t
-nsLayoutStylesheetCache::Amount()
+size_t
+nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
 {
-  return SizeOfIncludingThis(MallocSizeOf);
+  return nsLayoutStylesheetCache::gStyleCache
+       ? nsLayoutStylesheetCache::gStyleCache->
+           SizeOfIncludingThisHelper(aMallocSizeOf)
+       : 0;
 }
 
 size_t
-nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+nsLayoutStylesheetCache::SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t n = aMallocSizeOf(this);
 
   #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0;
 
   MEASURE(mScrollbarsSheet);
   MEASURE(mFormsSheet);
   MEASURE(mUserContentSheet);
@@ -166,19 +185,16 @@ nsLayoutStylesheetCache::SizeOfIncluding
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - gCSSLoader
 
   return n;
 }
 
 nsLayoutStylesheetCache::nsLayoutStylesheetCache()
-  : MemoryUniReporter("explicit/layout/style-sheet-cache",
-                      KIND_HEAP, UNITS_BYTES,
-                      "Memory used for some built-in style sheets.")
 {
   nsCOMPtr<nsIObserverService> obsSvc =
     mozilla::services::GetObserverService();
   NS_ASSERTION(obsSvc, "No global observer service?");
 
   if (obsSvc) {
     obsSvc->AddObserver(this, "profile-before-change", false);
     obsSvc->AddObserver(this, "profile-do-change", false);
@@ -203,41 +219,36 @@ nsLayoutStylesheetCache::nsLayoutStylesh
   }
   NS_ASSERTION(mQuirkSheet, "Could not load quirk.css");
 
   NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/full-screen-override.css");
   if (uri) {
     LoadSheet(uri, mFullScreenOverrideSheet, true);
   }
   NS_ASSERTION(mFullScreenOverrideSheet, "Could not load full-screen-override.css");
+
+  mReporter = new LayoutStyleSheetCacheReporter();
+  NS_RegisterMemoryReporter(mReporter);
 }
 
 nsLayoutStylesheetCache::~nsLayoutStylesheetCache()
 {
-  UnregisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
   gStyleCache = nullptr;
 }
 
 void
-nsLayoutStylesheetCache::InitMemoryReporter()
-{
-  RegisterWeakMemoryReporter(this);
-}
-
-void
 nsLayoutStylesheetCache::EnsureGlobal()
 {
   if (gStyleCache) return;
 
   gStyleCache = new nsLayoutStylesheetCache();
   if (!gStyleCache) return;
 
   NS_ADDREF(gStyleCache);
-
-  gStyleCache->InitMemoryReporter();
 }
 
 void
 nsLayoutStylesheetCache::InitFromProfile()
 {
   nsCOMPtr<nsIXULRuntime> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
   if (appInfo) {
     bool inSafeMode = false;
--- a/layout/style/nsLayoutStylesheetCache.h
+++ b/layout/style/nsLayoutStylesheetCache.h
@@ -2,67 +2,68 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsLayoutStylesheetCache_h__
 #define nsLayoutStylesheetCache_h__
 
-#include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 
 class nsCSSStyleSheet;
 class nsIFile;
+class nsIMemoryReporter;
 class nsIURI;
 
 namespace mozilla {
 namespace css {
 class Loader;
 }
 }
 
 class nsLayoutStylesheetCache MOZ_FINAL
- : public mozilla::MemoryUniReporter
- , public nsIObserver
+ : public nsIObserver
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   static nsCSSStyleSheet* ScrollbarsSheet();
   static nsCSSStyleSheet* FormsSheet();
   static nsCSSStyleSheet* UserContentSheet();
   static nsCSSStyleSheet* UserChromeSheet();
   static nsCSSStyleSheet* UASheet();
   static nsCSSStyleSheet* QuirkSheet();
   static nsCSSStyleSheet* FullScreenOverrideSheet();
 
   static void Shutdown();
 
-  int64_t Amount() MOZ_OVERRIDE;
-  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+  static size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 private:
   nsLayoutStylesheetCache();
   ~nsLayoutStylesheetCache();
 
   static void EnsureGlobal();
   void InitFromProfile();
-  void InitMemoryReporter();
   static void LoadSheetFile(nsIFile* aFile, nsRefPtr<nsCSSStyleSheet> &aSheet);
   static void LoadSheet(nsIURI* aURI, nsRefPtr<nsCSSStyleSheet> &aSheet,
                         bool aEnableUnsafeRules);
 
+  size_t SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf) const;
+
   static nsLayoutStylesheetCache* gStyleCache;
   static mozilla::css::Loader* gCSSLoader;
   nsRefPtr<nsCSSStyleSheet> mScrollbarsSheet;
   nsRefPtr<nsCSSStyleSheet> mFormsSheet;
   nsRefPtr<nsCSSStyleSheet> mUserContentSheet;
   nsRefPtr<nsCSSStyleSheet> mUserChromeSheet;
   nsRefPtr<nsCSSStyleSheet> mUASheet;
   nsRefPtr<nsCSSStyleSheet> mQuirkSheet;
   nsRefPtr<nsCSSStyleSheet> mFullScreenOverrideSheet;
+
+  nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 #endif
--- a/modules/libpref/src/Preferences.cpp
+++ b/modules/libpref/src/Preferences.cpp
@@ -336,17 +336,17 @@ PreferenceServiceReporter::CollectReport
   return NS_OK;
 }
 
 namespace {
 class AddPreferencesMemoryReporterRunnable : public nsRunnable
 {
   NS_IMETHOD Run()
   {
-    return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
+    return NS_RegisterMemoryReporter(new PreferenceServiceReporter());
   }
 };
 } // anonymous namespace
 
 // static
 Preferences*
 Preferences::GetInstanceForService()
 {
@@ -371,19 +371,19 @@ Preferences::GetInstanceForService()
     return nullptr;
   }
 
   gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
 
   gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
 
   // Preferences::GetInstanceForService() can be called from GetService(), and
-  // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter).  To
-  // avoid a potential recursive GetService() call, we can't register the
-  // memory reporter here; instead, do it off a runnable.
+  // NS_RegisterMemoryReporter calls GetService(nsIMemoryReporter).  To avoid a
+  // potential recursive GetService() call, we can't register the memory
+  // reporter here; instead, do it off a runnable.
   nsRefPtr<AddPreferencesMemoryReporterRunnable> runnable =
     new AddPreferencesMemoryReporterRunnable();
   NS_DispatchToMainThread(runnable);
 
   NS_ADDREF(sPreferences);
   return sPreferences;
 }
 
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -1066,22 +1066,20 @@ private:
     nsCOMPtr<nsIThread>   mThread;
 };
 
 /******************************************************************************
  * nsCacheService
  *****************************************************************************/
 nsCacheService *   nsCacheService::gService = nullptr;
 
-NS_IMPL_ISUPPORTS_INHERITED2(nsCacheService, MemoryMultiReporter,
-                             nsICacheService, nsICacheServiceInternal)
+NS_IMPL_ISUPPORTS2(nsCacheService, nsICacheService, nsICacheServiceInternal)
 
 nsCacheService::nsCacheService()
-    : MemoryMultiReporter("cache-service"),
-      mObserver(nullptr),
+    : mObserver(nullptr),
       mLock("nsCacheService.mLock"),
       mCondVar(mLock, "nsCacheService.mCondVar"),
       mTimeStampLock("nsCacheService.mTimeStampLock"),
       mInitialized(false),
       mClearingEntries(false),
       mEnableMemoryDevice(true),
       mEnableDiskDevice(true),
       mMemoryDevice(nullptr),
@@ -1153,30 +1151,28 @@ nsCacheService::Init()
     rv = nsDeleteDir::Init();
     if (NS_FAILED(rv)) {
         NS_WARNING("Can't initialize nsDeleteDir");
     }
 
     // initialize hashtable for active cache entries
     rv = mActiveEntries.Init();
     if (NS_FAILED(rv)) return rv;
-
+    
     // create profile/preference observer
     if (!mObserver) {
       mObserver = new nsCacheProfilePrefObserver();
       NS_ADDREF(mObserver);
       mObserver->Install();
     }
 
     mEnableDiskDevice    = mObserver->DiskCacheEnabled();
     mEnableOfflineDevice = mObserver->OfflineCacheEnabled();
     mEnableMemoryDevice  = mObserver->MemoryCacheEnabled();
 
-    RegisterWeakMemoryReporter(this);
-
     mInitialized = true;
     return NS_OK;
 }
 
 // static
 PLDHashOperator
 nsCacheService::ShutdownCustomCacheDeviceEnum(const nsAString& aProfileDir,
                                               nsRefPtr<nsOfflineCacheDevice>& aDevice,
@@ -1209,18 +1205,16 @@ nsCacheService::Shutdown()
             return;
 
         mClearingEntries = true;
         DoomActiveEntries(nullptr);
     }
 
     CloseAllStreams();
 
-    UnregisterWeakMemoryReporter(this);
-
     {
         nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_SHUTDOWN));
         NS_ASSERTION(mInitialized, "Bad state");
 
         mInitialized = false;
 
         // Clear entries
         ClearDoomList();
@@ -1357,18 +1351,17 @@ EvictionNotifierRunnable::Run()
 }
 
 } // anonymous namespace
 
 nsresult
 nsCacheService::EvictEntriesForClient(const char *          clientID,
                                       nsCacheStoragePolicy  storagePolicy)
 {
-    nsRefPtr<EvictionNotifierRunnable> r =
-        new EvictionNotifierRunnable(NS_ISUPPORTS_CAST(nsICacheService*, this));
+    nsRefPtr<EvictionNotifierRunnable> r = new EvictionNotifierRunnable(this);
     NS_DispatchToMainThread(r);
 
     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_EVICTENTRIESFORCLIENT));
     nsresult res = NS_OK;
 
     if (storagePolicy == nsICache::STORE_ANYWHERE ||
         storagePolicy == nsICache::STORE_ON_DISK) {
 
@@ -3179,40 +3172,8 @@ nsCacheService::LeavePrivateBrowsing()
 
     gService->DoomActiveEntries(IsEntryPrivate);
 
     if (gService->mMemoryDevice) {
         // clear memory cache
         gService->mMemoryDevice->EvictPrivateEntries();
     }
 }
-
-NS_IMETHODIMP
-nsCacheService::CollectReports(nsIHandleReportCallback* aHandleReport,
-                               nsISupports* aData)
-{
-    size_t disk = 0;
-    if (mDiskDevice) {
-        nsCacheServiceAutoLock
-            lock(LOCK_TELEM(NSCACHESERVICE_DISKDEVICEHEAPSIZE));
-        disk = mDiskDevice->SizeOfIncludingThis(MallocSizeOf);
-    }
-
-    size_t memory = mMemoryDevice ? mMemoryDevice->TotalSize() : 0;
-
-#define REPORT(_path, _amount, _desc)                                         \
-    do {                                                                      \
-        nsresult rv;                                                          \
-        rv = aHandleReport->Callback(EmptyCString(),                          \
-                                     NS_LITERAL_CSTRING(_path),               \
-                                     KIND_HEAP, UNITS_BYTES, _amount,         \
-                                     NS_LITERAL_CSTRING(_desc), aData);       \
-        NS_ENSURE_SUCCESS(rv, rv);                                            \
-    } while (0)
-
-    REPORT("explicit/network/disk-cache", disk,
-           "Memory used by the network disk cache.");
-
-    REPORT("explicit/network/memory-cache", memory,
-           "Memory used by the network memory cache.");
-
-    return NS_OK;
-}
--- a/netwerk/cache/nsCacheService.h
+++ b/netwerk/cache/nsCacheService.h
@@ -8,17 +8,16 @@
 #define _nsCacheService_h_
 
 #include "nsICacheService.h"
 #include "nsCacheSession.h"
 #include "nsCacheDevice.h"
 #include "nsCacheEntry.h"
 #include "nsThreadUtils.h"
 #include "nsICacheListener.h"
-#include "nsIMemoryReporter.h"
 
 #include "prthread.h"
 #include "nsIObserver.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsRefPtrHashtable.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/Mutex.h"
@@ -57,18 +56,17 @@ private:
     nsICacheListener *mListener;
     nsresult          mStatus;
 };
 
 /******************************************************************************
  *  nsCacheService
  ******************************************************************************/
 
-class nsCacheService : public mozilla::MemoryMultiReporter,
-                       public nsICacheServiceInternal
+class nsCacheService : public nsICacheServiceInternal
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSICACHESERVICE
     NS_DECL_NSICACHESERVICEINTERNAL
 
     nsCacheService();
     virtual ~nsCacheService();
@@ -218,19 +216,16 @@ public:
     static void      AssertOwnsLock()
     { gService->mLock.AssertCurrentThreadOwns(); }
 
     static void      LeavePrivateBrowsing();
     bool             IsDoomListEmpty();
 
     typedef bool (*DoomCheckFn)(nsCacheEntry* entry);
 
-    NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                             nsISupports* aData);
-
 private:
     friend class nsCacheServiceAutoLock;
     friend class nsOfflineCacheDevice;
     friend class nsProcessRequestEvent;
     friend class nsSetSmartSizeEvent;
     friend class nsBlockOnCacheThreadEvent;
     friend class nsSetDiskSmartSizeCallback;
     friend class nsDoomEvent;
--- a/netwerk/cache/nsDiskCacheDevice.cpp
+++ b/netwerk/cache/nsDiskCacheDevice.cpp
@@ -363,26 +363,53 @@ nsDiskCache::Truncate(PRFileDesc *  fd, 
     return NS_OK;
 }
 
 
 /******************************************************************************
  *  nsDiskCacheDevice
  *****************************************************************************/
 
+class NetworkDiskCacheReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+    NetworkDiskCacheReporter(nsDiskCacheDevice* aDevice)
+      : MemoryUniReporter(
+            "explicit/network/disk-cache",
+            KIND_HEAP,
+            UNITS_BYTES,
+            "Memory used by the network disk cache.")
+      , mDevice(aDevice)
+    {}
+
+private:
+    int64_t Amount()
+    {
+        nsCacheServiceAutoLock
+            lock(LOCK_TELEM(NSCACHESERVICE_DISKDEVICEHEAPSIZE));
+        return mDevice->SizeOfIncludingThis(MallocSizeOf);
+    }
+
+    nsDiskCacheDevice* mDevice;
+};
+
 nsDiskCacheDevice::nsDiskCacheDevice()
     : mCacheCapacity(0)
     , mMaxEntrySize(-1) // -1 means "no limit"
     , mInitialized(false)
     , mClearingDiskCache(false)
+    , mReporter(nullptr)
 {
+    mReporter = new NetworkDiskCacheReporter(this);
+    NS_RegisterMemoryReporter(mReporter);
 }
 
 nsDiskCacheDevice::~nsDiskCacheDevice()
 {
+    NS_UnregisterMemoryReporter(mReporter);
     Shutdown();
 }
 
 
 /**
  *  methods of nsCacheDevice
  */
 nsresult
--- a/netwerk/cache/nsDiskCacheDevice.h
+++ b/netwerk/cache/nsDiskCacheDevice.h
@@ -13,16 +13,17 @@
 #include "nsDiskCacheBlockFile.h"
 #include "nsDiskCacheEntry.h"
 
 #include "nsIFile.h"
 #include "nsIObserver.h"
 #include "nsCOMArray.h"
 
 class nsDiskCacheMap;
+class nsIMemoryReporter;
 
 
 class nsDiskCacheDevice : public nsCacheDevice {
 public:
     nsDiskCacheDevice();
     virtual ~nsDiskCacheDevice();
 
     virtual nsresult        Init();
@@ -106,11 +107,13 @@ private:
     nsCOMPtr<nsIFile>       mCacheDirectory;
     nsDiskCacheBindery      mBindery;
     uint32_t                mCacheCapacity;     // Unit is KiB's
     int32_t                 mMaxEntrySize;      // Unit is bytes internally
     // XXX need soft/hard limits, currentTotal
     nsDiskCacheMap          mCacheMap;
     bool                    mInitialized;
     bool                    mClearingDiskCache;
+
+    nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 #endif // _nsDiskCacheDevice_h_
--- a/netwerk/cache/nsMemoryCacheDevice.cpp
+++ b/netwerk/cache/nsMemoryCacheDevice.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCache.h"
 #include "nsMemoryCacheDevice.h"
 #include "nsCacheService.h"
 #include "nsICacheService.h"
 #include "nsICacheVisitor.h"
 #include "nsIStorageStream.h"
+#include "nsIMemoryReporter.h"
 #include "nsCRT.h"
 #include "nsReadableUtils.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Telemetry.h"
 #include <algorithm>
 
 // The memory cache implements the "LRU-SP" caching algorithm
 // described in "LRU-SP: A Size-Adjusted and Popularity-Aware LRU Replacement
@@ -23,34 +24,58 @@
 // We keep kQueueCount LRU queues, which should be about ceil(log2(mHardLimit))
 // The queues hold exponentially increasing ranges of floor(log2((size/nref)))
 // values for entries.
 // Entries larger than 2^(kQueueCount-1) go in the last queue.
 // Entries with no expiration go in the first queue.
 
 const char *gMemoryDeviceID      = "memory";
 
+class NetworkMemoryCacheReporter MOZ_FINAL :
+    public mozilla::MemoryUniReporter
+{
+public:
+    NetworkMemoryCacheReporter(nsMemoryCacheDevice* aDevice)
+      : MemoryUniReporter(
+            "explicit/network/memory-cache",
+            KIND_HEAP,
+            UNITS_BYTES,
+            "Memory used by the network memory cache.")
+      , mDevice(aDevice)
+    {}
+
+private:
+    int64_t Amount() { return mDevice->TotalSize(); }
+
+    nsMemoryCacheDevice* mDevice;
+};
+
 
 nsMemoryCacheDevice::nsMemoryCacheDevice()
     : mInitialized(false),
       mHardLimit(4 * 1024 * 1024),       // default, if no pref
       mSoftLimit((mHardLimit * 9) / 10), // default, if no pref
       mTotalSize(0),
       mInactiveSize(0),
       mEntryCount(0),
       mMaxEntryCount(0),
-      mMaxEntrySize(-1)  // -1 means "no limit"
+      mMaxEntrySize(-1), // -1 means "no limit"
+      mReporter(nullptr)
 {
     for (int i=0; i<kQueueCount; ++i)
         PR_INIT_CLIST(&mEvictionList[i]);
+
+    mReporter = new NetworkMemoryCacheReporter(this);
+    NS_RegisterMemoryReporter(mReporter);
 }
 
 
 nsMemoryCacheDevice::~nsMemoryCacheDevice()
 {
+    NS_UnregisterMemoryReporter(mReporter);
     Shutdown();
 }
 
 
 nsresult
 nsMemoryCacheDevice::Init()
 {
     if (mInitialized)  return NS_ERROR_ALREADY_INITIALIZED;
--- a/netwerk/cache/nsMemoryCacheDevice.h
+++ b/netwerk/cache/nsMemoryCacheDevice.h
@@ -7,16 +7,17 @@
 #ifndef _nsMemoryCacheDevice_h_
 #define _nsMemoryCacheDevice_h_
 
 #include "nsCacheDevice.h"
 #include "pldhash.h"
 #include "nsCacheEntry.h"
 
 
+class nsIMemoryReporter;
 class nsMemoryCacheDeviceInfo;
 
 /******************************************************************************
  * nsMemoryCacheDevice
  ******************************************************************************/
 class nsMemoryCacheDevice : public nsCacheDevice
 {
 public:
@@ -94,16 +95,18 @@ private:
     int32_t                mTotalSize;
     int32_t                mInactiveSize;
 
     int32_t                mEntryCount;
     int32_t                mMaxEntryCount;
     int32_t                mMaxEntrySize; // internal unit is bytes
 
     // XXX what other stats do we want to keep?
+
+    nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 
 /******************************************************************************
  * nsMemoryCacheDeviceInfo - used to call nsIVisitor for about:cache
  ******************************************************************************/
 class nsMemoryCacheDeviceInfo : public nsICacheDeviceInfo {
 public:
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDNSService2.h"
 #include "nsIDNSRecord.h"
 #include "nsIDNSListener.h"
 #include "nsICancelable.h"
+#include "nsIMemoryReporter.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIServiceManager.h"
 #include "nsIXPConnect.h"
 #include "nsProxyRelease.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsAutoPtr.h"
@@ -388,32 +389,46 @@ nsDNSSyncRequest::SizeOfIncludingThis(Ma
     // is worthwhile:
     // - mMonitor
 
     return n;
 }
 
 //-----------------------------------------------------------------------------
 
+class NetworkDNSServiceReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+    NetworkDNSServiceReporter(nsDNSService* aService)
+        : MemoryUniReporter("explicit/network/dns-service",
+                             KIND_HEAP, UNITS_BYTES,
+                             "Memory used for the DNS service.")
+        , mService(aService)
+    {}
+private:
+    int64_t Amount() MOZ_OVERRIDE
+    {
+        return mService->SizeOfIncludingThis(MallocSizeOf);
+    }
+
+    nsDNSService *mService;
+};
+
 nsDNSService::nsDNSService()
-    : MemoryUniReporter("explicit/network/dns-service",
-                        KIND_HEAP, UNITS_BYTES,
-                        "Memory used for the DNS service.")
-    , mLock("nsDNSServer.mLock")
+    : mLock("nsDNSServer.mLock")
     , mFirstTime(true)
     , mOffline(false)
 {
 }
 
 nsDNSService::~nsDNSService()
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED3(nsDNSService, MemoryUniReporter, nsIDNSService,
-                             nsPIDNSService, nsIObserver)
+NS_IMPL_ISUPPORTS3(nsDNSService, nsIDNSService, nsPIDNSService, nsIObserver)
 
 NS_IMETHODIMP
 nsDNSService::Init()
 {
     if (mResolver)
         return NS_OK;
     NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED);
 
@@ -509,25 +524,26 @@ nsDNSService::Init()
 
             while (tokenizer.hasMoreTokens()) {
                 const nsSubstring& domain = tokenizer.nextToken();
                 mLocalDomains.PutEntry(nsDependentCString(NS_ConvertUTF16toUTF8(domain).get()));
             }
         }
     }
 
-    RegisterWeakMemoryReporter(this);
+    mReporter = new NetworkDNSServiceReporter(this);
+    NS_RegisterMemoryReporter(mReporter);
 
     return rv;
 }
 
 NS_IMETHODIMP
 nsDNSService::Shutdown()
 {
-    UnregisterWeakMemoryReporter(this);
+    NS_UnregisterMemoryReporter(mReporter);
 
     nsRefPtr<nsHostResolver> res;
     {
         MutexAutoLock lock(mLock);
         res = mResolver;
         mResolver = nullptr;
     }
     if (res)
@@ -916,17 +932,17 @@ nsDNSService::GetDNSCacheEntries(nsTArra
 static size_t
 SizeOfLocalDomainsEntryExcludingThis(nsCStringHashKey* entry,
                                      MallocSizeOf mallocSizeOf, void*)
 {
     return entry->GetKey().SizeOfExcludingThisMustBeUnshared(mallocSizeOf);
 }
 
 size_t
-nsDNSService::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+nsDNSService::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
 {
     // Measurement of the following members may be added later if DMD finds it
     // is worthwhile:
     // - mIDN
     // - mLock
 
     size_t n = mallocSizeOf(this);
     n += mResolver->SizeOfIncludingThis(mallocSizeOf);
--- a/netwerk/dns/nsDNSService2.h
+++ b/netwerk/dns/nsDNSService2.h
@@ -2,43 +2,39 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsDNSService2_h__
 #define nsDNSService2_h__
 
 #include "nsPIDNSService.h"
 #include "nsIIDNService.h"
-#include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "nsHostResolver.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Attributes.h"
 
-class nsDNSService MOZ_FINAL : public mozilla::MemoryUniReporter
-                             , public nsPIDNSService
+class nsIMemoryReporter;
+
+class nsDNSService MOZ_FINAL : public nsPIDNSService
                              , public nsIObserver
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSPIDNSSERVICE
     NS_DECL_NSIDNSSERVICE
     NS_DECL_NSIOBSERVER
 
     nsDNSService();
     ~nsDNSService();
 
-    int64_t Amount() MOZ_OVERRIDE
-    {
-        return SizeOfIncludingThis(MallocSizeOf);
-    }
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
 private:
     uint16_t GetAFForLookup(const nsACString &host, uint32_t flags);
 
     nsRefPtr<nsHostResolver>  mResolver;
     nsCOMPtr<nsIIDNService>   mIDN;
 
@@ -49,11 +45,13 @@ private:
     // IPv4 DNS lookups are performed. This allows the user to disable IPv6 on
     // a per-domain basis and work around broken DNS servers. See bug 68796.
     nsAdoptingCString         mIPv4OnlyDomains;
     bool                      mDisableIPv6;
     bool                      mDisablePrefetch;
     bool                      mFirstTime;
     bool                      mOffline;
     nsTHashtable<nsCStringHashKey> mLocalDomains;
+
+    nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 #endif //nsDNSService2_h__
--- a/netwerk/dns/nsEffectiveTLDService.cpp
+++ b/netwerk/dns/nsEffectiveTLDService.cpp
@@ -8,23 +8,23 @@
 // complete description of the expected file format and parsing rules, see
 // http://wiki.mozilla.org/Gecko:Effective_TLD_Service
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Util.h"
 
 #include "nsEffectiveTLDService.h"
 #include "nsIIDNService.h"
+#include "nsIMemoryReporter.h"
 #include "nsNetUtil.h"
 #include "prnetdb.h"
 
 using namespace mozilla;
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsEffectiveTLDService, MemoryUniReporter,
-                             nsIEffectiveTLDService)
+NS_IMPL_ISUPPORTS1(nsEffectiveTLDService, nsIEffectiveTLDService)
 
 // ----------------------------------------------------------------------
 
 #define ETLD_STR_NUM_1(line) str##line
 #define ETLD_STR_NUM(line) ETLD_STR_NUM_1(line)
 #define ETLD_ENTRY_OFFSET(name) offsetof(struct etld_string_list, ETLD_STR_NUM(__LINE__))
 
 const ETLDEntry nsDomainEntry::entries[] = {
@@ -56,25 +56,38 @@ nsDomainEntry::FuncForStaticAsserts(void
 #undef ETLD_ENTRY_OFFSET
 #undef ETLD_STR_NUM
 #undef ETLD_STR_NUM1
 
 // ----------------------------------------------------------------------
 
 static nsEffectiveTLDService *gService = nullptr;
 
+class EffectiveTLDServiceReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+  EffectiveTLDServiceReporter()
+    : MemoryUniReporter("explicit/xpcom/effective-TLD-service",
+                         KIND_HEAP, UNITS_BYTES,
+                         "Memory used by the effective TLD service.")
+  {}
+
+private:
+  int64_t Amount() MOZ_OVERRIDE
+  {
+    return gService ? gService->SizeOfIncludingThis(MallocSizeOf) : 0;
+  }
+};
+
 nsEffectiveTLDService::nsEffectiveTLDService()
   // We'll probably have to rehash at least once, since nsTHashtable doesn't
   // use a perfect hash, but at least we'll save a few rehashes along the way.
   // Next optimization here is to precompute the hash using something like
   // gperf, but one step at a time.  :-)
-  : MemoryUniReporter("explicit/xpcom/effective-TLD-service",
-                       KIND_HEAP, UNITS_BYTES,
-                       "Memory used by the effective TLD service.")
-  , mHash(ArrayLength(nsDomainEntry::entries))
+  : mHash(ArrayLength(nsDomainEntry::entries))
 {
 }
 
 nsresult
 nsEffectiveTLDService::Init()
 {
   const ETLDEntry *entries = nsDomainEntry::entries;
 
@@ -94,41 +107,37 @@ nsEffectiveTLDService::Init()
 #endif
     nsDomainEntry *entry = mHash.PutEntry(domain);
     NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
     entry->SetData(&entries[i]);
   }
 
   MOZ_ASSERT(!gService);
   gService = this;
-  RegisterWeakMemoryReporter(this);
+  mReporter = new EffectiveTLDServiceReporter();
+  NS_RegisterMemoryReporter(mReporter);
 
   return NS_OK;
 }
 
 nsEffectiveTLDService::~nsEffectiveTLDService()
 {
-  UnregisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
   gService = nullptr;
 }
 
-int64_t
-nsEffectiveTLDService::Amount()
-{
-  return SizeOfIncludingThis(MallocSizeOf);
-}
-
 size_t
-nsEffectiveTLDService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+nsEffectiveTLDService::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
 {
   size_t n = aMallocSizeOf(this);
   n += mHash.SizeOfExcludingThis(nullptr, aMallocSizeOf);
 
   // Measurement of the following members may be added later if DMD finds it is
   // worthwhile:
+  // - mReporter
   // - mIDNService
 
   return n;
 }
 
 // External function for dealing with URI's correctly.
 // Pulls out the host portion from an nsIURI, and calls through to
 // GetPublicSuffixFromHost().
--- a/netwerk/dns/nsEffectiveTLDService.h
+++ b/netwerk/dns/nsEffectiveTLDService.h
@@ -97,30 +97,28 @@ private:
     char strtab[1];
   } strings;
   static const ETLDEntry entries[];
   void FuncForStaticAsserts(void);
 #undef ETLD_STR_NUM
 #undef ETLD_STR_NUM1
 };
 
-class nsEffectiveTLDService MOZ_FINAL
-  : public mozilla::MemoryUniReporter
-  , public nsIEffectiveTLDService
+class nsEffectiveTLDService MOZ_FINAL : public nsIEffectiveTLDService
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIEFFECTIVETLDSERVICE
 
   nsEffectiveTLDService();
   nsresult Init();
 
-  int64_t Amount() MOZ_OVERRIDE;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 private:
   nsresult GetBaseDomainInternal(nsCString &aHostname, int32_t aAdditionalParts, nsACString &aBaseDomain);
   nsresult NormalizeHostname(nsCString &aHostname);
   ~nsEffectiveTLDService();
 
+  nsCOMPtr<nsIMemoryReporter> mReporter;
   nsTHashtable<nsDomainEntry> mHash;
   nsCOMPtr<nsIIDNService>     mIDNService;
 };
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/scache/StartupCache.h"
 
 #include "nsAutoPtr.h"
 #include "nsClassHashtable.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsIClassInfo.h"
 #include "nsIFile.h"
+#include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsIOutputStream.h"
 #include "nsIStartupCache.h"
 #include "nsIStorageStream.h"
 #include "nsIStreamBufferAccess.h"
 #include "nsIStringStream.h"
 #include "nsISupports.h"
@@ -46,41 +47,48 @@
 #define SC_WORDSIZE "4"
 #else
 #define SC_WORDSIZE "8"
 #endif
 
 namespace mozilla {
 namespace scache {
 
-NS_IMETHODIMP
-StartupCache::CollectReports(nsIHandleReportCallback* aHandleReport,
-                             nsISupports* aData)
+class StartupCacheMappingReporter MOZ_FINAL : public MemoryUniReporter
 {
-#define REPORT(_path, _kind, _amount, _desc)                                \
-  do {                                                                      \
-    nsresult rv =                                                           \
-      aHandleReport->Callback(EmptyCString(),                               \
-                              NS_LITERAL_CSTRING(_path),                    \
-                              _kind, UNITS_BYTES, _amount,                  \
-                              NS_LITERAL_CSTRING(_desc), aData);            \
-    NS_ENSURE_SUCCESS(rv, rv);                                              \
-  } while (0)
+public:
+  StartupCacheMappingReporter()
+    : MemoryUniReporter("explicit/startup-cache/mapping",
+                         KIND_NONHEAP, UNITS_BYTES,
+"Memory used to hold the mapping of the startup cache from file.  This memory "
+"is likely to be swapped out shortly after start-up.")
+  {}
+private:
+  int64_t Amount() MOZ_OVERRIDE
+  {
+    mozilla::scache::StartupCache* sc =
+      mozilla::scache::StartupCache::GetSingleton();
+    return sc ? sc->SizeOfMapping() : 0;
+  }
+};
 
-  REPORT("explicit/startup-cache/mapping", KIND_NONHEAP,
-         SizeOfMapping(),
-         "Memory used to hold the mapping of the startup cache from file. "
-         "This memory is likely to be swapped out shortly after start-up.");
-
-  REPORT("explicit/startup-cache/data", KIND_HEAP,
-         HeapSizeOfIncludingThis(MallocSizeOf),
-         "Memory used by the startup cache for things other than the file "
-         "mapping.");
-
-  return NS_OK;
+class StartupCacheDataReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+  StartupCacheDataReporter()
+    : MemoryUniReporter("explicit/startup-cache/data", KIND_HEAP, UNITS_BYTES,
+"Memory used by the startup cache for things other than the file mapping.")
+  {}
+private:
+  int64_t Amount() MOZ_OVERRIDE
+  {
+    mozilla::scache::StartupCache* sc =
+      mozilla::scache::StartupCache::GetSingleton();
+    return sc ? sc->HeapSizeOfIncludingThis(MallocSizeOf) : 0;
+  }
 };
 
 static const char sStartupCacheName[] = "startupCache." SC_WORDSIZE "." SC_ENDIAN;
 #if defined(XP_WIN) && defined(MOZ_METRO)
 static const char sMetroStartupCacheName[] = "metroStartupCache." SC_WORDSIZE "." SC_ENDIAN;
 #endif
 
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
@@ -97,42 +105,41 @@ StartupCache::GetSingleton()
   }
 
   return StartupCache::gStartupCache;
 }
 
 void
 StartupCache::DeleteSingleton()
 {
+  delete StartupCache::gStartupCache;
   StartupCache::gStartupCache = nullptr;
 }
 
 nsresult
 StartupCache::InitSingleton()
 {
   nsresult rv;
   StartupCache::gStartupCache = new StartupCache();
 
   rv = StartupCache::gStartupCache->Init();
   if (NS_FAILED(rv)) {
+    delete StartupCache::gStartupCache;
     StartupCache::gStartupCache = nullptr;
   }
   return rv;
 }
 
-StaticRefPtr<StartupCache> StartupCache::gStartupCache;
+StartupCache* StartupCache::gStartupCache;
 bool StartupCache::gShutdownInitiated;
 bool StartupCache::gIgnoreDiskCache;
 enum StartupCache::TelemetrifyAge StartupCache::gPostFlushAgeAction = StartupCache::IGNORE_AGE;
 
-NS_IMPL_ISUPPORTS_INHERITED0(StartupCache, MemoryMultiReporter)
-
 StartupCache::StartupCache()
-  : MemoryMultiReporter("startup-cache"),
-    mArchive(nullptr), mStartupWriteInitiated(false), mWriteThread(nullptr)
+  : mArchive(nullptr), mStartupWriteInitiated(false), mWriteThread(nullptr)
 { }
 
 StartupCache::~StartupCache()
 {
   if (mTimer) {
     mTimer->Cancel();
   }
 
@@ -144,17 +151,19 @@ StartupCache::~StartupCache()
   // If we shutdown quickly timer wont have fired. Instead of writing
   // it on the main thread and block the shutdown we simply wont update
   // the startup cache. Always do this if the file doesn't exist since
   // we use it part of the packge step.
   if (!mArchive) {
     WriteToDisk();
   }
 
-  UnregisterWeakMemoryReporter(this);
+  gStartupCache = nullptr;
+  NS_UnregisterMemoryReporter(mMappingReporter);
+  NS_UnregisterMemoryReporter(mDataReporter);
 }
 
 nsresult
 StartupCache::Init()
 {
   // workaround for bug 653936
   nsCOMPtr<nsIProtocolHandler> jarInitializer(do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar"));
 
@@ -231,17 +240,20 @@ StartupCache::Init()
 
   // Sometimes we don't have a cache yet, that's ok.
   // If it's corrupted, just remove it and start over.
   if (gIgnoreDiskCache || (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)) {
     NS_WARNING("Failed to load startupcache file correctly, removing!");
     InvalidateCache();
   }
 
-  RegisterWeakMemoryReporter(this);
+  mMappingReporter = new StartupCacheMappingReporter();
+  mDataReporter    = new StartupCacheDataReporter();
+  NS_RegisterMemoryReporter(mMappingReporter);
+  NS_RegisterMemoryReporter(mDataReporter);
 
   return NS_OK;
 }
 
 /**
  * LoadArchive can be called from the main thread or while reloading cache on write thread.
  */
 nsresult
@@ -369,17 +381,17 @@ StartupCache::PutBuffer(const char* id, 
 #endif
   
   entry = new CacheEntry(data.forget(), len);
   mTable.Put(idStr, entry);
   return ResetStartupWriteTimer();
 }
 
 size_t
-StartupCache::SizeOfMapping()
+StartupCache::SizeOfMapping() 
 {
     return mArchive ? mArchive->SizeOfMapping() : 0;
 }
 
 size_t
 StartupCache::HeapSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
 {
     // This function could measure more members, but they haven't been found by
@@ -526,17 +538,17 @@ StartupCache::WaitOnWriteThread()
   NS_ASSERTION(NS_IsMainThread(), "Startup cache should only wait for io thread on main thread");
   if (!mWriteThread || mWriteThread == PR_GetCurrentThread())
     return;
 
   PR_JoinThread(mWriteThread);
   mWriteThread = nullptr;
 }
 
-void
+void 
 StartupCache::ThreadedWrite(void *aClosure)
 {
   PR_SetCurrentThreadName("StartupCache");
   gStartupCache->WriteToDisk();
 }
 
 /*
  * The write-thread is spawned on a timeout(which is reset with every write). This
--- a/startupcache/StartupCache.h
+++ b/startupcache/StartupCache.h
@@ -6,24 +6,24 @@
 #ifndef StartupCache_h_
 #define StartupCache_h_
 
 #include "nsClassHashtable.h"
 #include "nsComponentManagerUtils.h"
 #include "nsZipArchive.h"
 #include "nsIStartupCache.h"
 #include "nsITimer.h"
-#include "nsIMemoryReporter.h"
 #include "nsIObserverService.h"
 #include "nsIObserver.h"
 #include "nsIOutputStream.h"
 #include "nsIFile.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/StaticPtr.h"
+
+class nsIMemoryReporter;
 
 /**
  * The StartupCache is a persistent cache of simple key-value pairs,
  * where the keys are null-terminated c-strings and the values are 
  * arbitrary data, passed as a (char*, size) tuple. 
  *
  * Clients should use the GetSingleton() static method to access the cache. It 
  * will be available from the end of XPCOM init (NS_InitXPCOM3 in nsXPComInit.cpp), 
@@ -62,20 +62,19 @@
  * Some utility functions are provided in StartupCacheUtils. These functions wrap the
  * buffers into object streams, which may be useful for serializing objects. Note
  * the above caution about multiply-referenced objects, though -- the streams are just
  * as 'dumb' as the underlying buffers about multiply-referenced objects. They just
  * provide some convenience in writing out data.
  */
 
 namespace mozilla {
-
 namespace scache {
 
-struct CacheEntry
+struct CacheEntry 
 {
   nsAutoArrayPtr<char> data;
   uint32_t size;
 
   CacheEntry() : data(nullptr), size(0) { }
 
   // Takes possession of buf
   CacheEntry(char* buf, uint32_t len) : data(buf), size(len) { }
@@ -92,28 +91,27 @@ struct CacheEntry
 // We don't want to refcount StartupCache, and ObserverService wants to
 // refcount its listeners, so we'll let it refcount this instead.
 class StartupCacheListener MOZ_FINAL : public nsIObserver
 {
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
 };
 
-class StartupCache : public mozilla::MemoryMultiReporter
+class StartupCache
 {
 
 friend class StartupCacheListener;
 friend class StartupCacheWrapper;
-
+                                
 public:
-  NS_DECL_ISUPPORTS
 
   // StartupCache methods. See above comments for a more detailed description.
 
-  // Returns a buffer that was previously stored, caller takes ownership.
+  // Returns a buffer that was previously stored, caller takes ownership. 
   nsresult GetBuffer(const char* id, char** outbuf, uint32_t* length);
 
   // Stores a buffer. Caller keeps ownership, we make a copy.
   nsresult PutBuffer(const char* id, const char* inbuf, uint32_t length);
 
   // Removes the cache file.
   void InvalidateCache();
 
@@ -125,28 +123,25 @@ public:
   nsresult GetDebugObjectOutputStream(nsIObjectOutputStream* aStream,
                                       nsIObjectOutputStream** outStream);
 
   nsresult RecordAgesAlways();
 
   static StartupCache* GetSingleton();
   static void DeleteSingleton();
 
-  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData);
-
   // This measures all the heap memory used by the StartupCache, i.e. it
   // excludes the mapping.
   size_t HeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
   size_t SizeOfMapping();
 
 private:
   StartupCache();
-  virtual ~StartupCache();
+  ~StartupCache();
 
   enum TelemetrifyAge {
     IGNORE_AGE = 0,
     RECORD_AGE = 1
   };
   static enum TelemetrifyAge gPostFlushAgeAction;
 
   nsresult LoadArchive(enum TelemetrifyAge flag);
@@ -162,30 +157,33 @@ private:
   static size_t SizeOfEntryExcludingThis(const nsACString& key,
                                          const nsAutoPtr<CacheEntry>& data,
                                          mozilla::MallocSizeOf mallocSizeOf,
                                          void *);
 
   nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
   nsRefPtr<nsZipArchive> mArchive;
   nsCOMPtr<nsIFile> mFile;
-
+  
   nsCOMPtr<nsIObserverService> mObserverService;
   nsRefPtr<StartupCacheListener> mListener;
   nsCOMPtr<nsITimer> mTimer;
 
   bool mStartupWriteInitiated;
 
-  static StaticRefPtr<StartupCache> gStartupCache;
+  static StartupCache *gStartupCache;
   static bool gShutdownInitiated;
   static bool gIgnoreDiskCache;
   PRThread *mWriteThread;
 #ifdef DEBUG
   nsTHashtable<nsISupportsHashKey> mWriteObjectMap;
 #endif
+
+  nsCOMPtr<nsIMemoryReporter> mMappingReporter;
+  nsCOMPtr<nsIMemoryReporter> mDataReporter;
 };
 
 // This debug outputstream attempts to detect if clients are writing multiple
 // references to the same object. We only support that if that object
 // is a singleton.
 #ifdef DEBUG
 class StartupCacheDebugOutputStream MOZ_FINAL
   : public nsIObjectOutputStream
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -28,16 +28,17 @@
 #include "sqlite3.h"
 
 #ifdef SQLITE_OS_WIN
 // "windows.h" was included and it can #define lots of things we care about...
 #undef CompareString
 #endif
 
 #include "nsIPromptService.h"
+#include "nsIMemoryReporter.h"
 
 #ifdef MOZ_STORAGE_MEMORY
 #  include "mozmemory.h"
 #  ifdef MOZ_DMD
 #    include "DMD.h"
 #  endif
 #endif
 
@@ -64,150 +65,166 @@ static mozilla::Atomic<size_t> gSqliteMe
 #endif
 
 static int64_t
 StorageSQLiteDistinguishedAmount()
 {
   return ::sqlite3_memory_used();
 }
 
-/**
- * Passes a single SQLite memory statistic to a memory reporter callback.
- *
- * @param aHandleReport
- *        The callback.
- * @param aData
- *        The data for the callback.
- * @param aConn
- *        The SQLite connection.
- * @param aPathHead
- *        Head of the path for the memory report.
- * @param aKind
- *        The memory report statistic kind, one of "stmt", "cache" or
- *        "schema".
- * @param aDesc
- *        The memory report description.
- * @param aOption
- *        The SQLite constant for getting the measurement.
- * @param aTotal
- *        The accumulator for the measurement.
- */
-nsresult
-ReportConn(nsIHandleReportCallback *aHandleReport,
-           nsISupports *aData,
-           sqlite3 *aConn,
-           const nsACString &aPathHead,
-           const nsACString &aKind,
-           const nsACString &aDesc,
-           int aOption,
-           size_t *aTotal)
+class StorageSQLiteReporter MOZ_FINAL : public MemoryMultiReporter
 {
-  nsCString path(aPathHead);
-  path.Append(aKind);
-  path.AppendLiteral("-used");
+private:
+  Service *mService;    // a weakref because Service contains a strongref to this
+  nsCString mStmtDesc;
+  nsCString mCacheDesc;
+  nsCString mSchemaDesc;
+
+public:
+  StorageSQLiteReporter(Service *aService)
+  : MemoryMultiReporter("storage-sqlite")
+  , mService(aService)
+  {
+    mStmtDesc = NS_LITERAL_CSTRING(
+      "Memory (approximate) used by all prepared statements used by "
+      "connections to this database.");
+
+    mCacheDesc = NS_LITERAL_CSTRING(
+      "Memory (approximate) used by all pager caches used by connections "
+      "to this database.");
+
+    mSchemaDesc = NS_LITERAL_CSTRING(
+      "Memory (approximate) used to store the schema for all databases "
+      "associated with connections to this database.");
+  }
 
-  int curr = 0, max = 0;
-  int rc = ::sqlite3_db_status(aConn, aOption, &curr, &max, 0);
-  nsresult rv = convertResultCode(rc);
-  NS_ENSURE_SUCCESS(rv, rv);
+  // Warning: To get a Connection's measurements requires holding its lock.
+  // There may be a delay getting the lock if another thread is accessing the
+  // Connection.  This isn't very nice if CollectReports is called from the
+  // main thread!  But at the time of writing this function is only called when
+  // about:memory is loaded (not, for example, when telemetry pings occur) and
+  // any delays in that case aren't so bad.
+  NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb,
+                            nsISupports *aClosure)
+  {
+    nsresult rv;
+    size_t totalConnSize = 0;
+    {
+      nsTArray<nsRefPtr<Connection> > connections;
+      mService->getConnections(connections);
 
-  rv = aHandleReport->Callback(EmptyCString(), path,
-                               nsIMemoryReporter::KIND_HEAP,
-                               nsIMemoryReporter::UNITS_BYTES, int64_t(curr),
-                               aDesc, aData);
-  NS_ENSURE_SUCCESS(rv, rv);
-  *aTotal += curr;
-
-  return NS_OK;
-}
+      for (uint32_t i = 0; i < connections.Length(); i++) {
+        nsRefPtr<Connection> &conn = connections[i];
 
-// Warning: To get a Connection's measurements requires holding its lock.
-// There may be a delay getting the lock if another thread is accessing the
-// Connection.  This isn't very nice if CollectReports is called from the main
-// thread!  But at the time of writing this function is only called when
-// about:memory is loaded (not, for example, when telemetry pings occur) and
-// any delays in that case aren't so bad.
-NS_IMETHODIMP
-Service::CollectReports(nsIHandleReportCallback *aHandleReport,
-                        nsISupports *aData)
-{
-  nsresult rv;
-  size_t totalConnSize = 0;
-  {
-    nsTArray<nsRefPtr<Connection> > connections;
-    getConnections(connections);
+        // Someone may have closed the Connection, in which case we skip it.
+        bool isReady;
+        (void)conn->GetConnectionReady(&isReady);
+        if (!isReady) {
+            continue;
+        }
+
+        nsCString pathHead("explicit/storage/sqlite/");
+        pathHead.Append(conn->getFilename());
+        pathHead.AppendLiteral("/");
+
+        SQLiteMutexAutoLock lockedScope(conn->sharedDBMutex);
 
-    for (uint32_t i = 0; i < connections.Length(); i++) {
-      nsRefPtr<Connection> &conn = connections[i];
+        rv = reportConn(aCb, aClosure, *conn.get(), pathHead,
+                        NS_LITERAL_CSTRING("stmt"), mStmtDesc,
+                        SQLITE_DBSTATUS_STMT_USED, &totalConnSize);
+        NS_ENSURE_SUCCESS(rv, rv);
 
-      // Someone may have closed the Connection, in which case we skip it.
-      bool isReady;
-      (void)conn->GetConnectionReady(&isReady);
-      if (!isReady) {
-          continue;
+        rv = reportConn(aCb, aClosure, *conn.get(), pathHead,
+                        NS_LITERAL_CSTRING("cache"), mCacheDesc,
+                        SQLITE_DBSTATUS_CACHE_USED, &totalConnSize);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        rv = reportConn(aCb, aClosure, *conn.get(), pathHead,
+                        NS_LITERAL_CSTRING("schema"), mSchemaDesc,
+                        SQLITE_DBSTATUS_SCHEMA_USED, &totalConnSize);
+        NS_ENSURE_SUCCESS(rv, rv);
       }
 
-      nsCString pathHead("explicit/storage/sqlite/");
-      pathHead.Append(conn->getFilename());
-      pathHead.AppendLiteral("/");
-
-      SQLiteMutexAutoLock lockedScope(conn->sharedDBMutex);
-
-      NS_NAMED_LITERAL_CSTRING(stmtDesc,
-        "Memory (approximate) used by all prepared statements used by "
-        "connections to this database.");
-      rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
-                      NS_LITERAL_CSTRING("stmt"), stmtDesc,
-                      SQLITE_DBSTATUS_STMT_USED, &totalConnSize);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      NS_NAMED_LITERAL_CSTRING(cacheDesc,
-        "Memory (approximate) used by all pager caches used by connections "
-        "to this database.");
-      rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
-                      NS_LITERAL_CSTRING("cache"), cacheDesc,
-                      SQLITE_DBSTATUS_CACHE_USED, &totalConnSize);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      NS_NAMED_LITERAL_CSTRING(schemaDesc,
-        "Memory (approximate) used to store the schema for all databases "
-        "associated with connections to this database.");
-      rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
-                      NS_LITERAL_CSTRING("schema"), schemaDesc,
-                      SQLITE_DBSTATUS_SCHEMA_USED, &totalConnSize);
-      NS_ENSURE_SUCCESS(rv, rv);
+#ifdef MOZ_DMD
+      if (::sqlite3_memory_used() != int64_t(gSqliteMemoryUsed)) {
+        NS_WARNING("memory consumption reported by SQLite doesn't match "
+                   "our measurements");
+      }
+#endif
     }
 
-#ifdef MOZ_DMD
-    if (::sqlite3_memory_used() != int64_t(gSqliteMemoryUsed)) {
-      NS_WARNING("memory consumption reported by SQLite doesn't match "
-                 "our measurements");
-    }
-#endif
+    int64_t other = ::sqlite3_memory_used() - totalConnSize;
+
+    rv = aCb->Callback(NS_LITERAL_CSTRING(""),
+                       NS_LITERAL_CSTRING("explicit/storage/sqlite/other"),
+                       nsIMemoryReporter::KIND_HEAP,
+                       nsIMemoryReporter::UNITS_BYTES, other,
+                       NS_LITERAL_CSTRING("All unclassified sqlite memory."),
+                       aClosure);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
   }
 
-  int64_t other = ::sqlite3_memory_used() - totalConnSize;
+private:
+  /**
+   * Passes a single SQLite memory statistic to a memory reporter callback.
+   *
+   * @param aCallback
+   *        The callback.
+   * @param aClosure
+   *        The closure for the callback.
+   * @param aConn
+   *        The SQLite connection.
+   * @param aPathHead
+   *        Head of the path for the memory report.
+   * @param aKind
+   *        The memory report statistic kind, one of "stmt", "cache" or
+   *        "schema".
+   * @param aDesc
+   *        The memory report description.
+   * @param aOption
+   *        The SQLite constant for getting the measurement.
+   * @param aTotal
+   *        The accumulator for the measurement.
+   */
+  nsresult reportConn(nsIMemoryReporterCallback *aCb,
+                      nsISupports *aClosure,
+                      sqlite3 *aConn,
+                      const nsACString &aPathHead,
+                      const nsACString &aKind,
+                      const nsACString &aDesc,
+                      int aOption,
+                      size_t *aTotal)
+  {
+    nsCString path(aPathHead);
+    path.Append(aKind);
+    path.AppendLiteral("-used");
 
-  rv = aHandleReport->Callback(
-          EmptyCString(),
-          NS_LITERAL_CSTRING("explicit/storage/sqlite/other"),
-          KIND_HEAP, UNITS_BYTES, other,
-          NS_LITERAL_CSTRING("All unclassified sqlite memory."),
-          aData);
-  NS_ENSURE_SUCCESS(rv, rv);
+    int curr = 0, max = 0;
+    int rc = ::sqlite3_db_status(aConn, aOption, &curr, &max, 0);
+    nsresult rv = convertResultCode(rc);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-  return NS_OK;
-}
+    rv = aCb->Callback(NS_LITERAL_CSTRING(""), path,
+                       nsIMemoryReporter::KIND_HEAP,
+                       nsIMemoryReporter::UNITS_BYTES, int64_t(curr),
+                       aDesc, aClosure);
+    NS_ENSURE_SUCCESS(rv, rv);
+    *aTotal += curr;
+
+    return NS_OK;
+  }
+};
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Service
 
-NS_IMPL_ISUPPORTS_INHERITED2(
+NS_IMPL_ISUPPORTS2(
   Service,
-  MemoryMultiReporter,
   mozIStorageService,
   nsIObserver
 )
 
 Service *Service::gService = nullptr;
 
 Service *
 Service::getSingleton()
@@ -273,27 +290,26 @@ int32_t
 Service::getSynchronousPref()
 {
   return sSynchronousPref;
 }
 
 int32_t Service::sDefaultPageSize = PREF_TS_PAGESIZE_DEFAULT;
 
 Service::Service()
-: MemoryMultiReporter("storage-sqlite")
-, mMutex("Service::mMutex")
+: mMutex("Service::mMutex")
 , mSqliteVFS(nullptr)
 , mRegistrationMutex("Service::mRegistrationMutex")
 , mConnections()
 {
 }
 
 Service::~Service()
 {
-  mozilla::UnregisterWeakMemoryReporter(this);
+  (void)::NS_UnregisterMemoryReporter(mStorageSQLiteReporter);
   mozilla::UnregisterStorageSQLiteDistinguishedAmount();
 
   int rc = sqlite3_vfs_unregister(mSqliteVFS);
   if (rc != SQLITE_OK)
     NS_WARNING("Failed to unregister sqlite vfs wrapper.");
 
   // Shutdown the sqlite3 API.  Warn if shutdown did not turn out okay, but
   // there is nothing actionable we can do in that case.
@@ -514,17 +530,21 @@ Service::initialize()
     Preferences::GetInt(PREF_TS_SYNCHRONOUS, PREF_TS_SYNCHRONOUS_DEFAULT);
 
   // We need to obtain the toolkit.storage.pageSize preferences on the main
   // thread because the preference service can only be accessed there.  This
   // is cached in the service for all future Open[Unshared]Database calls.
   sDefaultPageSize =
       Preferences::GetInt(PREF_TS_PAGESIZE, PREF_TS_PAGESIZE_DEFAULT);
 
-  mozilla::RegisterWeakMemoryReporter(this);
+  // Create and register our SQLite memory reporter and distinguished amount
+  // function.  Registration can only happen on the main thread (otherwise
+  // you'll get cryptic crashes).
+  mStorageSQLiteReporter = new StorageSQLiteReporter(this);
+  (void)::NS_RegisterMemoryReporter(mStorageSQLiteReporter);
   mozilla::RegisterStorageSQLiteDistinguishedAmount(StorageSQLiteDistinguishedAmount);
 
   return NS_OK;
 }
 
 int
 Service::localeCompareStrings(const nsAString &aStr1,
                               const nsAString &aStr2,
--- a/storage/src/mozStorageService.h
+++ b/storage/src/mozStorageService.h
@@ -5,33 +5,31 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZSTORAGESERVICE_H
 #define MOZSTORAGESERVICE_H
 
 #include "nsCOMPtr.h"
 #include "nsICollation.h"
 #include "nsIFile.h"
-#include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "nsTArray.h"
 #include "mozilla/Mutex.h"
 
 #include "mozIStorageService.h"
 
 class nsIMemoryReporter;
 class nsIXPConnect;
 struct sqlite3_vfs;
 
 namespace mozilla {
 namespace storage {
 
 class Connection;
-class Service : public MemoryMultiReporter
-              , public mozIStorageService
+class Service : public mozIStorageService
               , public nsIObserver
 {
 public:
   /**
    * Initializes the service.  This must be called before any other function!
    */
   nsresult initialize();
 
@@ -53,19 +51,16 @@ public:
                            int32_t aComparisonStrength);
 
   static Service *getSingleton();
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_MOZISTORAGESERVICE
   NS_DECL_NSIOBSERVER
 
-  NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport,
-                            nsISupports *aData);
-
   /**
    * Obtains an already AddRefed pointer to XPConnect.  This is used by
    * language helpers.
    */
   static already_AddRefed<nsIXPConnect> getXPConnect();
 
   /**
    * Obtains the cached data for the toolkit.storage.synchronous preference.
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul
@@ -1,17 +1,17 @@
 <?xml version="1.0"?>
 <?xml-stylesheet type="text/css" href="chrome://global/skin"?>
 <?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
 <window title="about:memory"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
   <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
-  <!-- This file uses fake memory reporters to test the presentation of memory
+  <!-- This file uses fake memory reporters to test the presentation of memory 
        reports in about:memory.  test_memoryReporters.xul uses the real
        memory reporters to test whether the memory reporters are producing
        sensible results. -->
 
   <!-- test results are displayed in the html:body -->
   <body xmlns="http://www.w3.org/1999/xhtml"></body>
 
   <!-- test code goes here -->
@@ -22,33 +22,41 @@
   SimpleTest.expectAssertions(27);
 
   const Cc = Components.classes;
   const Ci = Components.interfaces;
   const Cr = Components.results;
   let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
             getService(Ci.nsIMemoryReporterManager);
 
-  // Hide all the real reporters;  we'll restore them at the end.
-  mgr.blockRegistrationAndHideExistingReporters();
+  // Remove all the real reporters;  save them to restore at the end.
+  mgr.blockRegistration();
+  let e = mgr.enumerateReporters();
+  let realReporters = [];
+  while (e.hasMoreElements()) {
+    let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
+    mgr.unregisterReporter(r);
+    realReporters.push(r);
+  }
 
   // Setup various fake-but-deterministic reporters.
   const KB = 1024;
   const MB = KB * KB;
   const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP;
   const HEAP    = Ci.nsIMemoryReporter.KIND_HEAP;
   const OTHER   = Ci.nsIMemoryReporter.KIND_OTHER;
 
   const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
   const COUNT = Ci.nsIMemoryReporter.UNITS_COUNT;
   const COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE;
   const PERCENTAGE = Ci.nsIMemoryReporter.UNITS_PERCENTAGE;
 
   let fakeReporters = [
-    { collectReports: function(aCbObj, aClosure) {
+    { name: "fake0",
+      collectReports: function(aCbObj, aClosure) {
         function f(aP, aK, aU, aA) {
           aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
         }
         f("heap-allocated",     OTHER,   BYTES, 500 * MB);
         f("heap-unallocated",   OTHER,   BYTES, 100 * MB);
         f("explicit/a",         HEAP,    BYTES, 222 * MB);
         f("explicit/b/a",       HEAP,    BYTES,  85 * MB);
         f("explicit/b/b",       HEAP,    BYTES,  75 * MB);
@@ -75,76 +83,80 @@
         f("other6/small",       OTHER,   COUNT, 1);
         // Check that a 0 / 0 is handled correctly.
         f("other7/zero",        OTHER,   BYTES, 0);
         // These compartments ones shouldn't be displayed.
         f("compartments/user/foo",   OTHER, COUNT, 1);
         f("compartments/system/foo", OTHER, COUNT, 1);
       }
     },
-    { collectReports: function(aCbObj, aClosure) {
+    { name: "fake1",
+      collectReports: function(aCbObj, aClosure) {
         function f(aP, aK, aU, aA) {
           aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
         }
         f("explicit/c/d",     NONHEAP, BYTES,  13 * MB);
         f("explicit/c/d",     NONHEAP, BYTES,  10 * MB); // dup
         f("explicit/c/other", NONHEAP, BYTES,  77 * MB);
         f("explicit/cc",      NONHEAP, BYTES,  13 * MB);
         f("explicit/cc",      NONHEAP, BYTES,  10 * MB); // dup
         f("explicit/d",       NONHEAP, BYTES, 499 * KB); // omitted
         f("explicit/e",       NONHEAP, BYTES, 100 * KB); // omitted
         f("explicit/f/g/h/i", HEAP,    BYTES,  10 * MB);
         f("explicit/f/g/h/j", HEAP,    BYTES,  10 * MB);
       }
     },
-    { collectReports: function(aCbObj, aClosure) {
+    { name: "fake2",
+      collectReports: function(aCbObj, aClosure) {
         function f(aP, aK, aU, aA) {
           aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
         }
         f("other3",           OTHER,   COUNT, 777);
         f("other2",           OTHER,   BYTES, 222 * MB);
         f("perc2",            OTHER,   PERCENTAGE, 10000);
         f("perc1",            OTHER,   PERCENTAGE, 4567);
         f("compartments/user/https:\\\\very-long-url.com\\very-long\\oh-so-long\\really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789", OTHER, COUNT, 1);
       }
     },
-    { collectReports: function(aCbObj, aClosure) {
+    { name: "compartments",
+      collectReports: function(aCbObj, aClosure) {
         function f(aP) {
           aCbObj.callback("", aP, OTHER, COUNT, 1, "Desc.", aClosure);
         }
         f("compartments/user/bar");
         f("compartments/system/bar");
       }
     }
   ];
   for (let i = 0; i < fakeReporters.length; i++) {
-    mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]);
+    mgr.registerReporterEvenIfBlocked(fakeReporters[i]);
   }
 
   // mgr.explicit sums "heap-allocated" and all the appropriate NONHEAP ones:
   // - "explicit/c", "explicit/cc" x 2, "explicit/d", "explicit/e"
   // - but *not* "explicit/c/d" x 2
   // Check explicit now before we add the fake reporters for the fake 2nd
   // and subsequent processes.
   //
   // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a
   // --enable-trace-malloc build.  Allow for that exception, but *only* that
   // exception.
   try {
     is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit");
   } catch (ex) {
     is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception");
   }
-
+ 
   // The main process always comes first when we display about:memory.  The
   // remaining processes are sorted by their |resident| values (starting with
   // the largest).  Processes without a |resident| memory reporter are saved
   // for the end.
   let fakeReporters2 = [
-    { collectReports: function(aCbObj, aClosure) {
+    { name: "fake3",
+      collectReports: function(aCbObj, aClosure) {
         function f(aP1, aP2, aK, aU, aA) {
           aCbObj.callback(aP1, aP2, aK, aU, aA, "Desc.", aClosure);
         }
         f("2nd", "heap-allocated",  OTHER,   BYTES,1000* MB);
         f("2nd", "heap-unallocated",OTHER,   BYTES,100 * MB);
         f("2nd", "explicit/a/b/c",  HEAP,    BYTES,497 * MB);
         f("2nd", "explicit/a/b/c",  HEAP,    BYTES,  1 * MB); // dup: merge
         f("2nd", "explicit/a/b/c",  HEAP,    BYTES,  1 * MB); // dup: merge
@@ -188,17 +200,17 @@
         f("5th", "explicit/b/c/d/e", NONHEAP, BYTES, 20 * KB);
         f("5th", "explicit/b/c/d/f", NONHEAP, BYTES,-60 * KB);
         f("5th", "explicit/b/c/g/h", NONHEAP, BYTES, 10 * KB);
         f("5th", "explicit/b/c/i/j", NONHEAP, BYTES,  5 * KB);
       }
     }
   ];
   for (let i = 0; i < fakeReporters2.length; i++) {
-    mgr.registerStrongReporterEvenIfBlocked(fakeReporters2[i]);
+    mgr.registerReporterEvenIfBlocked(fakeReporters2[i]);
   }
   fakeReporters = fakeReporters.concat(fakeReporters2);
   ]]>
   </script>
 
   <iframe id="amFrame"  height="300" src="about:memory"></iframe>
   <!-- vary the capitalization to make sure that works -->
   <iframe id="amvFrame" height="300" src="About:Memory"></iframe>
@@ -538,17 +550,26 @@ Other Measurements\n\
 \n\
 104,857,600 B ── heap-allocated\n\
 \n\
 End of 5th\n\
 ";
 
   function finish()
   {
-    mgr.unblockRegistrationAndRestoreOriginalReporters();
+    // Unregister fake reporters and re-register the real reporters, just in
+    // case subsequent tests rely on them.
+    for (let i = 0; i < fakeReporters.length; i++) {
+      mgr.unregisterReporter(fakeReporters[i]);
+    }
+    for (let i = 0; i < realReporters.length; i++) {
+      mgr.registerReporterEvenIfBlocked(realReporters[i]);
+    }
+    mgr.unblockRegistration();
+
     SimpleTest.finish();
   }
 
   // Cut+paste the entire page and check that the cut text matches what we
   // expect.  This tests the output in general and also that the cutting and
   // pasting works as expected.
   function test(aFrameId, aVerbose, aExpected, aNext) {
     SimpleTest.executeSoon(function() {
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul
@@ -17,33 +17,41 @@
   <![CDATA[
   "use strict";
 
   const Cc = Components.classes;
   const Ci = Components.interfaces;
   let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
             getService(Ci.nsIMemoryReporterManager);
 
-  // Hide all the real reporters;  we'll restore them at the end.
-  mgr.blockRegistrationAndHideExistingReporters();
+  // Remove all the real reporters;  save them to restore at the end.
+  mgr.blockRegistration();
+  let e = mgr.enumerateReporters();
+  let realReporters = [];
+  while (e.hasMoreElements()) {
+    let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
+    mgr.unregisterReporter(r);
+    realReporters.push(r);
+  }
 
   // Setup various fake-but-deterministic reporters.
   const KB = 1024;
   const MB = KB * KB;
   const HEAP  = Ci.nsIMemoryReporter.KIND_HEAP;
   const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
   const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
 
   let hiPath  = "explicit/h/i";
   let hi2Path = "explicit/h/i2";
   let jkPath  = "explicit/j/k";
   let jk2Path = "explicit/j/k2";
 
   let fakeReporters = [
-    { collectReports: function(aCbObj, aClosure) {
+    { name: "fake1",
+      collectReports: function(aCbObj, aClosure) {
         function f(aP, aK, aA) {
           aCbObj.callback("", aP, aK, BYTES, aA, "Desc.", aClosure);
         }
         f("heap-allocated",     OTHER,   250 * MB);
         f("explicit/a/b",       HEAP,     50 * MB);
         f("explicit/a/c/d",     HEAP,     25 * MB);
         f("explicit/a/c/e",     HEAP,     15 * MB);
         f("explicit/a/f",       HEAP,     30 * MB);
@@ -54,29 +62,38 @@
         f(jk2Path,              HEAP,    0.3 * MB);
         f("explicit/a/l/m",     HEAP,    0.1 * MB);
         f("explicit/a/l/n",     HEAP,    0.1 * MB);
       }
     }
   ];
 
   for (let i = 0; i < fakeReporters.length; i++) {
-    mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]);
+    mgr.registerReporterEvenIfBlocked(fakeReporters[i]);
   }
 
   ]]>
   </script>
 
   <iframe id="amFrame"  height="500" src="about:memory"></iframe>
 
   <script type="application/javascript">
   <![CDATA[
   function finish()
   {
-    mgr.unblockRegistrationAndRestoreOriginalReporters();
+    // Unregister fake reporters and re-register the real reporters, just in
+    // case subsequent tests rely on them.
+    for (let i = 0; i < fakeReporters.length; i++) {
+      mgr.unregisterReporter(fakeReporters[i]);
+    }
+    for (let i = 0; i < realReporters.length; i++) {
+      mgr.registerReporterEvenIfBlocked(realReporters[i]);
+    }
+    mgr.unblockRegistration();
+
     SimpleTest.finish();
   }
 
   // Click on the identified element, then cut+paste the entire page and
   // check that the cut text matches what we expect.
   function test(aId, aSwap, aExpected, aNext) {
     let win = document.getElementById("amFrame").contentWindow;
     if (aId) {
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
@@ -17,53 +17,70 @@
   <![CDATA[
   "use strict";
 
   const Cc = Components.classes;
   const Ci = Components.interfaces;
   let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
             getService(Ci.nsIMemoryReporterManager);
 
-  // Hide all the real reporters;  we'll restore them at the end.
-  mgr.blockRegistrationAndHideExistingReporters();
+  // Remove all the real reporters;  save them to restore at the end.
+  mgr.blockRegistration();
+  let e = mgr.enumerateReporters();
+  let realReporters = [];
+  while (e.hasMoreElements()) {
+    let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
+    mgr.unregisterReporter(r);
+    realReporters.push(r);
+  }
 
   // Setup a minimal number of fake reporters.
   const KB = 1024;
   const MB = KB * KB;
   const HEAP  = Ci.nsIMemoryReporter.KIND_HEAP;
   const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
   const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
 
   let fakeReporters = [
-    { collectReports: function(aCbObj, aClosure) {
+    { name: "fake1",
+      collectReports: function(aCbObj, aClosure) {
         function f(aP, aK, aA, aD) {
           aCbObj.callback("", aP, aK, BYTES, aA, aD, aClosure);
         }
         f("heap-allocated",     OTHER,   250 * MB, "Heap allocated.");
         f("explicit/a/b",       HEAP,     50 * MB, "A b.");
         f("other/a",            OTHER,   0.2 * MB, "Other a.");
         f("other/b",            OTHER,   0.1 * MB, "Other b.");
       }
     }
   ];
 
   for (let i = 0; i < fakeReporters.length; i++) {
-    mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]);
+    mgr.registerReporterEvenIfBlocked(fakeReporters[i]);
   }
 
   ]]>
   </script>
 
   <iframe id="amFrame"  height="400" src="about:memory"></iframe>
 
   <script type="application/javascript">
   <![CDATA[
   function finish()
   {
-    mgr.unblockRegistrationAndRestoreOriginalReporters();
+    // Unregister fake reporters and re-register the real reporters, just in
+    // case subsequent tests rely on them.
+    for (let i = 0; i < fakeReporters.length; i++) {
+      mgr.unregisterReporter(fakeReporters[i]);
+    }
+    for (let i = 0; i < realReporters.length; i++) {
+      mgr.registerReporterEvenIfBlocked(realReporters[i]);
+    }
+    mgr.unblockRegistration();
+
     SimpleTest.finish();
   }
 
   // Load the given file into the frame, then copy+paste the entire frame and
   // check that the cut text matches what we expect.
   function test(aFilename, aFilename2, aExpected, aDumpFirst, aNext) {
     let frame = document.getElementById("amFrame");
     frame.focus();
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
@@ -170,16 +170,19 @@
   mgr.sizeOfTab(window, jsObjectsSize, jsStringsSize, jsOtherSize,
                 domSize, styleSize, otherSize, totalSize,
                 jsMilliseconds, nonJSMilliseconds);
 
   let e = mgr.enumerateReporters();
   while (e.hasMoreElements()) {
     let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
     r.collectReports(handleReport, null);
+
+    // Access |name| to make sure it doesn't crash or assert.
+    dummy = r.name;
   }
 
   function checkSpecialReport(aName, aAmounts, aCanBeUnreasonable)
   {
     ok(aAmounts.length == 1, aName + " has " + aAmounts.length + " report");
     let n = aAmounts[0];
     // Check the size is reasonable -- i.e. not ridiculously large or small.
     ok((100 * 1000 <= n && n <= 10 * 1000 * 1000 * 1000) || aCanBeUnreasonable,
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -26,16 +26,17 @@
 #include "mozilla/dom/Link.h"
 #include "nsDocShellCID.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 #include "nsIXPConnect.h"
 #include "mozilla/unused.h"
 #include "nsContentUtils.h" // for nsAutoScriptBlocker
+#include "nsIMemoryReporter.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "nsPrintfCString.h"
 #include "nsTHashtable.h"
 #include "jsapi.h"
 
 // Initial size for the cache holding visited status observers.
 #define VISIT_OBSERVERS_INITIAL_CACHE_SIZE 128
 
@@ -1902,59 +1903,69 @@ StoreAndNotifyEmbedVisit(VisitData& aPla
     (void)NS_ProxyRelease(mainThread, aCallback, true);
   }
 
   VisitData noReferrer;
   nsCOMPtr<nsIRunnable> event = new NotifyVisitObservers(aPlace, noReferrer);
   (void)NS_DispatchToMainThread(event);
 }
 
+class HistoryLinksHashtableReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+  HistoryLinksHashtableReporter()
+    : MemoryUniReporter("explicit/history-links-hashtable",
+                         KIND_HEAP, UNITS_BYTES,
+"Memory used by the hashtable that records changes to the visited state of "
+"links.")
+    {}
+private:
+  int64_t Amount() MOZ_OVERRIDE
+  {
+    History* history = History::GetService();
+    return history ? history->SizeOfIncludingThis(MallocSizeOf) : 0;
+  }
+};
+
 } // anonymous namespace
 
 ////////////////////////////////////////////////////////////////////////////////
 //// History
 
 History* History::gService = nullptr;
 
 History::History()
-  : MemoryUniReporter("explicit/history-links-hashtable",
-                      KIND_HEAP, UNITS_BYTES,
-"Memory used by the hashtable that records changes to the visited state of "
-"links.")
-  , mShuttingDown(false)
+  : mShuttingDown(false)
   , mShutdownMutex("History::mShutdownMutex")
   , mObservers(VISIT_OBSERVERS_INITIAL_CACHE_SIZE)
   , mRecentlyVisitedURIsNextIndex(0)
 {
   NS_ASSERTION(!gService, "Ruh-roh!  This service has already been created!");
   gService = this;
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   NS_WARN_IF_FALSE(os, "Observer service was not found!");
   if (os) {
     (void)os->AddObserver(this, TOPIC_PLACES_SHUTDOWN, false);
   }
+
+  mReporter = new HistoryLinksHashtableReporter();
+  NS_RegisterMemoryReporter(mReporter);
 }
 
 History::~History()
 {
-  UnregisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
 
   gService = nullptr;
 
   NS_ASSERTION(mObservers.Count() == 0,
                "Not all Links were removed before we disappear!");
 }
 
-void
-History::InitMemoryReporter()
-{
-  RegisterWeakMemoryReporter(this);
-}
-
 NS_IMETHODIMP
 History::NotifyVisited(nsIURI* aURI)
 {
   NS_ENSURE_ARG(aURI);
 
   nsAutoScriptBlocker scriptBlocker;
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
@@ -2216,22 +2227,16 @@ History::FetchPageInfo(VisitData& _place
 }
 
 /* static */ size_t
 History::SizeOfEntryExcludingThis(KeyClass* aEntry, mozilla::MallocSizeOf aMallocSizeOf, void *)
 {
   return aEntry->array.SizeOfExcludingThis(aMallocSizeOf);
 }
 
-int64_t
-History::Amount()
-{
-  return SizeOfIncludingThis(MallocSizeOf);
-}
-
 size_t
 History::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOfThis)
 {
   return aMallocSizeOfThis(this) +
          mObservers.SizeOfExcludingThis(SizeOfEntryExcludingThis, aMallocSizeOfThis);
 }
 
 /* static */
@@ -2251,17 +2256,16 @@ History::GetService()
 
 /* static */
 History*
 History::GetSingleton()
 {
   if (!gService) {
     gService = new History();
     NS_ENSURE_TRUE(gService, nullptr);
-    gService->InitMemoryReporter();
   }
 
   NS_ADDREF(gService);
   return gService;
 }
 
 mozIStorageConnection*
 History::GetDBConn()
@@ -2909,19 +2913,18 @@ History::Observe(nsISupports* aSubject, 
   }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsISupports
 
-NS_IMPL_ISUPPORTS_INHERITED4(
+NS_IMPL_ISUPPORTS4(
   History
-, MemoryUniReporter
 , IHistory
 , nsIDownloadHistory
 , mozIAsyncHistory
 , nsIObserver
 )
 
 } // namespace places
 } // namespace mozilla
--- a/toolkit/components/places/History.h
+++ b/toolkit/components/places/History.h
@@ -15,33 +15,33 @@
 #include "Database.h"
 
 #include "mozilla/dom/Link.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 #include "nsURIHashKey.h"
 #include "nsTObserverArray.h"
 #include "nsDeque.h"
-#include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "mozIStorageConnection.h"
 
+class nsIMemoryReporter;
+
 namespace mozilla {
 namespace places {
 
 struct VisitData;
 
 #define NS_HISTORYSERVICE_CID \
   {0x0937a705, 0x91a6, 0x417a, {0x82, 0x92, 0xb2, 0x2e, 0xb1, 0x0d, 0xa8, 0x6c}}
 
 // Max size of History::mRecentlyVisitedURIs
 #define RECENTLY_VISITED_URI_SIZE 8
 
-class History : mozilla::MemoryUniReporter
-              , public IHistory
+class History : public IHistory
               , public nsIDownloadHistory
               , public mozIAsyncHistory
               , public nsIObserver
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_IHISTORY
   NS_DECL_NSIDOWNLOADHISTORY
@@ -80,17 +80,16 @@ public:
    *        Whether or the page was recorded in moz_places, false otherwise.
    */
   nsresult FetchPageInfo(VisitData& _place, bool* _exists);
 
   /**
    * Get the number of bytes of memory this History object is using,
    * including sizeof(*this))
    */
-  int64_t Amount() MOZ_OVERRIDE;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
   /**
    * Obtains a pointer to this service.
    */
   static History* GetService();
 
   /**
@@ -127,18 +126,16 @@ public:
    * Helper function to append a new URI to mRecentlyVisitedURIs. See
    * mRecentlyVisitedURIs.
    */
   void AppendToRecentlyVisitedURIs(nsIURI* aURI);
 
 private:
   virtual ~History();
 
-  void InitMemoryReporter();
-
   /**
    * Obtains a read-write database connection.
    */
   mozIStorageConnection* GetDBConn();
 
   /**
    * The database handle.  This is initialized lazily by the first call to
    * GetDBConn(), so never use it directly, or, if you really need, always
@@ -208,14 +205,16 @@ private:
    * to avoid saving these locations repeatedly in a short period.
    */
   typedef nsAutoTArray<nsCOMPtr<nsIURI>, RECENTLY_VISITED_URI_SIZE>
           RecentlyVisitedArray;
   RecentlyVisitedArray mRecentlyVisitedURIs;
   RecentlyVisitedArray::index_type mRecentlyVisitedURIsNextIndex;
 
   bool IsRecentlyVisitedURI(nsIURI* aURI);
+
+  nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 } // namespace places
 } // namespace mozilla
 
 #endif // mozilla_places_History_h_
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -227,53 +227,49 @@ HangReports::GetStacks() const {
   return mStacks;
 }
 
 uint32_t
 HangReports::GetDuration(unsigned aIndex) const {
   return mDurations[aIndex];
 }
 
-class TelemetryImpl MOZ_FINAL
-  : public MemoryUniReporter
-  , public nsITelemetry
+class TelemetryImpl MOZ_FINAL : public nsITelemetry
 {
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSITELEMETRY
 
 public:
+  TelemetryImpl();
   ~TelemetryImpl();
-
-  void InitMemoryReporter();
-
+  
   static bool CanRecord();
   static already_AddRefed<nsITelemetry> CreateTelemetryInstance();
   static void ShutdownTelemetry();
   static void RecordSlowStatement(const nsACString &sql, const nsACString &dbName,
                                   uint32_t delay);
 #if defined(MOZ_ENABLE_PROFILER_SPS)
   static void RecordChromeHang(uint32_t duration,
                                Telemetry::ProcessedStack &aStack);
 #endif
   static void RecordThreadHangStats(Telemetry::ThreadHangStats& aStats);
   static nsresult GetHistogramEnumId(const char *name, Telemetry::ID *id);
-  int64_t Amount() MOZ_OVERRIDE;
-  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
+  static int64_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
   struct Stat {
     uint32_t hitCount;
     uint32_t totalTime;
   };
   struct StmtStats {
     struct Stat mainThread;
     struct Stat otherThreads;
   };
   typedef nsBaseHashtableET<nsCStringHashKey, StmtStats> SlowSQLEntryType;
 
 private:
-  TelemetryImpl();
+  size_t SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf);
 
   static nsCString SanitizeSQL(const nsACString& sql);
 
   enum SanitizedState { Sanitized, Unsanitized };
 
   static void StoreSlowSQL(const nsACString &offender, uint32_t delay,
                            SanitizedState state);
 
@@ -325,58 +321,75 @@ private:
   // AutoHashtable here.
   nsTHashtable<nsCStringHashKey> mTrackedDBs;
   Mutex mHashMutex;
   HangReports mHangReports;
   Mutex mHangReportsMutex;
   // mThreadHangStats stores recorded, inactive thread hang stats
   Vector<Telemetry::ThreadHangStats> mThreadHangStats;
   Mutex mThreadHangStatsMutex;
+  nsCOMPtr<nsIMemoryReporter> mReporter;
 
   CombinedStacks mLateWritesStacks; // This is collected out of the main thread.
   bool mCachedTelemetryData;
   uint32_t mLastShutdownTime;
   uint32_t mFailedLockCount;
   nsCOMArray<nsIFetchTelemetryDataCallback> mCallbacks;
   friend class nsFetchTelemetryData;
 };
 
 TelemetryImpl*  TelemetryImpl::sTelemetry = nullptr;
 
-int64_t
-TelemetryImpl::Amount()
-{
-  return SizeOfIncludingThis(MallocSizeOf);
-}
-
 size_t
-TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+TelemetryImpl::SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf)
 {
   size_t n = aMallocSizeOf(this);
   // Ignore the hashtables in mAddonMap; they are not significant.
   n += mAddonMap.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   n += mHistogramMap.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   n += mPrivateSQL.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   n += mSanitizedSQL.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   n += mTrackedDBs.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   n += mHangReports.SizeOfExcludingThis();
   n += mThreadHangStats.sizeOfExcludingThis(aMallocSizeOf);
+  return n;
+}
 
-  // It's a bit gross that we measure this other stuff that lives outside of
-  // TelemetryImpl... oh well.
+int64_t
+TelemetryImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+{
+  int64_t n = 0;
+  if (sTelemetry) {
+    n += sTelemetry->SizeOfIncludingThisHelper(aMallocSizeOf);
+  }
+
   StatisticsRecorder::Histograms hs;
   StatisticsRecorder::GetHistograms(&hs);
+
   for (HistogramIterator it = hs.begin(); it != hs.end(); ++it) {
     Histogram *h = *it;
     n += h->SizeOfIncludingThis(aMallocSizeOf);
   }
-
   return n;
 }
 
+class TelemetryReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+  TelemetryReporter()
+    : MemoryUniReporter("explicit/telemetry", KIND_HEAP, UNITS_BYTES,
+                         "Memory used by the telemetry system.")
+  {}
+private:
+  int64_t Amount() MOZ_OVERRIDE
+  {
+    return TelemetryImpl::SizeOfIncludingThis(MallocSizeOf);
+  }
+};
+
 // A initializer to initialize histogram collection
 StatisticsRecorder gStatisticsRecorder;
 
 // Hardcoded probes
 struct TelemetryHistogram {
   uint32_t min;
   uint32_t max;
   uint32_t bucketCount;
@@ -746,17 +759,17 @@ public:
       mTelemetry(TelemetryImpl::sTelemetry),
       mProfileDir(aProfileDir)
   {
   }
 
 private:
   const char* mShutdownTimeFilename;
   nsCOMPtr<nsIFile> mFailedProfileLockFile;
-  nsRefPtr<TelemetryImpl> mTelemetry;
+  nsCOMPtr<TelemetryImpl> mTelemetry;
   nsCOMPtr<nsIFile> mProfileDir;
 
 public:
   void MainThread() {
     mTelemetry->mCachedTelemetryData = true;
     for (unsigned int i = 0, n = mTelemetry->mCallbacks.Count(); i < n; ++i) {
       mTelemetry->mCallbacks[i]->Complete();
     }
@@ -926,18 +939,16 @@ TelemetryImpl::AsyncFetchTelemetryData(n
                                                          failedProfileLockFile,
                                                          profileDir);
 
   targetThread->Dispatch(event, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
 TelemetryImpl::TelemetryImpl():
-MemoryUniReporter("explicit/telemetry", KIND_HEAP, UNITS_BYTES,
-                  "Memory used by the telemetry system."),
 mHistogramMap(Telemetry::HistogramCount),
 mCanRecord(XRE_GetProcessType() == GeckoProcessType_Default),
 mHashMutex("Telemetry::mHashMutex"),
 mHangReportsMutex("Telemetry::mHangReportsMutex"),
 mThreadHangStatsMutex("Telemetry::mThreadHangStatsMutex"),
 mCachedTelemetryData(false),
 mLastShutdownTime(0),
 mFailedLockCount(0)
@@ -953,25 +964,22 @@ mFailedLockCount(0)
 
   for (size_t i = 0; i < ArrayLength(trackedDBs); i++)
     mTrackedDBs.PutEntry(nsDependentCString(trackedDBs[i]));
 
 #ifdef DEBUG
   // Mark immutable to prevent asserts on simultaneous access from multiple threads
   mTrackedDBs.MarkImmutable();
 #endif
+  mReporter = new TelemetryReporter();
+  NS_RegisterMemoryReporter(mReporter);
 }
 
 TelemetryImpl::~TelemetryImpl() {
-  UnregisterWeakMemoryReporter(this);
-}
-
-void
-TelemetryImpl::InitMemoryReporter() {
-  RegisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
 }
 
 NS_IMETHODIMP
 TelemetryImpl::NewHistogram(const nsACString &name, uint32_t min, uint32_t max,
                             uint32_t bucketCount, uint32_t histogramType,
                             JSContext *cx, JS::Value *ret)
 {
   Histogram *h;
@@ -2015,19 +2023,16 @@ already_AddRefed<nsITelemetry>
 TelemetryImpl::CreateTelemetryInstance()
 {
   NS_ABORT_IF_FALSE(sTelemetry == nullptr, "CreateTelemetryInstance may only be called once, via GetService()");
   sTelemetry = new TelemetryImpl();
   // AddRef for the local reference
   NS_ADDREF(sTelemetry);
   // AddRef for the caller
   nsCOMPtr<nsITelemetry> ret = sTelemetry;
-
-  sTelemetry->InitMemoryReporter();
-
   return ret.forget();
 }
 
 void
 TelemetryImpl::ShutdownTelemetry()
 {
   NS_IF_RELEASE(sTelemetry);
 }
@@ -2242,17 +2247,17 @@ TelemetryImpl::RecordThreadHangStats(Tel
   if (!sTelemetry || !sTelemetry->mCanRecord)
     return;
 
   MutexAutoLock autoLock(sTelemetry->mThreadHangStatsMutex);
 
   sTelemetry->mThreadHangStats.append(Move(aStats));
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(TelemetryImpl, MemoryUniReporter, nsITelemetry)
+NS_IMPL_ISUPPORTS1(TelemetryImpl, nsITelemetry)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsITelemetry, TelemetryImpl::CreateTelemetryInstance)
 
 #define NS_TELEMETRY_CID \
   {0xaea477f2, 0xb3a2, 0x469c, {0xaa, 0x29, 0x0a, 0x82, 0xd1, 0x32, 0xb8, 0x29}}
 NS_DEFINE_NAMED_CID(NS_TELEMETRY_CID);
 
 const Module::CIDEntry kTelemetryCIDs[] = {
   { &kNS_TELEMETRY_CID, false, nullptr, nsITelemetryConstructor },
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
@@ -9,16 +9,17 @@
 #include "nsDebug.h"
 #include "nsPrintfCString.h"
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsUrlClassifierPrefixSet.h"
 #include "nsIUrlClassifierPrefixSet.h"
 #include "nsIRandomGenerator.h"
 #include "nsIFile.h"
+#include "nsIMemoryReporter.h"
 #include "nsToolkitCompsCID.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/FileUtils.h"
 #include "prlog.h"
@@ -30,46 +31,63 @@ using namespace mozilla;
 static const PRLogModuleInfo *gUrlClassifierPrefixSetLog = nullptr;
 #define LOG(args) PR_LOG(gUrlClassifierPrefixSetLog, PR_LOG_DEBUG, args)
 #define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierPrefixSetLog, 4)
 #else
 #define LOG(args)
 #define LOG_ENABLED() (false)
 #endif
 
-NS_IMPL_ISUPPORTS2(
-  nsUrlClassifierPrefixSet, nsIUrlClassifierPrefixSet, nsIMemoryReporter)
+class PrefixSetReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+  PrefixSetReporter(nsUrlClassifierPrefixSet* aPrefixSet,
+                    const nsACString& aName)
+    : MemoryUniReporter(
+        nsPrintfCString(
+          "explicit/storage/prefix-set/%s",
+          (!aName.IsEmpty() ? PromiseFlatCString(aName).get() : "?!")
+        ).get(),
+        KIND_HEAP, UNITS_BYTES,
+        "Memory used by the prefix set for a URL classifier.")
+    , mPrefixSet(aPrefixSet)
+  {}
+
+private:
+  int64_t Amount() MOZ_OVERRIDE
+  {
+    return mPrefixSet->SizeOfIncludingThis(MallocSizeOf);
+  }
+
+  nsUrlClassifierPrefixSet* mPrefixSet;
+};
+
+NS_IMPL_ISUPPORTS1(nsUrlClassifierPrefixSet, nsIUrlClassifierPrefixSet)
 
 nsUrlClassifierPrefixSet::nsUrlClassifierPrefixSet()
   : mHasPrefixes(false)
-  , mMemoryReportPath()
 {
 #if defined(PR_LOGGING)
   if (!gUrlClassifierPrefixSetLog)
     gUrlClassifierPrefixSetLog = PR_NewLogModule("UrlClassifierPrefixSet");
 #endif
 }
 
 NS_IMETHODIMP
 nsUrlClassifierPrefixSet::Init(const nsACString& aName)
 {
-  mMemoryReportPath =
-    nsPrintfCString(
-      "explicit/storage/prefix-set/%s",
-      (!aName.IsEmpty() ? PromiseFlatCString(aName).get() : "?!")
-    );
-
-  RegisterWeakMemoryReporter(this);
+  mReporter = new PrefixSetReporter(this, aName);
+  NS_RegisterMemoryReporter(mReporter);
 
   return NS_OK;
 }
 
 nsUrlClassifierPrefixSet::~nsUrlClassifierPrefixSet()
 {
-  UnregisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
 }
 
 NS_IMETHODIMP
 nsUrlClassifierPrefixSet::SetPrefixes(const uint32_t* aArray, uint32_t aLength)
 {
   if (aLength <= 0) {
     if (mHasPrefixes) {
       LOG(("Clearing PrefixSet"));
@@ -245,31 +263,18 @@ nsUrlClassifierPrefixSet::Contains(uint3
 
   if (diff == 0) {
     *aFound = true;
   }
 
   return NS_OK;
 }
 
-NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(UrlClassifierMallocSizeOf)
-
-NS_IMETHODIMP
-nsUrlClassifierPrefixSet::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                         nsISupports* aData)
-{
-  return aHandleReport->Callback(
-    EmptyCString(), mMemoryReportPath, KIND_HEAP, UNITS_BYTES,
-    SizeOfIncludingThis(UrlClassifierMallocSizeOf),
-    NS_LITERAL_CSTRING("Memory used by the prefix set for a URL classifier."),
-    aData);
-}
-
 size_t
-nsUrlClassifierPrefixSet::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+nsUrlClassifierPrefixSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
 {
   size_t n = 0;
   n += aMallocSizeOf(this);
   n += mDeltas.SizeOfExcludingThis(aMallocSizeOf);
   n += mIndexPrefixes.SizeOfExcludingThis(aMallocSizeOf);
   n += mIndexStarts.SizeOfExcludingThis(aMallocSizeOf);
   return n;
 }
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h
@@ -5,65 +5,64 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsUrlClassifierPrefixSet_h_
 #define nsUrlClassifierPrefixSet_h_
 
 #include "nsISupportsUtils.h"
 #include "nsID.h"
 #include "nsIFile.h"
-#include "nsIMemoryReporter.h"
 #include "nsIMutableArray.h"
 #include "nsIUrlClassifierPrefixSet.h"
 #include "nsTArray.h"
 #include "nsToolkitCompsCID.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/FileUtils.h"
 
-class nsUrlClassifierPrefixSet
-  : public nsIUrlClassifierPrefixSet
-  , public nsIMemoryReporter
+class nsIMemoryReporter;
+
+class nsUrlClassifierPrefixSet : public nsIUrlClassifierPrefixSet
 {
 public:
   nsUrlClassifierPrefixSet();
   virtual ~nsUrlClassifierPrefixSet();
 
   NS_IMETHOD Init(const nsACString& aName);
   NS_IMETHOD SetPrefixes(const uint32_t* aArray, uint32_t aLength);
   NS_IMETHOD GetPrefixes(uint32_t* aCount, uint32_t** aPrefixes);
   NS_IMETHOD Contains(uint32_t aPrefix, bool* aFound);
   NS_IMETHOD IsEmpty(bool* aEmpty);
   NS_IMETHOD LoadFromFile(nsIFile* aFile);
   NS_IMETHOD StoreToFile(nsIFile* aFile);
 
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSIMEMORYREPORTER
+  NS_DECL_ISUPPORTS
 
-  // Return the estimated size of the set on disk and in memory, in bytes.
+  // Return the estimated size of the set on disk and in memory,
+  // in bytes
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 
 protected:
   static const uint32_t DELTAS_LIMIT = 100;
   static const uint32_t MAX_INDEX_DIFF = (1 << 16);
   static const uint32_t PREFIXSET_VERSION_MAGIC = 1;
 
+  nsCOMPtr<nsIMemoryReporter> mReporter;
+
   nsresult MakePrefixSet(const uint32_t* aArray, uint32_t aLength);
   uint32_t BinSearch(uint32_t start, uint32_t end, uint32_t target);
   nsresult LoadFromFd(mozilla::AutoFDClose& fileFd);
   nsresult StoreToFd(mozilla::AutoFDClose& fileFd);
 
   // boolean indicating whether |setPrefixes| has been
   // called with a non-empty array.
   bool mHasPrefixes;
   // the prefix for each index.
   FallibleTArray<uint32_t> mIndexPrefixes;
   // the value corresponds to the beginning of the run
   // (an index in |_deltas|) for the index
   FallibleTArray<uint32_t> mIndexStarts;
   // array containing deltas from indices.
   FallibleTArray<uint16_t> mDeltas;
-
-  nsCString mMemoryReportPath;
 };
 
 #endif
--- a/xpcom/base/AvailableMemoryTracker.cpp
+++ b/xpcom/base/AvailableMemoryTracker.cpp
@@ -505,20 +505,20 @@ void Activate()
 
   Preferences::AddUintVarCache(&sLowPhysicalMemoryThreshold,
       "memory.low_physical_memory_threshold_mb", 0);
   Preferences::AddUintVarCache(&sLowCommitSpaceThreshold,
       "memory.low_commit_space_threshold_mb", 128);
   Preferences::AddUintVarCache(&sLowMemoryNotificationIntervalMS,
       "memory.low_memory_notification_interval_ms", 10000);
 
-  RegisterStrongMemoryReporter(new LowCommitSpaceEventsReporter());
-  RegisterStrongMemoryReporter(new LowMemoryEventsPhysicalReporter());
+  NS_RegisterMemoryReporter(new LowCommitSpaceEventsReporter());
+  NS_RegisterMemoryReporter(new LowMemoryEventsPhysicalReporter());
   if (sizeof(void*) == 4) {
-    RegisterStrongMemoryReporter(new LowMemoryEventsVirtualReporter());
+    NS_RegisterMemoryReporter(new LowMemoryEventsVirtualReporter());
   }
   RegisterLowMemoryEventsVirtualDistinguishedAmount(LowMemoryEventsVirtualDistinguishedAmount);
   RegisterLowMemoryEventsPhysicalDistinguishedAmount(LowMemoryEventsPhysicalDistinguishedAmount);
   sHooksActive = true;
 #endif
 
   // This object is held alive by the observer service.
   nsRefPtr<nsMemoryPressureWatcher> watcher = new nsMemoryPressureWatcher();
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -990,20 +990,18 @@ enum ccType {
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
 ////////////////////////////////////////////////////////////////////////
 // Top level structure for the cycle collector.
 ////////////////////////////////////////////////////////////////////////
 
-class nsCycleCollector : public MemoryMultiReporter
+class nsCycleCollector
 {
-    NS_DECL_ISUPPORTS
-
     bool mCollectionInProgress;
     // mScanInProgress should be false when we're collecting white objects.
     bool mScanInProgress;
     CycleCollectorResults mResults;
     TimeStamp mCollectionStart;
 
     CycleCollectedJSRuntime *mJSRuntime;
 
@@ -1015,24 +1013,26 @@ class nsCycleCollector : public MemoryMu
 
     nsCycleCollectorParams mParams;
 
     uint32_t mWhiteNodeCount;
 
     CC_BeforeUnlinkCallback mBeforeUnlinkCB;
     CC_ForgetSkippableCallback mForgetSkippableCB;
 
+    nsCOMPtr<nsIMemoryReporter> mReporter;
+
     nsPurpleBuffer mPurpleBuf;
 
     uint32_t mUnmergedNeeded;
     uint32_t mMergedInARow;
 
 public:
     nsCycleCollector();
-    virtual ~nsCycleCollector();
+    ~nsCycleCollector();
 
     void RegisterJSRuntime(CycleCollectedJSRuntime *aJSRuntime);
     void ForgetJSRuntime();
 
     void SetBeforeUnlinkCallback(CC_BeforeUnlinkCallback aBeforeUnlinkCB)
     {
         CheckThreadSafety();
         mBeforeUnlinkCB = aBeforeUnlinkCB;
@@ -1049,20 +1049,17 @@ public:
     uint32_t SuspectedCount();
     void ForgetSkippable(bool aRemoveChildlessNodes, bool aAsyncSnowWhiteFreeing);
     bool FreeSnowWhite(bool aUntilNoSWInPurpleBuffer);
 
     bool Collect(ccType aCCType,
                  nsICycleCollectorListener *aManualListener);
     void Shutdown();
 
-    NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData);
-
-    void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+    void SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                              size_t *aObjectSize,
                              size_t *aGraphNodesSize,
                              size_t *aGraphEdgesSize,
                              size_t *aWeakMapsSize,
                              size_t *aPurpleBufferSize) const;
 
 private:
     void CheckThreadSafety();
@@ -1077,18 +1074,16 @@ private:
     void ScanWeakMaps();
 
     // returns whether anything was collected
     bool CollectWhite();
 
     void CleanupAfterCollection();
 };
 
-NS_IMPL_ISUPPORTS_INHERITED0(nsCycleCollector, MemoryMultiReporter)
-
 /**
  * GraphWalker is templatized over a Visitor class that must provide
  * the following two methods:
  *
  * bool ShouldVisitNode(PtrInfo const *pi);
  * void VisitNode(PtrInfo *pi);
  */
 template <class Visitor>
@@ -1116,17 +1111,17 @@ public:
 };
 
 
 ////////////////////////////////////////////////////////////////////////
 // The static collector struct
 ////////////////////////////////////////////////////////////////////////
 
 struct CollectorData {
-  nsRefPtr<nsCycleCollector> mCollector;
+  nsCycleCollector* mCollector;
   CycleCollectedJSRuntime* mRuntime;
 };
 
 static mozilla::ThreadLocal<CollectorData*> sCollectorData;
 
 ////////////////////////////////////////////////////////////////////////
 // Utility functions
 ////////////////////////////////////////////////////////////////////////
@@ -2471,108 +2466,120 @@ nsCycleCollector::CollectWhite()
 
     nsCycleCollector_dispatchDeferredDeletion(false);
 
     return count > 0;
 }
 
 
 ////////////////////////
-// Memory reporting
+// Memory reporter
 ////////////////////////
 
-NS_IMETHODIMP
-nsCycleCollector::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                 nsISupports* aData)
+class CycleCollectorReporter MOZ_FINAL : public MemoryMultiReporter
 {
-    size_t objectSize, graphNodesSize, graphEdgesSize, weakMapsSize,
-           purpleBufferSize;
-    SizeOfIncludingThis(MallocSizeOf,
-                        &objectSize,
-                        &graphNodesSize, &graphEdgesSize,
-                        &weakMapsSize,
-                        &purpleBufferSize);
-
-#define REPORT(_path, _amount, _desc)                                     \
-    do {                                                                  \
-        size_t amount = _amount;  /* evaluate |_amount| only once */      \
-        if (amount > 0) {                                                 \
-            nsresult rv;                                                  \
-            rv = aHandleReport->Callback(EmptyCString(),                  \
-                                         NS_LITERAL_CSTRING(_path),       \
-                                         KIND_HEAP, UNITS_BYTES, _amount, \
-                                         NS_LITERAL_CSTRING(_desc),       \
-                                         aData);                          \
-            if (NS_WARN_IF(NS_FAILED(rv)))                                \
-                return rv;                                                \
-        }                                                                 \
-    } while (0)
-
-    REPORT("explicit/cycle-collector/collector-object", objectSize,
-           "Memory used for the cycle collector object itself.");
-
-    REPORT("explicit/cycle-collector/graph-nodes", graphNodesSize,
-           "Memory used for the nodes of the cycle collector's graph. "
-           "This should be zero when the collector is idle.");
-
-    REPORT("explicit/cycle-collector/graph-edges", graphEdgesSize,
-           "Memory used for the edges of the cycle collector's graph. "
-           "This should be zero when the collector is idle.");
-
-    REPORT("explicit/cycle-collector/weak-maps", weakMapsSize,
-           "Memory used for the representation of weak maps in the "
-           "cycle collector's graph. "
-           "This should be zero when the collector is idle.");
-
-    REPORT("explicit/cycle-collector/purple-buffer", purpleBufferSize,
-           "Memory used for the cycle collector's purple buffer.");
-
-#undef REPORT
-
-    return NS_OK;
+  public:
+    CycleCollectorReporter(nsCycleCollector* aCollector)
+        : MemoryMultiReporter("cycle-collector"),
+          mCollector(aCollector)
+    {}
+
+    NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
+                              nsISupports* aClosure)
+    {
+        size_t objectSize, graphNodesSize, graphEdgesSize, weakMapsSize,
+            purpleBufferSize;
+        mCollector->SizeOfIncludingThis(MallocSizeOf,
+                                        &objectSize,
+                                        &graphNodesSize, &graphEdgesSize,
+                                        &weakMapsSize,
+                                        &purpleBufferSize);
+
+    #define REPORT(_path, _amount, _desc)                                     \
+        do {                                                                  \
+            size_t amount = _amount;  /* evaluate |_amount| only once */      \
+            if (amount > 0) {                                                 \
+                nsresult rv;                                                  \
+                rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
+                                   nsIMemoryReporter::KIND_HEAP,              \
+                                   nsIMemoryReporter::UNITS_BYTES, _amount,   \
+                                   NS_LITERAL_CSTRING(_desc), aClosure);      \
+                if (NS_WARN_IF(NS_FAILED(rv)))                                \
+                    return rv;                                                \
+            }                                                                 \
+        } while (0)
+
+        REPORT("explicit/cycle-collector/collector-object", objectSize,
+               "Memory used for the cycle collector object itself.");
+
+        REPORT("explicit/cycle-collector/graph-nodes", graphNodesSize,
+               "Memory used for the nodes of the cycle collector's graph. "
+               "This should be zero when the collector is idle.");
+
+        REPORT("explicit/cycle-collector/graph-edges", graphEdgesSize,
+               "Memory used for the edges of the cycle collector's graph. "
+               "This should be zero when the collector is idle.");
+
+        REPORT("explicit/cycle-collector/weak-maps", weakMapsSize,
+               "Memory used for the representation of weak maps in the "
+               "cycle collector's graph. "
+               "This should be zero when the collector is idle.");
+
+        REPORT("explicit/cycle-collector/purple-buffer", purpleBufferSize,
+               "Memory used for the cycle collector's purple buffer.");
+
+    #undef REPORT
+
+        return NS_OK;
+    }
+
+  private:
+    NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf)
+
+    nsCycleCollector* mCollector;
 };
 
 
 ////////////////////////////////////////////////////////////////////////
 // Collector implementation
 ////////////////////////////////////////////////////////////////////////
 
 nsCycleCollector::nsCycleCollector() :
-    MemoryMultiReporter("cycle-collector"),
     mCollectionInProgress(false),
     mScanInProgress(false),
     mJSRuntime(nullptr),
     mThread(NS_GetCurrentThread()),
     mWhiteNodeCount(0),
     mBeforeUnlinkCB(nullptr),
     mForgetSkippableCB(nullptr),
+    mReporter(nullptr),
     mUnmergedNeeded(0),
     mMergedInARow(0)
 {
 }
 
 nsCycleCollector::~nsCycleCollector()
 {
-    UnregisterWeakMemoryReporter(this);
+    NS_UnregisterMemoryReporter(mReporter);
 }
 
 void
 nsCycleCollector::RegisterJSRuntime(CycleCollectedJSRuntime *aJSRuntime)
 {
     if (mJSRuntime)
         Fault("multiple registrations of cycle collector JS runtime", aJSRuntime);
 
     mJSRuntime = aJSRuntime;
 
-    // We can't register as a reporter in nsCycleCollector() because that runs
+    // We can't register the reporter in nsCycleCollector() because that runs
     // before the memory reporter manager is initialized.  So we do it here
     // instead.
     static bool registered = false;
     if (!registered) {
-        RegisterWeakMemoryReporter(this);
+        NS_RegisterMemoryReporter(new CycleCollectorReporter(this));
         registered = true;
     }
 }
 
 void
 nsCycleCollector::ForgetJSRuntime()
 {
     if (!mJSRuntime)
@@ -2843,17 +2850,17 @@ nsCycleCollector::Shutdown()
     if (PR_GetEnv("XPCOM_CC_RUN_DURING_SHUTDOWN"))
 #endif
     {
         ShutdownCollect();
     }
 }
 
 void
-nsCycleCollector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
+nsCycleCollector::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                                       size_t *aObjectSize,
                                       size_t *aGraphNodesSize,
                                       size_t *aGraphEdgesSize,
                                       size_t *aWeakMapsSize,
                                       size_t *aPurpleBufferSize) const
 {
     *aObjectSize = aMallocSizeOf(this);
 
@@ -3089,21 +3096,22 @@ void
 nsCycleCollector_startup()
 {
     MOZ_ASSERT(sCollectorData.initialized(),
                "Forgot to call nsCycleCollector_init!");
     if (sCollectorData.get()) {
         MOZ_CRASH();
     }
 
-    CollectorData* data = new CollectorData;
-    data->mCollector = new nsCycleCollector();
+    nsAutoPtr<nsCycleCollector> collector(new nsCycleCollector());
+    nsAutoPtr<CollectorData> data(new CollectorData);
     data->mRuntime = nullptr;
-
-    sCollectorData.set(data);
+    data->mCollector = collector.forget();
+
+    sCollectorData.set(data.forget());
 }
 
 void
 nsCycleCollector_setBeforeUnlinkCallback(CC_BeforeUnlinkCallback aCB)
 {
     CollectorData *data = sCollectorData.get();
 
     // We should have started the cycle collector by now.
@@ -3197,15 +3205,16 @@ void
 nsCycleCollector_shutdown()
 {
     CollectorData *data = sCollectorData.get();
 
     if (data) {
         MOZ_ASSERT(data->mCollector);
         PROFILER_LABEL("CC", "nsCycleCollector_shutdown");
         data->mCollector->Shutdown();
+        delete data->mCollector;
         data->mCollector = nullptr;
         if (!data->mRuntime) {
           delete data;
           sCollectorData.set(nullptr);
         }
     }
 }
--- a/xpcom/base/nsIMemoryReporter.idl
+++ b/xpcom/base/nsIMemoryReporter.idl
@@ -142,20 +142,27 @@ interface nsIMemoryReporterCallback : ns
  *   heap-level allocation (e.g. malloc/calloc/operator new).  Reporters
  *   in this tree must have kind HEAP or NONHEAP, units BYTES, and a
  *   description that is a sentence (i.e. starts with a capital letter and
  *   ends with a period, or similar).
  *
  * - All other reports are unconstrained except that they must have a
  *   description that is a sentence.
  */
-[scriptable, uuid(0884cd0f-5829-4381-979b-0f53904030ed)]
+[scriptable, uuid(53248304-124b-43cd-99dc-6e5797b91618)]
 interface nsIMemoryReporter : nsISupports
 {
   /*
+   * The name of the reporter.  Useful when only one reporter needs to be run.
+   * Must be unique;  if reporters share names it's likely the wrong one will
+   * be called in certain circumstances.
+   */
+  readonly attribute ACString name;
+
+  /*
    * Run the reporter.
    */
   void collectReports(in nsIMemoryReporterCallback callback,
                       in nsISupports data);
 
   /*
    * Kinds.  See the |kind| comment in nsIMemoryReporterCallback.
    */
@@ -173,51 +180,42 @@ interface nsIMemoryReporter : nsISupport
 };
 
 [scriptable, function, uuid(548b3909-c04d-4ca6-8466-b8bee3837457)]
 interface nsIFinishReportingCallback : nsISupports
 {
   void callback(in nsISupports data);
 };
 
-[scriptable, builtinclass, uuid(9245d89e-6523-45f9-bc15-a69789e33cbb)]
+[scriptable, builtinclass, uuid(41c667f4-16b3-424f-95d9-a6f903f72eb2)]
 interface nsIMemoryReporterManager : nsISupports
 {
   /*
    * Initialize.
    */
   void init();
 
   /*
    * Register the given nsIMemoryReporter.  After a reporter is registered,
    * it will be available via enumerateReporters().  The Manager service
-   * will hold a strong reference to the given reporter, and will be
-   * responsible for freeing the reporter at shutdown.
+   * will hold a strong reference to the given reporter.
    */
-  void registerStrongReporter(in nsIMemoryReporter reporter);
+  void registerReporter(in nsIMemoryReporter reporter);
 
   /*
-   * Like registerReporter, but the Manager service will hold a weak reference
-   * to the given reporter.  The reporter should be unregistered before
-   * shutdown.
+   * Unregister the given memory reporter.
    */
-  void registerWeakReporter(in nsIMemoryReporter reporter);
-
-  /*
-   * Unregister the given memory reporter, which must have been registered with
-   * registerWeakReporter().
-   */
-  void unregisterWeakReporter(in nsIMemoryReporter reporter);
+  void unregisterReporter(in nsIMemoryReporter reporter);
 
   /*
    * These functions should only be used for testing purposes.
    */
-  void blockRegistrationAndHideExistingReporters();
-  void unblockRegistrationAndRestoreOriginalReporters();
-  void registerStrongReporterEvenIfBlocked(in nsIMemoryReporter aReporter);
+  void blockRegistration();
+  void unblockRegistration();
+  void registerReporterEvenIfBlocked(in nsIMemoryReporter aReporter);
 
   /*
    * Return an enumerator of nsIMemoryReporters that are currently registered
    * in the current process.  WARNING: this does not do anything with child
    * processes.  Use getReports() if you want measurements from child
    * processes.
    */
   nsISimpleEnumerator enumerateReporters();
@@ -368,28 +366,24 @@ interface nsIMemoryReporterManager : nsI
 #include "nsTArray.h"
 
 class nsPIDOMWindow;
 
 // nsIHandleReportCallback is a better name, but keep nsIMemoryReporterCallback
 // around for backwards compatibility.
 typedef nsIMemoryReporterCallback nsIHandleReportCallback;
 
-namespace mozilla {
-
-// Register a memory reporter.  The manager service will hold a strong
-// reference to this reporter.
-XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter);
+// Note that the memory reporters are held in an nsCOMArray, which means
+// that individual reporters should be referenced with |nsIMemoryReporter *|
+// instead of nsCOMPtr<nsIMemoryReporter>.
 
-// Register a memory reporter.  The manager service will hold a weak reference
-// to this reporter.
-XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter);
+XPCOM_API(nsresult) NS_RegisterMemoryReporter(nsIMemoryReporter* aReporter);
+XPCOM_API(nsresult) NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter);
 
-// Unregister a weak memory reporter.
-XPCOM_API(nsresult) UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter);
+namespace mozilla {
 
 // The memory reporter manager provides access to several distinguished
 // amounts via attributes.  Some of these amounts are provided by Gecko
 // components that cannot be accessed directly from XPCOM code.  So we provide
 // the following functions for those components to be registered with the
 // manager.
 
 typedef int64_t (*InfallibleAmountFn)();
@@ -590,16 +584,22 @@ public:
   MemoryMultiReporter(const char* aName)
     : mName(aName)
   {}
 
   virtual ~MemoryMultiReporter() {}
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
+  NS_IMETHOD GetName(nsACString& aName)
+  {
+    aName.Assign(mName);
+    return NS_OK;
+  }
+
   NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
                             nsISupports* aClosure) = 0;
 
 protected:
   NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf)
   NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(MallocSizeOfOnAlloc)
   NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(MallocSizeOfOnFree)
 
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -708,17 +708,17 @@ private:
     int64_t Amount() MOZ_OVERRIDE { return HeapOverheadRatio(); }
 };
 #endif  // HAVE_JEMALLOC_STATS
 
 // Why is this here?  At first glance, you'd think it could be defined and
 // registered with nsMemoryReporterManager entirely within nsAtomTable.cpp.
 // However, the obvious time to register it is when the table is initialized,
 // and that happens before XPCOM components are initialized, which means the
-// RegisterStrongMemoryReporter call fails.  So instead we do it here.
+// NS_RegisterMemoryReporter call fails.  So instead we do it here.
 class AtomTablesReporter MOZ_FINAL : public MemoryUniReporter
 {
 public:
     AtomTablesReporter()
       : MemoryUniReporter("explicit/atom-tables", KIND_HEAP, UNITS_BYTES,
 "Memory used by the dynamic and static atoms tables.")
     {}
 private:
@@ -796,122 +796,108 @@ NS_IMETHODIMP
 nsMemoryReporterManager::Init()
 {
 #if defined(HAVE_JEMALLOC_STATS) && defined(XP_LINUX)
     if (!jemalloc_stats)
         return NS_ERROR_FAILURE;
 #endif
 
 #ifdef HAVE_JEMALLOC_STATS
-    RegisterStrongReporter(new HeapAllocatedReporter());
-    RegisterStrongReporter(new HeapOverheadWasteReporter());
-    RegisterStrongReporter(new HeapOverheadBookkeepingReporter());
-    RegisterStrongReporter(new HeapOverheadPageCacheReporter());
-    RegisterStrongReporter(new HeapCommittedReporter());
-    RegisterStrongReporter(new HeapOverheadRatioReporter());
+    RegisterReporter(new HeapAllocatedReporter);
+    RegisterReporter(new HeapOverheadWasteReporter);
+    RegisterReporter(new HeapOverheadBookkeepingReporter);
+    RegisterReporter(new HeapOverheadPageCacheReporter);
+    RegisterReporter(new HeapCommittedReporter);
+    RegisterReporter(new HeapOverheadRatioReporter);
 #endif
 
 #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS
-    RegisterStrongReporter(new VsizeReporter());
-    RegisterStrongReporter(new ResidentReporter());
+    RegisterReporter(new VsizeReporter);
+    RegisterReporter(new ResidentReporter);
 #endif
 
 #ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER
-    RegisterStrongReporter(new VsizeMaxContiguousReporter());
+    RegisterReporter(new VsizeMaxContiguousReporter);
 #endif
 
 #ifdef HAVE_RESIDENT_UNIQUE_REPORTER
-    RegisterStrongReporter(new ResidentUniqueReporter());
+    RegisterReporter(new ResidentUniqueReporter);
 #endif
 
 #ifdef HAVE_PAGE_FAULT_REPORTERS
-    RegisterStrongReporter(new PageFaultsSoftReporter());
-    RegisterStrongReporter(new PageFaultsHardReporter());
+    RegisterReporter(new PageFaultsSoftReporter);
+    RegisterReporter(new PageFaultsHardReporter);
 #endif
 
 #ifdef HAVE_PRIVATE_REPORTER
-    RegisterStrongReporter(new PrivateReporter());
+    RegisterReporter(new PrivateReporter);
 #endif
 
-    RegisterStrongReporter(new AtomTablesReporter());
+    RegisterReporter(new AtomTablesReporter);
 
 #ifdef MOZ_DMD
-    RegisterStrongReporter(new mozilla::dmd::DMDReporter());
+    RegisterReporter(new mozilla::dmd::DMDReporter);
 #endif
 
 #if defined(XP_LINUX)
     nsMemoryInfoDumper::Initialize();
 #endif
 
     return NS_OK;
 }
 
 namespace {
 
-// ReporterEnumerator takes the two hashtables of reporters in its constructor
-// and creates an nsISimpleEnumerator from its contents.
-//
-// The resultant enumerator works over a copy of the hashtable elements, so
-// it's safe to mutate or destroy the hashtables after the enumerator is
-// created.
-//
-class ReporterEnumerator MOZ_FINAL : public nsISimpleEnumerator
+/**
+ * HastableEnumerator takes an nsTHashtable<nsISupportsHashKey>& in its
+ * constructor and creates an nsISimpleEnumerator from its contents.
+ *
+ * The resultant enumerator works over a copy of the hashtable, so it's safe to
+ * mutate or destroy the hashtable after the enumerator is created.
+ */
+
+class HashtableEnumerator MOZ_FINAL : public nsISimpleEnumerator
 {
 public:
-    ReporterEnumerator(
-        nsMemoryReporterManager::StrongReportersTable* aStrongReporters,
-        nsMemoryReporterManager::WeakReportersTable* aWeakReporters)
-      : mIndex(0)
+    HashtableEnumerator(nsTHashtable<nsISupportsHashKey>& aHashtable)
+        : mIndex(0)
     {
-        aStrongReporters->EnumerateEntries(StrongEnumerator, this);
-        aWeakReporters->EnumerateEntries(WeakEnumerator, this);
+        aHashtable.EnumerateEntries(EnumeratorFunc, this);
     }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSISIMPLEENUMERATOR
 
 private:
     static PLDHashOperator
-    StrongEnumerator(nsISupportsHashKey* aEntry, void* aData);
-
-    static PLDHashOperator
-    WeakEnumerator(nsPtrHashKey<nsISupports>* aEntry, void* aData);
+    EnumeratorFunc(nsISupportsHashKey* aEntry, void* aData);
 
     uint32_t mIndex;
     nsCOMArray<nsISupports> mArray;
 };
 
-NS_IMPL_ISUPPORTS1(ReporterEnumerator, nsISimpleEnumerator)
+NS_IMPL_ISUPPORTS1(HashtableEnumerator, nsISimpleEnumerator)
 
 /* static */ PLDHashOperator
-ReporterEnumerator::StrongEnumerator(nsISupportsHashKey* aElem, void* aData)
+HashtableEnumerator::EnumeratorFunc(nsISupportsHashKey* aElem, void* aData)
 {
-    ReporterEnumerator* enumerator = static_cast<ReporterEnumerator*>(aData);
-    enumerator->mArray.AppendObject(aElem->GetKey());
-    return PL_DHASH_NEXT;
-}
-
-/* static */ PLDHashOperator
-ReporterEnumerator::WeakEnumerator(nsPtrHashKey<nsISupports>* aElem,
-                                   void* aData)
-{
-    ReporterEnumerator* enumerator = static_cast<ReporterEnumerator*>(aData);
+    HashtableEnumerator* enumerator = static_cast<HashtableEnumerator*>(aData);
     enumerator->mArray.AppendObject(aElem->GetKey());
     return PL_DHASH_NEXT;
 }
 
 NS_IMETHODIMP
-ReporterEnumerator::HasMoreElements(bool* aResult)
+HashtableEnumerator::HasMoreElements(bool* aResult)
 {
     *aResult = mIndex < mArray.Length();
     return NS_OK;
 }
 
 NS_IMETHODIMP
-ReporterEnumerator::GetNext(nsISupports** aNext)
+HashtableEnumerator::GetNext(nsISupports** aNext)
 {
     if (mIndex < mArray.Length()) {
         nsCOMPtr<nsISupports> next = mArray.ObjectAt(mIndex);
         next.forget(aNext);
         mIndex++;
         return NS_OK;
     }
 
@@ -919,47 +905,39 @@ ReporterEnumerator::GetNext(nsISupports*
     return NS_ERROR_FAILURE;
 }
 
 } // anonymous namespace
 
 nsMemoryReporterManager::nsMemoryReporterManager()
   : mMutex("nsMemoryReporterManager::mMutex"),
     mIsRegistrationBlocked(false),
-    mStrongReporters(new StrongReportersTable()),
-    mWeakReporters(new WeakReportersTable()),
-    mSavedStrongReporters(nullptr),
-    mSavedWeakReporters(nullptr),
     mNumChildProcesses(0),
     mNextGeneration(1),
     mGetReportsState(nullptr)
 {
 }
 
 nsMemoryReporterManager::~nsMemoryReporterManager()
 {
-    delete mStrongReporters;
-    delete mWeakReporters;
-    NS_ASSERTION(!mSavedStrongReporters, "failed to restore strong reporters");
-    NS_ASSERTION(!mSavedWeakReporters, "failed to restore weak reporters");
 }
 
 NS_IMETHODIMP
 nsMemoryReporterManager::EnumerateReporters(nsISimpleEnumerator** aResult)
 {
     // Memory reporters are not necessarily threadsafe, so this function must
     // be called from the main thread.
     if (!NS_IsMainThread()) {
         MOZ_CRASH();
     }
 
     mozilla::MutexAutoLock autoLock(mMutex);
 
-    nsRefPtr<ReporterEnumerator> enumerator =
-        new ReporterEnumerator(mStrongReporters, mWeakReporters);
+    nsRefPtr<HashtableEnumerator> enumerator =
+        new HashtableEnumerator(mReporters);
     enumerator.forget(aResult);
     return NS_OK;
 }
 
 //#define DEBUG_CHILD_PROCESS_MEMORY_REPORTING 1
 
 #ifdef DEBUG_CHILD_PROCESS_MEMORY_REPORTING
 #define MEMORY_REPORTING_LOG(format, ...) \
@@ -1042,19 +1020,22 @@ nsMemoryReporterManager::GetReports(
                                                mNumChildProcesses,
                                                aHandleReport,
                                                aHandleReportData,
                                                aFinishReporting,
                                                aFinishReportingData);
     }
 
     // Get reports for this process.
+    nsRefPtr<HashtableEnumerator> e;
+    {
+        mozilla::MutexAutoLock autoLock(mMutex);
+        e = new HashtableEnumerator(mReporters);
+    }
     bool more;
-    nsCOMPtr<nsISimpleEnumerator> e;
-    EnumerateReporters(getter_AddRefs(e));
     while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
         nsCOMPtr<nsIMemoryReporter> r;
         e->GetNext(getter_AddRefs(r));
         r->CollectReports(aHandleReport, aHandleReportData);
     }
 
     // If there are no child processes, we can finish up immediately.
     return (mNumChildProcesses == 0)
@@ -1166,142 +1147,104 @@ nsMemoryReporterManager::FinishReporting
     (void)mGetReportsState->mFinishReporting->Callback(
         mGetReportsState->mFinishReportingData);
 
     delete mGetReportsState;
     mGetReportsState = nullptr;
 }
 
 static void
-CrashIfRefcountIsZero(nsISupports* aObj)
+DebugAssertRefcountIsNonZero(nsISupports* aObj)
 {
+#ifdef DEBUG
     // This will probably crash if the object's refcount is 0.
     uint32_t refcnt = NS_ADDREF(aObj);
-    if (refcnt <= 1) {
-        MOZ_CRASH("CrashIfRefcountIsZero: refcount is zero");
-    }
+    MOZ_ASSERT(refcnt >= 2);
     NS_RELEASE(aObj);
+#endif
 }
 
 nsresult
 nsMemoryReporterManager::RegisterReporterHelper(
-    nsIMemoryReporter* aReporter, bool aForce, bool aStrong)
+    nsIMemoryReporter* aReporter, bool aForce)
 {
     // This method is thread-safe.
     mozilla::MutexAutoLock autoLock(mMutex);
 
-    if (mIsRegistrationBlocked && !aForce) {
-        return NS_ERROR_FAILURE;
-    }
-
-    if (mStrongReporters->Contains(aReporter) ||
-        mWeakReporters->Contains(aReporter))
-    {
+    if ((mIsRegistrationBlocked && !aForce) || mReporters.Contains(aReporter)) {
         return NS_ERROR_FAILURE;
     }
 
-    // If |aStrong| is true, |aReporter| may have a refcnt of 0, so we take
-    // a kung fu death grip before calling PutEntry.  Otherwise, if PutEntry
-    // addref'ed and released |aReporter| before finally addref'ing it for
-    // good, it would free aReporter!  The kung fu death grip could itself be
-    // problematic if PutEntry didn't addref |aReporter| (because then when the
-    // death grip goes out of scope, we would delete the reporter).  In debug
-    // mode, we check that this doesn't happen.
+    // This method needs to be safe even if |aReporter| has a refcnt of 0, so
+    // we take a kung fu death grip before calling PutEntry.  Otherwise, if
+    // PutEntry addref'ed and released |aReporter| before finally addref'ing it
+    // for good, it would free aReporter!
     //
-    // If |aStrong| is false, we require that |aReporter| have a non-zero
-    // refcnt.
-    //
-    if (aStrong) {
+    // The kung fu death grip could itself be problematic if PutEntry didn't
+    // addref |aReporter| (because then when the death grip goes out of scope,
+    // we would delete the reporter).  In debug mode, we check that this
+    // doesn't happen.
+
+    {
         nsCOMPtr<nsIMemoryReporter> kungFuDeathGrip = aReporter;
-        mStrongReporters->PutEntry(aReporter);
-        CrashIfRefcountIsZero(aReporter);
-    } else {
-        CrashIfRefcountIsZero(aReporter);
-        mWeakReporters->PutEntry(aReporter);
+        mReporters.PutEntry(aReporter);
     }
 
+    DebugAssertRefcountIsNonZero(aReporter);
+
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsMemoryReporterManager::RegisterStrongReporter(nsIMemoryReporter* aReporter)
+nsMemoryReporterManager::RegisterReporter(nsIMemoryReporter* aReporter)
 {
-    return RegisterReporterHelper(aReporter, /* force = */ false,
-                                  /* strong = */ true);
+    return RegisterReporterHelper(aReporter, /* force = */ false);
 }
 
 NS_IMETHODIMP
-nsMemoryReporterManager::RegisterWeakReporter(nsIMemoryReporter* aReporter)
+nsMemoryReporterManager::RegisterReporterEvenIfBlocked(
+    nsIMemoryReporter* aReporter)
 {
-    return RegisterReporterHelper(aReporter, /* force = */ false,
-                                  /* strong = */ false);
+    return RegisterReporterHelper(aReporter, /* force = */ true);
 }
 
 NS_IMETHODIMP
-nsMemoryReporterManager::RegisterStrongReporterEvenIfBlocked(
-    nsIMemoryReporter* aReporter)
-{
-    return RegisterReporterHelper(aReporter, /* force = */ true,
-                                  /* strong = */ true);
-}
-
-NS_IMETHODIMP
-nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter)
+nsMemoryReporterManager::UnregisterReporter(nsIMemoryReporter* aReporter)
 {
     // This method is thread-safe.
     mozilla::MutexAutoLock autoLock(mMutex);
 
-    MOZ_ASSERT(!mStrongReporters->Contains(aReporter));
-
-    if (mWeakReporters->Contains(aReporter)) {
-        mWeakReporters->RemoveEntry(aReporter);
-        return NS_OK;
+    if (!mReporters.Contains(aReporter)) {
+        return NS_ERROR_FAILURE;
     }
 
-    return NS_ERROR_FAILURE;
+    mReporters.RemoveEntry(aReporter);
+    return NS_OK;
 }
 
 NS_IMETHODIMP
-nsMemoryReporterManager::BlockRegistrationAndHideExistingReporters()
+nsMemoryReporterManager::BlockRegistration()
 {
     // This method is thread-safe.
     mozilla::MutexAutoLock autoLock(mMutex);
     if (mIsRegistrationBlocked) {
         return NS_ERROR_FAILURE;
     }
     mIsRegistrationBlocked = true;
-
-    // Hide the existing reporters, saving them for later restoration.
-    MOZ_ASSERT(!mSavedStrongReporters);
-    MOZ_ASSERT(!mSavedWeakReporters);
-    mSavedStrongReporters = mStrongReporters;
-    mSavedWeakReporters = mWeakReporters;
-    mStrongReporters = new StrongReportersTable();
-    mWeakReporters = new WeakReportersTable();
-
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsMemoryReporterManager::UnblockRegistrationAndRestoreOriginalReporters()
+nsMemoryReporterManager::UnblockRegistration()
 {
     // This method is thread-safe.
     mozilla::MutexAutoLock autoLock(mMutex);
     if (!mIsRegistrationBlocked) {
         return NS_ERROR_FAILURE;
     }
-
-    // Banish the current reporters, and restore the hidden ones.
-    delete mStrongReporters;
-    delete mWeakReporters;
-    mStrongReporters = mSavedStrongReporters;
-    mWeakReporters = mSavedWeakReporters;
-    mSavedStrongReporters = nullptr;
-    mSavedWeakReporters = nullptr;
-
     mIsRegistrationBlocked = false;
     return NS_OK;
 }
 
 // This is just a wrapper for int64_t that implements nsISupports, so it can be
 // passed to nsIMemoryReporter::CollectReports.
 class Int64Wrapper MOZ_FINAL : public nsISupports {
 public:
@@ -1673,47 +1616,37 @@ nsMemoryReporterManager::SizeOfTab(nsIDO
 }
 
 // Most memory reporters don't need thread safety, but some do.  Make them all
 // thread-safe just to be safe.  Memory reporters are created and destroyed
 // infrequently enough that the performance cost should be negligible.
 NS_IMPL_ISUPPORTS1(MemoryUniReporter, nsIMemoryReporter)
 NS_IMPL_ISUPPORTS1(MemoryMultiReporter, nsIMemoryReporter)
 
-namespace mozilla {
-
 nsresult
-RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter)
+NS_RegisterMemoryReporter(nsIMemoryReporter* aReporter)
 {
     nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
     if (!mgr) {
         return NS_ERROR_FAILURE;
     }
-    return mgr->RegisterStrongReporter(aReporter);
+    return mgr->RegisterReporter(aReporter);
 }
 
 nsresult
-RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter)
+NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter)
 {
     nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
     if (!mgr) {
         return NS_ERROR_FAILURE;
     }
-    return mgr->RegisterWeakReporter(aReporter);
+    return mgr->UnregisterReporter(aReporter);
 }
 
-nsresult
-UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter)
-{
-    nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
-    if (!mgr) {
-        return NS_ERROR_FAILURE;
-    }
-    return mgr->UnregisterWeakReporter(aReporter);
-}
+namespace mozilla {
 
 #define GET_MEMORY_REPORTER_MANAGER(mgr)                                      \
     nsRefPtr<nsMemoryReporterManager> mgr =                                   \
         nsMemoryReporterManager::GetOrCreate();                               \
     if (!mgr) {                                                               \
         return NS_ERROR_FAILURE;                                              \
     }
 
--- a/xpcom/base/nsMemoryReporterManager.h
+++ b/xpcom/base/nsMemoryReporterManager.h
@@ -31,19 +31,16 @@ public:
   // Gets the memory reporter manager service.
   static nsMemoryReporterManager* GetOrCreate()
   {
     nsCOMPtr<nsIMemoryReporterManager> imgr =
       do_GetService("@mozilla.org/memory-reporter-manager;1");
     return static_cast<nsMemoryReporterManager*>(imgr.get());
   }
 
-  typedef nsTHashtable<nsISupportsHashKey>         StrongReportersTable;
-  typedef nsTHashtable<nsPtrHashKey<nsISupports> > WeakReportersTable;
-
   void IncrementNumChildProcesses();
   void DecrementNumChildProcesses();
 
   // Inter-process memory reporting proceeds as follows.
   //
   // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER)
   //   synchronously gets memory reports for the current process, tells all
   //   child processes to get memory reports, and sets up some state
@@ -144,32 +141,25 @@ public:
     mozilla::JSSizeOfTabFn    mJS;
     mozilla::NonJSSizeOfTabFn mNonJS;
 
     SizeOfTabFns() { mozilla::PodZero(this); }
   };
   SizeOfTabFns mSizeOfTabFns;
 
 private:
-  nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter,
-                                  bool aForce, bool aStrongRef);
+  nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter, bool aForce);
 
   static void TimeoutCallback(nsITimer* aTimer, void* aData);
   static const uint32_t kTimeoutLengthMS = 5000;
 
+  nsTHashtable<nsISupportsHashKey> mReporters;
   Mutex mMutex;
   bool mIsRegistrationBlocked;
 
-  StrongReportersTable* mStrongReporters;
-  WeakReportersTable* mWeakReporters;
-
-  // These two are only used for testing purposes.
-  StrongReportersTable* mSavedStrongReporters;
-  WeakReportersTable* mSavedWeakReporters;
-
   uint32_t mNumChildProcesses;
   uint32_t mNextGeneration;
 
   struct GetReportsState {
     uint32_t                             mGeneration;
     nsCOMPtr<nsITimer>                   mTimer;
     uint32_t                             mNumChildProcesses;
     uint32_t                             mNumChildProcessesCompleted;
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -578,17 +578,17 @@ NS_InitXPCOM2(nsIServiceManager* *result
                                   nullptr,
                                   NS_XPCOM_STARTUP_OBSERVER_ID);
 #ifdef XP_WIN
     CreateAnonTempFileRemover();
 #endif
 
     // The memory reporter manager is up and running -- register a reporter for
     // ICU's memory usage.
-    RegisterStrongMemoryReporter(new ICUReporter());
+    NS_RegisterMemoryReporter(new ICUReporter());
 
     mozilla::Telemetry::Init();
 
     mozilla::HangMonitor::Startup();
     mozilla::BackgroundHangMonitor::Startup();
 
 #ifdef MOZ_VISUAL_EVENT_TRACER
     mozilla::eventtracer::Init();
--- a/xpcom/components/nsCategoryManager.cpp
+++ b/xpcom/components/nsCategoryManager.cpp
@@ -12,16 +12,17 @@
 #include "prio.h"
 #include "prprf.h"
 #include "prlock.h"
 #include "nsCOMPtr.h"
 #include "nsTHashtable.h"
 #include "nsClassHashtable.h"
 #include "nsIFactory.h"
 #include "nsIStringEnumerator.h"
+#include "nsIMemoryReporter.h"
 #include "nsSupportsPrimitives.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "nsQuickSort.h"
@@ -395,17 +396,32 @@ CategoryEnumerator::enumfunc_createenume
   return PL_DHASH_NEXT;
 }
 
 
 //
 // nsCategoryManager implementations
 //
 
-NS_IMPL_QUERY_INTERFACE_INHERITED1(nsCategoryManager, MemoryUniReporter, nsICategoryManager)
+NS_IMPL_QUERY_INTERFACE1(nsCategoryManager, nsICategoryManager)
+
+class XPCOMCategoryManagerReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+    XPCOMCategoryManagerReporter()
+      : MemoryUniReporter("explicit/xpcom/category-manager",
+                           KIND_HEAP, UNITS_BYTES,
+                           "Memory used for the XPCOM category manager.")
+    {}
+private:
+    int64_t Amount() MOZ_OVERRIDE
+    {
+        return nsCategoryManager::SizeOfIncludingThis(MallocSizeOf);
+    }
+};
 
 NS_IMETHODIMP_(nsrefcnt)
 nsCategoryManager::AddRef()
 {
   return 2;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
@@ -436,35 +452,34 @@ nsCategoryManager::Create(nsISupports* a
 {
   if (aOuter)
     return NS_ERROR_NO_AGGREGATION;
 
   return GetSingleton()->QueryInterface(aIID, aResult);
 }
 
 nsCategoryManager::nsCategoryManager()
-  : MemoryUniReporter("explicit/xpcom/category-manager",
-                       KIND_HEAP, UNITS_BYTES,
-                       "Memory used for the XPCOM category manager.")
-  , mLock("nsCategoryManager")
+  : mLock("nsCategoryManager")
   , mSuppressNotifications(false)
+  , mReporter(nullptr)
 {
   PL_INIT_ARENA_POOL(&mArena, "CategoryManagerArena",
                      NS_CATEGORYMANAGER_ARENA_SIZE);
 }
 
 void
 nsCategoryManager::InitMemoryReporter()
 {
-  RegisterWeakMemoryReporter(this);
+  mReporter = new XPCOMCategoryManagerReporter();
+  NS_RegisterMemoryReporter(mReporter);
 }
 
 nsCategoryManager::~nsCategoryManager()
 {
-  UnregisterWeakMemoryReporter(this);
+  NS_UnregisterMemoryReporter(mReporter);
 
   // the hashtable contains entries that must be deleted before the arena is
   // destroyed, or else you will have PRLocks undestroyed and other Really
   // Bad Stuff (TM)
   mTable.Clear();
 
   PL_FinishArenaPool(&mArena);
 }
@@ -473,35 +488,38 @@ inline CategoryNode*
 nsCategoryManager::get_category(const char* aName) {
   CategoryNode* node;
   if (!mTable.Get(aName, &node)) {
     return nullptr;
   }
   return node;
 }
 
-int64_t
-nsCategoryManager::Amount()
+/* static */ int64_t
+nsCategoryManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
 {
-    return SizeOfIncludingThis(MallocSizeOf);
+  return nsCategoryManager::gCategoryManager
+       ? nsCategoryManager::gCategoryManager->SizeOfIncludingThisHelper(
+          aMallocSizeOf)
+       : 0;
 }
 
 static size_t
 SizeOfCategoryManagerTableEntryExcludingThis(nsDepCharHashKey::KeyType aKey,
                                              const nsAutoPtr<CategoryNode> &aData,
                                              MallocSizeOf aMallocSizeOf,
                                              void* aUserArg)
 {
     // We don't measure the string pointed to by aKey because it's a non-owning
     // pointer.
     return aData.get()->SizeOfExcludingThis(aMallocSizeOf);
 }
 
 size_t
-nsCategoryManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+nsCategoryManager::SizeOfIncludingThisHelper(MallocSizeOf aMallocSizeOf)
 {
   size_t n = aMallocSizeOf(this);
 
   n += PL_SizeOfArenaPoolExcludingPool(&mArena, aMallocSizeOf);
 
   n += mTable.SizeOfExcludingThis(SizeOfCategoryManagerTableEntryExcludingThis,
                                   aMallocSizeOf);
 
@@ -560,19 +578,17 @@ nsCategoryManager::NotifyObservers( cons
       return;
 
     nsresult rv = entry->SetData(nsDependentCString(aEntryName));
     if (NS_FAILED(rv))
       return;
 
     r = new CategoryNotificationRunnable(entry, aTopic, aCategoryName);
   } else {
-    r = new CategoryNotificationRunnable(
-              NS_ISUPPORTS_CAST(nsICategoryManager*, this),
-              aTopic, aCategoryName);
+    r = new CategoryNotificationRunnable(this, aTopic, aCategoryName);
   }
 
   NS_DispatchToMainThread(r);
 }
 
 NS_IMETHODIMP
 nsCategoryManager::GetCategoryEntry( const char *aCategoryName,
                                      const char *aEntryName,
--- a/xpcom/components/nsCategoryManager.h
+++ b/xpcom/components/nsCategoryManager.h
@@ -6,17 +6,16 @@
 
 #ifndef NSCATEGORYMANAGER_H
 #define NSCATEGORYMANAGER_H
 
 #include "prio.h"
 #include "plarena.h"
 #include "nsClassHashtable.h"
 #include "nsICategoryManager.h"
-#include "nsIMemoryReporter.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Attributes.h"
 
 class nsIMemoryReporter;
 
 /* 16d222a6-1dd2-11b2-b693-f38b02c021b2 */
 #define NS_CATEGORYMANAGER_CID \
@@ -93,18 +92,17 @@ private:
 
 
 /**
  * The main implementation of nsICategoryManager.
  *
  * This implementation is thread-safe.
  */
 class nsCategoryManager MOZ_FINAL
-  : public mozilla::MemoryUniReporter
-  , public nsICategoryManager
+  : public nsICategoryManager
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICATEGORYMANAGER
 
   /**
    * Suppress or unsuppress notifications of category changes to the
    * observer service. This is to be used by nsComponentManagerImpl
@@ -119,30 +117,32 @@ public:
                         char** aOldValue = nullptr);
 
   static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
   void InitMemoryReporter();
 
   static nsCategoryManager* GetSingleton();
   static void Destroy();
 
-  int64_t Amount() MOZ_OVERRIDE;
+  static int64_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 private:
   static nsCategoryManager* gCategoryManager;
 
   nsCategoryManager();
   ~nsCategoryManager();
 
-  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
+  size_t SizeOfIncludingThisHelper(mozilla::MallocSizeOf aMallocSizeOf);
 
   CategoryNode* get_category(const char* aName);
   void NotifyObservers(const char* aTopic,
                        const char* aCategoryName, // must be a static string
                        const char* aEntryName);
 
   PLArenaPool mArena;
   nsClassHashtable<nsDepCharHashKey, CategoryNode> mTable;
   mozilla::Mutex mLock;
   bool mSuppressNotifications;
+
+  nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 #endif
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -35,16 +35,17 @@
 #include "nsDirectoryService.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsCategoryManager.h"
 #include "nsCategoryManagerUtils.h"
 #include "xptiprivate.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 #include "nsIConsoleService.h"
+#include "nsIMemoryReporter.h"
 #include "nsIObserverService.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIStringEnumerator.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIClassInfo.h"
 #include "nsLocalFile.h"
@@ -277,35 +278,50 @@ CloneAndAppend(nsIFile* aBase, const nsA
     f->AppendNative(append);
     return f.forget();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsComponentManagerImpl
 ////////////////////////////////////////////////////////////////////////////////
 
+class XPCOMComponentManagerReporter MOZ_FINAL : public MemoryUniReporter
+{
+public:
+    XPCOMComponentManagerReporter()
+      : MemoryUniReporter("explicit/xpcom/component-manager",
+                           KIND_HEAP, UNITS_BYTES,
+                           "Memory used for the XPCOM component manager.")
+    {}
+private:
+    int64_t Amount() MOZ_OVERRIDE
+    {
+        return nsComponentManagerImpl::gComponentManager
+             ? nsComponentManagerImpl::gComponentManager->SizeOfIncludingThis(
+                 MallocSizeOf)
+             : 0;
+    }
+};
+
 nsresult
 nsComponentManagerImpl::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
 {
     if (aOuter)
         return NS_ERROR_NO_AGGREGATION;
 
     if (!gComponentManager)
         return NS_ERROR_FAILURE;
 
     return gComponentManager->QueryInterface(aIID, aResult);
 }
 
 static const int CONTRACTID_HASHTABLE_INITIAL_SIZE = 2048;
 
 nsComponentManagerImpl::nsComponentManagerImpl()
-    : MemoryUniReporter("explicit/xpcom/component-manager",
-                        KIND_HEAP, UNITS_BYTES,
-                        "Memory used for the XPCOM component manager.")
-    , mFactories(CONTRACTID_HASHTABLE_INITIAL_SIZE)
+    : mFactories(CONTRACTID_HASHTABLE_INITIAL_SIZE)
     , mContractIDs(CONTRACTID_HASHTABLE_INITIAL_SIZE)
     , mLock("nsComponentManagerImpl.mLock")
     , mStatus(NOT_INITIALIZED)
 {
 }
 
 nsTArray<const mozilla::Module*>* nsComponentManagerImpl::sStaticModules;
 
@@ -393,17 +409,18 @@ nsresult nsComponentManagerImpl::Init()
         cl->type = NS_COMPONENT_LOCATION;
         cl->location.Init(greOmnijar, "chrome.manifest");
     }
 
     RereadChromeManifests(false);
 
     nsCategoryManager::GetSingleton()->SuppressNotifications(false);
 
-    RegisterWeakMemoryReporter(this);
+    mReporter = new XPCOMComponentManagerReporter();
+    NS_RegisterMemoryReporter(mReporter);
 
     // Unfortunately, we can't register the nsCategoryManager memory reporter
     // in its constructor (which is triggered by the GetSingleton() call
     // above) because the memory reporter manager isn't initialized at that
     // point.  So we wait until now.
     nsCategoryManager::GetSingleton()->InitMemoryReporter();
 
     mStatus = NORMAL;
@@ -778,17 +795,18 @@ nsresult nsComponentManagerImpl::Shutdow
 {
     PR_ASSERT(NORMAL == mStatus);
 
     mStatus = SHUTDOWN_IN_PROGRESS;
 
     // Shutdown the component manager
     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
 
-    UnregisterWeakMemoryReporter(this);
+    NS_UnregisterMemoryReporter(mReporter);
+    mReporter = nullptr;
 
     // Release all cached factories
     mContractIDs.Clear();
     mFactories.Clear(); // XXX release the objects, don't just clear
     mLoaderMap.Clear();
     mKnownModules.Clear();
     mKnownStaticModules.Clear();
 
@@ -813,24 +831,23 @@ nsComponentManagerImpl::~nsComponentMana
     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction."));
 
     if (SHUTDOWN_COMPLETE != mStatus)
         Shutdown();
 
     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed."));
 }
 
-NS_IMPL_ISUPPORTS_INHERITED5(
-    nsComponentManagerImpl,
-    MemoryUniReporter,
-    nsIComponentManager,
-    nsIServiceManager,
-    nsIComponentRegistrar,
-    nsISupportsWeakReference,
-    nsIInterfaceRequestor)
+NS_IMPL_ISUPPORTS5(nsComponentManagerImpl,
+                   nsIComponentManager,
+                   nsIServiceManager,
+                   nsIComponentRegistrar,
+                   nsISupportsWeakReference,
+                   nsIInterfaceRequestor)
+
 
 nsresult
 nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
 {
     NS_WARNING("This isn't supported");
     // fall through to QI as anything QIable is a superset of what can be
     // got via the GetInterface()
     return  QueryInterface(uuid, result);
@@ -1685,24 +1702,18 @@ SizeOfContractIDsEntryExcludingThis(nsCS
                                     MallocSizeOf aMallocSizeOf,
                                     void* aUserArg)
 {
     // We don't measure the nsFactoryEntry data because its owned by mFactories
     // (which measures them in SizeOfFactoriesEntryExcludingThis).
     return aKey.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
 }
 
-int64_t
-nsComponentManagerImpl::Amount()
-{
-    return SizeOfIncludingThis(MallocSizeOf);
-}
-
 size_t
-nsComponentManagerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+nsComponentManagerImpl::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
 {
     size_t n = aMallocSizeOf(this);
     n += mLoaderMap.SizeOfExcludingThis(nullptr, aMallocSizeOf);
     n += mFactories.SizeOfExcludingThis(SizeOfFactoriesEntryExcludingThis, aMallocSizeOf);
     n += mContractIDs.SizeOfExcludingThis(SizeOfContractIDsEntryExcludingThis, aMallocSizeOf);
 
     n += sStaticModules->SizeOfIncludingThis(aMallocSizeOf);
     n += sModuleLocations->SizeOfIncludingThis(aMallocSizeOf);
--- a/xpcom/components/nsComponentManager.h
+++ b/xpcom/components/nsComponentManager.h
@@ -6,17 +6,16 @@
 #ifndef nsComponentManager_h__
 #define nsComponentManager_h__
 
 #include "nsXPCOM.h"
 
 #include "xpcom-private.h"
 #include "nsIComponentManager.h"
 #include "nsIComponentRegistrar.h"
-#include "nsIMemoryReporter.h"
 #include "nsIServiceManager.h"
 #include "nsIFile.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Module.h"
 #include "mozilla/ModuleLoader.h"
 #include "mozilla/Mutex.h"
 #include "nsXULAppAPI.h"
 #include "nsNativeComponentLoader.h"
@@ -34,16 +33,17 @@
 #include "nsInterfaceHashtable.h"
 #include "nsClassHashtable.h"
 #include "nsTArray.h"
 
 #include "mozilla/Omnijar.h"
 #include "mozilla/Attributes.h"
 
 struct nsFactoryEntry;
+class nsIMemoryReporter;
 class nsIServiceManager;
 struct PRThread;
 
 #define NS_COMPONENTMANAGER_CID                      \
 { /* 91775d60-d5dc-11d2-92fb-00e09805570f */         \
     0x91775d60,                                      \
     0xd5dc,                                          \
     0x11d2,                                          \
@@ -114,18 +114,17 @@ private:
     mozilla::Mutex mMutex;
     volatile PRThread* mOwnerThread;
 };
 
 typedef mozilla::BaseAutoLock<SafeMutex> SafeMutexAutoLock;
 typedef mozilla::BaseAutoUnlock<SafeMutex> SafeMutexAutoUnlock;
 
 class nsComponentManagerImpl MOZ_FINAL
-    : public mozilla::MemoryUniReporter
-    , public nsIComponentManager
+    : public nsIComponentManager
     , public nsIServiceManager
     , public nsSupportsWeakReference
     , public nsIComponentRegistrar
     , public nsIInterfaceRequestor
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIINTERFACEREQUESTOR
@@ -308,21 +307,22 @@ public:
 
     inline PendingServiceInfo* AddPendingService(const nsCID& aServiceCID,
                                                  PRThread* aThread);
     inline void RemovePendingService(const nsCID& aServiceCID);
     inline PRThread* GetPendingServiceThread(const nsCID& aServiceCID) const;
 
     nsTArray<PendingServiceInfo> mPendingServices;
 
-    int64_t Amount() MOZ_OVERRIDE;
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
 private:
     ~nsComponentManagerImpl();
+
+    nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 
 #define NS_MAX_FILENAME_LEN     1024
 
 #define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24)
 
 struct nsFactoryEntry
--- a/xpcom/ds/nsObserverList.h
+++ b/xpcom/ds/nsObserverList.h
@@ -41,17 +41,17 @@ struct ObserverRef
     return static_cast<nsIWeakReference*>((nsISupports*) ref);
   }
 
   bool operator==(nsISupports* b) const { return ref == b; }
 };
 
 class nsObserverList : public nsCharPtrHashKey
 {
-  friend class nsObserverService;
+  friend class mozilla::ObserverServiceReporter;
 
 public:
   nsObserverList(const char *key) : nsCharPtrHashKey(key)
   { MOZ_COUNT_CTOR(nsObserverList); }
 
   ~nsObserverList() { MOZ_COUNT_DTOR(nsObserverList); }
 
   nsresult AddObserver(nsIObserver* anObserver, bool ownsWeak);
--- a/xpcom/ds/nsObserverService.cpp
+++ b/xpcom/ds/nsObserverService.cpp
@@ -6,16 +6,17 @@
 #include "prlog.h"
 #include "nsAutoPtr.h"
 #include "nsIObserverService.h"
 #include "nsIObserver.h"
 #include "nsObserverService.h"
 #include "nsObserverList.h"
 #include "nsThreadUtils.h"
 #include "nsEnumeratorUtils.h"
+#include "nsIMemoryReporter.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/Services.h"
 
 #define NOTIFY_GLOBAL_OBSERVERS
 
 #if defined(PR_LOGGING)
 // Log module for nsObserverService logging...
 //
@@ -36,39 +37,51 @@ GetObserverServiceLog()
 }
   #define LOG(x)  PR_LOG(GetObserverServiceLog(), PR_LOG_DEBUG, x)
 #else
   #define LOG(x)
 #endif /* PR_LOGGING */
 
 namespace mozilla {
 
+class ObserverServiceReporter MOZ_FINAL : public MemoryMultiReporter
+{
+public:
+    ObserverServiceReporter()
+        : MemoryMultiReporter("observer-service")
+    {}
+
+    NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb,
+                              nsISupports *aClosure);
+
+protected:
+    static const size_t kSuspectReferentCount = 100;
+    static PLDHashOperator CountReferents(nsObserverList* aObserverList,
+                                          void* aClosure);
+};
+
 struct SuspectObserver {
     SuspectObserver(const char* aTopic, size_t aReferentCount)
         : topic(aTopic), referentCount(aReferentCount) {}
     const char* topic;
     size_t referentCount;
 };
 
 struct ObserverServiceReferentCount {
     ObserverServiceReferentCount()
         : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
     size_t numStrong;
     size_t numWeakAlive;
     size_t numWeakDead;
     nsTArray<SuspectObserver> suspectObservers;
 };
 
-} // namespace mozilla
-
-using namespace mozilla;
-
 PLDHashOperator
-nsObserverService::CountReferents(nsObserverList* aObserverList,
-                                  void* aClosure)
+ObserverServiceReporter::CountReferents(nsObserverList* aObserverList,
+                                        void* aClosure)
 {
     if (!aObserverList) {
         return PL_DHASH_NEXT;
     }
 
     ObserverServiceReferentCount* referentCount =
         static_cast<ObserverServiceReferentCount*>(aClosure);
 
@@ -102,104 +115,122 @@ nsObserverService::CountReferents(nsObse
         SuspectObserver suspect(aObserverList->GetKey(), total);
         referentCount->suspectObservers.AppendElement(suspect);
     }
 
     return PL_DHASH_NEXT;
 }
 
 NS_IMETHODIMP
-nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
-                                  nsISupports* aData)
+ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb,
+                                        nsISupports* aClosure)
 {
+    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+    nsObserverService* service = static_cast<nsObserverService*>(os.get());
+    if (!service) {
+        return NS_OK;
+    }
+
     ObserverServiceReferentCount referentCount;
-    mObserverTopicTable.EnumerateEntries(CountReferents, &referentCount);
+    service->mObserverTopicTable.EnumerateEntries(CountReferents,
+                                                  &referentCount);
 
     nsresult rv;
     for (uint32_t i = 0; i < referentCount.suspectObservers.Length(); i++) {
         SuspectObserver& suspect = referentCount.suspectObservers[i];
         nsPrintfCString suspectPath("observer-service-suspect/"
                                     "referent(topic=%s)",
                                     suspect.topic);
-        rv = aHandleReport->Callback(/* process */ EmptyCString(),
-            suspectPath, KIND_OTHER, UNITS_COUNT, suspect.referentCount,
+        rv = cb->Callback(/* process */ EmptyCString(),
+            suspectPath,
+            nsIMemoryReporter::KIND_OTHER,
+            nsIMemoryReporter::UNITS_COUNT,
+            suspect.referentCount,
             NS_LITERAL_CSTRING("A topic with a suspiciously large number of "
                                "referents.  This may be symptomatic of a leak "
                                "if the number of referents is high with "
                                "respect to the number of windows."),
-            aData);
+            aClosure);
 
       if (NS_WARN_IF(NS_FAILED(rv)))
           return rv;
     }
 
-    rv = aHandleReport->Callback(/* process */ EmptyCString(),
+    rv = cb->Callback(/* process */ EmptyCString(),
         NS_LITERAL_CSTRING("observer-service/referent/strong"),
-        KIND_OTHER, UNITS_COUNT, referentCount.numStrong,
+        nsIMemoryReporter::KIND_OTHER,
+        nsIMemoryReporter::UNITS_COUNT,
+        referentCount.numStrong,
         NS_LITERAL_CSTRING("The number of strong references held by the "
                            "observer service."),
-        aData);
+        aClosure);
 
     if (NS_WARN_IF(NS_FAILED(rv)))
         return rv;
 
-    rv = aHandleReport->Callback(/* process */ EmptyCString(),
+    rv = cb->Callback(/* process */ EmptyCString(),
         NS_LITERAL_CSTRING("observer-service/referent/weak/alive"),
-        KIND_OTHER, UNITS_COUNT, referentCount.numWeakAlive,
+        nsIMemoryReporter::KIND_OTHER,
+        nsIMemoryReporter::UNITS_COUNT,
+        referentCount.numWeakAlive,
         NS_LITERAL_CSTRING("The number of weak references held by the "
                            "observer service that are still alive."),
-        aData);
+        aClosure);
 
     if (NS_WARN_IF(NS_FAILED(rv)))
         return rv;
 
-    rv = aHandleReport->Callback(/* process */ EmptyCString(),
+    rv = cb->Callback(/* process */ EmptyCString(),
         NS_LITERAL_CSTRING("observer-service/referent/weak/dead"),
-        KIND_OTHER, UNITS_COUNT, referentCount.numWeakDead,
+        nsIMemoryReporter::KIND_OTHER,
+        nsIMemoryReporter::UNITS_COUNT,
+        referentCount.numWeakDead,
         NS_LITERAL_CSTRING("The number of weak references held by the "
                            "observer service that are dead."),
-        aData);
+        aClosure);
 
     if (NS_WARN_IF(NS_FAILED(rv)))
         return rv;
 
     return NS_OK;
 }
 
+} // namespace mozilla
+
+using namespace mozilla;
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsObserverService Implementation
 
 
-NS_IMPL_ISUPPORTS_INHERITED2(
-    nsObserverService,
-    MemoryMultiReporter,
-    nsIObserverService,
-    nsObserverService)
+NS_IMPL_ISUPPORTS2(nsObserverService, nsIObserverService, nsObserverService)
 
 nsObserverService::nsObserverService() :
-    MemoryMultiReporter("observer-service"),
-    mShuttingDown(false)
+    mShuttingDown(false), mReporter(nullptr)
 {
 }
 
 nsObserverService::~nsObserverService(void)
 {
     Shutdown();
 }
 
 void
 nsObserverService::RegisterReporter()
 {
-    RegisterWeakMemoryReporter(this);
+    mReporter = new ObserverServiceReporter();
+    NS_RegisterMemoryReporter(mReporter);
 }
 
 void
 nsObserverService::Shutdown()
 {
-    UnregisterWeakMemoryReporter(this);
+    if (mReporter) {
+        NS_UnregisterMemoryReporter(mReporter);
+    }
 
     mShuttingDown = true;
 
     mObserverTopicTable.Clear();
 }
 
 nsresult
 nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
--- a/xpcom/ds/nsObserverService.h
+++ b/xpcom/ds/nsObserverService.h
@@ -3,30 +3,32 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsObserverService_h___
 #define nsObserverService_h___
 
 #include "nsIObserverService.h"
 #include "nsObserverList.h"
-#include "nsIMemoryReporter.h"
 #include "nsTHashtable.h"
 #include "mozilla/Attributes.h"
 
 // {D07F5195-E3D1-11d2-8ACD-00105A1B8860}
 #define NS_OBSERVERSERVICE_CID \
     { 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } }
 
 class nsIMemoryReporter;
 
-class nsObserverService MOZ_FINAL
-  : public mozilla::MemoryMultiReporter
-  , public nsIObserverService
-{
+namespace mozilla {
+class ObserverServiceReporter;
+} // namespace mozilla
+
+class nsObserverService MOZ_FINAL : public nsIObserverService {
+  friend class mozilla::ObserverServiceReporter;
+
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_OBSERVERSERVICE_CID)
 
   nsObserverService();
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVERSERVICE
   
@@ -34,25 +36,20 @@ public:
 
   static nsresult
   Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
 
   // Unmark any strongly held observers implemented in JS so the cycle
   // collector will not traverse them.
   NS_IMETHOD UnmarkGrayStrongObservers();
 
-  NS_IMETHOD CollectReports(nsIHandleReportCallback *aHandleReport,
-                            nsISupports *aData);
-
 private:
   ~nsObserverService(void);
   void RegisterReporter();
 
-  static const size_t kSuspectReferentCount = 100;
-  static PLDHashOperator CountReferents(nsObserverList* aObserverList,
-                                        void* aClosure);
   bool mShuttingDown;
   nsTHashtable<nsObserverList> mObserverTopicTable;
+  nsCOMPtr<nsIMemoryReporter> mReporter;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsObserverService, NS_OBSERVERSERVICE_CID)
 
 #endif /* nsObserverService_h___ */
--- a/xpcom/reflect/xptinfo/public/XPTInterfaceInfoManager.h
+++ b/xpcom/reflect/xptinfo/public/XPTInterfaceInfoManager.h
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_XPTInterfaceInfoManager_h_
 #define mozilla_XPTInterfaceInfoManager_h_
 
 #include "nsIInterfaceInfoManager.h"
-#include "nsIMemoryReporter.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "nsDataHashtable.h"
 
 template<typename T> class nsCOMArray;
 class nsIMemoryReporter;
@@ -21,18 +20,17 @@ class XPTHeader;
 class XPTInterfaceDirectoryEntry;
 class xptiInterfaceEntry;
 class xptiInterfaceInfo;
 class xptiTypelibGuts;
 
 namespace mozilla {
 
 class XPTInterfaceInfoManager MOZ_FINAL
-    : public mozilla::MemoryUniReporter
-    , public nsIInterfaceInfoManager
+    : public nsIInterfaceInfoManager
 {
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIINTERFACEINFOMANAGER
 
 public:
     // GetSingleton() is infallible
     static XPTInterfaceInfoManager* GetSingleton();
     static void FreeInterfaceInfoManager();
@@ -44,26 +42,25 @@ public:
     static Mutex& GetResolveLock()
     {
         return GetSingleton()->mResolveLock;
     }
 
     xptiInterfaceEntry* GetInterfaceEntryForIID(const nsIID *iid);
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
-    int64_t Amount() MOZ_OVERRIDE;
+
+    static int64_t GetXPTIWorkingSetSize();
 
 private:
     XPTInterfaceInfoManager();
     ~XPTInterfaceInfoManager();
 
-    void InitMemoryReporter();
-
     void RegisterXPTHeader(XPTHeader* aHeader);
-
+                          
     // idx is the index of this interface in the XPTHeader
     void VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* iface,
                                 uint16_t idx,
                                 xptiTypelibGuts* typelib);
 
 private:
 
     class xptiWorkingSet
@@ -107,13 +104,15 @@ private:
 
     // XXX xptiInterfaceInfo want's to poke at the working set itself
     friend class ::xptiInterfaceInfo;
     friend class ::xptiInterfaceEntry;
     friend class ::xptiTypelibGuts;
 
     xptiWorkingSet               mWorkingSet;
     Mutex                        mResolveLock;
+
+    nsCOMPtr<nsIMemoryReporter>  mReporter;
 };
 
 }
 
 #endif
--- a/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
+++ b/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp
@@ -1,112 +1,112 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Implementation of xptiInterfaceInfoManager. */
 
+#include "mozilla/MemoryReporting.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 
-#include "mozilla/FileUtils.h"
-#include "mozilla/MemoryReporting.h"
-#include "mozilla/StaticPtr.h"
-
 #include "xptiprivate.h"
 #include "nsDependentString.h"
 #include "nsString.h"
 #include "nsISupportsArray.h"
 #include "nsArrayEnumerator.h"
 #include "nsDirectoryService.h"
+#include "mozilla/FileUtils.h"
 #include "nsIMemoryReporter.h"
 
 using namespace mozilla;
 
-NS_IMPL_ISUPPORTS_INHERITED1(
-  XPTInterfaceInfoManager,
-  MemoryUniReporter,
-  nsIInterfaceInfoManager)
+NS_IMPL_ISUPPORTS1(XPTInterfaceInfoManager,
+                   nsIInterfaceInfoManager)
 
-static StaticRefPtr<XPTInterfaceInfoManager> gInterfaceInfoManager;
+static XPTInterfaceInfoManager* gInterfaceInfoManager = nullptr;
 #ifdef DEBUG
 static int gCallCount = 0;
 #endif
 
 size_t
-XPTInterfaceInfoManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
+XPTInterfaceInfoManager::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
 {
     size_t n = aMallocSizeOf(this);
     ReentrantMonitorAutoEnter monitor(mWorkingSet.mTableReentrantMonitor);
     // The entries themselves are allocated out of an arena accounted
     // for elsewhere, so don't measure them
     n += mWorkingSet.mIIDTable.SizeOfExcludingThis(nullptr, aMallocSizeOf);
     n += mWorkingSet.mNameTable.SizeOfExcludingThis(nullptr, aMallocSizeOf);
     return n;
 }
 
-int64_t
-XPTInterfaceInfoManager::Amount()
+class XPTIWorkingSetReporter MOZ_FINAL : public MemoryUniReporter
 {
-    size_t n = SizeOfIncludingThis(MallocSizeOf);
+public:
+    XPTIWorkingSetReporter()
+      : MemoryUniReporter("explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES,
+                           "Memory used by the XPCOM typelib system.")
+    {}
+private:
+    int64_t Amount() MOZ_OVERRIDE
+    {
+        size_t n = gInterfaceInfoManager
+                 ? gInterfaceInfoManager->SizeOfIncludingThis(MallocSizeOf)
+                 : 0;
 
-    // Measure gXPTIStructArena here, too.  This is a bit grotty because it
-    // doesn't belong to the XPTIInterfaceInfoManager, but there's no
-    // obviously better place to measure it.
-    n += XPT_SizeOfArena(gXPTIStructArena, MallocSizeOf);
+        // Measure gXPTIStructArena here, too.  This is a bit grotty because it
+        // doesn't belong to the xptiInterfaceInfoManager, but there's no
+        // obviously better place to measure it.
+        n += XPT_SizeOfArena(gXPTIStructArena, MallocSizeOf);
 
-    return n;
-}
+        return n;
+    }
+};
 
 // static
 XPTInterfaceInfoManager*
 XPTInterfaceInfoManager::GetSingleton()
 {
     if (!gInterfaceInfoManager) {
         gInterfaceInfoManager = new XPTInterfaceInfoManager();
-        gInterfaceInfoManager->InitMemoryReporter();
+        NS_ADDREF(gInterfaceInfoManager);
     }
     return gInterfaceInfoManager;
 }
 
 void
 XPTInterfaceInfoManager::FreeInterfaceInfoManager()
 {
-    gInterfaceInfoManager = nullptr;
+    NS_IF_RELEASE(gInterfaceInfoManager);
 }
 
 XPTInterfaceInfoManager::XPTInterfaceInfoManager()
-    :   MemoryUniReporter("explicit/xpti-working-set", KIND_HEAP, UNITS_BYTES,
-                          "Memory used by the XPCOM typelib system."),
-        mWorkingSet(),
+    :   mWorkingSet(),
         mResolveLock("XPTInterfaceInfoManager.mResolveLock")
 {
+    mReporter = new XPTIWorkingSetReporter();
+    NS_RegisterMemoryReporter(mReporter);
 }
 
 XPTInterfaceInfoManager::~XPTInterfaceInfoManager()
 {
     // We only do this on shutdown of the service.
     mWorkingSet.InvalidateInterfaceInfos();
 
-    UnregisterWeakMemoryReporter(this);
+    NS_UnregisterMemoryReporter(mReporter);
 
     gInterfaceInfoManager = nullptr;
 #ifdef DEBUG
     gCallCount = 0;
 #endif
 }
 
 void
-XPTInterfaceInfoManager::InitMemoryReporter()
-{
-    RegisterWeakMemoryReporter(this);
-}
-
-void
 XPTInterfaceInfoManager::RegisterBuffer(char *buf, uint32_t length)
 {
     XPTState *state = XPT_NewXDRState(XPT_DECODE, buf, length);
     if (!state)
         return;
 
     XPTCursor cursor;
     if (!XPT_MakeCursor(state, XPT_HEADER, 0, &cursor)) {