summaryrefslogtreecommitdiff
path: root/Source/WebCore/loader/cache/MemoryCache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/loader/cache/MemoryCache.cpp')
-rw-r--r--Source/WebCore/loader/cache/MemoryCache.cpp922
1 files changed, 356 insertions, 566 deletions
diff --git a/Source/WebCore/loader/cache/MemoryCache.cpp b/Source/WebCore/loader/cache/MemoryCache.cpp
index 652422cf6..75ee84bb7 100644
--- a/Source/WebCore/loader/cache/MemoryCache.cpp
+++ b/Source/WebCore/loader/cache/MemoryCache.cpp
@@ -25,9 +25,9 @@
#include "BitmapImage.h"
#include "CachedImage.h"
+#include "CachedImageClient.h"
#include "CachedResource.h"
#include "CachedResourceHandle.h"
-#include "CrossThreadTask.h"
#include "Document.h"
#include "FrameLoader.h"
#include "FrameLoaderTypes.h"
@@ -35,166 +35,156 @@
#include "Image.h"
#include "Logging.h"
#include "PublicSuffix.h"
-#include "SecurityOrigin.h"
-#include "SecurityOriginHash.h"
+#include "SharedBuffer.h"
#include "WorkerGlobalScope.h"
#include "WorkerLoaderProxy.h"
#include "WorkerThread.h"
#include <stdio.h>
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
-#include <wtf/TemporaryChange.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/SetForScope.h>
#include <wtf/text/CString.h>
-#if ENABLE(DISK_IMAGE_CACHE)
-#include "DiskImageCacheIOS.h"
-#include "ResourceBuffer.h"
-#endif
-
namespace WebCore {
static const int cDefaultCacheCapacity = 8192 * 1024;
static const double cMinDelayBeforeLiveDecodedPrune = 1; // Seconds.
static const float cTargetPrunePercentage = .95f; // Percentage of capacity toward which we prune, to avoid immediately pruning again.
-static const double cDefaultDecodedDataDeletionInterval = 0;
+static const auto defaultDecodedDataDeletionInterval = std::chrono::seconds { 0 };
-MemoryCache* memoryCache()
+MemoryCache& MemoryCache::singleton()
{
- static MemoryCache* staticCache = new MemoryCache;
ASSERT(WTF::isMainThread());
-
- return staticCache;
+ static NeverDestroyed<MemoryCache> memoryCache;
+ return memoryCache;
}
MemoryCache::MemoryCache()
: m_disabled(false)
- , m_pruneEnabled(true)
, m_inPruneResources(false)
, m_capacity(cDefaultCacheCapacity)
, m_minDeadCapacity(0)
, m_maxDeadCapacity(cDefaultCacheCapacity)
- , m_deadDecodedDataDeletionInterval(cDefaultDecodedDataDeletionInterval)
+ , m_deadDecodedDataDeletionInterval(defaultDecodedDataDeletionInterval)
, m_liveSize(0)
, m_deadSize(0)
+ , m_pruneTimer(*this, &MemoryCache::prune)
{
+ static_assert(sizeof(long long) > sizeof(unsigned), "Numerical overflow can happen when adjusting the size of the cached memory.");
}
-URL MemoryCache::removeFragmentIdentifierIfNeeded(const URL& originalURL)
+auto MemoryCache::sessionResourceMap(SessionID sessionID) const -> CachedResourceMap*
+{
+ ASSERT(sessionID.isValid());
+ return m_sessionResources.get(sessionID);
+}
+
+auto MemoryCache::ensureSessionResourceMap(SessionID sessionID) -> CachedResourceMap&
+{
+ ASSERT(sessionID.isValid());
+ auto& map = m_sessionResources.add(sessionID, nullptr).iterator->value;
+ if (!map)
+ map = std::make_unique<CachedResourceMap>();
+ return *map;
+}
+
+bool MemoryCache::shouldRemoveFragmentIdentifier(const URL& originalURL)
{
if (!originalURL.hasFragmentIdentifier())
- return originalURL;
+ return false;
// Strip away fragment identifier from HTTP URLs.
- // Data URLs must be unmodified. For file and custom URLs clients may expect resources
+ // Data URLs must be unmodified. For file and custom URLs clients may expect resources
// to be unique even when they differ by the fragment identifier only.
- if (!originalURL.protocolIsInHTTPFamily())
+ return originalURL.protocolIsInHTTPFamily();
+}
+
+URL MemoryCache::removeFragmentIdentifierIfNeeded(const URL& originalURL)
+{
+ if (!shouldRemoveFragmentIdentifier(originalURL))
return originalURL;
URL url = originalURL;
url.removeFragmentIdentifier();
return url;
}
-bool MemoryCache::add(CachedResource* resource)
+bool MemoryCache::add(CachedResource& resource)
{
if (disabled())
return false;
ASSERT(WTF::isMainThread());
-#if ENABLE(CACHE_PARTITIONING)
- CachedResourceItem* originMap = m_resources.get(resource->url());
- if (!originMap) {
- originMap = new CachedResourceItem;
- m_resources.set(resource->url(), adoptPtr(originMap));
- }
- originMap->set(resource->cachePartition(), resource);
-#else
- m_resources.set(resource->url(), resource);
-#endif
- resource->setInCache(true);
+ auto key = std::make_pair(resource.url(), resource.cachePartition());
+
+ ensureSessionResourceMap(resource.sessionID()).set(key, &resource);
+ resource.setInCache(true);
resourceAccessed(resource);
- LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resource->url().string().latin1().data(), resource);
+ LOG(ResourceLoading, "MemoryCache::add Added '%s', resource %p\n", resource.url().string().latin1().data(), &resource);
return true;
}
-void MemoryCache::revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse& response)
+void MemoryCache::revalidationSucceeded(CachedResource& revalidatingResource, const ResourceResponse& response)
{
- CachedResource* resource = revalidatingResource->resourceToRevalidate();
- ASSERT(resource);
- ASSERT(!resource->inCache());
- ASSERT(resource->isLoaded());
- ASSERT(revalidatingResource->inCache());
+ ASSERT(revalidatingResource.resourceToRevalidate());
+ CachedResource& resource = *revalidatingResource.resourceToRevalidate();
+ ASSERT(!resource.inCache());
+ ASSERT(resource.isLoaded());
- // Calling evict() can potentially delete revalidatingResource, which we use
+ // Calling remove() can potentially delete revalidatingResource, which we use
// below. This mustn't be the case since revalidation means it is loaded
// and so canDelete() is false.
- ASSERT(!revalidatingResource->canDelete());
+ ASSERT(!revalidatingResource.canDelete());
- evict(revalidatingResource);
+ remove(revalidatingResource);
-#if ENABLE(CACHE_PARTITIONING)
- ASSERT(!m_resources.get(resource->url()) || !m_resources.get(resource->url())->get(resource->cachePartition()));
- CachedResourceItem* originMap = m_resources.get(resource->url());
- if (!originMap) {
- originMap = new CachedResourceItem;
- m_resources.set(resource->url(), adoptPtr(originMap));
- }
- originMap->set(resource->cachePartition(), resource);
-#else
- ASSERT(!m_resources.get(resource->url()));
- m_resources.set(resource->url(), resource);
-#endif
- resource->setInCache(true);
- resource->updateResponseAfterRevalidation(response);
+ auto& resources = ensureSessionResourceMap(resource.sessionID());
+ auto key = std::make_pair(resource.url(), resource.cachePartition());
+
+ ASSERT(!resources.get(key));
+ resources.set(key, &resource);
+ resource.setInCache(true);
+ resource.updateResponseAfterRevalidation(response);
insertInLRUList(resource);
- int delta = resource->size();
- if (resource->decodedSize() && resource->hasClients())
+ long long delta = resource.size();
+ if (resource.decodedSize() && resource.hasClients())
insertInLiveDecodedResourcesList(resource);
if (delta)
- adjustSize(resource->hasClients(), delta);
-
- revalidatingResource->switchClientsToRevalidatedResource();
- ASSERT(!revalidatingResource->m_deleted);
+ adjustSize(resource.hasClients(), delta);
+
+ revalidatingResource.switchClientsToRevalidatedResource();
+ ASSERT(!revalidatingResource.m_deleted);
// this deletes the revalidating resource
- revalidatingResource->clearResourceToRevalidate();
+ revalidatingResource.clearResourceToRevalidate();
}
-void MemoryCache::revalidationFailed(CachedResource* revalidatingResource)
+void MemoryCache::revalidationFailed(CachedResource& revalidatingResource)
{
ASSERT(WTF::isMainThread());
- LOG(ResourceLoading, "Revalidation failed for %p", revalidatingResource);
- ASSERT(revalidatingResource->resourceToRevalidate());
- revalidatingResource->clearResourceToRevalidate();
+ LOG(ResourceLoading, "Revalidation failed for %p", &revalidatingResource);
+ ASSERT(revalidatingResource.resourceToRevalidate());
+ revalidatingResource.clearResourceToRevalidate();
}
-CachedResource* MemoryCache::resourceForURL(const URL& resourceURL)
+CachedResource* MemoryCache::resourceForRequest(const ResourceRequest& request, SessionID sessionID)
{
- return resourceForRequest(ResourceRequest(resourceURL));
+ // FIXME: Change all clients to make sure HTTP(s) URLs have no fragment identifiers before calling here.
+ // CachedResourceLoader is now doing this. Add an assertion once all other clients are doing it too.
+ auto* resources = sessionResourceMap(sessionID);
+ if (!resources)
+ return nullptr;
+ return resourceForRequestImpl(request, *resources);
}
-CachedResource* MemoryCache::resourceForRequest(const ResourceRequest& request)
+CachedResource* MemoryCache::resourceForRequestImpl(const ResourceRequest& request, CachedResourceMap& resources)
{
ASSERT(WTF::isMainThread());
URL url = removeFragmentIdentifierIfNeeded(request.url());
-#if ENABLE(CACHE_PARTITIONING)
- CachedResourceItem* item = m_resources.get(url);
- CachedResource* resource = 0;
- if (item)
- resource = item->get(request.cachePartition());
-#else
- CachedResource* resource = m_resources.get(url);
-#endif
- bool wasPurgeable = MemoryCache::shouldMakeResourcePurgeableOnEviction() && resource && resource->isPurgeable();
- if (resource && !resource->makePurgeable(false)) {
- ASSERT(!resource->hasClients());
- evict(resource);
- return 0;
- }
- // Add the size back since we had subtracted it when we marked the memory as purgeable.
- if (wasPurgeable)
- adjustSize(resource->hasClients(), resource->size());
- return resource;
+
+ auto key = std::make_pair(url, request.cachePartition());
+ return resources.get(key);
}
unsigned MemoryCache::deadCapacity() const
@@ -212,51 +202,46 @@ unsigned MemoryCache::liveCapacity() const
return m_capacity - deadCapacity();
}
-#if USE(CG)
-// FIXME: Remove the USE(CG) once we either make NativeImagePtr a smart pointer on all platforms or
-// remove the usage of CFRetain() in MemoryCache::addImageToCache() so as to make the code platform-independent.
-bool MemoryCache::addImageToCache(NativeImagePtr image, const URL& url, const String& cachePartition)
+static CachedImageClient& dummyCachedImageClient()
+{
+ static NeverDestroyed<CachedImageClient> client;
+ return client;
+}
+
+bool MemoryCache::addImageToCache(NativeImagePtr&& image, const URL& url, const String& domainForCachePartition)
{
ASSERT(image);
- removeImageFromCache(url, cachePartition); // Remove cache entry if it already exists.
+ SessionID sessionID = SessionID::defaultSessionID();
+ removeImageFromCache(url, domainForCachePartition); // Remove cache entry if it already exists.
- RefPtr<BitmapImage> bitmapImage = BitmapImage::create(image, nullptr);
+ RefPtr<BitmapImage> bitmapImage = BitmapImage::create(WTFMove(image), nullptr);
if (!bitmapImage)
return false;
- CachedImageManual* cachedImage = new CachedImageManual(url, bitmapImage.get());
- if (!cachedImage)
- return false;
+ auto cachedImage = std::make_unique<CachedImage>(url, bitmapImage.get(), sessionID);
- // Actual release of the CGImageRef is done in BitmapImage.
- CFRetain(image);
- cachedImage->addFakeClient();
+ cachedImage->addClient(dummyCachedImageClient());
cachedImage->setDecodedSize(bitmapImage->decodedSize());
-#if ENABLE(CACHE_PARTITIONING)
- cachedImage->resourceRequest().setCachePartition(cachePartition);
-#endif
- add(cachedImage);
- return true;
+ cachedImage->resourceRequest().setDomainForCachePartition(domainForCachePartition);
+
+ return add(*cachedImage.release());
}
-void MemoryCache::removeImageFromCache(const URL& url, const String& cachePartition)
+void MemoryCache::removeImageFromCache(const URL& url, const String& domainForCachePartition)
{
-#if ENABLE(CACHE_PARTITIONING)
- CachedResource* resource;
- if (CachedResourceItem* item = m_resources.get(url))
- resource = item->get(ResourceRequest::partitionName(cachePartition));
- else
- resource = nullptr;
-#else
- UNUSED_PARAM(cachePartition);
- CachedResource* resource = m_resources.get(url);
-#endif
+ auto* resources = sessionResourceMap(SessionID::defaultSessionID());
+ if (!resources)
+ return;
+
+ auto key = std::make_pair(url, ResourceRequest::partitionName(domainForCachePartition));
+
+ CachedResource* resource = resources->get(key);
if (!resource)
return;
// A resource exists and is not a manually cached image, so just remove it.
- if (!resource->isImage() || !static_cast<CachedImage*>(resource)->isManual()) {
- evict(resource);
+ if (!is<CachedImage>(*resource) || !downcast<CachedImage>(*resource).isManuallyCached()) {
+ remove(*resource);
return;
}
@@ -265,15 +250,11 @@ void MemoryCache::removeImageFromCache(const URL& url, const String& cachePartit
// dead resources are pruned. That might be immediately since
// removing the last client triggers a MemoryCache::prune, so the
// resource may be deleted after this call.
- static_cast<CachedImageManual*>(resource)->removeFakeClient();
+ downcast<CachedImage>(*resource).removeClient(dummyCachedImageClient());
}
-#endif
void MemoryCache::pruneLiveResources(bool shouldDestroyDecodedDataForAllLiveResources)
{
- if (!m_pruneEnabled)
- return;
-
unsigned capacity = shouldDestroyDecodedDataForAllLiveResources ? 0 : liveCapacity();
if (capacity && m_liveSize <= capacity)
return;
@@ -283,41 +264,67 @@ void MemoryCache::pruneLiveResources(bool shouldDestroyDecodedDataForAllLiveReso
pruneLiveResourcesToSize(targetSize, shouldDestroyDecodedDataForAllLiveResources);
}
-void MemoryCache::pruneLiveResourcesToPercentage(float prunePercentage)
+void MemoryCache::forEachResource(const std::function<void(CachedResource&)>& function)
{
- if (!m_pruneEnabled)
- return;
+ for (auto& unprotectedLRUList : m_allResources) {
+ Vector<CachedResourceHandle<CachedResource>> lruList;
+ copyToVector(*unprotectedLRUList, lruList);
+ for (auto& resource : lruList)
+ function(*resource);
+ }
+}
- if (prunePercentage < 0.0f || prunePercentage > 0.95f)
+void MemoryCache::forEachSessionResource(SessionID sessionID, const std::function<void (CachedResource&)>& function)
+{
+ auto it = m_sessionResources.find(sessionID);
+ if (it == m_sessionResources.end())
return;
- unsigned currentSize = m_liveSize + m_deadSize;
- unsigned targetSize = static_cast<unsigned>(currentSize * prunePercentage);
+ Vector<CachedResourceHandle<CachedResource>> resourcesForSession;
+ copyValuesToVector(*it->value, resourcesForSession);
+
+ for (auto& resource : resourcesForSession)
+ function(*resource);
+}
- pruneLiveResourcesToSize(targetSize);
+void MemoryCache::destroyDecodedDataForAllImages()
+{
+ MemoryCache::singleton().forEachResource([](CachedResource& resource) {
+ if (resource.isImage())
+ resource.destroyDecodedData();
+ });
}
void MemoryCache::pruneLiveResourcesToSize(unsigned targetSize, bool shouldDestroyDecodedDataForAllLiveResources)
{
if (m_inPruneResources)
return;
- TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true);
+ SetForScope<bool> reentrancyProtector(m_inPruneResources, true);
double currentTime = FrameView::currentPaintTimeStamp();
if (!currentTime) // In case prune is called directly, outside of a Frame paint.
currentTime = monotonicallyIncreasingTime();
// Destroy any decoded data in live objects that we can.
- // Start from the tail, since this is the least recently accessed of the objects.
+ // Start from the head, since this is the least recently accessed of the objects.
// The list might not be sorted by the m_lastDecodedAccessTime. The impact
// of this weaker invariant is minor as the below if statement to check the
// elapsedTime will evaluate to false as the currentTime will be a lot
// greater than the current->m_lastDecodedAccessTime.
// For more details see: https://bugs.webkit.org/show_bug.cgi?id=30209
- CachedResource* current = m_liveDecodedResources.m_tail;
- while (current) {
- CachedResource* prev = current->m_prevInLiveResourcesList;
+ auto it = m_liveDecodedResources.begin();
+ while (it != m_liveDecodedResources.end()) {
+ auto* current = *it;
+
+ // Increment the iterator now because the call to destroyDecodedData() below
+ // may cause a call to ListHashSet::remove() and invalidate the current
+ // iterator. Note that this is safe because unlike iteration of most
+ // WTF Hash data structures, iteration is guaranteed safe against mutation
+ // of the ListHashSet, except for removal of the item currently pointed to
+ // by a given iterator.
+ ++it;
+
ASSERT(current->hasClients());
if (current->isLoaded() && current->decodedSize()) {
// Check to see if the remaining resources are too new to prune.
@@ -325,23 +332,18 @@ void MemoryCache::pruneLiveResourcesToSize(unsigned targetSize, bool shouldDestr
if (!shouldDestroyDecodedDataForAllLiveResources && elapsedTime < cMinDelayBeforeLiveDecodedPrune)
return;
- // Destroy our decoded data. This will remove us from
- // m_liveDecodedResources, and possibly move us to a different LRU
- // list in m_allResources.
+ // Destroy our decoded data. This will remove us from m_liveDecodedResources, and possibly move us
+ // to a different LRU list in m_allResources.
current->destroyDecodedData();
if (targetSize && m_liveSize <= targetSize)
return;
}
- current = prev;
}
}
void MemoryCache::pruneDeadResources()
{
- if (!m_pruneEnabled)
- return;
-
unsigned capacity = deadCapacity();
if (capacity && m_deadSize <= capacity)
return;
@@ -350,135 +352,61 @@ void MemoryCache::pruneDeadResources()
pruneDeadResourcesToSize(targetSize);
}
-void MemoryCache::pruneDeadResourcesToPercentage(float prunePercentage)
-{
- if (!m_pruneEnabled)
- return;
-
- if (prunePercentage < 0.0f || prunePercentage > 0.95f)
- return;
-
- unsigned currentSize = m_liveSize + m_deadSize;
- unsigned targetSize = static_cast<unsigned>(currentSize * prunePercentage);
-
- pruneDeadResourcesToSize(targetSize);
-}
-
void MemoryCache::pruneDeadResourcesToSize(unsigned targetSize)
{
if (m_inPruneResources)
return;
- TemporaryChange<bool> reentrancyProtector(m_inPruneResources, true);
-
- int size = m_allResources.size();
+ SetForScope<bool> reentrancyProtector(m_inPruneResources, true);
- // See if we have any purged resources we can evict.
- for (int i = 0; i < size; i++) {
- CachedResource* current = m_allResources[i].m_tail;
- while (current) {
- CachedResource* prev = current->m_prevInAllResourcesList;
- if (current->wasPurged()) {
- ASSERT(!current->hasClients());
- ASSERT(!current->isPreloaded());
- evict(current);
- }
- current = prev;
- }
- }
if (targetSize && m_deadSize <= targetSize)
return;
bool canShrinkLRULists = true;
- for (int i = size - 1; i >= 0; i--) {
- // Remove from the tail, since this is the least frequently accessed of the objects.
- CachedResource* current = m_allResources[i].m_tail;
-
+ for (int i = m_allResources.size() - 1; i >= 0; i--) {
+ // Make a copy of the LRUList first (and ref the resources) as calling
+ // destroyDecodedData() can alter the LRUList.
+ Vector<CachedResourceHandle<CachedResource>> lruList;
+ copyToVector(*m_allResources[i], lruList);
+
// First flush all the decoded data in this queue.
- while (current) {
- // Protect 'previous' so it can't get deleted during destroyDecodedData().
- CachedResourceHandle<CachedResource> previous = current->m_prevInAllResourcesList;
- ASSERT(!previous || previous->inCache());
- if (!current->hasClients() && !current->isPreloaded() && current->isLoaded()) {
+ // Remove from the head, since this is the least frequently accessed of the objects.
+ for (auto& resource : lruList) {
+ if (!resource->inCache())
+ continue;
+
+ if (!resource->hasClients() && !resource->isPreloaded() && resource->isLoaded()) {
// Destroy our decoded data. This will remove us from
// m_liveDecodedResources, and possibly move us to a different
// LRU list in m_allResources.
- current->destroyDecodedData();
+ resource->destroyDecodedData();
if (targetSize && m_deadSize <= targetSize)
return;
}
- // Decoded data may reference other resources. Stop iterating if 'previous' somehow got
- // kicked out of cache during destroyDecodedData().
- if (previous && !previous->inCache())
- break;
- current = previous.get();
}
- // Now evict objects from this queue.
- current = m_allResources[i].m_tail;
- while (current) {
- CachedResourceHandle<CachedResource> previous = current->m_prevInAllResourcesList;
- ASSERT(!previous || previous->inCache());
- if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) {
- if (!makeResourcePurgeable(current))
- evict(current);
+ // Now evict objects from this list.
+ // Remove from the head, since this is the least frequently accessed of the objects.
+ for (auto& resource : lruList) {
+ if (!resource->inCache())
+ continue;
+ if (!resource->hasClients() && !resource->isPreloaded() && !resource->isCacheValidator()) {
+ remove(*resource);
if (targetSize && m_deadSize <= targetSize)
return;
}
- if (previous && !previous->inCache())
- break;
- current = previous.get();
}
// Shrink the vector back down so we don't waste time inspecting
// empty LRU lists on future prunes.
- if (m_allResources[i].m_head)
+ if (!m_allResources[i]->isEmpty())
canShrinkLRULists = false;
else if (canShrinkLRULists)
- m_allResources.resize(i);
+ m_allResources.shrink(i);
}
}
-#if ENABLE(DISK_IMAGE_CACHE)
-void MemoryCache::flushCachedImagesToDisk()
-{
- if (!diskImageCache().isEnabled())
- return;
-
-#ifndef NDEBUG
- double start = WTF::currentTimeMS();
- unsigned resourceCount = 0;
- unsigned cachedSize = 0;
-#endif
-
- for (size_t i = m_allResources.size(); i; ) {
- --i;
- CachedResource* current = m_allResources[i].m_tail;
- while (current) {
- CachedResource* previous = current->m_prevInAllResourcesList;
-
- if (!current->isUsingDiskImageCache() && current->canUseDiskImageCache()) {
- current->useDiskImageCache();
- current->destroyDecodedData();
-#ifndef NDEBUG
- LOG(DiskImageCache, "Cache::diskCacheResources(): attempting to save (%d) bytes", current->resourceBuffer()->sharedBuffer()->size());
- ++resourceCount;
- cachedSize += current->resourceBuffer()->sharedBuffer()->size();
-#endif
- }
-
- current = previous;
- }
- }
-
-#ifndef NDEBUG
- double end = WTF::currentTimeMS();
- LOG(DiskImageCache, "DiskImageCache: took (%f) ms to cache (%d) bytes for (%d) resources", end - start, cachedSize, resourceCount);
-#endif
-}
-#endif // ENABLE(DISK_IMAGE_CACHE)
-
void MemoryCache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes)
{
ASSERT(minDeadBytes <= maxDeadBytes);
@@ -489,400 +417,269 @@ void MemoryCache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, un
prune();
}
-bool MemoryCache::makeResourcePurgeable(CachedResource* resource)
-{
- if (!MemoryCache::shouldMakeResourcePurgeableOnEviction())
- return false;
-
- if (!resource->inCache())
- return false;
-
- if (resource->isPurgeable())
- return true;
-
- if (!resource->isSafeToMakePurgeable())
- return false;
-
- if (!resource->makePurgeable(true))
- return false;
-
- adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
-
- return true;
-}
-
-void MemoryCache::evict(CachedResource* resource)
+void MemoryCache::remove(CachedResource& resource)
{
ASSERT(WTF::isMainThread());
- LOG(ResourceLoading, "Evicting resource %p for '%s' from cache", resource, resource->url().string().latin1().data());
+ LOG(ResourceLoading, "Evicting resource %p for '%s' from cache", &resource, resource.url().string().latin1().data());
// The resource may have already been removed by someone other than our caller,
// who needed a fresh copy for a reload. See <http://bugs.webkit.org/show_bug.cgi?id=12479#c6>.
- if (resource->inCache()) {
- // Remove from the resource map.
-#if ENABLE(CACHE_PARTITIONING)
- CachedResourceItem* item = m_resources.get(resource->url());
- if (item) {
- item->remove(resource->cachePartition());
- if (!item->size())
- m_resources.remove(resource->url());
- }
-#else
- m_resources.remove(resource->url());
-#endif
- resource->setInCache(false);
-
- // Remove from the appropriate LRU list.
- removeFromLRUList(resource);
- removeFromLiveDecodedResourcesList(resource);
-
- // If the resource was purged, it means we had already decremented the size when we made the
- // resource purgeable in makeResourcePurgeable(). So adjust the size if we are evicting a
- // resource that was not marked as purgeable.
- if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() || !resource->isPurgeable())
- adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
- } else
-#if ENABLE(CACHE_PARTITIONING)
- ASSERT(!m_resources.get(resource->url()) || m_resources.get(resource->url())->get(resource->cachePartition()) != resource);
-#else
- ASSERT(m_resources.get(resource->url()) != resource);
-#endif
+ if (auto* resources = sessionResourceMap(resource.sessionID())) {
+ auto key = std::make_pair(resource.url(), resource.cachePartition());
+
+ if (resource.inCache()) {
+ // Remove resource from the resource map.
+ resources->remove(key);
+ resource.setInCache(false);
+
+ // If the resource map is now empty, remove it from m_sessionResources.
+ if (resources->isEmpty())
+ m_sessionResources.remove(resource.sessionID());
+
+ // Remove from the appropriate LRU list.
+ removeFromLRUList(resource);
+ removeFromLiveDecodedResourcesList(resource);
+ adjustSize(resource.hasClients(), -static_cast<long long>(resource.size()));
+ } else
+ ASSERT(resources->get(key) != &resource);
+ }
- resource->deleteIfPossible();
+ resource.deleteIfPossible();
}
-MemoryCache::LRUList* MemoryCache::lruListFor(CachedResource* resource)
+auto MemoryCache::lruListFor(CachedResource& resource) -> LRUList&
{
- unsigned accessCount = std::max(resource->accessCount(), 1U);
- unsigned queueIndex = WTF::fastLog2(resource->size() / accessCount);
+ unsigned accessCount = std::max(resource.accessCount(), 1U);
+ unsigned queueIndex = WTF::fastLog2(resource.size() / accessCount);
#ifndef NDEBUG
- resource->m_lruIndex = queueIndex;
+ resource.m_lruIndex = queueIndex;
#endif
- if (m_allResources.size() <= queueIndex)
- m_allResources.grow(queueIndex + 1);
- return &m_allResources[queueIndex];
+
+ m_allResources.reserveCapacity(queueIndex + 1);
+ while (m_allResources.size() <= queueIndex)
+ m_allResources.uncheckedAppend(std::make_unique<LRUList>());
+ return *m_allResources[queueIndex];
}
-void MemoryCache::removeFromLRUList(CachedResource* resource)
+void MemoryCache::removeFromLRUList(CachedResource& resource)
{
// If we've never been accessed, then we're brand new and not in any list.
- if (resource->accessCount() == 0)
+ if (!resource.accessCount())
return;
#if !ASSERT_DISABLED
- unsigned oldListIndex = resource->m_lruIndex;
+ unsigned oldListIndex = resource.m_lruIndex;
#endif
- LRUList* list = lruListFor(resource);
+ LRUList& list = lruListFor(resource);
-#if !ASSERT_DISABLED
// Verify that the list we got is the list we want.
- ASSERT(resource->m_lruIndex == oldListIndex);
-
- // Verify that we are in fact in this list.
- bool found = false;
- for (CachedResource* current = list->m_head; current; current = current->m_nextInAllResourcesList) {
- if (current == resource) {
- found = true;
- break;
- }
- }
- ASSERT(found);
-#endif
-
- CachedResource* next = resource->m_nextInAllResourcesList;
- CachedResource* prev = resource->m_prevInAllResourcesList;
-
- if (next == 0 && prev == 0 && list->m_head != resource)
- return;
-
- resource->m_nextInAllResourcesList = 0;
- resource->m_prevInAllResourcesList = 0;
-
- if (next)
- next->m_prevInAllResourcesList = prev;
- else if (list->m_tail == resource)
- list->m_tail = prev;
+ ASSERT(resource.m_lruIndex == oldListIndex);
- if (prev)
- prev->m_nextInAllResourcesList = next;
- else if (list->m_head == resource)
- list->m_head = next;
+ bool removed = list.remove(&resource);
+ ASSERT_UNUSED(removed, removed);
}
-void MemoryCache::insertInLRUList(CachedResource* resource)
+void MemoryCache::insertInLRUList(CachedResource& resource)
{
- // Make sure we aren't in some list already.
- ASSERT(!resource->m_nextInAllResourcesList && !resource->m_prevInAllResourcesList);
- ASSERT(resource->inCache());
- ASSERT(resource->accessCount() > 0);
-
- LRUList* list = lruListFor(resource);
-
- resource->m_nextInAllResourcesList = list->m_head;
- if (list->m_head)
- list->m_head->m_prevInAllResourcesList = resource;
- list->m_head = resource;
+ ASSERT(resource.inCache());
+ ASSERT(resource.accessCount() > 0);
- if (!resource->m_nextInAllResourcesList)
- list->m_tail = resource;
-
-#if !ASSERT_DISABLED
- // Verify that we are in now in the list like we should be.
- list = lruListFor(resource);
- bool found = false;
- for (CachedResource* current = list->m_head; current; current = current->m_nextInAllResourcesList) {
- if (current == resource) {
- found = true;
- break;
- }
- }
- ASSERT(found);
-#endif
-
+ auto addResult = lruListFor(resource).add(&resource);
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
}
-void MemoryCache::resourceAccessed(CachedResource* resource)
+void MemoryCache::resourceAccessed(CachedResource& resource)
{
- ASSERT(resource->inCache());
+ ASSERT(resource.inCache());
// Need to make sure to remove before we increase the access count, since
// the queue will possibly change.
removeFromLRUList(resource);
// If this is the first time the resource has been accessed, adjust the size of the cache to account for its initial size.
- if (!resource->accessCount())
- adjustSize(resource->hasClients(), resource->size());
+ if (!resource.accessCount())
+ adjustSize(resource.hasClients(), resource.size());
// Add to our access count.
- resource->increaseAccessCount();
+ resource.increaseAccessCount();
// Now insert into the new queue.
insertInLRUList(resource);
}
-void MemoryCache::removeResourcesWithOrigin(SecurityOrigin* origin)
+void MemoryCache::removeResourcesWithOrigin(SecurityOrigin& origin)
{
- Vector<CachedResource*> resourcesWithOrigin;
-
- CachedResourceMap::iterator e = m_resources.end();
-#if ENABLE(CACHE_PARTITIONING)
- String originPartition = ResourceRequest::partitionName(origin->host());
-#endif
+ String originPartition = ResourceRequest::partitionName(origin.host());
- for (CachedResourceMap::iterator it = m_resources.begin(); it != e; ++it) {
-#if ENABLE(CACHE_PARTITIONING)
- for (CachedResourceItem::iterator itemIterator = it->value->begin(); itemIterator != it->value->end(); ++itemIterator) {
- CachedResource* resource = itemIterator->value;
- String partition = itemIterator->key;
- if (partition == originPartition) {
- resourcesWithOrigin.append(resource);
+ Vector<CachedResource*> resourcesWithOrigin;
+ for (auto& resources : m_sessionResources.values()) {
+ for (auto& keyValue : *resources) {
+ auto& resource = *keyValue.value;
+ auto& partitionName = keyValue.key.second;
+ if (partitionName == originPartition) {
+ resourcesWithOrigin.append(&resource);
continue;
}
-#else
- CachedResource* resource = it->value;
-#endif
- RefPtr<SecurityOrigin> resourceOrigin = SecurityOrigin::createFromString(resource->url());
- if (!resourceOrigin)
- continue;
- if (resourceOrigin->equal(origin))
- resourcesWithOrigin.append(resource);
-#if ENABLE(CACHE_PARTITIONING)
+ RefPtr<SecurityOrigin> resourceOrigin = SecurityOrigin::create(resource.url());
+ if (resourceOrigin->equal(&origin))
+ resourcesWithOrigin.append(&resource);
}
-#endif
}
- for (size_t i = 0; i < resourcesWithOrigin.size(); ++i)
- remove(resourcesWithOrigin[i]);
+ for (auto* resource : resourcesWithOrigin)
+ remove(*resource);
+}
+
+void MemoryCache::removeResourcesWithOrigins(SessionID sessionID, const HashSet<RefPtr<SecurityOrigin>>& origins)
+{
+ auto* resourceMap = sessionResourceMap(sessionID);
+ if (!resourceMap)
+ return;
+
+ HashSet<String> originPartitions;
+
+ for (auto& origin : origins)
+ originPartitions.add(ResourceRequest::partitionName(origin->host()));
+
+ Vector<CachedResource*> resourcesToRemove;
+ for (auto& keyValuePair : *resourceMap) {
+ auto& resource = *keyValuePair.value;
+ auto& partitionName = keyValuePair.key.second;
+ if (originPartitions.contains(partitionName)) {
+ resourcesToRemove.append(&resource);
+ continue;
+ }
+ if (origins.contains(SecurityOrigin::create(resource.url()).ptr()))
+ resourcesToRemove.append(&resource);
+ }
+
+ for (auto& resource : resourcesToRemove)
+ remove(*resource);
}
void MemoryCache::getOriginsWithCache(SecurityOriginSet& origins)
{
-#if ENABLE(CACHE_PARTITIONING)
- DEFINE_STATIC_LOCAL(String, httpString, ("http"));
-#endif
- CachedResourceMap::iterator e = m_resources.end();
- for (CachedResourceMap::iterator it = m_resources.begin(); it != e; ++it) {
-#if ENABLE(CACHE_PARTITIONING)
- if (it->value->begin()->key == emptyString())
- origins.add(SecurityOrigin::createFromString(it->value->begin()->value->url()));
- else
- origins.add(SecurityOrigin::create(httpString, it->value->begin()->key, 0));
-#else
- origins.add(SecurityOrigin::createFromString(it->value->url()));
-#endif
+ for (auto& resources : m_sessionResources.values()) {
+ for (auto& keyValue : *resources) {
+ auto& resource = *keyValue.value;
+ auto& partitionName = keyValue.key.second;
+ if (!partitionName.isEmpty())
+ origins.add(SecurityOrigin::create(ASCIILiteral("http"), partitionName, 0));
+ else
+ origins.add(SecurityOrigin::create(resource.url()));
+ }
}
}
-void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource* resource)
+HashSet<RefPtr<SecurityOrigin>> MemoryCache::originsWithCache(SessionID sessionID) const
{
- // If we've never been accessed, then we're brand new and not in any list.
- if (!resource->m_inLiveDecodedResourcesList)
- return;
- resource->m_inLiveDecodedResourcesList = false;
+ HashSet<RefPtr<SecurityOrigin>> origins;
-#if !ASSERT_DISABLED
- // Verify that we are in fact in this list.
- bool found = false;
- for (CachedResource* current = m_liveDecodedResources.m_head; current; current = current->m_nextInLiveResourcesList) {
- if (current == resource) {
- found = true;
- break;
+ auto it = m_sessionResources.find(sessionID);
+ if (it != m_sessionResources.end()) {
+ for (auto& keyValue : *it->value) {
+ auto& resource = *keyValue.value;
+ auto& partitionName = keyValue.key.second;
+ if (!partitionName.isEmpty())
+ origins.add(SecurityOrigin::create("http", partitionName, 0));
+ else
+ origins.add(SecurityOrigin::create(resource.url()));
}
}
- ASSERT(found);
-#endif
- CachedResource* next = resource->m_nextInLiveResourcesList;
- CachedResource* prev = resource->m_prevInLiveResourcesList;
-
- if (next == 0 && prev == 0 && m_liveDecodedResources.m_head != resource)
- return;
-
- resource->m_nextInLiveResourcesList = 0;
- resource->m_prevInLiveResourcesList = 0;
-
- if (next)
- next->m_prevInLiveResourcesList = prev;
- else if (m_liveDecodedResources.m_tail == resource)
- m_liveDecodedResources.m_tail = prev;
+ return origins;
+}
- if (prev)
- prev->m_nextInLiveResourcesList = next;
- else if (m_liveDecodedResources.m_head == resource)
- m_liveDecodedResources.m_head = next;
+void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource& resource)
+{
+ m_liveDecodedResources.remove(&resource);
}
-void MemoryCache::insertInLiveDecodedResourcesList(CachedResource* resource)
+void MemoryCache::insertInLiveDecodedResourcesList(CachedResource& resource)
{
// Make sure we aren't in the list already.
- ASSERT(!resource->m_nextInLiveResourcesList && !resource->m_prevInLiveResourcesList && !resource->m_inLiveDecodedResourcesList);
- resource->m_inLiveDecodedResourcesList = true;
-
- resource->m_nextInLiveResourcesList = m_liveDecodedResources.m_head;
- if (m_liveDecodedResources.m_head)
- m_liveDecodedResources.m_head->m_prevInLiveResourcesList = resource;
- m_liveDecodedResources.m_head = resource;
-
- if (!resource->m_nextInLiveResourcesList)
- m_liveDecodedResources.m_tail = resource;
-
-#if !ASSERT_DISABLED
- // Verify that we are in now in the list like we should be.
- bool found = false;
- for (CachedResource* current = m_liveDecodedResources.m_head; current; current = current->m_nextInLiveResourcesList) {
- if (current == resource) {
- found = true;
- break;
- }
- }
- ASSERT(found);
-#endif
-
+ ASSERT(!m_liveDecodedResources.contains(&resource));
+ m_liveDecodedResources.add(&resource);
}
-void MemoryCache::addToLiveResourcesSize(CachedResource* resource)
+void MemoryCache::addToLiveResourcesSize(CachedResource& resource)
{
- m_liveSize += resource->size();
- m_deadSize -= resource->size();
+ m_liveSize += resource.size();
+ m_deadSize -= resource.size();
}
-void MemoryCache::removeFromLiveResourcesSize(CachedResource* resource)
+void MemoryCache::removeFromLiveResourcesSize(CachedResource& resource)
{
- m_liveSize -= resource->size();
- m_deadSize += resource->size();
+ m_liveSize -= resource.size();
+ m_deadSize += resource.size();
}
-void MemoryCache::adjustSize(bool live, int delta)
+void MemoryCache::adjustSize(bool live, long long delta)
{
if (live) {
- ASSERT(delta >= 0 || ((int)m_liveSize + delta >= 0));
+ ASSERT(delta >= 0 || (static_cast<long long>(m_liveSize) + delta >= 0));
m_liveSize += delta;
} else {
- ASSERT(delta >= 0 || ((int)m_deadSize + delta >= 0));
+ ASSERT(delta >= 0 || (static_cast<long long>(m_deadSize) + delta >= 0));
m_deadSize += delta;
}
}
-void MemoryCache::removeUrlFromCache(ScriptExecutionContext* context, const String& urlString)
-{
- removeRequestFromCache(context, ResourceRequest(urlString));
-}
-
-void MemoryCache::removeRequestFromCache(ScriptExecutionContext* context, const ResourceRequest& request)
+void MemoryCache::removeRequestFromSessionCaches(ScriptExecutionContext& context, const ResourceRequest& request)
{
- if (context->isWorkerGlobalScope()) {
- WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(context);
- workerGlobalScope->thread()->workerLoaderProxy().postTaskToLoader(createCallbackTask(&crossThreadRemoveRequestFromCache, request));
+ if (is<WorkerGlobalScope>(context)) {
+ downcast<WorkerGlobalScope>(context).thread().workerLoaderProxy().postTaskToLoader([request = request.isolatedCopy()] (ScriptExecutionContext& context) {
+ MemoryCache::removeRequestFromSessionCaches(context, request);
+ });
return;
}
- removeRequestFromCacheImpl(context, request);
-}
-
-void MemoryCache::removeRequestFromCacheImpl(ScriptExecutionContext*, const ResourceRequest& request)
-{
- if (CachedResource* resource = memoryCache()->resourceForRequest(request))
- memoryCache()->remove(resource);
-}
-
-void MemoryCache::crossThreadRemoveRequestFromCache(ScriptExecutionContext* context, PassOwnPtr<WebCore::CrossThreadResourceRequestData> requestData)
-{
- OwnPtr<ResourceRequest> request(ResourceRequest::adopt(requestData));
- MemoryCache::removeRequestFromCacheImpl(context, *request);
+ auto& memoryCache = MemoryCache::singleton();
+ for (auto& resources : memoryCache.m_sessionResources) {
+ if (CachedResource* resource = memoryCache.resourceForRequestImpl(request, *resources.value))
+ memoryCache.remove(*resource);
+ }
}
-void MemoryCache::TypeStatistic::addResource(CachedResource* o)
+void MemoryCache::TypeStatistic::addResource(CachedResource& resource)
{
- bool purged = o->wasPurged();
- bool purgeable = o->isPurgeable() && !purged;
- int pageSize = (o->encodedSize() + o->overheadSize() + 4095) & ~4095;
count++;
- size += purged ? 0 : o->size();
- liveSize += o->hasClients() ? o->size() : 0;
- decodedSize += o->decodedSize();
- purgeableSize += purgeable ? pageSize : 0;
- purgedSize += purged ? pageSize : 0;
-#if ENABLE(DISK_IMAGE_CACHE)
- // Only the data inside the resource was mapped, not the entire resource.
- mappedSize += o->isUsingDiskImageCache() ? o->resourceBuffer()->sharedBuffer()->size() : 0;
-#endif
+ size += resource.size();
+ liveSize += resource.hasClients() ? resource.size() : 0;
+ decodedSize += resource.decodedSize();
}
MemoryCache::Statistics MemoryCache::getStatistics()
{
Statistics stats;
- CachedResourceMap::iterator e = m_resources.end();
- for (CachedResourceMap::iterator i = m_resources.begin(); i != e; ++i) {
-#if ENABLE(CACHE_PARTITIONING)
- for (CachedResourceItem::iterator itemIterator = i->value->begin(); itemIterator != i->value->end(); ++itemIterator) {
- CachedResource* resource = itemIterator->value;
-#else
- CachedResource* resource = i->value;
-#endif
+
+ for (auto& resources : m_sessionResources.values()) {
+ for (auto* resource : resources->values()) {
switch (resource->type()) {
case CachedResource::ImageResource:
- stats.images.addResource(resource);
+ stats.images.addResource(*resource);
break;
case CachedResource::CSSStyleSheet:
- stats.cssStyleSheets.addResource(resource);
+ stats.cssStyleSheets.addResource(*resource);
break;
case CachedResource::Script:
- stats.scripts.addResource(resource);
+ stats.scripts.addResource(*resource);
break;
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
- stats.xslStyleSheets.addResource(resource);
+ stats.xslStyleSheets.addResource(*resource);
break;
#endif
+#if ENABLE(SVG_FONTS)
+ case CachedResource::SVGFontResource:
+#endif
case CachedResource::FontResource:
- stats.fonts.addResource(resource);
+ stats.fonts.addResource(*resource);
break;
default:
break;
}
-#if ENABLE(CACHE_PARTITIONING)
}
-#endif
}
return stats;
}
@@ -893,16 +690,10 @@ void MemoryCache::setDisabled(bool disabled)
if (!m_disabled)
return;
- for (;;) {
- CachedResourceMap::iterator outerIterator = m_resources.begin();
- if (outerIterator == m_resources.end())
- break;
-#if ENABLE(CACHE_PARTITIONING)
- CachedResourceItem::iterator innerIterator = outerIterator->value->begin();
- evict(innerIterator->value);
-#else
- evict(outerIterator->value);
-#endif
+ while (!m_sessionResources.isEmpty()) {
+ auto& resources = *m_sessionResources.begin()->value;
+ ASSERT(!resources.isEmpty());
+ remove(*resources.begin()->value);
}
}
@@ -915,66 +706,65 @@ void MemoryCache::evictResources()
setDisabled(false);
}
+void MemoryCache::evictResources(SessionID sessionID)
+{
+ if (disabled())
+ return;
+
+ forEachSessionResource(sessionID, [this] (CachedResource& resource) { remove(resource); });
+
+ ASSERT(!m_sessionResources.contains(sessionID));
+}
+
+bool MemoryCache::needsPruning() const
+{
+ return m_liveSize + m_deadSize > m_capacity || m_deadSize > m_maxDeadCapacity;
+}
+
void MemoryCache::prune()
{
- if (m_liveSize + m_deadSize <= m_capacity && m_deadSize <= m_maxDeadCapacity) // Fast path.
+ if (!needsPruning())
return;
pruneDeadResources(); // Prune dead first, in case it was "borrowing" capacity from live.
pruneLiveResources();
}
-void MemoryCache::pruneToPercentage(float targetPercentLive)
+void MemoryCache::pruneSoon()
{
- pruneDeadResourcesToPercentage(targetPercentLive); // Prune dead first, in case it was "borrowing" capacity from live.
- pruneLiveResourcesToPercentage(targetPercentLive);
+ if (m_pruneTimer.isActive())
+ return;
+ if (!needsPruning())
+ return;
+ m_pruneTimer.startOneShot(0);
}
-
#ifndef NDEBUG
void MemoryCache::dumpStats()
{
Statistics s = getStatistics();
-#if ENABLE(DISK_IMAGE_CACHE)
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize", "PurgeableSize", "PurgedSize", "Mapped", "\"Real\"");
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
- printf("%-13s %13d %13d %13d %13d %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize, s.images.purgeableSize, s.images.purgedSize, s.images.mappedSize, s.images.size - s.images.mappedSize);
-#else
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize", "PurgeableSize", "PurgedSize");
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize, s.images.purgeableSize, s.images.purgedSize);
-#endif
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize, s.cssStyleSheets.purgeableSize, s.cssStyleSheets.purgedSize);
+ printf("%-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize");
+ printf("%-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------");
+ printf("%-13s %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize);
+ printf("%-13s %13d %13d %13d %13d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize);
#if ENABLE(XSLT)
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize, s.xslStyleSheets.purgeableSize, s.xslStyleSheets.purgedSize);
+ printf("%-13s %13d %13d %13d %13d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize);
#endif
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize, s.scripts.purgeableSize, s.scripts.purgedSize);
- printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize, s.fonts.purgeableSize, s.fonts.purgedSize);
- printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
+ printf("%-13s %13d %13d %13d %13d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize);
+ printf("%-13s %13d %13d %13d %13d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize);
+ printf("%-13s %-13s %-13s %-13s %-13s\n\n", "-------------", "-------------", "-------------", "-------------", "-------------");
}
void MemoryCache::dumpLRULists(bool includeLive) const
{
-#if ENABLE(DISK_IMAGE_CACHE)
- printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged, isMemoryMapped):\n");
-#else
- printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged):\n");
-#endif
+ printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced):\n");
int size = m_allResources.size();
for (int i = size - 1; i >= 0; i--) {
printf("\n\nList %d: ", i);
- CachedResource* current = m_allResources[i].m_tail;
- while (current) {
- CachedResource* prev = current->m_prevInAllResourcesList;
- if (includeLive || !current->hasClients())
-#if ENABLE(DISK_IMAGE_CACHE)
- printf("(%.1fK, %.1fK, %uA, %dR, %d, %d, %d); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients(), current->isPurgeable(), current->wasPurged(), current->isUsingDiskImageCache());
-#else
- printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients(), current->isPurgeable(), current->wasPurged());
-#endif
-
- current = prev;
+ for (auto* resource : *m_allResources[i]) {
+ if (includeLive || !resource->hasClients())
+ printf("(%.1fK, %.1fK, %uA, %dR); ", resource->decodedSize() / 1024.0f, (resource->encodedSize() + resource->overheadSize()) / 1024.0f, resource->accessCount(), resource->hasClients());
}
}
}