Fixing bug 572614. Eliminate double hash lookups in document.getElementById(). r=jonas@sicking.cc

This commit is contained in:
Johnny Stenback 2010-06-21 19:59:37 -07:00
parent c50fb5d521
commit 4548ec1aa1
4 changed files with 72 additions and 54 deletions

View File

@ -2337,7 +2337,8 @@ nsDocument::AddToNameTable(Element *aElement, nsIAtom* aName)
if (!mIsRegularHTML)
return;
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aName);
nsIdentifierMapEntry *entry =
mIdentifierMap.GetEntry(nsDependentAtomString(aName));
// entry is null if we're not tracking the elements with this name
@ -2353,7 +2354,8 @@ nsDocument::RemoveFromNameTable(Element *aElement, nsIAtom* aName)
if (!mIsRegularHTML || mIdentifierMap.Count() == 0)
return;
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aName);
nsIdentifierMapEntry *entry =
mIdentifierMap.GetEntry(nsDependentAtomString(aName));
if (!entry) // Should never be false unless we had OOM when adding the entry
return;
@ -2363,7 +2365,8 @@ nsDocument::RemoveFromNameTable(Element *aElement, nsIAtom* aName)
void
nsDocument::AddToIdTable(Element *aElement, nsIAtom* aId)
{
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aId);
nsIdentifierMapEntry *entry =
mIdentifierMap.PutEntry(nsDependentAtomString(aId));
if (entry) { /* True except on OOM */
entry->AddIdElement(aElement);
@ -2380,12 +2383,13 @@ nsDocument::RemoveFromIdTable(Element *aElement, nsIAtom* aId)
return;
}
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId);
nsIdentifierMapEntry *entry =
mIdentifierMap.GetEntry(nsDependentAtomString(aId));
if (!entry) // Can be null for XML elements with changing ids.
return;
if (entry->RemoveIdElement(aElement)) {
mIdentifierMap.RemoveEntry(aId);
mIdentifierMap.RawRemoveEntry(entry);
}
}
@ -3721,38 +3725,27 @@ nsDocument::BeginLoad()
NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
}
PRBool
nsDocument::CheckGetElementByIdArg(const nsIAtom* aId)
// static
void
nsDocument::ReportEmptyGetElementByIdArg()
{
if (aId == nsGkAtoms::_empty) {
nsContentUtils::ReportToConsole(
nsContentUtils::eDOM_PROPERTIES,
"EmptyGetElementByIdParam",
nsnull, 0,
nsnull,
EmptyString(), 0, 0,
nsIScriptError::warningFlag,
"DOM");
return PR_FALSE;
}
return PR_TRUE;
nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
"EmptyGetElementByIdParam",
nsnull, 0,
nsnull,
EmptyString(), 0, 0,
nsIScriptError::warningFlag,
"DOM");
}
Element*
nsDocument::GetElementById(const nsAString& aElementId)
{
nsCOMPtr<nsIAtom> idAtom(do_GetAtom(aElementId));
if (!idAtom) {
// This can only fail due to OOM when the atom doesn't exist, in which
// case there can't be an entry for it.
if (!CheckGetElementByIdArg(aElementId)) {
return nsnull;
}
if (!CheckGetElementByIdArg(idAtom)) {
return nsnull;
}
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(idAtom);
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
return entry ? entry->GetIdElement() : nsnull;
}
@ -3773,10 +3766,12 @@ Element*
nsDocument::AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
void* aData)
{
if (!CheckGetElementByIdArg(aID))
nsDependentAtomString id(aID);
if (!CheckGetElementByIdArg(id))
return nsnull;
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aID);
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(id);
NS_ENSURE_TRUE(entry, nsnull);
entry->AddContentChangeCallback(aObserver, aData);
@ -3787,10 +3782,12 @@ void
nsDocument::RemoveIDTargetObserver(nsIAtom* aID,
IDTargetObserver aObserver, void* aData)
{
if (!CheckGetElementByIdArg(aID))
nsDependentAtomString id(aID);
if (!CheckGetElementByIdArg(id))
return;
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aID);
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(id);
if (!entry) {
return;
}

View File

