diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp index 0afa6814b00a..f2234903436b 100644 --- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -9,8 +9,10 @@ #include "nsGlobalWindow.h" #include "nsIDocument.h" #include "nsIEffectiveTLDService.h" -#include "mozilla/Services.h" +#include "mozilla/ClearOnShutdown.h" #include "mozilla/Preferences.h" +#include "mozilla/Services.h" +#include "mozilla/StaticPtr.h" #include "nsNetCID.h" #include "nsPrintfCString.h" #include "XPCJSMemoryReporter.h" @@ -19,6 +21,8 @@ using namespace mozilla; +StaticRefPtr sWindowReporter; + nsWindowMemoryReporter::nsWindowMemoryReporter() : mCheckForGhostWindowsCallbackPending(false) { @@ -31,27 +35,22 @@ NS_IMPL_ISUPPORTS3(nsWindowMemoryReporter, nsIMemoryReporter, nsIObserver, void nsWindowMemoryReporter::Init() { - // The memory reporter manager will own this object. - nsRefPtr windowReporter = new nsWindowMemoryReporter(); - NS_RegisterMemoryReporter(windowReporter); + MOZ_ASSERT(!sWindowReporter); + sWindowReporter = new nsWindowMemoryReporter(); + ClearOnShutdown(&sWindowReporter); + NS_RegisterMemoryReporter(sWindowReporter); nsCOMPtr 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, + os->AddObserver(sWindowReporter, DOM_WINDOW_DESTROYED_TOPIC, /* weakRef = */ true); - os->AddObserver(windowReporter, "after-minimize-memory-usage", + os->AddObserver(sWindowReporter, "after-minimize-memory-usage", /* weakRef = */ true); } - nsRefPtr ghostURLsReporter = - new GhostURLsReporter(windowReporter); - NS_RegisterMemoryReporter(ghostURLsReporter); - - nsRefPtr numGhostsReporter = - new NumGhostsReporter(windowReporter); - NS_RegisterMemoryReporter(numGhostsReporter); + NS_RegisterMemoryReporter(new GhostWindowsReporter()); } static already_AddRefed @@ -311,6 +310,52 @@ GetWindows(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure) return PL_DHASH_NEXT; } +struct ReportGhostWindowsEnumeratorData +{ + nsIMemoryReporterCallback* callback; + nsISupports* closure; + nsresult rv; +}; + +static PLDHashOperator +ReportGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void* aClosure) +{ + ReportGhostWindowsEnumeratorData *data = + static_cast(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; + } + + nsAutoCString path; + path.AppendLiteral("ghost-windows/"); + AppendWindowURI(window, path); + + nsresult rv = data->callback->Callback( + /* process = */ EmptyCString(), + path, + nsIMemoryReporter::KIND_OTHER, + nsIMemoryReporter::UNITS_COUNT, + /* amount = */ 1, + /* description = */ NS_LITERAL_CSTRING("A ghost window."), + data->closure); + + if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) { + data->rv = rv; + } + + return PL_DHASH_NEXT; +} + NS_IMETHODIMP nsWindowMemoryReporter::GetName(nsACString &aName) { @@ -331,12 +376,18 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb, WindowArray windows; windowsById->Enumerate(GetWindows, &windows); - // Get the IDs of all the "ghost" windows. + // Get the IDs of all the "ghost" windows, and call aCb->Callback() for each + // one. nsTHashtable ghostWindows; CheckForGhostWindows(&ghostWindows); + ReportGhostWindowsEnumeratorData reportGhostWindowsEnumData = + { aCb, aClosure, NS_OK }; + ghostWindows.EnumerateEntries(ReportGhostWindowsEnumerator, + &reportGhostWindowsEnumData); + nsresult rv = reportGhostWindowsEnumData.rv; + NS_ENSURE_SUCCESS(rv, rv); WindowPaths windowPaths; - WindowPaths topWindowPaths; // Collect window memory usage. @@ -344,17 +395,17 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb, nsCOMPtr addonManager = do_GetService("@mozilla.org/addons/integration;1"); for (uint32_t i = 0; i < windows.Length(); i++) { - nsresult rv = CollectWindowReports(windows[i], addonManager, - &windowTotalSizes, &ghostWindows, - &windowPaths, &topWindowPaths, aCb, - aClosure); + rv = CollectWindowReports(windows[i], addonManager, + &windowTotalSizes, &ghostWindows, + &windowPaths, &topWindowPaths, aCb, + aClosure); NS_ENSURE_SUCCESS(rv, rv); } // Report JS memory usage. We do this from here because the JS memory // reporter needs to be passed |windowPaths|. - nsresult rv = xpc::JSReporter::CollectReports(&windowPaths, &topWindowPaths, - aCb, aClosure); + rv = xpc::JSReporter::CollectReports(&windowPaths, &topWindowPaths, + aCb, aClosure); NS_ENSURE_SUCCESS(rv, rv); #define REPORT(_path, _amount, _desc) \ @@ -662,94 +713,10 @@ nsWindowMemoryReporter::CheckForGhostWindows( &ghostEnumData); } -NS_IMPL_ISUPPORTS1(nsWindowMemoryReporter::GhostURLsReporter, - nsIMemoryReporter) - -nsWindowMemoryReporter:: -GhostURLsReporter::GhostURLsReporter( - nsWindowMemoryReporter* aWindowReporter) - : mWindowReporter(aWindowReporter) -{ -} - -NS_IMETHODIMP -nsWindowMemoryReporter:: -GhostURLsReporter::GetName(nsACString& aName) -{ - aName.AssignLiteral("ghost-windows-multi"); - return NS_OK; -} - -struct ReportGhostWindowsEnumeratorData -{ - nsIMemoryReporterCallback* callback; - nsISupports* closure; - nsresult rv; -}; - -static PLDHashOperator -ReportGhostWindowsEnumerator(nsUint64HashKey* aIDHashKey, void* aClosure) -{ - ReportGhostWindowsEnumeratorData *data = - static_cast(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; - } - - nsAutoCString path; - path.AppendLiteral("ghost-windows/"); - AppendWindowURI(window, path); - - nsresult rv = data->callback->Callback( - /* process = */ EmptyCString(), - path, - nsIMemoryReporter::KIND_OTHER, - nsIMemoryReporter::UNITS_COUNT, - /* amount = */ 1, - /* description = */ NS_LITERAL_CSTRING("A ghost window."), - data->closure); - - if (NS_FAILED(rv) && NS_SUCCEEDED(data->rv)) { - data->rv = rv; - } - - return PL_DHASH_NEXT; -} - -NS_IMETHODIMP -nsWindowMemoryReporter:: -GhostURLsReporter::CollectReports( - nsIMemoryReporterCallback* aCb, - nsISupports* aClosure) -{ - // Get the IDs of all the ghost windows in existance. - nsTHashtable ghostWindows; - mWindowReporter->CheckForGhostWindows(&ghostWindows); - - ReportGhostWindowsEnumeratorData reportGhostWindowsEnumData = - { aCb, aClosure, NS_OK }; - - // Call aCb->Callback() for each ghost window. - ghostWindows.EnumerateEntries(ReportGhostWindowsEnumerator, - &reportGhostWindowsEnumData); - - return reportGhostWindowsEnumData.rv; -} - int64_t -nsWindowMemoryReporter::NumGhostsReporter::Amount() +nsWindowMemoryReporter::GhostWindowsReporter::Amount() { nsTHashtable ghostWindows; - mWindowReporter->CheckForGhostWindows(&ghostWindows); + sWindowReporter->CheckForGhostWindows(&ghostWindows); return ghostWindows.Count(); } diff --git a/dom/base/nsWindowMemoryReporter.h b/dom/base/nsWindowMemoryReporter.h index a53021e1ad51..df567b533781 100644 --- a/dom/base/nsWindowMemoryReporter.h +++ b/dom/base/nsWindowMemoryReporter.h @@ -120,31 +120,14 @@ public: static void Init(); private: - /** - * GhostURLsReporter generates the list of all ghost windows' URLs. If - * you're only interested in this list, running this report is faster than - * running nsWindowMemoryReporter. - */ - class GhostURLsReporter MOZ_FINAL : public nsIMemoryReporter - { - public: - GhostURLsReporter(nsWindowMemoryReporter* aWindowReporter); - - NS_DECL_ISUPPORTS - NS_DECL_NSIMEMORYREPORTER - - private: - nsRefPtr mWindowReporter; - }; - /** * nsGhostWindowReporter generates the "ghost-windows" report, which counts * the number of ghost windows present. */ - class NumGhostsReporter MOZ_FINAL : public mozilla::MemoryUniReporter + class GhostWindowsReporter MOZ_FINAL : public mozilla::MemoryUniReporter { public: - NumGhostsReporter(nsWindowMemoryReporter* aWindowReporter) + GhostWindowsReporter() : MemoryUniReporter("ghost-windows", KIND_OTHER, UNITS_COUNT, "The number of ghost windows present (the number of nodes underneath " "explicit/window-objects/top(none)/ghost, modulo race conditions). A ghost " @@ -154,13 +137,10 @@ private: "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(aWindowReporter) {} private: int64_t Amount() MOZ_OVERRIDE; - - nsRefPtr mWindowReporter; }; // Protect ctor, use Init() instead.