diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index da64914f62d..d3cc35f6d48 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -895,32 +895,6 @@ NS_IMPL_ISUPPORTS( , nsIMemoryReporterCallback ) -class MemoryReportFinishedCallback final : public nsIFinishReportingCallback -{ -public: - NS_DECL_ISUPPORTS - - explicit MemoryReportFinishedCallback(MemoryReportRequestChild* aActor) - : mActor(aActor) - { - } - - NS_IMETHOD Callback(nsISupports* aUnused) override - { - bool sent = PMemoryReportRequestChild::Send__delete__(mActor); - return sent ? NS_OK : NS_ERROR_FAILURE; - } - -private: - ~MemoryReportFinishedCallback() {} - - nsRefPtr mActor; -}; -NS_IMPL_ISUPPORTS( - MemoryReportFinishedCallback -, nsIFinishReportingCallback -) - bool ContentChild::RecvPMemoryReportRequestConstructor( PMemoryReportRequestChild* aChild, @@ -957,12 +931,11 @@ NS_IMETHODIMP MemoryReportRequestChild::Run() // MemoryReport. nsRefPtr cb = new MemoryReportCallback(this, process); - nsRefPtr finished = - new MemoryReportFinishedCallback(this); + mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize, + FileDescriptorToFILE(mDMDFile, "wb")); - return mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize, - FileDescriptorToFILE(mDMDFile, "wb"), - finished, nullptr); + bool sent = Send__delete__(this); + return sent ? NS_OK : NS_ERROR_FAILURE; } bool diff --git a/image/test/mochitest/test_bug601470.html b/image/test/mochitest/test_bug601470.html index a9e1cc7880e..fea2424b2a4 100644 --- a/image/test/mochitest/test_bug601470.html +++ b/image/test/mochitest/test_bug601470.html @@ -30,13 +30,12 @@ window.onload = function() { amount += aAmount; } - var finished = function() { - ok(amount > 0, "we should be using a nonzero amount of memory"); - ok(true, "yay, didn't crash!"); - SimpleTest.finish(); - } + mgr.getReportsForThisProcess(handleReport, null, /* anonymize = */ false); - mgr.getReports(handleReport, null, finished, null, /* anonymize = */ false); + ok(amount > 0, "we should be using a nonzero amount of memory"); + ok(true, "yay, didn't crash!"); + + SimpleTest.finish(); } diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul index bfeab4c7b41..d00e1ae1538 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul @@ -119,6 +119,21 @@ mgr.registerStrongReporterEvenIfBlocked(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 + // --disable-jemalloc 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 @@ -552,14 +567,7 @@ End of 5th\n\ SimpleTest.waitForClipboard( function(aActual) { mostRecentActual = aActual; - let rslt = aActual.trim() === aExpected.trim(); - if (!rslt) { - // Try copying again. - synthesizeKey("A", {accelKey: true}); - synthesizeKey("C", {accelKey: true}); - } - - return rslt; + return aActual.trim() === aExpected.trim(); }, function() { synthesizeKey("A", {accelKey: true}); diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul index 8cf197e6d11..e2f93d0adc4 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul @@ -106,14 +106,7 @@ SimpleTest.waitForClipboard( function(aActual) { mostRecentActual = aActual; - let rslt = aActual.trim() === aExpected.trim(); - if (!rslt) { - // Try copying again. - synthesizeKey("A", {accelKey: true}); - synthesizeKey("C", {accelKey: true}); - } - - return rslt; + return aActual.trim() === aExpected.trim(); }, function() { synthesizeKey("A", {accelKey: true}); diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul index 035bb05ed48..d9f1b81064e 100644 --- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul +++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul @@ -44,8 +44,6 @@ const XUL_NS = "http:\\\\www.mozilla.org\\keymaster\\gatekeeper\\there.is.only.xul"; - SimpleTest.waitForExplicitFinish(); - let vsizeAmounts = []; let residentAmounts = []; let heapAllocatedAmounts = []; @@ -143,6 +141,21 @@ let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); + // Access the distinguished amounts (mgr.explicit et al.) just to make sure + // they don't crash. We can't check their actual values because they're + // non-deterministic. + // + // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a + // --disable-jemalloc build. Allow for that exception, but *only* that + // exception. + let dummy; + let haveExplicit = true; + try { + dummy = mgr.explicit; + } catch (ex) { + is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception"); + haveExplicit = false; + } let amounts = [ "vsize", "vsizeMaxContiguous", @@ -169,7 +182,7 @@ // aren't available on all platforms. But if the attribute simply // isn't present, that indicates the distinguished amounts have changed // and this file hasn't been updated appropriately. - let dummy = mgr[amounts[i]]; + dummy = mgr[amounts[i]]; ok(dummy !== undefined, "accessed an unknown distinguished amount: " + amounts[i]); } catch (ex) { @@ -191,33 +204,11 @@ domSize, styleSize, otherSize, totalSize, jsMilliseconds, nonJSMilliseconds); - let asyncSteps = [ - getReportsNormal, - getReportsAnonymized, - checkResults, - test_register_strong, - test_register_strong, // Make sure re-registering works - test_register_weak, - SimpleTest.finish - ]; + mgr.getReportsForThisProcess(handleReportNormal, null, + /* anonymize = */ false); - function runNext() { - setTimeout(asyncSteps.shift(), 0); - } - - function getReportsNormal() - { - mgr.getReports(handleReportNormal, null, - runNext, null, - /* anonymize = */ false); - } - - function getReportsAnonymized() - { - mgr.getReports(handleReportAnonymized, null, - runNext, null, - /* anonymize = */ true); - } + mgr.getReportsForThisProcess(handleReportAnonymized, null, + /* anonymize = */ true); function checkSizeReasonable(aName, aAmount) { @@ -235,50 +226,40 @@ } } - function checkResults() - { - try { - // Nb: mgr.heapAllocated will throw NS_ERROR_NOT_AVAILABLE if this is a - // --disable-jemalloc build. Allow for skipping this test on that - // exception, but *only* that exception. - let dummy = mgr.heapAllocated; - checkSpecialReport("heap-allocated", heapAllocatedAmounts); - } catch (ex) { - is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.heapAllocated exception"); - } - // vsize may be unreasonable if ASAN is enabled - checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); - checkSpecialReport("resident", residentAmounts); - - for (var reporter in jsGcHeapUsedGcThings) { - ok(jsGcHeapUsedGcThings[reporter] == 1); - } - checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", - jsGcHeapUsedGcThingsTotal); - - ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); - ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); - ok(present.places, "places is present"); - ok(present.images, "images is present"); - ok(present.xptiWorkingSet, "xpti-working-set is present"); - ok(present.atomTablesMain, "atom-tables/main is present"); - ok(present.sandboxLocation, "sandbox locations are present"); - ok(present.bigString, "large string is present"); - ok(present.smallString1, "small string 1 is present"); - ok(present.smallString2, "small string 2 is present"); - - ok(!present.anonymizedWhenUnnecessary, - "anonymized paths are not present when unnecessary. Failed case: " + - present.anonymizedWhenUnnecessary); - ok(!present.httpWhenAnonymized, - "http URLs are anonymized when necessary. Failed case: " + - present.httpWhenAnonymized); - ok(!present.unanonymizedFilePathWhenAnonymized, - "file URLs are anonymized when necessary. Failed case: " + - present.unanonymizedFilePathWhenAnonymized); - - runNext(); + // If mgr.explicit failed, we won't have "heap-allocated" either. + if (haveExplicit) { + checkSpecialReport("heap-allocated", heapAllocatedAmounts); } + // vsize may be unreasonable if ASAN is enabled + checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); + checkSpecialReport("resident", residentAmounts); + + for (var reporter in jsGcHeapUsedGcThings) { + ok(jsGcHeapUsedGcThings[reporter] == 1); + } + checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", + jsGcHeapUsedGcThingsTotal); + + ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); + ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); + ok(present.places, "places is present"); + ok(present.images, "images is present"); + ok(present.xptiWorkingSet, "xpti-working-set is present"); + ok(present.atomTablesMain, "atom-tables/main is present"); + ok(present.sandboxLocation, "sandbox locations are present"); + ok(present.bigString, "large string is present"); + ok(present.smallString1, "small string 1 is present"); + ok(present.smallString2, "small string 2 is present"); + + ok(!present.anonymizedWhenUnnecessary, + "anonymized paths are not present when unnecessary. Failed case: " + + present.anonymizedWhenUnnecessary); + ok(!present.httpWhenAnonymized, + "http URLs are anonymized when necessary. Failed case: " + + present.httpWhenAnonymized); + ok(!present.unanonymizedFilePathWhenAnonymized, + "file URLs are anonymized when necessary. Failed case: " + + present.unanonymizedFilePathWhenAnonymized); // Reporter registration tests @@ -371,28 +352,27 @@ mgr.registerStrongReporter(reporterAndCallback); // Check the generated reports. - mgr.getReports(reporterAndCallback, null, - () => { - reporterAndCallback.finish(); - window.setTimeout(test_unregister_strong, 0, reporterAndCallback); - }, null, - /* anonymize = */ false); - } + mgr.getReportsForThisProcess(reporterAndCallback, null, + /* anonymize = */ false); + reporterAndCallback.finish(); - function test_unregister_strong(aReporterAndCallback) - { - mgr.unregisterStrongReporter(aReporterAndCallback); + // Unregistration works. + mgr.unregisterStrongReporter(reporterAndCallback); // The reporter was unregistered, hence there shouldn't be any reports from // the test reporter. - mgr.getReports(aReporterAndCallback, null, - () => { - aReporterAndCallback.finish(0); - runNext(); - }, null, - /* anonymize = */ false); + mgr.getReportsForThisProcess(reporterAndCallback, null, + /* anonymize = */ false); + reporterAndCallback.finish(0); } + test_register_strong(); + + // Check strong reporters a second time, to make sure a reporter can be + // re-registered. + test_register_strong(); + + // Check that you cannot register JS components as weak reporters. function test_register_weak() { let reporterAndCallback = new MemoryReporterAndCallback(); @@ -412,12 +392,9 @@ ok(ex.message.indexOf("NS_ERROR_") >= 0, "WrappedJS reporter got rejected: " + ex); } - - runNext(); } - // Kick-off the async tests. - runNext(); + test_register_weak(); ]]> diff --git a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul index 3452bbbc720..29c85a5c72a 100644 --- a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul +++ b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul @@ -24,8 +24,6 @@ const Ci = Components.interfaces; const Cu = Components.utils; - SimpleTest.waitForExplicitFinish(); - // Make a fake DB file. let file = Cc["@mozilla.org/file/directory_service;1"]. getService(Ci.nsIProperties). @@ -42,12 +40,11 @@ // them. It shouldn't crash. let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - mgr.getReports(function(){}, null, - () => { - ok(true, "didn't crash"); - SimpleTest.finish(); - }, null, - /* anonymize = */ false); + mgr.getReportsForThisProcess(function(){}, null, /* anonymize = */ false); + + // If we haven't crashed, we've passed, but the test harness requires that + // we explicitly check something. + ok(true, "didn't crash"); ]]> diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index e00f736f55c..39e3be823b1 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -205,7 +205,7 @@ interface nsIFinishReportingCallback : nsISupports void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(61de6dc7-ed11-4104-a577-79941f22f434)] +[scriptable, builtinclass, uuid(5e4eaa5a-4808-4b97-8005-e7cdc4d73693)] interface nsIMemoryReporterManager : nsISupports { /* @@ -220,7 +220,6 @@ interface nsIMemoryReporterManager : nsISupports * unregisterStrongReporter() at any point. */ void registerStrongReporter(in nsIMemoryReporter reporter); - void registerStrongAsyncReporter(in nsIMemoryReporter reporter); /* * Like registerReporter, but the Manager service will hold a weak reference @@ -230,7 +229,6 @@ interface nsIMemoryReporterManager : nsISupports * register your JavaScript components with registerStrongReporter(). */ void registerWeakReporter(in nsIMemoryReporter reporter); - void registerWeakAsyncReporter(in nsIMemoryReporter reporter); /* * Unregister the given memory reporter, which must have been registered with @@ -291,6 +289,14 @@ interface nsIMemoryReporterManager : nsISupports in boolean minimizeMemoryUsage, in AString DMDDumpIdent); + /* + * Get memory reports in the current process only. |handleReport| is called + * for each report. + */ + void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport, + in nsISupports handleReportData, + in boolean anonymize); + /* * As above, but if DMD is enabled and |DMDFile| is non-null then * write a DMD report to that file and close it. @@ -299,14 +305,7 @@ interface nsIMemoryReporterManager : nsISupports getReportsForThisProcessExtended(in nsIMemoryReporterCallback handleReport, in nsISupports handleReportData, in boolean anonymize, - in FILE DMDFile, - in nsIFinishReportingCallback finishReporting, - in nsISupports finishReportingData); - - /* - * Called by an asynchronous memory reporter upon completion. - */ - [noscript] void endReport(); + in FILE DMDFile); /* * The memory reporter manager, for the most part, treats reporters @@ -316,8 +315,9 @@ interface nsIMemoryReporterManager : nsISupports * interesting that we want external code (e.g. telemetry) to be able to rely * on them. * - * Note that these are not reporters and so getReports() does not look at - * them. However, distinguished amounts can be embedded in a reporter. + * Note that these are not reporters and so getReports() and + * getReportsForThisProcess() do not look at them. However, distinguished + * amounts can be embedded in a reporter. * * Access to these attributes can fail. In particular, some of them are not * available on all platforms. @@ -325,6 +325,11 @@ interface nsIMemoryReporterManager : nsISupports * If you add a new distinguished amount, please update * toolkit/components/aboutmemory/tests/test_memoryReporters.xul. * + * |explicit| (UNITS_BYTES) The total size of explicit memory allocations, + * both at the OS-level (eg. via mmap, VirtualAlloc) and at the heap level + * (eg. via malloc, calloc, operator new). It covers all heap allocations, + * but will miss any OS-level ones not covered by memory reporters. + * * |vsize| (UNITS_BYTES) The virtual size, i.e. the amount of address space * taken up. * @@ -373,6 +378,7 @@ interface nsIMemoryReporterManager : nsISupports * |pageFaultsHard| (UNITS_COUNT_CUMULATIVE) The number of hard (a.k.a. * major) page faults that have occurred since the process started. */ + readonly attribute int64_t explicit; readonly attribute int64_t vsize; readonly attribute int64_t vsizeMaxContiguous; readonly attribute int64_t resident; @@ -453,12 +459,10 @@ namespace mozilla { // Register a memory reporter. The manager service will hold a strong // reference to this reporter. XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter); -XPCOM_API(nsresult) RegisterStrongAsyncMemoryReporter(nsIMemoryReporter* aReporter); // Register a memory reporter. The manager service will hold a weak reference // to this reporter. XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter); -XPCOM_API(nsresult) RegisterWeakAsyncMemoryReporter(nsIMemoryReporter* aReporter); // Unregister a strong memory reporter. XPCOM_API(nsresult) UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter); @@ -516,6 +520,15 @@ nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn); } #if defined(MOZ_DMD) && !defined(MOZILLA_XPCOMRT_API) +namespace mozilla { +namespace dmd { +// This runs all the memory reporters in the current process but does nothing +// with the results; i.e. it does the minimal amount of work possible for DMD +// to do its thing. It does nothing with child processes. +void RunReportersForThisProcess(); +} +} + #if !defined(MOZ_MEMORY) #error "MOZ_DMD requires MOZ_MEMORY" #endif diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index eef9f403a59..4deb7883969 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1356,8 +1356,7 @@ nsMemoryReporterManager::nsMemoryReporterManager() , mSavedStrongReporters(nullptr) , mSavedWeakReporters(nullptr) , mNextGeneration(1) - , mPendingProcessesState(nullptr) - , mPendingReportersState(nullptr) + , mGetReportsState(nullptr) { } @@ -1415,11 +1414,11 @@ nsMemoryReporterManager::GetReportsExtended( uint32_t generation = mNextGeneration++; - if (mPendingProcessesState) { + if (mGetReportsState) { // A request is in flight. Don't start another one. And don't report // an error; just ignore it, and let the in-flight request finish. MEMORY_REPORTING_LOG("GetReports (gen=%u, s->gen=%u): abort\n", - generation, mPendingProcessesState->mGeneration); + generation, mGetReportsState->mGeneration); return NS_OK; } @@ -1430,15 +1429,16 @@ nsMemoryReporterManager::GetReportsExtended( if (concurrency < 1) { concurrency = 1; } - mPendingProcessesState = new PendingProcessesState(generation, - aAnonymize, - aMinimize, - concurrency, - aHandleReport, - aHandleReportData, - aFinishReporting, - aFinishReportingData, - aDMDDumpIdent); + mGetReportsState = new GetReportsState(generation, + aAnonymize, + aMinimize, + concurrency, + aHandleReport, + aHandleReportData, + aFinishReporting, + aFinishReportingData, + aDMDDumpIdent); + mGetReportsState->mChildrenPending = new nsTArray>(); if (aMinimize) { rv = MinimizeMemoryUsage(NS_NewRunnableMethod( @@ -1452,7 +1452,7 @@ nsMemoryReporterManager::GetReportsExtended( nsresult nsMemoryReporterManager::StartGettingReports() { - PendingProcessesState* s = mPendingProcessesState; + GetReportsState* s = mGetReportsState; nsresult rv; // Get reports for this process. @@ -1467,11 +1467,8 @@ nsMemoryReporterManager::StartGettingReports() } } #endif - - // This is async. GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData, - s->mAnonymize, parentDMDFile, - s->mFinishReporting, s->mFinishReportingData); + s->mAnonymize, parentDMDFile); nsTArray childWeakRefs; ContentParent::GetAll(childWeakRefs); @@ -1482,7 +1479,7 @@ nsMemoryReporterManager::StartGettingReports() // to be buffered and consume (possibly scarce) memory. for (size_t i = 0; i < childWeakRefs.Length(); ++i) { - s->mChildrenPending.AppendElement(childWeakRefs[i]); + s->mChildrenPending->AppendElement(childWeakRefs[i]); } nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID); @@ -1503,44 +1500,25 @@ nsMemoryReporterManager::StartGettingReports() s->mTimer.swap(timer); } + // The parent's report is done; make note of that, and start + // launching child process reports (if any). + EndProcessReport(s->mGeneration, true); return NS_OK; } -void -nsMemoryReporterManager::DispatchReporter( - nsIMemoryReporter* aReporter, bool aIsAsync, +NS_IMETHODIMP +nsMemoryReporterManager::GetReportsForThisProcess( nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - bool aAnonymize) + nsISupports* aHandleReportData, bool aAnonymize) { - MOZ_ASSERT(mPendingReportersState); - - // Grab refs to everything used in the lambda function. - nsRefPtr self = this; - nsCOMPtr reporter = aReporter; - nsCOMPtr handleReport = aHandleReport; - nsCOMPtr handleReportData = aHandleReportData; - - nsCOMPtr event = NS_NewRunnableFunction( - [self, reporter, aIsAsync, handleReport, handleReportData, aAnonymize] () { - reporter->CollectReports(handleReport, - handleReportData, - aAnonymize); - if (!aIsAsync) { - self->EndReport(); - } - }); - - NS_DispatchToMainThread(event); - mPendingReportersState->mReportsPending++; + return GetReportsForThisProcessExtended(aHandleReport, aHandleReportData, + aAnonymize, nullptr); } NS_IMETHODIMP nsMemoryReporterManager::GetReportsForThisProcessExtended( nsIHandleReportCallback* aHandleReport, nsISupports* aHandleReportData, - bool aAnonymize, FILE* aDMDFile, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData) + bool aAnonymize, FILE* aDMDFile) { // Memory reporters are not necessarily threadsafe, so this function must // be called from the main thread. @@ -1548,11 +1526,6 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( MOZ_CRASH(); } - if (NS_WARN_IF(mPendingReportersState)) { - // Report is already in progress. - return NS_ERROR_IN_PROGRESS; - } - #ifdef MOZ_DMD if (aDMDFile) { // Clear DMD's reportedness state before running the memory @@ -1563,58 +1536,39 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( MOZ_ASSERT(!aDMDFile); #endif - mPendingReportersState = new PendingReportersState( - aFinishReporting, aFinishReportingData, aDMDFile); - + nsCOMArray allReporters; { mozilla::MutexAutoLock autoLock(mMutex); - for (auto iter = mStrongReporters->Iter(); !iter.Done(); iter.Next()) { - DispatchReporter(iter.Key(), iter.Data(), - aHandleReport, aHandleReportData, aAnonymize); + nsRefPtrHashKey* entry = iter.Get(); + allReporters.AppendElement(entry->GetKey()); } - for (auto iter = mWeakReporters->Iter(); !iter.Done(); iter.Next()) { - nsCOMPtr reporter = iter.Key(); - DispatchReporter(reporter, iter.Data(), - aHandleReport, aHandleReportData, aAnonymize); + nsPtrHashKey* entry = iter.Get(); + allReporters.AppendElement(entry->GetKey()); } } + for (uint32_t i = 0; i < allReporters.Length(); i++) { + allReporters[i]->CollectReports(aHandleReport, aHandleReportData, + aAnonymize); + } - return NS_OK; -} - -NS_IMETHODIMP -nsMemoryReporterManager::EndReport() -{ - if (--mPendingReportersState->mReportsPending == 0) { #ifdef MOZ_DMD - if (mPendingReportersState->mDMDFile) { - nsMemoryInfoDumper::DumpDMDToFile(mPendingReportersState->mDMDFile); - } -#endif - if (mPendingProcessesState) { - // This is the parent process. - EndProcessReport(mPendingProcessesState->mGeneration, true); - } else { - mPendingReportersState->mFinishReporting->Callback( - mPendingReportersState->mFinishReportingData); - } - - delete mPendingReportersState; - mPendingReportersState = nullptr; + if (aDMDFile) { + return nsMemoryInfoDumper::DumpDMDToFile(aDMDFile); } +#endif return NS_OK; } -nsMemoryReporterManager::PendingProcessesState* +nsMemoryReporterManager::GetReportsState* nsMemoryReporterManager::GetStateForGeneration(uint32_t aGeneration) { // Memory reporting only happens on the main thread. MOZ_RELEASE_ASSERT(NS_IsMainThread()); - PendingProcessesState* s = mPendingProcessesState; + GetReportsState* s = mGetReportsState; if (!s) { // If we reach here, then: @@ -1651,7 +1605,7 @@ nsMemoryReporterManager::HandleChildReport( uint32_t aGeneration, const dom::MemoryReport& aChildReport) { - PendingProcessesState* s = GetStateForGeneration(aGeneration); + GetReportsState* s = GetStateForGeneration(aGeneration); if (!s) { return; } @@ -1671,7 +1625,7 @@ nsMemoryReporterManager::HandleChildReport( /* static */ bool nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild, - const PendingProcessesState* aState) + const GetReportsState* aState) { #ifdef MOZ_NUWA_PROCESS if (aChild->IsNuwaProcess()) { @@ -1709,7 +1663,7 @@ nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild, void nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) { - PendingProcessesState* s = GetStateForGeneration(aGeneration); + GetReportsState* s = GetStateForGeneration(aGeneration); if (!s) { return; } @@ -1722,29 +1676,29 @@ nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) aGeneration, s->mNumProcessesCompleted, aSuccess ? "completed" : "exited during report", s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); // Start pending children up to the concurrency limit. while (s->mNumProcessesRunning < s->mConcurrencyLimit && - !s->mChildrenPending.IsEmpty()) { + !s->mChildrenPending->IsEmpty()) { // Pop last element from s->mChildrenPending nsRefPtr nextChild; - nextChild.swap(s->mChildrenPending.LastElement()); - s->mChildrenPending.TruncateLength(s->mChildrenPending.Length() - 1); + nextChild.swap(s->mChildrenPending->LastElement()); + s->mChildrenPending->TruncateLength(s->mChildrenPending->Length() - 1); // Start report (if the child is still alive and not Nuwa). if (StartChildReport(nextChild, s)) { ++s->mNumProcessesRunning; MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): started child report" " (%u running, %u pending)\n", aGeneration, s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); } } // If all the child processes (if any) have reported, we can cancel // the timer (if started) and finish up. Otherwise, just return. if (s->mNumProcessesRunning == 0) { - MOZ_ASSERT(s->mChildrenPending.IsEmpty()); + MOZ_ASSERT(s->mChildrenPending->IsEmpty()); if (s->mTimer) { s->mTimer->Cancel(); } @@ -1756,15 +1710,15 @@ nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData) { nsMemoryReporterManager* mgr = static_cast(aData); - PendingProcessesState* s = mgr->mPendingProcessesState; + GetReportsState* s = mgr->mGetReportsState; // Release assert because: if the pointer is null we're about to // crash regardless of DEBUG, and this way the compiler doesn't // complain about unused variables. - MOZ_RELEASE_ASSERT(s, "mgr->mPendingProcessesState"); + MOZ_RELEASE_ASSERT(s, "mgr->mGetReportsState"); MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u; %u running, %u pending)\n", s->mGeneration, s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); // We don't bother sending any kind of cancellation message to the child // processes that haven't reported back. @@ -1779,43 +1733,25 @@ nsMemoryReporterManager::FinishReporting() MOZ_CRASH(); } - MOZ_ASSERT(mPendingProcessesState); + MOZ_ASSERT(mGetReportsState); MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u; %u processes reported)\n", - mPendingProcessesState->mGeneration, - mPendingProcessesState->mNumProcessesCompleted); + mGetReportsState->mGeneration, + mGetReportsState->mNumProcessesCompleted); - // Call this before deleting |mPendingProcessesState|. That way, if + // Call this before deleting |mGetReportsState|. That way, if // |mFinishReportData| calls GetReports(), it will silently abort, as // required. - nsresult rv = mPendingProcessesState->mFinishReporting->Callback( - mPendingProcessesState->mFinishReportingData); + nsresult rv = mGetReportsState->mFinishReporting->Callback( + mGetReportsState->mFinishReportingData); - delete mPendingProcessesState; - mPendingProcessesState = nullptr; + delete mGetReportsState; + mGetReportsState = nullptr; return rv; } -nsMemoryReporterManager::PendingProcessesState::PendingProcessesState( - uint32_t aGeneration, bool aAnonymize, bool aMinimize, - uint32_t aConcurrencyLimit, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - const nsAString& aDMDDumpIdent) - : mGeneration(aGeneration) - , mAnonymize(aAnonymize) - , mMinimize(aMinimize) - , mChildrenPending() - , mNumProcessesRunning(1) // reporting starts with the parent - , mNumProcessesCompleted(0) - , mConcurrencyLimit(aConcurrencyLimit) - , mHandleReport(aHandleReport) - , mHandleReportData(aHandleReportData) - , mFinishReporting(aFinishReporting) - , mFinishReportingData(aFinishReportingData) - , mDMDDumpIdent(aDMDDumpIdent) +nsMemoryReporterManager::GetReportsState::~GetReportsState() { + delete mChildrenPending; } static void @@ -1831,7 +1767,7 @@ CrashIfRefcountIsZero(nsISupports* aObj) nsresult nsMemoryReporterManager::RegisterReporterHelper( - nsIMemoryReporter* aReporter, bool aForce, bool aStrong, bool aIsAsync) + nsIMemoryReporter* aReporter, bool aForce, bool aStrong) { // This method is thread-safe. mozilla::MutexAutoLock autoLock(mMutex); @@ -1858,7 +1794,7 @@ nsMemoryReporterManager::RegisterReporterHelper( // if (aStrong) { nsCOMPtr kungFuDeathGrip = aReporter; - mStrongReporters->Put(aReporter, aIsAsync); + mStrongReporters->PutEntry(aReporter); CrashIfRefcountIsZero(aReporter); } else { CrashIfRefcountIsZero(aReporter); @@ -1871,7 +1807,7 @@ nsMemoryReporterManager::RegisterReporterHelper( // CollectReports(). return NS_ERROR_XPC_BAD_CONVERT_JS; } - mWeakReporters->Put(aReporter, aIsAsync); + mWeakReporters->PutEntry(aReporter); } return NS_OK; @@ -1881,32 +1817,14 @@ NS_IMETHODIMP nsMemoryReporterManager::RegisterStrongReporter(nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ true, - /* async = */ false); -} - -NS_IMETHODIMP -nsMemoryReporterManager::RegisterStrongAsyncReporter(nsIMemoryReporter* aReporter) -{ - return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ true, - /* async = */ true); + /* strong = */ true); } NS_IMETHODIMP nsMemoryReporterManager::RegisterWeakReporter(nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ false, - /* async = */ false); -} - -NS_IMETHODIMP -nsMemoryReporterManager::RegisterWeakAsyncReporter(nsIMemoryReporter* aReporter) -{ - return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ false, - /* async = */ true); + /* strong = */ false); } NS_IMETHODIMP @@ -1914,8 +1832,7 @@ nsMemoryReporterManager::RegisterStrongReporterEvenIfBlocked( nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ true, - /* strong = */ true, - /* async = */ false); + /* strong = */ true); } NS_IMETHODIMP @@ -1927,7 +1844,7 @@ nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter) MOZ_ASSERT(!mWeakReporters->Contains(aReporter)); if (mStrongReporters->Contains(aReporter)) { - mStrongReporters->Remove(aReporter); + mStrongReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1936,7 +1853,7 @@ nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter) // references that these reporters aren't expecting (which can keep them // alive longer than intended). if (mSavedStrongReporters && mSavedStrongReporters->Contains(aReporter)) { - mSavedStrongReporters->Remove(aReporter); + mSavedStrongReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1952,7 +1869,7 @@ nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) MOZ_ASSERT(!mStrongReporters->Contains(aReporter)); if (mWeakReporters->Contains(aReporter)) { - mWeakReporters->Remove(aReporter); + mWeakReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1961,7 +1878,7 @@ nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) // references that the old reporters aren't expecting (which can end up as // dangling pointers that lead to use-after-frees). if (mSavedWeakReporters && mSavedWeakReporters->Contains(aReporter)) { - mSavedWeakReporters->Remove(aReporter); + mSavedWeakReporters->RemoveEntry(aReporter); return NS_OK; } @@ -2010,6 +1927,84 @@ nsMemoryReporterManager::UnblockRegistrationAndRestoreOriginalReporters() return NS_OK; } +// This is just a wrapper for int64_t that implements nsISupports, so it can be +// passed to nsIMemoryReporter::CollectReports. +class Int64Wrapper final : public nsISupports +{ + ~Int64Wrapper() {} + +public: + NS_DECL_ISUPPORTS + Int64Wrapper() : mValue(0) + { + } + int64_t mValue; +}; + +NS_IMPL_ISUPPORTS0(Int64Wrapper) + +class ExplicitCallback final : public nsIHandleReportCallback +{ + ~ExplicitCallback() {} + +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, + int32_t aKind, int32_t aUnits, int64_t aAmount, + const nsACString& aDescription, + nsISupports* aWrappedExplicit) override + { + // Using the "heap-allocated" reporter here instead of + // nsMemoryReporterManager.heapAllocated goes against the usual + // pattern. But it's for a good reason: in tests, we can easily + // create artificial (i.e. deterministic) reporters -- which allows us + // to precisely test nsMemoryReporterManager.explicit -- but we can't + // do that for distinguished amounts. + if (aPath.EqualsLiteral("heap-allocated") || + (aKind == nsIMemoryReporter::KIND_NONHEAP && + PromiseFlatCString(aPath).Find("explicit") == 0)) { + Int64Wrapper* wrappedInt64 = static_cast(aWrappedExplicit); + wrappedInt64->mValue += aAmount; + } + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(ExplicitCallback, nsIHandleReportCallback) + +NS_IMETHODIMP +nsMemoryReporterManager::GetExplicit(int64_t* aAmount) +{ + if (NS_WARN_IF(!aAmount)) { + return NS_ERROR_INVALID_ARG; + } + *aAmount = 0; +#ifndef HAVE_JEMALLOC_STATS + return NS_ERROR_NOT_AVAILABLE; +#else + + // For each reporter we call CollectReports and filter out the + // non-explicit, non-NONHEAP measurements (except for "heap-allocated"). + // That's lots of wasted work, and we used to have a GetExplicitNonHeap() + // method which did this more efficiently, but it ended up being more + // trouble than it was worth. + + nsRefPtr handleReport = new ExplicitCallback(); + nsRefPtr wrappedExplicitSize = new Int64Wrapper(); + + // Anonymization doesn't matter here, because we're only summing all the + // reported values. Enable it anyway because it's slightly faster, since it + // doesn't have to get URLs, find notable strings, etc. + GetReportsForThisProcess(handleReport, wrappedExplicitSize, + /* anonymize = */ true); + + *aAmount = wrappedExplicitSize->mValue; + + return NS_OK; +#endif // HAVE_JEMALLOC_STATS +} + NS_IMETHODIMP nsMemoryReporterManager::GetVsize(int64_t* aVsize) { @@ -2378,61 +2373,61 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow, namespace mozilla { -#define GET_MEMORY_REPORTER_MANAGER(mgr) \ - nsRefPtr mgr = \ - nsMemoryReporterManager::GetOrCreate(); \ - if (!mgr) { \ - return NS_ERROR_FAILURE; \ - } - nsresult RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter) { // Hold a strong reference to the argument to make sure it gets released if // we return early below. nsCOMPtr reporter = aReporter; - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterStrongReporter(reporter); -} -nsresult -RegisterStrongAsyncMemoryReporter(nsIMemoryReporter* aReporter) -{ - // Hold a strong reference to the argument to make sure it gets released if - // we return early below. - nsCOMPtr reporter = aReporter; - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterStrongAsyncReporter(reporter); + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } + return mgr->RegisterStrongReporter(reporter); } nsresult RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->RegisterWeakReporter(aReporter); } -nsresult -RegisterWeakAsyncMemoryReporter(nsIMemoryReporter* aReporter) -{ - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterWeakAsyncReporter(aReporter); -} - nsresult UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->UnregisterStrongReporter(aReporter); } nsresult UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->UnregisterWeakReporter(aReporter); } +#define GET_MEMORY_REPORTER_MANAGER(mgr) \ + nsRefPtr mgr = \ + nsMemoryReporterManager::GetOrCreate(); \ + if (!mgr) { \ + return NS_ERROR_FAILURE; \ + } + // Macro for generating functions that register distinguished amount functions // with the memory reporter manager. #define DEFINE_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \ @@ -2488,3 +2483,45 @@ DEFINE_REGISTER_SIZE_OF_TAB(NonJS); #undef GET_MEMORY_REPORTER_MANAGER } // namespace mozilla + +#if defined(MOZ_DMD) + +namespace mozilla { +namespace dmd { + +class DoNothingCallback final : public nsIHandleReportCallback +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, + int32_t aKind, int32_t aUnits, int64_t aAmount, + const nsACString& aDescription, + nsISupports* aData) override + { + // Do nothing; the reporter has already reported to DMD. + return NS_OK; + } + +private: + ~DoNothingCallback() {} +}; + +NS_IMPL_ISUPPORTS(DoNothingCallback, nsIHandleReportCallback) + +void +RunReportersForThisProcess() +{ + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + + nsRefPtr doNothing = new DoNothingCallback(); + + mgr->GetReportsForThisProcess(doNothing, nullptr, /* anonymize = */ false); +} + +} // namespace dmd +} // namespace mozilla + +#endif // defined(MOZ_DMD) + diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 16af7b53f24..152e83a69b1 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -41,14 +41,14 @@ public: return static_cast(imgr.get()); } - typedef nsDataHashtable, bool> StrongReportersTable; - typedef nsDataHashtable, bool> WeakReportersTable; + typedef nsTHashtable> StrongReportersTable; + typedef nsTHashtable> WeakReportersTable; // Inter-process memory reporting proceeds as follows. // // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER) // synchronously gets memory reports for the current process, sets up some - // state (mPendingProcessesState) for when child processes report back -- + // state (mGetReportsState) for when child processes report back -- // including a timer -- and starts telling child processes to get memory // reports. Control then returns to the main event loop. // @@ -108,7 +108,7 @@ public: // is incomplete. // // Now, what what happens if a child process is created/destroyed in the - // middle of a request? Well, PendingProcessesState is initialized with an array + // middle of a request? Well, GetReportsState is initialized with an array // of child process actors as of when the report started. So... // // - If a process is created after reporting starts, it won't be sent a @@ -184,15 +184,10 @@ public: private: nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter, - bool aForce, bool aStrongRef, bool aIsAsync); + bool aForce, bool aStrongRef); nsresult StartGettingReports(); nsresult FinishReporting(); - void DispatchReporter(nsIMemoryReporter* aReporter, bool aIsAsync, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - bool aAnonymize); - static void TimeoutCallback(nsITimer* aTimer, void* aData); // Note: this timeout needs to be long enough to allow for the // possibility of DMD reports and/or running on a low-end phone. @@ -210,16 +205,16 @@ private: uint32_t mNextGeneration; - // Used to keep track of state of which processes are currently running and - // waiting to run memory reports. Holds references to parameters needed when - // requesting a memory report and finishing reporting. - struct PendingProcessesState + struct GetReportsState { uint32_t mGeneration; bool mAnonymize; bool mMinimize; nsCOMPtr mTimer; - nsTArray> mChildrenPending; + // This is a pointer to an nsTArray because otherwise C++ is + // unhappy unless this header includes ContentParent.h, which not + // everything that includes this header knows how to find. + nsTArray>* mChildrenPending; uint32_t mNumProcessesRunning; uint32_t mNumProcessesCompleted; uint32_t mConcurrencyLimit; @@ -229,52 +224,39 @@ private: nsCOMPtr mFinishReportingData; nsString mDMDDumpIdent; - PendingProcessesState(uint32_t aGeneration, bool aAnonymize, bool aMinimize, - uint32_t aConcurrencyLimit, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - const nsAString& aDMDDumpIdent); - }; - - // Used to keep track of the state of the asynchronously run memory - // reporters. The callback and file handle used when all memory reporters - // have finished are also stored here. - struct PendingReportersState - { - // Number of memory reporters currently running. - uint32_t mReportsPending; - - // Callback for when all memory reporters have completed. - nsCOMPtr mFinishReporting; - nsCOMPtr mFinishReportingData; - - // File handle to write a DMD report to if requested. - FILE* mDMDFile; - - PendingReportersState(nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - FILE* aDMDFile) - : mReportsPending(0) + GetReportsState(uint32_t aGeneration, bool aAnonymize, bool aMinimize, + uint32_t aConcurrencyLimit, + nsIHandleReportCallback* aHandleReport, + nsISupports* aHandleReportData, + nsIFinishReportingCallback* aFinishReporting, + nsISupports* aFinishReportingData, + const nsAString& aDMDDumpIdent) + : mGeneration(aGeneration) + , mAnonymize(aAnonymize) + , mMinimize(aMinimize) + , mChildrenPending(nullptr) + , mNumProcessesRunning(1) // reporting starts with the parent + , mNumProcessesCompleted(0) + , mConcurrencyLimit(aConcurrencyLimit) + , mHandleReport(aHandleReport) + , mHandleReportData(aHandleReportData) , mFinishReporting(aFinishReporting) , mFinishReportingData(aFinishReportingData) - , mDMDFile(aDMDFile) + , mDMDDumpIdent(aDMDDumpIdent) { } + + ~GetReportsState(); }; // When this is non-null, a request is in flight. Note: We use manual // new/delete for this because its lifetime doesn't match block scope or // anything like that. - PendingProcessesState* mPendingProcessesState; + GetReportsState* mGetReportsState; - // This is reinitialized each time a call to GetReports is initiated. - PendingReportersState* mPendingReportersState; - - PendingProcessesState* GetStateForGeneration(uint32_t aGeneration); + GetReportsState* GetStateForGeneration(uint32_t aGeneration); static bool StartChildReport(mozilla::dom::ContentParent* aChild, - const PendingProcessesState* aState); + const GetReportsState* aState); }; #define NS_MEMORY_REPORTER_MANAGER_CID \