Bug 633305 - about:memory should display memory reporters that live in the child process r=cjones a=blocking-fennec
authorDoug Turner <dougt@dougt.org>
Wed, 16 Feb 2011 10:43:23 -0800
changeset 63194 410519307e63e2e48b6c6d646fc8bf3750aa65f5
parent 63193 621f7ea2a6f494ffb92f3ce34f24a4f6cc5bb2e2
child 63195 d34e0e81327a059a1bb6773522bb1d13ef517a37
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerscjones, blocking-fennec
bugs633305
milestone2.0b13pre
Bug 633305 - about:memory should display memory reporters that live in the child process r=cjones a=blocking-fennec
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/ipc/PMemoryReportRequest.ipdl
dom/ipc/ipdl.mk
toolkit/components/aboutmemory/content/aboutMemory.js
toolkit/components/aboutmemory/content/aboutMemory.xhtml
xpcom/base/nsMemoryReporterManager.cpp
xpcom/base/nsMemoryReporterManager.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -54,17 +54,17 @@
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 #include "mozilla/jsipc/PContextWrapperChild.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/StorageChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
 
 #include "nsAudioStream.h"
-
+#include "nsIMemoryReporter.h"
 #include "nsIObserverService.h"
 #include "nsTObserverArray.h"
 #include "nsIObserver.h"
 #include "nsIPrefService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsWeakReference.h"
 #include "nsIScriptError.h"
@@ -77,35 +77,59 @@
 #include "base/message_loop.h"
 #include "base/task.h"
 
 #include "nsChromeRegistryContent.h"
 #include "mozilla/chrome/RegistryMessageUtils.h"
 #include "nsFrameMessageManager.h"
 
 #include "nsIGeolocationProvider.h"
+#include "mozilla/dom/PMemoryReportRequestChild.h"
 
 #ifdef MOZ_PERMISSIONS
 #include "nsPermission.h"
 #include "nsPermissionManager.h"
 #endif
 
 #include "nsAccelerometer.h"
 
 #if defined(ANDROID)
 #include "APKOpen.h"
 #endif
 
+#ifdef XP_WIN
+#include <process.h>
+#define getpid _getpid
+#endif
+
 using namespace mozilla::ipc;
 using namespace mozilla::net;
 using namespace mozilla::places;
 using namespace mozilla::docshell;
 
 namespace mozilla {
 namespace dom {
+
+class MemoryReportRequestChild : public PMemoryReportRequestChild
+{
+public:
+    MemoryReportRequestChild();
+    virtual ~MemoryReportRequestChild();
+};
+
+MemoryReportRequestChild::MemoryReportRequestChild()
+{
+    MOZ_COUNT_CTOR(MemoryReportRequestChild);
+}
+
+MemoryReportRequestChild::~MemoryReportRequestChild()
+{
+    MOZ_COUNT_DTOR(MemoryReportRequestChild);
+}
+
 class AlertObserver
 {
 public:
 
     AlertObserver(nsIObserver *aObserver, const nsString& aData)
         : mObserver(aObserver)
         , mData(aData)
     {
@@ -255,16 +279,63 @@ ContentChild::InitXPCOM()
         return;
     }
 
     mConsoleListener = new ConsoleListener(this);
     if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
         NS_WARNING("Couldn't register console listener for child process");
 }
 
+PMemoryReportRequestChild*
+ContentChild::AllocPMemoryReportRequest()
+{
+    return new MemoryReportRequestChild();
+}
+
+bool
+ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child)
+{
+    InfallibleTArray<MemoryReport> reports;
+    
+    nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
+    nsCOMPtr<nsISimpleEnumerator> r;
+    mgr->EnumerateReporters(getter_AddRefs(r));
+
+    PRBool more;
+    while (NS_SUCCEEDED(r->HasMoreElements(&more)) && more) {
+      nsCOMPtr<nsIMemoryReporter> report;
+      r->GetNext(getter_AddRefs(report));
+
+      nsCString path;
+      nsCString desc;
+      PRInt64 memoryUsed;
+      report->GetPath(getter_Copies(path));
+      report->GetDescription(getter_Copies(desc));
+      report->GetMemoryUsed(&memoryUsed);
+
+      MemoryReport memreport(nsPrintfCString("Content Process - %d - ", getpid()),
+                             path,
+                             desc,
+                             memoryUsed);
+
+      reports.AppendElement(memreport);
+
+    }
+
+    child->Send__delete__(child, reports);
+    return true;
+}
+
+bool
+ContentChild::DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor)
+{
+    delete actor;
+    return true;
+}
+
 PBrowserChild*
 ContentChild::AllocPBrowser(const PRUint32& aChromeFlags)
 {
     nsRefPtr<TabChild> iframe = new TabChild(aChromeFlags);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget().get() : NULL;
 }
 
 bool
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -78,16 +78,25 @@ public:
     virtual bool RecvDummy(Shmem& foo) { return true; }
 
     virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags);
     virtual bool DeallocPBrowser(PBrowserChild*);
 
     virtual PCrashReporterChild* AllocPCrashReporter();
     virtual bool DeallocPCrashReporter(PCrashReporterChild*);
 
