From 6ecfad14f84b15997d9fcb81e17a1f2119733bcc Mon Sep 17 00:00:00 2001 From: roytam1 Date: Tue, 19 Sep 2023 16:39:50 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1140558 - Part 2 - Make the testing deepEqual implementation shared properly in ObjectUtils.jsm. r=yoric (f1a217e34a) - Bug 1154773 - Change undefined property a.prototype. r=Yoric (8a4dc37d6c) - Bug 1202971 (part 1) - Fix compile warnings in libmar. r=rstrong. (30cdf015c2) - bug 1200360 - fix $(DEFINES) usage in modules/libmar/tool/moz.build. r=mshal (26f1c5640b) - Bug 903135 - Updates to libmar needed to support B2G MAR signature verification. r=bbondy (81612e2200) - Bug 1228332 - Fix a potentially uninitialized pointer read, flagged by static analysis. r=spohl (9cac770c90) - Bug 1202971 (part 2) - Fix compile warnings in toolkit/mozapps/update/tests. r=rstrong. (814f2b3b8b) - Bug 973933 - Fix libmar warnings. r=rstrong. a=Callek (e0c2d3edcc) - Bug 1232219 (part 1) - Fix -Wunused warnings in libmar/. r=bbondy. (dc046504df) - Bug 1228281 - [GTK3] add padding to buttons. r=karlt (fe8ca55f58) - Bug 1232219 (part 2.5) - Fix -Wunused warnings in parser/expat/lib/. r=hsivonen. (e4d10c5d68) - Bug 1232219 (part 3) - Fix remaining -Wunused warnings. r=glandium. (35c5f3c38e) - Bug 1232219 (follow-up) - Fix nsinstall.c bustage in SM(e) builds. r=me. (d62c12cf35) - Bug 1186815 (part 1) - Replace nsBaseHashtable::Enumerate() calls in modules/libjar/ with iterators. r=mwu. (6959b19fab) - Bug 1186815 (part 2) - Replace nsBaseHashtable::Enumerate() calls in modules/libjar/ with iterators. r=mwu. (02c6f50482) - Bug 1181444 (part 1.5) - Remove dead PLDHashOperator declarations. r=froydnj. (c956e03dc0) - Bug 1225407 - Replace nsInterfaceHashtable::EnumerateRead() call in SubstitutingProtocolHandler with an iterator. r=michal (aa71f5499c) - Bug 1187781 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (68f51d05ba) - Bug 1187781 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (1dfc261267) - Bug 1187781 (part 3) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (922fc4e4ef) - Bug 1187781 (part 4) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (7b1915053f) - Bug 1187781 (part 5) - Replace nsBaseHashtable::EnumerateRead() calls in dom/xbl/ with iterators. r=mrbkap. (5df4cc1d09) - Bug 1181444 (part 2) - Remove nsBaseHashtable::Enumerate(). r=froydnj. (c606342f1d) - Bug 1243912 - Remove unused Loader::RemoveEntriesWithURI declaration. r=njn (e59b2ef892) - Bug 1187137 (part 4) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (17fb17c48f) - Bug 1187137 (part 5) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (89d430cf98) - Bug 1187137 (part 6) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (37befe08c6) - Bug 1187137 (part 7) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin (a8227c4b3e) - Bug 1187137 (part 1) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=michal. (05f71a4a94) - Bug 1187137 (part 2) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=michal. (5defa991b5) - Bug 1187137 (part 3) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=michal. (f2e0a4be0f) - Bug 1187137 (part 8) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (11b77f3b67) - Bug 1187137 (part 9) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (7a6bd9a17e) - Bug 1230743 - telemtry for nsConnectionEntry hit rate r=hurley (a75d6ec52c) - Bug 1218297 - eventtokenbucket shutdown leak r=valentin (1723059684) - Bug 1239961 - Minimize amount of PR_Poll and PR_Read calls during shutdown. r=mcmanus (127259afb6) - Bug 1187137 (part 10) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (eee20459fb) - Bug 1187137 (part 11) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (864bc96862) - Bug 1187137 (part 12) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (4fd9540167) - Bug 1187137 (part 13) - Replace nsBaseHashtable::Enumerate() calls in netwerk/protocol/ with iterators. r=valentin. (65a01f4083) - Bug 1187151 (part 14) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=baku. (a71b4169a9) - Bug 1187141 - Replace nsBaseHashtable::Enumerate() calls in storage/ with iterators. r=mak. (d95fb168c9) - Bug 1187151 (part 11) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=khuey. (dda92d0455) - Bug 1187151 (part 10) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=khuey. (f59270049c) - Bug 1191460 Contextual Identity tests r=tanvi,r=ttaubert (03c079ede9) - Bug 1187151 (part 12) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=khuey. (0aa9356990) - Bug 1187151 (part 15) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=baku. (10e60a4b55) - Bug 1187151 (part 16) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=mccr8. (2ef1033aae) - Bug 1187151 (part 17) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=mccr8. (dc37dfc17b) - Bug 1241763: Don't fire dom-window-destroyed on outer windows. r=bz (ea30677af6) - Bug 1192128 - In DOM memory reporter, handle WindowID() being a uint64_t. r=mccr8. (b3f834b8f6) - Bug 1187151 (part 18) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=mccr8. (22d4fbe0f0) - Bug 1187138 (part 2) - Replace nsBaseHashtable::Enumerate() calls in toolkit/ with iterators. r=froydnj. (b4740ef44b) - Bug 1187138 (part 3) - Replace nsBaseHashtable::Enumerate() calls in toolkit/ with iterators. r=froydnj. (931eb9e813) - Bug 1187138 (part 4) - Replace nsBaseHashtable::Enumerate() calls in toolkit/ with iterators. r=froydnj. (a92fef3586) - Bug 1192189 - Fix assertion condition to use to-be-restyled element's composed document. r=dbaron (6c7733b7cc) - Bug 1187144 (part 10) - Replace nsBaseHashtable::Enumerate() calls in layout/ with iterators. r=heycam. (e93ad4330c) - Bug 1250525 - remove #IFDEF ENABLE_TESTS from dom/quota/ActorsParent.cpp. r=janv (22bc8fc0af) - Bug 1236632 - remove unused variable in FactoryOp::WaitForTransactions; r=janv (3c56b90fff) - Bug 1187116 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (f37ac71816) - Bug 1187116 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (6bf16c51fe) - Bug 1187116 (part 3) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (351b7d5d34) - Bug 1187116 (part 4) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (330678dde4) - Bug 1187116 (part 5) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (43d20a7fa3) - Bug 1187116 (part 6) - Replace nsBaseHashtable::EnumerateRead() calls in dom/indexedDB/ with iterators. r=khuey. (d448d80726) - quick fix by revert of anticipated patch (00a093055d) - Bug 1186814 - Replace nsBaseHashtable::EnumerateRead() calls in extensions/spellcheck/ with iterators. r=ehsan. (ff78039ba0) --- .../components/contextualidentity/moz.build | 12 + .../test/browser/browser.ini | 7 + .../test/browser/browser_usercontext.js | 91 +++ .../file_reflect_cookie_into_title.html | 23 + browser/components/moz.build | 1 + config/nsinstall.c | 6 +- dom/base/nsCCUncollectableMarker.cpp | 52 +- dom/base/nsDOMAttributeMap.cpp | 35 +- dom/base/nsFrameMessageManager.cpp | 14 +- dom/base/nsGlobalWindow.cpp | 43 +- dom/base/nsPIDOMWindow.h | 1 + dom/base/nsScriptNameSpaceManager.h | 5 - dom/base/nsWindowMemoryReporter.cpp | 190 ++--- dom/base/nsWindowMemoryReporter.h | 4 +- dom/bluetooth/common/BluetoothService.cpp | 29 +- dom/events/EventStateManager.cpp | 17 +- dom/events/EventStateManager.h | 6 +- dom/html/HTMLMediaElement.h | 5 - dom/indexedDB/ActorsParent.cpp | 664 +++++----------- dom/messagechannel/MessagePortService.h | 6 - dom/smil/nsSMILCompositor.h | 4 - dom/storage/DOMStorageDBThread.cpp | 59 +- dom/xbl/nsBindingManager.cpp | 40 +- dom/xbl/nsXBLDocumentInfo.cpp | 36 +- dom/xbl/nsXBLPrototypeBinding.cpp | 249 +++--- dom/xul/nsXULPrototypeCache.cpp | 39 +- dom/xul/templates/nsXULTemplateBuilder.cpp | 25 +- dom/xul/templates/nsXULTemplateBuilder.h | 1 + .../spellcheck/hunspell/glue/mozHunspell.cpp | 53 +- gfx/thebes/gfxPlatformFontList.h | 5 - layout/base/RestyleTracker.cpp | 139 ++-- layout/style/Loader.h | 5 - layout/style/nsRuleNode.h | 7 - layout/tables/SpanningCellSorter.h | 4 - media/libcubeb/src/moz.build | 3 + media/libmkv/moz.build | 3 + media/libnestegg/src/moz.build | 2 +- media/libpng/moz.build | 3 + memory/build/mozjemalloc_compat.c | 2 +- modules/libjar/nsJAR.cpp | 72 +- modules/libmar/sign/mar_sign.c | 9 +- modules/libmar/sign/moz.build | 3 - modules/libmar/sign/nss_secutil.c | 5 +- modules/libmar/src/mar.h | 30 +- modules/libmar/src/mar_cmdline.h | 32 - modules/libmar/src/mar_read.c | 12 +- modules/libmar/src/moz.build | 3 - modules/libmar/tool/mar.c | 133 ++-- modules/libmar/tool/moz.build | 9 +- modules/libmar/verify/cryptox.c | 32 +- modules/libmar/verify/cryptox.h | 29 +- modules/libmar/verify/mar_verify.c | 164 ++-- modules/libpref/nsPrefBranch.h | 5 - netwerk/base/EventTokenBucket.cpp | 12 + netwerk/base/EventTokenBucket.h | 2 +- netwerk/base/nsSocketTransportService2.cpp | 12 +- .../protocol/http/ConnectionDiagnostics.cpp | 106 ++- netwerk/protocol/http/Http2Session.cpp | 158 ++-- netwerk/protocol/http/Http2Session.h | 16 +- netwerk/protocol/http/SpdySession31.cpp | 147 ++-- netwerk/protocol/http/SpdySession31.h | 16 +- netwerk/protocol/http/SpdyStream31.cpp | 17 +- netwerk/protocol/http/SpdyStream31.h | 4 - netwerk/protocol/http/nsCORSListenerProxy.cpp | 35 +- netwerk/protocol/http/nsHttpConnection.cpp | 5 +- netwerk/protocol/http/nsHttpConnection.h | 2 +- netwerk/protocol/http/nsHttpConnectionMgr.cpp | 744 ++++++++---------- netwerk/protocol/http/nsHttpConnectionMgr.h | 36 +- netwerk/protocol/http/nsHttpHandler.h | 13 + .../res/SubstitutingProtocolHandler.cpp | 37 +- parser/expat/lib/xmlparse.c | 21 +- storage/StatementCache.h | 13 +- toolkit/components/mediasniffer/mp3sniff.c | 3 +- .../components/places/nsFaviconService.cpp | 19 +- toolkit/components/places/nsNavBookmarks.cpp | 27 +- toolkit/components/places/nsNavHistory.cpp | 17 +- .../components/places/nsNavHistoryResult.cpp | 50 +- .../satchel/nsFormFillController.cpp | 43 +- .../components/satchel/nsFormFillController.h | 4 +- toolkit/components/telemetry/Histograms.json | 5 + toolkit/modules/ObjectUtils.jsm | 174 ++++ toolkit/modules/moz.build | 1 + .../mozapps/update/tests/TestAUSHelper.cpp | 4 +- toolkit/mozapps/update/tests/moz.build | 3 - widget/gtk/gtk3drawing.c | 23 +- xpcom/glue/nsBaseHashtable.h | 85 -- xpcom/tests/TestHashtables.cpp | 173 ++-- xpcom/tests/gtest/TestPLDHash.cpp | 4 +- 88 files changed, 1901 insertions(+), 2558 deletions(-) create mode 100644 browser/components/contextualidentity/moz.build create mode 100644 browser/components/contextualidentity/test/browser/browser.ini create mode 100644 browser/components/contextualidentity/test/browser/browser_usercontext.js create mode 100644 browser/components/contextualidentity/test/browser/file_reflect_cookie_into_title.html create mode 100644 toolkit/modules/ObjectUtils.jsm 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;