diff --git a/dom/base/Link.cpp b/dom/base/Link.cpp index b1c56e706bf4..409739a80ab1 100644 --- a/dom/base/Link.cpp +++ b/dom/base/Link.cpp @@ -34,6 +34,7 @@ Link::Link(Element *aElement) , mNeedsRegistration(false) , mRegistered(false) , mHasPendingLinkUpdate(false) + , mInDNSPrefetch(false) { MOZ_ASSERT(mElement, "Must have an element"); } @@ -45,11 +46,17 @@ Link::Link() , mNeedsRegistration(false) , mRegistered(false) , mHasPendingLinkUpdate(false) + , mInDNSPrefetch(false) { } Link::~Link() { + // !mElement is for mock_Link. + MOZ_ASSERT(!mElement || !mElement->IsInComposedDoc()); + if (IsInDNSPrefetch()) { + nsHTMLDNSPrefetch::LinkDestroyed(this); + } UnregisterFromHistory(); } diff --git a/dom/base/Link.h b/dom/base/Link.h index c5e4dbaff1a9..5ceffe35f445 100644 --- a/dom/base/Link.h +++ b/dom/base/Link.h @@ -136,6 +136,10 @@ public: // If you change this, change also the method in Element. virtual void NodeInfoChanged(nsIDocument* aOldDoc) = 0; + bool IsInDNSPrefetch() { return mInDNSPrefetch; } + void SetIsInDNSPrefetch() { mInDNSPrefetch = true; } + void ClearIsInDNSPrefetch() { mInDNSPrefetch = false; } + protected: virtual ~Link(); @@ -179,6 +183,8 @@ private: bool mRegistered : 1; bool mHasPendingLinkUpdate : 1; + + bool mInDNSPrefetch : 1; }; NS_DEFINE_STATIC_IID_ACCESSOR(Link, MOZILLA_DOM_LINK_IMPLEMENTATION_IID) diff --git a/dom/html/nsHTMLDNSPrefetch.cpp b/dom/html/nsHTMLDNSPrefetch.cpp index 8e46efcfc2da..9ba10df34214 100644 --- a/dom/html/nsHTMLDNSPrefetch.cpp +++ b/dom/html/nsHTMLDNSPrefetch.cpp @@ -247,6 +247,15 @@ nsHTMLDNSPrefetch::CancelPrefetchLow(const nsAString &hostname, aReason); } +void +nsHTMLDNSPrefetch::LinkDestroyed(Link* aLink) +{ + MOZ_ASSERT(aLink->IsInDNSPrefetch()); + if (sPrefetches) { + // Clean up all the possible links at once. + sPrefetches->RemoveUnboundLinks(); + } +} ///////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -291,6 +300,9 @@ void nsHTMLDNSPrefetch::nsDeferrals::Flush() { while (mHead != mTail) { + if (mEntries[mTail].mElement) { + mEntries[mTail].mElement->ClearIsInDNSPrefetch(); + } mEntries[mTail].mElement = nullptr; mTail = (mTail + 1) & sMaxDeferredMask; } @@ -306,9 +318,10 @@ nsHTMLDNSPrefetch::nsDeferrals::Add(uint16_t flags, Link *aElement) if (((mHead + 1) & sMaxDeferredMask) == mTail) return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; - + + aElement->SetIsInDNSPrefetch(); mEntries[mHead].mFlags = flags; - mEntries[mHead].mElement = do_GetWeakReference(aElement); + mEntries[mHead].mElement = aElement; mHead = (mHead + 1) & sMaxDeferredMask; if (!mActiveLoaderCount && !mTimerArmed && mTimer) { @@ -328,9 +341,9 @@ nsHTMLDNSPrefetch::nsDeferrals::SubmitQueue() if (!sDNSService) return; while (mHead != mTail) { - nsCOMPtr content = do_QueryReferent(mEntries[mTail].mElement); - if (content) { - nsCOMPtr link = do_QueryInterface(content); + nsCOMPtr link = mEntries[mTail].mElement; + if (link) { + link->ClearIsInDNSPrefetch(); // Only prefetch here if request was deferred and deferral not cancelled if (link && link->HasDeferredDNSPrefetchRequest()) { nsCOMPtr hrefURI(link ? link->GetURI() : nullptr); @@ -400,6 +413,20 @@ nsHTMLDNSPrefetch::nsDeferrals::Activate() observerService->AddObserver(this, "xpcom-shutdown", true); } +void +nsHTMLDNSPrefetch::nsDeferrals::RemoveUnboundLinks() +{ + uint16_t tail = mTail; + while (mHead != tail) { + if (mEntries[tail].mElement && + !mEntries[tail].mElement->GetElement()->IsInComposedDoc()) { + mEntries[tail].mElement->ClearIsInDNSPrefetch(); + mEntries[tail].mElement = nullptr; + } + tail = (tail + 1) & sMaxDeferredMask; + } +} + // nsITimer related method void diff --git a/dom/html/nsHTMLDNSPrefetch.h b/dom/html/nsHTMLDNSPrefetch.h index b62a2f2c02b1..dc8312280817 100644 --- a/dom/html/nsHTMLDNSPrefetch.h +++ b/dom/html/nsHTMLDNSPrefetch.h @@ -63,6 +63,8 @@ public: static nsresult CancelPrefetchLow(mozilla::dom::Link *aElement, nsresult aReason); + static void LinkDestroyed(mozilla::dom::Link* aLink); + private: static nsresult Prefetch(const nsAString &host, const mozilla::OriginAttributes &aOriginAttributes, @@ -103,6 +105,8 @@ public: void Activate(); nsresult Add(uint16_t flags, mozilla::dom::Link *aElement); + void RemoveUnboundLinks(); + private: ~nsDeferrals(); void Flush(); @@ -123,7 +127,8 @@ public: struct deferred_entry { uint16_t mFlags; - nsWeakPtr mElement; + // Link implementation clears this raw pointer in its destructor. + mozilla::dom::Link* mElement; } mEntries[sMaxDeferred]; };