+    virtual PMemoryReportRequestChild*
+    AllocPMemoryReportRequest();
+
+    virtual bool
+    DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor);
+
+    virtual bool
+    RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child);
+
     virtual PTestShellChild* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellChild*);
     virtual bool RecvPTestShellConstructor(PTestShellChild*);
 
     virtual PAudioChild* AllocPAudio(const PRInt32&,
                                      const PRInt32&,
                                      const PRInt32&);
     virtual bool DeallocPAudio(PAudioChild*);
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -83,16 +83,20 @@
 #include "nsICrashReporter.h"
 #include "nsExceptionHandler.h"
 #endif
 
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "mozilla/dom/StorageParent.h"
 #include "nsAccelerometer.h"
 
+#include "nsIMemoryReporter.h"
+#include "nsMemoryReporterManager.h"
+#include "mozilla/dom/PMemoryReportRequestParent.h"
+
 #ifdef ANDROID
 #include "gfxAndroidPlatform.h"
 #endif
 
 #include "nsIClipboard.h"
 #include "nsWidgetsCID.h"
 #include "nsISupportsPrimitives.h"
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
@@ -104,16 +108,48 @@ using namespace mozilla::places;
 using mozilla::MonitorAutoEnter;
 using base::KillProcess;
 
 namespace mozilla {
 namespace dom {
 
 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
 
+class MemoryReportRequestParent : public PMemoryReportRequestParent
+{
+public:
+    MemoryReportRequestParent();
+    virtual ~MemoryReportRequestParent();
+
+    virtual bool    Recv__delete__(const InfallibleTArray<MemoryReport>& report);
+private:
+    ContentParent* Owner()
+    {
+        return static_cast<ContentParent*>(Manager());
+    }
+};
+    
+
+MemoryReportRequestParent::MemoryReportRequestParent()
+{
+    MOZ_COUNT_CTOR(MemoryReportRequestParent);
+}
+
+bool
+MemoryReportRequestParent::Recv__delete__(const InfallibleTArray<MemoryReport>& report)
+{
+    Owner()->SetChildMemoryReporters(report);
+    return true;
+}
+
+MemoryReportRequestParent::~MemoryReportRequestParent()
+{
+    MOZ_COUNT_DTOR(MemoryReportRequestParent);
+}
+
 ContentParent* ContentParent::gSingleton;
 
 ContentParent*
 ContentParent::GetSingleton(PRBool aForceNew)
 {
     if (gSingleton && !gSingleton->IsAlive())
         gSingleton = nsnull;
     
@@ -130,16 +166,17 @@ ContentParent::GetSingleton(PRBool aForc
                         (do_GetService(NS_PREFSERVICE_CONTRACTID));
                     if (prefs) {  
                         prefs->AddObserver("", parent, PR_FALSE);
                     }
                 }
                 obs->AddObserver(
                   parent, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, PR_FALSE);
 
+                obs->AddObserver(parent, "child-memory-reporter-request", PR_FALSE);
                 obs->AddObserver(parent, "memory-pressure", PR_FALSE); 
             }
             nsCOMPtr<nsIThreadInternal>
                 threadInt(do_QueryInterface(NS_GetCurrentThread()));
             if (threadInt) {
                 threadInt->GetObserver(getter_AddRefs(parent->mOldObserver));
                 threadInt->SetObserver(parent);
             }
@@ -198,20 +235,24 @@ ContentParent::ActorDestroy(ActorDestroy
 {
     nsCOMPtr<nsIThreadObserver>
         kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
     nsCOMPtr<nsIObserverService>
         obs(do_GetService("@mozilla.org/observer-service;1"));
     if (obs) {
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "xpcom-shutdown");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "memory-pressure");
-        obs->RemoveObserver(static_cast<nsIObserver*>(this),
-                           NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC);
+        obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-memory-reporter-request");
+        obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC);
     }
 
+    // clear the child memory reporters
+    InfallibleTArray<MemoryReport> empty;
+    SetChildMemoryReporters(empty);
+
     // remove the global remote preferences observers
     nsCOMPtr<nsIPrefBranch2> prefs 
             (do_GetService(NS_PREFSERVICE_CONTRACTID));
     if (prefs) { 
         prefs->RemoveObserver("", this);
     }
 
     RecvRemoveGeolocationListener();
@@ -543,16 +584,20 @@ ContentParent::Observe(nsISupports* aSub
     }
     // listening for alert notifications
     else if (!strcmp(aTopic, "alertfinished") ||
              !strcmp(aTopic, "alertclickcallback") ) {
         if (!SendNotifyAlertsObserver(nsDependentCString(aTopic),
                                       nsDependentString(aData)))
             return NS_ERROR_NOT_AVAILABLE;
     }
+    else if (!strcmp(aTopic, "child-memory-reporter-request")) {
+        SendPMemoryReportRequestConstructor();
+    }
+
     return NS_OK;
 }
 
 PBrowserParent*
 ContentParent::AllocPBrowser(const PRUint32& aChromeFlags)
 {
   TabParent* parent = new TabParent();
   if (parent){
@@ -577,16 +622,58 @@ ContentParent::AllocPCrashReporter()
 
 bool
 ContentParent::DeallocPCrashReporter(PCrashReporterParent* crashreporter)
 {
   delete crashreporter;
   return true;
 }
 
+PMemoryReportRequestParent*
+ContentParent::AllocPMemoryReportRequest()
+{
+  MemoryReportRequestParent* parent = new MemoryReportRequestParent();
+  return parent;
+}
+
+bool
+ContentParent::DeallocPMemoryReportRequest(PMemoryReportRequestParent* actor)
+{
+  delete actor;
+  return true;
+}
+
+void
+ContentParent::SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report)
+{
+    nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
+    for (PRUint32 i = 0; i < mMemoryReporters.Count(); i++)
+        mgr->UnregisterReporter(mMemoryReporters[i]);
+
+    for (PRUint32 i = 0; i < report.Length(); i++) {
+
+        nsCString prefix = report[i].prefix();
+        nsCString path   = report[i].path();
+        nsCString desc   = report[i].desc();
+        PRInt64 memoryUsed = report[i].memoryUsed();
+        
+        nsRefPtr<nsMemoryReporter> r = new nsMemoryReporter(prefix,
+                                                            path,
+                                                            desc,
+                                                            memoryUsed);
+      mMemoryReporters.AppendObject(r);
+      mgr->RegisterReporter(r);
+    }
+
+    nsCOMPtr<nsIObserverService> obs =
+        do_GetService("@mozilla.org/observer-service;1");
+    if (obs)
+        obs->NotifyObservers(nsnull, "child-memory-reporter-update", nsnull);
+}
+
 PTestShellParent*
 ContentParent::AllocPTestShell()
 {
   return new TestShellParent();
 }
 
 bool
 ContentParent::DeallocPTestShell(PTestShellParent* shell)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -37,26 +37,29 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_ContentParent_h
 #define mozilla_dom_ContentParent_h
 
 #include "base/waitable_event_watcher.h"
 
 #include "mozilla/dom/PContentParent.h"
+#include "mozilla/dom/PMemoryReportRequestParent.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 
 #include "nsIObserver.h"
 #include "nsIThreadInternal.h"
 #include "mozilla/Monitor.h"
 #include "nsNetUtil.h"
 #include "nsIPrefService.h"
 #include "nsIPermissionManager.h"
 #include "nsIDOMGeoPositionCallback.h"
 #include "nsIAccelerometer.h"
+#include "nsIMemoryReporter.h"
+#include "nsCOMArray.h"
 
 namespace mozilla {
 
 namespace ipc {
 class TestShellParent;
 }
 
 namespace dom {
@@ -93,16 +96,18 @@ public:
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
 
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
 
+    void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
+
 protected:
     void OnChannelConnected(int32 pid);
     virtual void ActorDestroy(ActorDestroyReason why);
 
 private:
     static ContentParent* gSingleton;
 
     // Hide the raw constructor methods since we don't want client code
@@ -114,16 +119,19 @@ private:
     virtual ~ContentParent();
 
     virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags);
     virtual bool DeallocPBrowser(PBrowserParent* frame);
 
     virtual PCrashReporterParent* AllocPCrashReporter();
     virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
 
+    virtual PMemoryReportRequestParent* AllocPMemoryReportRequest();
+    virtual bool DeallocPMemoryReportRequest(PMemoryReportRequestParent* actor);
+
     virtual PTestShellParent* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellParent* shell);
 
     virtual PAudioParent* AllocPAudio(const PRInt32&,
                                      const PRInt32&,
                                      const PRInt32&);
     virtual bool DeallocPAudio(PAudioParent*);
 
@@ -201,16 +209,22 @@ private:
 
     GeckoChildProcessHost* mSubprocess;
 
     PRInt32 mGeolocationWatchID;
     int mRunToCompletionDepth;
     bool mShouldCallUnblockChild;
     nsCOMPtr<nsIThreadObserver> mOldObserver;
 
+    // This is a cache of all of the memory reporters
+    // registered in the child process.  To update this, one
+    // can broadcast the topic "child-memory-reporter-request" using
+    // the nsIObserverService.
+    nsCOMArray<nsIMemoryReporter> mMemoryReporters;
+
     bool mIsAlive;
     nsCOMPtr<nsIPrefServiceInternal> mPrefService;
     time_t mProcessStartTime;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -38,16 +38,17 @@
 
 include protocol PAudio;
 include protocol PBrowser;
 include protocol PCrashReporter;
 include protocol PTestShell;
 include protocol PNecko;
 include protocol PExternalHelperApp;
 include protocol PStorage;
+include protocol PMemoryReportRequest;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
 
 include "nsGeoPositionIPCSerialiser.h";
 include "PPrefTuple.h";
 
 using GeoPosition;
@@ -91,20 +92,23 @@ rpc protocol PContent
 {
     manages PAudio;
     manages PBrowser;
     manages PCrashReporter;
     manages PTestShell;
     manages PNecko;
     manages PExternalHelperApp;
     manages PStorage;
+    manages PMemoryReportRequest;
 
 child:
     PBrowser(PRUint32 chromeFlags);
 
+    PMemoryReportRequest();
+
     PTestShell();
 
     RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
                    OverrideMapping[] overrides, nsCString locale);
 
     async SetOffline(PRBool offline);
 
     async NotifyVisited(URI uri);
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PMemoryReportRequest.ipdl
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Memory Reporting IPC
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+include protocol PContent;
+
+namespace mozilla {
+namespace dom {
+
+struct MemoryReport {
+  nsCString prefix;
+  nsCString path;
+  nsCString desc;
+  PRInt64 memoryUsed;
+};
+
+protocol PMemoryReportRequest {
+  manager PContent;
+
+  parent:
+    __delete__(MemoryReport[] report);
+};
+
+}
+}
--- a/dom/ipc/ipdl.mk
+++ b/dom/ipc/ipdl.mk
@@ -37,9 +37,10 @@
 IPDLSRCS = \
   PAudio.ipdl \
   PBrowser.ipdl \
   PContent.ipdl \
   PContentDialog.ipdl \
   PCrashReporter.ipdl \
   PDocumentRenderer.ipdl \
   PContentPermissionRequest.ipdl \
+  PMemoryReportRequest.ipdl \
   $(NULL)
--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -134,38 +134,64 @@ function updateMemoryStatus()
         $("memOverview").style.display = "none";
     }
 
     var mo = $("memOtherRows");
     while (mo.lastChild)
         mo.removeChild(mo.lastChild);
 
     var otherCount = 0;
