Bug 613595. Speed up the cache-hit case for getElementsByTagName. r=peterv

This commit is contained in:
Boris Zbarsky 2010-11-23 14:10:56 -05:00
Родитель 5c09bffd17
Коммит 4193bc442a
6 изменённых файлов: 77 добавлений и 81 удалений

Просмотреть файл

@ -203,24 +203,20 @@ ContentListHashtableMatchEntry(PLDHashTable *table,
{
const ContentListHashEntry *e =
static_cast<const ContentListHashEntry *>(entry);
const nsContentListKey* list1 = e->mContentList->GetKey();
const nsContentListKey* list2 = static_cast<const nsContentListKey *>(key);
const nsContentList* list = e->mContentList;
const nsContentListKey* ourKey = static_cast<const nsContentListKey *>(key);
return list1->Equals(*list2);
return list->MatchesKey(*ourKey);
}
already_AddRefed<nsContentList>
NS_GetContentList(nsINode* aRootNode,
PRInt32 aMatchNameSpaceId,
nsIAtom* aHTMLMatchAtom,
nsIAtom* aXMLMatchAtom)
const nsAString& aTagname)
{
NS_ASSERTION(aRootNode, "content list has to have a root");
if(!aXMLMatchAtom)
aXMLMatchAtom = aHTMLMatchAtom;
nsContentList* list = nsnull;
static PLDHashTableOps hash_table_ops =
@ -249,15 +245,14 @@ NS_GetContentList(nsINode* aRootNode,
ContentListHashEntry *entry = nsnull;
// First we look in our hashtable. Then we create a content list if needed
if (gContentListHashTable.ops) {
nsContentListKey hashKey(aRootNode, aHTMLMatchAtom,
aXMLMatchAtom, aMatchNameSpaceId);
nsContentListKey hashKey(aRootNode, aMatchNameSpaceId, aTagname);
// A PL_DHASH_ADD is equivalent to a PL_DHASH_LOOKUP for cases
// when the entry is already in the hashtable.
entry = static_cast<ContentListHashEntry *>
(PL_DHashTableOperate(&gContentListHashTable,
&hashKey,
PL_DHASH_ADD));
&hashKey,
PL_DHASH_ADD));
if (entry)
list = entry->mContentList;
}
@ -265,8 +260,17 @@ NS_GetContentList(nsINode* aRootNode,
if (!list) {
// We need to create a ContentList and add it to our new entry, if
// we have an entry
nsCOMPtr<nsIAtom> xmlAtom = do_GetAtom(aTagname);
nsCOMPtr<nsIAtom> htmlAtom;
if (aMatchNameSpaceId == kNameSpaceID_Unknown) {
nsAutoString lowercaseName;
nsContentUtils::ASCIIToLower(aTagname, lowercaseName);
htmlAtom = do_GetAtom(lowercaseName);
} else {
htmlAtom = xmlAtom;
}
list = new nsContentList(aRootNode, aMatchNameSpaceId,
aHTMLMatchAtom, aXMLMatchAtom);
htmlAtom, xmlAtom);
if (entry) {
entry->mContentList = list;
}
@ -391,7 +395,10 @@ nsContentList::nsContentList(nsINode* aRootNode,
nsIAtom* aXMLMatchAtom,
PRBool aDeep)
: nsBaseContentList(),
nsContentListKey(aRootNode, aHTMLMatchAtom, aXMLMatchAtom, aMatchNameSpaceId),
mRootNode(aRootNode),
mMatchNameSpaceId(aMatchNameSpaceId),
mHTMLMatchAtom(aHTMLMatchAtom),
mXMLMatchAtom(aXMLMatchAtom),
mFunc(nsnull),
mDestroyFunc(nsnull),
mData(nsnull),
@ -419,12 +426,15 @@ nsContentList::nsContentList(nsINode* aRootNode,
PRInt32 aMatchNameSpaceId,
PRBool aFuncMayDependOnAttr)
: nsBaseContentList(),
nsContentListKey(aRootNode, aMatchAtom, aMatchAtom, aMatchNameSpaceId),
mRootNode(aRootNode),
mMatchNameSpaceId(aMatchNameSpaceId),
mHTMLMatchAtom(aMatchAtom),
mXMLMatchAtom(aMatchAtom),
mFunc(aFunc),
mDestroyFunc(aDestroyFunc),
mData(aData),
mMatchAll(PR_FALSE),
mState(LIST_DIRTY),
mMatchAll(PR_FALSE),
mDeep(aDeep),
mFuncMayDependOnAttr(aFuncMayDependOnAttr)
{
@ -907,8 +917,10 @@ nsContentList::RemoveFromHashtable()
if (!gContentListHashTable.ops)
return;
nsDependentAtomString str(mXMLMatchAtom);
nsContentListKey key(mRootNode, mMatchNameSpaceId, str);
PL_DHashTableOperate(&gContentListHashTable,
GetKey(),
&key,
PL_DHASH_REMOVE);
if (gContentListHashTable.entryCount == 0) {

Просмотреть файл

@ -140,53 +140,35 @@ public:
* Class that's used as the key to hash nsContentList implementations
* for fast retrieval
*/
class nsContentListKey
struct nsContentListKey
{
public:
nsContentListKey(nsINode* aRootNode,
nsIAtom* aHTMLMatchAtom,
nsIAtom* aXMLMatchAtom,
PRInt32 aMatchNameSpaceId)
: mHTMLMatchAtom(aHTMLMatchAtom),
mXMLMatchAtom(aXMLMatchAtom),
PRInt32 aMatchNameSpaceId,
const nsAString& aTagname)
: mRootNode(aRootNode),
mMatchNameSpaceId(aMatchNameSpaceId),
mRootNode(aRootNode)
mTagname(aTagname)
{
NS_ASSERTION(!aXMLMatchAtom == !aHTMLMatchAtom, "Either neither or both atoms should be null");
}
nsContentListKey(const nsContentListKey& aContentListKey)
: mHTMLMatchAtom(aContentListKey.mHTMLMatchAtom),
mXMLMatchAtom(aContentListKey.mXMLMatchAtom),
: mRootNode(aContentListKey.mRootNode),
mMatchNameSpaceId(aContentListKey.mMatchNameSpaceId),
mRootNode(aContentListKey.mRootNode)
mTagname(aContentListKey.mTagname)
{
}
PRBool Equals(const nsContentListKey& aContentListKey) const
{
NS_ASSERTION(mHTMLMatchAtom == aContentListKey.mHTMLMatchAtom
|| mXMLMatchAtom != aContentListKey.mXMLMatchAtom, "HTML atoms should match if XML atoms match");
return
mXMLMatchAtom == aContentListKey.mXMLMatchAtom &&
mMatchNameSpaceId == aContentListKey.mMatchNameSpaceId &&
mRootNode == aContentListKey.mRootNode;
}
inline PRUint32 GetHash(void) const
{
return
NS_PTR_TO_INT32(mXMLMatchAtom.get()) ^
HashString(mTagname) ^
(NS_PTR_TO_INT32(mRootNode) << 12) ^
(mMatchNameSpaceId << 24);
}
protected:
nsCOMPtr<nsIAtom> mHTMLMatchAtom;
nsCOMPtr<nsIAtom> mXMLMatchAtom;
PRInt32 mMatchNameSpaceId;
nsINode* mRootNode; // Weak ref
nsINode* const mRootNode; // Weak ref
const PRInt32 mMatchNameSpaceId;
const nsAString& mTagname;
};
/**
@ -214,7 +196,6 @@ protected:
* tree based on some criterion.
*/
class nsContentList : public nsBaseContentList,
protected nsContentListKey,
public nsIHTMLCollection,
public nsStubMutationObserver,
public nsWrapperCache
@ -290,11 +271,6 @@ public:
NS_HIDDEN_(nsIContent*) Item(PRUint32 aIndex, PRBool aDoFlush);
NS_HIDDEN_(nsIContent*) NamedItem(const nsAString& aName, PRBool aDoFlush);
nsContentListKey* GetKey() {
return static_cast<nsContentListKey*>(this);
}
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
@ -318,6 +294,19 @@ public:
return static_cast<nsContentList*>(list);
}
PRBool MatchesKey(const nsContentListKey& aKey) const
{
// The root node is most commonly the same: the document. And the
// most common namespace id is kNameSpaceID_Unknown. So check the
// string first.
NS_PRECONDITION(mXMLMatchAtom,
"How did we get here with a null match atom on our list?");
return
mXMLMatchAtom->Equals(aKey.mTagname) &&
mRootNode == aKey.mRootNode &&
mMatchNameSpaceId == aKey.mMatchNameSpaceId;
}
protected:
/**
* Returns whether the element matches our criterion
@ -388,6 +377,11 @@ protected:
RemoveFromHashtable();
}
nsINode* mRootNode; // Weak ref
PRInt32 mMatchNameSpaceId;
nsCOMPtr<nsIAtom> mHTMLMatchAtom;
nsCOMPtr<nsIAtom> mXMLMatchAtom;
/**
* Function to use to determine whether a piece of content matches
* our criterion
@ -494,11 +488,15 @@ protected:
nsString mString;
};
// If aMatchNameSpaceId is kNameSpaceID_Unknown, this will return a
// content list which matches ASCIIToLower(aTagname) against HTML
// elements in HTML documents and aTagname against everything else.
// For any other value of aMatchNameSpaceId, the list will match
// aTagname against all elements.
already_AddRefed<nsContentList>
NS_GetContentList(nsINode* aRootNode,
PRInt32 aMatchNameSpaceId,
nsIAtom* aHTMLMatchAtom,
nsIAtom* aXMLMatchAtom = nsnull);
const nsAString& aTagname);
already_AddRefed<nsContentList>
NS_GetFuncStringContentList(nsINode* aRootNode,

Просмотреть файл

@ -4579,17 +4579,6 @@ nsDocument::CreateEntityReference(const nsAString& aName,
return NS_OK;
}
already_AddRefed<nsContentList>
nsDocument::GetElementsByTagName(const nsAString& aTagname)
{
nsAutoString lowercaseName;
nsContentUtils::ASCIIToLower(aTagname, lowercaseName);
nsCOMPtr<nsIAtom> xmlAtom = do_GetAtom(aTagname);
nsCOMPtr<nsIAtom> htmlAtom = do_GetAtom(lowercaseName);
return NS_GetContentList(this, kNameSpaceID_Unknown, htmlAtom, xmlAtom);
}
NS_IMETHODIMP
nsDocument::GetElementsByTagName(const nsAString& aTagname,
nsIDOMNodeList** aReturn)
@ -4615,9 +4604,9 @@ nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
NS_ENSURE_SUCCESS(rv, nsnull);
}
nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aLocalName);
NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
return NS_GetContentList(this, nameSpaceId, nameAtom);
return NS_GetContentList(this, nameSpaceId, aLocalName);
}
NS_IMETHODIMP
@ -5184,7 +5173,7 @@ nsDocument::GetTitleContent(PRUint32 aNamespace)
return nsnull;
nsRefPtr<nsContentList> list =
NS_GetContentList(this, aNamespace, nsGkAtoms::title);
NS_GetContentList(this, aNamespace, NS_LITERAL_STRING("title"));
return list->Item(0, PR_FALSE);
}
@ -7473,7 +7462,7 @@ nsDocument::OnPageShow(PRBool aPersisted,
// Send out notifications that our <link> elements are attached.
nsRefPtr<nsContentList> links = NS_GetContentList(root,
kNameSpaceID_Unknown,
nsGkAtoms::link);
NS_LITERAL_STRING("link"));
PRUint32 linkCount = links->Length(PR_TRUE);
for (PRUint32 i = 0; i < linkCount; ++i) {
@ -7525,7 +7514,7 @@ nsDocument::OnPageHide(PRBool aPersisted,
if (aPersisted && root) {
nsRefPtr<nsContentList> links = NS_GetContentList(root,
kNameSpaceID_Unknown,
nsGkAtoms::link);
NS_LITERAL_STRING("link"));
PRUint32 linkCount = links->Length(PR_TRUE);
for (PRUint32 i = 0; i < linkCount; ++i) {

Просмотреть файл

@ -978,7 +978,9 @@ public:
virtual void SetChangeScrollPosWhenScrollingToRef(PRBool aValue);
already_AddRefed<nsContentList>
GetElementsByTagName(const nsAString& aTagName);
GetElementsByTagName(const nsAString& aTagName) {
return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName);
}
already_AddRefed<nsContentList>
GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName);

Просмотреть файл

@ -2558,13 +2558,8 @@ nsresult
nsGenericElement::GetElementsByTagName(const nsAString& aTagname,
nsIDOMNodeList** aReturn)
{
nsAutoString lowercaseName;
nsContentUtils::ASCIIToLower(aTagname, lowercaseName);
nsCOMPtr<nsIAtom> XMLAtom = do_GetAtom(aTagname);
nsCOMPtr<nsIAtom> HTMLAtom = do_GetAtom(lowercaseName);
nsContentList *list = NS_GetContentList(this, kNameSpaceID_Unknown,
HTMLAtom, XMLAtom).get();
aTagname).get();
// transfer ref to aReturn
*aReturn = list;
@ -2690,9 +2685,9 @@ nsGenericElement::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aLocalName);
NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
nsContentList *list = NS_GetContentList(this, nameSpaceId, nameAtom).get();
nsContentList *list = NS_GetContentList(this, nameSpaceId, aLocalName).get();
// transfer ref to aReturn
*aReturn = list;

Просмотреть файл

@ -1537,7 +1537,7 @@ nsHTMLDocument::GetBody(nsresult *aResult)
// The document is most likely a frameset document so look for the
// outer most frameset element
nsRefPtr<nsContentList> nodeList =
NS_GetContentList(this, kNameSpaceID_XHTML, nsGkAtoms::frameset);
NS_GetContentList(this, kNameSpaceID_XHTML, NS_LITERAL_STRING("frameset"));
return nodeList->GetNodeAt(0);
}