diff options
Diffstat (limited to 'WebCore/loader')
-rw-r--r-- | WebCore/loader/Cache.cpp | 40 | ||||
-rw-r--r-- | WebCore/loader/Cache.h | 28 | ||||
-rw-r--r-- | WebCore/loader/CachedCSSStyleSheet.cpp | 3 | ||||
-rw-r--r-- | WebCore/loader/CachedFont.cpp | 2 | ||||
-rw-r--r-- | WebCore/loader/CachedImage.cpp | 3 | ||||
-rw-r--r-- | WebCore/loader/CachedScript.cpp | 3 | ||||
-rw-r--r-- | WebCore/loader/EmptyClients.h | 5 | ||||
-rw-r--r-- | WebCore/loader/FrameLoaderClient.h | 4 | ||||
-rw-r--r-- | WebCore/loader/PingLoader.cpp | 32 | ||||
-rw-r--r-- | WebCore/loader/PingLoader.h | 4 | ||||
-rw-r--r-- | WebCore/loader/RedirectScheduler.cpp | 2 |
11 files changed, 112 insertions, 14 deletions
diff --git a/WebCore/loader/Cache.cpp b/WebCore/loader/Cache.cpp index dbcec00..28c9f93 100644 --- a/WebCore/loader/Cache.cpp +++ b/WebCore/loader/Cache.cpp @@ -238,11 +238,15 @@ void Cache::revalidationFailed(CachedResource* revalidatingResource) CachedResource* Cache::resourceForURL(const String& url) { CachedResource* resource = m_resources.get(url); + bool wasPurgeable = Cache::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; } @@ -363,7 +367,9 @@ void Cache::pruneDeadResources() while (current) { CachedResource* prev = current->m_prevInAllResourcesList; if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) { - evict(current); + if (!makeResourcePurgeable(current)) + evict(current); + // If evict() caused pruneDeadResources() to be re-entered, bail out. This can happen when removing an // SVG CachedImage that has subresources. if (!m_inPruneDeadResources) @@ -397,6 +403,25 @@ void Cache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned prune(); } +bool Cache::makeResourcePurgeable(CachedResource* resource) +{ + if (!Cache::shouldMakeResourcePurgeableOnEviction()) + return false; + + if (!resource->inCache()) + return false; + + if (!resource->isSafeToMakePurgeable()) + return false; + + if (!resource->makePurgeable(true)) + return false; + + adjustSize(resource->hasClients(), -static_cast<int>(resource->size())); + + return true; +} + void Cache::evict(CachedResource* resource) { // The resource may have already been removed by someone other than our caller, @@ -410,10 +435,10 @@ void Cache::evict(CachedResource* resource) removeFromLRUList(resource); removeFromLiveDecodedResourcesList(resource); - // Subtract from our size totals. - int delta = -static_cast<int>(resource->size()); - if (delta) - adjustSize(resource->hasClients(), delta); + // If the resource was purged, it means we had already decremented the size when we made the + // resource purgeable in makeResourcePurgeable(). + if (!Cache::shouldMakeResourcePurgeableOnEviction() || !resource->wasPurged()) + adjustSize(resource->hasClients(), -static_cast<int>(resource->size())); } else ASSERT(m_resources.get(resource->url()) != resource); @@ -725,7 +750,7 @@ void Cache::dumpStats() void Cache::dumpLRULists(bool includeLive) const { - printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced):\n"); + printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged):\n"); int size = m_allResources.size(); for (int i = size - 1; i >= 0; i--) { @@ -734,7 +759,8 @@ void Cache::dumpLRULists(bool includeLive) const while (current) { CachedResource* prev = current->m_prevInAllResourcesList; if (includeLive || !current->hasClients()) - printf("(%.1fK, %.1fK, %uA, %dR); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients()); + 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()); + current = prev; } } diff --git a/WebCore/loader/Cache.h b/WebCore/loader/Cache.h index 9d7e8be..eb5b398 100644 --- a/WebCore/loader/Cache.h +++ b/WebCore/loader/Cache.h @@ -55,6 +55,22 @@ class KURL; // -------|-----+++++++++++++++| // -------|-----+++++++++++++++|+++++ +// The behavior of the cache changes in the following way if shouldMakeResourcePurgeableOnEviction +// returns true. +// +// 1. Dead resources in the cache are kept in non-purgeable memory. +// 2. When we prune dead resources, instead of freeing them, we mark their memory as purgeable and +// keep the resources until the kernel reclaims the purgeable memory. +// +// By leaving the in-cache dead resources in dirty resident memory, we decrease the likelihood of +// the kernel claiming that memory and forcing us to refetch the resource (for example when a user +// presses back). +// +// And by having an unbounded number of resource objects using purgeable memory, we can use as much +// memory as is available on the machine. The trade-off here is that the CachedResource object (and +// its member variables) are allocated in non-purgeable TC-malloc'd memory so we would see slightly +// more memory use due to this. + class Cache : public Noncopyable { public: friend Cache* cache(); @@ -148,6 +164,8 @@ public: void addToLiveResourcesSize(CachedResource*); void removeFromLiveResourcesSize(CachedResource*); + static bool shouldMakeResourcePurgeableOnEviction(); + // Function to collect cache statistics for the caches window in the Safari Debug menu. Statistics getStatistics(); @@ -173,6 +191,7 @@ private: void pruneDeadResources(); // Flush decoded and encoded data from resources not referenced by Web pages. void pruneLiveResources(); // Flush decoded data from resources still referenced by Web pages. + bool makeResourcePurgeable(CachedResource*); void evict(CachedResource*); // Member variables. @@ -204,6 +223,15 @@ private: HashMap<String, CachedResource*> m_resources; }; +inline bool Cache::shouldMakeResourcePurgeableOnEviction() +{ +#if PLATFORM(IOS) + return true; +#else + return false; +#endif +} + // Function to obtain the global cache. Cache* cache(); diff --git a/WebCore/loader/CachedCSSStyleSheet.cpp b/WebCore/loader/CachedCSSStyleSheet.cpp index 7866efd..877cd1d 100644 --- a/WebCore/loader/CachedCSSStyleSheet.cpp +++ b/WebCore/loader/CachedCSSStyleSheet.cpp @@ -27,6 +27,7 @@ #include "config.h" #include "CachedCSSStyleSheet.h" +#include "Cache.h" #include "CachedResourceClient.h" #include "CachedResourceClientWalker.h" #include "HTTPParsers.h" @@ -58,7 +59,7 @@ void CachedCSSStyleSheet::didAddClient(CachedResourceClient *c) void CachedCSSStyleSheet::allClientsRemoved() { - if (isSafeToMakePurgeable()) + if (!Cache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable()) makePurgeable(true); } diff --git a/WebCore/loader/CachedFont.cpp b/WebCore/loader/CachedFont.cpp index 166fa85..ef88af8 100644 --- a/WebCore/loader/CachedFont.cpp +++ b/WebCore/loader/CachedFont.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "CachedFont.h" -#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(WINDOWS) || OS(LINUX))) || PLATFORM(HAIKU) || OS(WINCE) || PLATFORM(ANDROID) +#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(WINDOWS) || OS(LINUX) || OS(FREEBSD))) || PLATFORM(HAIKU) || OS(WINCE) || PLATFORM(ANDROID) #define STORE_FONT_CUSTOM_PLATFORM_DATA #endif diff --git a/WebCore/loader/CachedImage.cpp b/WebCore/loader/CachedImage.cpp index 908c425..641ce94 100644 --- a/WebCore/loader/CachedImage.cpp +++ b/WebCore/loader/CachedImage.cpp @@ -338,7 +338,8 @@ void CachedImage::destroyDecodedData() // Invoking addClient() will reconstruct the image object. m_image = 0; setDecodedSize(0); - makePurgeable(true); + if (!Cache::shouldMakeResourcePurgeableOnEviction()) + makePurgeable(true); } else if (m_image && !errorOccurred()) m_image->destroyDecodedData(); } diff --git a/WebCore/loader/CachedScript.cpp b/WebCore/loader/CachedScript.cpp index 58895d6..1898438 100644 --- a/WebCore/loader/CachedScript.cpp +++ b/WebCore/loader/CachedScript.cpp @@ -27,6 +27,7 @@ #include "config.h" #include "CachedScript.h" +#include "Cache.h" #include "CachedResourceClient.h" #include "CachedResourceClientWalker.h" #include "SharedBuffer.h" @@ -110,7 +111,7 @@ void CachedScript::destroyDecodedData() { m_script = String(); setDecodedSize(0); - if (isSafeToMakePurgeable()) + if (!Cache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable()) makePurgeable(true); } diff --git a/WebCore/loader/EmptyClients.h b/WebCore/loader/EmptyClients.h index f295663..6fb003e 100644 --- a/WebCore/loader/EmptyClients.h +++ b/WebCore/loader/EmptyClients.h @@ -340,7 +340,7 @@ public: virtual void didDisplayInsecureContent() { } virtual void didRunInsecureContent(SecurityOrigin*) { } virtual PassRefPtr<Frame> createFrame(const KURL&, const String&, HTMLFrameOwnerElement*, const String&, bool, int, int) { return 0; } - virtual void didTransferChildFrameToNewDocument() { } + virtual void didTransferChildFrameToNewDocument(Page*) { } virtual PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool) { return 0; } virtual PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL&, const Vector<String>&, const Vector<String>&) { return 0; } #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) @@ -361,6 +361,7 @@ public: virtual void didCreateScriptContextForFrame() { } virtual void didDestroyScriptContextForFrame() { } virtual void didCreateIsolatedScriptContext() { } + virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; } #endif virtual void registerForIconNotification(bool) { } @@ -550,6 +551,7 @@ public: virtual void startUpdating() { } virtual void stopUpdating() { } virtual DeviceMotionData* currentDeviceMotion() const { return 0; } + virtual void deviceMotionControllerDestroyed() { } }; class EmptyDeviceOrientationClient : public DeviceOrientationClient { @@ -558,6 +560,7 @@ public: virtual void startUpdating() { } virtual void stopUpdating() { } virtual DeviceOrientation* lastOrientation() const { return 0; } + virtual void deviceOrientationControllerDestroyed() { } }; } diff --git a/WebCore/loader/FrameLoaderClient.h b/WebCore/loader/FrameLoaderClient.h index 427b81e..803eb11 100644 --- a/WebCore/loader/FrameLoaderClient.h +++ b/WebCore/loader/FrameLoaderClient.h @@ -64,6 +64,7 @@ namespace WebCore { class IntSize; class KURL; class NavigationAction; + class Page; class ProtectionSpace; class PluginView; class PolicyChecker; @@ -229,7 +230,7 @@ namespace WebCore { virtual PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) = 0; - virtual void didTransferChildFrameToNewDocument() = 0; + virtual void didTransferChildFrameToNewDocument(Page* oldPage) = 0; virtual PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool loadManually) = 0; virtual void redirectDataToPlugin(Widget* pluginWidget) = 0; @@ -253,6 +254,7 @@ namespace WebCore { virtual void didCreateScriptContextForFrame() = 0; virtual void didDestroyScriptContextForFrame() = 0; virtual void didCreateIsolatedScriptContext() = 0; + virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) = 0; #endif virtual void registerForIconNotification(bool listen = true) = 0; diff --git a/WebCore/loader/PingLoader.cpp b/WebCore/loader/PingLoader.cpp index 2a628ce..dd00128 100644 --- a/WebCore/loader/PingLoader.cpp +++ b/WebCore/loader/PingLoader.cpp @@ -32,6 +32,7 @@ #include "config.h" #include "PingLoader.h" +#include "FormData.h" #include "Frame.h" #include "ResourceHandle.h" #include "SecurityOrigin.h" @@ -60,9 +61,40 @@ void PingLoader::loadImage(Frame* frame, const KURL& url) UNUSED_PARAM(leakedPingLoader); } +// http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#hyperlink-auditing +void PingLoader::sendPing(Frame* frame, const KURL& pingURL, const KURL& destinationURL) +{ + ResourceRequest request(pingURL); + request.setTargetType(ResourceRequest::TargetIsSubresource); + request.setHTTPMethod("POST"); + request.setHTTPContentType("text/ping"); + request.setHTTPBody(FormData::create("PING")); + request.setHTTPHeaderField("Cache-Control", "max-age=0"); + frame->loader()->addExtraFieldsToSubresourceRequest(request); + + SecurityOrigin* sourceOrigin = frame->document()->securityOrigin(); + RefPtr<SecurityOrigin> pingOrigin = SecurityOrigin::create(pingURL); + FrameLoader::addHTTPOriginIfNeeded(request, sourceOrigin->toString()); + request.setHTTPHeaderField("Ping-To", destinationURL); + if (sourceOrigin->isSameSchemeHostPort(pingOrigin.get())) + request.setHTTPHeaderField("Ping-From", frame->document()->url()); + else if (!SecurityOrigin::shouldHideReferrer(pingURL, frame->loader()->outgoingReferrer())) + request.setHTTPReferrer(frame->loader()->outgoingReferrer()); + OwnPtr<PingLoader> pingLoader = adoptPtr(new PingLoader(frame, request)); + + // Leak the ping loader, since it will kill itself as soon as it receives a response. + PingLoader* leakedPingLoader = pingLoader.leakPtr(); + UNUSED_PARAM(leakedPingLoader); +} + PingLoader::PingLoader(Frame* frame, const ResourceRequest& request) + : m_timeout(this, &PingLoader::timeout) { m_handle = ResourceHandle::create(frame->loader()->networkingContext(), request, this, false, false); + + // If the server never responds, FrameLoader won't be able to cancel this load and + // we'll sit here waiting forever. Set a very generous timeout, just in case. + m_timeout.startOneShot(60000); } PingLoader::~PingLoader() diff --git a/WebCore/loader/PingLoader.h b/WebCore/loader/PingLoader.h index e26a9c9..eb43166 100644 --- a/WebCore/loader/PingLoader.h +++ b/WebCore/loader/PingLoader.h @@ -33,6 +33,7 @@ #define PingLoader_h #include "ResourceHandleClient.h" +#include "Timer.h" #include <wtf/Noncopyable.h> #include <wtf/RefPtr.h> @@ -52,6 +53,7 @@ class ResourceResponse; class PingLoader : private ResourceHandleClient, public Noncopyable { public: static void loadImage(Frame*, const KURL& url); + static void sendPing(Frame*, const KURL& pingURL, const KURL& destinationURL); ~PingLoader(); @@ -62,8 +64,10 @@ private: void didReceiveData(ResourceHandle*, const char*, int) { delete this; } void didFinishLoading(ResourceHandle*, double) { delete this; } void didFail(ResourceHandle*, const ResourceError&) { delete this; } + void timeout(Timer<PingLoader>*) { delete this; } RefPtr<ResourceHandle> m_handle; + Timer<PingLoader> m_timeout; }; } diff --git a/WebCore/loader/RedirectScheduler.cpp b/WebCore/loader/RedirectScheduler.cpp index ce0e3f8..ce41cde 100644 --- a/WebCore/loader/RedirectScheduler.cpp +++ b/WebCore/loader/RedirectScheduler.cpp @@ -318,7 +318,7 @@ void RedirectScheduler::scheduleFormSubmission(PassRefPtr<FormSubmission> submis // to match IE and Opera. // See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this. bool isUserGesture = m_frame->loader()->isProcessingUserGesture(); - bool lockBackForwardList = mustLockBackForwardList(m_frame, isUserGesture) || (submission->state()->formSubmissionTrigger() == SubmittedByJavaScript && m_frame->tree()->parent()); + bool lockBackForwardList = mustLockBackForwardList(m_frame, isUserGesture) || (submission->state()->formSubmissionTrigger() == SubmittedByJavaScript && m_frame->tree()->parent() && !isUserGesture); schedule(adoptPtr(new ScheduledFormSubmission(submission, lockBackForwardList, duringLoad, isUserGesture))); } |