+
     for each (var rep in gMemReporters) {
         var row = makeTableRow([rep.path, rep.description],
                                makeTableCell(formatNumber(rep.memoryUsed), "memValue"));
 
         mo.appendChild(row);
 
         otherCount++;
     }
 
     if (otherCount == 0) {
         var row = makeTableRow("No other information available.");
         mo.appendChild(row);
     }
 }
 
-function doLoad()
+function updateMemoryReporters()
 {
+    gMemReporters = [];
+
     var mgr = Components
         .classes["@mozilla.org/memory-reporter-manager;1"]
         .getService(Components.interfaces.nsIMemoryReporterManager);
 
     var e = mgr.enumerateReporters();
     while (e.hasMoreElements()) {
         var mr = e.getNext().QueryInterface(Components.interfaces.nsIMemoryReporter);
         gMemReporters[mr.path] = mr;
     }
+}
 
+function ChildMemoryListener(subject, topic, data) {
+  updateMemoryReporters();
+  updateMemoryStatus();
+}
+
+
+function doLoad()
+{
+    var os = Components.classes["@mozilla.org/observer-service;1"].
+        getService(Components.interfaces.nsIObserverService);
+    os.notifyObservers(null, "child-memory-reporter-request", null);
+
+    os.addObserver(ChildMemoryListener, "child-memory-reporter-update", false);
+
+    updateMemoryReporters();
     updateMemoryStatus();
 }
 
