diff --git a/accessible/src/jsat/OutputGenerator.jsm b/accessible/src/jsat/OutputGenerator.jsm
index f340a245c0d..3a7ecec1f53 100644
--- a/accessible/src/jsat/OutputGenerator.jsm
+++ b/accessible/src/jsat/OutputGenerator.jsm
@@ -220,7 +220,12 @@ this.OutputGenerator = {
if (!typeName || typeName === 'text') {
return;
}
- aDesc.push(gStringBundle.GetStringFromName('textInputType_' + typeName));
+ typeName = 'textInputType_' + typeName;
+ try {
+ aDesc.push(gStringBundle.GetStringFromName(typeName));
+ } catch (x) {
+ Logger.warning('Failed to get a string from a bundle for', typeName);
+ }
},
get outputOrder() {
diff --git a/accessible/tests/mochitest/jsat/test_utterance_order.html b/accessible/tests/mochitest/jsat/test_utterance_order.html
index 2ab7e40c9df..bb661893bbc 100644
--- a/accessible/tests/mochitest/jsat/test_utterance_order.html
+++ b/accessible/tests/mochitest/jsat/test_utterance_order.html
@@ -83,6 +83,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
"Column 1 Row 1", "Fruits and vegetables",
"table with 1 column and 1 row"
]]
+ }, {
+ accOrElmOrID: "date",
+ expected: [["date entry", "2011-09-29"], ["2011-09-29", "date entry"]]
}, {
accOrElmOrID: "email",
expected: [
@@ -302,6 +305,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
+
diff --git a/browser/app/profile/extensions/Makefile.in b/browser/app/profile/extensions/Makefile.in
deleted file mode 100644
index 3cac5851b51..00000000000
--- a/browser/app/profile/extensions/Makefile.in
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DISTROEXT = $(abspath $(FINAL_TARGET))/distribution/extensions
-
-include $(topsrcdir)/config/config.mk
-
-ifneq (,$(filter beta,$(MOZ_UPDATE_CHANNEL)))
-EXTENSIONS = \
- $(NULL)
-
-all_xpis = $(foreach dir,$(EXTENSIONS),$(DISTROEXT)/$(dir).xpi)
-libs:: $(all_xpis)
-GARBAGE += $(all_xpis)
-
-define pp_one
-$(2) := $(2)
-$(2)_PATH := $(dir $(2))
-$(2)_TARGET := libs-$(1)
-PP_TARGETS += $(2)
-endef
-$(foreach d,$(EXTENSIONS), \
- $(foreach in,$(shell cd $(srcdir) ; find $(d) -name '*.in'), \
- $(eval $(call pp_one,$(d),$(in))) \
- ) \
-)
-
-endif
-
-include $(topsrcdir)/config/rules.mk
-
-$(all_xpis): $(DISTROEXT)/%.xpi: $(call mkdir_deps,$(DISTROEXT)) libs-%
- cd $* && \
- $(ZIP) -r9XD $@ * -x \*.in -x \*.mkdir.done
- cd $(abspath $(srcdir)/$*) && \
- $(ZIP) -r9XD $@ * -x \*.in -x \*.mkdir.done
-
-.PHONY: $(all_xpis:.xpi=)
diff --git a/browser/devtools/webconsole/test/browser.ini b/browser/devtools/webconsole/test/browser.ini
index dc441e50d45..2e092f70f0b 100644
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -185,6 +185,8 @@ support-files =
[browser_webconsole_bug_630733_response_redirect_headers.js]
[browser_webconsole_bug_632275_getters_document_width.js]
[browser_webconsole_bug_632347_iterators_generators.js]
+# Too many intermittent timeouts (bug 935277)
+skip-if = os == "linux"
[browser_webconsole_bug_632817.js]
[browser_webconsole_bug_642108_pruneTest.js]
[browser_webconsole_bug_642615_autocomplete.js]
diff --git a/build/Makefile.in b/build/Makefile.in
index d47fef04487..768e63da945 100644
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -47,6 +47,10 @@ DEFINES += \
-DACCEPTED_MAR_CHANNEL_IDS="$(ACCEPTED_MAR_CHANNEL_IDS)" \
$(NULL)
+ifeq ($(MOZ_BUILD_APP),browser)
+DEFINES += -DMOZ_BUILD_APP_IS_BROWSER
+endif
+
ifdef MOZ_APP_PROFILE
DEFINES += -DMOZ_APP_PROFILE="$(MOZ_APP_PROFILE)"
endif
diff --git a/build/application.ini b/build/application.ini
index bb27da61f6f..7d816a49195 100644
--- a/build/application.ini
+++ b/build/application.ini
@@ -1,8 +1,14 @@
#if MOZ_APP_STATIC_INI
+#ifdef MOZ_BUILD_APP_IS_BROWSER
+; This file is not used. If you modify it and want the application to use
+; your modifications, move it under the browser/ subdirectory and start with
+; the "-app /path/to/browser/application.ini" argument.
+#else
; This file is not used. If you modify it and want the application to use
; your modifications, start with the "-app /path/to/application.ini"
; argument.
#endif
+#endif
#if 0
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
diff --git a/content/base/src/nsDOMFile.cpp b/content/base/src/nsDOMFile.cpp
index 7fdef4474c3..48f69f49f5d 100644
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@@ -645,15 +646,12 @@ nsDOMMemoryFile::DataOwner::sMemoryReporterRegistered;
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(DOMMemoryFileDataOwnerMallocSizeOf)
class nsDOMMemoryFileDataOwnerMemoryReporter MOZ_FINAL
- : public nsIMemoryReporter
+ : public MemoryMultiReporter
{
- NS_DECL_THREADSAFE_ISUPPORTS
-
- NS_IMETHOD GetName(nsACString& aName)
- {
- aName.AssignASCII("dom-memory-file-data-owner");
- return NS_OK;
- }
+public:
+ nsDOMMemoryFileDataOwnerMemoryReporter()
+ : MemoryMultiReporter("dom-memory-file-data-owner")
+ {}
NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCallback,
nsISupports *aClosure)
@@ -728,9 +726,6 @@ class nsDOMMemoryFileDataOwnerMemoryReporter MOZ_FINAL
}
};
-NS_IMPL_ISUPPORTS1(nsDOMMemoryFileDataOwnerMemoryReporter,
- nsIMemoryReporter)
-
/* static */ void
nsDOMMemoryFile::DataOwner::EnsureMemoryReporterRegistered()
{
diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp
index bc94b0d8e25..a989affc923 100644
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1080,11 +1080,15 @@ struct MessageManagerReferentCount
namespace mozilla {
namespace dom {
-class MessageManagerReporter MOZ_FINAL : public nsIMemoryReporter
+class MessageManagerReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIMEMORYREPORTER
+ MessageManagerReporter()
+ : MemoryMultiReporter("message-manager")
+ {}
+
+ NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCallback,
+ nsISupports* aData);
static const size_t kSuspectReferentCount = 300;
protected:
@@ -1092,8 +1096,6 @@ protected:
MessageManagerReferentCount* aReferentCount);
};
-NS_IMPL_ISUPPORTS1(MessageManagerReporter, nsIMemoryReporter)
-
static PLDHashOperator
CollectMessageListenerData(const nsAString& aKey,
nsAutoTObserverArray* aListeners,
@@ -1153,13 +1155,6 @@ MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
}
}
-NS_IMETHODIMP
-MessageManagerReporter::GetName(nsACString& aName)
-{
- aName.AssignLiteral("message-manager");
- return NS_OK;
-}
-
static nsresult
ReportReferentCount(const char* aManagerType,
const MessageManagerReferentCount& aReferentCount,
diff --git a/content/canvas/src/WebGLContextReporter.cpp b/content/canvas/src/WebGLContextReporter.cpp
index 8b42f8b475b..f98153d4504 100644
--- a/content/canvas/src/WebGLContextReporter.cpp
+++ b/content/canvas/src/WebGLContextReporter.cpp
@@ -11,22 +11,17 @@ using namespace mozilla;
NS_IMPL_ISUPPORTS1(WebGLMemoryPressureObserver, nsIObserver)
-class WebGLMemoryReporter MOZ_FINAL : public nsIMemoryReporter
+class WebGLMemoryReporter MOZ_FINAL : public MemoryMultiReporter
{
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIMEMORYREPORTER
+public:
+ WebGLMemoryReporter()
+ : MemoryMultiReporter("webgl")
+ {}
+
+ NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
+ nsISupports* aClosure);
};
-NS_IMPL_ISUPPORTS1(WebGLMemoryReporter, nsIMemoryReporter)
-
-NS_IMETHODIMP
-WebGLMemoryReporter::GetName(nsACString &aName)
-{
- aName.AssignLiteral("webgl");
- return NS_OK;
-}
-
NS_IMETHODIMP
WebGLMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
nsISupports* aClosure)
diff --git a/content/media/MediaDecoder.cpp b/content/media/MediaDecoder.cpp
index c0de05d0050..6dc305faadc 100644
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -1763,16 +1763,12 @@ MediaDecoder::IsAppleMP3Enabled()
}
#endif
-class MediaReporter MOZ_FINAL : public nsIMemoryReporter
+class MediaReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
- NS_DECL_ISUPPORTS
-
- NS_IMETHOD GetName(nsACString& aName)
- {
- aName.AssignLiteral("media");
- return NS_OK;
- }
+ MediaReporter()
+ : MemoryMultiReporter("media")
+ {}
NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
nsISupports* aClosure)
@@ -1800,8 +1796,6 @@ public:
}
};
-NS_IMPL_ISUPPORTS1(MediaReporter, nsIMemoryReporter)
-
MediaDecoderOwner*
MediaDecoder::GetOwner()
{
diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp
index 755e479cf85..26b54a6078a 100644
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -433,7 +433,7 @@ ContentChild::InitXPCOM()
}
PMemoryReportRequestChild*
-ContentChild::AllocPMemoryReportRequestChild()
+ContentChild::AllocPMemoryReportRequestChild(const uint32_t& generation)
{
return new MemoryReportRequestChild();
}
@@ -480,7 +480,9 @@ NS_IMPL_ISUPPORTS1(
)
bool
-ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child)
+ContentChild::RecvPMemoryReportRequestConstructor(
+ PMemoryReportRequestChild* child,
+ const uint32_t& generation)
{
nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
@@ -504,7 +506,7 @@ ContentChild::RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* chi
r->CollectReports(cb, wrappedReports);
}
- child->Send__delete__(child, reports);
+ child->Send__delete__(child, generation, reports);
return true;
}
diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h
index 40dfbe5ca7f..71e703a02e7 100644
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -111,13 +111,14 @@ public:
virtual bool DeallocPIndexedDBChild(PIndexedDBChild* aActor);
virtual PMemoryReportRequestChild*
- AllocPMemoryReportRequestChild();
+ AllocPMemoryReportRequestChild(const uint32_t& generation);
virtual bool
DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor);
virtual bool
- RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child);
+ RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child,
+ const uint32_t& generation);
virtual bool
RecvAudioChannelNotify();
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index 3ae773bb5b3..c2a2366dd09 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -78,6 +78,7 @@
#include "nsISupportsPrimitives.h"
#include "nsIURIFixup.h"
#include "nsIWindowWatcher.h"
+#include "nsMemoryReporterManager.h"
#include "nsServiceManagerUtils.h"
#include "nsStyleSheetService.h"
#include "nsThreadUtils.h"
@@ -160,61 +161,13 @@ namespace dom {
#define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
-// This represents all the memory reports provided by a child process.
-class ChildReporter MOZ_FINAL : public nsIMemoryReporter
-{
-public:
- ChildReporter(const InfallibleTArray& childReports)
- {
- for (uint32_t i = 0; i < childReports.Length(); i++) {
- MemoryReport r(childReports[i].process(),
- childReports[i].path(),
- childReports[i].kind(),
- childReports[i].units(),
- childReports[i].amount(),
- childReports[i].desc());
-
- // Child reports have a non-empty process.
- MOZ_ASSERT(!r.process().IsEmpty());
-
- mChildReports.AppendElement(r);
- }
- }
-
- NS_DECL_ISUPPORTS
-
- NS_IMETHOD GetName(nsACString& name)
- {
- name.AssignLiteral("content-child");
- return NS_OK;
- }
-
- NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
- nsISupports* aClosure)
- {
- for (uint32_t i = 0; i < mChildReports.Length(); i++) {
- nsresult rv;
- MemoryReport r = mChildReports[i];
- rv = aCb->Callback(r.process(), r.path(), r.kind(), r.units(),
- r.amount(), r.desc(), aClosure);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- return NS_OK;
- }
-
- private:
- InfallibleTArray mChildReports;
-};
-
-NS_IMPL_ISUPPORTS1(ChildReporter, nsIMemoryReporter)
-
class MemoryReportRequestParent : public PMemoryReportRequestParent
{
public:
MemoryReportRequestParent();
virtual ~MemoryReportRequestParent();
- virtual bool Recv__delete__(const InfallibleTArray& report);
+ virtual bool Recv__delete__(const uint32_t& generation, const InfallibleTArray& report);
private:
ContentParent* Owner()
{
@@ -228,9 +181,13 @@ MemoryReportRequestParent::MemoryReportRequestParent()
}
bool
-MemoryReportRequestParent::Recv__delete__(const InfallibleTArray& childReports)
+MemoryReportRequestParent::Recv__delete__(const uint32_t& generation, const InfallibleTArray& childReports)
{
- Owner()->SetChildMemoryReports(childReports);
+ nsRefPtr mgr =
+ nsMemoryReporterManager::GetOrCreate();
+ if (mgr) {
+ mgr->HandleChildReports(generation, childReports);
+ }
return true;
}
@@ -239,29 +196,21 @@ MemoryReportRequestParent::~MemoryReportRequestParent()
MOZ_COUNT_DTOR(MemoryReportRequestParent);
}
-/**
- * A memory reporter for ContentParent objects themselves.
- */
-class ContentParentMemoryReporter MOZ_FINAL : public nsIMemoryReporter
+// A memory reporter for ContentParent objects themselves.
+class ContentParentsMemoryReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIMEMORYREPORTER
- NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf)
+ ContentParentsMemoryReporter()
+ : MemoryMultiReporter("content-parents")
+ {}
+
+ NS_IMETHOD CollectReports(nsIMemoryReporterCallback* cb,
+ nsISupports* aClosure);
};
-NS_IMPL_ISUPPORTS1(ContentParentMemoryReporter, nsIMemoryReporter)
-
NS_IMETHODIMP
-ContentParentMemoryReporter::GetName(nsACString& aName)
-{
- aName.AssignLiteral("ContentParents");
- return NS_OK;
-}
-
-NS_IMETHODIMP
-ContentParentMemoryReporter::CollectReports(nsIMemoryReporterCallback* cb,
- nsISupports* aClosure)
+ContentParentsMemoryReporter::CollectReports(nsIMemoryReporterCallback* cb,
+ nsISupports* aClosure)
{
nsAutoTArray cps;
ContentParent::GetAllEvenIfDead(cps);
@@ -511,8 +460,7 @@ ContentParent::StartUp()
return;
}
- nsRefPtr mr = new ContentParentMemoryReporter();
- NS_RegisterMemoryReporter(mr);
+ NS_RegisterMemoryReporter(new ContentParentsMemoryReporter());
sCanLaunchSubprocesses = true;
@@ -1043,7 +991,6 @@ ContentParent::ShutDownProcess(bool aCloseWithError)
// shut down the cycle collector. But by then it's too late to release any
// CC'ed objects, so we need to null them out here, while we still can. See
// bug 899761.
- mChildReporter = nullptr;
if (mMessageManager) {
mMessageManager->Disconnect();
mMessageManager = nullptr;
@@ -1218,8 +1165,12 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
ppm->Disconnect();
}
- // unregister the child memory reporter
- UnregisterChildMemoryReporter();
+ // Tell the memory reporter manager that this ContentParent is going away.
+ nsRefPtr mgr =
+ nsMemoryReporterManager::GetOrCreate();
+ if (mgr) {
+ mgr->DecrementNumChildProcesses();
+ }
// remove the global remote preferences observers
Preferences::RemoveObserver(this, "");
@@ -1426,6 +1377,13 @@ ContentParent::ContentParent(mozIApplication* aApp,
IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
+ // Tell the memory reporter manager that this ContentParent exists.
+ nsRefPtr mgr =
+ nsMemoryReporterManager::GetOrCreate();
+ if (mgr) {
+ mgr->IncrementNumChildProcesses();
+ }
+
std::vector extraArgs;
if (aIsNuwaProcess) {
extraArgs.push_back("-nuwa");
@@ -2037,7 +1995,7 @@ ContentParent::Observe(nsISupports* aSubject,
return NS_ERROR_NOT_AVAILABLE;
}
else if (!strcmp(aTopic, "child-memory-reporter-request")) {
- unused << SendPMemoryReportRequestConstructor();
+ unused << SendPMemoryReportRequestConstructor((uint32_t)(uintptr_t)aData);
}
else if (!strcmp(aTopic, "child-gc-request")){
unused << SendGarbageCollect();
@@ -2481,7 +2439,7 @@ ContentParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor)
}
PMemoryReportRequestParent*
-ContentParent::AllocPMemoryReportRequestParent()
+ContentParent::AllocPMemoryReportRequestParent(const uint32_t& generation)
{
MemoryReportRequestParent* parent = new MemoryReportRequestParent();
return parent;
@@ -2494,32 +2452,6 @@ ContentParent::DeallocPMemoryReportRequestParent(PMemoryReportRequestParent* act
return true;
}
-void
-ContentParent::SetChildMemoryReports(const InfallibleTArray& childReports)
-{
- nsCOMPtr mgr =
- do_GetService("@mozilla.org/memory-reporter-manager;1");
-
- if (mChildReporter)
- mgr->UnregisterReporter(mChildReporter);
-
- mChildReporter = new ChildReporter(childReports);
- mgr->RegisterReporter(mChildReporter);
-
- nsCOMPtr obs =
- do_GetService("@mozilla.org/observer-service;1");
- if (obs)
- obs->NotifyObservers(nullptr, "child-memory-reporter-update", nullptr);
-}
-
-void
-ContentParent::UnregisterChildMemoryReporter()
-{
- nsCOMPtr mgr =
- do_GetService("@mozilla.org/memory-reporter-manager;1");
- mgr->UnregisterReporter(mChildReporter);
-}
-
PTestShellParent*
ContentParent::AllocPTestShellParent()
{
diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h
index c291d3965b9..cb2ca2751c3 100644
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -140,10 +140,6 @@ public:
bool IsAlive();
bool IsForApp();
- void SetChildMemoryReports(const InfallibleTArray&
- childReports);
- void UnregisterChildMemoryReporter();
-
GeckoChildProcessHost* Process() {
return mSubprocess;
}
@@ -340,7 +336,7 @@ private:
virtual bool DeallocPIndexedDBParent(PIndexedDBParent* aActor);
- virtual PMemoryReportRequestParent* AllocPMemoryReportRequestParent();
+ virtual PMemoryReportRequestParent* AllocPMemoryReportRequestParent(const uint32_t& generation);
virtual bool DeallocPMemoryReportRequestParent(PMemoryReportRequestParent* actor);
virtual PTestShellParent* AllocPTestShellParent();
@@ -500,14 +496,6 @@ private:
uint64_t mChildID;
int32_t mGeolocationWatchID;
- // This is a reporter holding the reports from the child's last
- // "child-memory-reporter-update" notification. To update this, one can
- // broadcast the topic "child-memory-reporter-request" using the
- // nsIObserverService.
- //
- // Note that this assumes there is at most one child process at a time!
- nsCOMPtr mChildReporter;
-
nsString mAppManifestURL;
/**
diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl
index 641fe30482c..59c9184ce96 100644
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -231,7 +231,7 @@ child:
*/
async SetProcessPrivileges(ChildPrivileges privs);
- PMemoryReportRequest();
+ PMemoryReportRequest(uint32_t generation);
/**
* Notify the AudioChannelService in the child processes.
diff --git a/dom/ipc/PMemoryReportRequest.ipdl b/dom/ipc/PMemoryReportRequest.ipdl
index f2f95165449..530f06940cf 100644
--- a/dom/ipc/PMemoryReportRequest.ipdl
+++ b/dom/ipc/PMemoryReportRequest.ipdl
@@ -21,7 +21,7 @@ protocol PMemoryReportRequest {
manager PContent;
parent:
- __delete__(MemoryReport[] report);
+ __delete__(uint32_t generation, MemoryReport[] report);
};
}
diff --git a/dom/locales/en-US/chrome/accessibility/AccessFu.properties b/dom/locales/en-US/chrome/accessibility/AccessFu.properties
index 2d0d2229ddf..3d3560ab5e7 100644
--- a/dom/locales/en-US/chrome/accessibility/AccessFu.properties
+++ b/dom/locales/en-US/chrome/accessibility/AccessFu.properties
@@ -73,6 +73,7 @@ definition = definition
textarea = text area
# Text input types
+textInputType_date = date
textInputType_email = e-mail
textInputType_search = search
textInputType_tel = telephone
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index 1fa8c10cec3..d5583d7a420 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1950,7 +1950,7 @@ struct WorkerPrivate::TimeoutInfo
bool mCanceled;
};
-class WorkerPrivate::MemoryReporter MOZ_FINAL : public nsIMemoryReporter
+class WorkerPrivate::MemoryReporter MOZ_FINAL : public MemoryMultiReporter
{
friend class WorkerPrivate;
@@ -1960,10 +1960,9 @@ class WorkerPrivate::MemoryReporter MOZ_FINAL : public nsIMemoryReporter
bool mAlreadyMappedToAddon;
public:
- NS_DECL_THREADSAFE_ISUPPORTS
-
MemoryReporter(WorkerPrivate* aWorkerPrivate)
- : mMutex(aWorkerPrivate->mMutex), mWorkerPrivate(aWorkerPrivate),
+ : MemoryMultiReporter("workers"),
+ mMutex(aWorkerPrivate->mMutex), mWorkerPrivate(aWorkerPrivate),
mAlreadyMappedToAddon(false)
{
aWorkerPrivate->AssertIsOnWorkerThread();
@@ -1983,13 +1982,6 @@ public:
NS_LITERAL_CSTRING(")/");
}
- NS_IMETHOD
- GetName(nsACString& aName)
- {
- aName.AssignLiteral("workers");
- return NS_OK;
- }
-
NS_IMETHOD
CollectReports(nsIMemoryReporterCallback* aCallback,
nsISupports* aClosure)
@@ -2072,8 +2064,6 @@ private:
}
};
-NS_IMPL_ISUPPORTS1(WorkerPrivate::MemoryReporter, nsIMemoryReporter)
-
template
WorkerPrivateParent::WorkerPrivateParent(
JSContext* aCx,
diff --git a/gfx/src/nsFont.h b/gfx/src/nsFont.h
index f579ae5c629..6e885ac30be 100644
--- a/gfx/src/nsFont.h
+++ b/gfx/src/nsFont.h
@@ -48,7 +48,7 @@ struct NS_GFX nsFont {
// Force this font to not be considered a 'generic' font, even if
// the name is the same as a CSS generic font family.
- uint8_t systemFont;
+ bool systemFont;
// The variant of the font (normal, small-caps)
uint8_t variant;
diff --git a/gfx/thebes/d3dkmtQueryStatistics.h b/gfx/thebes/d3dkmtQueryStatistics.h
index 03c6601517c..9305f1dbddb 100644
--- a/gfx/thebes/d3dkmtQueryStatistics.h
+++ b/gfx/thebes/d3dkmtQueryStatistics.h
@@ -6,6 +6,9 @@
* Windows 8 RC SDK. The work for this file itself was based on the one in ProcessHacker at
* http://processhacker.svn.sourceforge.net/viewvc/processhacker/2.x/trunk/plugins/ExtendedTools/d3dkmt.h?revision=4758&view=markup
* For more details see Mozilla Bug 689870.
+ * [Bug 917496 indicates that some of these structs may not match reality, and
+ * therefore should not be trusted. See the reference to bug 917496 in
+ * gfxWindowsPlatform.cpp.]
*/
typedef struct _D3DKMTQS_COUNTER
diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp
index c8b869b2b29..1b08a4987d1 100644
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -631,21 +631,13 @@ PR_STATIC_ASSERT(uint32_t(CAIRO_SURFACE_TYPE_SKIA) ==
static int64_t gSurfaceMemoryUsed[gfxSurfaceTypeMax] = { 0 };
-class SurfaceMemoryReporter MOZ_FINAL :
- public nsIMemoryReporter
+class SurfaceMemoryReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
SurfaceMemoryReporter()
+ : MemoryMultiReporter("gfx-surface")
{ }
- NS_DECL_ISUPPORTS
-
- NS_IMETHOD GetName(nsACString &name)
- {
- name.AssignLiteral("gfx-surface");
- return NS_OK;
- }
-
NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb,
nsISupports *aClosure)
{
@@ -673,8 +665,6 @@ public:
}
};
-NS_IMPL_ISUPPORTS1(SurfaceMemoryReporter, nsIMemoryReporter)
-
void
gfxASurface::RecordMemoryUsedForSurfaceType(gfxSurfaceType aType,
int32_t aBytes)
diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp
index 45886688bbe..f9cedc2daee 100644
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1360,17 +1360,8 @@ gfxFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
* shaped-word caches to free up memory.
*/
-NS_IMPL_ISUPPORTS1(gfxFontCache::MemoryReporter, nsIMemoryReporter)
-
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(FontCacheMallocSizeOf)
-NS_IMETHODIMP
-gfxFontCache::MemoryReporter::GetName(nsACString &aName)
-{
- aName.AssignLiteral("font-cache");
- return NS_OK;
-}
-
NS_IMETHODIMP
gfxFontCache::MemoryReporter::CollectReports
(nsIMemoryReporterCallback* aCb,
diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h
index b302e950436..fc43d51de72 100644
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -950,12 +950,15 @@ public:
FontCacheSizes* aSizes) const;
protected:
- class MemoryReporter MOZ_FINAL
- : public nsIMemoryReporter
+ class MemoryReporter MOZ_FINAL : public mozilla::MemoryMultiReporter
{
public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIMEMORYREPORTER
+ MemoryReporter()
+ : MemoryMultiReporter("font-cache")
+ {}
+
+ NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
+ nsISupports* aClosure);
};
// Observer for notifications that the font cache cares about
diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp
index ed779ce2068..58c16b7c658 100644
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -71,16 +71,11 @@ gfxFontListPrefObserver::Observe(nsISupports *aSubject,
return NS_OK;
}
-NS_IMPL_ISUPPORTS1(gfxPlatformFontList::MemoryReporter, nsIMemoryReporter)
-
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(FontListMallocSizeOf)
-NS_IMETHODIMP
-gfxPlatformFontList::MemoryReporter::GetName(nsACString &aName)
-{
- aName.AssignLiteral("font-list");
- return NS_OK;
-}
+gfxPlatformFontList::MemoryReporter::MemoryReporter()
+ : MemoryMultiReporter("font-list")
+{}
NS_IMETHODIMP
gfxPlatformFontList::MemoryReporter::CollectReports
diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h
index 4f3858c1001..6b95f8b1efc 100644
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -178,12 +178,12 @@ public:
void RemoveCmap(const gfxCharacterMap *aCharMap);
protected:
- class MemoryReporter MOZ_FINAL
- : public nsIMemoryReporter
+ class MemoryReporter MOZ_FINAL : public mozilla::MemoryMultiReporter
{
public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIMEMORYREPORTER
+ MemoryReporter();
+ NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb,
+ nsISupports *aClosure);
};
gfxPlatformFontList(bool aNeedFullnamePostscriptNames = true);
diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp
index a82943cedc5..f8453504d5f 100644
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -207,70 +207,63 @@ typedef HRESULT (WINAPI*D3D11CreateDeviceFunc)(
ID3D11DeviceContext *ppImmediateContext
);
-class GPUAdapterReporter : public nsIMemoryReporter {
-
+class GPUAdapterReporter : public MemoryMultiReporter
+{
// Callers must Release the DXGIAdapter after use or risk mem-leak
static bool GetDXGIAdapter(IDXGIAdapter **DXGIAdapter)
{
ID3D10Device1 *D2D10Device;
IDXGIDevice *DXGIDevice;
bool result = false;
-
+
if (D2D10Device = mozilla::gfx::Factory::GetDirect3D10Device()) {
if (D2D10Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&DXGIDevice) == S_OK) {
result = (DXGIDevice->GetAdapter(DXGIAdapter) == S_OK);
DXGIDevice->Release();
}
}
-
+
return result;
}
-
-public:
- NS_DECL_ISUPPORTS
- // nsIMemoryReporter abstract method implementation
- NS_IMETHOD
- GetName(nsACString &aName)
- {
- aName.AssignLiteral("gpuadapter");
- return NS_OK;
- }
-
- // nsIMemoryReporter abstract method implementation
+public:
+ GPUAdapterReporter()
+ : MemoryMultiReporter("gpu-adapter")
+ {}
+
NS_IMETHOD
CollectReports(nsIMemoryReporterCallback* aCb,
nsISupports* aClosure)
{
int32_t winVers, buildNum;
HANDLE ProcessHandle = GetCurrentProcess();
-
+
int64_t dedicatedBytesUsed = 0;
int64_t sharedBytesUsed = 0;
int64_t committedBytesUsed = 0;
IDXGIAdapter *DXGIAdapter;
-
+
HMODULE gdi32Handle;
PFND3DKMTQS queryD3DKMTStatistics;
-
+
winVers = gfxWindowsPlatform::WindowsOSVersion(&buildNum);
-
+
// GPU memory reporting is not available before Windows 7
- if (winVers < gfxWindowsPlatform::kWindows7)
+ if (winVers < gfxWindowsPlatform::kWindows7)
return NS_OK;
-
+
if (gdi32Handle = LoadLibrary(TEXT("gdi32.dll")))
queryD3DKMTStatistics = (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
-
+
if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) {
// Most of this block is understood thanks to wj32's work on Process Hacker
-
+
DXGI_ADAPTER_DESC adapterDesc;
D3DKMTQS queryStatistics;
-
+
DXGIAdapter->GetDesc(&adapterDesc);
DXGIAdapter->Release();
-
+
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
queryStatistics.Type = D3DKMTQS_PROCESS;
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
@@ -278,29 +271,29 @@ public:
if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
committedBytesUsed = queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated;
}
-
+
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
queryStatistics.Type = D3DKMTQS_ADAPTER;
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
ULONG i;
ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments;
-
+
for (i = 0; i < segmentCount; i++) {
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
queryStatistics.Type = D3DKMTQS_SEGMENT;
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
queryStatistics.QuerySegment.SegmentId = i;
-
+
if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
bool aperture;
-
+
// SegmentInformation has a different definition in Win7 than later versions
if (winVers < gfxWindowsPlatform::kWindows8)
aperture = queryStatistics.QueryResult.SegmentInfoWin7.Aperture;
else
aperture = queryStatistics.QueryResult.SegmentInfoWin8.Aperture;
-
+
memset(&queryStatistics, 0, sizeof(D3DKMTQS));
queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT;
queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
@@ -320,9 +313,9 @@ public:
}
}
}
-
+
FreeLibrary(gdi32Handle);
-
+
#define REPORT(_path, _amount, _desc) \
do { \
nsresult rv; \
@@ -342,13 +335,12 @@ public:
REPORT("gpu-shared", sharedBytesUsed,
"In-process memory that is shared with the GPU.");
-
+
#undef REPORT
return NS_OK;
}
};
-NS_IMPL_ISUPPORTS1(GPUAdapterReporter, nsIMemoryReporter)
static __inline void
BuildKeyNameFromFontName(nsAString &aName)
@@ -385,13 +377,16 @@ gfxWindowsPlatform::gfxWindowsPlatform()
UpdateRenderMode();
- mGPUAdapterReporter = new GPUAdapterReporter();
- NS_RegisterMemoryReporter(mGPUAdapterReporter);
+ // This reporter is disabled because it frequently gives bogus values. See
+ // bug 917496.
+ //mGPUAdapterReporter = new GPUAdapterReporter();
+ //NS_RegisterMemoryReporter(mGPUAdapterReporter);
+ mGPUAdapterReporter = nullptr;
}
gfxWindowsPlatform::~gfxWindowsPlatform()
{
- NS_UnregisterMemoryReporter(mGPUAdapterReporter);
+ //NS_UnregisterMemoryReporter(mGPUAdapterReporter);
mDeviceManager = nullptr;
diff --git a/image/src/imgLoader.cpp b/image/src/imgLoader.cpp
index 6dade7df6a4..e2d5123725c 100644
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -50,21 +50,12 @@ using namespace mozilla::image;
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(ImagesMallocSizeOf)
-class imgMemoryReporter MOZ_FINAL :
- public nsIMemoryReporter
+class imgMemoryReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
imgMemoryReporter()
- {
- }
-
- NS_DECL_ISUPPORTS
-
- NS_IMETHOD GetName(nsACString &name)
- {
- name.Assign("images");
- return NS_OK;
- }
+ : MemoryMultiReporter("images")
+ {}
NS_IMETHOD CollectReports(nsIMemoryReporterCallback *callback,
nsISupports *closure)
@@ -223,8 +214,6 @@ private:
}
};
-NS_IMPL_ISUPPORTS1(imgMemoryReporter, nsIMemoryReporter)
-
NS_IMPL_ISUPPORTS3(nsProgressNotificationProxy,
nsIProgressEventSink,
nsIChannelEventSink,
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
index 8c5831fb98a..714b6ff0295 100644
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1326,13 +1326,7 @@ Neuter(JSContext *cx, unsigned argc, jsval *vp)
return false;
}
- void *contents;
- uint8_t *data;
- if (!JS_StealArrayBufferContents(cx, obj, &contents, &data))
- return false;
-
- js_free(contents);
- return true;
+ return JS_NeuterArrayBuffer(cx, obj);
}
static const JSFunctionSpecWithHelp TestingFunctions[] = {
diff --git a/js/src/configure.in b/js/src/configure.in
index f0a963ad587..1815b0764e4 100644
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4300,16 +4300,9 @@ if test "$JS_HAS_CTYPES" -a -z "$MOZ_NATIVE_FFI"; then
ac_configure_args="$ac_configure_args --with-pic"
fi
if test "$CROSS_COMPILE"; then
- case "$target" in
- *-android*|*-linuxandroid*)
- export AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS CFLAGS LDFLAGS
+ export AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS CFLAGS LDFLAGS
- ac_configure_args="$ac_configure_args --build=$build --host=$target HOST_CC=\"$HOST_CC\""
- ;;
- *)
- ac_configure_args="$ac_configure_args --build=$build --host=$target HOST_CC=\"$HOST_CC\" CC=\"$CC\""
- ;;
- esac
+ ac_configure_args="$ac_configure_args --build=$build --host=$target HOST_CC=\"$HOST_CC\""
fi
if test "$_MSC_VER"; then
# Use a wrapper script for cl and ml that looks more like gcc.
diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js
index 148a5918227..45a7e047360 100644
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -79,6 +79,7 @@ var ignoreCallees = {
"mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC.
"mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
"nsIThreadManager.GetIsMainThread" : true,
+ "PLDHashTableOps.hashKey" : true,
};
function fieldCallCannotGC(csu, fullfield)
diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp
index 516525b4d55..396396147ed 100644
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2908,38 +2908,22 @@ BaselineCompiler::emit_JSOP_RUNONCE()
return callVM(RunOnceScriptPrologueInfo);
}
-static bool
-DoCreateRestParameter(JSContext *cx, BaselineFrame *frame, MutableHandleValue res)
-{
- unsigned numFormals = frame->numFormalArgs() - 1;
- unsigned numActuals = frame->numActualArgs();
- unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
- Value *rest = frame->argv() + numFormals;
-
- JSObject *obj = NewDenseCopiedArray(cx, numRest, rest, nullptr);
- if (!obj)
- return false;
- types::FixRestArgumentsType(cx, obj);
- res.setObject(*obj);
- return true;
-}
-
-typedef bool(*DoCreateRestParameterFn)(JSContext *cx, BaselineFrame *, MutableHandleValue);
-static const VMFunction DoCreateRestParameterInfo =
- FunctionInfo(DoCreateRestParameter);
-
bool
BaselineCompiler::emit_JSOP_REST()
{
frame.syncStack(0);
- prepareVMCall();
- masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
- pushArg(R0.scratchReg());
+ JSObject *templateObject = NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject);
+ if (!templateObject)
+ return false;
+ types::FixRestArgumentsType(cx, templateObject);
- if (!callVM(DoCreateRestParameterInfo))
+ // Call IC.
+ ICRest_Fallback::Compiler compiler(cx, templateObject);
+ if (!emitOpIC(compiler.getStub(&stubSpace_)))
return false;
+ // Mark R0 as pushed stack value.
frame.push(R0);
return true;
}
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
index 764acb14781..16a8769c262 100644
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -9463,5 +9463,41 @@ ICGetProp_DOMProxyShadowed::ICGetProp_DOMProxyShadowed(IonCode *stubCode,
pcOffset_(pcOffset)
{ }
+//
+// Rest_Fallback
+//
+
+static bool DoRestFallback(JSContext *cx, ICRest_Fallback *stub,
+ BaselineFrame *frame, MutableHandleValue res)
+{
+ unsigned numFormals = frame->numFormalArgs() - 1;
+ unsigned numActuals = frame->numActualArgs();
+ unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
+ Value *rest = frame->argv() + numFormals;
+
+ JSObject *obj = NewDenseCopiedArray(cx, numRest, rest, nullptr);
+ if (!obj)
+ return false;
+ types::FixRestArgumentsType(cx, obj);
+ res.setObject(*obj);
+ return true;
+}
+
+typedef bool (*DoRestFallbackFn)(JSContext *, ICRest_Fallback *, BaselineFrame *,
+ MutableHandleValue);
+static const VMFunction DoRestFallbackInfo =
+ FunctionInfo(DoRestFallback);
+
+bool
+ICRest_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
+{
+ EmitRestoreTailCallReg(masm);
+
+ masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
+ masm.push(BaselineStubReg);
+
+ return tailCallVM(DoRestFallbackInfo, masm);
+}
+
} // namespace jit
} // namespace js
diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h
index 54fa61d19e9..de5750bebf3 100644
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -5853,6 +5853,47 @@ class ICTypeOf_Typed : public ICFallbackStub
};
};
+class ICRest_Fallback : public ICFallbackStub
+{
+ friend class ICStubSpace;
+
+ HeapPtrObject templateObject_;
+
+ ICRest_Fallback(IonCode *stubCode, JSObject *templateObject)
+ : ICFallbackStub(ICStub::Rest_Fallback, stubCode), templateObject_(templateObject)
+ { }
+
+ public:
+ static const uint32_t MAX_OPTIMIZED_STUBS = 8;
+
+ static inline ICRest_Fallback *New(ICStubSpace *space, IonCode *code,
+ JSObject *templateObject) {
+ if (!code)
+ return nullptr;
+ return space->allocate(code, templateObject);
+ }
+
+ JSObject *templateObject() {
+ return templateObject_;
+ }
+
+ class Compiler : public ICStubCompiler {
+ protected:
+ RootedObject templateObject;
+ bool generateStubCode(MacroAssembler &masm);
+
+ public:
+ Compiler(JSContext *cx, JSObject *templateObject)
+ : ICStubCompiler(cx, ICStub::Rest_Fallback),
+ templateObject(cx, templateObject)
+ { }
+
+ ICStub *getStub(ICStubSpace *space) {
+ return ICRest_Fallback::New(space, getStubCode(), templateObject);
+ }
+ };
+};
+
// Stub for JSOP_RETSUB ("returning" from a |finally| block).
class ICRetSub_Fallback : public ICFallbackStub
{
diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp
index d78d5c7bc11..ea996156d33 100644
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -397,6 +397,8 @@ BaselineInspector::getTemplateObject(jsbytecode *pc)
return stub->toNewArray_Fallback()->templateObject();
case ICStub::NewObject_Fallback:
return stub->toNewObject_Fallback()->templateObject();
+ case ICStub::Rest_Fallback:
+ return stub->toRest_Fallback()->templateObject();
case ICStub::Call_Scripted:
if (JSObject *obj = stub->toCall_Scripted()->templateObject())
return obj;
diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp
index d0672ac4e53..3190fa8dea5 100644
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4963,19 +4963,17 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
}
JS_ASSERT_IF(gotLambda, originals.length() <= 1);
- // If any call targets need to be cloned, clone them. Keep track of the
- // originals as we need to case on them for poly inline.
+ // If any call targets need to be cloned, look for existing clones to use.
+ // Keep track of the originals as we need to case on them for poly inline.
bool hasClones = false;
ObjectVector targets;
- RootedFunction fun(cx);
- RootedScript scriptRoot(cx, script());
for (uint32_t i = 0; i < originals.length(); i++) {
- fun = &originals[i]->as();
+ JSFunction *fun = &originals[i]->as();
if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite) {
- fun = CloneFunctionAtCallsite(cx, fun, scriptRoot, pc);
- if (!fun)
- return false;
- hasClones = true;
+ if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment, fun, script(), pc)) {
+ fun = clone;
+ hasClones = true;
+ }
}
if (!targets.append(fun))
return false;
@@ -7473,23 +7471,14 @@ IonBuilder::jsop_arguments_length()
return pushConstant(Int32Value(inlineCallInfo_->argv().length()));
}
-static JSObject *
-CreateRestArgumentsTemplateObject(JSContext *cx, unsigned length)
-{
- JSObject *templateObject = NewDenseUnallocatedArray(cx, length, nullptr, TenuredObject);
- if (templateObject)
- types::FixRestArgumentsType(cx, templateObject);
- return templateObject;
-}
-
bool
IonBuilder::jsop_rest()
{
- // We don't know anything about the callee.
+ JSObject *templateObject = inspector->getTemplateObject(pc);
+ JS_ASSERT(templateObject->is());
+
if (inliningDepth_ == 0) {
- JSObject *templateObject = CreateRestArgumentsTemplateObject(cx, 0);
- if (!templateObject)
- return false;
+ // We don't know anything about the callee.
MArgumentsLength *numActuals = MArgumentsLength::New();
current->add(numActuals);
@@ -7505,9 +7494,6 @@ IonBuilder::jsop_rest()
unsigned numActuals = inlineCallInfo_->argv().length();
unsigned numFormals = info().nargs() - 1;
unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
- JSObject *templateObject = CreateRestArgumentsTemplateObject(cx, numRest);
- if (!templateObject)
- return false;
MNewArray *array = new MNewArray(numRest, templateObject, MNewArray::NewArray_Allocating);
current->add(array);
diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h
index ed105f58dfb..51c00142424 100644
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -583,7 +583,7 @@ class IonBuilder : public MIRGenerator
InliningStatus inlineNewParallelArray(CallInfo &callInfo);
InliningStatus inlineParallelArray(CallInfo &callInfo);
InliningStatus inlineParallelArrayTail(CallInfo &callInfo,
- HandleFunction target,
+ JSFunction *target,
MDefinition *ctor,
types::TemporaryTypeSet *ctorTypes,
uint32_t discards);
diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp
index 52749763047..38e1e671a0b 100644
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1195,14 +1195,12 @@ IonBuilder::inlineNewParallelArray(CallInfo &callInfo)
types::TemporaryTypeSet *ctorTypes = callInfo.getArg(0)->resultTypeSet();
JSObject *targetObj = ctorTypes ? ctorTypes->getSingleton() : nullptr;
- RootedFunction target(cx);
+ JSFunction *target = nullptr;
if (targetObj && targetObj->is())
target = &targetObj->as();
if (target && target->isInterpreted() && target->nonLazyScript()->shouldCloneAtCallsite) {
- RootedScript scriptRoot(cx, script());
- target = CloneFunctionAtCallsite(cx, target, scriptRoot, pc);
- if (!target)
- return InliningStatus_Error;
+ if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment, target, script(), pc))
+ target = clone;
}
MDefinition *ctor = makeCallsiteClone(
target,
@@ -1220,15 +1218,13 @@ IonBuilder::inlineParallelArray(CallInfo &callInfo)
return InliningStatus_NotInlined;
uint32_t argc = callInfo.argc();
- RootedFunction target(cx, ParallelArrayObject::getConstructor(cx, argc));
+ JSFunction *target = ParallelArrayObject::getConstructor(cx, argc);
if (!target)
return InliningStatus_Error;
JS_ASSERT(target->nonLazyScript()->shouldCloneAtCallsite);
- RootedScript script(cx, script_);
- target = CloneFunctionAtCallsite(cx, target, script, pc);
- if (!target)
- return InliningStatus_Error;
+ if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment, target, script(), pc))
+ target = clone;
MConstant *ctor = MConstant::New(ObjectValue(*target));
current->add(ctor);
@@ -1238,7 +1234,7 @@ IonBuilder::inlineParallelArray(CallInfo &callInfo)
IonBuilder::InliningStatus
IonBuilder::inlineParallelArrayTail(CallInfo &callInfo,
- HandleFunction target,
+ JSFunction *target,
MDefinition *ctor,
types::TemporaryTypeSet *ctorTypes,
uint32_t discards)
diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp
index 013f1fae599..b07d2ba5206 100644
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -110,9 +110,10 @@ JSCompartment::sweepCallsiteClones()
}
JSFunction *
-js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc)
+js::ExistingCloneFunctionAtCallsite(JSCompartment *comp, JSFunction *fun,
+ JSScript *script, jsbytecode *pc)
{
- JS_ASSERT(cx->typeInferenceEnabled());
+ JS_ASSERT(comp->zone()->types.inferenceEnabled);
JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite);
JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope());
JS_ASSERT(types::UseNewTypeForClone(fun));
@@ -126,23 +127,25 @@ js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript scri
typedef CallsiteCloneKey Key;
typedef CallsiteCloneTable Table;
- Table &table = cx->compartment()->callsiteClones;
- if (!table.initialized() && !table.init())
+ Table &table = comp->callsiteClones;
+ if (!table.initialized())
return nullptr;
- uint32_t offset = pc - script->code;
- void* originalScript = script;
- void* originalFun = fun;
- SkipRoot skipScript(cx, &originalScript);
- SkipRoot skipFun(cx, &originalFun);
-
- Table::AddPtr p = table.lookupForAdd(Key(fun, script, offset));
- SkipRoot skipHash(cx, &p); /* Prevent the hash from being poisoned. */
+ Table::Ptr p = table.lookup(Key(fun, script, pc - script->code));
if (p)
return p->value;
+ return nullptr;
+}
+
+JSFunction *
+js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc)
+{
+ if (JSFunction *clone = ExistingCloneFunctionAtCallsite(cx->compartment(), fun, script, pc))
+ return clone;
+
RootedObject parent(cx, fun->environment());
- RootedFunction clone(cx, CloneFunctionObject(cx, fun, parent));
+ JSFunction *clone = CloneFunctionObject(cx, fun, parent);
if (!clone)
return nullptr;
@@ -154,15 +157,14 @@ js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript scri
clone->nonLazyScript()->isCallsiteClone = true;
clone->nonLazyScript()->setOriginalFunctionObject(fun);
- Key key(fun, script, offset);
+ typedef CallsiteCloneKey Key;
+ typedef CallsiteCloneTable Table;
- /* Recalculate the hash if script or fun have been moved. */
- if (script != originalScript || fun != originalFun) {
- p = table.lookupForAdd(key);
- JS_ASSERT(!p);
- }
+ Table &table = cx->compartment()->callsiteClones;
+ if (!table.initialized() && !table.init())
+ return nullptr;
- if (!table.relookupOrAdd(p, key, clone.get()))
+ if (!table.putNew(Key(fun, script, pc - script->code), clone))
return nullptr;
return clone;
diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h
index cd3879104b9..90470910715 100644
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -64,6 +64,10 @@ typedef HashMap CallsiteCloneTable;
+JSFunction *
+ExistingCloneFunctionAtCallsite(JSCompartment *comp, JSFunction *fun,
+ JSScript *script, jsbytecode *pc);
+
JSFunction *CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun,
HandleScript script, jsbytecode *pc);
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index afcd92f049a..92a84cf57df 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1248,8 +1248,8 @@ JS_GetArrayBufferViewBuffer(JSObject *obj);
/*
* Set an ArrayBuffer's length to 0 and neuter all of its views.
*/
-extern JS_FRIEND_API(void)
-JS_NeuterArrayBuffer(JSObject *obj, JSContext *cx);
+extern JS_FRIEND_API(bool)
+JS_NeuterArrayBuffer(JSContext *cx, JS::HandleObject obj);
/*
* Check whether obj supports JS_GetDataView* APIs.
diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp
index b501fb0d673..439a7a29c6e 100644
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -4031,12 +4031,12 @@ JS_GetArrayBufferData(JSObject *obj)
}
JS_FRIEND_API(bool)
-JS_NeuterArrayBuffer(JSContext *cx, JSObject *obj)
+JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj)
{
- ArrayBufferObject &buffer = obj->as();
- if (!buffer.neuterViews(cx))
+ Rooted buffer(cx, &obj->as());
+ if (!buffer->neuterViews(cx))
return false;
- buffer.neuter(cx);
+ buffer->neuter(cx);
return true;
}
diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp
index 3d5e48f05f5..acb6f297610 100644
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2398,15 +2398,12 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
} // namespace xpc
-class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
+class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
- NS_DECL_THREADSAFE_ISUPPORTS
-
- NS_IMETHOD GetName(nsACString &name) {
- name.AssignLiteral("js-main-runtime-compartments");
- return NS_OK;
- }
+ JSMainRuntimeCompartmentsReporter()
+ : MemoryMultiReporter("js-main-runtime-compartments")
+ {}
typedef js::Vector Paths;
@@ -2445,8 +2442,6 @@ class JSMainRuntimeCompartmentsReporter MOZ_FINAL : public nsIMemoryReporter
}
};
-NS_IMPL_ISUPPORTS1(JSMainRuntimeCompartmentsReporter, nsIMemoryReporter)
-
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(OrphanMallocSizeOf)
namespace xpc {
diff --git a/layout/reftests/w3c-css/submitted/reftest.list b/layout/reftests/w3c-css/submitted/reftest.list
index b9832858621..4a21929c957 100644
--- a/layout/reftests/w3c-css/submitted/reftest.list
+++ b/layout/reftests/w3c-css/submitted/reftest.list
@@ -50,7 +50,7 @@ include multicol3/reftest.list
# include transitions/reftest.list
# User Interface Level 3
-# include ui3/reftest.list
+include ui3/reftest.list
# Values and Units Level 3
include values3/reftest.list
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-001-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-001-ref.xht
new file mode 100644
index 00000000000..e886a0f05e3
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-001-ref.xht
@@ -0,0 +1,40 @@
+
+
+
+ CSS Reference: Box Sizing - Border-Box with specified width
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-001.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-001.xht
new file mode 100644
index 00000000000..f41214de953
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-001.xht
@@ -0,0 +1,43 @@
+
+
+
+ CSS Test: Box Sizing - Border-Box with specified width
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-002-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-002-ref.xht
new file mode 100644
index 00000000000..7c6bc218a0b
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-002-ref.xht
@@ -0,0 +1,41 @@
+
+
+
+ CSS Reference: Box Sizing - Border-Box with specified width
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-002.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-002.xht
new file mode 100644
index 00000000000..8385cce059a
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-002.xht
@@ -0,0 +1,44 @@
+
+
+
+ CSS Test: Box Sizing - Border-Box with specified width
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-003-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-003-ref.xht
new file mode 100644
index 00000000000..c468c5b5b99
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-003-ref.xht
@@ -0,0 +1,43 @@
+
+
+
+ CSS Reference: Box Sizing - Border-Box with specified width/height
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-003.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-003.xht
new file mode 100644
index 00000000000..57f78a8f10c
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-003.xht
@@ -0,0 +1,46 @@
+
+
+
+ CSS Test: Box Sizing - Border-Box with specified width/height
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-004-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-004-ref.xht
new file mode 100644
index 00000000000..a635acd13e4
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-004-ref.xht
@@ -0,0 +1,46 @@
+
+
+
+ CSS Reference: Box Sizing - Border-Box with min/max width/height
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-004.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-004.xht
new file mode 100644
index 00000000000..9ffe7889a72
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-border-box-004.xht
@@ -0,0 +1,49 @@
+
+
+
+ CSS Test: Box Sizing - Border-Box with min/max width/height
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-001-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-001-ref.xht
new file mode 100644
index 00000000000..ca3ff0f7ec0
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-001-ref.xht
@@ -0,0 +1,41 @@
+
+
+
+ CSS Reference: Box Sizing - Content-Box with specified width/height
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-001.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-001.xht
new file mode 100644
index 00000000000..b0ca31dbfe7
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-001.xht
@@ -0,0 +1,44 @@
+
+
+
+ CSS Test: Box Sizing - Content-Box with specified width/height
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-002-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-002-ref.xht
new file mode 100644
index 00000000000..b280e57693c
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-002-ref.xht
@@ -0,0 +1,42 @@
+
+
+
+ CSS Reference: Box Sizing - Content-Box with specified width/height
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-002.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-002.xht
new file mode 100644
index 00000000000..120318fd382
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-002.xht
@@ -0,0 +1,45 @@
+
+
+
+ CSS Test: Box Sizing - Content-Box with specified width/height
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-003-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-003-ref.xht
new file mode 100644
index 00000000000..042b5628aa8
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-003-ref.xht
@@ -0,0 +1,43 @@
+
+
+
+ CSS Reference: Box Sizing - Content-Box with min/max width/height
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-003.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-003.xht
new file mode 100644
index 00000000000..1146b54cfb0
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-content-box-003.xht
@@ -0,0 +1,45 @@
+
+
+
+ CSS Test: Box Sizing - Content-Box with min/max width/height
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-001-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-001-ref.xht
new file mode 100644
index 00000000000..d9a1f41e4cc
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-001-ref.xht
@@ -0,0 +1,40 @@
+
+
+
+ CSS Reference: Box Sizing - Padding-Box with specified width/height
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-001.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-001.xht
new file mode 100644
index 00000000000..76da3340f8f
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-001.xht
@@ -0,0 +1,43 @@
+
+
+
+ CSS Test: Box Sizing - Padding-Box with specified width/height
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-002-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-002-ref.xht
new file mode 100644
index 00000000000..06260223d31
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-002-ref.xht
@@ -0,0 +1,42 @@
+
+
+
+ CSS Reference: Box Sizing - Padding-Box with specified width/height
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-002.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-002.xht
new file mode 100644
index 00000000000..5f5465e66c9
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-002.xht
@@ -0,0 +1,45 @@
+
+
+
+ CSS Test: Box Sizing - Padding-Box with specified width/height
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-003-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-003-ref.xht
new file mode 100644
index 00000000000..d3ba96f37e4
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-003-ref.xht
@@ -0,0 +1,42 @@
+
+
+
+ CSS Reference: Box Sizing - Padding-Box with min/max width/height
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-003.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-003.xht
new file mode 100644
index 00000000000..fee74d81f8d
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-003.xht
@@ -0,0 +1,49 @@
+
+
+
+ CSS Test: Box Sizing - Padding-Box with min/max width/height
+
+
+
+
+
+
+ The two divs should be side-by-side, not one on top of another. No red should be visible.
+
+
+
LEFT HALF
+
RIGHT HALF
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/box-sizing-replaced-001-ref.xht b/layout/reftests/w3c-css/submitted/ui3/box-sizing-replaced-001-ref.xht
new file mode 100644
index 00000000000..815813c51e7
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/box-sizing-replaced-001-ref.xht
@@ -0,0 +1,52 @@
+
+
+
+ CSS Reference: Min/Max Height and Width Constraints on Replaced Elements with Box-Sizing
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/reftests/w3c-css/submitted/ui3/reftest.list b/layout/reftests/w3c-css/submitted/ui3/reftest.list
new file mode 100644
index 00000000000..f5d9ef53267
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/ui3/reftest.list
@@ -0,0 +1,13 @@
+== box-sizing-border-box-001.xht box-sizing-border-box-001-ref.xht
+== box-sizing-border-box-002.xht box-sizing-border-box-002-ref.xht
+== box-sizing-border-box-003.xht box-sizing-border-box-003-ref.xht
+== box-sizing-border-box-004.xht box-sizing-border-box-004-ref.xht
+== box-sizing-content-box-001.xht box-sizing-content-box-001-ref.xht
+== box-sizing-content-box-002.xht box-sizing-content-box-002-ref.xht
+== box-sizing-content-box-003.xht box-sizing-content-box-003-ref.xht
+== box-sizing-padding-box-001.xht box-sizing-padding-box-001-ref.xht
+== box-sizing-padding-box-002.xht box-sizing-padding-box-002-ref.xht
+== box-sizing-padding-box-003.xht box-sizing-padding-box-003-ref.xht
+== box-sizing-replaced-001.xht box-sizing-replaced-001-ref.xht
+== box-sizing-replaced-002.xht box-sizing-replaced-002-ref.xht
+== box-sizing-replaced-003.xht box-sizing-replaced-003-ref.xht
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-1.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-1.png
new file mode 100644
index 00000000000..d6946724d9e
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-1.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-10.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-10.png
new file mode 100644
index 00000000000..bfdca3e6f35
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-10.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-11.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-11.png
new file mode 100644
index 00000000000..38ee90dda0f
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-11.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-12.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-12.png
new file mode 100644
index 00000000000..87433d4d7b9
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-12.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-13.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-13.png
new file mode 100644
index 00000000000..c07d66e7881
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-13.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-14.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-14.png
new file mode 100644
index 00000000000..e89dbe97586
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-14.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-15.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-15.png
new file mode 100644
index 00000000000..717ea111b6f
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-15.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-16.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-16.png
new file mode 100644
index 00000000000..0a49bbf1c33
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-16.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-17.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-17.png
new file mode 100644
index 00000000000..a2ee273d798
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-17.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-18.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-18.png
new file mode 100644
index 00000000000..d18f4534179
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-18.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-19.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-19.png
new file mode 100644
index 00000000000..8900f36c41c
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-19.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-2.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-2.png
new file mode 100644
index 00000000000..58338097fe2
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-2.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-3.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-3.png
new file mode 100644
index 00000000000..e5e7d6e8a8c
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-3.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-4.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-4.png
new file mode 100644
index 00000000000..c099ae4271a
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-4.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-5.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-5.png
new file mode 100644
index 00000000000..9d9d8105ff2
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-5.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-6.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-6.png
new file mode 100644
index 00000000000..781f894a5ec
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-6.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-7.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-7.png
new file mode 100644
index 00000000000..3f91a11f8e2
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-7.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-8.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-8.png
new file mode 100644
index 00000000000..69951ec2571
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-8.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-9.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-9.png
new file mode 100644
index 00000000000..3ac586daa5a
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max-9.png differ
diff --git a/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max.png b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max.png
new file mode 100644
index 00000000000..3ef233005ae
Binary files /dev/null and b/layout/reftests/w3c-css/submitted/ui3/support/replaced-min-max.png differ
diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp
index 7602b03c3cc..95e58f5c4f9 100644
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -230,7 +230,8 @@ nsChangeHint nsStyleFont::CalcFontDifference(const nsFont& aFont1, const nsFont&
(aFont1.variantNumeric == aFont2.variantNumeric) &&
(aFont1.variantPosition == aFont2.variantPosition) &&
(aFont1.fontFeatureSettings == aFont2.fontFeatureSettings) &&
- (aFont1.languageOverride == aFont2.languageOverride)) {
+ (aFont1.languageOverride == aFont2.languageOverride) &&
+ (aFont1.systemFont == aFont2.systemFont)) {
if ((aFont1.decorations == aFont2.decorations)) {
return NS_STYLE_HINT_NONE;
}
diff --git a/modules/libpref/src/Preferences.cpp b/modules/libpref/src/Preferences.cpp
index bd5005d36ab..0160eb9c511 100644
--- a/modules/libpref/src/Preferences.cpp
+++ b/modules/libpref/src/Preferences.cpp
@@ -208,13 +208,16 @@ Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeO
return n;
}
-NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(PreferencesMallocSizeOf)
-
-class PreferencesReporter MOZ_FINAL : public nsIMemoryReporter
+class PreferenceServiceReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIMEMORYREPORTER
+ PreferenceServiceReporter()
+ : MemoryMultiReporter("preference-service")
+ {}
+
+ NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCallback,
+ nsISupports* aData);
+
protected:
static const uint32_t kSuspectReferentCount = 1000;
static PLDHashOperator CountReferents(PrefCallback* aKey,
@@ -222,15 +225,6 @@ protected:
void* aClosure);
};
-NS_IMPL_ISUPPORTS1(PreferencesReporter, nsIMemoryReporter)
-
-NS_IMETHODIMP
-PreferencesReporter::GetName(nsACString& aName)
-{
- aName.AssignLiteral("preference-service");
- return NS_OK;
-}
-
struct PreferencesReferentCount {
PreferencesReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
size_t numStrong;
@@ -242,9 +236,9 @@ struct PreferencesReferentCount {
};
PLDHashOperator
-PreferencesReporter::CountReferents(PrefCallback* aKey,
- nsAutoPtr& aCallback,
- void* aClosure)
+PreferenceServiceReporter::CountReferents(PrefCallback* aKey,
+ nsAutoPtr& aCallback,
+ void* aClosure)
{
PreferencesReferentCount* referentCount =
static_cast(aClosure);
@@ -279,8 +273,8 @@ PreferencesReporter::CountReferents(PrefCallback* aKey,
}
NS_IMETHODIMP
-PreferencesReporter::CollectReports(nsIMemoryReporterCallback* aCb,
- nsISupports* aClosure)
+PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb,
+ nsISupports* aClosure)
{
#define REPORT(_path, _kind, _units, _amount, _desc) \
do { \
@@ -293,7 +287,7 @@ PreferencesReporter::CollectReports(nsIMemoryReporterCallback* aCb,
REPORT(NS_LITERAL_CSTRING("explicit/preferences"),
nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
- Preferences::SizeOfIncludingThisAndOtherStuff(PreferencesMallocSizeOf),
+ Preferences::SizeOfIncludingThisAndOtherStuff(MallocSizeOf),
"Memory used by the preferences system.");
nsPrefBranch* rootBranch =
@@ -347,7 +341,7 @@ class AddPreferencesMemoryReporterRunnable : public nsRunnable
{
NS_IMETHOD Run()
{
- return NS_RegisterMemoryReporter(new PreferencesReporter());
+ return NS_RegisterMemoryReporter(new PreferenceServiceReporter());
}
};
} // anonymous namespace
diff --git a/modules/libpref/src/nsPrefBranch.h b/modules/libpref/src/nsPrefBranch.h
index b9477f050ce..8884e60a284 100644
--- a/modules/libpref/src/nsPrefBranch.h
+++ b/modules/libpref/src/nsPrefBranch.h
@@ -24,13 +24,13 @@
#include "mozilla/MemoryReporting.h"
namespace mozilla {
-class PreferencesReporter;
+class PreferenceServiceReporter;
} // namespace mozilla;
class nsPrefBranch;
class PrefCallback : public PLDHashEntryHdr {
- friend class mozilla::PreferencesReporter;
+ friend class mozilla::PreferenceServiceReporter;
public:
typedef PrefCallback* KeyType;
@@ -178,7 +178,7 @@ class nsPrefBranch : public nsIPrefBranchInternal,
public nsIObserver,
public nsSupportsWeakReference
{
- friend class mozilla::PreferencesReporter;
+ friend class mozilla::PreferenceServiceReporter;
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIPREFBRANCH
diff --git a/python/mozboot/mozboot/centos.py b/python/mozboot/mozboot/centos.py
index 144d9438919..0158c6a76ae 100644
--- a/python/mozboot/mozboot/centos.py
+++ b/python/mozboot/mozboot/centos.py
@@ -34,6 +34,7 @@ class CentOSBootstrapper(BaseBootstrapper):
'libXt-devel',
'mercurial',
'mesa-libGL-devel',
+ 'pulseaudio-libs-devel',
'wireless-tools-devel',
'yasm')
diff --git a/python/mozboot/mozboot/debian.py b/python/mozboot/mozboot/debian.py
index bd2f47ba6cf..2c1b8d67267 100644
--- a/python/mozboot/mozboot/debian.py
+++ b/python/mozboot/mozboot/debian.py
@@ -21,6 +21,7 @@ class DebianBootstrapper(BaseBootstrapper):
'libgtk2.0-dev',
'libiw-dev',
'libnotify-dev',
+ 'libpulse-dev',
'libxt-dev',
'mercurial',
'mesa-common-dev',
diff --git a/python/mozboot/mozboot/fedora.py b/python/mozboot/mozboot/fedora.py
index 0efc55733c9..f6471f9fa40 100644
--- a/python/mozboot/mozboot/fedora.py
+++ b/python/mozboot/mozboot/fedora.py
@@ -29,6 +29,7 @@ class FedoraBootstrapper(BaseBootstrapper):
'libXt-devel',
'mercurial',
'mesa-libGL-devel',
+ 'pulseaudio-libs-devel',
'wireless-tools-devel',
'yasm')
diff --git a/storage/src/mozStorageService.cpp b/storage/src/mozStorageService.cpp
index b67fe1da4ad..caf1379db3f 100644
--- a/storage/src/mozStorageService.cpp
+++ b/storage/src/mozStorageService.cpp
@@ -59,7 +59,7 @@ StorageSQLiteDistinguishedAmount()
return ::sqlite3_memory_used();
}
-class StorageSQLiteReporter MOZ_FINAL : public nsIMemoryReporter
+class StorageSQLiteReporter MOZ_FINAL : public MemoryMultiReporter
{
private:
Service *mService; // a weakref because Service contains a strongref to this
@@ -68,10 +68,9 @@ private:
nsCString mSchemaDesc;
public:
- NS_DECL_THREADSAFE_ISUPPORTS
-
StorageSQLiteReporter(Service *aService)
- : mService(aService)
+ : MemoryMultiReporter("storage-sqlite")
+ , mService(aService)
{
mStmtDesc = NS_LITERAL_CSTRING(
"Memory (approximate) used by all prepared statements used by "
@@ -86,12 +85,6 @@ public:
"associated with connections to this database.");
}
- NS_IMETHOD GetName(nsACString &aName)
- {
- aName.AssignLiteral("storage-sqlite-multi");
- return NS_OK;
- }
-
// Warning: To get a Connection's measurements requires holding its lock.
// There may be a delay getting the lock if another thread is accessing the
// Connection. This isn't very nice if CollectReports is called from the
@@ -204,11 +197,6 @@ private:
}
};
-NS_IMPL_ISUPPORTS1(
- StorageSQLiteReporter,
- nsIMemoryReporter
-)
-
////////////////////////////////////////////////////////////////////////////////
//// Service
diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk
index ec0cec02e2d..5966af5e94e 100644
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -90,8 +90,12 @@ endif
mochitest-remote: DM_TRANS?=adb
mochitest-remote:
- @if [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \
- echo "please prepare your host with the environment variable MOZ_HOST_BIN"; \
+ @if [ "${MOZ_HOST_BIN}" = "" ]; then \
+ echo "environment variable MOZ_HOST_BIN must be set to a directory containing host xpcshell"; \
+ elif [ ! -d ${MOZ_HOST_BIN} ]; then \
+ echo "MOZ_HOST_BIN does not specify a directory"; \
+ elif [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \
+ echo "xpcshell not found in MOZ_HOST_BIN"; \
elif [ "${TEST_DEVICE}" = "" -a "$(DM_TRANS)" != "adb" ]; then \
echo "please prepare your host with the environment variable TEST_DEVICE"; \
else \
@@ -103,8 +107,12 @@ mochitest-robotium: mochitest-robocop
mochitest-robocop: DM_TRANS?=adb
mochitest-robocop:
- @if [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \
- echo "please prepare your host with the environment variable MOZ_HOST_BIN"; \
+ @if [ "${MOZ_HOST_BIN}" = "" ]; then \
+ echo "environment variable MOZ_HOST_BIN must be set to a directory containing host xpcshell"; \
+ elif [ ! -d ${MOZ_HOST_BIN} ]; then \
+ echo "MOZ_HOST_BIN does not specify a directory"; \
+ elif [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \
+ echo "xpcshell not found in MOZ_HOST_BIN"; \
elif [ "${TEST_DEVICE}" = "" -a "$(DM_TRANS)" != "adb" ]; then \
echo "please prepare your host with the environment variable TEST_DEVICE"; \
else \
@@ -212,8 +220,12 @@ reftest:
reftest-remote: TEST_PATH?=layout/reftests/reftest.list
reftest-remote: DM_TRANS?=adb
reftest-remote:
- @if [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \
- echo "please prepare your host with the environment variable MOZ_HOST_BIN"; \
+ @if [ "${MOZ_HOST_BIN}" = "" ]; then \
+ echo "environment variable MOZ_HOST_BIN must be set to a directory containing host xpcshell"; \
+ elif [ ! -d ${MOZ_HOST_BIN} ]; then \
+ echo "MOZ_HOST_BIN does not specify a directory"; \
+ elif [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \
+ echo "xpcshell not found in MOZ_HOST_BIN"; \
elif [ "${TEST_DEVICE}" = "" -a "$(DM_TRANS)" != "adb" ]; then \
echo "please prepare your host with the environment variable TEST_DEVICE"; \
else \
@@ -224,8 +236,12 @@ reftest-remote:
reftest-b2g: TEST_PATH?=layout/reftests/reftest.list
reftest-b2g:
- @if [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \
- echo "please set the MOZ_HOST_BIN environment variable"; \
+ @if [ "${MOZ_HOST_BIN}" = "" ]; then \
+ echo "environment variable MOZ_HOST_BIN must be set to a directory containing host xpcshell"; \
+ elif [ ! -d ${MOZ_HOST_BIN} ]; then \
+ echo "MOZ_HOST_BIN does not specify a directory"; \
+ elif [ ! -f ${MOZ_HOST_BIN}/xpcshell ]; then \
+ echo "xpcshell not found in MOZ_HOST_BIN"; \
elif [ "${B2G_PATH}" = "" -o "${ADB_PATH}" = "" ]; then \
echo "please set the B2G_PATH and ADB_PATH environment variables"; \
else \
diff --git a/toolkit/components/aboutmemory/content/aboutMemory.js b/toolkit/components/aboutmemory/content/aboutMemory.js
index 639289a7d33..0c7cee1d296 100644
--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -48,11 +48,6 @@ XPCOMUtils.defineLazyGetter(this, "nsGzipConverter",
let gMgr = Cc["@mozilla.org/memory-reporter-manager;1"]
.getService(Ci.nsIMemoryReporterManager);
-// We need to know about "child-memory-reporter-update" events from child
-// processes.
-Services.obs.addObserver(updateAboutMemoryFromReporters,
- "child-memory-reporter-update", false);
-
let gUnnamedProcessStr = "Main Process";
let gIsDiff = false;
@@ -120,8 +115,6 @@ function debug(x)
function onUnload()
{
- Services.obs.removeObserver(updateAboutMemoryFromReporters,
- "child-memory-reporter-update");
}
//---------------------------------------------------------------------------
@@ -388,11 +381,6 @@ function doMMU()
function doMeasure()
{
- // Notify any children that they should measure memory consumption, then
- // update the page. If any reports come back from children,
- // updateAboutMemoryFromReporters() will be called again and the page will
- // regenerate.
- Services.obs.notifyObservers(null, "child-memory-reporter-request", null);
updateAboutMemoryFromReporters();
}
@@ -402,10 +390,7 @@ function doMeasure()
*/
function updateAboutMemoryFromReporters()
{
- // First, clear the contents of main. Necessary because
- // updateAboutMemoryFromReporters() might be called more than once due to the
- // "child-memory-reporter-update" observer.
- updateMainAndFooter("", SHOW_FOOTER);
+ updateMainAndFooter("Measuring...", HIDE_FOOTER);
try {
let processLiveMemoryReports =
@@ -416,12 +401,13 @@ function updateAboutMemoryFromReporters()
aDescription, /* presence = */ undefined);
}
- let e = gMgr.enumerateReporters();
- while (e.hasMoreElements()) {
- let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
- mr.collectReports(handleReport, null);
+ let displayReportsAndFooter = function() {
+ updateMainAndFooter("", SHOW_FOOTER);
+ aDisplayReports();
}
- aDisplayReports();
+
+ gMgr.getReports(handleReport, null,
+ displayReportsAndFooter, null);
}
// Process the reports from the live memory reporters.
@@ -1841,9 +1827,11 @@ function saveReportsToFile()
let dumper = Cc["@mozilla.org/memory-info-dumper;1"]
.getService(Ci.nsIMemoryInfoDumper);
- dumper.dumpMemoryReportsToNamedFile(fp.file.path);
+ let finishDumping = () => {
+ updateMainAndFooter("Saved reports to " + fp.file.path, HIDE_FOOTER);
+ }
- updateMainAndFooter("Saved reports to " + fp.file.path, HIDE_FOOTER);
+ dumper.dumpMemoryReportsToNamedFile(fp.file.path, finishDumping, null);
}
};
fp.open(fpCallback);
diff --git a/toolkit/components/aboutmemory/tests/Makefile.in b/toolkit/components/aboutmemory/tests/Makefile.in
deleted file mode 100644
index 5af1a06954a..00000000000
--- a/toolkit/components/aboutmemory/tests/Makefile.in
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ifndef MOZ_ASAN
-MOCHITEST_CHROME_FILES += \
- remote.xul \
- test_memoryReporters.xul \
- test_memoryReporters2.xul \
- $(NULL)
-endif
diff --git a/toolkit/components/aboutmemory/tests/chrome.ini b/toolkit/components/aboutmemory/tests/chrome.ini
index dec13aef2e1..54328f8e5de 100644
--- a/toolkit/components/aboutmemory/tests/chrome.ini
+++ b/toolkit/components/aboutmemory/tests/chrome.ini
@@ -4,9 +4,13 @@ support-files =
memory-reports-diff1.json
memory-reports-diff2.json
memory-reports-good.json
+ remote.xul
[test_aboutmemory.xul]
[test_aboutmemory2.xul]
[test_aboutmemory3.xul]
[test_aboutmemory4.xul]
+[test_aboutmemory5.xul]
+[test_memoryReporters.xul]
+[test_memoryReporters2.xul]
[test_sqliteMultiReporter.xul]
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
index 72bf8351d18..21d383b4f6f 100644
--- a/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory3.xul
@@ -108,21 +108,60 @@
let e = document.createEvent('Event');
e.initEvent('change', true, true);
- if (!aFilename2) {
- if (aDumpFirst) {
- let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
- getService(Ci.nsIMemoryInfoDumper);
+ function check() {
+ // Initialize the clipboard contents.
+ SpecialPowers.clipboardCopyString("initial clipboard value");
- dumper.dumpMemoryReportsToNamedFile(filePath,
- /* minimizeMemoryUsage = */ false,
- /* dumpChildProcesses = */ false);
+ let numFailures = 0, maxFailures = 30;
+
+ // Because the file load is async, we don't know when it will finish and
+ // the output will show up. So we poll.
+ function copyPasteAndCheck() {
+ // Copy and paste frame contents, and filter out non-deterministic
+ // differences.
+ synthesizeKey("A", {accelKey: true});
+ synthesizeKey("C", {accelKey: true});
+ let actual = SpecialPowers.getClipboardData("text/unicode");
+ actual = actual.replace(/\(pid \d+\)/g, "(pid NNN)");
+
+ if (actual === aExpected) {
+ SimpleTest.ok(true, "Clipboard has the expected contents");
+ aNext();
+ } else {
+ numFailures++;
+ if (numFailures === maxFailures) {
+ ok(false, "pasted text doesn't match");
+ dump("******EXPECTED******\n");
+ dump(aExpected);
+ dump("*******ACTUAL*******\n");
+ dump(actual);
+ dump("********************\n");
+ finish();
+ } else {
+ setTimeout(copyPasteAndCheck, 100);
+ }
+ }
+ }
+ copyPasteAndCheck();
+ }
+
+ if (!aFilename2) {
+ function loadAndCheck() {
+ let fileInput1 =
+ frame.contentWindow.document.getElementById("fileInput1");
+ fileInput1.value = filePath; // this works because it's a chrome test
+
+ fileInput1.dispatchEvent(e);
+ check();
}
- let fileInput1 =
- frame.contentWindow.document.getElementById("fileInput1");
- fileInput1.value = filePath; // this works because it's a chrome test
-
- fileInput1.dispatchEvent(e);
+ if (aDumpFirst) {
+ let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
+ getService(Ci.nsIMemoryInfoDumper);
+ dumper.dumpMemoryReportsToNamedFile(filePath, loadAndCheck, null);
+ } else {
+ loadAndCheck();
+ }
} else {
let fileInput2 =
@@ -144,42 +183,9 @@
let e2 = document.createEvent('Event');
e2.initEvent('change', true, true);
fileInput2.dispatchEvent(e);
+
+ check();
}
-
- // Initialize the clipboard contents.
- SpecialPowers.clipboardCopyString("initial clipboard value");
-
- let numFailures = 0, maxFailures = 30;
-
- // Because the file load is async, we don't know when it will finish and
- // the output will show up. So we poll.
- function copyPasteAndCheck() {
- // Copy and paste frame contents, and filter out non-deterministic
- // differences.
- synthesizeKey("A", {accelKey: true});
- synthesizeKey("C", {accelKey: true});
- let actual = SpecialPowers.getClipboardData("text/unicode");
- actual = actual.replace(/\(pid \d+\)/g, "(pid NNN)");
-
- if (actual === aExpected) {
- SimpleTest.ok(true, "Clipboard has the expected contents");
- aNext();
- } else {
- numFailures++;
- if (numFailures === maxFailures) {
- ok(false, "pasted text doesn't match");
- dump("******EXPECTED******\n");
- dump(aExpected);
- dump("*******ACTUAL*******\n");
- dump(actual);
- dump("********************\n");
- finish();
- } else {
- setTimeout(copyPasteAndCheck, 100);
- }
- }
- }
- copyPasteAndCheck();
}
// Returns a function that chains together multiple test() calls.
diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
new file mode 100644
index 00000000000..50a464310cc
--- /dev/null
+++ b/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
index 2573f28a8bd..0f6deb4bf51 100644
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
@@ -179,12 +179,12 @@
dummy = r.name;
}
- function checkSpecialReport(aName, aAmounts)
+ function checkSpecialReport(aName, aAmounts, aCanBeUnreasonable)
{
ok(aAmounts.length == 1, aName + " has " + aAmounts.length + " report");
let n = aAmounts[0];
// Check the size is reasonable -- i.e. not ridiculously large or small.
- ok(100 * 1000 <= n && n <= 10 * 1000 * 1000 * 1000,
+ ok((100 * 1000 <= n && n <= 10 * 1000 * 1000 * 1000) || aCanBeUnreasonable,
aName + "'s size is reasonable");
}
@@ -192,7 +192,8 @@
if (haveExplicit) {
checkSpecialReport("heap-allocated", heapAllocatedAmounts);
}
- checkSpecialReport("vsize", vsizeAmounts);
+ // vsize may be unreasonable if ASAN is enabled
+ checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true);
checkSpecialReport("resident", residentAmounts);
checkSpecialReport("js-main-runtime-gc-heap-committed/used/gc-things", jsGcHeapAmounts);
diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul
index 2be3d7c468f..2c1e726821b 100644
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters2.xul
@@ -19,15 +19,11 @@
SimpleTest.waitForExplicitFinish();
- // We want to know when a remote process sends us an update.
- let os = Cc["@mozilla.org/observer-service;1"]
- .getService(Ci.nsIObserverService);
- os.addObserver(childMemoryReporterUpdate, "child-memory-reporter-update", false);
-
let numRemotes = 3;
+ let numReady = 0;
- // Create some remote processes, and set up message-passing so that go() is
- // called once per process, once it is fully initialized.
+ // Create some remote processes, and set up message-passing so that
+ // we know when each child is fully initialized.
let remotes = [];
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", 3]]}, function() {
for (let i = 0; i < numRemotes; i++) {
@@ -39,47 +35,40 @@
let mm = remoteBrowser.messageManager;
mm.addMessageListener("test:ready", function readyHandler() {
mm.removeMessageListener("test:ready", readyHandler);
- remoteReady();
+ numReady++;
+ if (numReady == numRemotes) {
+ // All the remote processes are ready. Do memory reporting.
+ doReports();
+ }
});
mm.loadFrameScript("data:," + encodeURI("sendAsyncMessage('test:ready');"), true);
});
}
});
- let numReady = 0;
+ let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
+ getService(Ci.nsIMemoryReporterManager);
- function remoteReady()
+ function doReports()
{
- numReady++;
- if (numReady == numRemotes) {
- // All the remote processes are ready. Ask them for memory reports.
- os.notifyObservers(null, "child-memory-reporter-request", null);
- }
- }
+ let residents = {};
- let numUpdates = 0;
-
- function childMemoryReporterUpdate()
- {
- numUpdates++;
- if (numUpdates == numRemotes) {
- // All the remote processes have reported back. Check reports.
- let vsizes = {};
-
- // Get all the reports.
- let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
- getService(Ci.nsIMemoryReporterManager);
- let e = mgr.enumerateReporters();
- while (e.hasMoreElements()) {
- let r = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
- r.collectReports(function(aProcess, aPath, aKind, aUnits, aAmount, aDesc) {
- if (aPath === "vsize") {
- ok(100 * 1000 <= aAmount && aAmount <= 10 * 1000 * 1000 * 1000,
- "vsize is reasonable");
- vsizes[aProcess] = aAmount;
- }
- }, null);
+ let handleReport = function(aProcess, aPath, aKind, aUnits, aAmount, aDesc) {
+ if (aPath === "resident") {
+ ok(100 * 1000 <= aAmount && aAmount <= 10 * 1000 * 1000 * 1000,
+ "resident is reasonable");
+ residents[aProcess] = aAmount;
}
+ }
+
+ let processReports = function() {
+ // First, test a failure case: calling getReports() before the previous
+ // getReports() has finished should silently abort. (And the arguments
+ // won't be used.)
+ mgr.getReports(
+ () => ok(false, "handleReport called for nested getReports() call"),
+ null, null, null
+ );
// Close the remote processes.
for (let i = 0; i < numRemotes; i++) {
@@ -88,8 +77,8 @@
// Check the results.
- let processes = Object.keys(vsizes);
- ok(processes.length == numRemotes + 1, "correct vsize count");
+ let processes = Object.keys(residents);
+ ok(processes.length == numRemotes + 1, "correct resident count");
let numEmptyProcesses = 0, numNonEmptyProcesses = 0;
for (let i = 0; i < processes.length; i++) {
@@ -107,6 +96,9 @@
SimpleTest.finish();
}
+
+ mgr.getReports(handleReport, null, processReports, null);
}
+
]]>
diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp
index 1bcd577a9e5..ba01e6f0f6c 100644
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -2387,21 +2387,14 @@ nsCycleCollector::CollectWhite()
// Memory reporter
////////////////////////
-class CycleCollectorReporter MOZ_FINAL : public nsIMemoryReporter
+class CycleCollectorReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
CycleCollectorReporter(nsCycleCollector* aCollector)
- : mCollector(aCollector)
+ : MemoryMultiReporter("cycle-collector"),
+ mCollector(aCollector)
{}
- NS_DECL_ISUPPORTS
-
- NS_IMETHOD GetName(nsACString& name)
- {
- name.AssignLiteral("cycle-collector");
- return NS_OK;
- }
-
NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
nsISupports* aClosure)
{
@@ -2461,8 +2454,6 @@ class CycleCollectorReporter MOZ_FINAL : public nsIMemoryReporter
nsCycleCollector* mCollector;
};
-NS_IMPL_ISUPPORTS1(CycleCollectorReporter, nsIMemoryReporter)
-
////////////////////////////////////////////////////////////////////////
// Collector implementation
diff --git a/xpcom/base/nsIMemoryInfoDumper.idl b/xpcom/base/nsIMemoryInfoDumper.idl
index 7042f778e97..6566c1d52ab 100644
--- a/xpcom/base/nsIMemoryInfoDumper.idl
+++ b/xpcom/base/nsIMemoryInfoDumper.idl
@@ -5,13 +5,18 @@
#include "nsISupports.idl"
-[scriptable, builtinclass, uuid(3FFA5113-2A10-43BB-923B-6A2FAF67BE97)]
+[scriptable, function, uuid(2dea18fc-fbfa-4bf7-ad45-0efaf5495f5e)]
+interface nsIFinishDumpingCallback : nsISupports
+{
+ void callback(in nsISupports data);
+};
+
+[scriptable, builtinclass, uuid(fd5de30a-e3d6-4965-8244-86709e1ed23b)]
interface nsIMemoryInfoDumper : nsISupports
{
/**
- * This dumps gzipped memory reports for this process. If a file of the
- * given name exists, it will be overwritten. Nothing is done for any child
- * processes (and their children, recursively).
+ * This dumps gzipped memory reports for this process and its child
+ * processes. If a file of the given name exists, it will be overwritten.
*
* @param aFilename The output file.
*
@@ -83,17 +88,19 @@ interface nsIMemoryInfoDumper : nsISupports
* }
* }
*/
- void dumpMemoryReportsToNamedFile(in AString aFilename);
+ void dumpMemoryReportsToNamedFile(in AString aFilename,
+ in nsIFinishDumpingCallback aFinishDumping,
+ in nsISupports aFinishDumpingData);
/**
* Similar to dumpMemoryReportsToNamedFile, this method dumps gzipped memory
- * reports for this process and possibly our child processes (and their
+ * reports for this process and possibly its child processes (and their
* children, recursively) to a file in the tmp directory called
* memory-reports--.json.gz (or something similar, such as
* memory-reports---1.json.gz; no existing file will be
* overwritten).
*
- * If DMD is enabled, this method also dump gzipped DMD output to a file in
+ * If DMD is enabled, this method also dumps gzipped DMD output to a file in
* the tmp directory called dmd--.txt.gz (or something
* similar; again, no existing file will be overwritten).
*
diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl
index 56943cc3fd3..4a6a551ba45 100644
--- a/xpcom/base/nsIMemoryReporter.idl
+++ b/xpcom/base/nsIMemoryReporter.idl
@@ -179,13 +179,19 @@ interface nsIMemoryReporter : nsISupports
const int32_t UNITS_PERCENTAGE = 3;
};
-[scriptable, builtinclass, uuid(4db7040a-16f9-4249-879b-fe72729c7ef5)]
+[scriptable, function, uuid(548b3909-c04d-4ca6-8466-b8bee3837457)]
+interface nsIFinishReportingCallback : nsISupports
+{
+ void callback(in nsISupports data);
+};
+
+[scriptable, builtinclass, uuid(a1292276-726b-4ef5-a017-5a455d6664dd)]
interface nsIMemoryReporterManager : nsISupports
{
/*
- * Return an enumerator of nsIMemoryReporters that are currently registered.
+ * Initialize.
*/
- nsISimpleEnumerator enumerateReporters();
+ void init();
/*
* Register the given nsIMemoryReporter. After a reporter is registered,
@@ -207,9 +213,30 @@ interface nsIMemoryReporterManager : nsISupports
void registerReporterEvenIfBlocked(in nsIMemoryReporter aReporter);
/*
- * Initialize.
+ * Return an enumerator of nsIMemoryReporters that are currently registered
+ * in the current process. WARNING: this does not do anything with child
+ * processes. Use getReports() if you want measurements from child
+ * processes.
*/
- void init();
+ nsISimpleEnumerator enumerateReporters();
+
+ /*
+ * Get memory reports for the current process and all child processes.
+ * |handleReport| is called for each report, and |finishReporting| is called
+ * once all reports have been handled.
+ *
+ * |finishReporting| is called even if, for example, some child processes
+ * fail to report back. However, calls to this method will silently and
+ * immediately abort -- and |finishReporting| will not be called -- if a
+ * previous getReports() call is still in flight, i.e. if it has not yet
+ * finished invoking |finishReporting|. The silent abort is because the
+ * in-flight request will finish soon, and the caller would very likely just
+ * catch and ignore any error anyway.
+ */
+ void getReports(in nsIMemoryReporterCallback handleReport,
+ in nsISupports handleReportData,
+ in nsIFinishReportingCallback finishReporting,
+ in nsISupports finishReportingData);
/*
* The memory reporter manager, for the most part, treats reporters
@@ -332,9 +359,14 @@ interface nsIMemoryReporterManager : nsISupports
#include "js/TypeDecls.h"
#include "nsStringGlue.h"
+#include "nsTArray.h"
class nsPIDOMWindow;
+// nsIHandleReportCallback is a better name, but keep nsIMemoryReporterCallback
+// around for backwards compatibility.
+typedef nsIMemoryReporterCallback nsIHandleReportCallback;
+
// Note that the memory reporters are held in an nsCOMArray, which means
// that individual reporters should be referenced with |nsIMemoryReporter *|
// instead of nsCOMPtr.
@@ -396,8 +428,9 @@ nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn);
#if defined(MOZ_DMD)
namespace mozilla {
namespace dmd {
-// This runs all the memory reporters but does nothing with the results; i.e.
-// it does the minimal amount of work possible for DMD to do its thing.
+// 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 RunReporters();
}
}
@@ -459,18 +492,18 @@ namespace mozilla {
// memory uni-reporters. You just need to provide the following.
// - The constant values: nameAndPath (which serves as both the reporters name,
// and the path in its single report), kind, units, and description. They
-// are passed to the MemoryUniReporter constructor.
-// - A (private) Amount() or (public) GetAmount() method. It can use the
+// are arguments to the MemoryUniReporter constructor.
+// - A private Amount() or public GetAmount() method. It can use the
// MallocSizeOf method if necessary. (There is also
// MallocSizeOfOn{Alloc,Free}, which can be useful.) Use Amount() if the
// reporter is infallible, and GetAmount() otherwise. (If you fail to
// provide one or the other, you'll get assertion failures when the memory
// reporter runs.)
//
-// The class name of subclasses should match the path, minus the "explicit"
-// (if present), and with "Reporter" at the end. For example:
-// - "explicit/dom/xyzzy" --> DOMXyzzyReporter
-// - "js-compartments/system" --> JSCompartmentsSystemReporter
+// The class name of subclasses should match the nameAndPath, minus the
+// "explicit" (if present), and with "Reporter" at the end. For example:
+// - nameAndPath == "explicit/dom/xyzzy" --> DOMXyzzyReporter
+// - nameAndPath == "js-compartments/system" --> JSCompartmentsSystemReporter
//
class MemoryUniReporter : public nsIMemoryReporter
{
@@ -528,6 +561,46 @@ protected:
const nsCString mDescription;
};
+// The following base class reduces the amount of boilerplate code required for
+// memory multi-reporters. You just need to provide the following.
+// - The constant value: name. It is an argument to the MemoryMultiReporter
+// constructor. The name of each multi-reporter should be unique.
+// - A public CollectReports() method. It can use the MallocSizeOf method if
+// necessary. (There is also MallocSizeOfOn{Alloc,Free}, which can be
+// useful.)
+//
+// The class name of subclasses should match the name, with "Reporter" at
+// the end. For example:
+// - name == "foo" --> FooMultiReporter
+//
+class MemoryMultiReporter : public nsIMemoryReporter
+{
+public:
+ MemoryMultiReporter(const char* aName)
+ : mName(aName)
+ {}
+
+ virtual ~MemoryMultiReporter() {}
+
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ NS_IMETHOD GetName(nsACString& aName)
+ {
+ aName.Assign(mName);
+ return NS_OK;
+ }
+
+ NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCb,
+ nsISupports* aClosure) = 0;
+
+protected:
+ NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(MallocSizeOf)
+ NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_ALLOC_FUN(MallocSizeOfOnAlloc)
+ NS_MEMORY_REPORTER_MALLOC_SIZEOF_ON_FREE_FUN(MallocSizeOfOnFree)
+
+ const nsCString mName;
+};
+
} // namespace mozilla
%}
diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp
index 82d046a5d6a..c5ae19f0840 100644
--- a/xpcom/base/nsMemoryInfoDumper.cpp
+++ b/xpcom/base/nsMemoryInfoDumper.cpp
@@ -610,32 +610,33 @@ namespace mozilla {
} while (0)
static nsresult
-DumpReport(nsIGZFileWriter *aWriter, bool *aIsFirstPtr,
+DumpReport(nsIGZFileWriter *aWriter, bool aIsFirst,
const nsACString &aProcess, const nsACString &aPath, int32_t aKind,
int32_t aUnits, int64_t aAmount, const nsACString &aDescription)
{
- // We only want to dump reports for this process. If |aProcess| is
- // non-nullptr that means we've received it from another process in response
- // to a "child-memory-reporter-request" event; ignore such reports.
- if (!aProcess.IsEmpty()) {
- return NS_OK;
- }
+ DUMP(aWriter, aIsFirst ? "[" : ",");
- DUMP(aWriter, *aIsFirstPtr ? "[" : ",");
- *aIsFirstPtr = false;
-
- // Generate the process identifier, which is of the form "$PROCESS_NAME
- // (pid $PID)", or just "(pid $PID)" if we don't have a process name. If
- // we're the main process, we let $PROCESS_NAME be "Main Process".
nsAutoCString process;
- if (XRE_GetProcessType() == GeckoProcessType_Default) {
- // We're the main process.
- process.AssignLiteral("Main Process ");
- } else if (ContentChild *cc = ContentChild::GetSingleton()) {
- // Try to get the process name from ContentChild.
- cc->GetProcessName(process);
+ if (aProcess.IsEmpty()) {
+ // If the process is empty, the report originated with the process doing
+ // the dumping. In that case, generate the process identifier, which is of
+ // the form "$PROCESS_NAME (pid $PID)", or just "(pid $PID)" if we don't
+ // have a process name. If we're the main process, we let $PROCESS_NAME be
+ // "Main Process".
+ if (XRE_GetProcessType() == GeckoProcessType_Default) {
+ // We're the main process.
+ process.AssignLiteral("Main Process");
+ } else if (ContentChild *cc = ContentChild::GetSingleton()) {
+ // Try to get the process name from ContentChild.
+ cc->GetProcessName(process);
+ }
+ ContentChild::AppendProcessId(process);
+
+ } else {
+ // Otherwise, the report originated with another process and already has a
+ // process name. Just use that.
+ process = aProcess;
}
- ContentChild::AppendProcessId(process);
DUMP(aWriter, "\n {\"process\": \"");
DUMP(aWriter, process);
@@ -666,12 +667,12 @@ DumpReport(nsIGZFileWriter *aWriter, bool *aIsFirstPtr,
return NS_OK;
}
-class DumpReporterCallback MOZ_FINAL : public nsIMemoryReporterCallback
+class DumpReportCallback MOZ_FINAL : public nsIHandleReportCallback
{
public:
NS_DECL_ISUPPORTS
- DumpReporterCallback() : mIsFirst(true) {}
+ DumpReportCallback() : mIsFirst(true) {}
NS_IMETHOD Callback(const nsACString &aProcess, const nsACString &aPath,
int32_t aKind, int32_t aUnits, int64_t aAmount,
@@ -681,15 +682,17 @@ public:
nsCOMPtr writer = do_QueryInterface(aData);
NS_ENSURE_TRUE(writer, NS_ERROR_FAILURE);
- return DumpReport(writer, &mIsFirst, aProcess, aPath, aKind, aUnits,
- aAmount, aDescription);
+ nsresult rv = DumpReport(writer, mIsFirst, aProcess, aPath, aKind, aUnits,
+ aAmount, aDescription);
+ mIsFirst = false;
+ return rv;
}
private:
bool mIsFirst;
};
-NS_IMPL_ISUPPORTS1(DumpReporterCallback, nsIMemoryReporterCallback)
+NS_IMPL_ISUPPORTS1(DumpReportCallback, nsIHandleReportCallback)
} // namespace mozilla
@@ -785,7 +788,7 @@ DMDWrite(void* aState, const char* aFmt, va_list ap)
#endif
static nsresult
-DumpProcessMemoryReportsToGZFileWriter(nsIGZFileWriter *aWriter)
+DumpHeader(nsIGZFileWriter* aWriter)
{
// Increment this number if the format changes.
//
@@ -804,22 +807,39 @@ DumpProcessMemoryReportsToGZFileWriter(nsIGZFileWriter *aWriter)
DUMP(aWriter, ",\n");
DUMP(aWriter, " \"reports\": ");
- // Process reporters.
- bool more;
- nsCOMPtr e;
- mgr->EnumerateReporters(getter_AddRefs(e));
- nsRefPtr cb = new DumpReporterCallback();
- while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
- nsCOMPtr r;
- e->GetNext(getter_AddRefs(r));
- r->CollectReports(cb, aWriter);
- }
+ return NS_OK;
+}
+static nsresult
+DumpFooter(nsIGZFileWriter* aWriter)
+{
DUMP(aWriter, "\n ]\n}\n");
return NS_OK;
}
+static nsresult
+DumpProcessMemoryReportsToGZFileWriter(nsIGZFileWriter* aWriter)
+{
+ nsresult rv = DumpHeader(aWriter);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Process reporters.
+ bool more;
+ nsCOMPtr e;
+ nsCOMPtr mgr =
+ do_GetService("@mozilla.org/memory-reporter-manager;1");
+ mgr->EnumerateReporters(getter_AddRefs(e));
+ nsRefPtr dumpReport = new DumpReportCallback();
+ while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
+ nsCOMPtr r;
+ e->GetNext(getter_AddRefs(r));
+ r->CollectReports(dumpReport, aWriter);
+ }
+
+ return DumpFooter(aWriter);
+}
+
nsresult
DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier)
{
@@ -977,8 +997,45 @@ nsMemoryInfoDumper::DumpMemoryInfoToTempDir(const nsAString& aIdentifier,
return DumpProcessMemoryInfoToTempDir(identifier);
}
+// This dumps the JSON footer and closes the file, and then calls the given
+// nsIFinishDumpingCallback.
+class FinishReportingCallback MOZ_FINAL : public nsIFinishReportingCallback
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ FinishReportingCallback(nsIFinishDumpingCallback* aFinishDumping,
+ nsISupports* aFinishDumpingData)
+ : mFinishDumping(aFinishDumping)
+ , mFinishDumpingData(aFinishDumpingData)
+ {}
+
+ NS_IMETHOD Callback(nsISupports* aData)
+ {
+ nsCOMPtr writer = do_QueryInterface(aData);
+ NS_ENSURE_TRUE(writer, NS_ERROR_FAILURE);
+
+ nsresult rv = DumpFooter(writer);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = writer->Finish();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return mFinishDumping->Callback(mFinishDumpingData);
+ }
+
+private:
+ nsCOMPtr mFinishDumping;
+ nsCOMPtr mFinishDumpingData;
+};
+
+NS_IMPL_ISUPPORTS1(FinishReportingCallback, nsIFinishReportingCallback)
+
NS_IMETHODIMP
-nsMemoryInfoDumper::DumpMemoryReportsToNamedFile(const nsAString& aFilename)
+nsMemoryInfoDumper::DumpMemoryReportsToNamedFile(
+ const nsAString& aFilename,
+ nsIFinishDumpingCallback* aFinishDumping,
+ nsISupports* aFinishDumpingData)
{
MOZ_ASSERT(!aFilename.IsEmpty());
@@ -1006,12 +1063,16 @@ nsMemoryInfoDumper::DumpMemoryReportsToNamedFile(const nsAString& aFilename)
rv = mrWriter->Init(mrFile);
NS_ENSURE_SUCCESS(rv, rv);
- DumpProcessMemoryReportsToGZFileWriter(mrWriter);
-
- rv = mrWriter->Finish();
+ rv = DumpHeader(mrWriter);
NS_ENSURE_SUCCESS(rv, rv);
- return NS_OK;
+ // Process reports and finish up.
+ nsRefPtr dumpReport = new DumpReportCallback();
+ nsRefPtr finishReporting =
+ new FinishReportingCallback(aFinishDumping, aFinishDumpingData);
+ nsCOMPtr mgr =
+ do_GetService("@mozilla.org/memory-reporter-manager;1");
+ return mgr->GetReports(dumpReport, mrWriter, finishReporting, mrWriter);
}
#undef DUMP
diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp
index 373be344be9..bf3f6ec5914 100644
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -11,6 +11,7 @@
#include "nsServiceManagerUtils.h"
#include "nsMemoryReporterManager.h"
#include "nsISimpleEnumerator.h"
+#include "nsITimer.h"
#include "nsThreadUtils.h"
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
@@ -23,6 +24,7 @@
#include "mozilla/PodOperations.h"
#include "mozilla/Services.h"
#include "mozilla/Telemetry.h"
+#include "mozilla/dom/PMemoryReportRequestParent.h" // for dom::MemoryReport
#ifndef XP_WIN
#include
@@ -665,21 +667,14 @@ private:
namespace mozilla {
namespace dmd {
-class DMDReporter MOZ_FINAL : public nsIMemoryReporter
+class DMDReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
DMDReporter()
+ : MemoryMultiReporter("dmd")
{}
- NS_DECL_ISUPPORTS
-
- NS_IMETHOD GetName(nsACString& aName)
- {
- aName.Assign("dmd");
- return NS_OK;
- }
-
- NS_IMETHOD CollectReports(nsIMemoryReporterCallback* aCallback,
+ NS_IMETHOD CollectReports(nsIHandleReport* aHandleReport,
nsISupports* aData)
{
dmd::Sizes sizes;
@@ -688,10 +683,10 @@ public:
#define REPORT(_path, _amount, _desc) \
do { \
nsresult rv; \
- rv = aCallback->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
- nsIMemoryReporter::KIND_HEAP, \
- nsIMemoryReporter::UNITS_BYTES, _amount, \
- NS_LITERAL_CSTRING(_desc), aData); \
+ rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
+ nsIMemoryReporter::KIND_HEAP, \
+ nsIMemoryReporter::UNITS_BYTES, _amount, \
+ NS_LITERAL_CSTRING(_desc), aData); \
NS_ENSURE_SUCCESS(rv, rv); \
} while (0)
@@ -719,8 +714,6 @@ public:
}
};
-NS_IMPL_ISUPPORTS1(DMDReporter, nsIMemoryReporter)
-
} // namespace dmd
} // namespace mozilla
@@ -845,10 +838,11 @@ HashtableEnumerator::GetNext(nsISupports** aNext)
nsMemoryReporterManager::nsMemoryReporterManager()
: mMutex("nsMemoryReporterManager::mMutex"),
- mIsRegistrationBlocked(false)
+ mIsRegistrationBlocked(false),
+ mNumChildProcesses(0),
+ mNextGeneration(1),
+ mGetReportsState(nullptr)
{
- PodZero(&mAmountFns);
- PodZero(&mSizeOfTabFns);
}
nsMemoryReporterManager::~nsMemoryReporterManager()
@@ -858,8 +852,8 @@ nsMemoryReporterManager::~nsMemoryReporterManager()
NS_IMETHODIMP
nsMemoryReporterManager::EnumerateReporters(nsISimpleEnumerator** aResult)
{
- // Memory reporters are not necessarily threadsafe, so EnumerateReporters()
- // must be called from the main thread.
+ // Memory reporters are not necessarily threadsafe, so this function must
+ // be called from the main thread.
if (!NS_IsMainThread()) {
MOZ_CRASH();
}
@@ -872,6 +866,220 @@ nsMemoryReporterManager::EnumerateReporters(nsISimpleEnumerator** aResult)
return NS_OK;
}
+//#define DEBUG_CHILD_PROCESS_MEMORY_REPORTING 1
+
+#ifdef DEBUG_CHILD_PROCESS_MEMORY_REPORTING
+#define MEMORY_REPORTING_LOG(format, ...) \
+ fprintf(stderr, "++++ MEMORY REPORTING: " format, ##__VA_ARGS__);
+#else
+#define MEMORY_REPORTING_LOG(...)
+#endif
+
+void
+nsMemoryReporterManager::IncrementNumChildProcesses()
+{
+ if (!NS_IsMainThread()) {
+ MOZ_CRASH();
+ }
+ mNumChildProcesses++;
+ MEMORY_REPORTING_LOG("IncrementNumChildProcesses --> %d\n",
+ mNumChildProcesses);
+}
+
+void
+nsMemoryReporterManager::DecrementNumChildProcesses()
+{
+ if (!NS_IsMainThread()) {
+ MOZ_CRASH();
+ }
+ MOZ_ASSERT(mNumChildProcesses > 0);
+ mNumChildProcesses--;
+ MEMORY_REPORTING_LOG("DecrementNumChildProcesses --> %d\n",
+ mNumChildProcesses);
+}
+
+NS_IMETHODIMP
+nsMemoryReporterManager::GetReports(
+ nsIHandleReportCallback* aHandleReport,
+ nsISupports* aHandleReportData,
+ nsIFinishReportingCallback* aFinishReporting,
+ nsISupports* aFinishReportingData)
+{
+ // Memory reporters are not necessarily threadsafe, so this function must
+ // be called from the main thread.
+ if (!NS_IsMainThread()) {
+ MOZ_CRASH();
+ }
+
+ uint32_t generation = mNextGeneration++;
+
+ 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, mGetReportsState->mGeneration);
+ return NS_OK;
+ }
+
+ MEMORY_REPORTING_LOG("GetReports (gen=%u, %d child(ren) present)\n",
+ generation, mNumChildProcesses);
+
+ if (mNumChildProcesses > 0) {
+ // Request memory reports from child processes. We do this *before*
+ // collecting reports for this process so each process can collect
+ // reports in parallel.
+ nsCOMPtr obs =
+ do_GetService("@mozilla.org/observer-service;1");
+ NS_ENSURE_STATE(obs);
+
+ // Casting the uint32_t generation to |const PRUnichar*| is a hack, but
+ // simpler than converting the number to an actual string.
+ obs->NotifyObservers(nullptr, "child-memory-reporter-request",
+ (const PRUnichar*)(uintptr_t)generation);
+
+ nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID);
+ NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
+ nsresult rv = timer->InitWithFuncCallback(TimeoutCallback,
+ this, kTimeoutLengthMS,
+ nsITimer::TYPE_ONE_SHOT);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mGetReportsState = new GetReportsState(generation,
+ timer,
+ mNumChildProcesses,
+ aHandleReport,
+ aHandleReportData,
+ aFinishReporting,
+ aFinishReportingData);
+ }
+
+ // Get reports for this process.
+ nsRefPtr e;
+ {
+ mozilla::MutexAutoLock autoLock(mMutex);
+ e = new HashtableEnumerator(mReporters);
+ }
+ bool more;
+ while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
+ nsCOMPtr r;
+ e->GetNext(getter_AddRefs(r));
+ r->CollectReports(aHandleReport, aHandleReportData);
+ }
+
+ // If there are no child processes, we can finish up immediately.
+ return (mNumChildProcesses == 0)
+ ? aFinishReporting->Callback(aFinishReportingData)
+ : NS_OK;
+}
+
+// This function has no return value. If something goes wrong, there's no
+// clear place to report the problem to, but that's ok -- we will end up
+// hitting the timeout and executing TimeoutCallback().
+void
+nsMemoryReporterManager::HandleChildReports(
+ const uint32_t& aGeneration,
+ const InfallibleTArray& aChildReports)
+{
+ // Memory reporting only happens on the main thread.
+ if (!NS_IsMainThread()) {
+ MOZ_CRASH();
+ }
+
+ GetReportsState* s = mGetReportsState;
+
+ if (!s) {
+ // If we reach here, either:
+ //
+ // - A child process reported back too late, and no subsequent request
+ // is in flight.
+ //
+ // - (Unlikely) A "child-memory-reporter-request" notification was
+ // triggered from somewhere other than GetReports(), causing child
+ // processes to report back when the nsMemoryReporterManager wasn't
+ // expecting it.
+ //
+ // Either way, there's nothing to be done. Just ignore it.
+ MEMORY_REPORTING_LOG(
+ "HandleChildReports: no request in flight (aGen=%u)\n",
+ aGeneration);
+ return;
+ }
+
+ if (aGeneration != s->mGeneration) {
+ // If we reach here, a child process must have reported back, too late,
+ // while a subsequent (higher-numbered) request is in flight. Again,
+ // ignore it.
+ MOZ_ASSERT(aGeneration < s->mGeneration);
+ MEMORY_REPORTING_LOG(
+ "HandleChildReports: gen mismatch (aGen=%u, s->gen=%u)\n",
+ aGeneration, s->mGeneration);
+ return;
+ }
+
+ // Process the reports from the child process.
+ for (uint32_t i = 0; i < aChildReports.Length(); i++) {
+ const dom::MemoryReport& r = aChildReports[i];
+
+ // Child reports should have a non-empty process.
+ MOZ_ASSERT(!r.process().IsEmpty());
+
+ // If the call fails, ignore and continue.
+ s->mHandleReport->Callback(r.process(), r.path(), r.kind(),
+ r.units(), r.amount(), r.desc(),
+ s->mHandleReportData);
+ }
+
+ // If all the child processes have reported, we can cancel the timer and
+ // finish up. Otherwise, just return.
+
+ s->mNumChildProcessesCompleted++;
+ MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): completed child %d\n",
+ aGeneration, s->mNumChildProcessesCompleted);
+
+ if (s->mNumChildProcessesCompleted == s->mNumChildProcesses) {
+ s->mTimer->Cancel();
+ FinishReporting();
+ }
+}
+
+/* static */ void
+nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData)
+{
+ nsMemoryReporterManager* mgr =
+ static_cast(aData);
+
+ MOZ_ASSERT(mgr->mGetReportsState);
+ MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u)\n",
+ mgr->mGetReportsState->mGeneration);
+
+ // We don't bother sending any kind of cancellation message to the child
+ // processes that haven't reported back.
+
+ mgr->FinishReporting();
+}
+
+void
+nsMemoryReporterManager::FinishReporting()
+{
+ // Memory reporting only happens on the main thread.
+ if (!NS_IsMainThread()) {
+ MOZ_CRASH();
+ }
+
+ MOZ_ASSERT(mGetReportsState);
+ MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u)\n",
+ mGetReportsState->mGeneration);
+
+ // Call this before deleting |mGetReportsState|. That way, if
+ // |mFinishReportData| calls GetReports(), it will silently abort, as
+ // required.
+ (void)mGetReportsState->mFinishReporting->Callback(
+ mGetReportsState->mFinishReportingData);
+
+ delete mGetReportsState;
+ mGetReportsState = nullptr;
+}
+
static void
DebugAssertRefcountIsNonZero(nsISupports* aObj)
{
@@ -975,7 +1183,7 @@ public:
};
NS_IMPL_ISUPPORTS0(Int64Wrapper)
-class ExplicitCallback MOZ_FINAL : public nsIMemoryReporterCallback
+class ExplicitCallback MOZ_FINAL : public nsIHandleReportCallback
{
public:
NS_DECL_ISUPPORTS
@@ -1002,7 +1210,7 @@ public:
return NS_OK;
}
};
-NS_IMPL_ISUPPORTS1(ExplicitCallback, nsIMemoryReporterCallback)
+NS_IMPL_ISUPPORTS1(ExplicitCallback, nsIHandleReportCallback)
NS_IMETHODIMP
nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
@@ -1020,7 +1228,7 @@ nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
// method which did this more efficiently, but it ended up being more
// trouble than it was worth.
- nsRefPtr cb = new ExplicitCallback();
+ nsRefPtr handleReport = new ExplicitCallback();
nsRefPtr wrappedExplicitSize = new Int64Wrapper();
nsCOMPtr e;
@@ -1028,7 +1236,7 @@ nsMemoryReporterManager::GetExplicit(int64_t* aAmount)
while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
nsCOMPtr r;
e->GetNext(getter_AddRefs(r));
- r->CollectReports(cb, wrappedExplicitSize);
+ r->CollectReports(handleReport, wrappedExplicitSize);
}
*aAmount = wrappedExplicitSize->mValue;
@@ -1325,6 +1533,7 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow,
// thread-safe just to be safe. Memory reporters are created and destroyed
// infrequently enough that the performance cost should be negligible.
NS_IMPL_ISUPPORTS1(MemoryUniReporter, nsIMemoryReporter)
+NS_IMPL_ISUPPORTS1(MemoryMultiReporter, nsIMemoryReporter)
nsresult
NS_RegisterMemoryReporter(nsIMemoryReporter* aReporter)
@@ -1349,10 +1558,8 @@ NS_UnregisterMemoryReporter(nsIMemoryReporter* aReporter)
namespace mozilla {
#define GET_MEMORY_REPORTER_MANAGER(mgr) \
- nsCOMPtr imgr = \
- do_GetService("@mozilla.org/memory-reporter-manager;1"); \
nsRefPtr mgr = \
- static_cast(imgr.get()); \
+ nsMemoryReporterManager::GetOrCreate(); \
if (!mgr) { \
return NS_ERROR_FAILURE; \
}
@@ -1418,7 +1625,7 @@ DEFINE_REGISTER_SIZE_OF_TAB(NonJS);
namespace mozilla {
namespace dmd {
-class NullReporterCallback : public nsIMemoryReporterCallback
+class DoNothingCallback : public nsIHandleReportCallback
{
public:
NS_DECL_ISUPPORTS
@@ -1433,8 +1640,8 @@ public:
}
};
NS_IMPL_ISUPPORTS1(
- NullReporterCallback
-, nsIMemoryReporterCallback
+ DoNothingCallback
+, nsIHandleReportCallback
)
void
@@ -1443,7 +1650,7 @@ RunReporters()
nsCOMPtr mgr =
do_GetService("@mozilla.org/memory-reporter-manager;1");
- nsRefPtr cb = new NullReporterCallback();
+ nsRefPtr doNothing = new DoNothingCallback();
bool more;
nsCOMPtr e;
@@ -1451,7 +1658,7 @@ RunReporters()
while (NS_SUCCEEDED(e->HasMoreElements(&more)) && more) {
nsCOMPtr r;
e->GetNext(getter_AddRefs(r));
- r->CollectReports(cb, nullptr);
+ r->CollectReports(doNothing, nullptr);
}
}
diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h
index af46957a43a..f2107ceef7a 100644
--- a/xpcom/base/nsMemoryReporterManager.h
+++ b/xpcom/base/nsMemoryReporterManager.h
@@ -11,6 +11,14 @@
using mozilla::Mutex;
+class nsITimer;
+
+namespace mozilla {
+namespace dom {
+class MemoryReport;
+}
+}
+
class nsMemoryReporterManager : public nsIMemoryReporterManager
{
public:
@@ -20,6 +28,93 @@ public:
nsMemoryReporterManager();
virtual ~nsMemoryReporterManager();
+ // Gets the memory reporter manager service.
+ static nsMemoryReporterManager* GetOrCreate()
+ {
+ nsCOMPtr imgr =
+ do_GetService("@mozilla.org/memory-reporter-manager;1");
+ return static_cast(imgr.get());
+ }
+
+ void IncrementNumChildProcesses();
+ void DecrementNumChildProcesses();
+
+ // Inter-process memory reporting proceeds as follows.
+ //
+ // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER)
+ // synchronously gets memory reports for the current process, tells all
+ // child processes to get memory reports, and sets up some state
+ // (mGetReportsState) for when the child processes report back, including a
+ // timer. Control then returns to the main event loop.
+ //
+ // - HandleChildReports() is called (asynchronously) once per child process
+ // that reports back. If all child processes report back before time-out,
+ // the timer is cancelled. (The number of child processes is part of the
+ // saved request state.)
+ //
+ // - TimeoutCallback() is called (asynchronously) if all the child processes
+ // don't respond within the time threshold.
+ //
+ // - FinishReporting() finishes things off. It is *always* called -- either
+ // from HandleChildReports() (if all child processes have reported back) or
+ // from TimeoutCallback() (if time-out occurs).
+ //
+ // All operations occur on the main thread.
+ //
+ // The above sequence of steps is a "request". A partially-completed request
+ // is described as "in flight".
+ //
+ // Each request has a "generation", a unique number that identifies it. This
+ // is used to ensure that each reports from a child process corresponds to
+ // the appropriate request from the parent process. (It's easier to
+ // implement a generation system than to implement a child report request
+ // cancellation mechanism.)
+ //
+ // Failures are mostly ignored, because it's (a) typically the most sensible
+ // thing to do, and (b) often hard to do anything else. The following are
+ // the failure cases of note.
+ //
+ // - If a request is made while the previous request is in flight, the new
+ // request is ignored, as per getReports()'s specification. No error is
+ // reported, because the previous request will complete soon enough.
+ //
+ // - If one or more child processes fail to respond within the time limit,
+ // things will proceed as if they don't exist. No error is reported,
+ // because partial information is better than nothing.
+ //
+ // - If a child process reports after the time-out occurs, it is ignored.
+ // (Generation checking will ensure it is ignored even if a subsequent
+ // request is in flight; this is the main use of generations.) No error
+ // is reported, because there's nothing sensible to be done about it at
+ // this late stage.
+ //
+ // Now, what what happens if a child process is created/destroyed in the
+ // middle of a request? Well, GetReportsState contains a copy of
+ // mNumChildProcesses which it uses to determine finished-ness. So...
+ //
+ // - If a process is created, it won't have received the request for reports,
+ // and the GetReportsState's mNumChildProcesses won't account for it. So
+ // the reported data will reflect how things were when the request began.
+ //
+ // - If a process is destroyed before reporting back, we'll just hit the
+ // time-out, because we'll have received reports (barring other errors)
+ // from N-1 child process. So the reported data will reflect how things
+ // are when the request ends.
+ //
+ // - If a process is destroyed after reporting back, but before all other
+ // child processes have reported back, it will be included in the reported
+ // data. So the reported data will reflect how things were when the
+ // request began.
+ //
+ // The inconsistencies between these three cases are unfortunate but
+ // difficult to avoid. It's enough of an edge case to not be worth doing
+ // more.
+ //
+ void HandleChildReports(
+ const uint32_t& generation,
+ const InfallibleTArray& aChildReports);
+ void FinishReporting();
+
// Functions that (a) implement distinguished amounts, and (b) are outside of
// this module.
struct AmountFns {
@@ -36,6 +131,8 @@ public:
mozilla::InfallibleAmountFn mLowMemoryEventsPhysical;
mozilla::InfallibleAmountFn mGhostWindows;
+
+ AmountFns() { mozilla::PodZero(this); }
};
AmountFns mAmountFns;
@@ -43,15 +140,55 @@ public:
struct SizeOfTabFns {
mozilla::JSSizeOfTabFn mJS;
mozilla::NonJSSizeOfTabFn mNonJS;
+
+ SizeOfTabFns() { mozilla::PodZero(this); }
};
SizeOfTabFns mSizeOfTabFns;
private:
- nsresult RegisterReporterHelper(nsIMemoryReporter *aReporter, bool aForce);
+ nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter, bool aForce);
+
+ static void TimeoutCallback(nsITimer* aTimer, void* aData);
+ static const uint32_t kTimeoutLengthMS = 5000;
nsTHashtable mReporters;
Mutex mMutex;
bool mIsRegistrationBlocked;
+
+ uint32_t mNumChildProcesses;
+ uint32_t mNextGeneration;
+
+ struct GetReportsState {
+ uint32_t mGeneration;
+ nsCOMPtr mTimer;
+ uint32_t mNumChildProcesses;
+ uint32_t mNumChildProcessesCompleted;
+ nsCOMPtr mHandleReport;
+ nsCOMPtr mHandleReportData;
+ nsCOMPtr mFinishReporting;
+ nsCOMPtr mFinishReportingData;
+
+ GetReportsState(uint32_t aGeneration, nsITimer* aTimer,
+ uint32_t aNumChildProcesses,
+ nsIHandleReportCallback* aHandleReport,
+ nsISupports* aHandleReportData,
+ nsIFinishReportingCallback* aFinishReporting,
+ nsISupports* aFinishReportingData)
+ : mGeneration(aGeneration),
+ mTimer(aTimer),
+ mNumChildProcesses(aNumChildProcesses),
+ mNumChildProcessesCompleted(0),
+ mHandleReport(aHandleReport),
+ mHandleReportData(aHandleReportData),
+ mFinishReporting(aFinishReporting),
+ mFinishReportingData(aFinishReportingData)
+ {}
+ };
+
+ // 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.
+ GetReportsState* mGetReportsState;
};
#define NS_MEMORY_REPORTER_MANAGER_CID \
diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp
index d233be2bd0a..b62b5d18853 100644
--- a/xpcom/ds/nsObserverService.cpp
+++ b/xpcom/ds/nsObserverService.cpp
@@ -42,26 +42,22 @@ GetObserverServiceLog()
namespace mozilla {
-class ObserverServiceReporter MOZ_FINAL : public nsIMemoryReporter
+class ObserverServiceReporter MOZ_FINAL : public MemoryMultiReporter
{
public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIMEMORYREPORTER
+ ObserverServiceReporter()
+ : MemoryMultiReporter("observer-service")
+ {}
+
+ NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCb,
+ nsISupports *aClosure);
+
protected:
static const size_t kSuspectReferentCount = 100;
static PLDHashOperator CountReferents(nsObserverList* aObserverList,
void* aClosure);
};
-NS_IMPL_ISUPPORTS1(ObserverServiceReporter, nsIMemoryReporter)
-
-NS_IMETHODIMP
-ObserverServiceReporter::GetName(nsACString& aName)
-{
- aName.AssignLiteral("observer-service");
- return NS_OK;
-}
-
struct SuspectObserver {
SuspectObserver(const char* aTopic, size_t aReferentCount)
: topic(aTopic), referentCount(aReferentCount) {}