diff --git a/browser/components/contextualidentity/moz.build b/browser/components/contextualidentity/moz.build
new file mode 100644
index 0000000000..7e3ff07cbd
--- /dev/null
+++ b/browser/components/contextualidentity/moz.build
@@ -0,0 +1,12 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+BROWSER_CHROME_MANIFESTS += [
+ 'test/browser/browser.ini',
+]
+
+with Files('**'):
+ BUG_COMPONENT = ('Firefox', 'Contextual Identity')
diff --git a/browser/components/contextualidentity/test/browser/browser.ini b/browser/components/contextualidentity/test/browser/browser.ini
new file mode 100644
index 0000000000..58611df0ad
--- /dev/null
+++ b/browser/components/contextualidentity/test/browser/browser.ini
@@ -0,0 +1,7 @@
+[DEFAULT]
+skip-if = buildapp == "mulet"
+support-files =
+ file_reflect_cookie_into_title.html
+
+[browser_usercontext.js]
+skip-if = e10s
diff --git a/browser/components/contextualidentity/test/browser/browser_usercontext.js b/browser/components/contextualidentity/test/browser/browser_usercontext.js
new file mode 100644
index 0000000000..b59b5ac4c3
--- /dev/null
+++ b/browser/components/contextualidentity/test/browser/browser_usercontext.js
@@ -0,0 +1,91 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+const USER_CONTEXTS = [
+ "default",
+ "personal",
+ "work",
+];
+
+const BASE_URI = "http://mochi.test:8888/browser/browser/components/"
+ + "contextualidentity/test/browser/file_reflect_cookie_into_title.html";
+
+
+// opens `uri' in a new tab with the provided userContextId and focuses it.
+// returns the newly opened tab
+function openTabInUserContext(uri, userContextId) {
+ // open the tab in the correct userContextId
+ let tab = gBrowser.addTab(uri, {userContextId});
+
+ // select tab and make sure its browser is focused
+ gBrowser.selectedTab = tab;
+ tab.ownerDocument.defaultView.focus();
+
+ return tab;
+}
+
+add_task(function* setup() {
+ // make sure userContext is enabled.
+ SpecialPowers.pushPrefEnv({"set": [
+ ["privacy.userContext.enabled", true]
+ ]});
+});
+
+add_task(function* cleanup() {
+ // make sure we don't leave any prefs set for the next tests
+ registerCleanupFunction(function() {
+ SpecialPowers.popPrefEnv();
+ });
+});
+
+add_task(function* test() {
+ for (let userContextId of Object.keys(USER_CONTEXTS)) {
+ // load the page in 3 different contexts and set a cookie
+ // which should only be visible in that context
+ let cookie = USER_CONTEXTS[userContextId];
+
+ // open our tab in the given user context
+ let tab = openTabInUserContext(BASE_URI+"?"+cookie, userContextId);
+
+ // wait for tab load
+ yield BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab));
+
+ // remove the tab
+ gBrowser.removeTab(tab);
+ }
+
+ {
+ // Set a cookie in a different context so we can detect if that affects
+ // cross-context properly. If we don't do that, we get an UNEXPECTED-PASS
+ // for the localStorage case for the last tab we set.
+ let tab = openTabInUserContext(BASE_URI+"?foo", 9999);
+ yield BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab));
+ gBrowser.removeTab(tab);
+ }
+
+ for (let userContextId of Object.keys(USER_CONTEXTS)) {
+ // Load the page without setting the cookie this time
+ let expectedContext = USER_CONTEXTS[userContextId];
+
+ let tab = openTabInUserContext(BASE_URI, userContextId);
+
+ // wait for load
+ let browser = gBrowser.getBrowserForTab(tab);
+ yield BrowserTestUtils.browserLoaded(browser);
+
+ // get the title
+ let title = browser.contentDocument.title.trim().split("|");
+
+ // check each item in the title and validate it meets expectatations
+ for (let part of title) {
+ let [storageMethodName, value] = part.split("=");
+ let is_f = storageMethodName == "cookie" ? is : todo_is;
+ is_f(value, expectedContext,
+ "the title reflects the expected contextual identity of " +
+ expectedContext + " for method " + storageMethodName + ": " + value);
+ }
+
+ gBrowser.removeTab(tab);
+ }
+});
diff --git a/browser/components/contextualidentity/test/browser/file_reflect_cookie_into_title.html b/browser/components/contextualidentity/test/browser/file_reflect_cookie_into_title.html
new file mode 100644
index 0000000000..b04f3fd5ca
--- /dev/null
+++ b/browser/components/contextualidentity/test/browser/file_reflect_cookie_into_title.html
@@ -0,0 +1,23 @@
+
+
+
+ title not set
+
+
+
+
+
diff --git a/browser/components/moz.build b/browser/components/moz.build
index 3f92e577cb..1f4c17eeda 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -6,6 +6,7 @@
DIRS += [
'about',
+ 'contextualidentity',
'certerror',
'dirprovider',
'downloads',
diff --git a/config/nsinstall.c b/config/nsinstall.c
index 96d8c3a4c0..d36176c012 100644
--- a/config/nsinstall.c
+++ b/config/nsinstall.c
@@ -213,7 +213,6 @@ static void
copydir( char *from, char *to, mode_t mode, char *group, char *owner,
int dotimes, uid_t uid, gid_t gid)
{
- int i;
DIR *dir;
struct dirent *ep;
struct stat sb;
@@ -262,13 +261,12 @@ copydir( char *from, char *to, mode_t mode, char *group, char *owner,
int
main(int argc, char **argv)
{
- int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc;
+ int onlydir, dodir, dolink, dorelsymlink, dotimes, opt, len, lplen, tdlen, bnlen, exists;
mode_t mode = 0755;
- char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, *bp, buf[BUFSIZ];
+ char *linkprefix, *owner, *group, *cp, *cwd, *todir, *toname, *name, *base, *linkname, buf[BUFSIZ];
uid_t uid;
gid_t gid;
struct stat sb, tosb, fromsb;
- struct utimbuf utb;
program = argv[0];
cwd = linkname = linkprefix = owner = group = 0;
diff --git a/dom/base/nsCCUncollectableMarker.cpp b/dom/base/nsCCUncollectableMarker.cpp
index 5d3ed90efe..dc234e1857 100644
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -467,37 +467,6 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
-struct TraceClosure
-{
- TraceClosure(JSTracer* aTrc, uint32_t aGCNumber)
- : mTrc(aTrc), mGCNumber(aGCNumber)
- {}
- JSTracer* mTrc;
- uint32_t mGCNumber;
-};
-
-static PLDHashOperator
-TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
-{
- if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
- TraceClosure* closure = static_cast(aClosure);
- aWindow->TraceGlobalJSObject(closure->mTrc);
- EventListenerManager* elm = aWindow->GetExistingListenerManager();
- if (elm) {
- elm->TraceListeners(closure->mTrc);
- }
-
-#ifdef MOZ_XUL
- nsIDocument* doc = aWindow->GetExtantDoc();
- if (doc && doc->IsXULDocument()) {
- XULDocument* xulDoc = static_cast(doc);
- xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
- }
-#endif
- }
- return PL_DHASH_NEXT;
-}
-
void
mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC)
{
@@ -518,12 +487,27 @@ mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownG
return;
}
- TraceClosure closure(aTrc, aGCNumber);
-
// Mark globals of active windows black.
nsGlobalWindow::WindowByIdTable* windowsById =
nsGlobalWindow::GetWindowsTable();
if (windowsById) {
- windowsById->Enumerate(TraceActiveWindowGlobal, &closure);
+ for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
+ nsGlobalWindow* window = iter.Data();
+ if (window->GetDocShell() && window->IsOuterWindow()) {
+ window->TraceGlobalJSObject(aTrc);
+ EventListenerManager* elm = window->GetExistingListenerManager();
+ if (elm) {
+ elm->TraceListeners(aTrc);
+ }
+
+#ifdef MOZ_XUL
+ nsIDocument* doc = window->GetExtantDoc();
+ if (doc && doc->IsXULDocument()) {
+ XULDocument* xulDoc = static_cast(doc);
+ xulDoc->TraceProtos(aTrc, aGCNumber);
+ }
+#endif
+ }
+ }
}
}
diff --git a/dom/base/nsDOMAttributeMap.cpp b/dom/base/nsDOMAttributeMap.cpp
index 1f98ec3c24..346707ffe4 100644
--- a/dom/base/nsDOMAttributeMap.cpp
+++ b/dom/base/nsDOMAttributeMap.cpp
@@ -37,27 +37,18 @@ nsDOMAttributeMap::nsDOMAttributeMap(Element* aContent)
// we'll be told to drop our reference
}
-/**
- * Clear map pointer for attributes.
- */
-PLDHashOperator
-RemoveMapRef(nsAttrHashKey::KeyType aKey, RefPtr& aData,
- void* aUserArg)
-{
- aData->SetMap(nullptr);
-
- return PL_DHASH_REMOVE;
-}
-
nsDOMAttributeMap::~nsDOMAttributeMap()
{
- mAttributeCache.Enumerate(RemoveMapRef, nullptr);
+ DropReference();
}
void
nsDOMAttributeMap::DropReference()
{
- mAttributeCache.Enumerate(RemoveMapRef, nullptr);
+ for (auto iter = mAttributeCache.Iter(); !iter.Done(); iter.Next()) {
+ iter.Data()->SetMap(nullptr);
+ iter.Remove();
+ }
mContent = nullptr;
}
@@ -70,20 +61,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMAttributeMap)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-PLDHashOperator
-TraverseMapEntry(nsAttrHashKey::KeyType aKey, RefPtr& aData,
- void* aUserArg)
-{
- nsCycleCollectionTraversalCallback *cb =
- static_cast(aUserArg);
-
- cb->NoteXPCOMChild(static_cast(aData.get()));
-
- return PL_DHASH_NEXT;
-}
-
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttributeMap)
- tmp->mAttributeCache.Enumerate(TraverseMapEntry, &cb);
+ for (auto iter = tmp->mAttributeCache.Iter(); !iter.Done(); iter.Next()) {
+ cb.NoteXPCOMChild(static_cast(iter.Data().get()));
+ }
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp
index 74b013e180..096715bb92 100644
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -1624,15 +1624,6 @@ nsMessageManagerScriptExecutor::DidCreateGlobal()
}
}
-static PLDHashOperator
-RemoveCachedScriptEntry(const nsAString& aKey,
- nsMessageManagerScriptHolder*& aData,
- void* aUserArg)
-{
- delete aData;
- return PL_DHASH_REMOVE;
-}
-
// static
void
nsMessageManagerScriptExecutor::Shutdown()
@@ -1640,7 +1631,10 @@ nsMessageManagerScriptExecutor::Shutdown()
if (sCachedScripts) {
AutoSafeJSContext cx;
NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
- sCachedScripts->Enumerate(RemoveCachedScriptEntry, nullptr);
+ for (auto iter = sCachedScripts->Iter(); !iter.Done(); iter.Next()) {
+ delete iter.Data();
+ iter.Remove();
+ }
delete sCachedScripts;
sCachedScripts = nullptr;
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index e2c5fc925e..70eb7a4a45 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1622,6 +1622,9 @@ nsGlobalWindow::FreeInnerObjects(bool aForDocumentOpen)
// other members that the window destroyed observers could
// re-create.
NotifyDOMWindowDestroyed(this);
+ if (auto* reporter = nsWindowMemoryReporter::Get()) {
+ reporter->ObserveDOMWindowDetached(this);
+ }
mInnerObjectsFreed = true;
@@ -1737,13 +1740,6 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
-static PLDHashOperator
-MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap& aData, void* aClosure)
-{
- JS::ExposeObjectToActiveJS(aData);
- return PL_DHASH_NEXT;
-}
-
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
if (tmp->IsBlackForCC(false)) {
if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
@@ -1751,7 +1747,11 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
}
tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
if (tmp->mCachedXBLPrototypeHandlers) {
- tmp->mCachedXBLPrototypeHandlers->Enumerate(MarkXBLHandlers, nullptr);
+ for (auto iter = tmp->mCachedXBLPrototypeHandlers->Iter();
+ !iter.Done();
+ iter.Next()) {
+ JS::ExposeObjectToActiveJS(iter.Data());
+ }
}
if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
elm->MarkForCC();
@@ -1947,24 +1947,14 @@ nsGlobalWindow::RiskyUnlink()
}
#endif
-struct TraceData
-{
- const TraceCallbacks& callbacks;
- void* closure;
-};
-
-static PLDHashOperator
-TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap& aData, void* aClosure)
-{
- TraceData* data = static_cast(aClosure);
- data->callbacks.Trace(&aData, "Cached XBL prototype handler", data->closure);
- return PL_DHASH_NEXT;
-}
-
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
if (tmp->mCachedXBLPrototypeHandlers) {
- TraceData data = { aCallbacks, aClosure };
- tmp->mCachedXBLPrototypeHandlers->Enumerate(TraceXBLHandlers, &data);
+ for (auto iter = tmp->mCachedXBLPrototypeHandlers->Iter();
+ !iter.Done();
+ iter.Next()) {
+ JS::Heap& data = iter.Data();
+ aCallbacks.Trace(&data, "Cached XBL prototype handler", aClosure);
+ }
}
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
@@ -2949,8 +2939,9 @@ nsGlobalWindow::DetachFromDocShell()
inner->FreeInnerObjects();
}
- // Make sure that this is called before we null out the document.
- NotifyDOMWindowDestroyed(this);
+ if (auto* reporter = nsWindowMemoryReporter::Get()) {
+ reporter->ObserveDOMWindowDetached(this);
+ }
NotifyWindowIDDestroyed("outer-window-destroyed");
diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h
index 435757f744..383ea4e2f6 100644
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -17,6 +17,7 @@
#include "js/TypeDecls.h"
#include "nsRefPtrHashtable.h"
+// Only fired for inner windows.
#define DOM_WINDOW_DESTROYED_TOPIC "dom-window-destroyed"
#define DOM_WINDOW_FROZEN_TOPIC "dom-window-frozen"
#define DOM_WINDOW_THAWED_TOPIC "dom-window-thawed"
diff --git a/dom/base/nsScriptNameSpaceManager.h b/dom/base/nsScriptNameSpaceManager.h
index c7794945a5..38d099f9ae 100644
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -180,11 +180,6 @@ public:
aConstructorEnabled);
}
- typedef PLDHashOperator
- (* NameEnumerator)(const nsAString& aGlobalName,
- const nsGlobalNameStruct& aGlobalNameStruct,
- void* aClosure);
-
class NameIterator : public PLDHashTable::Iterator
{
public:
diff --git a/dom/base/nsWindowMemoryReporter.cpp b/dom/base/nsWindowMemoryReporter.cpp
index c3ea89d716..0b473826bf 100644
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -113,10 +113,6 @@ nsWindowMemoryReporter::Init()
nsCOMPtr os = services::GetObserverService();
if (os) {
- // DOM_WINDOW_DESTROYED_TOPIC announces what we call window "detachment",
- // when a window's docshell is set to nullptr.
- os->AddObserver(sWindowReporter, DOM_WINDOW_DESTROYED_TOPIC,
- /* weakRef = */ true);
os->AddObserver(sWindowReporter, "after-minimize-memory-usage",
/* weakRef = */ true);
os->AddObserver(sWindowReporter, "cycle-collector-begin",
@@ -129,6 +125,12 @@ nsWindowMemoryReporter::Init()
RegisterGhostWindowsDistinguishedAmount(GhostWindowsReporter::DistinguishedAmount);
}
+/* static */ nsWindowMemoryReporter*
+nsWindowMemoryReporter::Get()
+{
+ return sWindowReporter;
+}
+
static already_AddRefed
GetWindowURI(nsIDOMWindow *aWindow)
{
@@ -169,7 +171,7 @@ AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize)
if (uri) {
if (aAnonymize && !aWindow->IsChromeWindow()) {
- aStr.AppendPrintf("", aWindow->WindowID());
+ aStr.AppendPrintf("", aWindow->WindowID());
} else {
nsCString spec;
uri->GetSpec(spec);
@@ -278,9 +280,7 @@ CollectWindowReports(nsGlobalWindow *aWindow,
if (top) {
windowPath += NS_LITERAL_CSTRING("top(");
AppendWindowURI(top, windowPath, aAnonymize);
- windowPath += NS_LITERAL_CSTRING(", id=");
- windowPath.AppendInt(top->WindowID());
- windowPath += NS_LITERAL_CSTRING(")");
+ windowPath.AppendPrintf(", id=%llu)", top->WindowID());
aTopWindowPaths->Put(aWindow->WindowID(), windowPath);
@@ -448,15 +448,6 @@ CollectWindowReports(nsGlobalWindow *aWindow,
typedef nsTArray< RefPtr > WindowArray;
-static
-PLDHashOperator
-GetWindows(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
-{
- ((WindowArray *)aClosure)->AppendElement(aWindow);
-
- return PL_DHASH_NEXT;
-}
-
NS_IMETHODIMP
nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
nsISupports* aClosure, bool aAnonymize)
@@ -468,7 +459,9 @@ nsWindowMemoryReporter::CollectReports(nsIMemoryReporterCallback* aCb,
// Hold on to every window in memory so that window objects can't be
// destroyed while we're calling the memory reporter callback.
WindowArray windows;
- windowsById->Enumerate(GetWindows, &windows);
+ for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
+ windows.AppendElement(iter.Data());
+ }
// Get the IDs of all the "ghost" windows, and call aCb->Callback() for each
// one.
@@ -618,9 +611,7 @@ NS_IMETHODIMP
nsWindowMemoryReporter::Observe(nsISupports *aSubject, const char *aTopic,
const char16_t *aData)
{
- if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC)) {
- ObserveDOMWindowDetached(aSubject);
- } else if (!strcmp(aTopic, "after-minimize-memory-usage")) {
+ if (!strcmp(aTopic, "after-minimize-memory-usage")) {
ObserveAfterMinimizeMemoryUsage();
} else if (!strcmp(aTopic, "cycle-collector-begin")) {
if (mCheckTimer) {
@@ -642,9 +633,9 @@ nsWindowMemoryReporter::Observe(nsISupports *aSubject, const char *aTopic,
}
void
-nsWindowMemoryReporter::ObserveDOMWindowDetached(nsISupports* aWindow)
+nsWindowMemoryReporter::ObserveDOMWindowDetached(nsGlobalWindow* aWindow)
{
- nsWeakPtr weakWindow = do_GetWeakReference(aWindow);
+ nsWeakPtr weakWindow = do_GetWeakReference(static_cast(aWindow));
if (!weakWindow) {
NS_WARNING("Couldn't take weak reference to a window?");
return;
@@ -693,19 +684,6 @@ nsWindowMemoryReporter::AsyncCheckForGhostWindows()
}
}
-static PLDHashOperator
-BackdateTimeStampsEnumerator(nsISupports *aKey, TimeStamp &aTimeStamp,
- void* aClosure)
-{
- TimeStamp *minTimeStamp = static_cast(aClosure);
-
- if (!aTimeStamp.IsNull() && aTimeStamp > *minTimeStamp) {
- aTimeStamp = *minTimeStamp;
- }
-
- return PL_DHASH_NEXT;
-}
-
void
nsWindowMemoryReporter::ObserveAfterMinimizeMemoryUsage()
{
@@ -718,79 +696,12 @@ nsWindowMemoryReporter::ObserveAfterMinimizeMemoryUsage()
TimeStamp minTimeStamp = TimeStamp::Now() -
TimeDuration::FromSeconds(GetGhostTimeout());
- mDetachedWindows.Enumerate(BackdateTimeStampsEnumerator,
- &minTimeStamp);
-}
-
-struct CheckForGhostWindowsEnumeratorData
-{
- nsTHashtable *nonDetachedDomains;
- nsTHashtable *ghostWindowIDs;
- nsIEffectiveTLDService *tldService;
- uint32_t ghostTimeout;
- TimeStamp now;
-};
-
-static PLDHashOperator
-CheckForGhostWindowsEnumerator(nsISupports *aKey, TimeStamp& aTimeStamp,
- void* aClosure)
-{
- CheckForGhostWindowsEnumeratorData *data =
- static_cast(aClosure);
-
- nsWeakPtr weakKey = do_QueryInterface(aKey);
- nsCOMPtr window = do_QueryReferent(weakKey);
- if (!window) {
- // The window object has been destroyed. Stop tracking its weak ref in our
- // hashtable.
- return PL_DHASH_REMOVE;
- }
-
- // Avoid calling GetTop() if we have no outer window. Nothing will break if
- // we do, but it will spew debug output, which can cause our test logs to
- // overflow.
- nsCOMPtr top;
- if (window->GetOuterWindow()) {
- top = window->GetOuterWindow()->GetTop();
- }
-
- if (top) {
- // The window is no longer detached, so we no longer want to track it.
- return PL_DHASH_REMOVE;
- }
-
- nsCOMPtr uri = GetWindowURI(window);
-
- nsAutoCString domain;
- if (uri) {
- // GetBaseDomain works fine if |uri| is null, but it outputs a warning
- // which ends up overrunning the mochitest logs.
- data->tldService->GetBaseDomain(uri, 0, domain);
- }
-
- if (data->nonDetachedDomains->Contains(domain)) {
- // This window shares a domain with a non-detached window, so reset its
- // clock.
- aTimeStamp = TimeStamp();
- } else {
- // This window does not share a domain with a non-detached window, so it
- // meets ghost criterion (2).
- if (aTimeStamp.IsNull()) {
- // This may become a ghost window later; start its clock.
- aTimeStamp = data->now;
- } else if ((data->now - aTimeStamp).ToSeconds() > data->ghostTimeout) {
- // This definitely is a ghost window, so add it to ghostWindowIDs, if
- // that is not null.
- if (data->ghostWindowIDs) {
- nsCOMPtr pWindow = do_QueryInterface(window);
- if (pWindow) {
- data->ghostWindowIDs->PutEntry(pWindow->WindowID());
- }
- }
+ for (auto iter = mDetachedWindows.Iter(); !iter.Done(); iter.Next()) {
+ TimeStamp& timeStamp = iter.Data();
+ if (!timeStamp.IsNull() && timeStamp > minTimeStamp) {
+ timeStamp = minTimeStamp;
}
}
-
- return PL_DHASH_NEXT;
}
/**
@@ -853,11 +764,62 @@ nsWindowMemoryReporter::CheckForGhostWindows(
// Update mDetachedWindows and write the ghost window IDs into aOutGhostIDs,
// if it's not null.
- CheckForGhostWindowsEnumeratorData ghostEnumData =
- { &nonDetachedWindowDomains, aOutGhostIDs, tldService,
- GetGhostTimeout(), mLastCheckForGhostWindows };
- mDetachedWindows.Enumerate(CheckForGhostWindowsEnumerator,
- &ghostEnumData);
+ uint32_t ghostTimeout = GetGhostTimeout();
+ TimeStamp now = mLastCheckForGhostWindows;
+ for (auto iter = mDetachedWindows.Iter(); !iter.Done(); iter.Next()) {
+ nsWeakPtr weakKey = do_QueryInterface(iter.Key());
+ nsCOMPtr window = do_QueryReferent(weakKey);
+ if (!window) {
+ // The window object has been destroyed. Stop tracking its weak ref in
+ // our hashtable.
+ iter.Remove();
+ continue;
+ }
+
+ // Avoid calling GetTop() if we have no outer window. Nothing will break if
+ // we do, but it will spew debug output, which can cause our test logs to
+ // overflow.
+ nsCOMPtr top;
+ if (window->GetOuterWindow()) {
+ top = window->GetOuterWindow()->GetTop();
+ }
+
+ if (top) {
+ // The window is no longer detached, so we no longer want to track it.
+ iter.Remove();
+ continue;
+ }
+
+ nsCOMPtr uri = GetWindowURI(nsGlobalWindow::Cast(window));
+
+ nsAutoCString domain;
+ if (uri) {
+ // GetBaseDomain works fine if |uri| is null, but it outputs a warning
+ // which ends up overrunning the mochitest logs.
+ tldService->GetBaseDomain(uri, 0, domain);
+ }
+
+ TimeStamp& timeStamp = iter.Data();
+
+ if (nonDetachedWindowDomains.Contains(domain)) {
+ // This window shares a domain with a non-detached window, so reset its
+ // clock.
+ timeStamp = TimeStamp();
+ } else {
+ // This window does not share a domain with a non-detached window, so it
+ // meets ghost criterion (2).
+ if (timeStamp.IsNull()) {
+ // This may become a ghost window later; start its clock.
+ timeStamp = now;
+ } else if ((now - timeStamp).ToSeconds() > ghostTimeout) {
+ // This definitely is a ghost window, so add it to aOutGhostIDs, if
+ // that is not null.
+ if (aOutGhostIDs && window) {
+ aOutGhostIDs->PutEntry(window->WindowID());
+ }
+ }
+ }
+ }
}
NS_IMPL_ISUPPORTS(nsWindowMemoryReporter::GhostWindowsReporter,
@@ -897,7 +859,9 @@ nsWindowMemoryReporter::UnlinkGhostWindows()
// Hold on to every window in memory so that window objects can't be
// destroyed while we're calling the UnlinkGhostWindows callback.
WindowArray windows;
- windowsById->Enumerate(GetWindows, &windows);
+ for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) {
+ windows.AppendElement(iter.Data());
+ }
// Get the IDs of all the "ghost" windows, and unlink them all.
nsTHashtable ghostWindows;
diff --git a/dom/base/nsWindowMemoryReporter.h b/dom/base/nsWindowMemoryReporter.h
index 7d76ab927d..3e5a97472f 100644
--- a/dom/base/nsWindowMemoryReporter.h
+++ b/dom/base/nsWindowMemoryReporter.h
@@ -158,6 +158,9 @@ public:
static void UnlinkGhostWindows();
#endif
+ static nsWindowMemoryReporter* Get();
+ void ObserveDOMWindowDetached(nsGlobalWindow* aWindow);
+
private:
~nsWindowMemoryReporter();
@@ -199,7 +202,6 @@ private:
*/
uint32_t GetGhostTimeout();
- void ObserveDOMWindowDetached(nsISupports* aWindow);
void ObserveAfterMinimizeMemoryUsage();
/**
diff --git a/dom/bluetooth/common/BluetoothService.cpp b/dom/bluetooth/common/BluetoothService.cpp
index 675649171c..76c1a945fa 100644
--- a/dom/bluetooth/common/BluetoothService.cpp
+++ b/dom/bluetooth/common/BluetoothService.cpp
@@ -294,28 +294,25 @@ BluetoothService::UnregisterBluetoothSignalHandler(
}
}
-PLDHashOperator
-RemoveAllSignalHandlers(const nsAString& aKey,
- nsAutoPtr& aData,
- void* aUserArg)
-{
- BluetoothSignalObserver* handler =
- static_cast(aUserArg);
- aData->RemoveObserver(handler);
- // We shouldn't have duplicate instances in the ObserverList, but there's
- // no appropriate way to do duplication check while registering, so
- // assertions are added here.
- MOZ_ASSERT(!aData->RemoveObserver(handler));
- return aData->Length() ? PL_DHASH_NEXT : PL_DHASH_REMOVE;
-}
-
void
BluetoothService::UnregisterAllSignalHandlers(BluetoothSignalObserver* aHandler)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aHandler);
- mBluetoothSignalObserverTable.Enumerate(RemoveAllSignalHandlers, aHandler);
+ for (auto iter = mBluetoothSignalObserverTable.Iter();
+ !iter.Done();
+ iter.Next()) {
+ nsAutoPtr& ol = iter.Data();
+ ol->RemoveObserver(aHandler);
+ // We shouldn't have duplicate instances in the ObserverList, but there's
+ // no appropriate way to do duplication check while registering, so
+ // assertions are added here.
+ MOZ_ASSERT(!ol->RemoveObserver(aHandler));
+ if (ol->Length() == 0) {
+ iter.Remove();
+ }
+ }
}
void
diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp
index 13162c60b7..5f3216ca97 100644
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -5024,19 +5024,17 @@ EventStateManager::SetContentState(nsIContent* aContent, EventStates aState)
return true;
}
-PLDHashOperator
+void
EventStateManager::ResetLastOverForContent(
const uint32_t& aIdx,
RefPtr& aElemWrapper,
- void* aClosure)
+ nsIContent* aContent)
{
- nsIContent* content = static_cast(aClosure);
if (aElemWrapper && aElemWrapper->mLastOverElement &&
- nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement, content)) {
+ nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement,
+ aContent)) {
aElemWrapper->mLastOverElement = nullptr;
}
-
- return PL_DHASH_NEXT;
}
void
@@ -5085,8 +5083,11 @@ EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
// See bug 292146 for why we want to null this out
ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent);
- mPointersEnterLeaveHelper.Enumerate(
- &EventStateManager::ResetLastOverForContent, aContent);
+ for (auto iter = mPointersEnterLeaveHelper.Iter();
+ !iter.Done();
+ iter.Next()) {
+ ResetLastOverForContent(iter.Key(), iter.Data(), aContent);
+ }
}
bool
diff --git a/dom/events/EventStateManager.h b/dom/events/EventStateManager.h
index 31d7c164e2..c7992fa5e6 100644
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -882,9 +882,9 @@ private:
nsIContent* aStopBefore,
EventStates aState,
bool aAddState);
- static PLDHashOperator ResetLastOverForContent(const uint32_t& aIdx,
- RefPtr& aChunk,
- void* aClosure);
+ static void ResetLastOverForContent(const uint32_t& aIdx,
+ RefPtr& aChunk,
+ nsIContent* aClosure);
void PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
nsEventStatus& aStatus,
bool dispatchedToContentProcess);
diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h
index faf277d52b..c026a94d85 100644
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -1197,11 +1197,6 @@ protected:
// Current audio volume
double mVolume;
- // Helper function to iterate over a hash table
- // and convert it to a JSObject.
- static PLDHashOperator BuildObjectFromTags(nsCStringHashKey::KeyType aKey,
- nsCString aValue,
- void* aUserArg);
nsAutoPtr mTags;
// URI of the resource we're attempting to load. This stores the value we
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index 94318f6e9f..3046348a1e 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -398,7 +398,7 @@ public:
MOZ_ASSERT(aId);
SelfType closure(aId, aName);
- aEnumerable.EnumerateRead(Enumerate, &closure);
+ MatchHelper(aEnumerable, &closure);
return closure.mMetadata;
}
@@ -411,7 +411,7 @@ public:
MOZ_ASSERT(aId);
SelfType closure(aId);
- aEnumerable.EnumerateRead(Enumerate, &closure);
+ MatchHelper(aEnumerable, &closure);
return closure.mMetadata;
}
@@ -436,25 +436,29 @@ private:
MOZ_ASSERT(aId);
}
- static PLDHashOperator
- Enumerate(const uint64_t& aKey, MetadataType* aValue, void* aClosure)
+ template
+ static void
+ MatchHelper(const Enumerable& aEnumerable, SelfType* aClosure)
{
AssertIsOnBackgroundThread();
- MOZ_ASSERT(aKey);
- MOZ_ASSERT(aValue);
MOZ_ASSERT(aClosure);
- auto* closure = static_cast(aClosure);
+ for (auto iter = aEnumerable.ConstIter(); !iter.Done(); iter.Next()) {
+#ifdef DEBUG
+ const uint64_t key = iter.Key();
+#endif
+ MetadataType* value = iter.UserData();
+ MOZ_ASSERT(key != 0);
+ MOZ_ASSERT(value);
- if (!aValue->mDeleted &&
- (closure->mId == aValue->mCommonMetadata.id() ||
- (closure->mCheckName &&
- closure->mName == aValue->mCommonMetadata.name()))) {
- closure->mMetadata = aValue;
- return PL_DHASH_STOP;
+ if (!value->mDeleted &&
+ (aClosure->mId == value->mCommonMetadata.id() ||
+ (aClosure->mCheckName &&
+ aClosure->mName == value->mCommonMetadata.name()))) {
+ aClosure->mMetadata = value;
+ break;
+ }
}
-
- return PL_DHASH_NEXT;
}
};
@@ -8702,7 +8706,6 @@ class QuotaClient final
// then we will attempt a full vacuum.
static const int32_t kPercentUnusedThreshold = 20;
- class AbortOperationsRunnable;
class AutoProgressHandler;
class GetDirectoryLockListener;
struct MaintenanceInfoBase;
@@ -9096,48 +9099,6 @@ private:
NS_DECL_NSIRUNNABLE
};
-class QuotaClient::AbortOperationsRunnable final
- : public nsRunnable
-{
- const ContentParentId mContentParentId;
- const nsCString mOrigin;
-
- nsTArray> mDatabases;
-
-public:
- explicit AbortOperationsRunnable(const nsACString& aOrigin)
- : mOrigin(aOrigin)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!mOrigin.IsEmpty());
- }
-
- explicit AbortOperationsRunnable(ContentParentId aContentParentId)
- : mContentParentId(aContentParentId)
- {
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(mOrigin.IsEmpty());
- }
-
- NS_DECL_ISUPPORTS_INHERITED
-
-private:
- ~AbortOperationsRunnable()
- { }
-
- static PLDHashOperator
- MatchOrigin(const nsACString& aKey,
- DatabaseActorInfo* aValue,
- void* aClosure);
-
- static PLDHashOperator
- MatchContentParentId(const nsACString& aKey,
- DatabaseActorInfo* aValue,
- void* aClosure);
-
- NS_DECL_NSIRUNNABLE
-};
-
class QuotaClient::GetDirectoryLockListener final
: public OpenDirectoryListener
{
@@ -15135,56 +15096,6 @@ VersionChangeTransaction::RecvDeleteObjectStore(const int64_t& aObjectStoreId)
{
AssertIsOnBackgroundThread();
- class MOZ_STACK_CLASS Helper final
- {
- const int64_t mObjectStoreId;
- bool mIsLastObjectStore;
- DebugOnly mFoundTargetId;
-
- public:
- static bool
- IsLastObjectStore(const FullDatabaseMetadata* aDatabaseMetadata,
- const int64_t aObjectStoreId)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aDatabaseMetadata);
- MOZ_ASSERT(aObjectStoreId);
-
- Helper helper(aObjectStoreId);
- aDatabaseMetadata->mObjectStores.EnumerateRead(&Enumerate, &helper);
-
- MOZ_ASSERT_IF(helper.mIsLastObjectStore, helper.mFoundTargetId);
-
- return helper.mIsLastObjectStore;
- }
-
- private:
- explicit
- Helper(const int64_t aObjectStoreId)
- : mObjectStoreId(aObjectStoreId)
- , mIsLastObjectStore(true)
- , mFoundTargetId(false)
- { }
-
- static PLDHashOperator
- Enumerate(const uint64_t& aKey,
- FullObjectStoreMetadata* aValue,
- void* aClosure)
- {
- auto* helper = static_cast(aClosure);
- MOZ_ASSERT(helper);
-
- if (uint64_t(helper->mObjectStoreId) == aKey) {
- helper->mFoundTargetId = true;
- } else if(!aValue->mDeleted) {
- helper->mIsLastObjectStore = false;
- return PL_DHASH_STOP;
- }
-
- return PL_DHASH_NEXT;
- }
- };
-
if (NS_WARN_IF(!aObjectStoreId)) {
ASSERT_UNLESS_FUZZING();
return false;
@@ -15214,11 +15125,22 @@ VersionChangeTransaction::RecvDeleteObjectStore(const int64_t& aObjectStoreId)
foundMetadata->mDeleted = true;
+ bool isLastObjectStore = true;
+ DebugOnly foundTargetId = false;
+ for (auto iter = dbMetadata->mObjectStores.Iter();
+ !iter.Done();
+ iter.Next()) {
+ if (uint64_t(aObjectStoreId) == iter.Key()) {
+ foundTargetId = true;
+ } else if (!iter.UserData()->mDeleted) {
+ isLastObjectStore = false;
+ break;
+ }
+ }
+ MOZ_ASSERT_IF(isLastObjectStore, foundTargetId);
+
RefPtr op =
- new DeleteObjectStoreOp(this,
- foundMetadata,
- Helper::IsLastObjectStore(dbMetadata,
- aObjectStoreId));
+ new DeleteObjectStoreOp(this, foundMetadata, isLastObjectStore);
if (NS_WARN_IF(!op->Init(this))) {
op->Cleanup();
@@ -15306,54 +15228,6 @@ VersionChangeTransaction::RecvDeleteIndex(const int64_t& aObjectStoreId,
{
AssertIsOnBackgroundThread();
- class MOZ_STACK_CLASS Helper final
- {
- const int64_t mIndexId;
- bool mIsLastIndex;
- DebugOnly mFoundTargetId;
-
- public:
- static bool
- IsLastIndex(const FullObjectStoreMetadata* aObjectStoreMetadata,
- const int64_t aIndexId)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aObjectStoreMetadata);
- MOZ_ASSERT(aIndexId);
-
- Helper helper(aIndexId);
- aObjectStoreMetadata->mIndexes.EnumerateRead(&Enumerate, &helper);
-
- MOZ_ASSERT_IF(helper.mIsLastIndex, helper.mFoundTargetId);
-
- return helper.mIsLastIndex;
- }
-
- private:
- explicit
- Helper(const int64_t aIndexId)
- : mIndexId(aIndexId)
- , mIsLastIndex(true)
- , mFoundTargetId(false)
- { }
-
- static PLDHashOperator
- Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
- {
- auto* helper = static_cast(aClosure);
- MOZ_ASSERT(helper);
-
- if (uint64_t(helper->mIndexId) == aKey) {
- helper->mFoundTargetId = true;
- } else if (!aValue->mDeleted) {
- helper->mIsLastIndex = false;
- return PL_DHASH_STOP;
- }
-
- return PL_DHASH_NEXT;
- }
- };
-
if (NS_WARN_IF(!aObjectStoreId)) {
ASSERT_UNLESS_FUZZING();
return false;
@@ -15402,12 +15276,26 @@ VersionChangeTransaction::RecvDeleteIndex(const int64_t& aObjectStoreId,
foundIndexMetadata->mDeleted = true;
+ bool isLastIndex = true;
+ DebugOnly foundTargetId = false;
+ for (auto iter = foundObjectStoreMetadata->mIndexes.ConstIter();
+ !iter.Done();
+ iter.Next()) {
+ if (uint64_t(aIndexId) == iter.Key()) {
+ foundTargetId = true;
+ } else if (!iter.UserData()->mDeleted) {
+ isLastIndex = false;
+ break;
+ }
+ }
+ MOZ_ASSERT_IF(isLastIndex, foundTargetId);
+
RefPtr op =
new DeleteIndexOp(this,
aObjectStoreId,
aIndexId,
foundIndexMetadata->mCommonMetadata.unique(),
- Helper::IsLastIndex(foundObjectStoreMetadata, aIndexId));
+ isLastIndex);
if (NS_WARN_IF(!op->Init(this))) {
op->Cleanup();
@@ -16744,29 +16632,55 @@ QuotaClient::ReleaseIOThreadObjects()
void
QuotaClient::AbortOperations(const nsACString& aOrigin)
{
- if (mBackgroundThread) {
- RefPtr runnable =
- new AbortOperationsRunnable(aOrigin);
+ AssertIsOnBackgroundThread();
- if (NS_FAILED(mBackgroundThread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
- // This can happen if the thread has shut down already.
- return;
+ if (!gLiveDatabaseHashtable) {
+ return;
+ }
+
+ nsTArray> databases;
+
+ for (auto iter = gLiveDatabaseHashtable->ConstIter();
+ !iter.Done(); iter.Next()) {
+ for (Database* database : iter.Data()->mLiveDatabases) {
+ if (aOrigin.IsVoid() || database->Origin() == aOrigin) {
+ databases.AppendElement(database);
+ }
}
}
+
+ for (Database* database : databases) {
+ database->Invalidate();
+ }
+
+ databases.Clear();
}
void
QuotaClient::AbortOperationsForProcess(ContentParentId aContentParentId)
{
- if (mBackgroundThread) {
- RefPtr runnable =
- new AbortOperationsRunnable(aContentParentId);
+ AssertIsOnBackgroundThread();
- if (NS_FAILED(mBackgroundThread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
- // This can happen if the thread has shut down already.
- return;
+ if (!gLiveDatabaseHashtable) {
+ return;
+ }
+
+ nsTArray> databases;
+
+ for (auto iter = gLiveDatabaseHashtable->ConstIter();
+ !iter.Done(); iter.Next()) {
+ for (Database* database : iter.Data()->mLiveDatabases) {
+ if (database->IsOwnedByProcess(aContentParentId)) {
+ databases.AppendElement(database);
+ }
}
}
+
+ for (Database* database : databases) {
+ database->Invalidate();
+ }
+
+ databases.Clear();
}
void
@@ -18036,79 +17950,6 @@ ShutdownWorkThreadsRunnable::Run()
return NS_OK;
}
-// static
-PLDHashOperator
-QuotaClient::
-AbortOperationsRunnable::MatchOrigin(const nsACString& aKey,
- DatabaseActorInfo* aValue,
- void* aClosure)
-{
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!aKey.IsEmpty());
- MOZ_ASSERT(aValue);
- MOZ_ASSERT(aClosure);
-
- auto* closure = static_cast(aClosure);
-
- for (Database* database : aValue->mLiveDatabases) {
- if (closure->mOrigin.IsVoid() || closure->mOrigin == database->Origin()) {
- closure->mDatabases.AppendElement(database);
- }
- }
-
- return PL_DHASH_NEXT;
-}
-
-// static
-PLDHashOperator
-QuotaClient::
-AbortOperationsRunnable::MatchContentParentId(const nsACString& aKey,
- DatabaseActorInfo* aValue,
- void* aClosure)
-{
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(!aKey.IsEmpty());
- MOZ_ASSERT(aValue);
- MOZ_ASSERT(aClosure);
-
- auto* closure = static_cast(aClosure);
-
- for (Database* database : aValue->mLiveDatabases) {
- if (database->IsOwnedByProcess(closure->mContentParentId)) {
- closure->mDatabases.AppendElement(database);
- }
- }
-
- return PL_DHASH_NEXT;
-}
-
-NS_IMPL_ISUPPORTS_INHERITED0(QuotaClient::AbortOperationsRunnable, nsRunnable)
-
-NS_IMETHODIMP
-QuotaClient::
-AbortOperationsRunnable::Run()
-{
- AssertIsOnBackgroundThread();
-
- if (!gLiveDatabaseHashtable) {
- return NS_OK;
- }
-
- if (mOrigin.IsEmpty()) {
- gLiveDatabaseHashtable->EnumerateRead(MatchContentParentId, this);
- } else {
- gLiveDatabaseHashtable->EnumerateRead(MatchOrigin, this);
- }
-
- for (Database* database : mDatabases) {
- database->Invalidate();
- }
-
- mDatabases.Clear();
-
- return NS_OK;
-}
-
void
QuotaClient::
GetDirectoryLockListener::DirectoryLockAcquired(DirectoryLock* aLock)
@@ -18555,51 +18396,7 @@ DatabaseOperationBase::GetUniqueIndexTableForObjectStore(
MOZ_ASSERT(aObjectStoreId);
MOZ_ASSERT(aMaybeUniqueIndexTable.isNothing());
- class MOZ_STACK_CLASS Helper final
- {
- public:
- static nsresult
- CopyUniqueValues(const IndexTable& aIndexes,
- Maybe& aMaybeUniqueIndexTable)
- {
- const uint32_t indexCount = aIndexes.Count();
- MOZ_ASSERT(indexCount);
-
- aMaybeUniqueIndexTable.emplace();
-
- aIndexes.EnumerateRead(Enumerate, aMaybeUniqueIndexTable.ptr());
-
- if (NS_WARN_IF(aMaybeUniqueIndexTable.ref().Count() != indexCount)) {
- IDB_REPORT_INTERNAL_ERR();
- aMaybeUniqueIndexTable.reset();
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
-#ifdef DEBUG
- aMaybeUniqueIndexTable.ref().MarkImmutable();
-#endif
- return NS_OK;
- }
-
- private:
- static PLDHashOperator
- Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
- {
- auto* uniqueIndexTable = static_cast(aClosure);
- MOZ_ASSERT(uniqueIndexTable);
- MOZ_ASSERT(!uniqueIndexTable->Get(aValue->mCommonMetadata.id()));
-
- if (NS_WARN_IF(!uniqueIndexTable->Put(aValue->mCommonMetadata.id(),
- aValue->mCommonMetadata.unique(),
- fallible))) {
- return PL_DHASH_STOP;
- }
-
- return PL_DHASH_NEXT;
- }
- };
-
- const RefPtr objectStoreMetadata =
+ const RefPtr objectStoreMetadata =
aTransaction->GetMetadataForObjectStoreId(aObjectStoreId);
MOZ_ASSERT(objectStoreMetadata);
@@ -18607,12 +18404,35 @@ DatabaseOperationBase::GetUniqueIndexTableForObjectStore(
return NS_OK;
}
- nsresult rv = Helper::CopyUniqueValues(objectStoreMetadata->mIndexes,
- aMaybeUniqueIndexTable);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
+ const uint32_t indexCount = objectStoreMetadata->mIndexes.Count();
+ MOZ_ASSERT(indexCount > 0);
+
+ aMaybeUniqueIndexTable.emplace();
+ UniqueIndexTable* uniqueIndexTable = aMaybeUniqueIndexTable.ptr();
+ MOZ_ASSERT(uniqueIndexTable);
+
+ for (auto iter = objectStoreMetadata->mIndexes.Iter(); !iter.Done(); iter.Next()) {
+ FullIndexMetadata* value = iter.UserData();
+ MOZ_ASSERT(!uniqueIndexTable->Get(value->mCommonMetadata.id()));
+
+ if (NS_WARN_IF(!uniqueIndexTable->Put(value->mCommonMetadata.id(),
+ value->mCommonMetadata.unique(),
+ fallible))) {
+ break;
+ }
}
+ if (NS_WARN_IF(aMaybeUniqueIndexTable.ref().Count() != indexCount)) {
+ IDB_REPORT_INTERNAL_ERR();
+ aMaybeUniqueIndexTable.reset();
+ NS_WARNING("out of memory");
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+#ifdef DEBUG
+ aMaybeUniqueIndexTable.ref().MarkImmutable();
+#endif
+
return NS_OK;
}
@@ -19586,9 +19406,6 @@ FactoryOp::WaitForTransactions()
MOZ_ASSERT(!mDatabaseId.IsEmpty());
MOZ_ASSERT(!IsActorDestroyed());
- nsTArray databaseIds;
- databaseIds.AppendElement(mDatabaseId);
-
mState = State::WaitingForTransactionsToComplete;
RefPtr helper =
@@ -21177,80 +20994,33 @@ OpenDatabaseOp::MetadataToSpec(DatabaseSpec& aSpec)
AssertIsOnOwningThread();
MOZ_ASSERT(mMetadata);
- class MOZ_STACK_CLASS Helper final
- {
- DatabaseSpec& mSpec;
- ObjectStoreSpec* mCurrentObjectStoreSpec;
+ aSpec.metadata() = mMetadata->mCommonMetadata;
- public:
- static void
- CopyToSpec(const FullDatabaseMetadata* aMetadata, DatabaseSpec& aSpec)
- {
- AssertIsOnBackgroundThread();
- MOZ_ASSERT(aMetadata);
+ for (auto objectStoreIter = mMetadata->mObjectStores.ConstIter();
+ !objectStoreIter.Done();
+ objectStoreIter.Next()) {
+ FullObjectStoreMetadata* metadata = objectStoreIter.UserData();
+ MOZ_ASSERT(objectStoreIter.Key());
+ MOZ_ASSERT(metadata);
- aSpec.metadata() = aMetadata->mCommonMetadata;
+ // XXX This should really be fallible...
+ ObjectStoreSpec* objectStoreSpec = aSpec.objectStores().AppendElement();
+ objectStoreSpec->metadata() = metadata->mCommonMetadata;
- Helper helper(aSpec);
- aMetadata->mObjectStores.EnumerateRead(Enumerate, &helper);
- }
-
- private:
- explicit Helper(DatabaseSpec& aSpec)
- : mSpec(aSpec)
- , mCurrentObjectStoreSpec(nullptr)
- { }
-
- static PLDHashOperator
- Enumerate(const uint64_t& aKey,
- FullObjectStoreMetadata* aValue,
- void* aClosure)
- {
- MOZ_ASSERT(aKey);
- MOZ_ASSERT(aValue);
- MOZ_ASSERT(aClosure);
-
- auto* helper = static_cast(aClosure);
-
- MOZ_ASSERT(!helper->mCurrentObjectStoreSpec);
+ for (auto indexIter = metadata->mIndexes.Iter();
+ !indexIter.Done();
+ indexIter.Next()) {
+ FullIndexMetadata* indexMetadata = indexIter.UserData();
+ MOZ_ASSERT(indexIter.Key());
+ MOZ_ASSERT(indexMetadata);
// XXX This should really be fallible...
- ObjectStoreSpec* objectStoreSpec =
- helper->mSpec.objectStores().AppendElement();
- objectStoreSpec->metadata() = aValue->mCommonMetadata;
-
- AutoRestore ar(helper->mCurrentObjectStoreSpec);
- helper->mCurrentObjectStoreSpec = objectStoreSpec;
-
- aValue->mIndexes.EnumerateRead(Enumerate, helper);
-
- return PL_DHASH_NEXT;
+ IndexMetadata* metadata = objectStoreSpec->indexes().AppendElement();
+ *metadata = indexMetadata->mCommonMetadata;
}
-
- static PLDHashOperator
- Enumerate(const uint64_t& aKey, FullIndexMetadata* aValue, void* aClosure)
- {
- MOZ_ASSERT(aKey);
- MOZ_ASSERT(aValue);
- MOZ_ASSERT(aClosure);
-
- auto* helper = static_cast(aClosure);
-
- MOZ_ASSERT(helper->mCurrentObjectStoreSpec);
-
- // XXX This should really be fallible...
- IndexMetadata* metadata =
- helper->mCurrentObjectStoreSpec->indexes().AppendElement();
- *metadata = aValue->mCommonMetadata;
-
- return PL_DHASH_NEXT;
- }
- };
-
- Helper::CopyToSpec(mMetadata, aSpec);
+ }
}
-
#ifdef DEBUG
void
@@ -21258,110 +21028,6 @@ OpenDatabaseOp::AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata)
{
AssertIsOnBackgroundThread();
- class MOZ_STACK_CLASS Helper final
- {
- const ObjectStoreTable& mOtherObjectStores;
- IndexTable* mCurrentOtherIndexTable;
-
- public:
- static void
- AssertConsistent(const ObjectStoreTable& aThisObjectStores,
- const ObjectStoreTable& aOtherObjectStores)
- {
- Helper helper(aOtherObjectStores);
- aThisObjectStores.EnumerateRead(Enumerate, &helper);
- }
-
- private:
- explicit Helper(const ObjectStoreTable& aOtherObjectStores)
- : mOtherObjectStores(aOtherObjectStores)
- , mCurrentOtherIndexTable(nullptr)
- { }
-
- static PLDHashOperator
- Enumerate(const uint64_t& /* aKey */,
- FullObjectStoreMetadata* aThisObjectStore,
- void* aClosure)
- {
- MOZ_ASSERT(aThisObjectStore);
- MOZ_ASSERT(!aThisObjectStore->mDeleted);
- MOZ_ASSERT(aClosure);
-
- auto* helper = static_cast(aClosure);
-
- MOZ_ASSERT(!helper->mCurrentOtherIndexTable);
-
- auto* otherObjectStore =
- MetadataNameOrIdMatcher::Match(
- helper->mOtherObjectStores, aThisObjectStore->mCommonMetadata.id());
- MOZ_ASSERT(otherObjectStore);
-
- MOZ_ASSERT(aThisObjectStore != otherObjectStore);
-
- MOZ_ASSERT(aThisObjectStore->mCommonMetadata.id() ==
- otherObjectStore->mCommonMetadata.id());
- MOZ_ASSERT(aThisObjectStore->mCommonMetadata.name() ==
- otherObjectStore->mCommonMetadata.name());
- MOZ_ASSERT(aThisObjectStore->mCommonMetadata.autoIncrement() ==
- otherObjectStore->mCommonMetadata.autoIncrement());
- MOZ_ASSERT(aThisObjectStore->mCommonMetadata.keyPath() ==
- otherObjectStore->mCommonMetadata.keyPath());
- // mNextAutoIncrementId and mComittedAutoIncrementId may be modified
- // concurrently with this OpenOp, so it is not possible to assert equality
- // here.
- MOZ_ASSERT(aThisObjectStore->mNextAutoIncrementId <=
- otherObjectStore->mNextAutoIncrementId);
- MOZ_ASSERT(aThisObjectStore->mComittedAutoIncrementId <=
- otherObjectStore->mComittedAutoIncrementId);
- MOZ_ASSERT(!otherObjectStore->mDeleted);
-
- MOZ_ASSERT(aThisObjectStore->mIndexes.Count() ==
- otherObjectStore->mIndexes.Count());
-
- AutoRestore ar(helper->mCurrentOtherIndexTable);
- helper->mCurrentOtherIndexTable = &otherObjectStore->mIndexes;
-
- aThisObjectStore->mIndexes.EnumerateRead(Enumerate, helper);
-
- return PL_DHASH_NEXT;
- }
-
- static PLDHashOperator
- Enumerate(const uint64_t& /* aKey */,
- FullIndexMetadata* aThisIndex,
- void* aClosure)
- {
- MOZ_ASSERT(aThisIndex);
- MOZ_ASSERT(!aThisIndex->mDeleted);
- MOZ_ASSERT(aClosure);
-
- auto* helper = static_cast(aClosure);
-
- MOZ_ASSERT(helper->mCurrentOtherIndexTable);
-
- auto* otherIndex =
- MetadataNameOrIdMatcher::Match(
- *helper->mCurrentOtherIndexTable, aThisIndex->mCommonMetadata.id());
- MOZ_ASSERT(otherIndex);
-
- MOZ_ASSERT(aThisIndex != otherIndex);
-
- MOZ_ASSERT(aThisIndex->mCommonMetadata.id() ==
- otherIndex->mCommonMetadata.id());
- MOZ_ASSERT(aThisIndex->mCommonMetadata.name() ==
- otherIndex->mCommonMetadata.name());
- MOZ_ASSERT(aThisIndex->mCommonMetadata.keyPath() ==
- otherIndex->mCommonMetadata.keyPath());
- MOZ_ASSERT(aThisIndex->mCommonMetadata.unique() ==
- otherIndex->mCommonMetadata.unique());
- MOZ_ASSERT(aThisIndex->mCommonMetadata.multiEntry() ==
- otherIndex->mCommonMetadata.multiEntry());
- MOZ_ASSERT(!otherIndex->mDeleted);
-
- return PL_DHASH_NEXT;
- }
- };
-
const FullDatabaseMetadata* thisDB = mMetadata;
const FullDatabaseMetadata* otherDB = aMetadata;
@@ -21386,7 +21052,67 @@ OpenDatabaseOp::AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata)
MOZ_ASSERT(thisDB->mObjectStores.Count() == otherDB->mObjectStores.Count());
- Helper::AssertConsistent(thisDB->mObjectStores, otherDB->mObjectStores);
+ for (auto objectStoreIter = thisDB->mObjectStores.ConstIter();
+ !objectStoreIter.Done();
+ objectStoreIter.Next()) {
+ FullObjectStoreMetadata* thisObjectStore = objectStoreIter.UserData();
+ MOZ_ASSERT(thisObjectStore);
+ MOZ_ASSERT(!thisObjectStore->mDeleted);
+
+ auto* otherObjectStore =
+ MetadataNameOrIdMatcher::Match(
+ otherDB->mObjectStores, thisObjectStore->mCommonMetadata.id());
+ MOZ_ASSERT(otherObjectStore);
+
+ MOZ_ASSERT(thisObjectStore != otherObjectStore);
+
+ MOZ_ASSERT(thisObjectStore->mCommonMetadata.id() ==
+ otherObjectStore->mCommonMetadata.id());
+ MOZ_ASSERT(thisObjectStore->mCommonMetadata.name() ==
+ otherObjectStore->mCommonMetadata.name());
+ MOZ_ASSERT(thisObjectStore->mCommonMetadata.autoIncrement() ==
+ otherObjectStore->mCommonMetadata.autoIncrement());
+ MOZ_ASSERT(thisObjectStore->mCommonMetadata.keyPath() ==
+ otherObjectStore->mCommonMetadata.keyPath());
+ // mNextAutoIncrementId and mComittedAutoIncrementId may be modified
+ // concurrently with this OpenOp, so it is not possible to assert equality
+ // here.
+ MOZ_ASSERT(thisObjectStore->mNextAutoIncrementId <=
+ otherObjectStore->mNextAutoIncrementId);
+ MOZ_ASSERT(thisObjectStore->mComittedAutoIncrementId <=
+ otherObjectStore->mComittedAutoIncrementId);
+ MOZ_ASSERT(!otherObjectStore->mDeleted);
+
+ MOZ_ASSERT(thisObjectStore->mIndexes.Count() ==
+ otherObjectStore->mIndexes.Count());
+
+ for (auto indexIter = thisObjectStore->mIndexes.Iter();
+ !indexIter.Done();
+ indexIter.Next()) {
+ FullIndexMetadata* thisIndex = indexIter.UserData();
+ MOZ_ASSERT(thisIndex);
+ MOZ_ASSERT(!thisIndex->mDeleted);
+
+ auto* otherIndex =
+ MetadataNameOrIdMatcher::
+ Match(otherObjectStore->mIndexes, thisIndex->mCommonMetadata.id());
+ MOZ_ASSERT(otherIndex);
+
+ MOZ_ASSERT(thisIndex != otherIndex);
+
+ MOZ_ASSERT(thisIndex->mCommonMetadata.id() ==
+ otherIndex->mCommonMetadata.id());
+ MOZ_ASSERT(thisIndex->mCommonMetadata.name() ==
+ otherIndex->mCommonMetadata.name());
+ MOZ_ASSERT(thisIndex->mCommonMetadata.keyPath() ==
+ otherIndex->mCommonMetadata.keyPath());
+ MOZ_ASSERT(thisIndex->mCommonMetadata.unique() ==
+ otherIndex->mCommonMetadata.unique());
+ MOZ_ASSERT(thisIndex->mCommonMetadata.multiEntry() ==
+ otherIndex->mCommonMetadata.multiEntry());
+ MOZ_ASSERT(!otherIndex->mDeleted);
+ }
+ }
}
#endif // DEBUG
diff --git a/dom/messagechannel/MessagePortService.h b/dom/messagechannel/MessagePortService.h
index c90fb0e899..eedaa40ddf 100644
--- a/dom/messagechannel/MessagePortService.h
+++ b/dom/messagechannel/MessagePortService.h
@@ -51,12 +51,6 @@ private:
class MessagePortServiceData;
-#ifdef DEBUG
- static PLDHashOperator
- CloseAllDebugCheck(const nsID& aID, MessagePortServiceData* aData,
- void* aPtr);
-#endif
-
nsClassHashtable mPorts;
};
diff --git a/dom/smil/nsSMILCompositor.h b/dom/smil/nsSMILCompositor.h
index 0c4d538bc8..3ac743f10a 100644
--- a/dom/smil/nsSMILCompositor.h
+++ b/dom/smil/nsSMILCompositor.h
@@ -84,10 +84,6 @@ public:
// method updates the cached value (and toggles the 'mForceCompositing' flag)
void UpdateCachedBaseValue(const nsSMILValue& aBaseValue);
- // Static callback methods
- static PLDHashOperator DoComposeAttribute(
- nsSMILCompositor* aCompositor, void *aData);
-
// The hash key (tuple of element/attributeName/attributeType)
KeyType mKey;
diff --git a/dom/storage/DOMStorageDBThread.cpp b/dom/storage/DOMStorageDBThread.cpp
index a98e314990..310ff9e9a4 100644
--- a/dom/storage/DOMStorageDBThread.cpp
+++ b/dom/storage/DOMStorageDBThread.cpp
@@ -1065,26 +1065,6 @@ DOMStorageDBThread::PendingOperations::HasTasks()
namespace {
-PLDHashOperator
-ForgetUpdatesForScope(const nsACString& aMapping,
- nsAutoPtr& aPendingTask,
- void* aArg)
-{
- DOMStorageDBThread::DBOperation* newOp = static_cast(aArg);
-
- if (newOp->Type() == DOMStorageDBThread::DBOperation::opClear &&
- aPendingTask->Scope() != newOp->Scope()) {
- return PL_DHASH_NEXT;
- }
-
- if (newOp->Type() == DOMStorageDBThread::DBOperation::opClearMatchingScope &&
- !StringBeginsWith(aPendingTask->Scope(), newOp->Scope())) {
- return PL_DHASH_NEXT;
- }
-
- return PL_DHASH_REMOVE;
-}
-
} // namespace
bool
@@ -1155,7 +1135,22 @@ DOMStorageDBThread::PendingOperations::Add(DOMStorageDBThread::DBOperation* aOpe
// We do this as an optimization as well as a must based on the logic,
// if we would not delete the update tasks, changes would have been stored
// to the database after clear operations have been executed.
- mUpdates.Enumerate(ForgetUpdatesForScope, aOperation);
+ for (auto iter = mUpdates.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& pendingTask = iter.Data();
+
+ if (aOperation->Type() == DBOperation::opClear &&
+ pendingTask->Scope() != aOperation->Scope()) {
+ continue;
+ }
+
+ if (aOperation->Type() == DBOperation::opClearMatchingScope &&
+ !StringBeginsWith(pendingTask->Scope(), aOperation->Scope())) {
+ continue;
+ }
+
+ iter.Remove();
+ }
+
mClears.Put(aOperation->Target(), aOperation);
break;
@@ -1172,20 +1167,6 @@ DOMStorageDBThread::PendingOperations::Add(DOMStorageDBThread::DBOperation* aOpe
}
}
-namespace {
-
-PLDHashOperator
-CollectTasks(const nsACString& aMapping, nsAutoPtr& aOperation, void* aArg)
-{
- nsTArray >* tasks =
- static_cast >*>(aArg);
-
- tasks->AppendElement(aOperation.forget());
- return PL_DHASH_NEXT;
-}
-
-} // namespace
-
bool
DOMStorageDBThread::PendingOperations::Prepare()
{
@@ -1196,10 +1177,14 @@ DOMStorageDBThread::PendingOperations::Prepare()
// scheduled, we drop all updates matching that scope. So,
// all scope-related update operations we have here now were
// scheduled after the clear operations.
- mClears.Enumerate(CollectTasks, &mExecList);
+ for (auto iter = mClears.Iter(); !iter.Done(); iter.Next()) {
+ mExecList.AppendElement(iter.Data().forget());
+ }
mClears.Clear();
- mUpdates.Enumerate(CollectTasks, &mExecList);
+ for (auto iter = mUpdates.Iter(); !iter.Done(); iter.Next()) {
+ mExecList.AppendElement(iter.Data().forget());
+ }
mUpdates.Clear();
return !!mExecList.Length();
diff --git a/dom/xbl/nsBindingManager.cpp b/dom/xbl/nsBindingManager.cpp
index 19807b4ab2..7d878bb8c4 100644
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -83,36 +83,20 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-static PLDHashOperator
-DocumentInfoHashtableTraverser(nsIURI* key,
- nsXBLDocumentInfo* di,
- void* userArg)
-{
- nsCycleCollectionTraversalCallback *cb =
- static_cast(userArg);
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mDocumentTable value");
- cb->NoteXPCOMChild(di);
- return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-LoadingDocHashtableTraverser(nsIURI* key,
- nsIStreamListener* sl,
- void* userArg)
-{
- nsCycleCollectionTraversalCallback *cb =
- static_cast(userArg);
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mLoadingDocTable value");
- cb->NoteXPCOMChild(sl);
- return PL_DHASH_NEXT;
-}
-
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager)
// The hashes keyed on nsIContent are traversed from the nsIContent itself.
- if (tmp->mDocumentTable)
- tmp->mDocumentTable->EnumerateRead(&DocumentInfoHashtableTraverser, &cb);
- if (tmp->mLoadingDocTable)
- tmp->mLoadingDocTable->EnumerateRead(&LoadingDocHashtableTraverser, &cb);
+ if (tmp->mDocumentTable) {
+ for (auto iter = tmp->mDocumentTable->Iter(); !iter.Done(); iter.Next()) {
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocumentTable value");
+ cb.NoteXPCOMChild(iter.UserData());
+ }
+ }
+ if (tmp->mLoadingDocTable) {
+ for (auto iter = tmp->mLoadingDocTable->Iter(); !iter.Done(); iter.Next()) {
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mLoadingDocTable value");
+ cb.NoteXPCOMChild(iter.UserData());
+ }
+ }
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttachedStack)
// No need to traverse mProcessAttachedQueueEvent, since it'll just
// fire at some point or become revoke and drop its ref to us.
diff --git a/dom/xbl/nsXBLDocumentInfo.cpp b/dom/xbl/nsXBLDocumentInfo.cpp
index 600b32201a..4a8095140c 100644
--- a/dom/xbl/nsXBLDocumentInfo.cpp
+++ b/dom/xbl/nsXBLDocumentInfo.cpp
@@ -80,13 +80,6 @@ UnmarkXBLJSObject(JS::GCCellPtr aPtr, const char* aName, void* aClosure)
JS::ExposeObjectToActiveJS(&aPtr.as());
}
-static PLDHashOperator
-UnmarkProtos(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
-{
- aProto->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
- return PL_DHASH_NEXT;
-}
-
void
nsXBLDocumentInfo::MarkInCCGeneration(uint32_t aGeneration)
{
@@ -95,7 +88,9 @@ nsXBLDocumentInfo::MarkInCCGeneration(uint32_t aGeneration)
}
// Unmark any JS we hold
if (mBindingTable) {
- mBindingTable->EnumerateRead(UnmarkProtos, nullptr);
+ for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
+ iter.UserData()->Trace(TraceCallbackFunc(UnmarkXBLJSObject), nullptr);
+ }
}
}
@@ -190,16 +185,6 @@ nsXBLDocumentInfo::RemovePrototypeBinding(const nsACString& aRef)
}
}
-// Callback to enumerate over the bindings from this document and write them
-// out to the cache.
-static PLDHashOperator
-WriteBinding(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
-{
- aProto->Write((nsIObjectOutputStream*)aClosure);
-
- return PL_DHASH_NEXT;
-}
-
// static
nsresult
nsXBLDocumentInfo::ReadPrototypeBindings(nsIURI* aURI, nsXBLDocumentInfo** aDocInfo)
@@ -292,7 +277,9 @@ nsXBLDocumentInfo::WritePrototypeBindings()
NS_ENSURE_SUCCESS(rv, rv);
if (mBindingTable) {
- mBindingTable->EnumerateRead(WriteBinding, stream);
+ for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
+ iter.UserData()->Write(stream);
+ }
}
// write a end marker at the end
@@ -316,18 +303,13 @@ nsXBLDocumentInfo::SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding)
mFirstBinding = aBinding;
}
-static PLDHashOperator
-FlushScopedSkinSheets(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
-{
- aProto->FlushSkinSheets();
- return PL_DHASH_NEXT;
-}
-
void
nsXBLDocumentInfo::FlushSkinStylesheets()
{
if (mBindingTable) {
- mBindingTable->EnumerateRead(FlushScopedSkinSheets, nullptr);
+ for (auto iter = mBindingTable->Iter(); !iter.Done(); iter.Next()) {
+ iter.UserData()->FlushSkinSheets();
+ }
}
}
diff --git a/dom/xbl/nsXBLPrototypeBinding.cpp b/dom/xbl/nsXBLPrototypeBinding.cpp
index 14093d8ccc..2f48bb6c3c 100644
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -488,101 +488,74 @@ nsXBLPrototypeBinding::LocateInstance(nsIContent* aBoundElement,
return copyParent->GetChildAt(templParent->IndexOf(aTemplChild));
}
-struct nsXBLAttrChangeData
-{
- nsXBLPrototypeBinding* mProto;
- nsIContent* mBoundElement;
- nsIContent* mContent;
- int32_t mSrcNamespace;
-
- nsXBLAttrChangeData(nsXBLPrototypeBinding* aProto,
- nsIContent* aElt, nsIContent* aContent)
- :mProto(aProto), mBoundElement(aElt), mContent(aContent) {}
-};
-
-// XXXbz this duplicates lots of AttributeChanged
-static PLDHashOperator
-SetAttrs(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure)
-{
- nsXBLAttrChangeData* changeData = static_cast(aClosure);
-
- nsIAtom* src = aEntry->GetSrcAttribute();
- int32_t srcNs = changeData->mSrcNamespace;
- nsAutoString value;
- bool attrPresent = true;
-
- if (src == nsGkAtoms::text && srcNs == kNameSpaceID_XBL) {
- nsContentUtils::GetNodeTextContent(changeData->mBoundElement, false,
- value);
- value.StripChar(char16_t('\n'));
- value.StripChar(char16_t('\r'));
- nsAutoString stripVal(value);
- stripVal.StripWhitespace();
-
- if (stripVal.IsEmpty())
- attrPresent = false;
- }
- else {
- attrPresent = changeData->mBoundElement->GetAttr(srcNs, src, value);
- }
-
- if (attrPresent) {
- nsIContent* content =
- changeData->mProto->GetImmediateChild(nsGkAtoms::content);
-
- nsXBLAttributeEntry* curr = aEntry;
- while (curr) {
- nsIAtom* dst = curr->GetDstAttribute();
- int32_t dstNs = curr->GetDstNameSpace();
- nsIContent* element = curr->GetElement();
-
- nsIContent *realElement =
- changeData->mProto->LocateInstance(changeData->mBoundElement, content,
- changeData->mContent, element);
-
- if (realElement) {
- realElement->SetAttr(dstNs, dst, value, false);
-
- // XXXndeakin shouldn't this be done in lieu of SetAttr?
- if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
- (realElement->NodeInfo()->Equals(nsGkAtoms::html,
- kNameSpaceID_XUL) &&
- dst == nsGkAtoms::value && !value.IsEmpty())) {
-
- RefPtr textContent =
- new nsTextNode(realElement->NodeInfo()->NodeInfoManager());
-
- textContent->SetText(value, false);
- realElement->AppendChildTo(textContent, false);
- }
- }
-
- curr = curr->GetNext();
- }
- }
-
- return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-SetAttrsNS(const uint32_t &aNamespace,
- nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes,
- void* aClosure)
-{
- if (aXBLAttributes && aClosure) {
- nsXBLAttrChangeData* changeData = static_cast(aClosure);
- changeData->mSrcNamespace = aNamespace;
- aXBLAttributes->EnumerateRead(SetAttrs, aClosure);
- }
- return PL_DHASH_NEXT;
-}
-
void
nsXBLPrototypeBinding::SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent)
{
- if (mAttributeTable) {
- nsXBLAttrChangeData data(this, aBoundElement, aAnonymousContent);
- mAttributeTable->EnumerateRead(SetAttrsNS, &data);
+ if (!mAttributeTable) {
+ return;
+ }
+
+ for (auto iter1 = mAttributeTable->Iter(); !iter1.Done(); iter1.Next()) {
+ InnerAttributeTable* xblAttributes = iter1.UserData();
+ if (xblAttributes) {
+ int32_t srcNamespace = iter1.Key();
+
+ for (auto iter2 = xblAttributes->Iter(); !iter2.Done(); iter2.Next()) {
+ // XXXbz this duplicates lots of AttributeChanged
+ nsXBLAttributeEntry* entry = iter2.UserData();
+ nsIAtom* src = entry->GetSrcAttribute();
+ nsAutoString value;
+ bool attrPresent = true;
+
+ if (src == nsGkAtoms::text && srcNamespace == kNameSpaceID_XBL) {
+ nsContentUtils::GetNodeTextContent(aBoundElement, false, value);
+ value.StripChar(char16_t('\n'));
+ value.StripChar(char16_t('\r'));
+ nsAutoString stripVal(value);
+ stripVal.StripWhitespace();
+
+ if (stripVal.IsEmpty()) {
+ attrPresent = false;
+ }
+ } else {
+ attrPresent = aBoundElement->GetAttr(srcNamespace, src, value);
+ }
+
+ if (attrPresent) {
+ nsIContent* content = GetImmediateChild(nsGkAtoms::content);
+
+ nsXBLAttributeEntry* curr = entry;
+ while (curr) {
+ nsIAtom* dst = curr->GetDstAttribute();
+ int32_t dstNs = curr->GetDstNameSpace();
+ nsIContent* element = curr->GetElement();
+
+ nsIContent* realElement =
+ LocateInstance(aBoundElement, content,
+ aAnonymousContent, element);
+
+ if (realElement) {
+ realElement->SetAttr(dstNs, dst, value, false);
+
+ // XXXndeakin shouldn't this be done in lieu of SetAttr?
+ if ((dst == nsGkAtoms::text && dstNs == kNameSpaceID_XBL) ||
+ (realElement->NodeInfo()->Equals(nsGkAtoms::html,
+ kNameSpaceID_XUL) &&
+ dst == nsGkAtoms::value && !value.IsEmpty())) {
+
+ RefPtr textContent =
+ new nsTextNode(realElement->NodeInfo()->NodeInfoManager());
+
+ textContent->SetText(value, false);
+ realElement->AppendChildTo(textContent, false);
+ }
+ }
+
+ curr = curr->GetNext();
+ }
+ }
+ }
+ }
}
}
@@ -1041,15 +1014,6 @@ nsXBLPrototypeBinding::ReadNewBinding(nsIObjectInputStream* aStream,
return rv;
}
-static PLDHashOperator
-WriteInterfaceID(const nsIID& aKey, nsIContent* aData, void* aClosure)
-{
- // We can just write out the ids. The cache will be invalidated when a
- // different build is used, so we don't need to worry about ids changing.
- static_cast(aClosure)->WriteID(aKey);
- return PL_DHASH_NEXT;
-}
-
nsresult
nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
{
@@ -1118,7 +1082,11 @@ nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
rv = aStream->Write32(mInterfaceTable.Count());
NS_ENSURE_SUCCESS(rv, rv);
- mInterfaceTable.EnumerateRead(WriteInterfaceID, aStream);
+ for (auto iter = mInterfaceTable.Iter(); !iter.Done(); iter.Next()) {
+ // We can just write out the ids. The cache will be invalidated when a
+ // different build is used, so we don't need to worry about ids changing.
+ aStream->WriteID(iter.Key());
+ }
// Write out the implementation details.
if (mImplementation) {
@@ -1381,60 +1349,6 @@ nsXBLPrototypeBinding::ReadContentNode(nsIObjectInputStream* aStream,
return NS_OK;
}
-// This structure holds information about a forwarded attribute that needs to be
-// written out. This is used because we need several fields passed within the
-// enumeration closure.
-struct WriteAttributeData
-{
- nsXBLPrototypeBinding* binding;
- nsIObjectOutputStream* stream;
- nsIContent* content;
- int32_t srcNamespace;
-
- WriteAttributeData(nsXBLPrototypeBinding* aBinding,
- nsIObjectOutputStream* aStream,
- nsIContent* aContent)
- : binding(aBinding), stream(aStream), content(aContent)
- { }
-};
-
-static PLDHashOperator
-WriteAttribute(nsISupports* aKey, nsXBLAttributeEntry* aEntry, void* aClosure)
-{
- WriteAttributeData* data = static_cast(aClosure);
- nsIObjectOutputStream* stream = data->stream;
- const int32_t srcNamespace = data->srcNamespace;
-
- do {
- if (aEntry->GetElement() == data->content) {
- data->binding->WriteNamespace(stream, srcNamespace);
- stream->WriteWStringZ(nsDependentAtomString(aEntry->GetSrcAttribute()).get());
- data->binding->WriteNamespace(stream, aEntry->GetDstNameSpace());
- stream->WriteWStringZ(nsDependentAtomString(aEntry->GetDstAttribute()).get());
- }
-
- aEntry = aEntry->GetNext();
- } while (aEntry);
-
- return PL_DHASH_NEXT;
-}
-
-// WriteAttributeNS is the callback to enumerate over the attribute
-// forwarding entries. Since these are stored in a hash of hashes,
-// we need to iterate over the inner hashes, calling WriteAttribute
-// to do the actual work.
-static PLDHashOperator
-WriteAttributeNS(const uint32_t &aNamespace,
- nsXBLPrototypeBinding::InnerAttributeTable* aXBLAttributes,
- void* aClosure)
-{
- WriteAttributeData* data = static_cast(aClosure);
- data->srcNamespace = aNamespace;
- aXBLAttributes->EnumerateRead(WriteAttribute, data);
-
- return PL_DHASH_NEXT;
-}
-
nsresult
nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
nsIContent* aNode)
@@ -1515,8 +1429,27 @@ nsXBLPrototypeBinding::WriteContentNode(nsIObjectOutputStream* aStream,
// Write out the attribute fowarding information
if (mAttributeTable) {
- WriteAttributeData data(this, aStream, aNode);
- mAttributeTable->EnumerateRead(WriteAttributeNS, &data);
+ for (auto iter1 = mAttributeTable->Iter(); !iter1.Done(); iter1.Next()) {
+ int32_t srcNamespace = iter1.Key();
+ InnerAttributeTable* xblAttributes = iter1.UserData();
+
+ for (auto iter2 = xblAttributes->Iter(); !iter2.Done(); iter2.Next()) {
+ nsXBLAttributeEntry* entry = iter2.UserData();
+
+ do {
+ if (entry->GetElement() == aNode) {
+ WriteNamespace(aStream, srcNamespace);
+ aStream->WriteWStringZ(
+ nsDependentAtomString(entry->GetSrcAttribute()).get());
+ WriteNamespace(aStream, entry->GetDstNameSpace());
+ aStream->WriteWStringZ(
+ nsDependentAtomString(entry->GetDstAttribute()).get());
+ }
+
+ entry = entry->GetNext();
+ } while (entry);
+ }
+ }
}
rv = aStream->Write8(XBLBinding_Serialize_NoMoreAttributes);
NS_ENSURE_SUCCESS(rv, rv);
diff --git a/dom/xul/nsXULPrototypeCache.cpp b/dom/xul/nsXULPrototypeCache.cpp
index 92dcdc2fdb..f94500ad3e 100644
--- a/dom/xul/nsXULPrototypeCache.cpp
+++ b/dom/xul/nsXULPrototypeCache.cpp
@@ -579,41 +579,22 @@ nsXULPrototypeCache::BeginCaching(nsIURI* aURI)
return NS_OK;
}
-static PLDHashOperator
-MarkXBLInCCGeneration(nsIURI* aKey, RefPtr &aDocInfo,
- void* aClosure)
-{
- uint32_t* gen = static_cast(aClosure);
- aDocInfo->MarkInCCGeneration(*gen);
- return PL_DHASH_NEXT;
-}
-
-static PLDHashOperator
-MarkXULInCCGeneration(nsIURI* aKey, RefPtr &aDoc,
- void* aClosure)
-{
- uint32_t* gen = static_cast(aClosure);
- aDoc->MarkInCCGeneration(*gen);
- return PL_DHASH_NEXT;
-}
-
void
nsXULPrototypeCache::MarkInCCGeneration(uint32_t aGeneration)
{
- mXBLDocTable.Enumerate(MarkXBLInCCGeneration, &aGeneration);
- mPrototypeTable.Enumerate(MarkXULInCCGeneration, &aGeneration);
-}
-
-static PLDHashOperator
-MarkScriptsInGC(nsIURI* aKey, JS::Heap& aScript, void* aClosure)
-{
- JSTracer* trc = static_cast(aClosure);
- JS::TraceEdge(trc, &aScript, "nsXULPrototypeCache script");
- return PL_DHASH_NEXT;
+ for (auto iter = mXBLDocTable.Iter(); !iter.Done(); iter.Next()) {
+ iter.Data()->MarkInCCGeneration(aGeneration);
+ }
+ for (auto iter = mPrototypeTable.Iter(); !iter.Done(); iter.Next()) {
+ iter.Data()->MarkInCCGeneration(aGeneration);
+ }
}
void
nsXULPrototypeCache::MarkInGC(JSTracer* aTrc)
{
- mScriptTable.Enumerate(MarkScriptsInGC, aTrc);
+ for (auto iter = mScriptTable.Iter(); !iter.Done(); iter.Next()) {
+ JS::Heap& script = iter.Data();
+ JS::TraceEdge(aTrc, &script, "nsXULPrototypeCache script");
+ }
}
diff --git a/dom/xul/templates/nsXULTemplateBuilder.cpp b/dom/xul/templates/nsXULTemplateBuilder.cpp
index bf7985da86..c8e55b97af 100644
--- a/dom/xul/templates/nsXULTemplateBuilder.cpp
+++ b/dom/xul/templates/nsXULTemplateBuilder.cpp
@@ -104,17 +104,20 @@ nsXULTemplateBuilder::nsXULTemplateBuilder(void)
MOZ_COUNT_CTOR(nsXULTemplateBuilder);
}
-static PLDHashOperator
-DestroyMatchList(nsISupports* aKey, nsTemplateMatch*& aMatch, void* aContext)
+void
+nsXULTemplateBuilder::DestroyMatchMap()
{
- // delete all the matches in the list
- while (aMatch) {
- nsTemplateMatch* next = aMatch->mNext;
- nsTemplateMatch::Destroy(aMatch, true);
- aMatch = next;
- }
+ for (auto iter = mMatchMap.Iter(); !iter.Done(); iter.Next()) {
+ nsTemplateMatch*& match = iter.Data();
+ // delete all the matches in the list
+ while (match) {
+ nsTemplateMatch* next = match->mNext;
+ nsTemplateMatch::Destroy(match, true);
+ match = next;
+ }
- return PL_DHASH_REMOVE;
+ iter.Remove();
+ }
}
nsXULTemplateBuilder::~nsXULTemplateBuilder(void)
@@ -195,7 +198,7 @@ nsXULTemplateBuilder::CleanUp(bool aIsFinal)
mQuerySets.Clear();
- mMatchMap.Enumerate(DestroyMatchList, nullptr);
+ DestroyMatchMap();
// Setting mQueryProcessor to null will close connections. This would be
// handled by the cycle collector, but we want to close them earlier.
@@ -232,7 +235,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateBuilder)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootResult)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mQueryProcessor)
- tmp->mMatchMap.Enumerate(DestroyMatchList, nullptr);
+ tmp->DestroyMatchMap();
for (uint32_t i = 0; i < tmp->mQuerySets.Length(); ++i) {
nsTemplateQuerySet* qs = tmp->mQuerySets[i];
delete qs;
diff --git a/dom/xul/templates/nsXULTemplateBuilder.h b/dom/xul/templates/nsXULTemplateBuilder.h
index b1fd7d4134..7da8ffc983 100644
--- a/dom/xul/templates/nsXULTemplateBuilder.h
+++ b/dom/xul/templates/nsXULTemplateBuilder.h
@@ -41,6 +41,7 @@ class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
public nsStubDocumentObserver
{
void CleanUp(bool aIsFinal);
+ void DestroyMatchMap();
public:
nsXULTemplateBuilder();
diff --git a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp
index f5cf0d9b87..144334b000 100644
--- a/extensions/spellcheck/hunspell/glue/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp
@@ -273,53 +273,32 @@ NS_IMETHODIMP mozHunspell::SetPersonalDictionary(mozIPersonalDictionary * aPerso
return NS_OK;
}
-struct AppendNewStruct
-{
- char16_t **dics;
- uint32_t count;
- bool failed;
-};
-
-static PLDHashOperator
-AppendNewString(const nsAString& aString, nsIFile* aFile, void* aClosure)
-{
- AppendNewStruct *ans = (AppendNewStruct*) aClosure;
- ans->dics[ans->count] = ToNewUnicode(aString);
- if (!ans->dics[ans->count]) {
- ans->failed = true;
- return PL_DHASH_STOP;
- }
-
- ++ans->count;
- return PL_DHASH_NEXT;
-}
-
NS_IMETHODIMP mozHunspell::GetDictionaryList(char16_t ***aDictionaries,
uint32_t *aCount)
{
if (!aDictionaries || !aCount)
return NS_ERROR_NULL_POINTER;
- AppendNewStruct ans = {
- (char16_t**) NS_Alloc(sizeof(char16_t*) * mDictionaries.Count()),
- 0,
- false
- };
+ uint32_t count = 0;
+ char16_t** dicts =
+ (char16_t**) moz_xmalloc(sizeof(char16_t*) * mDictionaries.Count());
- // This pointer is used during enumeration
- mDictionaries.EnumerateRead(AppendNewString, &ans);
-
- if (ans.failed) {
- while (ans.count) {
- --ans.count;
- NS_Free(ans.dics[ans.count]);
+ for (auto iter = mDictionaries.Iter(); !iter.Done(); iter.Next()) {
+ dicts[count] = ToNewUnicode(iter.Key());
+ if (!dicts[count]) {
+ while (count) {
+ --count;
+ free(dicts[count]);
+ }
+ free(dicts);
+ return NS_ERROR_OUT_OF_MEMORY;
}
- NS_Free(ans.dics);
- return NS_ERROR_OUT_OF_MEMORY;
+
+ ++count;
}
- *aDictionaries = ans.dics;
- *aCount = ans.count;
+ *aDictionaries = dicts;
+ *aCount = count;
return NS_OK;
}
diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h
index bc3fc33ddf..073c744303 100644
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -308,11 +308,6 @@ protected:
void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult);
- static PLDHashOperator
- HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
- RefPtr& aFamilyEntry,
- void* aUserArg);
-
virtual void GetFontFamilyNames(nsTArray& aFontFamilyNames);
nsILanguageAtomService* GetLangService();
diff --git a/layout/base/RestyleTracker.cpp b/layout/base/RestyleTracker.cpp
index 51b0d47110..0c2237048d 100644
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -63,78 +63,6 @@ struct RestyleEnumerateData : RestyleTracker::Hints {
#endif
};
-struct RestyleCollector {
- RestyleTracker* tracker;
- RestyleEnumerateData** restyleArrayPtr;
-#ifdef RESTYLE_LOGGING
- uint32_t count;
-#endif
-};
-
-static PLDHashOperator
-CollectRestyles(nsISupports* aElement,
- nsAutoPtr& aData,
- void* aRestyleCollector)
-{
- dom::Element* element =
- static_cast(aElement);
- RestyleCollector* collector =
- static_cast(aRestyleCollector);
- // Only collect the entries that actually need restyling by us (and
- // haven't, for example, already been restyled).
- // It's important to not mess with the flags on entries not in our
- // document.
- if (element->GetCrossShadowCurrentDoc() != collector->tracker->Document() ||
- !element->HasFlag(collector->tracker->RestyleBit())) {
- LOG_RESTYLE_IF(collector->tracker, true,
- "skipping pending restyle %s, already restyled or no longer "
- "in the document", FrameTagToString(element).get());
- return PL_DHASH_NEXT;
- }
-
- NS_ASSERTION(!element->HasFlag(collector->tracker->RootBit()) ||
- // Maybe we're just not reachable via the frame tree?
- (element->GetFlattenedTreeParent() &&
- (!element->GetFlattenedTreeParent()->GetPrimaryFrame() ||
- element->GetFlattenedTreeParent()->GetPrimaryFrame()->IsLeaf() ||
- element->GetCurrentDoc()->GetShell()->FrameManager()
- ->GetDisplayContentsStyleFor(element))) ||
- // Or not reachable due to an async reinsert we have
- // pending? If so, we'll have a reframe hint around.
- // That incidentally makes it safe that we still have
- // the bit, since any descendants that didn't get added
- // to the roots list because we had the bits will be
- // completely restyled in a moment.
- (aData->mChangeHint & nsChangeHint_ReconstructFrame),
- "Why did this not get handled while processing mRestyleRoots?");
-
- // Unset the restyle bits now, so if they get readded later as we
- // process we won't clobber that adding of the bit.
- element->UnsetFlags(collector->tracker->RestyleBit() |
- collector->tracker->RootBit() |
- collector->tracker->ConditionalDescendantsBit());
-
- RestyleEnumerateData** restyleArrayPtr = collector->restyleArrayPtr;
- RestyleEnumerateData* currentRestyle = *restyleArrayPtr;
- currentRestyle->mElement = element;
- currentRestyle->mRestyleHint = aData->mRestyleHint;
- currentRestyle->mChangeHint = aData->mChangeHint;
- // We can move aData since we'll be clearing mPendingRestyles after
- // we finish enumerating it.
- currentRestyle->mRestyleHintData = Move(aData->mRestyleHintData);
-#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
- currentRestyle->mBacktrace = Move(aData->mBacktrace);
-#endif
-#ifdef RESTYLE_LOGGING
- collector->count++;
-#endif
-
- // Increment to the next slot in the array
- *restyleArrayPtr = currentRestyle + 1;
-
- return PL_DHASH_NEXT;
-}
-
inline void
RestyleTracker::ProcessOneRestyle(Element* aElement,
nsRestyleHint aRestyleHint,
@@ -356,9 +284,68 @@ RestyleTracker::DoProcessRestyles()
RestyleEnumerateData* restylesToProcess =
restyleArr.AppendElements(mPendingRestyles.Count());
if (restylesToProcess) {
- RestyleEnumerateData* lastRestyle = restylesToProcess;
- RestyleCollector collector = { this, &lastRestyle };
- mPendingRestyles.Enumerate(CollectRestyles, &collector);
+ RestyleEnumerateData* restyle = restylesToProcess;
+#ifdef RESTYLE_LOGGING
+ uint32_t count = 0;
+#endif
+ for (auto iter = mPendingRestyles.Iter(); !iter.Done(); iter.Next()) {
+ auto element = static_cast(iter.Key());
+ RestyleTracker::RestyleData* data = iter.Data();
+
+ // Only collect the entries that actually need restyling by us (and
+ // haven't, for example, already been restyled).
+ // It's important to not mess with the flags on entries not in our
+ // document.
+ if (element->GetCrossShadowCurrentDoc() != Document() ||
+ !element->HasFlag(RestyleBit())) {
+ LOG_RESTYLE("skipping pending restyle %s, already restyled or no "
+ "longer in the document",
+ FrameTagToString(element).get());
+ continue;
+ }
+
+ NS_ASSERTION(
+ !element->HasFlag(RootBit()) ||
+ // Maybe we're just not reachable via the frame tree?
+ (element->GetFlattenedTreeParent() &&
+ (!element->GetFlattenedTreeParent()->GetPrimaryFrame() ||
+ element->GetFlattenedTreeParent()->GetPrimaryFrame()->IsLeaf() ||
+ element->GetCrossShadowCurrentDoc()->GetShell()->FrameManager()
+ ->GetDisplayContentsStyleFor(element))) ||
+ // Or not reachable due to an async reinsert we have
+ // pending? If so, we'll have a reframe hint around.
+ // That incidentally makes it safe that we still have
+ // the bit, since any descendants that didn't get added
+ // to the roots list because we had the bits will be
+ // completely restyled in a moment.
+ (data->mChangeHint & nsChangeHint_ReconstructFrame),
+ "Why did this not get handled while processing mRestyleRoots?");
+
+ // Unset the restyle bits now, so if they get readded later as we
+ // process we won't clobber that adding of the bit.
+ element->UnsetFlags(RestyleBit() |
+ RootBit() |
+ ConditionalDescendantsBit());
+
+ restyle->mElement = element;
+ restyle->mRestyleHint = data->mRestyleHint;
+ restyle->mChangeHint = data->mChangeHint;
+ // We can move data since we'll be clearing mPendingRestyles after
+ // we finish enumerating it.
+ restyle->mRestyleHintData = Move(data->mRestyleHintData);
+#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
+ restyle->mBacktrace = Move(data->mBacktrace);
+#endif
+
+#ifdef RESTYLE_LOGGING
+ count++;
+#endif
+
+ // Increment to the next slot in the array
+ restyle++;
+ }
+
+ RestyleEnumerateData* lastRestyle = restyle;
// Clear the hashtable now that we don't need it anymore
mPendingRestyles.Clear();
@@ -371,7 +358,7 @@ RestyleTracker::DoProcessRestyles()
++currentRestyle) {
LOG_RESTYLE("processing pending restyle %s at index %d/%d",
FrameTagToString(currentRestyle->mElement).get(),
- index++, collector.count);
+ index++, count);
LOG_RESTYLE_INDENT();
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
diff --git a/layout/style/Loader.h b/layout/style/Loader.h
index 62644f8a60..d2082eb2a5 100644
--- a/layout/style/Loader.h
+++ b/layout/style/Loader.h
@@ -441,11 +441,6 @@ public:
private:
friend class SheetLoadData;
- static PLDHashOperator
- RemoveEntriesWithURI(URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey,
- RefPtr& aSheet,
- void* aUserData);
-
// Note: null aSourcePrincipal indicates that the content policy and
// CheckLoadURI checks should be skipped.
// aIsPreload indicates whether the html parser preloads that
diff --git a/layout/style/nsRuleNode.h b/layout/style/nsRuleNode.h
index 26dbe0673f..f5298d8da1 100644
--- a/layout/style/nsRuleNode.h
+++ b/layout/style/nsRuleNode.h
@@ -458,18 +458,11 @@ private:
const PLDHashEntryHdr *aHdr,
const void *aKey);
- static PLDHashOperator
- SweepHashEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
- uint32_t number, void *arg);
void SweepChildren(nsTArray& aSweepQueue);
bool DestroyIfNotMarked();
static const PLDHashTableOps ChildrenHashOps;
- static PLDHashOperator
- EnqueueRuleNodeChildren(PLDHashTable *table, PLDHashEntryHdr *hdr,
- uint32_t number, void *arg);
-
Key GetKey() const {
return Key(mRule, GetLevel(), IsImportantRule());
}
diff --git a/layout/tables/SpanningCellSorter.h b/layout/tables/SpanningCellSorter.h
index b0eeabfdcc..8a0ac32906 100644
--- a/layout/tables/SpanningCellSorter.h
+++ b/layout/tables/SpanningCellSorter.h
@@ -76,10 +76,6 @@ private:
HashTableMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
const void *key);
- static PLDHashOperator
- FillSortedArray(PLDHashTable *table, PLDHashEntryHdr *hdr,
- uint32_t number, void *arg);
-
static int SortArray(const void *a, const void *b, void *closure);
/* state used only during enumeration */
diff --git a/media/libcubeb/src/moz.build b/media/libcubeb/src/moz.build
index f80fed2c36..ce937aa47c 100644
--- a/media/libcubeb/src/moz.build
+++ b/media/libcubeb/src/moz.build
@@ -82,3 +82,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
CFLAGS += CONFIG['MOZ_ALSA_CFLAGS']
CFLAGS += CONFIG['MOZ_PULSEAUDIO_CFLAGS']
+
+# We allow warnings for third-party code that can be updated from upstream.
+ALLOW_COMPILER_WARNINGS = True
diff --git a/media/libmkv/moz.build b/media/libmkv/moz.build
index f1d46acf36..caef51e6d8 100644
--- a/media/libmkv/moz.build
+++ b/media/libmkv/moz.build
@@ -25,3 +25,6 @@ if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
NO_VISIBILITY_FLAGS = True
FINAL_LIBRARY = 'gkmedias'
+
+# We allow warnings for third-party code that can be updated from upstream.
+ALLOW_COMPILER_WARNINGS = True
diff --git a/media/libnestegg/src/moz.build b/media/libnestegg/src/moz.build
index fcd3adc434..1a768c64e5 100644
--- a/media/libnestegg/src/moz.build
+++ b/media/libnestegg/src/moz.build
@@ -11,4 +11,4 @@ UNIFIED_SOURCES += [
FINAL_LIBRARY = 'gkmedias'
# We allow warnings for third-party code that can be updated from upstream.
-#ALLOW_COMPILER_WARNINGS = True
+ALLOW_COMPILER_WARNINGS = True
diff --git a/media/libpng/moz.build b/media/libpng/moz.build
index edc057855e..6d21a310ad 100644
--- a/media/libpng/moz.build
+++ b/media/libpng/moz.build
@@ -51,3 +51,6 @@ if CONFIG['GKMEDIAS_SHARED_LIBRARY']:
NO_VISIBILITY_FLAGS = True
FINAL_LIBRARY = 'gkmedias'
+
+# We allow warnings for third-party code that can be updated from upstream.
+ALLOW_COMPILER_WARNINGS = True
diff --git a/memory/build/mozjemalloc_compat.c b/memory/build/mozjemalloc_compat.c
index fd061d264f..14489b70ff 100644
--- a/memory/build/mozjemalloc_compat.c
+++ b/memory/build/mozjemalloc_compat.c
@@ -142,7 +142,7 @@ jemalloc_stats_impl(jemalloc_stats_t *stats)
// src/ctl.c
uint64_t epoch = 0;
size_t esz = sizeof(epoch);
- int ret = je_(mallctl)("epoch", &epoch, &esz, &epoch, esz);
+ je_(mallctl)("epoch", &epoch, &esz, &epoch, esz);
CTL_GET("arenas.narenas", narenas);
CTL_GET("arenas.page", page);
diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp
index a642b1f0d9..a7ae66db2e 100644
--- a/modules/libjar/nsJAR.cpp
+++ b/modules/libjar/nsJAR.cpp
@@ -1,4 +1,5 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; 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/. */
@@ -1096,16 +1097,11 @@ nsZipReaderCache::Init(uint32_t cacheSize)
return NS_OK;
}
-static PLDHashOperator
-DropZipReaderCache(const nsACString &aKey, nsJAR* aZip, void*)
-{
- aZip->SetZipReaderCache(nullptr);
- return PL_DHASH_NEXT;
-}
-
nsZipReaderCache::~nsZipReaderCache()
{
- mZips.EnumerateRead(DropZipReaderCache, nullptr);
+ for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
+ iter.UserData()->SetZipReaderCache(nullptr);
+ }
#ifdef ZIP_CACHE_HIT_RATE
printf("nsZipReaderCache size=%d hits=%d lookups=%d rate=%f%% flushes=%d missed %d\n",
@@ -1256,36 +1252,6 @@ nsZipReaderCache::GetFd(nsIFile* zipFile, PRFileDesc** aRetVal)
#endif /* XP_WIN */
}
-static PLDHashOperator
-FindOldestZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
-{
- nsJAR** oldestPtr = static_cast(aClosure);
- nsJAR* oldest = *oldestPtr;
- nsJAR* current = aZip;
- PRIntervalTime currentReleaseTime = current->GetReleaseTime();
- if (currentReleaseTime != PR_INTERVAL_NO_TIMEOUT) {
- if (oldest == nullptr ||
- currentReleaseTime < oldest->GetReleaseTime()) {
- *oldestPtr = current;
- }
- }
- return PL_DHASH_NEXT;
-}
-
-struct ZipFindData {nsJAR* zip; bool found;};
-
-static PLDHashOperator
-FindZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
-{
- ZipFindData* find_data = static_cast(aClosure);
-
- if (find_data->zip == aZip) {
- find_data->found = true;
- return PL_DHASH_STOP;
- }
- return PL_DHASH_NEXT;
-}
-
nsresult
nsZipReaderCache::ReleaseZip(nsJAR* zip)
{
@@ -1307,9 +1273,15 @@ nsZipReaderCache::ReleaseZip(nsJAR* zip)
// So, we are going to try safeguarding here by searching our hashtable while
// locked here for the zip. We return fast if it is not found.
- ZipFindData find_data = {zip, false};
- mZips.EnumerateRead(FindZip, &find_data);
- if (!find_data.found) {
+ bool found = false;
+ for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
+ if (zip == iter.UserData()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
#ifdef ZIP_CACHE_HIT_RATE
mZipSyncMisses++;
#endif
@@ -1321,8 +1293,18 @@ nsZipReaderCache::ReleaseZip(nsJAR* zip)
if (mZips.Count() <= mCacheSize)
return NS_OK;
+ // Find the oldest zip.
nsJAR* oldest = nullptr;
- mZips.EnumerateRead(FindOldestZip, &oldest);
+ for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
+ nsJAR* current = iter.UserData();
+ PRIntervalTime currentReleaseTime = current->GetReleaseTime();
+ if (currentReleaseTime != PR_INTERVAL_NO_TIMEOUT) {
+ if (oldest == nullptr ||
+ currentReleaseTime < oldest->GetReleaseTime()) {
+ oldest = current;
+ }
+ }
+ }
// Because of the craziness above it is possible that there is no zip that
// needs removing.
@@ -1378,7 +1360,9 @@ nsZipReaderCache::Observe(nsISupports *aSubject,
}
else if (strcmp(aTopic, "chrome-flush-caches") == 0) {
MutexAutoLock lock(mLock);
- mZips.EnumerateRead(DropZipReaderCache, nullptr);
+ for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
+ iter.UserData()->SetZipReaderCache(nullptr);
+ }
mZips.Clear();
}
else if (strcmp(aTopic, "flush-cache-entry") == 0) {
diff --git a/modules/libmar/sign/mar_sign.c b/modules/libmar/sign/mar_sign.c
index 6f21a31977..d43adbf39f 100644
--- a/modules/libmar/sign/mar_sign.c
+++ b/modules/libmar/sign/mar_sign.c
@@ -263,7 +263,7 @@ strip_signature_block(const char *src, const char * dest)
FILE *fpSrc = NULL, *fpDest = NULL;
int rv = -1, hasSignatureBlock;
char buf[BLOCKSIZE];
- char *indexBuf = NULL, *indexBufLoc;
+ char *indexBuf = NULL;
if (!src || !dest) {
fprintf(stderr, "ERROR: Invalid parameter passed in.\n");
@@ -433,7 +433,6 @@ strip_signature_block(const char *src, const char * dest)
/* Consume the index and adjust each index by the difference */
indexBuf = malloc(indexLength);
- indexBufLoc = indexBuf;
if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
fprintf(stderr, "ERROR: Could not read index\n");
goto failure;
@@ -533,6 +532,9 @@ extract_signature(const char *src, uint32_t sigIndex, const char * dest)
/* Skip to the correct signature */
for (i = 0; i <= sigIndex; i++) {
+ /* Avoid leaking while skipping signatures */
+ free(extractedSignature);
+
/* skip past the signature algorithm ID */
if (fseeko(fpSrc, sizeof(uint32_t), SEEK_CUR)) {
fprintf(stderr, "ERROR: Could not seek past sig algorithm ID.\n");
@@ -834,7 +836,7 @@ mar_repackage_and_sign(const char *NSSConfigDir,
char buf[BLOCKSIZE];
SECKEYPrivateKey *privKeys[MAX_SIGNATURES];
CERTCertificate *certs[MAX_SIGNATURES];
- char *indexBuf = NULL, *indexBufLoc;
+ char *indexBuf = NULL;
uint32_t k;
memset(signatureLengths, 0, sizeof(signatureLengths));
@@ -1056,7 +1058,6 @@ mar_repackage_and_sign(const char *NSSConfigDir,
/* Consume the index and adjust each index by signatureSectionLength */
indexBuf = malloc(indexLength);
- indexBufLoc = indexBuf;
if (fread(indexBuf, indexLength, 1, fpSrc) != 1) {
fprintf(stderr, "ERROR: Could not read index\n");
goto failure;
diff --git a/modules/libmar/sign/moz.build b/modules/libmar/sign/moz.build
index d8a6aa7d8f..d7b8d1f8b3 100644
--- a/modules/libmar/sign/moz.build
+++ b/modules/libmar/sign/moz.build
@@ -22,6 +22,3 @@ DEFINES['MAR_NSS'] = True
if CONFIG['OS_ARCH'] == 'WINNT':
USE_STATIC_LIBS = True
-
-# XXX: We should fix these warnings.
-ALLOW_COMPILER_WARNINGS = True
diff --git a/modules/libmar/sign/nss_secutil.c b/modules/libmar/sign/nss_secutil.c
index 31906914b6..4be51e0ac5 100644
--- a/modules/libmar/sign/nss_secutil.c
+++ b/modules/libmar/sign/nss_secutil.c
@@ -81,7 +81,10 @@ GetPasswordString(void *arg, char *prompt)
fflush(stdout);
}
- QUIET_FGETS (phrase, sizeof(phrase), input);
+ if (!QUIET_FGETS(phrase, sizeof(phrase), input)) {
+ fprintf(stderr, "QUIET_FGETS failed\n");
+ return NULL;
+ }
if (isInputTerminal) {
fprintf(stdout, "\n");
diff --git a/modules/libmar/src/mar.h b/modules/libmar/src/mar.h
index 4e53d2cb5b..98b454d94a 100644
--- a/modules/libmar/src/mar.h
+++ b/modules/libmar/src/mar.h
@@ -134,6 +134,26 @@ int mar_create(const char *dest,
*/
int mar_extract(const char *path);
+#define MAR_MAX_CERT_SIZE (16*1024) // Way larger than necessary
+
+/* Read the entire file (not a MAR file) into a newly-allocated buffer.
+ * This function does not write to stderr. Instead, the caller should
+ * write whatever error messages it sees fit. The caller must free the returned
+ * buffer using free().
+ *
+ * @param filePath The path to the file that should be read.
+ * @param maxSize The maximum valid file size.
+ * @param data On success, *data will point to a newly-allocated buffer
+ * with the file's contents in it.
+ * @param size On success, *size will be the size of the created buffer.
+ *
+ * @return 0 on success, -1 on error
+ */
+int mar_read_entire_file(const char * filePath,
+ uint32_t maxSize,
+ /*out*/ const uint8_t * *data,
+ /*out*/ uint32_t *size);
+
/**
* Verifies a MAR file by verifying each signature with the corresponding
* certificate. That is, the first signature will be verified using the first
@@ -154,12 +174,10 @@ int mar_extract(const char *path);
* a negative number if there was an error
* a positive number if the signature does not verify
*/
-#ifdef XP_WIN
-int mar_verify_signaturesW(MarFile *mar,
- const uint8_t * const *certData,
- const uint32_t *certDataSizes,
- uint32_t certCount);
-#endif
+int mar_verify_signatures(MarFile *mar,
+ const uint8_t * const *certData,
+ const uint32_t *certDataSizes,
+ uint32_t certCount);
/**
* Reads the product info block from the MAR file's additional block section.
diff --git a/modules/libmar/src/mar_cmdline.h b/modules/libmar/src/mar_cmdline.h
index e8645ec2b6..e2c9ed5fee 100644
--- a/modules/libmar/src/mar_cmdline.h
+++ b/modules/libmar/src/mar_cmdline.h
@@ -38,38 +38,6 @@ int get_mar_file_info(const char *path,
uint32_t *offsetAdditionalBlocks,
uint32_t *numAdditionalBlocks);
-/**
- * Verifies a MAR file by verifying each signature with the corresponding
- * certificate. That is, the first signature will be verified using the first
- * certificate given, the second signature will be verified using the second
- * certificate given, etc. The signature count must exactly match the number of
- * certificates given, and all signature verifications must succeed.
- * This is only used by the signmar program when used with arguments to verify
- * a MAR. This should not be used to verify a MAR that will be extracted in the
- * same operation by updater code. This function prints the error message if
- * verification fails.
- *
- * @param pathToMAR The path of the MAR file whose signature should be
- * checked
- * @param certData Pointer to the first element in an array of certificate
- * file data.
- * @param certDataSizes Pointer to the first element in an array for size of
- * the cert data.
- * @param certNames Pointer to the first element in an array of certificate
- * names.
- * Used only if compiled with NSS support
- * @param certCount The number of elements in certData, certDataSizes,
- * and certNames
- * @return 0 on success
- * a negative number if there was an error
- * a positive number if the signature does not verify
- */
-int mar_verify_signatures(const char *pathToMAR,
- const uint8_t * const *certData,
- const uint32_t *certDataSizes,
- const char * const *certNames,
- uint32_t certCount);
-
/**
* Reads the product info block from the MAR file's additional block section.
* The caller is responsible for freeing the fields in infoBlock
diff --git a/modules/libmar/src/mar_read.c b/modules/libmar/src/mar_read.c
index 2013b0f4bc..e05df61eeb 100644
--- a/modules/libmar/src/mar_read.c
+++ b/modules/libmar/src/mar_read.c
@@ -337,7 +337,7 @@ int get_mar_file_info_fp(FILE *fp,
}
}
- if (ftell(fp) == offsetToContent) {
+ if ((int64_t)ftell(fp) == (int64_t)offsetToContent) {
*hasAdditionalBlocks = 0;
} else {
if (numAdditionalBlocks) {
@@ -405,10 +405,12 @@ mar_read_product_info_block(MarFile *mar,
/* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and
product version < 32 bytes + 3 NULL terminator bytes. */
char buf[97] = { '\0' };
- int ret = get_mar_file_info_fp(mar->fp, NULL, NULL,
- &hasAdditionalBlocks,
- &offsetAdditionalBlocks,
- &numAdditionalBlocks);
+ if (get_mar_file_info_fp(mar->fp, NULL, NULL,
+ &hasAdditionalBlocks,
+ &offsetAdditionalBlocks,
+ &numAdditionalBlocks) != 0) {
+ return -1;
+ }
for (i = 0; i < numAdditionalBlocks; ++i) {
/* Read the additional block size */
if (fread(&additionalBlockSize,
diff --git a/modules/libmar/src/moz.build b/modules/libmar/src/moz.build
index 5ce04fa0a6..2d25e0849a 100644
--- a/modules/libmar/src/moz.build
+++ b/modules/libmar/src/moz.build
@@ -28,6 +28,3 @@ FORCE_STATIC_LIB = True
if CONFIG['OS_ARCH'] == 'WINNT':
USE_STATIC_LIBS = True
-
-# XXX: We should fix these warnings.
-ALLOW_COMPILER_WARNINGS = True
diff --git a/modules/libmar/tool/mar.c b/modules/libmar/tool/mar.c
index 8abbac7342..fc6d00ab88 100644
--- a/modules/libmar/tool/mar.c
+++ b/modules/libmar/tool/mar.c
@@ -19,6 +19,8 @@
#endif
#if !defined(NO_SIGN_VERIFY) && (!defined(XP_WIN) || defined(MAR_NSS))
+#include "cert.h"
+#include "pk11pub.h"
int NSSInitCryptoContext(const char *NSSConfigDir);
#endif
@@ -115,25 +117,26 @@ int main(int argc, char **argv) {
const char *certNames[MAX_SIGNATURES];
char *MARChannelID = MAR_CHANNEL_ID;
char *productVersion = MOZ_APP_VERSION;
- uint32_t i, k;
+ uint32_t k;
int rv = -1;
uint32_t certCount = 0;
int32_t sigIndex = -1;
-#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
- HANDLE certFile;
- uint8_t *certBuffers[MAX_SIGNATURES];
-#endif
-#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
- defined(XP_MACOSX))
- char* DERFilePaths[MAX_SIGNATURES];
+#if !defined(NO_SIGN_VERIFY)
uint32_t fileSizes[MAX_SIGNATURES];
- uint32_t read;
+ const uint8_t* certBuffers[MAX_SIGNATURES];
+#if ((!defined(MAR_NSS) && defined(XP_WIN)) || defined(XP_MACOSX)) || \
+ ((defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS))
+ char* DERFilePaths[MAX_SIGNATURES];
+#endif
+#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS)
+ CERTCertificate* certs[MAX_SIGNATURES];
+#endif
#endif
- memset(certNames, 0, sizeof(certNames));
+ memset((void*)certNames, 0, sizeof(certNames));
#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY)
- memset(certBuffers, 0, sizeof(certBuffers));
+ memset((void*)certBuffers, 0, sizeof(certBuffers));
#endif
#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \
defined(XP_MACOSX))
@@ -161,7 +164,9 @@ int main(int argc, char **argv) {
break;
/* -C workingdirectory */
} else if (argv[1][0] == '-' && argv[1][1] == 'C') {
- chdir(argv[2]);
+ if (chdir(argv[2]) != 0) {
+ return -1;
+ }
argv += 2;
argc -= 2;
}
@@ -319,43 +324,71 @@ int main(int argc, char **argv) {
return import_signature(argv[2], sigIndex, argv[3], argv[4]);
case 'v':
-
-#if defined(XP_WIN) && !defined(MAR_NSS)
if (certCount == 0) {
print_usage();
return -1;
}
- for (k = 0; k < certCount; ++k) {
- /* If the mar program was built using CryptoAPI, then read in the buffer
- containing the cert from disk. */
- certFile = CreateFileA(DERFilePaths[k], GENERIC_READ,
- FILE_SHARE_READ |
- FILE_SHARE_WRITE |
- FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- 0, NULL);
- if (INVALID_HANDLE_VALUE == certFile) {
- return -1;
- }
- fileSizes[k] = GetFileSize(certFile, NULL);
- certBuffers[k] = malloc(fileSizes[k]);
- if (!ReadFile(certFile, certBuffers[k], fileSizes[k], &read, NULL) ||
- fileSizes[k] != read) {
- CloseHandle(certFile);
- for (i = 0; i <= k; i++) {
- free(certBuffers[i]);
- }
- return -1;
- }
- CloseHandle(certFile);
+#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS)
+ if (!NSSConfigDir || certCount == 0) {
+ print_usage();
+ return -1;
}
- rv = mar_verify_signatures(argv[2], certBuffers, fileSizes,
- NULL, certCount);
+ if (NSSInitCryptoContext(NSSConfigDir)) {
+ fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
+ return -1;
+ }
+#endif
+
+ rv = 0;
for (k = 0; k < certCount; ++k) {
- free(certBuffers[k]);
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS)
+ rv = mar_read_entire_file(DERFilePaths[k], MAR_MAX_CERT_SIZE,
+ &certBuffers[k], &fileSizes[k]);
+
+ if (rv) {
+ fprintf(stderr, "ERROR: could not read file %s", DERFilePaths[k]);
+ break;
+ }
+#else
+ /* It is somewhat circuitous to look up a CERTCertificate and then pass
+ * in its DER encoding just so we can later re-create that
+ * CERTCertificate to extract the public key out of it. However, by doing
+ * things this way, we maximize the reuse of the mar_verify_signatures
+ * function and also we keep the control flow as similar as possible
+ * between programs and operating systems, at least for the functions
+ * that are critically important to security.
+ */
+ certs[k] = PK11_FindCertFromNickname(certNames[k], NULL);
+ if (certs[k]) {
+ certBuffers[k] = certs[k]->derCert.data;
+ fileSizes[k] = certs[k]->derCert.len;
+ } else {
+ rv = -1;
+ fprintf(stderr, "ERROR: could not find cert from nickname %s", certNames[k]);
+ break;
+ }
+#endif
+ }
+
+ if (!rv) {
+ MarFile *mar = mar_open(argv[2]);
+ if (mar) {
+ rv = mar_verify_signatures(mar, certBuffers, fileSizes, certCount);
+ mar_close(mar);
+ } else {
+ fprintf(stderr, "ERROR: Could not open MAR file.\n");
+ rv = -1;
+ }
+ }
+ for (k = 0; k < certCount; ++k) {
+#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS)
+ free((void*)certBuffers[k]);
+#else
+ /* certBuffers[k] is owned by certs[k] so don't free it */
+ CERT_DestroyCertificate(certs[k]);
+#endif
}
if (rv) {
/* Determine if the source MAR file has the new fields for signing */
@@ -369,26 +402,8 @@ int main(int argc, char **argv) {
}
return -1;
}
-
return 0;
-#elif defined(XP_MACOSX)
- return mar_verify_signatures(argv[2], (const uint8_t* const*)DERFilePaths,
- 0, NULL, certCount);
-#else
- if (!NSSConfigDir || certCount == 0) {
- print_usage();
- return -1;
- }
-
- if (NSSInitCryptoContext(NSSConfigDir)) {
- fprintf(stderr, "ERROR: Could not initialize crypto library.\n");
- return -1;
- }
-
- return mar_verify_signatures(argv[2], NULL, 0, certNames, certCount);
-
-#endif /* defined(XP_WIN) && !defined(MAR_NSS) */
case 's':
if (!NSSConfigDir || certCount == 0 || argc < 4) {
print_usage();
diff --git a/modules/libmar/tool/moz.build b/modules/libmar/tool/moz.build
index 5f04217030..5b521241fb 100644
--- a/modules/libmar/tool/moz.build
+++ b/modules/libmar/tool/moz.build
@@ -27,6 +27,7 @@ if CONFIG['MOZ_ENABLE_SIGNMAR']:
for var in ('MAR_CHANNEL_ID', 'MOZ_APP_VERSION'):
DEFINES[var] = '"%s"' % CONFIG[var]
+ HOST_DEFINES[var] = DEFINES[var]
if CONFIG['MOZ_ENABLE_SIGNMAR']:
USE_LIBS += [
@@ -57,14 +58,6 @@ if CONFIG['HOST_OS_ARCH'] == 'WINNT':
'ws2_32',
]
-# XXX: We should fix these warnings.
-ALLOW_COMPILER_WARNINGS = True
-
-HOST_CFLAGS += [
- #TODO: bug 1200360 - don't pass make variables here
- '$(DEFINES)',
-]
-
HOST_DEFINES['NO_SIGN_VERIFY'] = True
if CONFIG['CROSS_COMPILE'] and CONFIG['HOST_NSPR_MDCPUCFG']:
diff --git a/modules/libmar/verify/cryptox.c b/modules/libmar/verify/cryptox.c
index 48fbecdfab..af34210383 100644
--- a/modules/libmar/verify/cryptox.c
+++ b/modules/libmar/verify/cryptox.c
@@ -16,29 +16,32 @@
/**
* Loads the public key for the specified cert name from the NSS store.
*
- * @param certName The cert name to find.
+ * @param certData The DER-encoded X509 certificate to extract the key from.
+ * @param certDataSize The size of certData.
* @param publicKey Out parameter for the public key to use.
- * @param cert Out parameter for the certificate to use.
* @return CryptoX_Success on success, CryptoX_Error on error.
*/
CryptoX_Result
-NSS_LoadPublicKey(const char *certNickname,
- SECKEYPublicKey **publicKey,
- CERTCertificate **cert)
+NSS_LoadPublicKey(const unsigned char *certData, unsigned int certDataSize,
+ SECKEYPublicKey **publicKey)
{
- secuPWData pwdata = { PW_NONE, 0 };
- if (!cert || !publicKey || !cert) {
+ CERTCertificate * cert;
+ SECItem certDataItem = { siBuffer, (unsigned char*) certData, certDataSize };
+
+ if (!certData || !publicKey) {
return CryptoX_Error;
}
+ cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &certDataItem, NULL,
+ PR_FALSE, PR_TRUE);
/* Get the cert and embedded public key out of the database */
- *cert = PK11_FindCertFromNickname(certNickname, &pwdata);
- if (!*cert) {
+ if (!cert) {
return CryptoX_Error;
}
- *publicKey = CERT_ExtractPublicKey(*cert);
+ *publicKey = CERT_ExtractPublicKey(cert);
+ CERT_DestroyCertificate(cert);
+
if (!*publicKey) {
- CERT_DestroyCertificate(*cert);
return CryptoX_Error;
}
return CryptoX_Success;
@@ -150,12 +153,11 @@ CryptoX_Result
CryptoAPI_LoadPublicKey(HCRYPTPROV provider,
BYTE *certData,
DWORD sizeOfCertData,
- HCRYPTKEY *publicKey,
- HCERTSTORE *certStore)
+ HCRYPTKEY *publicKey)
{
CRYPT_DATA_BLOB blob;
CERT_CONTEXT *context;
- if (!provider || !certData || !publicKey || !certStore) {
+ if (!provider || !certData || !publicKey) {
return CryptoX_Error;
}
@@ -165,7 +167,7 @@ CryptoAPI_LoadPublicKey(HCRYPTPROV provider,
CERT_QUERY_CONTENT_FLAG_CERT,
CERT_QUERY_FORMAT_FLAG_BINARY,
0, NULL, NULL, NULL,
- certStore, NULL, (const void **)&context)) {
+ NULL, NULL, (const void **)&context)) {
return CryptoX_Error;
}
diff --git a/modules/libmar/verify/cryptox.h b/modules/libmar/verify/cryptox.h
index d5f61eaa1b..2296b815f4 100644
--- a/modules/libmar/verify/cryptox.h
+++ b/modules/libmar/verify/cryptox.h
@@ -15,7 +15,9 @@
#if defined(MAR_NSS)
-#include "nss_secutil.h"
+#include "cert.h"
+#include "keyhi.h"
+#include "cryptohi.h"
#define CryptoX_InvalidHandleValue NULL
#define CryptoX_ProviderHandle void*
@@ -26,9 +28,9 @@
#ifdef __cplusplus
extern "C" {
#endif
-CryptoX_Result NSS_LoadPublicKey(const char *certNickname,
- SECKEYPublicKey **publicKey,
- CERTCertificate **cert);
+CryptoX_Result NSS_LoadPublicKey(const unsigned char* certData,
+ unsigned int certDataSize,
+ SECKEYPublicKey** publicKey);
CryptoX_Result NSS_VerifyBegin(VFYContext **ctx,
SECKEYPublicKey * const *publicKey);
CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
@@ -46,9 +48,8 @@ CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx ,
VFY_DestroyContext(*SignatureHandle, PR_TRUE)
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
VFY_Update(*SignatureHandle, (const unsigned char*)(buf), len)
-#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
- publicKey, certName, cert) \
- NSS_LoadPublicKey(certName, publicKey, cert)
+#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
+ NSS_LoadPublicKey(certData, dataSize, publicKey)
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
NSS_VerifySignature(hash, (const unsigned char *)(signedData), len)
#define CryptoX_FreePublicKey(key) \
@@ -92,7 +93,7 @@ void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey);
#define CryptoX_VerifyUpdate(aInputData, aBuf, aLen) \
CryptoMac_VerifyUpdate(aInputData, aBuf, aLen)
#define CryptoX_LoadPublicKey(aProviderHandle, aCertData, aDataSize, \
- aPublicKey, aCertName, aCert) \
+ aPublicKey) \
CryptoMac_LoadPublicKey(aCertData, aDataSize, aPublicKey)
#define CryptoX_VerifySignature(aInputData, aPublicKey, aSignature, \
aSignatureLen) \
@@ -112,8 +113,7 @@ CryptoX_Result CryptoAPI_InitCryptoContext(HCRYPTPROV *provider);
CryptoX_Result CryptoAPI_LoadPublicKey(HCRYPTPROV hProv,
BYTE *certData,
DWORD sizeOfCertData,
- HCRYPTKEY *publicKey,
- HCERTSTORE *cert);
+ HCRYPTKEY *publicKey);
CryptoX_Result CryptoAPI_VerifyBegin(HCRYPTPROV provider, HCRYPTHASH* hash);
CryptoX_Result CryptoAPI_VerifyUpdate(HCRYPTHASH* hash,
BYTE *buf, DWORD len);
@@ -134,10 +134,8 @@ CryptoX_Result CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
#define CryptoX_FreeSignatureHandle(SignatureHandle)
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) \
CryptoAPI_VerifyUpdate(SignatureHandle, (BYTE *)(buf), len)
-#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
- publicKey, certName, cert) \
- CryptoAPI_LoadPublicKey(CryptoHandle, (BYTE*)(certData), \
- dataSize, publicKey, cert)
+#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
+ CryptoAPI_LoadPublicKey(CryptoHandle, (BYTE*)(certData), dataSize, publicKey)
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) \
CyprtoAPI_VerifySignature(hash, publicKey, signedData, len)
#define CryptoX_FreePublicKey(key) \
@@ -164,8 +162,7 @@ CryptoX_Result CyprtoAPI_VerifySignature(HCRYPTHASH *hash,
CryptoX_Error
#define CryptoX_FreeSignatureHandle(SignatureHandle)
#define CryptoX_VerifyUpdate(SignatureHandle, buf, len) CryptoX_Error
-#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, \
- publicKey, certName, cert) \
+#define CryptoX_LoadPublicKey(CryptoHandle, certData, dataSize, publicKey) \
CryptoX_Error
#define CryptoX_VerifySignature(hash, publicKey, signedData, len) CryptoX_Error
#define CryptoX_FreePublicKey(key) CryptoX_Error
diff --git a/modules/libmar/verify/mar_verify.c b/modules/libmar/verify/mar_verify.c
index 7578b62e31..ea93ce28a7 100644
--- a/modules/libmar/verify/mar_verify.c
+++ b/modules/libmar/verify/mar_verify.c
@@ -17,6 +17,46 @@
#include "mar.h"
#include "cryptox.h"
+int
+mar_read_entire_file(const char * filePath, uint32_t maxSize,
+ /*out*/ const uint8_t * *data,
+ /*out*/ uint32_t *size)
+{
+ int result;
+ FILE * f;
+
+ if (!filePath || !data || !size) {
+ return -1;
+ }
+
+ f = fopen(filePath, "rb");
+ if (!f) {
+ return -1;
+ }
+
+ result = -1;
+ if (!fseeko(f, 0, SEEK_END)) {
+ int64_t fileSize = ftello(f);
+ if (fileSize > 0 && fileSize <= maxSize && !fseeko(f, 0, SEEK_SET)) {
+ unsigned char * fileData;
+
+ *size = (unsigned int) fileSize;
+ fileData = malloc(*size);
+ if (fileData) {
+ if (fread(fileData, *size, 1, f) == 1) {
+ *data = fileData;
+ result = 0;
+ } else {
+ free(fileData);
+ }
+ }
+ }
+ fclose(f);
+ }
+
+ return result;
+}
+
int mar_extract_and_verify_signatures_fp(FILE *fp,
CryptoX_ProviderHandle provider,
CryptoX_PublicKey *keys,
@@ -81,92 +121,8 @@ ReadAndUpdateVerifyContext(FILE *fp,
* certificate given, the second signature will be verified using the second
* certificate given, etc. The signature count must exactly match the number of
* certificates given, and all signature verifications must succeed.
- * This is only used by the signmar program when used with arguments to verify
- * a MAR. This should not be used to verify a MAR that will be extracted in the
- * same operation by updater code. This function prints the error message if
- * verification fails.
*
- * @param pathToMARFile The path of the MAR file to verify.
- * @param certData Pointer to the first element in an array of certificate
- * file data.
- * @param certDataSizes Pointer to the first element in an array for size of the
- * cert data.
- * @param certNames Pointer to the first element in an array of certificate names.
- * Used only if compiled as NSS, specifies the certificate names
- * @param certCount The number of elements in certData, certDataSizes, and certNames
- * @return 0 on success
- * a negative number if there was an error
- * a positive number if the signature does not verify
- */
-int
-mar_verify_signatures(const char *pathToMARFile,
- const uint8_t * const *certData,
- const uint32_t *certDataSizes,
- const char * const *certNames,
- uint32_t certCount) {
- int rv;
- CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
- CryptoX_Certificate certs[MAX_SIGNATURES];
- CryptoX_PublicKey keys[MAX_SIGNATURES];
- FILE *fp;
- uint32_t k;
-
- memset(certs, 0, sizeof(certs));
- memset(keys, 0, sizeof(keys));
-
- if (!pathToMARFile || certCount == 0) {
- fprintf(stderr, "ERROR: Invalid parameter specified.\n");
- return CryptoX_Error;
- }
-
- fp = fopen(pathToMARFile, "rb");
- if (!fp) {
- fprintf(stderr, "ERROR: Could not open MAR file.\n");
- return CryptoX_Error;
- }
-
- if (CryptoX_Failed(CryptoX_InitCryptoProvider(&provider))) {
- fclose(fp);
- fprintf(stderr, "ERROR: Could not init crytpo library.\n");
- return CryptoX_Error;
- }
-
- /* Load the certs and keys */
- for (k = 0; k < certCount; k++) {
- if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
- &keys[k], certNames[k], &certs[k]))) {
- fclose(fp);
- fprintf(stderr, "ERROR: Could not load public key.\n");
- return CryptoX_Error;
- }
- }
-
- rv = mar_extract_and_verify_signatures_fp(fp, provider, keys, certCount);
- fclose(fp);
-
- /* Cleanup the allocated keys and certs */
- for (k = 0; k < certCount; k++) {
- if (keys[k]) {
- CryptoX_FreePublicKey(&keys[k]);
- }
-
- if (certs[k]) {
- CryptoX_FreeCertificate(&certs[k]);
- }
- }
- return rv;
-}
-
-#ifdef XP_WIN
-/**
- * Verifies a MAR file by verifying each signature with the corresponding
- * certificate. That is, the first signature will be verified using the first
- * certificate given, the second signature will be verified using the second
- * certificate given, etc. The signature count must exactly match the number of
- * certificates given, and all signature verifications must succeed.
- *
- * @param pathToMARFile The path of the MAR file who's signature
- * should be calculated
+ * @param mar The file who's signature should be calculated
* @param certData Pointer to the first element in an array of
* certificate data
* @param certDataSizes Pointer to the first element in an array for size of
@@ -175,17 +131,15 @@ mar_verify_signatures(const char *pathToMARFile,
* @return 0 on success
*/
int
-mar_verify_signaturesW(MarFile *mar,
- const uint8_t * const *certData,
- const uint32_t *certDataSizes,
- uint32_t certCount) {
+mar_verify_signatures(MarFile *mar,
+ const uint8_t * const *certData,
+ const uint32_t *certDataSizes,
+ uint32_t certCount) {
int rv = -1;
CryptoX_ProviderHandle provider = CryptoX_InvalidHandleValue;
- CryptoX_Certificate certs[MAX_SIGNATURES];
CryptoX_PublicKey keys[MAX_SIGNATURES];
uint32_t k;
- memset(certs, 0, sizeof(certs));
memset(keys, 0, sizeof(keys));
if (!mar || !certData || !certDataSizes || certCount == 0) {
@@ -205,7 +159,7 @@ mar_verify_signaturesW(MarFile *mar,
for (k = 0; k < certCount; ++k) {
if (CryptoX_Failed(CryptoX_LoadPublicKey(provider, certData[k], certDataSizes[k],
- &keys[k], "", &certs[k]))) {
+ &keys[k]))) {
fprintf(stderr, "ERROR: Could not load public key.\n");
goto failure;
}
@@ -219,15 +173,10 @@ failure:
if (keys[k]) {
CryptoX_FreePublicKey(&keys[k]);
}
-
- if (certs[k]) {
- CryptoX_FreeCertificate(&certs[k]);
- }
}
return rv;
}
-#endif
/**
* Extracts each signature from the specified MAR file,
@@ -244,11 +193,8 @@ mar_extract_and_verify_signatures_fp(FILE *fp,
CryptoX_ProviderHandle provider,
CryptoX_PublicKey *keys,
uint32_t keyCount) {
- char buf[5] = {0};
uint32_t signatureCount, signatureLen, numVerified = 0;
uint32_t signatureAlgorithmIDs[MAX_SIGNATURES];
- int rv = -1;
- int64_t curPos;
uint8_t *extractedSignatures[MAX_SIGNATURES];
uint32_t i;
@@ -336,13 +282,17 @@ mar_extract_and_verify_signatures_fp(FILE *fp,
}
}
- curPos = ftello(fp);
- rv = mar_verify_signatures_for_fp(fp,
- provider,
- keys,
- (const uint8_t * const *)extractedSignatures,
- signatureCount,
- &numVerified);
+ if (ftello(fp) == -1) {
+ return CryptoX_Error;
+ }
+ if (mar_verify_signatures_for_fp(fp,
+ provider,
+ keys,
+ (const uint8_t * const *)extractedSignatures,
+ signatureCount,
+ &numVerified) == CryptoX_Error) {
+ return CryptoX_Error;
+ }
for (i = 0; i < signatureCount; ++i) {
free(extractedSignatures[i]);
}
diff --git a/modules/libpref/nsPrefBranch.h b/modules/libpref/nsPrefBranch.h
index 79328cbfb7..e52f7649af 100644
--- a/modules/libpref/nsPrefBranch.h
+++ b/modules/libpref/nsPrefBranch.h
@@ -216,11 +216,6 @@ protected:
const char *getPrefName(const char *aPrefName);
void freeObserverList(void);
- friend PLDHashOperator
- FreeObserverFunc(PrefCallback *aKey,
- nsAutoPtr &aCallback,
- void *aArgs);
-
private:
int32_t mPrefRootLength;
nsCString mPrefRoot;
diff --git a/netwerk/base/EventTokenBucket.cpp b/netwerk/base/EventTokenBucket.cpp
index ae60442e10..9e8edeb61e 100644
--- a/netwerk/base/EventTokenBucket.cpp
+++ b/netwerk/base/EventTokenBucket.cpp
@@ -207,6 +207,18 @@ EventTokenBucket::UnPause()
UpdateTimer();
}
+void
+EventTokenBucket::Stop()
+{
+ MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
+ SOCKET_LOG(("EventTokenBucket::Stop %p armed=%d\n", this, mTimerArmed));
+ mStopped = true;
+ if (mTimerArmed) {
+ mTimer->Cancel();
+ mTimerArmed = false;
+ }
+}
+
nsresult
EventTokenBucket::SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable)
{
diff --git a/netwerk/base/EventTokenBucket.h b/netwerk/base/EventTokenBucket.h
index fe760e76d2..ff14abe65a 100644
--- a/netwerk/base/EventTokenBucket.h
+++ b/netwerk/base/EventTokenBucket.h
@@ -86,7 +86,7 @@ public:
// credits. ClearCredits can be used before unpausing if desired.
void Pause();
void UnPause();
- void Stop() { mStopped = true; }
+ void Stop();
// The returned cancelable event can only be canceled from the socket thread
nsresult SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable);
diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp
index aef332945b..7d081fdfb0 100644
--- a/netwerk/base/nsSocketTransportService2.cpp
+++ b/netwerk/base/nsSocketTransportService2.cpp
@@ -8,6 +8,7 @@
#include "nsSocketTransport2.h"
#include "NetworkActivityMonitor.h"
#include "mozilla/Preferences.h"
+#include "nsIOService.h"
#endif // !defined(MOZILLA_XPCOMRT_API)
#include "nsASocketHandler.h"
#include "nsError.h"
@@ -1002,7 +1003,16 @@ nsSocketTransportService::DoPollIteration(bool wait, TimeDuration *pollDuration)
// Measures seconds spent while blocked on PR_Poll
uint32_t pollInterval;
- int32_t n = Poll(wait, &pollInterval, pollDuration);
+ int32_t n = 0;
+#if !defined(MOZILLA_XPCOMRT_API)
+ if (!gIOService->IsNetTearingDown()) {
+ // Let's not do polling during shutdown.
+ n = Poll(wait, &pollInterval, pollDuration);
+ }
+#else
+ n = Poll(wait, &pollInterval, pollDuration);
+#endif // defined(MOZILLA_XPCOMRT_API)
+
if (n < 0) {
SOCKET_LOG((" PR_Poll error [%d] os error [%d]\n", PR_GetError(),
PR_GetOSError()));
diff --git a/netwerk/protocol/http/ConnectionDiagnostics.cpp b/netwerk/protocol/http/ConnectionDiagnostics.cpp
index 5a3b818b23..d1ab03e843 100644
--- a/netwerk/protocol/http/ConnectionDiagnostics.cpp
+++ b/netwerk/protocol/http/ConnectionDiagnostics.cpp
@@ -42,67 +42,61 @@ nsHttpConnectionMgr::OnMsgPrintDiagnostics(int32_t, ARefBase *)
mLogData.AppendPrintf("mNumActiveConns = %d\n", mNumActiveConns);
mLogData.AppendPrintf("mNumIdleConns = %d\n", mNumIdleConns);
- mCT.Enumerate(PrintDiagnosticsCB, this);
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& ent = iter.Data();
+
+ mLogData.AppendPrintf(" ent host = %s hashkey = %s\n",
+ ent->mConnInfo->Origin(), ent->mConnInfo->HashKey().get());
+ mLogData.AppendPrintf(" AtActiveConnectionLimit = %d\n",
+ AtActiveConnectionLimit(ent, NS_HTTP_ALLOW_KEEPALIVE));
+ mLogData.AppendPrintf(" RestrictConnections = %d\n",
+ RestrictConnections(ent));
+ mLogData.AppendPrintf(" Pending Q Length = %u\n",
+ ent->mPendingQ.Length());
+ mLogData.AppendPrintf(" Active Conns Length = %u\n",
+ ent->mActiveConns.Length());
+ mLogData.AppendPrintf(" Idle Conns Length = %u\n",
+ ent->mIdleConns.Length());
+ mLogData.AppendPrintf(" Half Opens Length = %u\n",
+ ent->mHalfOpens.Length());
+ mLogData.AppendPrintf(" Coalescing Keys Length = %u\n",
+ ent->mCoalescingKeys.Length());
+ mLogData.AppendPrintf(" Spdy using = %d, tested = %d, preferred = %d\n",
+ ent->mUsingSpdy, ent->mTestedSpdy, ent->mInPreferredHash);
+ mLogData.AppendPrintf(" pipelinestate = %d penalty = %d\n",
+ ent->mPipelineState, ent->mPipeliningPenalty);
+
+ uint32_t i;
+ for (i = 0; i < nsAHttpTransaction::CLASS_MAX; ++i) {
+ mLogData.AppendPrintf(" pipeline per class penalty 0x%x %d\n",
+ i, ent->mPipeliningClassPenalty[i]);
+ }
+ for (i = 0; i < ent->mActiveConns.Length(); ++i) {
+ mLogData.AppendPrintf(" :: Active Connection #%u\n", i);
+ ent->mActiveConns[i]->PrintDiagnostics(mLogData);
+ }
+ for (i = 0; i < ent->mIdleConns.Length(); ++i) {
+ mLogData.AppendPrintf(" :: Idle Connection #%u\n", i);
+ ent->mIdleConns[i]->PrintDiagnostics(mLogData);
+ }
+ for (i = 0; i < ent->mHalfOpens.Length(); ++i) {
+ mLogData.AppendPrintf(" :: Half Open #%u\n", i);
+ ent->mHalfOpens[i]->PrintDiagnostics(mLogData);
+ }
+ for (i = 0; i < ent->mPendingQ.Length(); ++i) {
+ mLogData.AppendPrintf(" :: Pending Transaction #%u\n", i);
+ ent->mPendingQ[i]->PrintDiagnostics(mLogData);
+ }
+ for (i = 0; i < ent->mCoalescingKeys.Length(); ++i) {
+ mLogData.AppendPrintf(" :: Coalescing Key #%u %s\n",
+ i, ent->mCoalescingKeys[i].get());
+ }
+ }
consoleService->LogStringMessage(NS_ConvertUTF8toUTF16(mLogData).Data());
mLogData.Truncate();
}
-PLDHashOperator
-nsHttpConnectionMgr::PrintDiagnosticsCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- nsHttpConnectionMgr *self = static_cast(closure);
- uint32_t i;
-
- self->mLogData.AppendPrintf(" ent host = %s hashkey = %s\n",
- ent->mConnInfo->Origin(), ent->mConnInfo->HashKey().get());
- self->mLogData.AppendPrintf(" AtActiveConnectionLimit = %d\n",
- self->AtActiveConnectionLimit(ent, NS_HTTP_ALLOW_KEEPALIVE));
- self->mLogData.AppendPrintf(" RestrictConnections = %d\n",
- self->RestrictConnections(ent));
- self->mLogData.AppendPrintf(" Pending Q Length = %u\n",
- ent->mPendingQ.Length());
- self->mLogData.AppendPrintf(" Active Conns Length = %u\n",
- ent->mActiveConns.Length());
- self->mLogData.AppendPrintf(" Idle Conns Length = %u\n",
- ent->mIdleConns.Length());
- self->mLogData.AppendPrintf(" Half Opens Length = %u\n",
- ent->mHalfOpens.Length());
- self->mLogData.AppendPrintf(" Coalescing Keys Length = %u\n",
- ent->mCoalescingKeys.Length());
- self->mLogData.AppendPrintf(" Spdy using = %d, tested = %d, preferred = %d\n",
- ent->mUsingSpdy, ent->mTestedSpdy, ent->mInPreferredHash);
- self->mLogData.AppendPrintf(" pipelinestate = %d penalty = %d\n",
- ent->mPipelineState, ent->mPipeliningPenalty);
- for (i = 0; i < nsAHttpTransaction::CLASS_MAX; ++i) {
- self->mLogData.AppendPrintf(" pipeline per class penalty 0x%x %d\n",
- i, ent->mPipeliningClassPenalty[i]);
- }
- for (i = 0; i < ent->mActiveConns.Length(); ++i) {
- self->mLogData.AppendPrintf(" :: Active Connection #%u\n", i);
- ent->mActiveConns[i]->PrintDiagnostics(self->mLogData);
- }
- for (i = 0; i < ent->mIdleConns.Length(); ++i) {
- self->mLogData.AppendPrintf(" :: Idle Connection #%u\n", i);
- ent->mIdleConns[i]->PrintDiagnostics(self->mLogData);
- }
- for (i = 0; i < ent->mHalfOpens.Length(); ++i) {
- self->mLogData.AppendPrintf(" :: Half Open #%u\n", i);
- ent->mHalfOpens[i]->PrintDiagnostics(self->mLogData);
- }
- for (i = 0; i < ent->mPendingQ.Length(); ++i) {
- self->mLogData.AppendPrintf(" :: Pending Transaction #%u\n", i);
- ent->mPendingQ[i]->PrintDiagnostics(self->mLogData);
- }
- for (i = 0; i < ent->mCoalescingKeys.Length(); ++i) {
- self->mLogData.AppendPrintf(" :: Coalescing Key #%u %s\n",
- i, ent->mCoalescingKeys[i].get());
- }
- return PL_DHASH_NEXT;
-}
-
void
nsHttpConnectionMgr::nsHalfOpenSocket::PrintDiagnostics(nsCString &log)
{
diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp
index b247057879..d768fdc69c 100644
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -134,51 +134,27 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
mPreviousPingThreshold = mPingThreshold;
}
-PLDHashOperator
-Http2Session::ShutdownEnumerator(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
+void
+Http2Session::Shutdown()
{
- Http2Session *self = static_cast(closure);
- nsresult result;
+ for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr &stream = iter.Data();
- // On a clean server hangup the server sets the GoAwayID to be the ID of
- // the last transaction it processed. If the ID of stream in the
- // local stream is greater than that it can safely be restarted because the
- // server guarantees it was not partially processed. Streams that have not
- // registered an ID haven't actually been sent yet so they can always be
- // restarted.
- if (self->mCleanShutdown &&
- (stream->StreamID() > self->mGoAwayID || !stream->HasRegisteredID())) {
- result = NS_ERROR_NET_RESET; // can be restarted
- } else if (stream->RecvdData()) {
- result = NS_ERROR_NET_PARTIAL_TRANSFER;
- } else {
- result = NS_ERROR_ABORT;
+ // On a clean server hangup the server sets the GoAwayID to be the ID of
+ // the last transaction it processed. If the ID of stream in the
+ // local stream is greater than that it can safely be restarted because the
+ // server guarantees it was not partially processed. Streams that have not
+ // registered an ID haven't actually been sent yet so they can always be
+ // restarted.
+ if (mCleanShutdown &&
+ (stream->StreamID() > mGoAwayID || !stream->HasRegisteredID())) {
+ CloseStream(stream, NS_ERROR_NET_RESET); // can be restarted
+ } else if (stream->RecvdData()) {
+ CloseStream(stream, NS_ERROR_NET_PARTIAL_TRANSFER);
+ } else {
+ CloseStream(stream, NS_ERROR_ABORT);
+ }
}
-
- self->CloseStream(stream, result);
-
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-Http2Session::GoAwayEnumerator(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
-{
- Http2Session *self = static_cast(closure);
-
- // these streams were not processed by the server and can be restarted.
- // Do that after the enumerator completes to avoid the risk of
- // a restart event re-entrantly modifying this hash. Be sure not to restart
- // a pushed (even numbered) stream
- if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
- !stream->HasRegisteredID()) {
- self->mGoAwayStreamsToRestart.Push(stream);
- }
-
- return PL_DHASH_NEXT;
}
Http2Session::~Http2Session()
@@ -186,7 +162,7 @@ Http2Session::~Http2Session()
LOG3(("Http2Session::~Http2Session %p mDownstreamState=%X",
this, mDownstreamState));
- mStreamTransactionHash.Enumerate(ShutdownEnumerator, this);
+ Shutdown();
}
void
@@ -1419,16 +1395,6 @@ Http2Session::RecvRstStream(Http2Session *self)
return NS_OK;
}
-PLDHashOperator
-Http2Session::UpdateServerRwinEnumerator(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
-{
- int32_t delta = *(static_cast(closure));
- stream->UpdateServerReceiveWindow(delta);
- return PL_DHASH_NEXT;
-}
-
nsresult
Http2Session::RecvSettings(Http2Session *self)
{
@@ -1488,10 +1454,13 @@ Http2Session::RecvSettings(Http2Session *self)
int32_t delta = value - self->mServerInitialStreamWindow;
self->mServerInitialStreamWindow = value;
- // SETTINGS only adjusts stream windows. Leave the sesison window alone.
- // we need to add the delta to all open streams (delta can be negative)
- self->mStreamTransactionHash.Enumerate(UpdateServerRwinEnumerator,
- &delta);
+ // SETTINGS only adjusts stream windows. Leave the session window alone.
+ // We need to add the delta to all open streams (delta can be negative)
+ for (auto iter = self->mStreamTransactionHash.Iter();
+ !iter.Done();
+ iter.Next()) {
+ iter.Data()->UpdateServerReceiveWindow(delta);
+ }
}
break;
@@ -1826,9 +1795,21 @@ Http2Session::RecvGoAway(Http2Session *self)
self->mInputFrameBuffer.get() + kFrameHeaderBytes + 4);
// Find streams greater than the last-good ID and mark them for deletion
- // in the mGoAwayStreamsToRestart queue with the GoAwayEnumerator. The
- // underlying transaction can be restarted.
- self->mStreamTransactionHash.Enumerate(GoAwayEnumerator, self);
+ // in the mGoAwayStreamsToRestart queue. The underlying transaction can be
+ // restarted.
+ for (auto iter = self->mStreamTransactionHash.Iter();
+ !iter.Done();
+ iter.Next()) {
+ // these streams were not processed by the server and can be restarted.
+ // Do that after the enumerator completes to avoid the risk of
+ // a restart event re-entrantly modifying this hash. Be sure not to restart
+ // a pushed (even numbered) stream
+ nsAutoPtr& stream = iter.Data();
+ if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
+ !stream->HasRegisteredID()) {
+ self->mGoAwayStreamsToRestart.Push(stream);
+ }
+ }
// Process the streams marked for deletion and restart.
size_t size = self->mGoAwayStreamsToRestart.GetSize();
@@ -1869,22 +1850,6 @@ Http2Session::RecvGoAway(Http2Session *self)
return NS_OK;
}
-PLDHashOperator
-Http2Session::RestartBlockedOnRwinEnumerator(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
-{
- Http2Session *self = static_cast(closure);
- MOZ_ASSERT(self->mServerSessionWindow > 0);
-
- if (!stream->BlockedOnRwin() || stream->ServerReceiveWindow() <= 0)
- return PL_DHASH_NEXT;
-
- self->mReadyForWrite.Push(stream);
- self->SetWriteCallbacks();
- return PL_DHASH_NEXT;
-}
-
nsresult
Http2Session::RecvWindowUpdate(Http2Session *self)
{
@@ -1965,7 +1930,19 @@ Http2Session::RecvWindowUpdate(Http2Session *self)
if ((oldRemoteWindow <= 0) && (self->mServerSessionWindow > 0)) {
LOG3(("Http2Session::RecvWindowUpdate %p restart session window\n",
self));
- self->mStreamTransactionHash.Enumerate(RestartBlockedOnRwinEnumerator, self);
+ for (auto iter = self->mStreamTransactionHash.Iter();
+ !iter.Done();
+ iter.Next()) {
+ MOZ_ASSERT(self->mServerSessionWindow > 0);
+
+ nsAutoPtr& stream = iter.Data();
+ if (!stream->BlockedOnRwin() || stream->ServerReceiveWindow() <= 0) {
+ continue;
+ }
+
+ self->mReadyForWrite.Push(stream);
+ self->SetWriteCallbacks();
+ }
}
LOG3(("Http2Session::RecvWindowUpdate %p session window "
"%d increased by %d now %d.\n", self,
@@ -3027,7 +3004,8 @@ Http2Session::Close(nsresult aReason)
mClosed = true;
- mStreamTransactionHash.Enumerate(ShutdownEnumerator, this);
+ Shutdown();
+
mStreamIDHash.Clear();
mStreamTransactionHash.Clear();
@@ -3708,22 +3686,6 @@ Http2Session::Http1xTransactionCount()
return 0;
}
-// used as an enumerator by TakeSubTransactions()
-static PLDHashOperator
- TakeStream(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
-{
- nsTArray > *list =
- static_cast > *>(closure);
-
- list->AppendElement(key);
-
- // removing the stream from the hash will delete the stream
- // and drop the transaction reference the hash held
- return PL_DHASH_REMOVE;
-}
-
nsresult
Http2Session::TakeSubTransactions(
nsTArray > &outTransactions)
@@ -3738,7 +3700,13 @@ Http2Session::TakeSubTransactions(
LOG3((" taking %d\n", mStreamTransactionHash.Count()));
- mStreamTransactionHash.Enumerate(TakeStream, &outTransactions);
+ for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
+ outTransactions.AppendElement(iter.Key());
+
+ // Removing the stream from the hash will delete the stream and drop the
+ // transaction reference the hash held.
+ iter.Remove();
+ }
return NS_OK;
}
diff --git a/netwerk/protocol/http/Http2Session.h b/netwerk/protocol/http/Http2Session.h
index 9a16ca8a12..5f0b737f7e 100644
--- a/netwerk/protocol/http/Http2Session.h
+++ b/netwerk/protocol/http/Http2Session.h
@@ -295,21 +295,7 @@ private:
// to track network I/O for timeout purposes
nsresult NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t, uint32_t *);
- static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
- nsAutoPtr &,
- void *);
-
- static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
- nsAutoPtr &,
- void *);
-
- static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
- nsAutoPtr &,
- void *);
-
- static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
- nsAutoPtr &,
- void *);
+ void Shutdown();
// This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
// from the first transaction on this session. That object contains the
diff --git a/netwerk/protocol/http/SpdySession31.cpp b/netwerk/protocol/http/SpdySession31.cpp
index 6ef51f6876..816604a867 100644
--- a/netwerk/protocol/http/SpdySession31.cpp
+++ b/netwerk/protocol/http/SpdySession31.cpp
@@ -91,45 +91,25 @@ SpdySession31::SpdySession31(nsISocketTransport *aSocketTransport)
mPingThreshold = gHttpHandler->SpdyPingThreshold();
}
-PLDHashOperator
-SpdySession31::ShutdownEnumerator(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
+void
+SpdySession31::Shutdown()
{
- SpdySession31 *self = static_cast(closure);
+ for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& stream = iter.Data();
- // On a clean server hangup the server sets the GoAwayID to be the ID of
- // the last transaction it processed. If the ID of stream in the
- // local stream is greater than that it can safely be restarted because the
- // server guarantees it was not partially processed. Streams that have not
- // registered an ID haven't actually been sent yet so they can always be
- // restarted.
- if (self->mCleanShutdown &&
- (stream->StreamID() > self->mGoAwayID || !stream->HasRegisteredID()))
- self->CloseStream(stream, NS_ERROR_NET_RESET); // can be restarted
- else
- self->CloseStream(stream, NS_ERROR_ABORT);
-
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-SpdySession31::GoAwayEnumerator(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
-{
- SpdySession31 *self = static_cast(closure);
-
- // these streams were not processed by the server and can be restarted.
- // Do that after the enumerator completes to avoid the risk of
- // a restart event re-entrantly modifying this hash. Be sure not to restart
- // a pushed (even numbered) stream
- if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
- !stream->HasRegisteredID()) {
- self->mGoAwayStreamsToRestart.Push(stream);
+ // On a clean server hangup the server sets the GoAwayID to be the ID of
+ // the last transaction it processed. If the ID of stream in the
+ // local stream is greater than that it can safely be restarted because the
+ // server guarantees it was not partially processed. Streams that have not
+ // registered an ID haven't actually been sent yet so they can always be
+ // restarted.
+ if (mCleanShutdown &&
+ (stream->StreamID() > mGoAwayID || !stream->HasRegisteredID())) {
+ CloseStream(stream, NS_ERROR_NET_RESET); // can be restarted
+ } else {
+ CloseStream(stream, NS_ERROR_ABORT);
+ }
}
-
- return PL_DHASH_NEXT;
}
SpdySession31::~SpdySession31()
@@ -140,7 +120,7 @@ SpdySession31::~SpdySession31()
inflateEnd(&mDownstreamZlib);
deflateEnd(&mUpstreamZlib);
- mStreamTransactionHash.Enumerate(ShutdownEnumerator, this);
+ Shutdown();
}
void
@@ -1370,16 +1350,6 @@ SpdySession31::HandleRstStream(SpdySession31 *self)
return NS_OK;
}
-PLDHashOperator
-SpdySession31::UpdateServerRwinEnumerator(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
-{
- int32_t delta = *(static_cast(closure));
- stream->UpdateRemoteWindow(delta);
- return PL_DHASH_NEXT;
-}
-
nsresult
SpdySession31::HandleSettings(SpdySession31 *self)
{
@@ -1431,8 +1401,11 @@ SpdySession31::HandleSettings(SpdySession31 *self)
// do not use SETTINGS to adjust the session window.
// we need to add the delta to all open streams (delta can be negative)
- self->mStreamTransactionHash.Enumerate(UpdateServerRwinEnumerator,
- &delta);
+ for (auto iter = self->mStreamTransactionHash.Iter();
+ !iter.Done();
+ iter.Next()) {
+ iter.Data()->UpdateRemoteWindow(delta);
+ }
}
break;
@@ -1506,9 +1479,22 @@ SpdySession31::HandleGoAway(SpdySession31 *self)
self->mCleanShutdown = true;
// Find streams greater than the last-good ID and mark them for deletion
- // in the mGoAwayStreamsToRestart queue with the GoAwayEnumerator. The
- // underlying transaction can be restarted.
- self->mStreamTransactionHash.Enumerate(GoAwayEnumerator, self);
+ // in the mGoAwayStreamsToRestart queue. The underlying transaction can be
+ // restarted.
+ for (auto iter = self->mStreamTransactionHash.Iter();
+ !iter.Done();
+ iter.Next()) {
+
+ // These streams were not processed by the server and can be restarted. Do
+ // that after the enumerator completes to avoid the risk of a restart event
+ // re-entrantly modifying this hash. Be sure not to restart a pushed (even
+ // numbered) stream.
+ nsAutoPtr& stream = iter.Data();
+ if ((stream->StreamID() > self->mGoAwayID && (stream->StreamID() & 1)) ||
+ !stream->HasRegisteredID()) {
+ self->mGoAwayStreamsToRestart.Push(stream);
+ }
+ }
// Process the streams marked for deletion and restart.
size_t size = self->mGoAwayStreamsToRestart.GetSize();
@@ -1622,22 +1608,6 @@ SpdySession31::HandleHeaders(SpdySession31 *self)
return rv;
}
-PLDHashOperator
-SpdySession31::RestartBlockedOnRwinEnumerator(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
-{
- SpdySession31 *self = static_cast(closure);
- MOZ_ASSERT(self->mRemoteSessionWindow > 0);
-
- if (!stream->BlockedOnRwin() || stream->RemoteWindow() <= 0)
- return PL_DHASH_NEXT;
-
- self->mReadyForWrite.Push(stream);
- self->SetWriteCallbacks();
- return PL_DHASH_NEXT;
-}
-
nsresult
SpdySession31::HandleWindowUpdate(SpdySession31 *self)
{
@@ -1681,7 +1651,19 @@ SpdySession31::HandleWindowUpdate(SpdySession31 *self)
if ((oldRemoteWindow <= 0) && (self->mRemoteSessionWindow > 0)) {
LOG3(("SpdySession31::HandleWindowUpdate %p restart session window\n",
self));
- self->mStreamTransactionHash.Enumerate(RestartBlockedOnRwinEnumerator, self);
+ for (auto iter = self->mStreamTransactionHash.Iter();
+ !iter.Done();
+ iter.Next()) {
+ MOZ_ASSERT(self->mRemoteSessionWindow > 0);
+
+ nsAutoPtr& stream = iter.Data();
+ if (!stream->BlockedOnRwin() || stream->RemoteWindow() <= 0) {
+ continue;
+ }
+
+ self->mReadyForWrite.Push(stream);
+ self->SetWriteCallbacks();
+ }
}
}
@@ -2366,7 +2348,8 @@ SpdySession31::Close(nsresult aReason)
mClosed = true;
- mStreamTransactionHash.Enumerate(ShutdownEnumerator, this);
+ Shutdown();
+
mStreamIDHash.Clear();
mStreamTransactionHash.Clear();
@@ -2908,22 +2891,6 @@ SpdySession31::Http1xTransactionCount()
return 0;
}
-// used as an enumerator by TakeSubTransactions()
-static PLDHashOperator
- TakeStream(nsAHttpTransaction *key,
- nsAutoPtr &stream,
- void *closure)
-{
- nsTArray > *list =
- static_cast > *>(closure);
-
- list->AppendElement(key);
-
- // removing the stream from the hash will delete the stream
- // and drop the transaction reference the hash held
- return PL_DHASH_REMOVE;
-}
-
nsresult
SpdySession31::TakeSubTransactions(
nsTArray > &outTransactions)
@@ -2938,7 +2905,13 @@ SpdySession31::TakeSubTransactions(
LOG3((" taking %d\n", mStreamTransactionHash.Count()));
- mStreamTransactionHash.Enumerate(TakeStream, &outTransactions);
+ for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
+ outTransactions.AppendElement(iter.Key());
+
+ // Removing the stream from the hash will delete the stream and drop the
+ // transaction reference the hash held.
+ iter.Remove();
+ }
return NS_OK;
}
diff --git a/netwerk/protocol/http/SpdySession31.h b/netwerk/protocol/http/SpdySession31.h
index 83aa8a8214..c4d2a932b0 100644
--- a/netwerk/protocol/http/SpdySession31.h
+++ b/netwerk/protocol/http/SpdySession31.h
@@ -243,21 +243,7 @@ private:
// to track network I/O for timeout purposes
nsresult NetworkRead(nsAHttpSegmentWriter *, char *, uint32_t, uint32_t *);
- static PLDHashOperator ShutdownEnumerator(nsAHttpTransaction *,
- nsAutoPtr &,
- void *);
-
- static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
- nsAutoPtr &,
- void *);
-
- static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
- nsAutoPtr &,
- void *);
-
- static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
- nsAutoPtr &,
- void *);
+ void Shutdown();
// This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
// from the first transaction on this session. That object contains the
diff --git a/netwerk/protocol/http/SpdyStream31.cpp b/netwerk/protocol/http/SpdyStream31.cpp
index 4036c1348a..d5d40da54e 100644
--- a/netwerk/protocol/http/SpdyStream31.cpp
+++ b/netwerk/protocol/http/SpdyStream31.cpp
@@ -228,18 +228,6 @@ SpdyStream31::WriteSegments(nsAHttpSegmentWriter *writer,
return rv;
}
-PLDHashOperator
-SpdyStream31::hdrHashEnumerate(const nsACString &key,
- nsAutoPtr &value,
- void *closure)
-{
- SpdyStream31 *self = static_cast(closure);
-
- self->CompressToFrame(key);
- self->CompressToFrame(value.get());
- return PL_DHASH_NEXT;
-}
-
void
SpdyStream31::CreatePushHashKey(const nsCString &scheme,
const nsCString &hostHeader,
@@ -535,7 +523,10 @@ SpdyStream31::GenerateSynFrame()
CompressToFrame(nsDependentCString(mTransaction->RequestHead()->IsHTTPS() ? "https" : "http"));
}
- hdrHash.Enumerate(hdrHashEnumerate, this);
+ for (auto iter = hdrHash.Iter(); !iter.Done(); iter.Next()) {
+ CompressToFrame(iter.Key());
+ CompressToFrame(iter.Data().get());
+ }
CompressFlushFrame();
// 4 to 7 are length and flags, which we can now fill in
diff --git a/netwerk/protocol/http/SpdyStream31.h b/netwerk/protocol/http/SpdyStream31.h
index 93cc2408b0..6408c5cf14 100644
--- a/netwerk/protocol/http/SpdyStream31.h
+++ b/netwerk/protocol/http/SpdyStream31.h
@@ -144,10 +144,6 @@ protected:
private:
friend class nsAutoPtr;
- static PLDHashOperator hdrHashEnumerate(const nsACString &,
- nsAutoPtr &,
- void *);
-
nsresult ParseHttpRequestHeaders(const char *, uint32_t, uint32_t *);
nsresult GenerateSynFrame();
diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp
index 9b0d2cb6f6..f83379634f 100644
--- a/netwerk/protocol/http/nsCORSListenerProxy.cpp
+++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp
@@ -183,10 +183,6 @@ public:
void Clear();
private:
- static PLDHashOperator
- RemoveExpiredEntries(const nsACString& aKey, nsAutoPtr& aValue,
- void* aUserData);
-
static bool GetCacheKey(nsIURI* aURI, nsIPrincipal* aPrincipal,
bool aWithCredentials, nsACString& _retval);
@@ -304,7 +300,17 @@ nsPreflightCache::GetEntry(nsIURI* aURI,
if (mTable.Count() == PREFLIGHT_CACHE_SIZE) {
// Try to kick out all the expired entries.
TimeStamp now = TimeStamp::NowLoRes();
- mTable.Enumerate(RemoveExpiredEntries, &now);
+ for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& entry = iter.Data();
+ entry->PurgeExpired(now);
+
+ if (entry->mHeaders.IsEmpty() &&
+ entry->mMethods.IsEmpty()) {
+ // Expired, remove from the list as well as the hash table.
+ entry->removeFrom(sPreflightCache->mList);
+ iter.Remove();
+ }
+ }
// If that didn't remove anything then kick out the least recently used
// entry.
@@ -351,25 +357,6 @@ nsPreflightCache::Clear()
mTable.Clear();
}
-/* static */ PLDHashOperator
-nsPreflightCache::RemoveExpiredEntries(const nsACString& aKey,
- nsAutoPtr& aValue,
- void* aUserData)
-{
- TimeStamp* now = static_cast(aUserData);
-
- aValue->PurgeExpired(*now);
-
- if (aValue->mHeaders.IsEmpty() &&
- aValue->mMethods.IsEmpty()) {
- // Expired, remove from the list as well as the hash table.
- aValue->removeFrom(sPreflightCache->mList);
- return PL_DHASH_REMOVE;
- }
-
- return PL_DHASH_NEXT;
-}
-
/* static */ bool
nsPreflightCache::GetCacheKey(nsIURI* aURI,
nsIPrincipal* aPrincipal,
diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp
index 48b9d50448..858a96a024 100644
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -651,7 +651,7 @@ nsHttpConnection::AddTransaction(nsAHttpTransaction *httpTransaction,
}
void
-nsHttpConnection::Close(nsresult reason)
+nsHttpConnection::Close(nsresult reason, bool aIsShutdown)
{
LOG(("nsHttpConnection::Close [this=%p reason=%x]\n", this, reason));
@@ -685,7 +685,8 @@ nsHttpConnection::Close(nsresult reason)
// socket with data pending. TLS is a classic case of this where
// a Alert record might be superfulous to a clean HTTP/SPDY shutdown.
// Never block to do this and limit it to a small amount of data.
- if (mSocketIn) {
+ // During shutdown just be fast!
+ if (mSocketIn && !aIsShutdown) {
char buffer[4000];
uint32_t count, total = 0;
nsresult rv;
diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h
index b213733610..809b19bc7c 100644
--- a/netwerk/protocol/http/nsHttpConnection.h
+++ b/netwerk/protocol/http/nsHttpConnection.h
@@ -77,7 +77,7 @@ public:
nsresult Activate(nsAHttpTransaction *, uint32_t caps, int32_t pri);
// Close the underlying socket transport.
- void Close(nsresult reason);
+ void Close(nsresult reason, bool aIsShutdown = false);
//-------------------------------------------------------------------------
// XXX document when these are ok to call
diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
index 002315c477..0ff4e51793 100644
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -532,25 +532,21 @@ nsHttpConnectionMgr::UpdateRequestTokenBucket(EventTokenBucket *aBucket)
0, aBucket);
}
-PLDHashOperator
-nsHttpConnectionMgr::RemoveDeadConnections(const nsACString &key,
- nsAutoPtr &ent,
- void *aArg)
-{
- if (ent->mIdleConns.Length() == 0 &&
- ent->mActiveConns.Length() == 0 &&
- ent->mHalfOpens.Length() == 0 &&
- ent->mPendingQ.Length() == 0) {
- return PL_DHASH_REMOVE;
- }
- return PL_DHASH_NEXT;
-}
-
nsresult
nsHttpConnectionMgr::ClearConnectionHistory()
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- mCT.Enumerate(RemoveDeadConnections, nullptr);
+
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& ent = iter.Data();
+ if (ent->mIdleConns.Length() == 0 &&
+ ent->mActiveConns.Length() == 0 &&
+ ent->mHalfOpens.Length() == 0 &&
+ ent->mPendingQ.Length() == 0) {
+ iter.Remove();
+ }
+ }
+
return NS_OK;
}
@@ -830,266 +826,6 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry)
return preferred;
}
-//-----------------------------------------------------------------------------
-// enumeration callbacks
-
-PLDHashOperator
-nsHttpConnectionMgr::ProcessOneTransactionCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
-
- if (self->ProcessPendingQForEntry(ent, false))
- return PL_DHASH_STOP;
-
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsHttpConnectionMgr::ProcessAllTransactionsCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
- self->ProcessPendingQForEntry(ent, true);
- return PL_DHASH_NEXT;
-}
-
-// If the global number of connections is preventing the opening of
-// new connections to a host without idle connections, then
-// close them regardless of their TTL
-PLDHashOperator
-nsHttpConnectionMgr::PurgeExcessIdleConnectionsCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
-
- while (self->mNumIdleConns + self->mNumActiveConns + 1 >= self->mMaxConns) {
- if (!ent->mIdleConns.Length()) {
- // There are no idle conns left in this connection entry
- return PL_DHASH_NEXT;
- }
- nsHttpConnection *conn = ent->mIdleConns[0];
- ent->mIdleConns.RemoveElementAt(0);
- conn->Close(NS_ERROR_ABORT);
- NS_RELEASE(conn);
- self->mNumIdleConns--;
- self->ConditionallyStopPruneDeadConnectionsTimer();
- }
- return PL_DHASH_STOP;
-}
-
-// If the global number of connections is preventing the opening of
-// new connections to a host without idle connections, then
-// close any spdy asap
-PLDHashOperator
-nsHttpConnectionMgr::PurgeExcessSpdyConnectionsCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- if (!ent->mUsingSpdy)
- return PL_DHASH_NEXT;
-
- nsHttpConnectionMgr *self = static_cast(closure);
- for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
- nsHttpConnection *conn = ent->mActiveConns[index];
- if (conn->UsingSpdy() && conn->CanReuse()) {
- conn->DontReuse();
- // stop on <= (particularly =) beacuse this dontreuse causes async close
- if (self->mNumIdleConns + self->mNumActiveConns + 1 <= self->mMaxConns)
- return PL_DHASH_STOP;
- }
- }
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsHttpConnectionMgr::PruneDeadConnectionsCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
- nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
-
- LOG((" pruning [ci=%s]\n", ent->mConnInfo->HashKey().get()));
-
- // Find out how long it will take for next idle connection to not be reusable
- // anymore.
- uint32_t timeToNextExpire = UINT32_MAX;
- int32_t count = ent->mIdleConns.Length();
- if (count > 0) {
- for (int32_t i=count-1; i>=0; --i) {
- nsHttpConnection *conn = ent->mIdleConns[i];
- if (!conn->CanReuse()) {
- ent->mIdleConns.RemoveElementAt(i);
- conn->Close(NS_ERROR_ABORT);
- NS_RELEASE(conn);
- self->mNumIdleConns--;
- } else {
- timeToNextExpire = std::min(timeToNextExpire, conn->TimeToLive());
- }
- }
- }
-
- if (ent->mUsingSpdy) {
- for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
- nsHttpConnection *conn = ent->mActiveConns[index];
- if (conn->UsingSpdy()) {
- if (!conn->CanReuse()) {
- // marking it dont reuse will create an active tear down if
- // the spdy session is idle.
- conn->DontReuse();
- }
- else {
- timeToNextExpire = std::min(timeToNextExpire,
- conn->TimeToLive());
- }
- }
- }
- }
-
- // If time to next expire found is shorter than time to next wake-up, we need to
- // change the time for next wake-up.
- if (timeToNextExpire != UINT32_MAX) {
- uint32_t now = NowInSeconds();
- uint64_t timeOfNextExpire = now + timeToNextExpire;
- // If pruning of dead connections is not already scheduled to happen
- // or time found for next connection to expire is is before
- // mTimeOfNextWakeUp, we need to schedule the pruning to happen
- // after timeToNextExpire.
- if (!self->mTimer || timeOfNextExpire < self->mTimeOfNextWakeUp) {
- self->PruneDeadConnectionsAfter(timeToNextExpire);
- }
- } else {
- self->ConditionallyStopPruneDeadConnectionsTimer();
- }
-
- // if this entry is empty, we have too many entries,
- // and this doesn't represent some painfully determined
- // red condition, then we can clean it up and restart from
- // yellow
- if (ent->PipelineState() != PS_RED &&
- self->mCT.Count() > 125 &&
- ent->mIdleConns.Length() == 0 &&
- ent->mActiveConns.Length() == 0 &&
- ent->mHalfOpens.Length() == 0 &&
- ent->mPendingQ.Length() == 0 &&
- ((!ent->mTestedSpdy && !ent->mUsingSpdy) ||
- !gHttpHandler->IsSpdyEnabled() ||
- self->mCT.Count() > 300)) {
- LOG((" removing empty connection entry\n"));
- return PL_DHASH_REMOVE;
- }
-
- // otherwise use this opportunity to compact our arrays...
- ent->mIdleConns.Compact();
- ent->mActiveConns.Compact();
- ent->mPendingQ.Compact();
-
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsHttpConnectionMgr::VerifyTrafficCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- // Iterate over all active connections and check them
- for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
- nsHttpConnection *conn = ent->mActiveConns[index];
- conn->CheckForTraffic(true);
- }
- // Iterate the idle connections and unmark them for traffic checks
- for (uint32_t index = 0; index < ent->mIdleConns.Length(); ++index) {
- nsHttpConnection *conn = ent->mIdleConns[index];
- conn->CheckForTraffic(false);
- }
-
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsHttpConnectionMgr::PruneNoTrafficCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- // Close the connections with no registered traffic
- nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
-
- LOG((" pruning no traffic [ci=%s]\n", ent->mConnInfo->HashKey().get()));
-
- uint32_t numConns = ent->mActiveConns.Length();
- if (numConns) {
- // walk the list backwards to allow us to remove entries easily
- for (int index = numConns-1; index >= 0; index--) {
- if (ent->mActiveConns[index]->NoTraffic()) {
- RefPtr conn = dont_AddRef(ent->mActiveConns[index]);
- ent->mActiveConns.RemoveElementAt(index);
- self->DecrementActiveConnCount(conn);
- conn->Close(NS_ERROR_ABORT);
- LOG((" closed active connection due to no traffic [conn=%p]\n",
- conn.get()));
- }
- }
- }
-
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsHttpConnectionMgr::ShutdownPassCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
-
- nsHttpTransaction *trans;
- nsHttpConnection *conn;
-
- // close all active connections
- while (ent->mActiveConns.Length()) {
- conn = ent->mActiveConns[0];
-
- ent->mActiveConns.RemoveElementAt(0);
- self->DecrementActiveConnCount(conn);
-
- conn->Close(NS_ERROR_ABORT);
- NS_RELEASE(conn);
- }
-
- // close all idle connections
- while (ent->mIdleConns.Length()) {
- conn = ent->mIdleConns[0];
-
- ent->mIdleConns.RemoveElementAt(0);
- self->mNumIdleConns--;
-
- conn->Close(NS_ERROR_ABORT);
- NS_RELEASE(conn);
- }
- // If all idle connections are removed,
- // we can stop pruning dead connections.
- self->ConditionallyStopPruneDeadConnectionsTimer();
-
- // close all pending transactions
- while (ent->mPendingQ.Length()) {
- trans = ent->mPendingQ[0];
-
- ent->mPendingQ.RemoveElementAt(0);
-
- trans->Close(NS_ERROR_ABORT);
- NS_RELEASE(trans);
- }
-
- // close all half open tcp connections
- for (int32_t i = ((int32_t) ent->mHalfOpens.Length()) - 1; i >= 0; i--)
- ent->mHalfOpens[i]->Abandon();
-
- return PL_DHASH_REMOVE;
-}
-
//-----------------------------------------------------------------------------
bool
@@ -1342,16 +1078,6 @@ nsHttpConnectionMgr::ClosePersistentConnections(nsConnectionEntry *ent)
ent->mActiveConns[i]->DontReuse();
}
-PLDHashOperator
-nsHttpConnectionMgr::ClosePersistentConnectionsCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- nsHttpConnectionMgr *self = static_cast(closure);
- self->ClosePersistentConnections(ent);
- return PL_DHASH_NEXT;
-}
-
bool
nsHttpConnectionMgr::RestrictConnections(nsConnectionEntry *ent,
bool ignorePossibleSpdyConnections)
@@ -1470,12 +1196,56 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
// beacuse we have already determined there are no idle connections
// to our destination
- if ((mNumIdleConns + mNumActiveConns + 1 >= mMaxConns) && mNumIdleConns)
- mCT.Enumerate(PurgeExcessIdleConnectionsCB, this);
+ if ((mNumIdleConns + mNumActiveConns + 1 >= mMaxConns) && mNumIdleConns) {
+ // If the global number of connections is preventing the opening of new
+ // connections to a host without idle connections, then close them
+ // regardless of their TTL.
+ auto iter = mCT.Iter();
+ while (mNumIdleConns + mNumActiveConns + 1 >= mMaxConns &&
+ !iter.Done()) {
+ nsAutoPtr &ent = iter.Data();
+ if (!ent->mIdleConns.Length()) {
+ iter.Next();
+ continue;
+ }
+ nsHttpConnection *conn = ent->mIdleConns[0];
+ ent->mIdleConns.RemoveElementAt(0);
+ conn->Close(NS_ERROR_ABORT);
+ NS_RELEASE(conn);
+ mNumIdleConns--;
+ ConditionallyStopPruneDeadConnectionsTimer();
+ }
+ }
if ((mNumIdleConns + mNumActiveConns + 1 >= mMaxConns) &&
mNumActiveConns && gHttpHandler->IsSpdyEnabled())
- mCT.Enumerate(PurgeExcessSpdyConnectionsCB, this);
+ {
+ // If the global number of connections is preventing the opening of new
+ // connections to a host without idle connections, then close any spdy
+ // ASAP.
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr &ent = iter.Data();
+ if (!ent->mUsingSpdy) {
+ continue;
+ }
+
+ for (uint32_t index = 0;
+ index < ent->mActiveConns.Length();
+ ++index) {
+ nsHttpConnection *conn = ent->mActiveConns[index];
+ if (conn->UsingSpdy() && conn->CanReuse()) {
+ conn->DontReuse();
+ // Stop on <= (particularly =) because this dontreuse
+ // causes async close.
+ if (mNumIdleConns + mNumActiveConns + 1 <= mMaxConns) {
+ goto outerLoopEnd;
+ }
+ }
+ }
+ }
+ outerLoopEnd:
+ ;
+ }
if (AtActiveConnectionLimit(ent, trans->Caps()))
return NS_ERROR_NOT_AVAILABLE;
@@ -2220,22 +1990,14 @@ nsHttpConnectionMgr::ProcessSpdyPendingQ(nsConnectionEntry *ent)
leftovers.Clear();
}
-PLDHashOperator
-nsHttpConnectionMgr::ProcessSpdyPendingQCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
- self->ProcessSpdyPendingQ(ent);
- return PL_DHASH_NEXT;
-}
-
void
nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ(int32_t, ARefBase *)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ\n"));
- mCT.Enumerate(ProcessSpdyPendingQCB, this);
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ ProcessSpdyPendingQ(iter.Data());
+ }
}
nsHttpConnection *
@@ -2277,7 +2039,54 @@ nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgShutdown\n"));
- mCT.Enumerate(ShutdownPassCB, this);
+ gHttpHandler->StopRequestTokenBucket();
+
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& ent = iter.Data();
+
+ // Close all active connections.
+ while (ent->mActiveConns.Length()) {
+ nsHttpConnection* conn = ent->mActiveConns[0];
+
+ ent->mActiveConns.RemoveElementAt(0);
+ DecrementActiveConnCount(conn);
+
+ conn->Close(NS_ERROR_ABORT, true);
+ NS_RELEASE(conn);
+ }
+
+ // Close all idle connections.
+ while (ent->mIdleConns.Length()) {
+ nsHttpConnection* conn = ent->mIdleConns[0];
+
+ ent->mIdleConns.RemoveElementAt(0);
+ mNumIdleConns--;
+
+ conn->Close(NS_ERROR_ABORT);
+ NS_RELEASE(conn);
+ }
+
+ // If all idle connections are removed we can stop pruning dead
+ // connections.
+ ConditionallyStopPruneDeadConnectionsTimer();
+
+ // Close all pending transactions.
+ while (ent->mPendingQ.Length()) {
+ nsHttpTransaction* trans = ent->mPendingQ[0];
+
+ ent->mPendingQ.RemoveElementAt(0);
+
+ trans->Close(NS_ERROR_ABORT);
+ NS_RELEASE(trans);
+ }
+
+ // Close all half open tcp connections.
+ for (int32_t i = int32_t(ent->mHalfOpens.Length()) - 1; i >= 0; i--) {
+ ent->mHalfOpens[i]->Abandon();
+ }
+
+ iter.Remove();
+ }
if (mTimeoutTick) {
mTimeoutTick->Cancel();
@@ -2419,7 +2228,9 @@ nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, ARefBase *param)
if (!ci) {
LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=nullptr]\n"));
// Try and dispatch everything
- mCT.Enumerate(ProcessAllTransactionsCB, this);
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ ProcessPendingQForEntry(iter.Data(), true);
+ }
return;
}
@@ -2431,7 +2242,11 @@ nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, ARefBase *param)
if (!(ent && ProcessPendingQForEntry(ent, false))) {
// if we reach here, it means that we couldn't dispatch a transaction
// for the specified connection info. walk the connection table...
- mCT.Enumerate(ProcessOneTransactionCB, this);
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ if (ProcessPendingQForEntry(iter.Data(), false)) {
+ break;
+ }
+ }
}
}
@@ -2478,8 +2293,86 @@ nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, ARefBase *)
// check canreuse() for all idle connections plus any active connections on
// connection entries that are using spdy.
- if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled()))
- mCT.Enumerate(PruneDeadConnectionsCB, this);
+ if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled())) {
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& ent = iter.Data();
+
+ LOG((" pruning [ci=%s]\n", ent->mConnInfo->HashKey().get()));
+
+ // Find out how long it will take for next idle connection to not
+ // be reusable anymore.
+ uint32_t timeToNextExpire = UINT32_MAX;
+ int32_t count = ent->mIdleConns.Length();
+ if (count > 0) {
+ for (int32_t i = count - 1; i >= 0; --i) {
+ nsHttpConnection* conn = ent->mIdleConns[i];
+ if (!conn->CanReuse()) {
+ ent->mIdleConns.RemoveElementAt(i);
+ conn->Close(NS_ERROR_ABORT);
+ NS_RELEASE(conn);
+ mNumIdleConns--;
+ } else {
+ timeToNextExpire =
+ std::min(timeToNextExpire, conn->TimeToLive());
+ }
+ }
+ }
+
+ if (ent->mUsingSpdy) {
+ for (uint32_t i = 0; i < ent->mActiveConns.Length(); ++i) {
+ nsHttpConnection* conn = ent->mActiveConns[i];
+ if (conn->UsingSpdy()) {
+ if (!conn->CanReuse()) {
+ // Marking it don't-reuse will create an active
+ // tear down if the spdy session is idle.
+ conn->DontReuse();
+ } else {
+ timeToNextExpire =
+ std::min(timeToNextExpire, conn->TimeToLive());
+ }
+ }
+ }
+ }
+
+ // If time to next expire found is shorter than time to next
+ // wake-up, we need to change the time for next wake-up.
+ if (timeToNextExpire != UINT32_MAX) {
+ uint32_t now = NowInSeconds();
+ uint64_t timeOfNextExpire = now + timeToNextExpire;
+ // If pruning of dead connections is not already scheduled to
+ // happen or time found for next connection to expire is is
+ // before mTimeOfNextWakeUp, we need to schedule the pruning to
+ // happen after timeToNextExpire.
+ if (!mTimer || timeOfNextExpire < mTimeOfNextWakeUp) {
+ PruneDeadConnectionsAfter(timeToNextExpire);
+ }
+ } else {
+ ConditionallyStopPruneDeadConnectionsTimer();
+ }
+
+ // If this entry is empty, we have too many entries, and this
+ // doesn't represent some painfully determined red condition, then
+ // we can clean it up and restart from yellow.
+ if (ent->PipelineState() != PS_RED &&
+ mCT.Count() > 125 &&
+ ent->mIdleConns.Length() == 0 &&
+ ent->mActiveConns.Length() == 0 &&
+ ent->mHalfOpens.Length() == 0 &&
+ ent->mPendingQ.Length() == 0 &&
+ ((!ent->mTestedSpdy && !ent->mUsingSpdy) ||
+ !gHttpHandler->IsSpdyEnabled() ||
+ mCT.Count() > 300)) {
+ LOG((" removing empty connection entry\n"));
+ iter.Remove();
+ continue;
+ }
+
+ // Otherwise use this opportunity to compact our arrays...
+ ent->mIdleConns.Compact();
+ ent->mActiveConns.Compact();
+ ent->mPendingQ.Compact();
+ }
+ }
}
void
@@ -2489,7 +2382,30 @@ nsHttpConnectionMgr::OnMsgPruneNoTraffic(int32_t, ARefBase *)
LOG(("nsHttpConnectionMgr::OnMsgPruneNoTraffic\n"));
// Prune connections without traffic
- mCT.Enumerate(PruneNoTrafficCB, this);
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+
+ // Close the connections with no registered traffic.
+ nsAutoPtr& ent = iter.Data();
+
+ LOG((" pruning no traffic [ci=%s]\n",
+ ent->mConnInfo->HashKey().get()));
+
+ uint32_t numConns = ent->mActiveConns.Length();
+ if (numConns) {
+ // Walk the list backwards to allow us to remove entries easily.
+ for (int index = numConns - 1; index >= 0; index--) {
+ if (ent->mActiveConns[index]->NoTraffic()) {
+ RefPtr conn =
+ dont_AddRef(ent->mActiveConns[index]);
+ ent->mActiveConns.RemoveElementAt(index);
+ DecrementActiveConnCount(conn);
+ conn->Close(NS_ERROR_ABORT);
+ LOG((" closed active connection due to no traffic "
+ "[conn=%p]\n", conn.get()));
+ }
+ }
+ }
+ }
mPruningNoTraffic = false; // not pruning anymore
}
@@ -2507,7 +2423,18 @@ nsHttpConnectionMgr::OnMsgVerifyTraffic(int32_t, ARefBase *)
}
// Mark connections for traffic verification
- mCT.Enumerate(VerifyTrafficCB, this);
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& ent = iter.Data();
+
+ // Iterate over all active connections and check them.
+ for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
+ ent->mActiveConns[index]->CheckForTraffic(true);
+ }
+ // Iterate the idle connections and unmark them for traffic checks.
+ for (uint32_t index = 0; index < ent->mIdleConns.Length(); ++index) {
+ ent->mIdleConns[index]->CheckForTraffic(false);
+ }
+ }
// If the timer is already there. we just re-init it
if(!mTrafficTimer) {
@@ -2534,7 +2461,10 @@ nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup(int32_t, ARefBase *para
nsHttpConnectionInfo *ci = static_cast(param);
- mCT.Enumerate(ClosePersistentConnectionsCB, this);
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ ClosePersistentConnections(iter.Data());
+ }
+
if (ci)
ResetIPFamilyPreference(ci);
}
@@ -2752,69 +2682,67 @@ nsHttpConnectionMgr::TimeoutTick()
// Set it to the max value here, and the TimeoutTickCB()s can
// reduce it to their local needs.
mTimeoutTickNext = 3600; // 1hr
- mCT.Enumerate(TimeoutTickCB, this);
+
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& ent = iter.Data();
+
+ LOG(("nsHttpConnectionMgr::TimeoutTickCB() this=%p host=%s "
+ "idle=%d active=%d half-len=%d pending=%d\n",
+ this, ent->mConnInfo->Origin(), ent->mIdleConns.Length(),
+ ent->mActiveConns.Length(), ent->mHalfOpens.Length(),
+ ent->mPendingQ.Length()));
+
+ // First call the tick handler for each active connection.
+ PRIntervalTime now = PR_IntervalNow();
+ for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
+ uint32_t connNextTimeout =
+ ent->mActiveConns[index]->ReadTimeoutTick(now);
+ mTimeoutTickNext = std::min(mTimeoutTickNext, connNextTimeout);
+ }
+
+ // Now check for any stalled half open sockets.
+ if (ent->mHalfOpens.Length()) {
+ TimeStamp now = TimeStamp::Now();
+ double maxConnectTime_ms = gHttpHandler->ConnectTimeout();
+
+ for (uint32_t index = ent->mHalfOpens.Length(); index > 0; ) {
+ index--;
+
+ nsHalfOpenSocket *half = ent->mHalfOpens[index];
+ double delta = half->Duration(now);
+ // If the socket has timed out, close it so the waiting
+ // transaction will get the proper signal.
+ if (delta > maxConnectTime_ms) {
+ LOG(("Force timeout of half open to %s after %.2fms.\n",
+ ent->mConnInfo->HashKey().get(), delta));
+ if (half->SocketTransport()) {
+ half->SocketTransport()->Close(NS_ERROR_ABORT);
+ }
+ if (half->BackupTransport()) {
+ half->BackupTransport()->Close(NS_ERROR_ABORT);
+ }
+ }
+
+ // If this half open hangs around for 5 seconds after we've
+ // closed() it then just abandon the socket.
+ if (delta > maxConnectTime_ms + 5000) {
+ LOG(("Abandon half open to %s after %.2fms.\n",
+ ent->mConnInfo->HashKey().get(), delta));
+ half->Abandon();
+ }
+ }
+ }
+ if (ent->mHalfOpens.Length()) {
+ mTimeoutTickNext = 1;
+ }
+ }
+
if (mTimeoutTick) {
mTimeoutTickNext = std::max(mTimeoutTickNext, 1U);
mTimeoutTick->SetDelay(mTimeoutTickNext * 1000);
}
}
-PLDHashOperator
-nsHttpConnectionMgr::TimeoutTickCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure)
-{
- nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
-
- LOG(("nsHttpConnectionMgr::TimeoutTickCB() this=%p host=%s "
- "idle=%d active=%d half-len=%d pending=%d\n",
- self, ent->mConnInfo->Origin(), ent->mIdleConns.Length(),
- ent->mActiveConns.Length(), ent->mHalfOpens.Length(),
- ent->mPendingQ.Length()));
-
- // first call the tick handler for each active connection
- PRIntervalTime now = PR_IntervalNow();
- for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
- uint32_t connNextTimeout = ent->mActiveConns[index]->ReadTimeoutTick(now);
- self->mTimeoutTickNext = std::min(self->mTimeoutTickNext, connNextTimeout);
- }
-
- // now check for any stalled half open sockets
- if (ent->mHalfOpens.Length()) {
- TimeStamp now = TimeStamp::Now();
- double maxConnectTime = gHttpHandler->ConnectTimeout(); /* in milliseconds */
-
- for (uint32_t index = ent->mHalfOpens.Length(); index > 0; ) {
- index--;
-
- nsHalfOpenSocket *half = ent->mHalfOpens[index];
- double delta = half->Duration(now);
- // If the socket has timed out, close it so the waiting transaction
- // will get the proper signal
- if (delta > maxConnectTime) {
- LOG(("Force timeout of half open to %s after %.2fms.\n",
- ent->mConnInfo->HashKey().get(), delta));
- if (half->SocketTransport())
- half->SocketTransport()->Close(NS_ERROR_NET_TIMEOUT);
- if (half->BackupTransport())
- half->BackupTransport()->Close(NS_ERROR_NET_TIMEOUT);
- }
-
- // If this half open hangs around for 5 seconds after we've closed() it
- // then just abandon the socket.
- if (delta > maxConnectTime + 5000) {
- LOG(("Abandon half open to %s after %.2fms.\n",
- ent->mConnInfo->HashKey().get(), delta));
- half->Abandon();
- }
- }
- }
- if (ent->mHalfOpens.Length()) {
- self->mTimeoutTickNext = 1;
- }
- return PL_DHASH_NEXT;
-}
-
// GetOrCreateConnectionEntry finds a ent for a particular CI for use in
// dispatching a transaction according to these rules
// 1] use an ent that matches the ci that can be dispatched immediately
@@ -2996,6 +2924,8 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
nsIAsyncOutputStream **outstream,
bool isBackup)
{
+ MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
+
nsresult rv;
const char *socketTypes[1];
uint32_t typeCount = 0;
@@ -3099,6 +3029,8 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
rv = socketTransport->SetSecurityCallbacks(this);
NS_ENSURE_SUCCESS(rv, rv);
+ mEnt->mUsedForConnection = true;
+
nsCOMPtr sout;
rv = socketTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED,
0, 0,
@@ -3557,6 +3489,7 @@ nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci)
, mInPreferredHash(false)
, mPreferIPv4(false)
, mPreferIPv6(false)
+ , mUsedForConnection(false)
{
MOZ_COUNT_CTOR(nsConnectionEntry);
if (gHttpHandler->GetPipelineAggressive()) {
@@ -3810,51 +3743,50 @@ nsConnectionEntry::MaxPipelineDepth(nsAHttpTransaction::Classifier aClass)
return mGreenDepth;
}
-PLDHashOperator
-nsHttpConnectionMgr::ReadConnectionEntry(const nsACString &key,
- nsAutoPtr &ent,
- void *aArg)
-{
- if (ent->mConnInfo->GetPrivate())
- return PL_DHASH_NEXT;
-
- nsTArray *args = static_cast *> (aArg);
- HttpRetParams data;
- data.host = ent->mConnInfo->Origin();
- data.port = ent->mConnInfo->OriginPort();
- for (uint32_t i = 0; i < ent->mActiveConns.Length(); i++) {
- HttpConnInfo info;
- info.ttl = ent->mActiveConns[i]->TimeToLive();
- info.rtt = ent->mActiveConns[i]->Rtt();
- if (ent->mActiveConns[i]->UsingSpdy())
- info.SetHTTP2ProtocolVersion(ent->mActiveConns[i]->GetSpdyVersion());
- else
- info.SetHTTP1ProtocolVersion(ent->mActiveConns[i]->GetLastHttpResponseVersion());
-
- data.active.AppendElement(info);
- }
- for (uint32_t i = 0; i < ent->mIdleConns.Length(); i++) {
- HttpConnInfo info;
- info.ttl = ent->mIdleConns[i]->TimeToLive();
- info.rtt = ent->mIdleConns[i]->Rtt();
- info.SetHTTP1ProtocolVersion(ent->mIdleConns[i]->GetLastHttpResponseVersion());
- data.idle.AppendElement(info);
- }
- for(uint32_t i = 0; i < ent->mHalfOpens.Length(); i++) {
- HalfOpenSockets hSocket;
- hSocket.speculative = ent->mHalfOpens[i]->IsSpeculative();
- data.halfOpens.AppendElement(hSocket);
- }
- data.spdy = ent->mUsingSpdy;
- data.ssl = ent->mConnInfo->EndToEndSSL();
- args->AppendElement(data);
- return PL_DHASH_NEXT;
-}
-
bool
nsHttpConnectionMgr::GetConnectionData(nsTArray *aArg)
{
- mCT.Enumerate(ReadConnectionEntry, aArg);
+ for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr& ent = iter.Data();
+
+ if (ent->mConnInfo->GetPrivate()) {
+ continue;
+ }
+
+ HttpRetParams data;
+ data.host = ent->mConnInfo->Origin();
+ data.port = ent->mConnInfo->OriginPort();
+ for (uint32_t i = 0; i < ent->mActiveConns.Length(); i++) {
+ HttpConnInfo info;
+ info.ttl = ent->mActiveConns[i]->TimeToLive();
+ info.rtt = ent->mActiveConns[i]->Rtt();
+ if (ent->mActiveConns[i]->UsingSpdy()) {
+ info.SetHTTP2ProtocolVersion(
+ ent->mActiveConns[i]->GetSpdyVersion());
+ } else {
+ info.SetHTTP1ProtocolVersion(
+ ent->mActiveConns[i]->GetLastHttpResponseVersion());
+ }
+ data.active.AppendElement(info);
+ }
+ for (uint32_t i = 0; i < ent->mIdleConns.Length(); i++) {
+ HttpConnInfo info;
+ info.ttl = ent->mIdleConns[i]->TimeToLive();
+ info.rtt = ent->mIdleConns[i]->Rtt();
+ info.SetHTTP1ProtocolVersion(
+ ent->mIdleConns[i]->GetLastHttpResponseVersion());
+ data.idle.AppendElement(info);
+ }
+ for (uint32_t i = 0; i < ent->mHalfOpens.Length(); i++) {
+ HalfOpenSockets hSocket;
+ hSocket.speculative = ent->mHalfOpens[i]->IsSpeculative();
+ data.halfOpens.AppendElement(hSocket);
+ }
+ data.spdy = ent->mUsingSpdy;
+ data.ssl = ent->mConnInfo->EndToEndSSL();
+ aArg->AppendElement(data);
+ }
+
return true;
}
diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h
index 555704f6cf..e0f3896f65 100644
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -369,15 +369,15 @@ private:
// To have the UsingSpdy flag means some host with the same connection
// entry has done NPN=spdy/* at some point. It does not mean every
// connection is currently using spdy.
- bool mUsingSpdy;
+ bool mUsingSpdy : 1;
// mTestedSpdy is set after NPN negotiation has occurred and we know
// with confidence whether a host speaks spdy or not (which is reflected
// in mUsingSpdy). Before mTestedSpdy is set, handshake parallelism is
// minimized so that we can multiplex on a single spdy connection.
- bool mTestedSpdy;
+ bool mTestedSpdy : 1;
- bool mInPreferredHash;
+ bool mInPreferredHash : 1;
// Flags to remember our happy-eyeballs decision.
// Reset only by Ctrl-F5 reload.
@@ -388,6 +388,9 @@ private:
// initially false.
bool mPreferIPv6 : 1;
+ // True if this connection entry has initiated a socket
+ bool mUsedForConnection : 1;
+
// Set the IP family preference flags according the connected family
void RecordIPFamilyPreference(uint16_t family);
// Resets all flags to their default values
@@ -510,16 +513,6 @@ private:
// NOTE: these members are only accessed on the socket transport thread
//-------------------------------------------------------------------------
- static PLDHashOperator ProcessOneTransactionCB(const nsACString &, nsAutoPtr &, void *);
- static PLDHashOperator ProcessAllTransactionsCB(const nsACString &, nsAutoPtr &, void *);
-
- static PLDHashOperator PruneDeadConnectionsCB(const nsACString &, nsAutoPtr &, void *);
- static PLDHashOperator ShutdownPassCB(const nsACString &, nsAutoPtr &, void *);
- static PLDHashOperator PurgeExcessIdleConnectionsCB(const nsACString &, nsAutoPtr &, void *);
- static PLDHashOperator PurgeExcessSpdyConnectionsCB(const nsACString &, nsAutoPtr &, void *);
- static PLDHashOperator ClosePersistentConnectionsCB(const nsACString &, nsAutoPtr &, void *);
- static PLDHashOperator VerifyTrafficCB(const nsACString &, nsAutoPtr &, void *);
- static PLDHashOperator PruneNoTrafficCB(const nsACString &, nsAutoPtr &, void *);
bool ProcessPendingQForEntry(nsConnectionEntry *, bool considerAll);
bool IsUnderPressure(nsConnectionEntry *ent,
nsHttpTransaction::Classifier classification);
@@ -571,9 +564,6 @@ private:
nsHttpTransaction *trans);
void ProcessSpdyPendingQ(nsConnectionEntry *ent);
- static PLDHashOperator ProcessSpdyPendingQCB(
- const nsACString &key, nsAutoPtr &ent,
- void *closure);
// used to marshall events to the socket transport thread.
nsresult PostEvent(nsConnEventHandler handler,
@@ -636,24 +626,12 @@ private:
//
nsClassHashtable mCT;
- static PLDHashOperator ReadConnectionEntry(const nsACString &key,
- nsAutoPtr &ent,
- void *aArg);
- static PLDHashOperator RemoveDeadConnections(const nsACString &key,
- nsAutoPtr &ent,
- void *aArg);
-
// Read Timeout Tick handlers
void TimeoutTick();
- static PLDHashOperator TimeoutTickCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure);
// For diagnostics
void OnMsgPrintDiagnostics(int32_t, ARefBase *);
- static PLDHashOperator PrintDiagnosticsCB(const nsACString &key,
- nsAutoPtr &ent,
- void *closure);
+
nsCString mLogData;
};
diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h
index 9d4847784a..bab76459a7 100644
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -29,6 +29,8 @@ class nsISiteSecurityService;
class nsIStreamConverterService;
class nsITimer;
+extern mozilla::Atomic gSocketThread;
+
namespace mozilla {
namespace net {
class ATokenBucketEvent;
@@ -559,6 +561,7 @@ public:
nsresult SubmitPacedRequest(ATokenBucketEvent *event,
nsICancelable **cancel)
{
+ MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
if (!mRequestTokenBucket)
return NS_ERROR_UNEXPECTED;
return mRequestTokenBucket->SubmitEvent(event, cancel);
@@ -567,9 +570,19 @@ public:
// Socket thread only
void SetRequestTokenBucket(EventTokenBucket *aTokenBucket)
{
+ MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
mRequestTokenBucket = aTokenBucket;
}
+ void StopRequestTokenBucket()
+ {
+ MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
+ if (mRequestTokenBucket) {
+ mRequestTokenBucket->Stop();
+ mRequestTokenBucket = nullptr;
+ }
+ }
+
private:
RefPtr mWifiTickler;
void TickleWifi(nsIInterfaceRequestor *cb);
diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
index 5ea8feee87..ca553490c2 100644
--- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
+++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
@@ -112,36 +112,19 @@ SubstitutingProtocolHandler::ConstructInternal()
// IPC marshalling.
//
-struct EnumerateSubstitutionArg
-{
- EnumerateSubstitutionArg(nsCString& aScheme, nsTArray& aMappings)
- : mScheme(aScheme), mMappings(aMappings) {}
- nsCString& mScheme;
- nsTArray& mMappings;
-};
-
-static PLDHashOperator
-EnumerateSubstitution(const nsACString& aKey,
- nsIURI* aURI,
- void* aArg)
-{
- auto arg = static_cast(aArg);
- SerializedURI uri;
- if (aURI) {
- aURI->GetSpec(uri.spec);
- aURI->GetOriginCharset(uri.charset);
- }
-
- SubstitutionMapping substitution = { arg->mScheme, nsCString(aKey), uri };
- arg->mMappings.AppendElement(substitution);
- return (PLDHashOperator)PL_DHASH_NEXT;
-}
-
void
SubstitutingProtocolHandler::CollectSubstitutions(InfallibleTArray& aMappings)
{
- EnumerateSubstitutionArg arg(mScheme, aMappings);
- mSubstitutions.EnumerateRead(&EnumerateSubstitution, &arg);
+ for (auto iter = mSubstitutions.ConstIter(); !iter.Done(); iter.Next()) {
+ nsCOMPtr uri = iter.Data();
+ SerializedURI serialized;
+ if (uri) {
+ uri->GetSpec(serialized.spec);
+ uri->GetOriginCharset(serialized.charset);
+ }
+ SubstitutionMapping substitution = { mScheme, nsCString(iter.Key()), serialized };
+ aMappings.AppendElement(substitution);
+ }
}
void
diff --git a/parser/expat/lib/xmlparse.c b/parser/expat/lib/xmlparse.c
index 9cfca793d4..aac3d36fbc 100644
--- a/parser/expat/lib/xmlparse.c
+++ b/parser/expat/lib/xmlparse.c
@@ -390,8 +390,10 @@ setContext(XML_Parser parser, const XML_Char *context);
static void FASTCALL normalizePublicId(XML_Char *s);
static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
+/* BEGIN MOZILLA CHANGE (unused API) */
/* do not call if parentParser != NULL */
-static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
+//static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
+/* END MOZILLA CHANGE */
static void
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
static int
@@ -403,7 +405,9 @@ static NAMED *
lookup(HASH_TABLE *table, KEY name, size_t createSize);
static void FASTCALL
hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
-static void FASTCALL hashTableClear(HASH_TABLE *);
+/* BEGIN MOZILLA CHANGE (unused API) */
+//static void FASTCALL hashTableClear(HASH_TABLE *);
+/* END MOZILLA CHANGE */
static void FASTCALL hashTableDestroy(HASH_TABLE *);
static void FASTCALL
hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
@@ -886,6 +890,8 @@ parserInit(XML_Parser parser, const XML_Char *encodingName)
#endif
}
+/* BEGIN MOZILLA CHANGE (unused API) */
+#if 0
/* moves list of bindings to freeBindingList */
static void FASTCALL
moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
@@ -898,8 +904,6 @@ moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
}
}
-/* BEGIN MOZILLA CHANGE (unused API) */
-#if 0
XML_Bool XMLCALL
XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
{
@@ -3075,7 +3079,6 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
static const XML_Char xmlnsPrefix[] = {
'x', 'm', 'l', 'n', 's', '\0'
};
- XML_Bool appendXMLNS = XML_TRUE;
((XML_Char *)s)[-1] = 0; /* clear flag */
if (!poolAppendString(&tempPool, xmlnsNamespace)
@@ -5909,6 +5912,8 @@ dtdCreate(const XML_Memory_Handling_Suite *ms)
return p;
}
+/* BEGIN MOZILLA CHANGE (unused API) */
+#if 0
static void
dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
{
@@ -5950,6 +5955,8 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
p->hasParamEntityRefs = XML_FALSE;
p->standalone = XML_FALSE;
}
+#endif
+/* END MOZILLA CHANGE */
static void
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
@@ -6289,6 +6296,8 @@ lookup(HASH_TABLE *table, KEY name, size_t createSize)
return table->v[i];
}
+/* BEGIN MOZILLA CHANGE (unused API) */
+#if 0
static void FASTCALL
hashTableClear(HASH_TABLE *table)
{
@@ -6299,6 +6308,8 @@ hashTableClear(HASH_TABLE *table)
}
table->used = 0;
}
+#endif
+/* END MOZILLA CHANGE */
static void FASTCALL
hashTableDestroy(HASH_TABLE *table)
diff --git a/storage/StatementCache.h b/storage/StatementCache.h
index a7f5378730..ed7714799f 100644
--- a/storage/StatementCache.h
+++ b/storage/StatementCache.h
@@ -79,7 +79,9 @@ public:
void
FinalizeStatements()
{
- (void)mCachedStatements.Enumerate(FinalizeCachedStatements, nullptr);
+ for (auto iter = mCachedStatements.Iter(); !iter.Done(); iter.Next()) {
+ (void)iter.Data()->Finalize();
+ }
// Clear the cache at this time too!
(void)mCachedStatements.Clear();
@@ -89,15 +91,6 @@ private:
inline
already_AddRefed
CreateStatement(const nsACString& aQuery);
- static
- PLDHashOperator
- FinalizeCachedStatements(const nsACString& aKey,
- nsCOMPtr& aStatement,
- void*)
- {
- (void)aStatement->Finalize();
- return PL_DHASH_NEXT;
- }
nsInterfaceHashtable mCachedStatements;
nsCOMPtr& mConnection;
diff --git a/toolkit/components/mediasniffer/mp3sniff.c b/toolkit/components/mediasniffer/mp3sniff.c
index bb30d80672..a515d9c583 100644
--- a/toolkit/components/mediasniffer/mp3sniff.c
+++ b/toolkit/components/mediasniffer/mp3sniff.c
@@ -118,12 +118,11 @@ static int id3_framesize(const uint8_t *p, long length)
int mp3_sniff(const uint8_t *buf, long length)
{
mp3_header header;
- const uint8_t *p, *q;
+ const uint8_t *p;
long skip;
long avail;
p = buf;
- q = p;
avail = length;
while (avail >= 4) {
if (is_id3(p, avail)) {
diff --git a/toolkit/components/places/nsFaviconService.cpp b/toolkit/components/places/nsFaviconService.cpp
index 484021fe7c..8371547c4e 100644
--- a/toolkit/components/places/nsFaviconService.cpp
+++ b/toolkit/components/places/nsFaviconService.cpp
@@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 8; 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/. */
@@ -415,18 +416,6 @@ nsFaviconService::GetFaviconLinkForIcon(nsIURI* aFaviconURI,
}
-static PLDHashOperator
-ExpireFailedFaviconsCallback(nsCStringHashKey::KeyType aKey,
- uint32_t& aData,
- void* userArg)
-{
- uint32_t* threshold = reinterpret_cast(userArg);
- if (aData < *threshold)
- return PL_DHASH_REMOVE;
- return PL_DHASH_NEXT;
-}
-
-
NS_IMETHODIMP
nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
{
@@ -444,7 +433,11 @@ nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
// of items that are the oldest
uint32_t threshold = mFailedFaviconSerial -
MAX_FAILED_FAVICONS + FAVICON_CACHE_REDUCE_COUNT;
- mFailedFavicons.Enumerate(ExpireFailedFaviconsCallback, &threshold);
+ for (auto iter = mFailedFavicons.Iter(); !iter.Done(); iter.Next()) {
+ if (iter.Data() < threshold) {
+ iter.Remove();
+ }
+ }
}
return NS_OK;
}
diff --git a/toolkit/components/places/nsNavBookmarks.cpp b/toolkit/components/places/nsNavBookmarks.cpp
index 7db9fc23ab..0930c436fc 100644
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -46,19 +46,6 @@ struct keywordSearchData
nsString keyword;
};
-PLDHashOperator
-SearchBookmarkForKeyword(nsTrimInt64HashKey::KeyType aKey,
- const nsString aValue,
- void* aUserArg)
-{
- keywordSearchData* data = reinterpret_cast(aUserArg);
- if (data->keyword.Equals(aValue)) {
- data->itemId = aKey;
- return PL_DHASH_STOP;
- }
- return PL_DHASH_NEXT;
-}
-
template
class AsyncGetBookmarksForURI : public AsyncStatementCallback
{
@@ -2277,7 +2264,12 @@ nsNavBookmarks::UpdateKeywordsHashForRemovedBookmark(int64_t aItemId)
keywordSearchData searchData;
searchData.keyword.Assign(keyword);
searchData.itemId = -1;
- mBookmarkToKeywordHash.EnumerateRead(SearchBookmarkForKeyword, &searchData);
+ for (auto iter = mBookmarkToKeywordHash.Iter(); !iter.Done(); iter.Next()) {
+ if (searchData.keyword.Equals(iter.Data())) {
+ searchData.itemId = iter.Key();
+ break;
+ }
+ }
if (searchData.itemId == -1) {
nsCOMPtr stmt = mDB->GetAsyncStatement(
"DELETE FROM moz_keywords "
@@ -2469,7 +2461,12 @@ nsNavBookmarks::GetURIForKeyword(const nsAString& aUserCasedKeyword,
keywordSearchData searchData;
searchData.keyword.Assign(keyword);
searchData.itemId = -1;
- mBookmarkToKeywordHash.EnumerateRead(SearchBookmarkForKeyword, &searchData);
+ for (auto iter = mBookmarkToKeywordHash.Iter(); !iter.Done(); iter.Next()) {
+ if (searchData.keyword.Equals(iter.Data())) {
+ searchData.itemId = iter.Key();
+ break;
+ }
+ }
if (searchData.itemId == -1) {
// Not found.
diff --git a/toolkit/components/places/nsNavHistory.cpp b/toolkit/components/places/nsNavHistory.cpp
index 454e89ff6c..8c3ea2b252 100644
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -3833,22 +3833,15 @@ nsNavHistory::CheckIsRecentEvent(RecentEventHash* hashTable,
//
// This goes through our
-static PLDHashOperator
-ExpireNonrecentEventsCallback(nsCStringHashKey::KeyType aKey,
- int64_t& aData,
- void* userArg)
-{
- int64_t* threshold = reinterpret_cast(userArg);
- if (aData < *threshold)
- return PL_DHASH_REMOVE;
- return PL_DHASH_NEXT;
-}
void
nsNavHistory::ExpireNonrecentEvents(RecentEventHash* hashTable)
{
int64_t threshold = GetNow() - RECENT_EVENT_THRESHOLD;
- hashTable->Enumerate(ExpireNonrecentEventsCallback,
- reinterpret_cast(&threshold));
+ for (auto iter = hashTable->Iter(); !iter.Done(); iter.Next()) {
+ if (iter.Data() < threshold) {
+ iter.Remove();
+ }
+ }
}
diff --git a/toolkit/components/places/nsNavHistoryResult.cpp b/toolkit/components/places/nsNavHistoryResult.cpp
index b75c8c2fb8..fa2c0a0634 100644
--- a/toolkit/components/places/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/nsNavHistoryResult.cpp
@@ -1,4 +1,5 @@
-//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 8; 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/. */
@@ -3941,46 +3942,32 @@ nsNavHistorySeparatorResultNode::nsNavHistorySeparatorResultNode()
}
-static PLDHashOperator
-RemoveBookmarkFolderObserversCallback(nsTrimInt64HashKey::KeyType aKey,
- nsNavHistoryResult::FolderObserverList*& aData,
- void* userArg)
-{
- delete aData;
- return PL_DHASH_REMOVE;
-}
-
NS_IMPL_CYCLE_COLLECTION_CLASS(nsNavHistoryResult)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsNavHistoryResult)
tmp->StopObserving();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers)
- tmp->mBookmarkFolderObservers.Enumerate(&RemoveBookmarkFolderObserversCallback, nullptr);
+ for (auto it = tmp->mBookmarkFolderObservers.Iter(); !it.Done(); it.Next()) {
+ delete it.Data();
+ it.Remove();
+ }
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAllBookmarksObservers)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistoryObservers)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-static PLDHashOperator
-TraverseBookmarkFolderObservers(nsTrimInt64HashKey::KeyType aKey,
- nsNavHistoryResult::FolderObserverList* &aData,
- void *aClosure)
-{
- nsCycleCollectionTraversalCallback* cb =
- static_cast(aClosure);
- for (uint32_t i = 0; i < aData->Length(); ++i) {
- NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
- "mBookmarkFolderObservers value[i]");
- nsNavHistoryResultNode* node = aData->ElementAt(i);
- cb->NoteXPCOMChild(node);
- }
- return PL_DHASH_NEXT;
-}
-
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsNavHistoryResult)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
- tmp->mBookmarkFolderObservers.Enumerate(&TraverseBookmarkFolderObservers, &cb);
+ for (auto it = tmp->mBookmarkFolderObservers.Iter(); !it.Done(); it.Next()) {
+ nsNavHistoryResult::FolderObserverList*& list = it.Data();
+ for (uint32_t i = 0; i < list->Length(); ++i) {
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
+ "mBookmarkFolderObservers value[i]");
+ nsNavHistoryResultNode* node = list->ElementAt(i);
+ cb.NoteXPCOMChild(node);
+ }
+ }
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAllBookmarksObservers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistoryObservers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -4012,8 +3999,11 @@ nsNavHistoryResult::nsNavHistoryResult(nsNavHistoryContainerResultNode* aRoot)
nsNavHistoryResult::~nsNavHistoryResult()
{
- // delete all bookmark folder observer arrays which are allocated on the heap
- mBookmarkFolderObservers.Enumerate(&RemoveBookmarkFolderObserversCallback, nullptr);
+ // Delete all heap-allocated bookmark folder observer arrays.
+ for (auto it = mBookmarkFolderObservers.Iter(); !it.Done(); it.Next()) {
+ delete it.Data();
+ it.Remove();
+ }
}
void
diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp
index 0528c076aa..b4c9f12b69 100644
--- a/toolkit/components/satchel/nsFormFillController.cpp
+++ b/toolkit/components/satchel/nsFormFillController.cpp
@@ -1,3 +1,5 @@
+/* -*- Mode: C++; tab-width: 8; 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/. */
@@ -75,15 +77,6 @@ nsFormFillController::nsFormFillController() :
MOZ_ASSERT(mController);
}
-struct PwmgrInputsEnumData
-{
- PwmgrInputsEnumData(nsFormFillController* aFFC, nsIDocument* aDoc)
- : mFFC(aFFC), mDoc(aDoc) {}
-
- nsFormFillController* mFFC;
- nsCOMPtr mDoc;
-};
-
nsFormFillController::~nsFormFillController()
{
if (mListNode) {
@@ -95,8 +88,7 @@ nsFormFillController::~nsFormFillController()
mFocusedInputNode = nullptr;
mFocusedInput = nullptr;
}
- PwmgrInputsEnumData ed(this, nullptr);
- mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
+ RemoveForDocument(nullptr);
// Remove ourselves as a focus listener from all cached docShells
uint32_t count = mDocShells.Length();
@@ -867,28 +859,26 @@ nsFormFillController::HandleEvent(nsIDOMEvent* aEvent)
StopControllingInput();
}
- PwmgrInputsEnumData ed(this, doc);
- mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
+ RemoveForDocument(doc);
}
return NS_OK;
}
-
-/* static */ PLDHashOperator
-nsFormFillController::RemoveForDocumentEnumerator(const nsINode* aKey,
- bool& aEntry,
- void* aUserData)
+void
+nsFormFillController::RemoveForDocument(nsIDocument* aDoc)
{
- PwmgrInputsEnumData* ed = static_cast(aUserData);
- if (aKey && (!ed->mDoc || aKey->OwnerDoc() == ed->mDoc)) {
- // mFocusedInputNode's observer is tracked separately, don't remove it here.
- if (aKey != ed->mFFC->mFocusedInputNode) {
- const_cast(aKey)->RemoveMutationObserver(ed->mFFC);
+ for (auto iter = mPwmgrInputs.Iter(); !iter.Done(); iter.Next()) {
+ const nsINode* key = iter.Key();
+ if (key && (!aDoc || key->OwnerDoc() == aDoc)) {
+ // mFocusedInputNode's observer is tracked separately, so don't remove it
+ // here.
+ if (key != mFocusedInputNode) {
+ const_cast(key)->RemoveMutationObserver(this);
+ }
+ iter.Remove();
}
- return PL_DHASH_REMOVE;
}
- return PL_DHASH_NEXT;
}
void
@@ -1134,8 +1124,7 @@ nsFormFillController::RemoveWindowListeners(nsIDOMWindow *aWindow)
nsCOMPtr domDoc;
aWindow->GetDocument(getter_AddRefs(domDoc));
nsCOMPtr doc = do_QueryInterface(domDoc);
- PwmgrInputsEnumData ed(this, doc);
- mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
+ RemoveForDocument(doc);
nsCOMPtr privateDOMWindow(do_QueryInterface(aWindow));
EventTarget* target = nullptr;
diff --git a/toolkit/components/satchel/nsFormFillController.h b/toolkit/components/satchel/nsFormFillController.h
index 76d58e5a59..e3ee9abe61 100644
--- a/toolkit/components/satchel/nsFormFillController.h
+++ b/toolkit/components/satchel/nsFormFillController.h
@@ -84,9 +84,7 @@ protected:
void MaybeRemoveMutationObserver(nsINode* aNode);
- static PLDHashOperator RemoveForDocumentEnumerator(const nsINode* aKey,
- bool& aEntry,
- void* aUserData);
+ void RemoveForDocument(nsIDocument* aDoc);
bool IsEventTrusted(nsIDOMEvent *aEvent);
// members //////////////////////////////////////////
diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json
index fe1d763209..8d36d5c005 100644
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -1449,6 +1449,11 @@
"n_values": 32,
"description": "H2: goaway reason from peer from rfc 7540. 31 is none received."
},
+ "HTTP_CONNECTION_ENTRY_CACHE_HIT_1" : {
+ "expires_in_version": "never",
+ "kind": "boolean",
+ "description": "Fraction of sockets that used a nsConnectionEntry with history - size 300."
+ },
"DISK_CACHE_CORRUPT_DETAILS": {
"expires_in_version": "40",
"kind": "enumerated",
diff --git a/toolkit/modules/ObjectUtils.jsm b/toolkit/modules/ObjectUtils.jsm
new file mode 100644
index 0000000000..04b9a1ac21
--- /dev/null
+++ b/toolkit/modules/ObjectUtils.jsm
@@ -0,0 +1,174 @@
+/* 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/. */
+
+// Portions of this file are originally from narwhal.js (http://narwhaljs.org)
+// Copyright (c) 2009 Thomas Robinson <280north.com>
+// MIT license: http://opensource.org/licenses/MIT
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [
+ "ObjectUtils"
+];
+
+const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
+
+// Used only to cause test failures.
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+ "resource://gre/modules/Promise.jsm");
+
+this.ObjectUtils = {
+ /**
+ * This tests objects & values for deep equality.
+ *
+ * We check using the most exact approximation of equality between two objects
+ * to keep the chance of false positives to a minimum.
+ * `JSON.stringify` is not designed to be used for this purpose; objects may
+ * have ambiguous `toJSON()` implementations that would influence the test.
+ *
+ * @param a (mixed) Object or value to be compared.
+ * @param b (mixed) Object or value to be compared.
+ * @return Boolean Whether the objects are deep equal.
+ */
+ deepEqual: function(a, b) {
+ return _deepEqual(a, b);
+ },
+
+ /**
+ * A thin wrapper on an object, designed to prevent client code from
+ * accessing non-existent properties because of typos.
+ *
+ * // Without `strict`
+ * let foo = { myProperty: 1 };
+ * foo.MyProperty; // undefined
+ *
+ * // With `strict`
+ * let strictFoo = ObjectUtils.strict(foo);
+ * strictFoo.myProperty; // 1
+ * strictFoo.MyProperty; // TypeError: No such property "MyProperty"
+ *
+ * Note that `strict` has no effect in non-DEBUG mode.
+ */
+ strict: function(obj) {
+ return _strict(obj);
+ }
+};
+
+// ... Start of previously MIT-licensed code.
+// This deepEqual implementation is originally from narwhal.js (http://narwhaljs.org)
+// Copyright (c) 2009 Thomas Robinson <280north.com>
+// MIT license: http://opensource.org/licenses/MIT
+
+function _deepEqual(a, b) {
+ // The numbering below refers to sections in the CommonJS spec.
+
+ // 7.1 All identical values are equivalent, as determined by ===.
+ if (a === b) {
+ return true;
+ // 7.2 If the b value is a Date object, the a value is
+ // equivalent if it is also a Date object that refers to the same time.
+ } else if (instanceOf(a, "Date") && instanceOf(b, "Date")) {
+ if (isNaN(a.getTime()) && isNaN(b.getTime()))
+ return true;
+ return a.getTime() === b.getTime();
+ // 7.3 If the b value is a RegExp object, the a value is
+ // equivalent if it is also a RegExp object with the same source and
+ // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
+ } else if (instanceOf(a, "RegExp") && instanceOf(b, "RegExp")) {
+ return a.source === b.source &&
+ a.global === b.global &&
+ a.multiline === b.multiline &&
+ a.lastIndex === b.lastIndex &&
+ a.ignoreCase === b.ignoreCase;
+ // 7.4 Other pairs that do not both pass typeof value == "object",
+ // equivalence is determined by ==.
+ } else if (typeof a != "object" && typeof b != "object") {
+ return a == b;
+ // 7.5 For all other Object pairs, including Array objects, equivalence is
+ // determined by having the same number of owned properties (as verified
+ // with Object.prototype.hasOwnProperty.call), the same set of keys
+ // (although not necessarily the same order), equivalent values for every
+ // corresponding key, and an identical 'prototype' property. Note: this
+ // accounts for both named and indexed properties on Arrays.
+ } else {
+ return objEquiv(a, b);
+ }
+}
+
+function instanceOf(object, type) {
+ return Object.prototype.toString.call(object) == "[object " + type + "]";
+}
+
+function isUndefinedOrNull(value) {
+ return value === null || value === undefined;
+}
+
+function isArguments(object) {
+ return instanceOf(object, "Arguments");
+}
+
+function objEquiv(a, b) {
+ if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) {
+ return false;
+ }
+ // An identical 'prototype' property.
+ if ((a.prototype || undefined) != (b.prototype || undefined)) {
+ return false;
+ }
+ // Object.keys may be broken through screwy arguments passing. Converting to
+ // an array solves the problem.
+ if (isArguments(a)) {
+ if (!isArguments(b)) {
+ return false;
+ }
+ a = pSlice.call(a);
+ b = pSlice.call(b);
+ return _deepEqual(a, b);
+ }
+ let ka, kb;
+ try {
+ ka = Object.keys(a);
+ kb = Object.keys(b);
+ } catch (e) {
+ // Happens when one is a string literal and the other isn't
+ return false;
+ }
+ // Having the same number of owned properties (keys incorporates
+ // hasOwnProperty)
+ if (ka.length != kb.length)
+ return false;
+ // The same set of keys (although not necessarily the same order),
+ ka.sort();
+ kb.sort();
+ // Equivalent values for every corresponding key, and possibly expensive deep
+ // test
+ for (let key of ka) {
+ if (!_deepEqual(a[key], b[key])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// ... End of previously MIT-licensed code.
+
+function _strict(obj) {
+ if (typeof obj != "object") {
+ throw new TypeError("Expected an object");
+ }
+
+ return new Proxy(obj, {
+ get: function(target, name) {
+ if (name in obj) {
+ return obj[name];
+ }
+
+ let error = new TypeError(`No such property: "${name}"`);
+ Promise.reject(error); // Cause an xpcshell/mochitest failure.
+ throw error;
+ }
+ });
+}
diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build
index ff91e32a60..bc4dc18dfa 100644
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -34,6 +34,7 @@ EXTRA_JS_MODULES += [
'LoadContextInfo.jsm',
'Log.jsm',
'NewTabUtils.jsm',
+ 'ObjectUtils.jsm',
'PageMenu.jsm',
'PageMetadata.jsm',
'PermissionsUtils.jsm',
diff --git a/toolkit/mozapps/update/tests/TestAUSHelper.cpp b/toolkit/mozapps/update/tests/TestAUSHelper.cpp
index e23c60589f..522c79d811 100644
--- a/toolkit/mozapps/update/tests/TestAUSHelper.cpp
+++ b/toolkit/mozapps/update/tests/TestAUSHelper.cpp
@@ -230,7 +230,9 @@ int NS_main(int argc, NS_tchar **argv)
NS_tfputs(NS_T("test"), file);
fclose(file);
}
- symlink(path, argv[5]);
+ if (symlink(path, argv[5]) != 0) {
+ return 1;
+ }
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
if (argc > 6 && !NS_tstrcmp(argv[6], NS_T("change-perm"))) {
diff --git a/toolkit/mozapps/update/tests/moz.build b/toolkit/mozapps/update/tests/moz.build
index 85d464231f..f68d904f99 100644
--- a/toolkit/mozapps/update/tests/moz.build
+++ b/toolkit/mozapps/update/tests/moz.build
@@ -54,6 +54,3 @@ if CONFIG['OS_ARCH'] == 'WINNT':
USE_STATIC_LIBS = True
if CONFIG['GNU_CC']:
WIN32_EXE_LDFLAGS += ['-municode']
-
-# XXX: We should fix these warnings
-ALLOW_COMPILER_WARNINGS = True
diff --git a/widget/gtk/gtk3drawing.c b/widget/gtk/gtk3drawing.c
index 3986e7ebb3..089ae36f6d 100644
--- a/widget/gtk/gtk3drawing.c
+++ b/widget/gtk/gtk3drawing.c
@@ -2685,20 +2685,19 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
*left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget));
- /* Don't add this padding in HTML, otherwise the buttons will
- become too big and stuff the layout. */
- if (!inhtml) {
- if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
- gtk_style_context_save(style);
- gtk_style_context_add_class(style, "image-button");
- }
-
- moz_gtk_add_style_padding(style, left, top, right, bottom);
-
- if (widget == MOZ_GTK_TOOLBAR_BUTTON)
- gtk_style_context_restore(style);
+ if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, "image-button");
}
+
+ moz_gtk_add_style_padding(style, left, top, right, bottom);
+
+ if (widget == MOZ_GTK_TOOLBAR_BUTTON)
+ gtk_style_context_restore(style);
+ // XXX: Subtract 1 pixel from the border to account for the added
+ // -moz-focus-inner border (Bug 1228281).
+ *left -= 1; *top -= 1; *right -= 1; *bottom -= 1;
moz_gtk_add_style_border(style, left, top, right, bottom);
return MOZ_GTK_SUCCESS;
}
diff --git a/xpcom/glue/nsBaseHashtable.h b/xpcom/glue/nsBaseHashtable.h
index c7db67e5a7..050e48c74e 100644
--- a/xpcom/glue/nsBaseHashtable.h
+++ b/xpcom/glue/nsBaseHashtable.h
@@ -10,20 +10,8 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/Move.h"
#include "nsTHashtable.h"
-#include "prlock.h"
#include "nsDebug.h"
-// These are the codes returned by |EnumReadFunction| and |EnumFunction|, which
-// control the behavior of EnumerateRead() and Enumerate(). The PLD/PL_D prefix
-// is because they originated in PLDHashTable, but that class no longer uses
-// them.
-enum PLDHashOperator
-{
- PL_DHASH_NEXT = 0, // enumerator says continue
- PL_DHASH_STOP = 1, // enumerator says stop
- PL_DHASH_REMOVE = 2 // enumerator says remove
-};
-
template
class nsBaseHashtable; // forward declaration
@@ -158,79 +146,6 @@ public:
*/
void Remove(KeyType aKey) { this->RemoveEntry(aKey); }
- /**
- * function type provided by the application for enumeration.
- * @param aKey the key being enumerated
- * @param aData data being enumerated
- * @param aUserArg passed unchanged from Enumerate
- * @return either
- * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or
- * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink
- */
- typedef PLDHashOperator (*EnumReadFunction)(KeyType aKey,
- UserDataType aData,
- void* aUserArg);
-
- /**
- * enumerate entries in the hashtable, without allowing changes
- * WARNING: this function is deprecated. Please use Iterator instead.
- * @param aEnumFunc enumeration callback
- * @param aUserArg passed unchanged to the EnumReadFunction
- */
- uint32_t EnumerateRead(EnumReadFunction aEnumFunc, void* aUserArg) const
- {
- uint32_t n = 0;
- for (auto iter = this->mTable.ConstIter(); !iter.Done(); iter.Next()) {
- auto entry = static_cast(iter.Get());
- PLDHashOperator op = aEnumFunc(entry->GetKey(), entry->mData, aUserArg);
- n++;
- MOZ_ASSERT(!(op & PL_DHASH_REMOVE));
- if (op & PL_DHASH_STOP) {
- break;
- }
- }
- return n;
- }
-
- /**
- * function type provided by the application for enumeration.
- * @param aKey the key being enumerated
- * @param aData Reference to data being enumerated, may be altered. e.g. for
- * nsInterfaceHashtable this is an nsCOMPtr reference...
- * @parm aUserArg passed unchanged from Enumerate
- * @return bitflag combination of
- * @link PLDHashOperator::PL_DHASH_REMOVE @endlink,
- * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or
- * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink
- */
- typedef PLDHashOperator (*EnumFunction)(KeyType aKey,
- DataType& aData,
- void* aUserArg);
-
- /**
- * enumerate entries in the hashtable, allowing changes.
- * WARNING: this function is deprecated. Please use Iterator and/or
- * MutatingIterator instead.
- * @param aEnumFunc enumeration callback
- * @param aUserArg passed unchanged to the EnumFunction
- */
- uint32_t Enumerate(EnumFunction aEnumFunc, void* aUserArg)
- {
- uint32_t n = 0;
- for (auto iter = this->mTable.Iter(); !iter.Done(); iter.Next()) {
- auto entry = static_cast(iter.Get());
- PLDHashOperator op = aEnumFunc(entry->GetKey(), entry->mData, aUserArg);
- n++;
- if (op & PL_DHASH_REMOVE) {
- iter.Remove();
- }
- if (op & PL_DHASH_STOP) {
- break;
- }
- }
- return n;
- }
-
// This is an iterator that also allows entry removal. Example usage:
//
// for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
diff --git a/xpcom/tests/TestHashtables.cpp b/xpcom/tests/TestHashtables.cpp
index 43c719c452..9dd4fecd0c 100644
--- a/xpcom/tests/TestHashtables.cpp
+++ b/xpcom/tests/TestHashtables.cpp
@@ -170,32 +170,6 @@ testTHashtable(nsTHashtable& hash, uint32_t numEntries) {
}
}
-PLDHashOperator
-nsDEnumRead(const uint32_t& aKey, const char* aData, void* userArg) {
- printf(" enumerated %u = \"%s\"\n", aKey, aData);
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsDEnum(const uint32_t& aKey, const char*& aData, void* userArg) {
- printf(" enumerated %u = \"%s\"\n", aKey, aData);
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsCEnumRead(const nsACString& aKey, TestUniChar* aData, void* userArg) {
- printf(" enumerated \"%s\" = %c\n",
- PromiseFlatCString(aKey).get(), aData->GetChar());
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsCEnum(const nsACString& aKey, nsAutoPtr& aData, void* userArg) {
- printf(" enumerated \"%s\" = %c\n",
- PromiseFlatCString(aKey).get(), aData->GetChar());
- return PL_DHASH_NEXT;
-}
-
//
// all this nsIFoo stuff was copied wholesale from TestCOMPtr.cpp
//
@@ -339,45 +313,6 @@ CreateIFoo( IFoo** result )
return NS_OK;
}
-PLDHashOperator
-nsIEnumRead(const uint32_t& aKey, IFoo* aFoo, void* userArg) {
- nsAutoCString str;
- aFoo->GetString(str);
-
- printf(" enumerated %u = \"%s\"\n", aKey, str.get());
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsIEnum(const uint32_t& aKey, nsCOMPtr& aData, void* userArg) {
- nsAutoCString str;
- aData->GetString(str);
-
- printf(" enumerated %u = \"%s\"\n", aKey, str.get());
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsIEnum2Read(nsISupports* aKey, uint32_t aData, void* userArg) {
- nsAutoCString str;
- nsCOMPtr foo = do_QueryInterface(aKey);
- foo->GetString(str);
-
-
- printf(" enumerated \"%s\" = %u\n", str.get(), aData);
- return PL_DHASH_NEXT;
-}
-
-PLDHashOperator
-nsIEnum2(nsISupports* aKey, uint32_t& aData, void* userArg) {
- nsAutoCString str;
- nsCOMPtr foo = do_QueryInterface(aKey);
- foo->GetString(str);
-
- printf(" enumerated \"%s\" = %u\n", str.get(), aData);
- return PL_DHASH_NEXT;
-}
-
} // namespace TestHashtables
using namespace TestHashtables;
@@ -402,7 +337,7 @@ main(void) {
printf("Check enumeration...");
count = nsTIterPrint(EntityToUnicode);
- if (count) {
+ if (count != 0) {
printf("entries remain in table!\n");
exit (8);
}
@@ -417,7 +352,7 @@ main(void) {
printf("Check enumeration...");
count = nsTIterPrint(EntityToUnicode);
- if (count) {
+ if (count != 0) {
printf("entries remain in table!\n");
exit (9);
}
@@ -458,24 +393,32 @@ main(void) {
printf("FOUND! BAD!\n");
exit (13);
}
-
+
printf("not found; good.\n");
-
+
printf("Enumerating:\n");
-
- count = UniToEntity.EnumerateRead(nsDEnumRead, nullptr);
+
+ count = 0;
+ for (auto iter = UniToEntity.Iter(); !iter.Done(); iter.Next()) {
+ printf(" enumerated %u = \"%s\"\n", iter.Key(), iter.UserData());
+ count++;
+ }
if (count != ENTITY_COUNT) {
printf(" Bad count!\n");
exit (14);
}
-
+
printf("Clearing...");
UniToEntity.Clear();
printf("OK\n");
printf("Checking count...");
- count = UniToEntity.Enumerate(nsDEnum, nullptr);
- if (count) {
+ count = 0;
+ for (auto iter = UniToEntity.Iter(); !iter.Done(); iter.Next()) {
+ printf(" enumerated %u = \"%s\"\n", iter.Key(), iter.Data());
+ count++;
+ }
+ if (count != 0) {
printf(" Clear did not remove all entries.\n");
exit (15);
}
@@ -518,24 +461,34 @@ main(void) {
printf("FOUND! BAD!\n");
exit (19);
}
-
+
printf("not found; good.\n");
-
+
printf("Enumerating:\n");
-
- count = EntToUniClass.EnumerateRead(nsCEnumRead, nullptr);
+
+ count = 0;
+ for (auto iter = EntToUniClass.Iter(); !iter.Done(); iter.Next()) {
+ printf(" enumerated \"%s\" = %c\n",
+ PromiseFlatCString(iter.Key()).get(), iter.UserData()->GetChar());
+ count++;
+ }
if (count != ENTITY_COUNT) {
printf(" Bad count!\n");
exit (20);
}
-
+
printf("Clearing...\n");
EntToUniClass.Clear();
printf(" Clearing OK\n");
printf("Checking count...");
- count = EntToUniClass.Enumerate(nsCEnum, nullptr);
- if (count) {
+ count = 0;
+ for (auto iter = EntToUniClass.Iter(); !iter.Done(); iter.Next()) {
+ printf(" enumerated \"%s\" = %c\n",
+ PromiseFlatCString(iter.Key()).get(), iter.Data()->GetChar());
+ count++;
+ }
+ if (count != 0) {
printf(" Clear did not remove all entries.\n");
exit (21);
}
@@ -571,7 +524,7 @@ main(void) {
for (i = 0; i < ENTITY_COUNT; ++i) {
printf(" Getting entry %s...", gEntities[i].mStr);
-
+
if (!EntToUniClass2.Get(fooArray[i], &myChar2)) {
printf("FAILED\n");
exit (24);
@@ -585,24 +538,38 @@ main(void) {
printf("FOUND! BAD!\n");
exit (25);
}
-
+
printf("not found; good.\n");
-
+
printf("Enumerating:\n");
-
- count = EntToUniClass2.EnumerateRead(nsIEnum2Read, nullptr);
+
+ count = 0;
+ for (auto iter = EntToUniClass2.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoCString s;
+ nsCOMPtr foo = do_QueryInterface(iter.Key());
+ foo->GetString(s);
+ printf(" enumerated \"%s\" = %u\n", s.get(), iter.UserData());
+ count++;
+ }
if (count != ENTITY_COUNT) {
printf(" Bad count!\n");
exit (26);
}
-
+
printf("Clearing...\n");
EntToUniClass2.Clear();
printf(" Clearing OK\n");
printf("Checking count...");
- count = EntToUniClass2.Enumerate(nsIEnum2, nullptr);
- if (count) {
+ count = 0;
+ for (auto iter = EntToUniClass2.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoCString s;
+ nsCOMPtr foo = do_QueryInterface(iter.Key());
+ foo->GetString(s);
+ printf(" enumerated \"%s\" = %u\n", s.get(), iter.Data());
+ count++;
+ }
+ if (count != 0) {
printf(" Clear did not remove all entries.\n");
exit (27);
}
@@ -633,7 +600,7 @@ main(void) {
for (i = 0; i < ENTITY_COUNT; ++i) {
printf(" Getting entry %s...", gEntities[i].mStr);
-
+
nsCOMPtr myEnt;
if (!UniToEntClass2.Get(gEntities[i].mUnicode, getter_AddRefs(myEnt))) {
printf("FAILED\n");
@@ -651,24 +618,36 @@ main(void) {
printf("FOUND! BAD!\n");
exit (31);
}
-
+
printf("not found; good.\n");
-
+
printf("Enumerating:\n");
-
- count = UniToEntClass2.EnumerateRead(nsIEnumRead, nullptr);
+
+ count = 0;
+ for (auto iter = UniToEntClass2.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoCString s;
+ iter.UserData()->GetString(s);
+ printf(" enumerated %u = \"%s\"\n", iter.Key(), s.get());
+ count++;
+ }
if (count != ENTITY_COUNT) {
printf(" Bad count!\n");
exit (32);
}
-
+
printf("Clearing...\n");
UniToEntClass2.Clear();
printf(" Clearing OK\n");
printf("Checking count...");
- count = UniToEntClass2.Enumerate(nsIEnum, nullptr);
- if (count) {
+ count = 0;
+ for (auto iter = UniToEntClass2.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoCString s;
+ iter.Data()->GetString(s);
+ printf(" enumerated %u = \"%s\"\n", iter.Key(), s.get());
+ count++;
+ }
+ if (count != 0) {
printf(" Clear did not remove all entries.\n");
exit (33);
}
diff --git a/xpcom/tests/gtest/TestPLDHash.cpp b/xpcom/tests/gtest/TestPLDHash.cpp
index e5c8273448..6d7150088c 100644
--- a/xpcom/tests/gtest/TestPLDHash.cpp
+++ b/xpcom/tests/gtest/TestPLDHash.cpp
@@ -345,8 +345,8 @@ TEST(PLDHashTableTest, GrowToMaxCapacity)
numInserted++;
}
- // We stop when the element count is 96.875% of PL_DHASH_MAX_SIZE (see
- // MaxLoadOnGrowthFailure()).
+ // We stop when the element count is 96.875% of PLDHashTable::kMaxCapacity
+ // (see MaxLoadOnGrowthFailure()).
if (numInserted !=
PLDHashTable::kMaxCapacity - (PLDHashTable::kMaxCapacity >> 5)) {
delete t;