+function doUnload()
+{
+    var os = Components.classes["@mozilla.org/observer-service;1"].
+        getService(Components.interfaces.nsIObserverService);
+    os.removeObserver(ChildMemoryListener, "child-memory-reporter-update");
+    
+}
--- a/toolkit/components/aboutmemory/content/aboutMemory.xhtml
+++ b/toolkit/components/aboutmemory/content/aboutMemory.xhtml
@@ -43,17 +43,17 @@
 
     <link rel="stylesheet" href="chrome://global/skin/aboutMemory.css"
           type="text/css"/>
 
     <script type="text/javascript"
             src="chrome://global/content/aboutMemory.js"/>
   </head>
 
-  <body onload="doLoad()">
+  <body onload="doLoad()" onunload="doUnload()">
     <h1>Memory Usage</h1>
 
     <div id="memOverview" class="memOverview memBox">
       <h2>Overview</h2>
       <table border="0">
 	<tbody>
 	  <tr>
             <td width="100%">Memory mapped:</td>
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -283,16 +283,55 @@ nsMemoryReporterManager::UnregisterRepor
 {
     mozilla::MutexAutoLock autoLock(mMutex); 
     if (!mReporters.RemoveObject(reporter))
         return NS_ERROR_FAILURE;
 
     return NS_OK;
 }
 
