From 98fff73826b4f85468dc9fe666a0d37f0cef17b9 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Mon, 3 Apr 2017 23:13:18 +0300 Subject: [PATCH] Bug 1351303, add main thread only cache for nsIAtoms to speed up atomization, r=froydnj --HG-- extra : rebase_source : 9c67cd71c0721329eaeaaa96a295e90abc480042 --- dom/base/Element.cpp | 8 +++--- dom/base/nsAttrValue.cpp | 10 ++++---- dom/base/nsContentUtils.cpp | 16 ++++++------ xpcom/ds/nsAtomTable.cpp | 49 +++++++++++++++++++++++++++++++++++-- xpcom/ds/nsIAtom.idl | 5 ++++ 5 files changed, 70 insertions(+), 18 deletions(-) diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index bfd176189370..283caa3b56d6 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1226,7 +1226,7 @@ Element::SetAttribute(const nsAString& aName, nsAutoString nameToUse; const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse); if (!name) { - nsCOMPtr nameAtom = NS_Atomize(nameToUse); + nsCOMPtr nameAtom = NS_AtomizeMainThread(nameToUse); if (!nameAtom) { aError.Throw(NS_ERROR_OUT_OF_MEMORY); return; @@ -1308,7 +1308,7 @@ Element::GetAttributeNS(const nsAString& aNamespaceURI, return; } - nsCOMPtr name = NS_Atomize(aLocalName); + nsCOMPtr name = NS_AtomizeMainThread(aLocalName); bool hasAttr = GetAttr(nsid, name, aReturn); if (!hasAttr) { SetDOMStringToNull(aReturn); @@ -1340,7 +1340,7 @@ Element::RemoveAttributeNS(const nsAString& aNamespaceURI, const nsAString& aLocalName, ErrorResult& aError) { - nsCOMPtr name = NS_Atomize(aLocalName); + nsCOMPtr name = NS_AtomizeMainThread(aLocalName); int32_t nsid = nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI, nsContentUtils::IsChromeDoc(OwnerDoc())); @@ -1413,7 +1413,7 @@ Element::HasAttributeNS(const nsAString& aNamespaceURI, return false; } - nsCOMPtr name = NS_Atomize(aLocalName); + nsCOMPtr name = NS_AtomizeMainThread(aLocalName); return HasAttr(nsid, name); } diff --git a/dom/base/nsAttrValue.cpp b/dom/base/nsAttrValue.cpp index 2358caa11dfb..720049ea32b4 100644 --- a/dom/base/nsAttrValue.cpp +++ b/dom/base/nsAttrValue.cpp @@ -750,7 +750,7 @@ nsAttrValue::GetAsAtom() const { switch (Type()) { case eString: - return NS_Atomize(GetStringValue()); + return NS_AtomizeMainThread(GetStringValue()); case eAtom: { @@ -762,7 +762,7 @@ nsAttrValue::GetAsAtom() const { nsAutoString val; ToString(val); - return NS_Atomize(val); + return NS_AtomizeMainThread(val); } } } @@ -1275,7 +1275,7 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue) ++iter; } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter)); - nsCOMPtr classAtom = NS_Atomize(Substring(start, iter)); + nsCOMPtr classAtom = NS_AtomizeMainThread(Substring(start, iter)); if (!classAtom) { Reset(); return; @@ -1316,7 +1316,7 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue) ++iter; } while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter)); - classAtom = NS_Atomize(Substring(start, iter)); + classAtom = NS_AtomizeMainThread(Substring(start, iter)); if (!array->AppendElement(classAtom)) { Reset(); @@ -1767,7 +1767,7 @@ nsAttrValue::SetMiscAtomOrString(const nsAString* aValue) "Empty string?"); MiscContainer* cont = GetMiscContainer(); if (len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) { - nsCOMPtr atom = NS_Atomize(*aValue); + nsCOMPtr atom = NS_AtomizeMainThread(*aValue); if (atom) { cont->mStringBits = reinterpret_cast(atom.forget().take()) | eAtomBase; diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 54460bb56782..3e9d6480c734 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -3079,11 +3079,11 @@ nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver, if (*aNamespace == kNameSpaceID_Unknown) return NS_ERROR_FAILURE; - *aLocalName = NS_Atomize(Substring(colon + 1, end)).take(); + *aLocalName = NS_AtomizeMainThread(Substring(colon + 1, end)).take(); } else { *aNamespace = kNameSpaceID_None; - *aLocalName = NS_Atomize(aQName).take(); + *aLocalName = NS_AtomizeMainThread(aQName).take(); } NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY); return NS_OK; @@ -3108,7 +3108,8 @@ nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI, const char16_t* end; qName.EndReading(end); - nsCOMPtr prefix = NS_Atomize(Substring(qName.get(), colon)); + nsCOMPtr prefix = + NS_AtomizeMainThread(Substring(qName.get(), colon)); rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix, nsID, aNodeType, aNodeInfo); @@ -3168,7 +3169,7 @@ nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix, nameStart = (uriEnd + 1); if (nameEnd) { const char16_t *prefixStart = nameEnd + 1; - *aPrefix = NS_Atomize(Substring(prefixStart, pos)).take(); + *aPrefix = NS_AtomizeMainThread(Substring(prefixStart, pos)).take(); } else { nameEnd = pos; @@ -3181,7 +3182,7 @@ nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix, nameEnd = pos; *aPrefix = nullptr; } - *aLocalName = NS_Atomize(Substring(nameStart, nameEnd)).take(); + *aLocalName = NS_AtomizeMainThread(Substring(nameStart, nameEnd)).take(); } // static @@ -4056,7 +4057,8 @@ nsContentUtils::GetEventMessageAndAtom(const nsAString& aName, } *aEventMessage = eUnidentifiedEvent; - nsCOMPtr atom = NS_Atomize(NS_LITERAL_STRING("on") + aName); + nsCOMPtr atom = + NS_AtomizeMainThread(NS_LITERAL_STRING("on") + aName); sUserDefinedEvents->AppendObject(atom); mapping.mAtom = atom; mapping.mMessage = eUnidentifiedEvent; @@ -4089,7 +4091,7 @@ nsContentUtils::GetEventMessageAndAtomForListener(const nsAString& aName, if (mapping.mMaybeSpecialSVGorSMILEvent) { // Try the atom version so that we should get the right message for // SVG/SMIL. - atom = NS_Atomize(NS_LITERAL_STRING("on") + aName); + atom = NS_AtomizeMainThread(NS_LITERAL_STRING("on") + aName); msg = GetEventMessage(atom); } else { atom = mapping.mAtom; diff --git a/xpcom/ds/nsAtomTable.cpp b/xpcom/ds/nsAtomTable.cpp index d274c5aaac69..205714f30203 100644 --- a/xpcom/ds/nsAtomTable.cpp +++ b/xpcom/ds/nsAtomTable.cpp @@ -358,17 +358,28 @@ static const PLDHashTableOps AtomTableOps = { //---------------------------------------------------------------------- +#define RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE 31 +static nsIAtom* + sRecentlyUsedMainThreadAtoms[RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE] = {}; + void DynamicAtom::GCAtomTable() { - MutexAutoLock lock(*gAtomTableLock); - GCAtomTableLocked(lock, GCKind::RegularOperation); + if (NS_IsMainThread()) { + MutexAutoLock lock(*gAtomTableLock); + GCAtomTableLocked(lock, GCKind::RegularOperation); + } } void DynamicAtom::GCAtomTableLocked(const MutexAutoLock& aProofOfLock, GCKind aKind) { + MOZ_ASSERT(NS_IsMainThread()); + for (uint32_t i = 0; i < RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE; ++i) { + sRecentlyUsedMainThreadAtoms[i] = nullptr; + } + uint32_t removedCount = 0; // Use a non-atomic temporary for cheaper increments. nsAutoCString nonZeroRefcountAtoms; uint32_t nonZeroRefcountAtomsCount = 0; @@ -719,6 +730,40 @@ NS_Atomize(const nsAString& aUTF16String) return atom.forget(); } +already_AddRefed +NS_AtomizeMainThread(const nsAString& aUTF16String) +{ + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr retVal; + uint32_t hash; + AtomTableKey key(aUTF16String.Data(), aUTF16String.Length(), &hash); + uint32_t index = hash % RECENTLY_USED_MAIN_THREAD_ATOM_CACHE_SIZE; + nsIAtom* atom = + sRecentlyUsedMainThreadAtoms[index]; + if (atom) { + uint32_t length = atom->GetLength(); + if (length == key.mLength && + (memcmp(atom->GetUTF16String(), + key.mUTF16String, length * sizeof(char16_t)) == 0)) { + retVal = atom; + return retVal.forget(); + } + } + + MutexAutoLock lock(*gAtomTableLock); + AtomTableEntry* he = static_cast(gAtomTable->Add(&key)); + + if (he->mAtom) { + retVal = he->mAtom; + } else { + retVal = DynamicAtom::Create(aUTF16String, hash); + he->mAtom = retVal; + } + + sRecentlyUsedMainThreadAtoms[index] = retVal; + return retVal.forget(); +} + nsrefcnt NS_GetNumberOfAtoms(void) { diff --git a/xpcom/ds/nsIAtom.idl b/xpcom/ds/nsIAtom.idl index 83dc939efe36..f1085089bbc1 100644 --- a/xpcom/ds/nsIAtom.idl +++ b/xpcom/ds/nsIAtom.idl @@ -125,6 +125,11 @@ extern already_AddRefed NS_Atomize(const char16_t* aUTF16String); */ extern already_AddRefed NS_Atomize(const nsAString& aUTF16String); +/** + * An optimized version of the method above for the main thread. + */ +extern already_AddRefed NS_AtomizeMainThread(const nsAString& aUTF16String); + /** * Return a count of the total number of atoms currently * alive in the system.