Back out bug 738011, bug 738624, and bug 737857 because of WinXP debug reftest log errors
authorMatt Brubeck <mbrubeck@mozilla.com>
Mon, 02 Apr 2012 12:44:31 -0700
changeset 90865 61aa02b5a7a11f80fd68ff114fb75f1067468812
parent 90864 3c1d6080a98f082afb0369318192aef7bf1e5ed3
child 90866 7da9ecd5424fb77cc57bea68a4725c9bc856f0ab
push id22394
push userMs2ger@gmail.com
push dateTue, 03 Apr 2012 07:22:53 +0000
treeherdermozilla-central@9894cd999781 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs738011, 738624, 737857
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Back out bug 738011, bug 738624, and bug 737857 because of WinXP debug reftest log errors
dom/base/nsWindowMemoryReporter.cpp
dom/base/nsWindowMemoryReporter.h
js/xpconnect/src/XPCJSRuntime.cpp
modules/libpref/src/init/all.js
toolkit/components/aboutmemory/content/aboutMemory.js
toolkit/components/aboutmemory/tests/test_aboutcompartments.xul
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/telemetry/TelemetryPing.js
xpcom/base/nsIMemoryReporter.idl
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -32,140 +32,132 @@
  * 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 "nsWindowMemoryReporter.h"
 #include "nsGlobalWindow.h"
-#include "nsIEffectiveTLDService.h"
-#include "mozilla/Services.h"
-#include "mozilla/Preferences.h"
-#include "nsNetCID.h"
-#include "nsPrintfCString.h"
 
-using namespace mozilla;
 
 nsWindowMemoryReporter::nsWindowMemoryReporter()
-  : mCheckForGhostWindowsCallbackPending(false)
 {
-  mDetachedWindows.Init();
 }
 
-NS_IMPL_ISUPPORTS3(nsWindowMemoryReporter, nsIMemoryMultiReporter, nsIObserver,
-                   nsSupportsWeakReference)
+NS_IMPL_ISUPPORTS1(nsWindowMemoryReporter, nsIMemoryMultiReporter)
 
 /* static */
 void
 nsWindowMemoryReporter::Init()
 {
-  // The memory reporter manager will own this object.
-  nsWindowMemoryReporter *windowReporter = new nsWindowMemoryReporter();
-  NS_RegisterMemoryMultiReporter(windowReporter);
-
-  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 NULL.
-    os->AddObserver(windowReporter, DOM_WINDOW_DESTROYED_TOPIC,
-                    /* weakRef = */ true);
-    os->AddObserver(windowReporter, "after-minimize-memory-usage",
-                    /* weakRef = */ true);
-  }
-
-  GhostURLsReporter *ghostMultiReporter =
-    new GhostURLsReporter(windowReporter);
-  NS_RegisterMemoryMultiReporter(ghostMultiReporter);
-
-  NumGhostsReporter *ghostReporter =
-    new NumGhostsReporter(windowReporter);
-  NS_RegisterMemoryReporter(ghostReporter);
+  // The memory reporter manager is going to own this object.
+  NS_RegisterMemoryMultiReporter(new nsWindowMemoryReporter());
 }
 