+NS_IMPL_ISUPPORTS1(nsMemoryReporter, nsIMemoryReporter)
+
+nsMemoryReporter::nsMemoryReporter(nsCString& prefix,
+                                   nsCString& path,
+                                   nsCString& desc,
+                                   PRInt64 memoryUsed)
+: mDesc(desc)
+, mMemoryUsed(memoryUsed) 
+{
+  if (!prefix.IsEmpty()) {
+    mPath.Append(prefix);
+    mPath.Append(NS_LITERAL_CSTRING(" - "));
+  }
+  mPath.Append(path);
+}
+
+nsMemoryReporter::~nsMemoryReporter()
+{
+}
+
+NS_IMETHODIMP nsMemoryReporter::GetPath(char **aPath)
+{
+  *aPath = strdup(mPath.get());
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMemoryReporter::GetDescription(char **aDescription)
+{
+  *aDescription = strdup(mDesc.get());
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsMemoryReporter::GetMemoryUsed(PRInt64 *aMemoryUsed)
+{
+  *aMemoryUsed = mMemoryUsed;
+  return NS_OK;
+}
+
+
 NS_COM nsresult
 NS_RegisterMemoryReporter (nsIMemoryReporter *reporter)
 {
     nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
     if (mgr == nsnull)
         return NS_ERROR_FAILURE;
     return mgr->RegisterReporter(reporter);
 }
--- a/xpcom/base/nsMemoryReporterManager.h
+++ b/xpcom/base/nsMemoryReporterManager.h
@@ -1,15 +1,34 @@
 
 #include "nsIMemoryReporter.h"
 #include "nsCOMArray.h"
 #include "mozilla/Mutex.h"
 
 using mozilla::Mutex;
 
+class nsMemoryReporter : public nsIMemoryReporter
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMEMORYREPORTER
+
+  nsMemoryReporter(nsCString& prefix,
+                   nsCString& path, 
+                   nsCString& desc,
+                   PRInt64 memoryUsed);
+
+  ~nsMemoryReporter();
+
+protected:
+  nsCString mPath, mDesc;
+  PRInt64 mMemoryUsed;
+};
+
+
 class nsMemoryReporterManager : public nsIMemoryReporterManager
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIMEMORYREPORTERMANAGER
 
     nsMemoryReporterManager();
     virtual ~nsMemoryReporterManager();