@ -145,17 +145,21 @@ class nsHTMLCSSStyleSheet;
* Perhaps the document.all results should have their own hashtable
* in nsHTMLDocument.
*/
class nsIdentifierMapEntry : public nsISupportsHashKey
class nsIdentifierMapEntry : public nsStringHashKey
{
public:
typedef mozilla::dom::Element Element;
nsIdentifierMapEntry(const nsISupports* aKey) :
nsISupportsHashKey(aKey), mNameContentList(nsnull)
nsIdentifierMapEntry(const nsAString& aKey) :
nsStringHashKey(&aKey), mNameContentList(nsnull)
{
}
nsIdentifierMapEntry(const nsAString *aKey) :
nsStringHashKey(aKey), mNameContentList(nsnull)
{
}
nsIdentifierMapEntry(const nsIdentifierMapEntry& aOther) :
nsISupportsHashKey(GetKey())
nsStringHashKey(&aOther.GetKey())
{
NS_ERROR("Should never be called");
}
@ -951,7 +955,16 @@ protected:
* service if it is.
* @returns PR_TRUE if aId looks correct, PR_FALSE otherwise.
*/
static PRBool CheckGetElementByIdArg(const nsIAtom* aId);
static inline PRBool CheckGetElementByIdArg(const nsAString& aId)
{
if (aId.IsEmpty()) {
ReportEmptyGetElementByIdArg();
return PR_FALSE;
}
return PR_TRUE;
}
static void ReportEmptyGetElementByIdArg();
void DispatchContentLoadedEvents();

View File

@ -2677,11 +2677,9 @@ nsHTMLDocument::ResolveName(const nsAString& aName,
{
*aResult = nsnull;
nsCOMPtr<nsIAtom> name(do_GetAtom(aName));
// We have built a table and cache the named items. The table will
// be updated as content is added and removed.
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(name);
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aName);
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
if (entry->IsInvalidName()) {
@ -2705,7 +2703,14 @@ nsHTMLDocument::ResolveName(const nsAString& aName,
Element* root = GetRootElement();
if (root && !aName.IsEmpty()) {
FindNamedItems(name, root, entry);
// do_GetAtom() can fail on OOM, but it'll only do that if the
// atom doesn't already exist, which means the named item
// doesn't exist either.
nsCOMPtr<nsIAtom> name(do_GetAtom(aName));
if (name) {
FindNamedItems(name, root, entry);
}
}
}
@ -2810,7 +2815,8 @@ nsHTMLDocument::PrePopulateIdentifierMap()
nsCOMPtr<nsIAtom> atom(do_GetAtom(names[i]));
NS_ENSURE_TRUE(atom, NS_ERROR_OUT_OF_MEMORY);
nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(atom);
nsIdentifierMapEntry* entry =
mIdentifierMap.PutEntry(nsDependentAtomString(atom));
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
entry->SetInvalidName();
@ -3135,8 +3141,7 @@ nsHTMLDocument::GetDocumentAllResult(const nsAString& aID, nsISupports** aResult
{
*aResult = nsnull;
nsCOMPtr<nsIAtom> id = do_GetAtom(aID);
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(id);
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aID);
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
Element* root = GetRootElement();
@ -3146,6 +3151,8 @@ nsHTMLDocument::GetDocumentAllResult(const nsAString& aID, nsISupports** aResult
nsRefPtr<nsContentList> docAllList = entry->GetDocAllList();
if (!docAllList) {
nsCOMPtr<nsIAtom> id = do_GetAtom(aID);
docAllList = new nsContentList(root, DocAllResultMatch,
nsnull, nsnull, PR_TRUE, id);
NS_ENSURE_TRUE(docAllList, NS_ERROR_OUT_OF_MEMORY);

View File

@ -1142,7 +1142,7 @@ nsXULDocument::GetElementsForID(const nsAString& aID,
nsCOMPtr<nsIAtom> atom = do_GetAtom(aID);
if (!atom)
return NS_ERROR_OUT_OF_MEMORY;
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(atom);
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aID);
if (entry) {
entry->AppendAllIdContent(&aElements);
}
@ -1639,6 +1639,16 @@ nsXULDocument::GetCommandDispatcher(nsIDOMXULCommandDispatcher** aTracker)
Element*
nsXULDocument::GetElementById(const nsAString& aId)
{
if (!CheckGetElementByIdArg(aId))
return nsnull;
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId);
if (entry) {
Element* element = entry->GetIdElement();
if (element)
return element;
}
nsCOMPtr<nsIAtom> atom(do_GetAtom(aId));
if (!atom) {
// This can only fail due OOM if the atom doesn't exist, in which
@ -1646,15 +1656,6 @@ nsXULDocument::GetElementById(const nsAString& aId)
return nsnull;
}
if (!CheckGetElementByIdArg(atom))
return nsnull;
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(atom);
if (entry) {
Element* element = entry->GetIdElement();
if (element)
return element;
}
nsRefMapEntry* refEntry = mRefMap.GetEntry(atom);
if (refEntry) {
NS_ASSERTION(refEntry->GetFirstElement(),