-static already_AddRefed<nsIURI>
-GetWindowURI(nsIDOMWindow *aWindow)
+static void
+AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
 {
-  nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(aWindow);
-  NS_ENSURE_TRUE(pWindow, NULL);
-
-  nsCOMPtr<nsIDocument> doc = do_QueryInterface(pWindow->GetExtantDocument());
+  nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
   nsCOMPtr<nsIURI> uri;
 
   if (doc) {
     uri = doc->GetDocumentURI();
   }
 
   if (!uri) {
-    nsCOMPtr<nsIScriptObjectPrincipal> scriptObjPrincipal =
-      do_QueryInterface(aWindow);
-    NS_ENSURE_TRUE(scriptObjPrincipal, NULL);
-
-    nsIPrincipal *principal = scriptObjPrincipal->GetPrincipal();
+    nsIPrincipal *principal = aWindow->GetPrincipal();
 
     if (principal) {
       principal->GetURI(getter_AddRefs(uri));
     }
   }
 
-  return uri.forget();
-}
-
-static void
-AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr)
-{
-  nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow);
-
   if (uri) {
     nsCString spec;
     uri->GetSpec(spec);
 
     // A hack: replace forward slashes with '\\' so they aren't
     // treated as path separators.  Users of the reporters
     // (such as about:memory) have to undo this change.
     spec.ReplaceChar('/', '\\');
 
     aStr += spec;
   } else {
-    // If we're unable to find a URI, we're dealing with a chrome window with
-    // no document in it (or somesuch), so we call this a "system window".
     aStr += NS_LITERAL_CSTRING("[system]");
   }
 }
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMStyleMallocSizeOf, "windows")
 
 static nsresult
 CollectWindowReports(nsGlobalWindow *aWindow,
                      nsWindowSizes *aWindowTotalSizes,
-                     nsTHashtable<nsUint64HashKey> *aGhostWindowIDs,
                      nsIMemoryMultiReporterCallback *aCb,
                      nsISupports *aClosure)
 {
+  // DOM window objects fall into one of three categories:
+  // - "active" windows are currently either displayed in an active
+  //   tab, or a child of such a window.
+  // - "cached" windows are in the fastback cache.
+  // - "other" windows are closed (or navigated away from w/o being
+  //   cached) yet held alive by either a website or our code. The
+  //   latter case may be a memory leak, but not necessarily.
+  //
+  // For each window we show how much memory the window and its
+  // document, etc, use, and we report those per URI, where the URI is
+  // the document URI, if available, or the codebase of the principal in
+  // the window. In the case where we're unable to find a URI we're
+  // dealing with a chrome window with no document in it (or somesuch),
+  // and for that we make the URI be the string "[system]".
+  //
+  // Outer windows are lumped in with inner windows, because the amount
+  // of memory used by outer windows is small.
+  //
+  // The path we give to the reporter callback for "active" and "cached"
+  // windows (both inner and outer) is as follows:
+  //
+  //   explicit/window-objects/top(<top-outer-uri>, id=<top-outer-id>)/<category>/window(<window-uri>)/...
+  //
+  // The path we give for "other" windows is as follows:
+  //
+  //   explicit/window-objects/top(none)/window(<window-uri>)/...
+  //
+  // Where:
+  // - <category> is "active" or "cached", as described above.
+  // - <top-outer-id> is the window id (nsPIDOMWindow::WindowID()) of
+  //   the top outer window (i.e. tab, or top level chrome window).
+  // - <top-inner-uri> is the URI of the top outer window.  Excepting
+  //   special windows (such as browser.xul or hiddenWindow.html) it's
+  //   what the address bar shows for the tab.
+  // - <window-uri> is the URI of aWindow.
+  //
+  // Exposing the top-outer-id ensures that each tab gets its own
+  // sub-tree, even if multiple tabs are showing the same URI.
+
   nsCAutoString windowPath("explicit/window-objects/");
 
-  // Our window should have a null top iff it has a null docshell.
-  MOZ_ASSERT(!!aWindow->GetTop() == !!aWindow->GetDocShell());
-
   nsGlobalWindow *top = aWindow->GetTop();
+  windowPath += NS_LITERAL_CSTRING("top(");
   if (top) {
-    windowPath += NS_LITERAL_CSTRING("top(");
     AppendWindowURI(top, windowPath);
     windowPath += NS_LITERAL_CSTRING(", id=");
     windowPath.AppendInt(top->WindowID());
-    windowPath += NS_LITERAL_CSTRING(")/");
+  } else {
+    windowPath += NS_LITERAL_CSTRING("none");
+  }
+  windowPath += NS_LITERAL_CSTRING(")/");
 
+  nsIDocShell *docShell = aWindow->GetDocShell();
+  if (docShell) {
+    MOZ_ASSERT(top, "'cached' or 'active' window lacks a top window");
     windowPath += aWindow->IsFrozen() ? NS_LITERAL_CSTRING("cached/")
                                       : NS_LITERAL_CSTRING("active/");
   } else {
-    if (aGhostWindowIDs->Contains(aWindow->WindowID())) {
-      windowPath += NS_LITERAL_CSTRING("top(none)/ghost/");
-    } else {
-      windowPath += NS_LITERAL_CSTRING("top(none)/detached/");
-    }
+    MOZ_ASSERT(!top, "'other' window has a top window");
   }
 
   windowPath += NS_LITERAL_CSTRING("window(");
   AppendWindowURI(aWindow, windowPath);
   windowPath += NS_LITERAL_CSTRING(")");
 
 #define REPORT(_pathTail, _amount, _desc)                                     \
   do {                                                                        \
@@ -236,30 +228,22 @@ nsWindowMemoryReporter::CollectReports(n
     nsGlobalWindow::GetWindowsTable();
   NS_ENSURE_TRUE(windowsById, NS_OK);
 
   // Hold on to every window in memory so that window objects can't be
   // destroyed while we're calling the memory reporter callback.
   WindowArray windows;
   windowsById->Enumerate(GetWindows, &windows);
 
-  // Get the IDs of all the "ghost" windows.
-  nsTHashtable<nsUint64HashKey> ghostWindows;
-  ghostWindows.Init();
-  CheckForGhostWindows(&ghostWindows);
-
-  nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(
-    NS_EFFECTIVETLDSERVICE_CONTRACTID);
-  NS_ENSURE_STATE(tldService);
-
   // Collect window memory usage.
+  nsRefPtr<nsGlobalWindow> *w = windows.Elements();
+  nsRefPtr<nsGlobalWindow> *end = w + windows.Length();
   nsWindowSizes windowTotalSizes(NULL);
-  for (PRUint32 i = 0; i < windows.Length(); i++) {
-    nsresult rv = CollectWindowReports(windows[i], &windowTotalSizes,
-                                       &ghostWindows, aCb, aClosure);
+  for (; w != end; ++w) {
+    nsresult rv = CollectWindowReports(*w, &windowTotalSizes, aCb, aClosure);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
 #define REPORT(_path, _amount, _desc)                                         \
   do {                                                                        \
     nsresult rv;                                                              \
     rv = aCb->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path),             \
                        nsIMemoryReporter::KIND_OTHER,                         \
@@ -297,396 +281,9 @@ nsWindowMemoryReporter::CollectReports(n
 NS_IMETHODIMP
 nsWindowMemoryReporter::GetExplicitNonHeap(PRInt64* aAmount)
 {
   // This reporter only measures heap memory.
   *aAmount = 0;
   return NS_OK;
 }
 
-PRUint32
-nsWindowMemoryReporter::GetGhostTimeout()
-{
-  return Preferences::GetUint("memory.ghost_window_timeout_seconds", 60);
-}
 
-NS_IMETHODIMP
-nsWindowMemoryReporter::Observe(nsISupports *aSubject, const char *aTopic,
-                                const PRUnichar *aData)
-{
-  if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC)) {
-    ObserveDOMWindowDetached(aSubject);
-  } else if (!strcmp(aTopic, "after-minimize-memory-usage")) {
-    ObserveAfterMinimizeMemoryUsage();
-  } else {
-    MOZ_ASSERT(false);
-  }
-
-  return NS_OK;
-}
-
-void
-nsWindowMemoryReporter::ObserveDOMWindowDetached(nsISupports* aWindow)
-{
-  nsWeakPtr weakWindow = do_GetWeakReference(aWindow);
-  if (!weakWindow) {
-    NS_WARNING("Couldn't take weak reference to a window?");
-    return;
-  }
-
-  mDetachedWindows.Put(weakWindow, TimeStamp());
-
-  if (!mCheckForGhostWindowsCallbackPending) {
-    nsCOMPtr<nsIRunnable> runnable =
-      NS_NewRunnableMethod(this,
-                           &nsWindowMemoryReporter::CheckForGhostWindowsCallback);
-    NS_DispatchToCurrentThread(runnable);
-    mCheckForGhostWindowsCallbackPending = true;
-  }
-}
-
-static PLDHashOperator
-BackdateTimeStampsEnumerator(nsISupports *aKey, TimeStamp &aTimeStamp,
-                             void* aClosure)
-{
-  TimeStamp *minTimeStamp = static_cast<TimeStamp*>(aClosure);
-  
-  if (!aTimeStamp.IsNull() && aTimeStamp > *minTimeStamp) {
-    aTimeStamp = *minTimeStamp;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-void
-nsWindowMemoryReporter::ObserveAfterMinimizeMemoryUsage()
-{
-  // Someone claims they've done enough GC/CCs so that all eligible windows
-  // have been free'd.  So we deem that any windows which satisfy ghost
-  // criteria (1) and (2) now satisfy criterion (3) as well.
-  //
-  // To effect this change, we'll backdate some of our timestamps.
-
-  TimeStamp minTimeStamp = TimeStamp::Now() -
-                           TimeDuration::FromSeconds(GetGhostTimeout());
-
-  mDetachedWindows.Enumerate(BackdateTimeStampsEnumerator,
-                             &minTimeStamp);
-}
-
-void
-nsWindowMemoryReporter::CheckForGhostWindowsCallback()
-{
-  mCheckForGhostWindowsCallbackPending = false;
-  CheckForGhostWindows();
-}
-
-struct CheckForGhostWindowsEnumeratorData
-{
-  nsTHashtable<nsCStringHashKey> *nonDetachedDomains;
-  nsTHashtable<nsUint64HashKey> *ghostWindowIDs;
-  nsIEffectiveTLDService *tldService;
-  PRUint32 ghostTimeout;
-  TimeStamp now;
-};
-
-static PLDHashOperator
-CheckForGhostWindowsEnumerator(nsISupports *aKey, TimeStamp& aTimeStamp,
-                               void* aClosure)
-{
-  CheckForGhostWindowsEnumeratorData *data =
-    static_cast<CheckForGhostWindowsEnumeratorData*>(aClosure);
-
-  nsWeakPtr weakKey = do_QueryInterface(aKey);
-  nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(weakKey);
-  if (!window) {
-    // The window object has been destroyed.  Stop tracking its weak ref in our
-    // hashtable.
-    return PL_DHASH_REMOVE;
-  }
-
-  nsCOMPtr<nsIDOMWindow> top;
-  window->GetTop(getter_AddRefs(top));
-  if (top) {
-    // The window is no longer detached, so we no longer want to track it.
-    return PL_DHASH_REMOVE;
-  }
-
-  nsCOMPtr<nsIURI> uri = GetWindowURI(window);
-
-  nsCAutoString domain;
-  if (uri) {
-    // GetBaseDomain works fine if |uri| is null, but it outputs a warning
-    // which ends up overrunning the mochitest logs.
-    data->tldService->GetBaseDomain(uri, 0, domain);
-  }
-
-  if (data->nonDetachedDomains->Contains(domain)) {
-    // This window shares a domain with a non-detached window, so reset its
-    // clock.
-    aTimeStamp = TimeStamp();
-  } else {
-    // This window does not share a domain with a non-detached window, so it
-    // meets ghost criterion (2).
-    if (aTimeStamp.IsNull()) {
-      // This may become a ghost window later; start its clock.
-      aTimeStamp = data->now;
-    } else if ((data->now - aTimeStamp).ToSeconds() > data->ghostTimeout) {
-      // This definitely is a ghost window, so add it to ghostWindowIDs, if
-      // that is not null.
-      if (data->ghostWindowIDs) {
-        nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(window);
-        if (pWindow) {
-          data->ghostWindowIDs->PutEntry(pWindow->WindowID());
-        }
-      }
-    }
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-struct GetNonDetachedWindowDomainsEnumeratorData
-{
-  nsTHashtable<nsCStringHashKey> *nonDetachedDomains;
-  nsIEffectiveTLDService *tldService;
-};
-
-static PLDHashOperator
-GetNonDetachedWindowDomainsEnumerator(const PRUint64& aId, nsGlobalWindow* aWindow,
-                                      void* aClosure)
-{
-  GetNonDetachedWindowDomainsEnumeratorData *data =
-    static_cast<GetNonDetachedWindowDomainsEnumeratorData*>(aClosure);
-
-  if (!aWindow->GetTop()) {
-    // This window is detached, so we don't care about its domain.
-    return PL_DHASH_NEXT;
-  }
-
-  nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow);
-
-  nsCAutoString domain;
-  if (uri) {
-    data->tldService->GetBaseDomain(uri, 0, domain);
-  }
-
-  data->nonDetachedDomains->PutEntry(domain);
-  return PL_DHASH_NEXT;
-}
-
-/**
- * Iterate over mDetachedWindows and update it to reflect the current state of
- * the world.  In particular:
- *
- *   - Remove weak refs to windows which no longer exist.
- *
- *   - Remove references to windows which are no longer detached.
- *
- *   - Reset the timestamp on detached windows which share a domain with a
- *     non-detached window (they no longer meet ghost criterion (2)).
- *
- *   - If a window now meets ghost criterion (2) but didn't before, set its
- *     timestamp to now.
- *
- * Additionally, if aOutGhostIDs is not null, fill it with the window IDs of
- * all ghost windows we found.
- */
-void
-nsWindowMemoryReporter::CheckForGhostWindows(
-  nsTHashtable<nsUint64HashKey> *aOutGhostIDs /* = NULL */)
-{
-  nsCOMPtr<nsIEffectiveTLDService> tldService = do_GetService(
-    NS_EFFECTIVETLDSERVICE_CONTRACTID);
-  if (!tldService) {
-    NS_WARNING("Couldn't get TLDService.");
-    return;
-  }
-
-  nsGlobalWindow::WindowByIdTable *windowsById =
-    nsGlobalWindow::GetWindowsTable();
-  if (!windowsById) {
-    NS_WARNING("GetWindowsTable returned null");
-    return;
-  }
-
-  nsTHashtable<nsCStringHashKey> nonDetachedWindowDomains;
-  nonDetachedWindowDomains.Init();
-
-  // Populate nonDetachedWindowDomains.
-  GetNonDetachedWindowDomainsEnumeratorData nonDetachedEnumData =
-    { &nonDetachedWindowDomains, tldService };
-  windowsById->EnumerateRead(GetNonDetachedWindowDomainsEnumerator,
-                             &nonDetachedEnumData);
-
-  // Update mDetachedWindows and write the ghost window IDs into aOutGhostIDs,
-  // if it's not null.
-  CheckForGhostWindowsEnumeratorData ghostEnumData =
-    { &nonDetachedWindowDomains, aOutGhostIDs, tldService,
-      GetGhostTimeout(), TimeStamp::Now() };
-  mDetachedWindows.Enumerate(CheckForGhostWindowsEnumerator,
-                             &ghostEnumData);
-}
-
-NS_IMPL_ISUPPORTS1(nsWindowMemoryReporter::GhostURLsReporter,
-                   nsIMemoryMultiReporter)
-
-nsWindowMemoryReporter::
-GhostURLsReporter::GhostURLsReporter(
-  nsWindowMemoryReporter* aWindowReporter)
-  : mWindowReporter(aWindowReporter)
-{
-}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-GhostURLsReporter::GetName(nsACString& aName)
-{
-  aName.AssignLiteral("ghost-windows");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-GhostURLsReporter::GetExplicitNonHeap(PRInt64* aOut)
-{
-  *aOut = 0;
-  return NS_OK;
-}
-
-struct ReportGhostWindowsEnumeratorData
-{
-  nsIMemoryMultiReporterCallback* callback;
-  nsISupports* closure;
-  nsresult rv;
-};
-
-static PLDHashOperator
-ReportGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void* aClosure)
-{
-  ReportGhostWindowsEnumeratorData *data =
-    static_cast<ReportGhostWindowsEnumeratorData*>(aClosure);
-
-  nsGlobalWindow::WindowByIdTable* windowsById =
-    nsGlobalWindow::GetWindowsTable();
-  if (!windowsById) {
-    NS_WARNING("Couldn't get window-by-id hashtable?");
-    return PL_DHASH_NEXT;
-  }
-
-  nsGlobalWindow* window = windowsById->Get(aIDHashKey->GetKey());
-  if (!window) {
-    NS_WARNING("Could not look up window?");
-    return PL_DHASH_NEXT;
-  }
-
-  nsCAutoString path;
-  path.AppendLiteral("ghost-windows/");
-  AppendWindowURI(window, path);
-
-  nsresult rv = data->callback->Callback(
-    /* process = */ EmptyCString(),
-    path,
-    nsIMemoryReporter::KIND_SUMMARY,
-    nsIMemoryReporter::UNITS_COUNT,
-    /* amount = */ 1,
-    /* desc = */ EmptyCString(),
-    data->closure);
-
-  if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) {
-    data->rv = rv;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-GhostURLsReporter::CollectReports(
-  nsIMemoryMultiReporterCallback* aCb,
-  nsISupports* aClosure)
-{
-  // Get the IDs of all the ghost windows in existance.
-  nsTHashtable<nsUint64HashKey> ghostWindows;
-  ghostWindows.Init();
-  mWindowReporter->CheckForGhostWindows(&ghostWindows);
-
-  ReportGhostWindowsEnumeratorData reportGhostWindowsEnumData =
-    { aCb, aClosure, NS_OK };
-
-  // Call aCb->Callback() for each ghost window.
-  ghostWindows.EnumerateEntries(ReportGhostWindowsEnumerator,
-                                &reportGhostWindowsEnumData);
-
-  return reportGhostWindowsEnumData.rv;
-}
-
-NS_IMPL_ISUPPORTS1(nsWindowMemoryReporter::NumGhostsReporter,
-                   nsIMemoryReporter)
-
-nsWindowMemoryReporter::
-NumGhostsReporter::NumGhostsReporter(
-  nsWindowMemoryReporter *aWindowReporter)
-  : mWindowReporter(aWindowReporter)
-{}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-NumGhostsReporter::GetProcess(nsACString& aProcess)
-{
-  aProcess.AssignLiteral("");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-NumGhostsReporter::GetPath(nsACString& aPath)
-{
-  aPath.AssignLiteral("ghost-windows");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-NumGhostsReporter::GetKind(PRInt32* aKind)
-{
-  *aKind = KIND_OTHER;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-NumGhostsReporter::GetUnits(PRInt32* aUnits)
-{
-  *aUnits = nsIMemoryReporter::UNITS_COUNT;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-NumGhostsReporter::GetDescription(nsACString& aDesc)
-{
-  nsPrintfCString str(1024,
-"The number of ghost windows present (the number of nodes underneath \
-explicit/window-objects/top(none)/ghost, modulo race conditions).  A ghost \
-window is not shown in any tab, does not share a domain with any non-detached \
-windows, and has met these criteria for at least %ds \
-(memory.ghost_window_timeout_seconds) or has survived a round of about:memory's \
-minimize memory usage button.\n\n\
-Ghost windows can happen legitimately, but they are often indicative of leaks \
-in the browser or add-ons.",
-  mWindowReporter->GetGhostTimeout());
-
-  aDesc.Assign(str);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowMemoryReporter::
-NumGhostsReporter::GetAmount(PRInt64* aAmount)
-{
-  nsTHashtable<nsUint64HashKey> ghostWindows;
-  ghostWindows.Init();
-  mWindowReporter->CheckForGhostWindows(&ghostWindows);
-
-  *aAmount = ghostWindows.Count();
-  return NS_OK;
-}
--- a/dom/base/nsWindowMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -34,197 +34,45 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsWindowMemoryReporter_h__
 #define nsWindowMemoryReporter_h__
 
 #include "nsIMemoryReporter.h"
-#include "nsIObserver.h"
-#include "nsDataHashtable.h"
-#include "nsWeakReference.h"
-#include "nsAutoPtr.h"
-#include "mozilla/TimeStamp.h"
 
 // This should be used for any nsINode sub-class that has fields of its own
 // that it needs to measure;  any sub-class that doesn't use it will inherit
 // SizeOfExcludingThis from its super-class.  SizeOfIncludingThis() need not be
 // defined, it is inherited from nsINode.
 #define NS_DECL_SIZEOF_EXCLUDING_THIS \
   virtual size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 
 class nsWindowSizes {
 public:
-  nsWindowSizes(nsMallocSizeOfFun aMallocSizeOf) {
-    memset(this, 0, sizeof(nsWindowSizes));
-    mMallocSizeOf = aMallocSizeOf;
-  }
-  nsMallocSizeOfFun mMallocSizeOf;
-  size_t mDOM;
-  size_t mStyleSheets;
-  size_t mLayoutArenas;
-  size_t mLayoutStyleSets;
-  size_t mLayoutTextRuns;
+    nsWindowSizes(nsMallocSizeOfFun aMallocSizeOf) {
+      memset(this, 0, sizeof(nsWindowSizes));
+      mMallocSizeOf = aMallocSizeOf;
+    }
+    nsMallocSizeOfFun mMallocSizeOf;
+    size_t mDOM;
+    size_t mStyleSheets;
+    size_t mLayoutArenas;
+    size_t mLayoutStyleSets;
+    size_t mLayoutTextRuns;
 };
 
-/**
- * nsWindowMemoryReporter is responsible for the 'explicit/window-objects'
- * memory reporter.
- *
- * We classify DOM window objects into one of three categories:
- *
- *   - "active" windows, which are displayed in a tab (as the top-level window
- *     or an iframe),
- *
- *   - "cached" windows, which are in the fastback cache (aka the bfcache), and
- *
- *   - "detached" windows, which have a null docshell.  A window becomes
- *     detached when its <iframe> or tab containing the window is destroyed --
- *     i.e., when the window is no longer active or cached.
- *
- * Additionally, we classify a subset of detached windows as "ghost" windows.
- * Although ghost windows can happen legitimately (a page can hold a reference
- * to a cross-domain window and then close its container), the presence of
- * ghost windows is often indicative of a memory leak.
- *
- * A window is a ghost if it meets the following three criteria:
- *
- *   1) The window is detached.
- *
- *   2) There exist no non-detached windows with the same base domain as
- *      the window's principal.  (For example, the base domain of
- *      "wiki.mozilla.co.uk" is "mozilla.co.uk".)  This criterion makes us less
- *      likely to flag a legitimately held-alive detached window as a ghost.
- *
- *   3) The window has met criteria (1) and (2) above for at least
- *      memory.ghost_window_timeout_seconds.  This criterion is in place so we
- *      don't immediately declare a window a ghost before the GC/CC has had a
- *      chance to run.
- *
- * nsWindowMemoryReporter observes window detachment and uses mDetachedWindows
- * to remember when a window first met criteria (1) and (2).  When we generate
- * a memory report, we use this accounting to determine which windows are
- * ghosts.
- *
- *
- * We use the following memory reporter path for active and cached windows:
- *
- *   explicit/window-objects/top(<top-outer-uri>, id=<top-outer-id>)/<category>/window(<window-uri>)/...
- *
- * For detached and ghost windows, we use
- *
- *   explicit/window-objects/top(none)/<category>/window(<window-uri>)/...
- *
- * Where
- *
- * - <category> is "active", "cached", "detached", or "ghost", as described
- *   above.
- *
- * - <top-outer-id> is the window id of the top outer window (i.e. the tab, or
- *   the top level chrome window).  Exposing this ensures that each tab gets
- *   its own sub-tree, even if multiple tabs are showing the same URI.
- *
- * - <top-uri> is the URI of the top window.  Excepting special windows (such
- *   as browser.xul or hiddenWindow.html) it's what the address bar shows for
- *   the tab.
- *
- */
-class nsWindowMemoryReporter: public nsIMemoryMultiReporter,
-                              public nsIObserver,
-                              public nsSupportsWeakReference
+class nsWindowMemoryReporter: public nsIMemoryMultiReporter
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMEMORYMULTIREPORTER
-  NS_DECL_NSIOBSERVER
 
   static void Init();
 
 private:
-  /**
-   * GhostURLsReporter generates the "ghost-windows" multi-report, which
-   * includes a list of all ghost windows' URLs.  If you're only interested in
-   * this list, running this report is faster than running
-   * nsWindowMemoryReporter.
-   */
-  class GhostURLsReporter: public nsIMemoryMultiReporter
-  {
-  public:
-    GhostURLsReporter(nsWindowMemoryReporter* aWindowReporter);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIMEMORYMULTIREPORTER
-
-  private:
-    nsRefPtr<nsWindowMemoryReporter> mWindowReporter;
-  };
-
-  /**
-   * nsGhostWindowReporter generates the "ghost-windows" single-report, which
-   * counts the number of ghost windows present.
-   */
-  class NumGhostsReporter: public nsIMemoryReporter
-  {
-  public:
-    NumGhostsReporter(nsWindowMemoryReporter* aWindowReporter);
-
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIMEMORYREPORTER
-
-  private:
-    nsRefPtr<nsWindowMemoryReporter> mWindowReporter;
-  };
-
   // Protect ctor, use Init() instead.
   nsWindowMemoryReporter();
-
-  /**
-   * Get the number of seconds for which a window must satisfy ghost criteria
-   * (1) and (2) before we deem that it satisfies criterion (3).
-   */
-  PRUint32 GetGhostTimeout();
-
-  void ObserveDOMWindowDetached(nsISupports* aWindow);
-  void ObserveAfterMinimizeMemoryUsage();
-
-  /**
-   * When we observe a DOM window being detached, we enqueue an asynchronous
-   * event which calls this method.  This method then calls
-   * CheckForGhostWindows.
-   */
-  void CheckForGhostWindowsCallback();
-
-  /**
-   * Iterate over all weak window pointers in mDetachedWindows and update our
-   * accounting of which windows meet ghost criterion (2).
-   *
-   * This method also cleans up mDetachedWindows, removing entries for windows
-   * which have been destroyed or are no longer detached.
-   *
-   * If aOutGhostIDs is non-null, we populate it with the Window IDs of the
-   * ghost windows.
-   *
-   * This is called asynchronously after we observe a DOM window being detached
-   * from its docshell, and also right before we generate a memory report.
-   */
-  void CheckForGhostWindows(nsTHashtable<nsUint64HashKey> *aOutGhostIDs = NULL);
-
-  /**
-   * Maps a weak reference to a detached window (nsIWeakReference) to the time
-   * when we observed that the window met ghost criterion (2) above.
-   *
-   * If the window has not yet met criterion (2) it maps to the null timestamp.
-   *
-   * (Although windows are not added to this table until they're detached, it's
-   * possible for a detached window to become non-detached, and we won't
-   * remove it from the table until CheckForGhostWindows runs.)
-   */
-  nsDataHashtable<nsISupportsHashKey, mozilla::TimeStamp> mDetachedWindows;
-
-  /**
-   * True if we have an asynchronous call to CheckForGhostWindows pending.
-   */
-  bool mCheckForGhostWindowsCallbackPending;
 };
 
 #endif // nsWindowMemoryReporter_h__
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1698,17 +1698,17 @@ class JSCompartmentsMultiReporter : publ
         Paths paths; 
         JS_IterateCompartments(nsXPConnect::GetRuntimeInstance()->GetJSRuntime(),
                                &paths, CompartmentCallback);
  
         // Report.
         for (size_t i = 0; i < paths.length(); i++)
             // These ones don't need a description, hence the "".
             REPORT(nsCString(paths[i]),
-                   nsIMemoryReporter::KIND_SUMMARY,
+                   nsIMemoryReporter::KIND_OTHER,
                    nsIMemoryReporter::UNITS_COUNT,
                    1, "");
 
         return NS_OK;
     }
 
     NS_IMETHOD
     GetExplicitNonHeap(PRInt64 *n)
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3519,17 +3519,16 @@ pref("browser.dom.window.dump.enabled", 
 // SPS Profiler
 pref("profiler.enabled", false);
 pref("profiler.interval", 10);
 pref("profiler.entries", 100000);
 
 // Network API
 pref("dom.network.enabled", true);
 pref("dom.network.metered", false);
-
 #ifdef XP_WIN
 // On 32-bit Windows, fire a low-memory notification if we have less than this
 // many mb of virtual address space available.
 pref("memory.low_virtual_memory_threshold_mb", 128);
 
 // On Windows 32- or 64-bit, fire a low-memory notification if we have less
 // than this many mb of commit space (physical memory plus page file) left.
 pref("memory.low_commit_space_threshold_mb", 128);
@@ -3538,13 +3537,8 @@ pref("memory.low_commit_space_threshold_
 // than this many mb of physical memory available on the whole machine.
 pref("memory.low_physical_memory_threshold_mb", 0);
 
 // On Windows 32- or 64-bit, don't fire a low-memory notification because of
 // low available physical memory or low commit space more than once every
 // low_memory_notification_interval_ms.
 pref("memory.low_memory_notification_interval_ms", 10000);
 #endif
-
-// How long must we wait before declaring that a window is a "ghost" (i.e., a
-// likely leak)?  This should be longer than it usually takes for an eligible
-// window to be collected via the GC/CC.
-pref("memory.ghost_window_timeout_seconds", 60);
--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -46,17 +46,16 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const KIND_NONHEAP           = Ci.nsIMemoryReporter.KIND_NONHEAP;
 const KIND_HEAP              = Ci.nsIMemoryReporter.KIND_HEAP;
 const KIND_OTHER             = Ci.nsIMemoryReporter.KIND_OTHER;
-const KIND_SUMMARY           = Ci.nsIMemoryReporter.KIND_SUMMARY;
 const UNITS_BYTES            = Ci.nsIMemoryReporter.UNITS_BYTES;
 const UNITS_COUNT            = Ci.nsIMemoryReporter.UNITS_COUNT;
 const UNITS_COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE;
 const UNITS_PERCENTAGE       = Ci.nsIMemoryReporter.UNITS_PERCENTAGE;
 
 // Because about:memory and about:compartments are non-standard URLs,
 // location.search is undefined, so we have to use location.href here.
 // The toLowerCase() calls ensure that addresses like "ABOUT:MEMORY" work.
@@ -159,22 +158,20 @@ function minimizeMemoryUsage3x(fAfter)
   }
 
   function sendHeapMinNotificationsInner()
   {
     let os = Cc["@mozilla.org/observer-service;1"]
              .getService(Ci.nsIObserverService);
     os.notifyObservers(null, "memory-pressure", "heap-minimize");
 
-    if (++i < 3) {
+    if (++i < 3)
       runSoon(sendHeapMinNotificationsInner);
-    } else {
-      os.notifyObservers(null, "after-minimize-memory-usage", "about:memory");
+    else
       runSoon(fAfter);
-    }
   }
 
   sendHeapMinNotificationsInner();
 }
 
 //---------------------------------------------------------------------------
  
 /**
@@ -258,41 +255,42 @@ function processMemoryReporters(aMgr, aI
       handleException("multi-reporter", name, e);
     }
   }
 }
 
 // This regexp matches sentences and sentence fragments, i.e. strings that
 // start with a capital letter and ends with a '.'.  (The final sentence may be
 // in parentheses, so a ')' might appear after the '.'.)
-const gSentenceRegExp = /^[A-Z].*\.\)?$/m;
+const gSentenceRegExp = /^[A-Z].*\.\)?$/;
 
 function checkReport(aUnsafePath, aKind, aUnits, aAmount, aDescription)
 {
   if (aUnsafePath.startsWith("explicit/")) {
     assert(aKind === KIND_HEAP || aKind === KIND_NONHEAP, "bad explicit kind");
     assert(aUnits === UNITS_BYTES, "bad explicit units");
     assert(aDescription.match(gSentenceRegExp),
            "non-sentence explicit description");
 
   } else if (aUnsafePath.startsWith("smaps/")) {
     assert(aKind === KIND_NONHEAP, "bad smaps kind");
     assert(aUnits === UNITS_BYTES, "bad smaps units");
     assert(aDescription !== "", "empty smaps description");
 
-  } else if (aKind === KIND_SUMMARY) {
-    assert(!aUnsafePath.startsWith("explicit/") &&
-           !aUnsafePath.startsWith("smaps/"),
-           "bad SUMMARY path");
+  } else if (aUnsafePath.startsWith("compartments/")) {
+    assert(aKind === KIND_OTHER, "bad compartments kind");
+    assert(aUnits === UNITS_COUNT, "bad compartments units");
+    assert(aAmount === 1, "bad amount");
+    assert(aDescription === "", "bad description");
 
   } else {
     assert(aUnsafePath.indexOf("/") === -1, "'other' path contains '/'");
     assert(aKind === KIND_OTHER, "bad other kind: " + aUnsafePath);
     assert(aDescription.match(gSentenceRegExp),
-           "non-sentence other description " + aDescription);
+           "non-sentence other description");
   }
 }
 
 //---------------------------------------------------------------------------
 
 function clearBody()
 {
   let oldBody = document.body;
@@ -534,32 +532,30 @@ Report.prototype = {
     return this._unsafePath.startsWith(aTreeName) &&
            this._unsafePath.charAt(aTreeName.length) === '/';
   }
 };
 
 function getReportsByProcess(aMgr)
 {
   // Ignore the "smaps" multi-reporter in non-verbose mode, and the
-  // "compartments" and "ghost-windows" multi-reporters all the time.  (Note
-  // that reports from these multi-reporters can reach here as single reports
-  // if they were in the child process.)
+  // "compartments" multi-reporter all the time.  (Note that reports from these
+  // multi-reporters can reach here as single reports if they were in the child
+  // process.)
 
   function ignoreSingle(aPath) 
   {
     return (aPath.startsWith("smaps/") && !gVerbose) ||
-           aPath.startsWith("compartments/") ||
-           aPath.startsWith("ghost-windows/");
+           (aPath.startsWith("compartments/"))
   }
 
   function ignoreMulti(aName)
   {
-    return (aName === "smaps" && !gVerbose) ||
-           aName === "compartments" ||
-           aName === "ghost-windows";
+    return ((aName === "smaps" && !gVerbose) ||
+            (aName === "compartments"));
   }
 
   let reportsByProcess = {};
 
   function handleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
                         aDescription)
   {
     let process = aProcess === "" ? "Main" : aProcess;
@@ -1551,31 +1547,25 @@ function updateAboutCompartments()
   // First, clear the page contents.  Necessary because
   // updateAboutCompartments() might be called more than once due to the
   // "child-memory-reporter-update" observer.
   let body = clearBody();
 
   let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
       getService(Ci.nsIMemoryReporterManager);
 
-  let compartmentsByProcess = getCompartmentsByProcess(mgr);
-  let ghostWindowsByProcess = getGhostWindowsByProcess(mgr);
-
-  function handleProcess(aProcess) {
-    appendProcessAboutCompartmentsElements(body, aProcess,
-                                           compartmentsByProcess[aProcess],
-                                           ghostWindowsByProcess[aProcess]);
-  }
-
   // Generate output for one process at a time.  Always start with the
   // Main process.
-  handleProcess('Main');
+  let compartmentsByProcess = getCompartmentsByProcess(mgr);
+  appendProcessCompartmentsElements(body, "Main",
+                                    compartmentsByProcess["Main"]);
   for (let process in compartmentsByProcess) {
     if (process !== "Main") {
-      handleProcess(process);
+      appendProcessCompartmentsElements(body, process,
+                                        compartmentsByProcess[process]);
     }
   }
 
   appendElement(body, "hr");
 
   let div1 = appendElement(body, "div");
   let a;
   if (gVerbose) {
@@ -1661,132 +1651,57 @@ function getCompartmentsByProcess(aMgr)
     }
   }
 
   processMemoryReporters(aMgr, ignoreSingle, ignoreMulti, handleReport);
 
   return compartmentsByProcess;
 }
 
-function GhostWindow(aUnsafeURL)
-{
-  // Call it _unsafeName rather than _unsafeURL for symmetry with the
-  // Compartment object.
-  this._unsafeName = aUnsafeURL;
-
-  // this._nMerged is only defined if > 1
-}
+//---------------------------------------------------------------------------
 
-GhostWindow.prototype = {
-  merge: function(r) {
-    this._nMerged = this._nMerged ? this._nMerged + 1 : 2;
-  }
-};
-
-function getGhostWindowsByProcess(aMgr)
+function appendProcessCompartmentsElementsHelper(aP, aCompartments, aKindString)
 {
-  function ignoreSingle(aPath) 
-  {
-    return !aPath.startsWith('ghost-windows/')
-  }
+  appendElementWithText(aP, "h2", "", aKindString + " Compartments\n");
 
-  function ignoreMulti(aName)
-  {
-    return aName !== "ghost-windows";
-  }
-
-  let ghostWindowsByProcess = {};
-
-  function handleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
-                        aDescription)
-  {
-    let unsafeSplit = aUnsafePath.split('/');
-    assert(unsafeSplit[0] == 'ghost-windows',
-           'Unexpected path in getGhostWindowsByProcess: ' + aUnsafePath);
-
-    let unsafeURL = unsafeSplit[1];
-    let ghostWindow = new GhostWindow(unsafeURL);
-
-    let process = aProcess === "" ? "Main" : aProcess;
-    if (!ghostWindowsByProcess[process]) {
-      ghostWindowsByProcess[process] = {};
-    }
-
-    if (ghostWindowsByProcess[process][unsafeURL]) {
-      ghostWindowsByProcess[process][unsafeURL].merge(ghostWindow);
-    }
-    else {
-      ghostWindowsByProcess[process][unsafeURL] = ghostWindow;
+  let compartmentTextArray = [];
+  let uPre = appendElement(aP, "pre", "entries");
+  for (let name in aCompartments) {
+    let c = aCompartments[name];
+    let isSystemKind = aKindString === "System";
+    if (c._isSystemCompartment === isSystemKind) {
+      let text = flipBackslashes(c._unsafeName);
+      if (c._nMerged) {
+        text += " [" + c._nMerged + "]";
+      }
+      text += "\n";
+      compartmentTextArray.push(text);
     }
   }
-
-  processMemoryReporters(aMgr, ignoreSingle, ignoreMulti, handleReport);
-
-  return ghostWindowsByProcess;
-}
-
-//---------------------------------------------------------------------------
-
-function appendProcessAboutCompartmentsElementsHelper(aP, aEntries, aKindString)
-{
-  // aEntries might be null or undefined, e.g. if there are no ghost windows
-  // for this process.
-  aEntries = aEntries ? aEntries : {};
-
-  appendElementWithText(aP, "h2", "", aKindString + "\n");
+  compartmentTextArray.sort();
 
-  let uPre = appendElement(aP, "pre", "entries");
-
-  let lines = [];
-  for (let name in aEntries) {
-    let e = aEntries[name];
-    let line = flipBackslashes(e._unsafeName);
-    if (e._nMerged) {
-      line += ' [' + e._nMerged + ']';
-    }
-    line += '\n';
-    lines.push(line);
-  }
-  lines.sort();
-
-  for (let i = 0; i < lines.length; i++) {
-    appendElementWithText(uPre, "span", "", lines[i]);
+  for (let i = 0; i < compartmentTextArray.length; i++) {
+    appendElementWithText(uPre, "span", "", compartmentTextArray[i]);
   }
 
   appendTextNode(aP, "\n");   // gives nice spacing when we cut and paste
 }
 
 /**
  * Appends the elements for a single process.
  *
  * @param aP
  *        The parent DOM node.
  * @param aProcess
  *        The name of the process.
  * @param aCompartments
  *        Table of Compartments for this process, indexed by _unsafeName.
- * @param aGhostWindows
- *        Array of window URLs of ghost windows.
- *
  * @return The generated text.
  */
-function appendProcessAboutCompartmentsElements(aP, aProcess, aCompartments, aGhostWindows)
+function appendProcessCompartmentsElements(aP, aProcess, aCompartments)
 {
   appendElementWithText(aP, "h1", "", aProcess + " Process");
   appendTextNode(aP, "\n\n");   // gives nice spacing when we cut and paste
-
-  let userCompartments = {};
-  let systemCompartments = {};
-  for (let name in aCompartments) {
-    let c = aCompartments[name];
-    if (c._isSystemCompartment) {
-      systemCompartments[name] = c;
-    }
-    else {
-      userCompartments[name] = c;
-    }
-  }
   
-  appendProcessAboutCompartmentsElementsHelper(aP, userCompartments, "User Compartments");
-  appendProcessAboutCompartmentsElementsHelper(aP, systemCompartments, "System Compartments");
-  appendProcessAboutCompartmentsElementsHelper(aP, aGhostWindows, "Ghost Windows");
+  appendProcessCompartmentsElementsHelper(aP, aCompartments, "User");
+  appendProcessCompartmentsElementsHelper(aP, aCompartments, "System");
 }
 
--- a/toolkit/components/aboutmemory/tests/test_aboutcompartments.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutcompartments.xul
@@ -42,17 +42,16 @@
   }
 
   // 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 SUMMARY = Ci.nsIMemoryReporter.KIND_SUMMARY;
 
   const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
   const COUNT = Ci.nsIMemoryReporter.UNITS_COUNT;
 
   function f(aProcess, aPath, aKind, aUnits, aAmount) {
     return {
       process:     aProcess,
       path:        aPath,
@@ -67,18 +66,18 @@
     // These should be ignored.
     f("", "explicit/a",         HEAP,    BYTES, 222 * MB),
     f("", "explicit/b/a",       HEAP,    BYTES,  85 * MB),
     f("", "explicit/b/b",       NONHEAP, BYTES,  85 * MB),
     f("", "other1",             OTHER,   BYTES, 111 * MB),
     f("", "other2",             OTHER,   COUNT, 888),
 
     f("2nd", "explicit/c",      HEAP,    BYTES, 333 * MB),
-    f("2nd", "compartments/user/child-user-compartment",     SUMMARY, COUNT, 1),
-    f("2nd", "compartments/system/child-system-compartment", SUMMARY, COUNT, 1)
+    f("2nd", "compartments/user/child-user-compartment",     OTHER, COUNT, 1),
+    f("2nd", "compartments/system/child-system-compartment", OTHER, COUNT, 1)
   ];
 
   var fakeMultiReporters = [
     // These shouldn't show up.
     { name: "fake",
       collectReports: function(aCbObj, aClosure) {
         function f(aP, aK, aU, aA) {
           aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
@@ -86,42 +85,32 @@
         f("explicit/a/d",     HEAP,    BYTES,  13 * MB);
         f("explicit/b/c",     NONHEAP, BYTES,  10 * MB);
        },
        explicitNonHeap: 10*MB
     },
     { name: "compartments",
       collectReports: function(aCbObj, aClosure) {
         function f(aP) {
-          aCbObj.callback("", aP, SUMMARY, COUNT, 1, "", aClosure);
+          aCbObj.callback("", aP, OTHER, COUNT, 1, "", aClosure);
         }
         f("compartments/user/http:\\\\foo.com\\");
         f("compartments/user/https:\\\\bar.com\\bar?baz");
         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");
         // This moz-nullprincipal one is shown under "System Compartments" even
         // though its path indicates it's a user compartment.
         f("compartments/user/moz-nullprincipal:{7ddefdaf-34f1-473f-9b03-50a4568ccb06}");
         // This should show up once with a "[3]" suffix
         f("compartments/system/[System Principal]");
         f("compartments/system/[System Principal]");
         f("compartments/system/[System Principal]");
         f("compartments/system/atoms");
       },
       explicitNonHeap: 0
     },
-    { name: "ghost-windows",
-      collectReports: function(aCbObj, aClosure) {
-        function f(aP) {
-          aCbObj.callback("", aP, SUMMARY, COUNT, 1, "", aClosure);
-        }
-        f("ghost-windows/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");
-        f("ghost-windows/http:\\\\foobar.com\\foo?bar#baz");
-      },
-      explicitNonHeap: 0
-    },
     // These shouldn't show up.
     { name: "smaps",
        collectReports: function(aCbObj, aClosure) {
         // The amounts are given in pages, so multiply here by 4kb.
         function f(aP, aA) {
           aCbObj.callback("", aP, NONHEAP, BYTES, aA * 4 * KB, "Desc.", aClosure);
         }
         f("smaps/vsize/a",     24);
@@ -155,30 +144,24 @@ http://foo.com/\n\
 https://bar.com/bar?baz\n\
 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\n\
 \n\
 System Compartments\n\
 [System Principal] [3]\n\
 atoms\n\
 moz-nullprincipal:{7ddefdaf-34f1-473f-9b03-50a4568ccb06}\n\
 \n\
-Ghost Windows\n\
-http://foobar.com/foo?bar#baz\n\
-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\n\
-\n\
 2nd Process\n\
 \n\
 User Compartments\n\
 child-user-compartment\n\
 \n\
 System Compartments\n\
 child-system-compartment\n\
 \n\
-Ghost Windows\n\
-\n\
 ";
 
   // Verbose mode output is the same when you cut and paste.
   var acvExpectedText = acExpectedText;
 
   function finish()
   {
     // Unregister fake reporters and multi-reporters, re-register the real
--- a/toolkit/components/telemetry/TelemetryHistograms.h
+++ b/toolkit/components/telemetry/TelemetryHistograms.h
@@ -97,17 +97,16 @@ HISTOGRAM_BOOLEAN(TELEMETRY_SUCCESS,  "S
 HISTOGRAM(MEMORY_JS_COMPARTMENTS_SYSTEM, 1, 1000, 50, EXPONENTIAL, "Total JavaScript compartments used for add-ons and internals.")
 HISTOGRAM(MEMORY_JS_COMPARTMENTS_USER, 1, 1000, 50, EXPONENTIAL, "Total JavaScript compartments used for web pages")
 HISTOGRAM(MEMORY_JS_GC_HEAP, 1024, 512 * 1024, 50, EXPONENTIAL, "Memory used by the garbage-collected JavaScript heap (KB)")
 HISTOGRAM(MEMORY_RESIDENT, 32 * 1024, 1024 * 1024, 50, EXPONENTIAL, "Resident memory size (KB)")
 HISTOGRAM(MEMORY_STORAGE_SQLITE, 1024, 512 * 1024, 50, EXPONENTIAL, "Memory used by SQLite (KB)")
 HISTOGRAM(MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED, 1024, 1024 * 1024, 50, EXPONENTIAL, "Memory used for uncompressed, in-use content images (KB)")
 HISTOGRAM(MEMORY_HEAP_ALLOCATED, 1024, 1024 * 1024, 50, EXPONENTIAL, "Heap memory allocated (KB)")
 HISTOGRAM(MEMORY_EXPLICIT, 1024, 1024 * 1024, 50, EXPONENTIAL, "Explicit memory allocations (KB)")
-HISTOGRAM(GHOST_WINDOWS, 1, 128, 8, EXPONENTIAL, "Number of ghost windows")
 #if defined(XP_MACOSX)
 HISTOGRAM(MEMORY_FREE_PURGED_PAGES_MS, 1, 1024, 10, EXPONENTIAL, "Time(ms) to purge MADV_FREE'd heap pages.")
 #elif defined(XP_WIN)
 HISTOGRAM(LOW_MEMORY_EVENTS_VIRTUAL, 1, 1024, 21, EXPONENTIAL, "Number of low-virtual-memory events fired since last ping")
 HISTOGRAM(LOW_MEMORY_EVENTS_PHYSICAL, 1, 1024, 21, EXPONENTIAL, "Number of low-physical-memory events fired since last ping")
 HISTOGRAM(LOW_MEMORY_EVENTS_COMMIT_SPACE, 1, 1024, 21, EXPONENTIAL, "Number of low-commit-space events fired since last ping")
 #endif
 
--- a/toolkit/components/telemetry/TelemetryPing.js
+++ b/toolkit/components/telemetry/TelemetryPing.js
@@ -63,18 +63,17 @@ const MEM_HISTOGRAMS = {
   "resident": "MEMORY_RESIDENT",
   "storage-sqlite": "MEMORY_STORAGE_SQLITE",
   "images-content-used-uncompressed":
     "MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED",
   "heap-allocated": "MEMORY_HEAP_ALLOCATED",
   "page-faults-hard": "PAGE_FAULTS_HARD",
   "low-memory-events-virtual": "LOW_MEMORY_EVENTS_VIRTUAL",
   "low-memory-events-commit-space": "LOW_MEMORY_EVENTS_COMMIT_SPACE",
-  "low-memory-events-physical": "LOW_MEMORY_EVENTS_PHYSICAL",
-  "ghost-windows": "GHOST_WINDOWS"
+  "low-memory-events-physical": "LOW_MEMORY_EVENTS_PHYSICAL"
 };
 // Seconds of idle time before pinging.
 // On idle-daily a gather-telemetry notification is fired, during it probes can
 // start asynchronous tasks to gather data.  On the next idle the data is sent.
 const IDLE_TIMEOUT_SECONDS = 5 * 60;
 
 var gLastMemoryPoll = null;
 
--- a/xpcom/base/nsIMemoryReporter.idl
+++ b/xpcom/base/nsIMemoryReporter.idl
@@ -112,18 +112,20 @@ interface nsIMemoryReporter : nsISupport
    * - Paths starting with "smaps/" represent regions of virtual memory that the
    *   process has mapped.  The rest of the path describes the type of
    *   measurement; for instance, the reporter "smaps/rss/[stack]" might report
    *   how much of the process's stack is currently in physical memory.
    *
    *   Reporters in this category must have kind NONHEAP, units BYTES, and
    *   a non-empty description.
    *
-   * - Reporters with kind SUMMARY may have any path which doesn't start with
-   *   "explicit/" or "smaps/".
+   * - Paths starting with "compartments/" represent the names of JS
+   *   compartments.  Reporters in this category must paths of the form
+   *   "compartments/user/<name>" or "compartments/system/<name>", amount 1,
+   *   kind OTHER, units COUNT, and an empty description.
    *
    * - All other paths represent cross-cutting values and may overlap with any
    *   other reporter.  Reporters in this category must have paths that do not
    *   contain '/' separators, kind OTHER, and a description that is a
    *   sentence.
    */
   readonly attribute AUTF8String path;
 
@@ -139,32 +141,20 @@ interface nsIMemoryReporter : nsISupport
    *    live on the heap.  Such memory is commonly allocated by calling one of
    *    the OS's memory-mapping functions (e.g. mmap, VirtualAlloc, or
    *    vm_allocate).  Reporters in this category must have units UNITS_BYTES
    *    and must have a path starting with "explicit/" or "smaps/".
    *
    *  - OTHER: reporters which don't fit into either of these categories. Such
    *    reporters must have a path that does not start with "explicit/" or
    *    "smaps/" and may have any units.
-   *
-   *  - SUMMARY: reporters which report data that's available in a more
-   *    detailed form via other reporters.  These reporters are sometimes
-   *    useful for efficiency purposes -- for example, a KIND_SUMMARY reporter
-   *    might list all the JS compartments without the overhead of the full JS
-   *    memory reporter, which walks the JS heap.
-   *
-   *    Unlike other reporters, SUMMARY reporters may have empty descriptions.
-   *
-   *    SUMMARY reporters must not have a path starting with "explicit/" or
-   *    "smaps/".
    */
   const PRInt32 KIND_NONHEAP = 0;
   const PRInt32 KIND_HEAP    = 1;
   const PRInt32 KIND_OTHER   = 2;
-  const PRInt32 KIND_SUMMARY = 3;
 
   /*
    * KIND_MAPPED is a deprecated synonym for KIND_NONHEAP.  We keep it around
    * to as not to break extensions which might use this interface, but we will
    * remove it eventually.
    */
   const PRInt32 KIND_MAPPED  = 0;