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)
This commit is contained in:
2023-09-19 16:39:50 +08:00
parent 2e9d0efbca
commit 6ecfad14f8
88 changed files with 1901 additions and 2558 deletions
@@ -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')
@@ -0,0 +1,7 @@
[DEFAULT]
skip-if = buildapp == "mulet"
support-files =
file_reflect_cookie_into_title.html
[browser_usercontext.js]
skip-if = e10s
@@ -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);
}
});
@@ -0,0 +1,23 @@
<html>
<head>
<meta charset="UTF-8">
<title>title not set</title>
<script>
// if we have a query string, use it to set the cookie and localStorage
if (window.location.search.length > 0) {
let context_name = window.location.search.substr(1);
document.cookie = "userContextId=" + context_name;
localStorage.setItem("userContext", context_name);
}
// get the cookie
let [name, val] = document.cookie.split("=");
// set the title to reflect the cookie and local storage values we find
document.title = "cookie=" + val + "|"
+ "local=" + localStorage.getItem("userContext");
</script>
</head>
<body></body>
</html>
+1
View File
@@ -6,6 +6,7 @@
DIRS += [
'about',
'contextualidentity',
'certerror',
'dirprovider',
'downloads',
+2 -4
View File
@@ -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;
+18 -34
View File
@@ -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<TraceClosure*>(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<XULDocument*>(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<XULDocument*>(doc);
xulDoc->TraceProtos(aTrc, aGCNumber);
}
#endif
}
}
}
}
+8 -27
View File
@@ -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<Attr>& 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<Attr>& aData,
void* aUserArg)
{
nsCycleCollectionTraversalCallback *cb =
static_cast<nsCycleCollectionTraversalCallback*>(aUserArg);
cb->NoteXPCOMChild(static_cast<nsINode*>(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<nsINode*>(iter.Data().get()));
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+4 -10
View File
@@ -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;
+17 -26
View File
@@ -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<JSObject*>& 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<JSObject*>& aData, void* aClosure)
{
TraceData* data = static_cast<TraceData*>(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<JSObject*>& 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");
+1
View File
@@ -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"
-5
View File
@@ -180,11 +180,6 @@ public:
aConstructorEnabled);
}
typedef PLDHashOperator
(* NameEnumerator)(const nsAString& aGlobalName,
const nsGlobalNameStruct& aGlobalNameStruct,
void* aClosure);
class NameIterator : public PLDHashTable::Iterator
{
public:
+77 -113
View File
@@ -113,10 +113,6 @@ nsWindowMemoryReporter::Init()
nsCOMPtr<nsIObserverService> 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<nsIURI>
GetWindowURI(nsIDOMWindow *aWindow)
{
@@ -169,7 +171,7 @@ AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize)
if (uri) {
if (aAnonymize && !aWindow->IsChromeWindow()) {
aStr.AppendPrintf("<anonymized-%d>", aWindow->WindowID());
aStr.AppendPrintf("<anonymized-%llu>", 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<nsGlobalWindow> > 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<nsIDOMEventTarget*>(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<TimeStamp*>(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<nsCStringHashKey> *nonDetachedDomains;
nsTHashtable<nsUint64HashKey> *ghostWindowIDs;
nsIEffectiveTLDService *tldService;
uint32_t ghostTimeout;
TimeStamp now;
};
static PLDHashOperator
CheckForGhostWindowsEnumerator(nsISupports *aKey, TimeStamp& aTimeStamp,
void* aClosure)
{
CheckForGhostWindowsEnumeratorData *data =
static_cast<CheckForGhostWindowsEnumeratorData*>(aClosure);
nsWeakPtr weakKey = do_QueryInterface(aKey);
nsCOMPtr<nsPIDOMWindow> 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<nsIDOMWindow> 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<nsIURI> 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<nsPIDOMWindow> 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<nsPIDOMWindow> 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<nsPIDOMWindow> 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<nsIURI> 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<nsUint64HashKey> ghostWindows;
+3 -1
View File
@@ -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();
/**
+13 -16
View File
@@ -294,28 +294,25 @@ BluetoothService::UnregisterBluetoothSignalHandler(
}
}
PLDHashOperator
RemoveAllSignalHandlers(const nsAString& aKey,
nsAutoPtr<BluetoothSignalObserverList>& aData,
void* aUserArg)
{
BluetoothSignalObserver* handler =
static_cast<BluetoothSignalObserver*>(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<BluetoothSignalObserverList>& 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
+9 -8
View File
@@ -5024,19 +5024,17 @@ EventStateManager::SetContentState(nsIContent* aContent, EventStates aState)
return true;
}
PLDHashOperator
void
EventStateManager::ResetLastOverForContent(
const uint32_t& aIdx,
RefPtr<OverOutElementsWrapper>& aElemWrapper,
void* aClosure)
nsIContent* aContent)
{
nsIContent* content = static_cast<nsIContent*>(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
+3 -3
View File
@@ -882,9 +882,9 @@ private:
nsIContent* aStopBefore,
EventStates aState,
bool aAddState);
static PLDHashOperator ResetLastOverForContent(const uint32_t& aIdx,
RefPtr<OverOutElementsWrapper>& aChunk,
void* aClosure);
static void ResetLastOverForContent(const uint32_t& aIdx,
RefPtr<OverOutElementsWrapper>& aChunk,
nsIContent* aClosure);
void PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
nsEventStatus& aStatus,
bool dispatchedToContentProcess);
-5
View File
@@ -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<const MetadataTags> mTags;
// URI of the resource we're attempting to load. This stores the value we
+195 -469
View File
@@ -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 <class Enumerable>
static void
MatchHelper(const Enumerable& aEnumerable, SelfType* aClosure)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(aKey);
MOZ_ASSERT(aValue);
MOZ_ASSERT(aClosure);
auto* closure = static_cast<SelfType*>(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<RefPtr<Database>> 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<bool> 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<Helper*>(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<bool> 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<DeleteObjectStoreOp> 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<bool> 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<Helper*>(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<bool> 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<DeleteIndexOp> 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<AbortOperationsRunnable> 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<RefPtr<Database>> 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<AbortOperationsRunnable> 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<RefPtr<Database>> 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<AbortOperationsRunnable*>(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<AbortOperationsRunnable*>(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<UniqueIndexTable>& 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<UniqueIndexTable*>(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<FullObjectStoreMetadata> objectStoreMetadata =
const RefPtr<FullObjectStoreMetadata> 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<nsCString> databaseIds;
databaseIds.AppendElement(mDatabaseId);
mState = State::WaitingForTransactionsToComplete;
RefPtr<WaitForTransactionsHelper> 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<Helper*>(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<ObjectStoreSpec*> 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<Helper*>(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<Helper*>(aClosure);
MOZ_ASSERT(!helper->mCurrentOtherIndexTable);
auto* otherObjectStore =
MetadataNameOrIdMatcher<FullObjectStoreMetadata>::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<IndexTable*> 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<Helper*>(aClosure);
MOZ_ASSERT(helper->mCurrentOtherIndexTable);
auto* otherIndex =
MetadataNameOrIdMatcher<FullIndexMetadata>::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<FullObjectStoreMetadata>::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<FullIndexMetadata>::
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
-6
View File
@@ -51,12 +51,6 @@ private:
class MessagePortServiceData;
#ifdef DEBUG
static PLDHashOperator
CloseAllDebugCheck(const nsID& aID, MessagePortServiceData* aData,
void* aPtr);
#endif
nsClassHashtable<nsIDHashKey, MessagePortServiceData> mPorts;
};
-4
View File
@@ -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;
+22 -37
View File
@@ -1065,26 +1065,6 @@ DOMStorageDBThread::PendingOperations::HasTasks()
namespace {
PLDHashOperator
ForgetUpdatesForScope(const nsACString& aMapping,
nsAutoPtr<DOMStorageDBThread::DBOperation>& aPendingTask,
void* aArg)
{
DOMStorageDBThread::DBOperation* newOp = static_cast<DOMStorageDBThread::DBOperation*>(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<DBOperation>& 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<DOMStorageDBThread::DBOperation>& aOperation, void* aArg)
{
nsTArray<nsAutoPtr<DOMStorageDBThread::DBOperation> >* tasks =
static_cast<nsTArray<nsAutoPtr<DOMStorageDBThread::DBOperation> >*>(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();
+12 -28
View File
@@ -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<nsCycleCollectionTraversalCallback*>(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<nsCycleCollectionTraversalCallback*>(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.
+9 -27
View File
@@ -80,13 +80,6 @@ UnmarkXBLJSObject(JS::GCCellPtr aPtr, const char* aName, void* aClosure)
JS::ExposeObjectToActiveJS(&aPtr.as<JSObject>());
}
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();
}
}
}
+91 -158
View File
@@ -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<nsXBLAttrChangeData*>(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<nsTextNode> 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<nsXBLAttrChangeData*>(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<nsTextNode> 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<nsIObjectOutputStream *>(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<WriteAttributeData *>(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<WriteAttributeData *>(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);
+10 -29
View File
@@ -579,41 +579,22 @@ nsXULPrototypeCache::BeginCaching(nsIURI* aURI)
return NS_OK;
}
static PLDHashOperator
MarkXBLInCCGeneration(nsIURI* aKey, RefPtr<nsXBLDocumentInfo> &aDocInfo,
void* aClosure)
{
uint32_t* gen = static_cast<uint32_t*>(aClosure);
aDocInfo->MarkInCCGeneration(*gen);
return PL_DHASH_NEXT;
}
static PLDHashOperator
MarkXULInCCGeneration(nsIURI* aKey, RefPtr<nsXULPrototypeDocument> &aDoc,
void* aClosure)
{
uint32_t* gen = static_cast<uint32_t*>(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<JSScript*>& aScript, void* aClosure)
{
JSTracer* trc = static_cast<JSTracer*>(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<JSScript*>& script = iter.Data();
JS::TraceEdge(aTrc, &script, "nsXULPrototypeCache script");
}
}
+14 -11
View File
@@ -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;
+1
View File
@@ -41,6 +41,7 @@ class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
public nsStubDocumentObserver
{
void CleanUp(bool aIsFinal);
void DestroyMatchMap();
public:
nsXULTemplateBuilder();
@@ -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;
}
-5
View File
@@ -308,11 +308,6 @@ protected:
void GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult);
static PLDHashOperator
HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
RefPtr<gfxFontFamily>& aFamilyEntry,
void* aUserArg);
virtual void GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames);
nsILanguageAtomService* GetLangService();
+63 -76
View File
@@ -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<RestyleTracker::RestyleData>& aData,
void* aRestyleCollector)
{
dom::Element* element =
static_cast<dom::Element*>(aElement);
RestyleCollector* collector =
static_cast<RestyleCollector*>(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<dom::Element*>(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)
-5
View File
@@ -441,11 +441,6 @@ public:
private:
friend class SheetLoadData;
static PLDHashOperator
RemoveEntriesWithURI(URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey,
RefPtr<CSSStyleSheet>& 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
-7
View File
@@ -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<nsRuleNode*>& 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());
}
-4
View File
@@ -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 */
+3
View File
@@ -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
+3
View File
@@ -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
+1 -1
View File
@@ -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
+3
View File
@@ -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
+1 -1
View File
@@ -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);
+28 -44
View File
@@ -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<nsJAR**>(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<ZipFindData*>(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) {
+5 -4
View File
@@ -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;
-3
View File
@@ -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
+4 -1
View File
@@ -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");
+24 -6
View File
@@ -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.
-32
View File
@@ -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
+7 -5
View File
@@ -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,
-3
View File
@@ -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
+74 -59
View File
@@ -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();
+1 -8
View File
@@ -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']:
+17 -15
View File
@@ -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;
}
+13 -16
View File
@@ -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
+57 -107
View File
@@ -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]);
}
-5
View File
@@ -216,11 +216,6 @@ protected:
const char *getPrefName(const char *aPrefName);
void freeObserverList(void);
friend PLDHashOperator
FreeObserverFunc(PrefCallback *aKey,
nsAutoPtr<PrefCallback> &aCallback,
void *aArgs);
private:
int32_t mPrefRootLength;
nsCString mPrefRoot;
+12
View File
@@ -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)
{
+1 -1
View File
@@ -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);
+11 -1
View File
@@ -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()));
+50 -56
View File
@@ -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<nsConnectionEntry>& 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<nsConnectionEntry> &ent,
void *closure)
{
nsHttpConnectionMgr *self = static_cast<nsHttpConnectionMgr *>(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)
{
+63 -95
View File
@@ -134,51 +134,27 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
mPreviousPingThreshold = mPingThreshold;
}
PLDHashOperator
Http2Session::ShutdownEnumerator(nsAHttpTransaction *key,
nsAutoPtr<Http2Stream> &stream,
void *closure)
void
Http2Session::Shutdown()
{
Http2Session *self = static_cast<Http2Session *>(closure);
nsresult result;
for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<Http2Stream> &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<Http2Stream> &stream,
void *closure)
{
Http2Session *self = static_cast<Http2Session *>(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<Http2Stream> &stream,
void *closure)
{
int32_t delta = *(static_cast<int32_t *>(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<Http2Stream>& 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<Http2Stream> &stream,
void *closure)
{
Http2Session *self = static_cast<Http2Session *>(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<Http2Stream>& 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<Http2Stream> &stream,
void *closure)
{
nsTArray<RefPtr<nsAHttpTransaction> > *list =
static_cast<nsTArray<RefPtr<nsAHttpTransaction> > *>(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<RefPtr<nsAHttpTransaction> > &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;
}
+1 -15
View File
@@ -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<Http2Stream> &,
void *);
static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
nsAutoPtr<Http2Stream> &,
void *);
static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
nsAutoPtr<Http2Stream> &,
void *);
static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
nsAutoPtr<Http2Stream> &,
void *);
void Shutdown();
// This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
// from the first transaction on this session. That object contains the
+60 -87
View File
@@ -91,45 +91,25 @@ SpdySession31::SpdySession31(nsISocketTransport *aSocketTransport)
mPingThreshold = gHttpHandler->SpdyPingThreshold();
}
PLDHashOperator
SpdySession31::ShutdownEnumerator(nsAHttpTransaction *key,
nsAutoPtr<SpdyStream31> &stream,
void *closure)
void
SpdySession31::Shutdown()
{
SpdySession31 *self = static_cast<SpdySession31 *>(closure);
for (auto iter = mStreamTransactionHash.Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<SpdyStream31>& 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<SpdyStream31> &stream,
void *closure)
{
SpdySession31 *self = static_cast<SpdySession31 *>(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<SpdyStream31> &stream,
void *closure)
{
int32_t delta = *(static_cast<int32_t *>(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<SpdyStream31>& 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<SpdyStream31> &stream,
void *closure)
{
SpdySession31 *self = static_cast<SpdySession31 *>(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<SpdyStream31>& 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<SpdyStream31> &stream,
void *closure)
{
nsTArray<RefPtr<nsAHttpTransaction> > *list =
static_cast<nsTArray<RefPtr<nsAHttpTransaction> > *>(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<RefPtr<nsAHttpTransaction> > &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;
}
+1 -15
View File
@@ -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<SpdyStream31> &,
void *);
static PLDHashOperator GoAwayEnumerator(nsAHttpTransaction *,
nsAutoPtr<SpdyStream31> &,
void *);
static PLDHashOperator UpdateServerRwinEnumerator(nsAHttpTransaction *,
nsAutoPtr<SpdyStream31> &,
void *);
static PLDHashOperator RestartBlockedOnRwinEnumerator(nsAHttpTransaction *,
nsAutoPtr<SpdyStream31> &,
void *);
void Shutdown();
// This is intended to be nsHttpConnectionMgr:nsConnectionHandle taken
// from the first transaction on this session. That object contains the
+4 -13
View File
@@ -228,18 +228,6 @@ SpdyStream31::WriteSegments(nsAHttpSegmentWriter *writer,
return rv;
}
PLDHashOperator
SpdyStream31::hdrHashEnumerate(const nsACString &key,
nsAutoPtr<nsCString> &value,
void *closure)
{
SpdyStream31 *self = static_cast<SpdyStream31 *>(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
-4
View File
@@ -144,10 +144,6 @@ protected:
private:
friend class nsAutoPtr<SpdyStream31>;
static PLDHashOperator hdrHashEnumerate(const nsACString &,
nsAutoPtr<nsCString> &,
void *);
nsresult ParseHttpRequestHeaders(const char *, uint32_t, uint32_t *);
nsresult GenerateSynFrame();
+11 -24
View File
@@ -183,10 +183,6 @@ public:
void Clear();
private:
static PLDHashOperator
RemoveExpiredEntries(const nsACString& aKey, nsAutoPtr<CacheEntry>& 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<CacheEntry>& 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<CacheEntry>& aValue,
void* aUserData)
{
TimeStamp* now = static_cast<TimeStamp*>(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,
+3 -2
View File
@@ -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;
+1 -1
View File
@@ -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
+338 -406
View File
@@ -532,25 +532,21 @@ nsHttpConnectionMgr::UpdateRequestTokenBucket(EventTokenBucket *aBucket)
0, aBucket);
}
PLDHashOperator
nsHttpConnectionMgr::RemoveDeadConnections(const nsACString &key,
nsAutoPtr<nsConnectionEntry> &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<nsConnectionEntry>& 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<nsConnectionEntry> &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<nsConnectionEntry> &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<nsConnectionEntry> &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<nsConnectionEntry> &ent,
void *closure)
{
if (!ent->mUsingSpdy)
return PL_DHASH_NEXT;
nsHttpConnectionMgr *self = static_cast<nsHttpConnectionMgr *>(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<nsConnectionEntry> &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<nsConnectionEntry> &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<nsConnectionEntry> &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<nsHttpConnection> 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<nsConnectionEntry> &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<nsConnectionEntry> &ent,
void *closure)
{
nsHttpConnectionMgr *self = static_cast<nsHttpConnectionMgr *>(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<nsConnectionEntry> &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<nsConnectionEntry> &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<nsConnectionEntry> &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<nsConnectionEntry>& 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<nsConnectionEntry>& 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<nsConnectionEntry>& 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<nsHttpConnection> 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<nsConnectionEntry>& 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<nsHttpConnectionInfo *>(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<nsConnectionEntry>& 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<nsConnectionEntry> &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<nsIOutputStream> 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<nsConnectionEntry> &ent,
void *aArg)
{
if (ent->mConnInfo->GetPrivate())
return PL_DHASH_NEXT;
nsTArray<HttpRetParams> *args = static_cast<nsTArray<HttpRetParams> *> (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<HttpRetParams> *aArg)
{
mCT.Enumerate(ReadConnectionEntry, aArg);
for (auto iter = mCT.Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<nsConnectionEntry>& 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;
}
+7 -29
View File
@@ -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<nsConnectionEntry> &, void *);
static PLDHashOperator ProcessAllTransactionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
static PLDHashOperator PruneDeadConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
static PLDHashOperator ShutdownPassCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
static PLDHashOperator PurgeExcessIdleConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
static PLDHashOperator PurgeExcessSpdyConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
static PLDHashOperator ClosePersistentConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
static PLDHashOperator VerifyTrafficCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
static PLDHashOperator PruneNoTrafficCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, 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<nsConnectionEntry> &ent,
void *closure);
// used to marshall events to the socket transport thread.
nsresult PostEvent(nsConnEventHandler handler,
@@ -636,24 +626,12 @@ private:
//
nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;
static PLDHashOperator ReadConnectionEntry(const nsACString &key,
nsAutoPtr<nsConnectionEntry> &ent,
void *aArg);
static PLDHashOperator RemoveDeadConnections(const nsACString &key,
nsAutoPtr<nsConnectionEntry> &ent,
void *aArg);
// Read Timeout Tick handlers
void TimeoutTick();
static PLDHashOperator TimeoutTickCB(const nsACString &key,
nsAutoPtr<nsConnectionEntry> &ent,
void *closure);
// For diagnostics
void OnMsgPrintDiagnostics(int32_t, ARefBase *);
static PLDHashOperator PrintDiagnosticsCB(const nsACString &key,
nsAutoPtr<nsConnectionEntry> &ent,
void *closure);
nsCString mLogData;
};
+13
View File
@@ -29,6 +29,8 @@ class nsISiteSecurityService;
class nsIStreamConverterService;
class nsITimer;
extern mozilla::Atomic<PRThread*, mozilla::Relaxed> 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<Tickler> mWifiTickler;
void TickleWifi(nsIInterfaceRequestor *cb);
@@ -112,36 +112,19 @@ SubstitutingProtocolHandler::ConstructInternal()
// IPC marshalling.
//
struct EnumerateSubstitutionArg
{
EnumerateSubstitutionArg(nsCString& aScheme, nsTArray<SubstitutionMapping>& aMappings)
: mScheme(aScheme), mMappings(aMappings) {}
nsCString& mScheme;
nsTArray<SubstitutionMapping>& mMappings;
};
static PLDHashOperator
EnumerateSubstitution(const nsACString& aKey,
nsIURI* aURI,
void* aArg)
{
auto arg = static_cast<EnumerateSubstitutionArg*>(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<SubstitutionMapping>& aMappings)
{
EnumerateSubstitutionArg arg(mScheme, aMappings);
mSubstitutions.EnumerateRead(&EnumerateSubstitution, &arg);
for (auto iter = mSubstitutions.ConstIter(); !iter.Done(); iter.Next()) {
nsCOMPtr<nsIURI> 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
+16 -5
View File
@@ -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)
+3 -10
View File
@@ -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<StatementType>
CreateStatement(const nsACString& aQuery);
static
PLDHashOperator
FinalizeCachedStatements(const nsACString& aKey,
nsCOMPtr<StatementType>& aStatement,
void*)
{
(void)aStatement->Finalize();
return PL_DHASH_NEXT;
}
nsInterfaceHashtable<nsCStringHashKey, StatementType> mCachedStatements;
nsCOMPtr<mozIStorageConnection>& mConnection;
+1 -2
View File
@@ -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)) {
+6 -13
View File
@@ -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<uint32_t*>(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;
}
+12 -15
View File
@@ -46,19 +46,6 @@ struct keywordSearchData
nsString keyword;
};
PLDHashOperator
SearchBookmarkForKeyword(nsTrimInt64HashKey::KeyType aKey,
const nsString aValue,
void* aUserArg)
{
keywordSearchData* data = reinterpret_cast<keywordSearchData*>(aUserArg);
if (data->keyword.Equals(aValue)) {
data->itemId = aKey;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
template<typename Method, typename DataType>
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<mozIStorageAsyncStatement> 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.
+5 -12
View File
@@ -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<int64_t*>(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<void*>(&threshold));
for (auto iter = hashTable->Iter(); !iter.Done(); iter.Next()) {
if (iter.Data() < threshold) {
iter.Remove();
}
}
}
@@ -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<nsCycleCollectionTraversalCallback*>(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
@@ -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<nsIDocument> 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<PwmgrInputsEnumData*>(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<nsINode*>(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<nsINode*>(key)->RemoveMutationObserver(this);
}
iter.Remove();
}
return PL_DHASH_REMOVE;
}
return PL_DHASH_NEXT;
}
void
@@ -1134,8 +1124,7 @@ nsFormFillController::RemoveWindowListeners(nsIDOMWindow *aWindow)
nsCOMPtr<nsIDOMDocument> domDoc;
aWindow->GetDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
PwmgrInputsEnumData ed(this, doc);
mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
RemoveForDocument(doc);
nsCOMPtr<nsPIDOMWindow> privateDOMWindow(do_QueryInterface(aWindow));
EventTarget* target = nullptr;
@@ -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 //////////////////////////////////////////
@@ -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",
+174
View File
@@ -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;
}
});
}
+1
View File
@@ -34,6 +34,7 @@ EXTRA_JS_MODULES += [
'LoadContextInfo.jsm',
'Log.jsm',
'NewTabUtils.jsm',
'ObjectUtils.jsm',
'PageMenu.jsm',
'PageMetadata.jsm',
'PermissionsUtils.jsm',
@@ -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"))) {
-3
View File
@@ -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
+11 -12
View File
@@ -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;
}
-85
View File
@@ -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 KeyClass, class DataType, class UserDataType>
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<EntryType*>(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<EntryType*>(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()) {
+76 -97
View File
@@ -170,32 +170,6 @@ testTHashtable(nsTHashtable<EntityToUnicodeEntry>& 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<TestUniChar>& 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<IFoo>& 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<IFoo> 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<IFoo> 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<IFoo> 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<IFoo> 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<IFoo> 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);
}
+2 -2
View File
@@ -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;