From daa9648aaa53255aaf0d57e4e79921a81854fbda Mon Sep 17 00:00:00 2001 From: roytam1 Date: Sat, 7 Feb 2026 22:12:17 +0800 Subject: [PATCH] ported from UXP: Issue #2928 - Improve imgLoader cache queue handling. (c5cc9805) --- image/imgLoader.cpp | 66 ++++++++++++++++++++++++++++++++++----------- image/imgLoader.h | 3 ++- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index c199ed154..797ed8fbe 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -942,12 +942,38 @@ using namespace std; void imgCacheQueue::Remove(imgCacheEntry* entry) { - auto it = find(mQueue.begin(), mQueue.end(), entry); - if (it != mQueue.end()) { - mSize -= (*it)->GetDataSize(); - mQueue.erase(it); - MarkDirty(); + uint64_t index = mQueue.IndexOf(entry); + if (index == queueContainer::NoIndex) { + return; } + + mSize -= mQueue[index]->GetDataSize(); + + // If the queue is clean and this is the first entry, + // then we can efficiently remove the entry without + // dirtying the sort order. + if (!IsDirty() && index == 0) { + std::pop_heap(mQueue.begin(), mQueue.end(), + imgLoader::CompareCacheEntries); + mQueue.RemoveElementAt(mQueue.Length() - 1); + return; + } + + // Remove from the middle of the list. This potentially + // breaks the binary heap sort order. + mQueue.RemoveElementAt(index); + + // If we only have one entry or the queue is empty, though, + // then the sort order is still effectively good. + // Simply refresh the list to clear the dirty flag. + if (mQueue.Length() <= 1) { + Refresh(); + return; + } + + // Otherwise we must mark the queue dirty and potentially + // trigger an expensive sort later. + MarkDirty(); } void @@ -956,23 +982,26 @@ imgCacheQueue::Push(imgCacheEntry* entry) mSize += entry->GetDataSize(); RefPtr refptr(entry); - mQueue.push_back(refptr); - MarkDirty(); + mQueue.AppendElement(Move(refptr)); + // If we're not dirty already, then we can efficiently add this to the binary heap immediately. + if (!IsDirty()) { + std::push_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries); + } } already_AddRefed imgCacheQueue::Pop() { - if (mQueue.empty()) { + if (mQueue.IsEmpty()) { return nullptr; } if (IsDirty()) { Refresh(); } - RefPtr entry = mQueue[0]; std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries); - mQueue.pop_back(); + RefPtr entry = Move(mQueue.LastElement()); + mQueue.RemoveElementAt(mQueue.Length() - 1); mSize -= entry->GetDataSize(); return entry.forget(); @@ -981,6 +1010,7 @@ imgCacheQueue::Pop() void imgCacheQueue::Refresh() { + // Re-heap the list. This is an O(3 * n) operation and best avoided if possible. std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries); mDirty = false; } @@ -1000,7 +1030,7 @@ imgCacheQueue::IsDirty() uint32_t imgCacheQueue::GetNumElements() const { - return mQueue.size(); + return mQueue.Length(); } bool @@ -1560,7 +1590,11 @@ void imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */) { imgCacheQueue& queue = GetCacheQueue(aForChrome); - queue.MarkDirty(); + // We only need to dirty the queue if there is any sorting taking place. + // Empty or single-entry lists can't become dirty. + if (queue.GetNumElements() > 1) { + queue.MarkDirty(); + } queue.UpdateSize(aSizeDiff); } @@ -1970,13 +2004,13 @@ imgLoader::EvictEntries(imgCacheQueue& aQueueToClear) // We have to make a temporary, since RemoveFromCache removes the element // from the queue, invalidating iterators. nsTArray > entries(aQueueToClear.GetNumElements()); - for (imgCacheQueue::const_iterator i = aQueueToClear.begin(); - i != aQueueToClear.end(); ++i) { + for (auto i = aQueueToClear.begin(); i != aQueueToClear.end(); ++i) { entries.AppendElement(*i); } - for (uint32_t i = 0; i < entries.Length(); ++i) { - if (!RemoveFromCache(entries[i])) { + // Iterate in reverse order to minimize array copying. + for (auto& entry : entries) { + if (!RemoveFromCache(entry)) { return NS_ERROR_FAILURE; } } diff --git a/image/imgLoader.h b/image/imgLoader.h index 2d5fd2e5e..50ced82cd 100644 --- a/image/imgLoader.h +++ b/image/imgLoader.h @@ -177,7 +177,8 @@ public: uint32_t GetSize() const; void UpdateSize(int32_t diff); uint32_t GetNumElements() const; - typedef std::vector > queueContainer; + bool Contains(imgCacheEntry* aEntry) const; + typedef nsTArray > queueContainer; typedef queueContainer::iterator iterator; typedef queueContainer::const_iterator const_iterator;