[WK2] Have WebBackForwardCache class coordinate page caching in all WebProcesses
https://bugs.webkit.org/show_bug.cgi?id=202929
<rdar://problem/56250421>

Reviewed by Alex Christensen.

Source/WebCore:

Drop FrameLoaderClient::didSaveToPageCache() function as it is no longer needed.
Instead, we now call HistoryItem::notifyChanged() whenever HistoryItem::m_cachedPage
changes. This communicates to the UIProcess whether or not a HistoryItem has an
associated CachedPage.

I also added more release logging to the PageCache and renamed its logging channel
from PageCache to WebBackForwardCache to match the UIProcess's channel.

* history/BackForwardItemIdentifier.h:
(WebCore::BackForwardItemIdentifier::string const):
* history/CachedFrame.cpp:
(WebCore::CachedFrame::CachedFrame):
* history/HistoryItem.cpp:
(WebCore::HistoryItem::setCachedPage):
(WebCore::HistoryItem::takeCachedPage):
* history/HistoryItem.h:
* history/PageCache.cpp:
(WebCore::PageCache::addIfCacheable):
(WebCore::PageCache::take):
(WebCore::PageCache::removeAllItemsForPage):
(WebCore::PageCache::get):
(WebCore::PageCache::remove):
(WebCore::PageCache::prune):
* loader/EmptyFrameLoaderClient.h:
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::commitProvisionalLoad):
(WebCore::FrameLoader::loadProvisionalItemFromCachedPage):
* loader/FrameLoaderClient.h:
* platform/Logging.h:

Source/WebKit:

Have WebBackForwardCache class coordinate page caching in all WebProcesses. To achieve this, the
following changes were made:
1. Whenever HistoryItem::m_cachedPage changes in WebCore, we notify the client that the HistoryItem
   has changed. I added a "hasCachedPage" boolean to the item info being passed the the UIProcess
   that is set based on whether or not HistoryItem::m_cachedPage is null.
2. The WebBackForwardCache now contains WebBackForwardCacheEntry objects instead of SuspendedPage
   objects. A WebBackForwardCacheEntry may have a SuspendedPage or not. As a result, we can now
   add the the back/forward cache CachedPage entries from the WebContent process, which do not have
   a SuspendedPageProxy in the UIProcess.
3. Now that WebBackForwardCache is aware of all CachedPages, it can properly enforce a cache capacity
   across call processes. Whenever a WebBackForwardCacheEntry is pruned from the cache and this entry
   does not have a SuspendedPageProxy, we send an IPC to the WebContent process to remove this
   cached page from the PageCache in WebCore.

Previously, as soon as we would cache a page in the WebContent process, we would send an IPC to the
UIProcess so that it would clear the PageCache in any previous WebContent process. This was a stop-gap
measure to avoid blowing up memory in a multi-process model by keeping a PageCache around in all
WebContent process. This would make sure only one process could have a PageCache at any point in time.
This logic is now dropped since the WebBackForwardCache can keep track of all cached pages across all
processes and enforce a cross-process limit on the number of cached pages. This means we can now have
PageCache entries across several WebContent processes, as long as we do not exceed the maximum number
of cached pages.

* Platform/Logging.h:
Add new BackForwardCache logging channel.

* Shared/SessionState.cpp:
(WebKit::BackForwardListItemState::encode const):
(WebKit::BackForwardListItemState::decode):
* Shared/SessionState.h:
Add new bit to BackForwardListItemState to indicate whether a HistoryItem has an associated
CachedPage or not.

* Shared/WebBackForwardListItem.cpp:
(WebKit::WebBackForwardListItem::~WebBackForwardListItem):
(WebKit::WebBackForwardListItem::wasRemovedFromBackForwardList):
(WebKit::WebBackForwardListItem::removeFromBackForwardCache):
(WebKit::WebBackForwardListItem::setBackForwardCacheEntry):
(WebKit::WebBackForwardListItem::suspendedPage const):
(WebKit::WebBackForwardListItem::loggingString):
* Shared/WebBackForwardListItem.h:
(WebKit::WebBackForwardListItem::backForwardCacheEntry const):
WebBackForwardListItem now own a WebBackForwardCacheEntry instead of simply a
SuspendedPage. The WebBackForwardCacheEntry may have a SuspendedPage or not.
Now, whenever a HistoryItem has a CachedPage in WebCore, its corresponding
WebBackForwardListItem in the UIProcess has an associated WebBackForwardCacheEntry
whether we have a SuspendedPageProxy for it in the UIProcess or not.

* Shared/WebProcessCreationParameters.cpp:
(WebKit::WebProcessCreationParameters::encode const):
(WebKit::WebProcessCreationParameters::decode):
* Shared/WebProcessCreationParameters.h:
Pass the PageCache capacity to the WebContent process on creation, so that it matches the
capacity of the WebBackForwardCache in the UIProcess.

* UIProcess/ProvisionalPageProxy.cpp:
(WebKit::ProvisionalPageProxy::goToBackForwardItem):
* UIProcess/SuspendedPageProxy.cpp:
(WebKit::messageNamesToIgnoreWhileSuspended):
(WebKit::SuspendedPageProxy::suspensionTimedOut):
* UIProcess/SuspendedPageProxy.h:
Stop storing the WebBackForwardListItem on the SuspendedPageProxy. This avoids having to
keep this pointer up to date. We do not really need it as we can now ask the WebBackForwardCache
to clear an entry by giving it a SuspendedPageProxy to match. Given how many entries we have at
most in the cache (2), iterating over them to find the one with a given suspended page is cheap.

* UIProcess/WebBackForwardCache.cpp:
(WebKit::WebBackForwardCache::WebBackForwardCache):
(WebKit::WebBackForwardCache::~WebBackForwardCache):

(WebKit::WebBackForwardCache::setCapacity):
Send an IPC of each WebProcess whenever the capacity of the WebBackForwardCache changes, in order
to update the capacity of the PageCache in those processes.

(WebKit::WebBackForwardCache::addEntry):
(WebKit::WebBackForwardCache::removeEntry):
(WebKit::WebBackForwardCache::takeSuspendedPage):
(WebKit::WebBackForwardCache::removeEntriesForProcess):
(WebKit::WebBackForwardCache::removeEntriesForSession):
(WebKit::WebBackForwardCache::removeEntriesMatching):
(WebKit::WebBackForwardCache::clear):

* UIProcess/WebBackForwardCache.h:
Use a Vector instead of a ListHashSet to store the entries. Given that we have at most 2 entries, using
a Vector will likely be more efficient and definitely use less memory.

* UIProcess/WebBackForwardCacheEntry.h: Added.
(WebKit::WebBackForwardCacheEntry::backForwardCache const):
(WebKit::WebBackForwardCacheEntry::WebBackForwardCacheEntry):
Add new WebBackForwardCacheEntry abstraction to match the concept of WebCore::CachedPage in the UIProcess.
A WebBackForwardCacheEntry may have a SuspendedPageProxy associated with it in the UIProcess or not.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::receivedNavigationPolicyDecision):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
Drop didSaveToPageCache as it is no longer necessary.

* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::initializeNewWebProcess):
(WebKit::WebProcessPool::disconnectProcess):
* UIProcess/WebProcessPool.h:

* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::updateBackForwardItem):
Whenever we get a BackForwardItem from the WebContent process, we now check it now has
an associated CachedPage or not. If it does, we make sure we add a corresponding
entry in the WebBackForwardCache so that the UIProcess knows about it. If it no longer
has a CachedPage and we don't have a SuspendedPageProxy for this item in the UIProcess,
then we remove the corresponding entry from the back/forward cache. Note that we don't
drop SuspendedPageProxy objects in the UIProcess simply because their corresponding
CachedPage in the WebProcess is gone, to maintain previous behavior. This is an
optimization that is useful on iOS, where we do not have a WebProcessCache, since we
can reuse processes from SuspendedPageProxies on navigation.

* UIProcess/WebProcessProxy.h:
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/WebCoreSupport/SessionStateConversion.cpp:
(WebKit::toBackForwardListItemState):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
* WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::initializeWebProcess):
(WebKit::WebProcess::setBackForwardCacheCapacity):
(WebKit::WebProcess::clearCachedPage):
* WebProcess/WebProcess.h:
* WebProcess/WebProcess.messages.in:

Source/WebKitLegacy/mac:

* WebCoreSupport/WebFrameLoaderClient.h:
* WebCoreSupport/WebFrameLoaderClient.mm:

Source/WebKitLegacy/win:

* WebCoreSupport/WebFrameLoaderClient.cpp:
* WebCoreSupport/WebFrameLoaderClient.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251121 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 381daf2..8812361 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,41 @@
+2019-10-14  Chris Dumez  <cdumez@apple.com>
+
+        [WK2] Have WebBackForwardCache class coordinate page caching in all WebProcesses
+        https://bugs.webkit.org/show_bug.cgi?id=202929
+        <rdar://problem/56250421>
+
+        Reviewed by Alex Christensen.
+
+        Drop FrameLoaderClient::didSaveToPageCache() function as it is no longer needed.
+        Instead, we now call HistoryItem::notifyChanged() whenever HistoryItem::m_cachedPage
+        changes. This communicates to the UIProcess whether or not a HistoryItem has an
+        associated CachedPage.
+
+        I also added more release logging to the PageCache and renamed its logging channel
+        from PageCache to WebBackForwardCache to match the UIProcess's channel.
+
+        * history/BackForwardItemIdentifier.h:
+        (WebCore::BackForwardItemIdentifier::string const):
+        * history/CachedFrame.cpp:
+        (WebCore::CachedFrame::CachedFrame):
+        * history/HistoryItem.cpp:
+        (WebCore::HistoryItem::setCachedPage):
+        (WebCore::HistoryItem::takeCachedPage):
+        * history/HistoryItem.h:
+        * history/PageCache.cpp:
+        (WebCore::PageCache::addIfCacheable):
+        (WebCore::PageCache::take):
+        (WebCore::PageCache::removeAllItemsForPage):
+        (WebCore::PageCache::get):
+        (WebCore::PageCache::remove):
+        (WebCore::PageCache::prune):
+        * loader/EmptyFrameLoaderClient.h:
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::commitProvisionalLoad):
+        (WebCore::FrameLoader::loadProvisionalItemFromCachedPage):
+        * loader/FrameLoaderClient.h:
+        * platform/Logging.h:
+
 2019-10-14  Said Abou-Hallawa  <sabouhallawa@apple.com>
 
         Outsets for referenced SVG filters are always zero
diff --git a/Source/WebCore/history/BackForwardItemIdentifier.h b/Source/WebCore/history/BackForwardItemIdentifier.h
index 2dae52c..36d16ef 100644
--- a/Source/WebCore/history/BackForwardItemIdentifier.h
+++ b/Source/WebCore/history/BackForwardItemIdentifier.h
@@ -42,6 +42,8 @@
     template<class Encoder> void encode(Encoder&) const;
     template<class Decoder> static Optional<BackForwardItemIdentifier> decode(Decoder&);
 
+    String string() const { return makeString(processIdentifier.toUInt64(), '-', itemIdentifier.toUInt64()); }
+
 #if !LOG_DISABLED
     const char* logString() const;
 #endif
diff --git a/Source/WebCore/history/CachedFrame.cpp b/Source/WebCore/history/CachedFrame.cpp
index 59a26b9..8f1e4da 100644
--- a/Source/WebCore/history/CachedFrame.cpp
+++ b/Source/WebCore/history/CachedFrame.cpp
@@ -198,13 +198,11 @@
     if (!m_isMainFrame)
         frame.page()->decrementSubframeCount();
 
-    frame.loader().client().didSaveToPageCache();
-
 #ifndef NDEBUG
     if (m_isMainFrame)
-        LOG(PageCache, "Finished creating CachedFrame for main frame url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
+        LOG(BackForwardCache, "Finished creating CachedFrame for main frame url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
     else
-        LOG(PageCache, "Finished creating CachedFrame for child frame with url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
+        LOG(BackForwardCache, "Finished creating CachedFrame for child frame with url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
 #endif
 
 #if PLATFORM(IOS_FAMILY)
diff --git a/Source/WebCore/history/HistoryItem.cpp b/Source/WebCore/history/HistoryItem.cpp
index 3c059e6..a79234d 100644
--- a/Source/WebCore/history/HistoryItem.cpp
+++ b/Source/WebCore/history/HistoryItem.cpp
@@ -172,6 +172,22 @@
     return m_cachedPage ? m_cachedPage->hasExpired() : false;
 }
 
+void HistoryItem::setCachedPage(std::unique_ptr<CachedPage>&& cachedPage)
+{
+    bool wasInPageCache = isInPageCache();
+    m_cachedPage = WTFMove(cachedPage);
+    if (wasInPageCache != isInPageCache())
+        notifyChanged();
+}
+
+std::unique_ptr<CachedPage> HistoryItem::takeCachedPage()
+{
+    ASSERT(m_cachedPage);
+    auto cachedPage = std::exchange(m_cachedPage, nullptr);
+    notifyChanged();
+    return cachedPage;
+}
+
 URL HistoryItem::url() const
 {
     return URL({ }, m_urlString);
diff --git a/Source/WebCore/history/HistoryItem.h b/Source/WebCore/history/HistoryItem.h
index 8af98e4..f85508f 100644
--- a/Source/WebCore/history/HistoryItem.h
+++ b/Source/WebCore/history/HistoryItem.h
@@ -219,6 +219,9 @@
     WEBCORE_EXPORT HistoryItem(const String& urlString, const String& title, const String& alternateTitle);
     WEBCORE_EXPORT HistoryItem(const String& urlString, const String& title, const String& alternateTitle, BackForwardItemIdentifier);
 
+    void setCachedPage(std::unique_ptr<CachedPage>&&);
+    std::unique_ptr<CachedPage> takeCachedPage();
+
     HistoryItem(const HistoryItem&);
 
     static int64_t generateSequenceNumber();
diff --git a/Source/WebCore/history/PageCache.cpp b/Source/WebCore/history/PageCache.cpp
index e35942c..b264516 100644
--- a/Source/WebCore/history/PageCache.cpp
+++ b/Source/WebCore/history/PageCache.cpp
@@ -57,7 +57,7 @@
 
 namespace WebCore {
 
-#define PCLOG(...) LOG(PageCache, "%*s%s", indentLevel*4, "", makeString(__VA_ARGS__).utf8().data())
+#define PCLOG(...) LOG(BackForwardCache, "%*s%s", indentLevel*4, "", makeString(__VA_ARGS__).utf8().data())
 
 static inline void logPageCacheFailureDiagnosticMessage(DiagnosticLoggingClient& client, const String& reason)
 {
@@ -460,11 +460,14 @@
         // Make sure we don't fire any JS events in this scope.
         ScriptDisallowedScope::InMainThread scriptDisallowedScope;
 
-        item.m_cachedPage = makeUnique<CachedPage>(*page);
+        item.setCachedPage(makeUnique<CachedPage>(*page));
         item.m_pruningReason = PruningReason::None;
         m_items.add(&item);
     }
     prune(PruningReason::ReachedMaxSize);
+
+    RELEASE_LOG(BackForwardCache, "PageCache::addIfCacheable item: %s, size: %u / %u", item.identifier().string().utf8().data(), pageCount(), maxSize());
+
     return true;
 }
 
@@ -477,10 +480,12 @@
     }
 
     m_items.remove(&item);
-    std::unique_ptr<CachedPage> cachedPage = WTFMove(item.m_cachedPage);
+    std::unique_ptr<CachedPage> cachedPage = item.takeCachedPage();
+
+    RELEASE_LOG(BackForwardCache, "PageCache::take item: %s, size: %u / %u", item.identifier().string().utf8().data(), pageCount(), maxSize());
 
     if (cachedPage->hasExpired() || (page && page->isResourceCachingDisabled())) {
-        LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", item.url().string().ascii().data());
+        LOG(BackForwardCache, "Not restoring page for %s from back/forward cache because cache entry has expired", item.url().string().ascii().data());
         logPageCacheFailureDiagnosticMessage(page, DiagnosticLoggingKeys::expiredKey());
         return nullptr;
     }
@@ -500,7 +505,8 @@
         auto current = it;
         ++it;
         if (&(*current)->m_cachedPage->page() == &page) {
-            (*current)->m_cachedPage = nullptr;
+            RELEASE_LOG(BackForwardCache, "PageCache::removeAllItemsForPage removing item: %s, size: %u / %u", (*current)->identifier().string().utf8().data(), pageCount() - 1, maxSize());
+            (*current)->setCachedPage(nullptr);
             m_items.remove(current);
         }
     }
@@ -516,7 +522,7 @@
     }
 
     if (cachedPage->hasExpired() || (page && page->isResourceCachingDisabled())) {
-        LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", item.url().string().ascii().data());
+        LOG(BackForwardCache, "Not restoring page for %s from back/forward cache because cache entry has expired", item.url().string().ascii().data());
         logPageCacheFailureDiagnosticMessage(page, DiagnosticLoggingKeys::expiredKey());
         remove(item);
         return nullptr;
@@ -531,15 +537,19 @@
         return;
 
     m_items.remove(&item);
-    item.m_cachedPage = nullptr;
+    item.setCachedPage(nullptr);
+
+    RELEASE_LOG(BackForwardCache, "PageCache::remove item: %s, size: %u / %u", item.identifier().string().utf8().data(), pageCount(), maxSize());
+
 }
 
 void PageCache::prune(PruningReason pruningReason)
 {
     while (pageCount() > maxSize()) {
         auto oldestItem = m_items.takeFirst();
-        oldestItem->m_cachedPage = nullptr;
+        oldestItem->setCachedPage(nullptr);
         oldestItem->m_pruningReason = pruningReason;
+        RELEASE_LOG(BackForwardCache, "PageCache::prune removing item: %s, size: %u / %u", oldestItem->identifier().string().utf8().data(), pageCount(), maxSize());
     }
 }
 
diff --git a/Source/WebCore/loader/EmptyFrameLoaderClient.h b/Source/WebCore/loader/EmptyFrameLoaderClient.h
index a76dc55..e596fa0 100644
--- a/Source/WebCore/loader/EmptyFrameLoaderClient.h
+++ b/Source/WebCore/loader/EmptyFrameLoaderClient.h
@@ -164,7 +164,6 @@
 #endif
     void transitionToCommittedForNewPage() final { }
 
-    void didSaveToPageCache() final { }
     void didRestoreFromPageCache() final { }
 
     void dispatchDidBecomeFrameset(bool) final { }
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp
index fd84cb1..079727e 100644
--- a/Source/WebCore/loader/FrameLoader.cpp
+++ b/Source/WebCore/loader/FrameLoader.cpp
@@ -2018,7 +2018,7 @@
     if (m_loadingFromCachedPage && history().provisionalItem())
         cachedPage = PageCache::singleton().take(*history().provisionalItem(), m_frame.page());
 
-    LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s' with cached page %p", m_frame.tree().uniqueName().string().utf8().data(),
+    LOG(BackForwardCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s' with cached page %p", m_frame.tree().uniqueName().string().utf8().data(),
         m_frame.document() ? m_frame.document()->url().stringCenterEllipsizedToLength().utf8().data() : "",
         pdl ? pdl->url().stringCenterEllipsizedToLength().utf8().data() : "<no provisional DocumentLoader>", cachedPage.get());
 
@@ -3680,7 +3680,7 @@
 void FrameLoader::loadProvisionalItemFromCachedPage()
 {
     DocumentLoader* provisionalLoader = provisionalDocumentLoader();
-    LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().stringCenterEllipsizedToLength().utf8().data());
+    LOG(BackForwardCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().stringCenterEllipsizedToLength().utf8().data());
 
     prepareForLoadStart();
 
diff --git a/Source/WebCore/loader/FrameLoaderClient.h b/Source/WebCore/loader/FrameLoaderClient.h
index ec732cc..8c7f175 100644
--- a/Source/WebCore/loader/FrameLoaderClient.h
+++ b/Source/WebCore/loader/FrameLoaderClient.h
@@ -278,7 +278,6 @@
 #endif
     virtual void transitionToCommittedForNewPage() = 0;
 
-    virtual void didSaveToPageCache() = 0;
     virtual void didRestoreFromPageCache() = 0;
 
     virtual void dispatchDidBecomeFrameset(bool) = 0; // Can change due to navigation or DOM modification.
diff --git a/Source/WebCore/platform/Logging.h b/Source/WebCore/platform/Logging.h
index 9d39123..22b5c04 100644
--- a/Source/WebCore/platform/Logging.h
+++ b/Source/WebCore/platform/Logging.h
@@ -42,6 +42,7 @@
     M(Animations) \
     M(ApplePay) \
     M(Archives) \
+    M(BackForwardCache) \
     M(ClipRects) \
     M(Compositing) \
     M(CompositingOverlap) \
@@ -80,7 +81,6 @@
     M(MessagePorts) \
     M(Network) \
     M(NotYetImplemented) \
-    M(PageCache) \
     M(PerformanceLogging) \
     M(PlatformLeaks) \
     M(Plugins) \
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index c04d5c3..2997b0a 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,139 @@
+2019-10-14  Chris Dumez  <cdumez@apple.com>
+
+        [WK2] Have WebBackForwardCache class coordinate page caching in all WebProcesses
+        https://bugs.webkit.org/show_bug.cgi?id=202929
+        <rdar://problem/56250421>
+
+        Reviewed by Alex Christensen.
+
+        Have WebBackForwardCache class coordinate page caching in all WebProcesses. To achieve this, the
+        following changes were made:
+        1. Whenever HistoryItem::m_cachedPage changes in WebCore, we notify the client that the HistoryItem
+           has changed. I added a "hasCachedPage" boolean to the item info being passed the the UIProcess
+           that is set based on whether or not HistoryItem::m_cachedPage is null.
+        2. The WebBackForwardCache now contains WebBackForwardCacheEntry objects instead of SuspendedPage
+           objects. A WebBackForwardCacheEntry may have a SuspendedPage or not. As a result, we can now
+           add the the back/forward cache CachedPage entries from the WebContent process, which do not have
+           a SuspendedPageProxy in the UIProcess.
+        3. Now that WebBackForwardCache is aware of all CachedPages, it can properly enforce a cache capacity
+           across call processes. Whenever a WebBackForwardCacheEntry is pruned from the cache and this entry
+           does not have a SuspendedPageProxy, we send an IPC to the WebContent process to remove this
+           cached page from the PageCache in WebCore.
+
+        Previously, as soon as we would cache a page in the WebContent process, we would send an IPC to the
+        UIProcess so that it would clear the PageCache in any previous WebContent process. This was a stop-gap
+        measure to avoid blowing up memory in a multi-process model by keeping a PageCache around in all
+        WebContent process. This would make sure only one process could have a PageCache at any point in time.
+        This logic is now dropped since the WebBackForwardCache can keep track of all cached pages across all
+        processes and enforce a cross-process limit on the number of cached pages. This means we can now have
+        PageCache entries across several WebContent processes, as long as we do not exceed the maximum number
+        of cached pages.
+
+        * Platform/Logging.h:
+        Add new BackForwardCache logging channel.
+
+        * Shared/SessionState.cpp:
+        (WebKit::BackForwardListItemState::encode const):
+        (WebKit::BackForwardListItemState::decode):
+        * Shared/SessionState.h:
+        Add new bit to BackForwardListItemState to indicate whether a HistoryItem has an associated
+        CachedPage or not.
+
+        * Shared/WebBackForwardListItem.cpp:
+        (WebKit::WebBackForwardListItem::~WebBackForwardListItem):
+        (WebKit::WebBackForwardListItem::wasRemovedFromBackForwardList):
+        (WebKit::WebBackForwardListItem::removeFromBackForwardCache):
+        (WebKit::WebBackForwardListItem::setBackForwardCacheEntry):
+        (WebKit::WebBackForwardListItem::suspendedPage const):
+        (WebKit::WebBackForwardListItem::loggingString):
+        * Shared/WebBackForwardListItem.h:
+        (WebKit::WebBackForwardListItem::backForwardCacheEntry const):
+        WebBackForwardListItem now own a WebBackForwardCacheEntry instead of simply a
+        SuspendedPage. The WebBackForwardCacheEntry may have a SuspendedPage or not.
+        Now, whenever a HistoryItem has a CachedPage in WebCore, its corresponding
+        WebBackForwardListItem in the UIProcess has an associated WebBackForwardCacheEntry
+        whether we have a SuspendedPageProxy for it in the UIProcess or not.
+
+        * Shared/WebProcessCreationParameters.cpp:
+        (WebKit::WebProcessCreationParameters::encode const):
+        (WebKit::WebProcessCreationParameters::decode):
+        * Shared/WebProcessCreationParameters.h:
+        Pass the PageCache capacity to the WebContent process on creation, so that it matches the
+        capacity of the WebBackForwardCache in the UIProcess.
+
+        * UIProcess/ProvisionalPageProxy.cpp:
+        (WebKit::ProvisionalPageProxy::goToBackForwardItem):
+        * UIProcess/SuspendedPageProxy.cpp:
+        (WebKit::messageNamesToIgnoreWhileSuspended):
+        (WebKit::SuspendedPageProxy::suspensionTimedOut):
+        * UIProcess/SuspendedPageProxy.h:
+        Stop storing the WebBackForwardListItem on the SuspendedPageProxy. This avoids having to
+        keep this pointer up to date. We do not really need it as we can now ask the WebBackForwardCache
+        to clear an entry by giving it a SuspendedPageProxy to match. Given how many entries we have at
+        most in the cache (2), iterating over them to find the one with a given suspended page is cheap.
+
+        * UIProcess/WebBackForwardCache.cpp:
+        (WebKit::WebBackForwardCache::WebBackForwardCache):
+        (WebKit::WebBackForwardCache::~WebBackForwardCache):
+
+        (WebKit::WebBackForwardCache::setCapacity):
+        Send an IPC of each WebProcess whenever the capacity of the WebBackForwardCache changes, in order
+        to update the capacity of the PageCache in those processes.
+
+        (WebKit::WebBackForwardCache::addEntry):
+        (WebKit::WebBackForwardCache::removeEntry):
+        (WebKit::WebBackForwardCache::takeSuspendedPage):
+        (WebKit::WebBackForwardCache::removeEntriesForProcess):
+        (WebKit::WebBackForwardCache::removeEntriesForSession):
+        (WebKit::WebBackForwardCache::removeEntriesMatching):
+        (WebKit::WebBackForwardCache::clear):
+
+        * UIProcess/WebBackForwardCache.h:
+        Use a Vector instead of a ListHashSet to store the entries. Given that we have at most 2 entries, using
+        a Vector will likely be more efficient and definitely use less memory.
+
+        * UIProcess/WebBackForwardCacheEntry.h: Added.
+        (WebKit::WebBackForwardCacheEntry::backForwardCache const):
+        (WebKit::WebBackForwardCacheEntry::WebBackForwardCacheEntry):
+        Add new WebBackForwardCacheEntry abstraction to match the concept of WebCore::CachedPage in the UIProcess.
+        A WebBackForwardCacheEntry may have a SuspendedPageProxy associated with it in the UIProcess or not.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::receivedNavigationPolicyDecision):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        Drop didSaveToPageCache as it is no longer necessary.
+
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::initializeNewWebProcess):
+        (WebKit::WebProcessPool::disconnectProcess):
+        * UIProcess/WebProcessPool.h:
+
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::updateBackForwardItem):
+        Whenever we get a BackForwardItem from the WebContent process, we now check it now has
+        an associated CachedPage or not. If it does, we make sure we add a corresponding
+        entry in the WebBackForwardCache so that the UIProcess knows about it. If it no longer
+        has a CachedPage and we don't have a SuspendedPageProxy for this item in the UIProcess,
+        then we remove the corresponding entry from the back/forward cache. Note that we don't
+        drop SuspendedPageProxy objects in the UIProcess simply because their corresponding
+        CachedPage in the WebProcess is gone, to maintain previous behavior. This is an
+        optimization that is useful on iOS, where we do not have a WebProcessCache, since we
+        can reuse processes from SuspendedPageProxies on navigation.
+
+        * UIProcess/WebProcessProxy.h:
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/WebCoreSupport/SessionStateConversion.cpp:
+        (WebKit::toBackForwardListItemState):
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::initializeWebProcess):
+        (WebKit::WebProcess::setBackForwardCacheCapacity):
+        (WebKit::WebProcess::clearCachedPage):
+        * WebProcess/WebProcess.h:
+        * WebProcess/WebProcess.messages.in:
+
 2019-10-14  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [Clipboard API] Refactor custom pasteboard writing codepaths to handle multiple items
diff --git a/Source/WebKit/Platform/Logging.h b/Source/WebKit/Platform/Logging.h
index 7aa9c72..296de86 100644
--- a/Source/WebKit/Platform/Logging.h
+++ b/Source/WebKit/Platform/Logging.h
@@ -45,6 +45,7 @@
     M(AutomationInteractions) \
     M(ActivityState) \
     M(BackForward) \
+    M(BackForwardCache) \
     M(CacheStorage) \
     M(ContentObservation) \
     M(ContextMenu) \
diff --git a/Source/WebKit/Shared/SessionState.cpp b/Source/WebKit/Shared/SessionState.cpp
index b37062c..8218b3e 100644
--- a/Source/WebKit/Shared/SessionState.cpp
+++ b/Source/WebKit/Shared/SessionState.cpp
@@ -229,6 +229,7 @@
 {
     encoder << identifier;
     encoder << pageState;
+    encoder << hasCachedPage;
 }
 
 Optional<BackForwardListItemState> BackForwardListItemState::decode(IPC::Decoder& decoder)
@@ -243,6 +244,9 @@
     if (!decoder.decode(result.pageState))
         return WTF::nullopt;
 
+    if (!decoder.decode(result.hasCachedPage))
+        return WTF::nullopt;
+
     return result;
 }
 
diff --git a/Source/WebKit/Shared/SessionState.h b/Source/WebKit/Shared/SessionState.h
index a329f95..993f0ba 100644
--- a/Source/WebKit/Shared/SessionState.h
+++ b/Source/WebKit/Shared/SessionState.h
@@ -137,6 +137,7 @@
 #if PLATFORM(COCOA) || PLATFORM(GTK)
     RefPtr<ViewSnapshot> snapshot;
 #endif
+    bool hasCachedPage { false };
 };
 
 struct BackForwardListState {
diff --git a/Source/WebKit/Shared/WebBackForwardListItem.cpp b/Source/WebKit/Shared/WebBackForwardListItem.cpp
index b0825af..5788488 100644
--- a/Source/WebKit/Shared/WebBackForwardListItem.cpp
+++ b/Source/WebKit/Shared/WebBackForwardListItem.cpp
@@ -28,6 +28,7 @@
 
 #include "SuspendedPageProxy.h"
 #include "WebBackForwardCache.h"
+#include "WebBackForwardCacheEntry.h"
 #include "WebProcessPool.h"
 #include "WebProcessProxy.h"
 #include <wtf/DebugUtilities.h>
@@ -54,6 +55,7 @@
 {
     ASSERT(allItems().get(m_itemState.identifier) == this);
     allItems().remove(m_itemState.identifier);
+    removeFromBackForwardCache();
 }
 
 HashMap<BackForwardItemIdentifier, WebBackForwardListItem*>& WebBackForwardListItem::allItems()
@@ -160,38 +162,30 @@
 
 void WebBackForwardListItem::wasRemovedFromBackForwardList()
 {
-    if (m_suspendedPage)
-        m_suspendedPage->backForwardCache().removeEntry(*this);
-    ASSERT(!m_suspendedPage);
+    removeFromBackForwardCache();
 }
 
-void WebBackForwardListItem::setSuspendedPage(std::unique_ptr<SuspendedPageProxy>&& suspendedPage)
+void WebBackForwardListItem::removeFromBackForwardCache()
 {
-    if (m_suspendedPage)
-        m_suspendedPage->clearBackForwardListItem();
-
-    m_suspendedPage = WTFMove(suspendedPage);
-
-    if (m_suspendedPage)
-        m_suspendedPage->setBackForwardListItem(*this);
+    if (m_backForwardCacheEntry)
+        m_backForwardCacheEntry->backForwardCache().removeEntry(*this);
+    ASSERT(!m_backForwardCacheEntry);
 }
 
-std::unique_ptr<SuspendedPageProxy> WebBackForwardListItem::takeSuspendedPage()
+void WebBackForwardListItem::setBackForwardCacheEntry(std::unique_ptr<WebBackForwardCacheEntry>&& backForwardCacheEntry)
 {
-    if (m_suspendedPage)
-        m_suspendedPage->clearBackForwardListItem();
-    return std::exchange(m_suspendedPage, nullptr);
+    m_backForwardCacheEntry = WTFMove(backForwardCacheEntry);
 }
 
 SuspendedPageProxy* WebBackForwardListItem::suspendedPage() const
 {
-    return m_suspendedPage.get();
+    return m_backForwardCacheEntry ? m_backForwardCacheEntry->suspendedPage() : nullptr;
 }
 
 #if !LOG_DISABLED
 const char* WebBackForwardListItem::loggingString()
 {
-    return debugString("Back/forward item ID ", itemID().logString(), ", original URL ", originalURL(), ", current URL ", url(), m_suspendedPage ? "(has a suspended page)" : "");
+    return debugString("Back/forward item ID ", itemID().logString(), ", original URL ", originalURL(), ", current URL ", url(), m_backForwardCacheEntry ? "(has a back/forward cache entry)" : "");
 }
 #endif // !LOG_DISABLED
 
diff --git a/Source/WebKit/Shared/WebBackForwardListItem.h b/Source/WebKit/Shared/WebBackForwardListItem.h
index b2cf771..6642e20 100644
--- a/Source/WebKit/Shared/WebBackForwardListItem.h
+++ b/Source/WebKit/Shared/WebBackForwardListItem.h
@@ -45,6 +45,7 @@
 
 class SuspendedPageProxy;
 class WebBackForwardCache;
+class WebBackForwardCacheEntry;
 
 class WebBackForwardListItem : public API::ObjectImpl<API::Object::Type::BackForwardListItem> {
 public:
@@ -81,6 +82,7 @@
 
     void wasRemovedFromBackForwardList();
 
+    WebBackForwardCacheEntry* backForwardCacheEntry() const { return m_backForwardCacheEntry.get(); }
     SuspendedPageProxy* suspendedPage() const;
 
 #if !LOG_DISABLED
@@ -90,16 +92,17 @@
 private:
     WebBackForwardListItem(BackForwardListItemState&&, WebPageProxyIdentifier);
 
+    void removeFromBackForwardCache();
+
     // WebBackForwardCache.
     friend class WebBackForwardCache;
-    void setSuspendedPage(std::unique_ptr<SuspendedPageProxy>&&);
-    std::unique_ptr<SuspendedPageProxy> takeSuspendedPage();
+    void setBackForwardCacheEntry(std::unique_ptr<WebBackForwardCacheEntry>&&);
 
     BackForwardListItemState m_itemState;
     URL m_resourceDirectoryURL;
     WebPageProxyIdentifier m_pageID;
     WebCore::ProcessIdentifier m_lastProcessIdentifier;
-    std::unique_ptr<SuspendedPageProxy> m_suspendedPage;
+    std::unique_ptr<WebBackForwardCacheEntry> m_backForwardCacheEntry;
 };
 
 typedef Vector<Ref<WebBackForwardListItem>> BackForwardListItemVector;
diff --git a/Source/WebKit/Shared/WebProcessCreationParameters.cpp b/Source/WebKit/Shared/WebProcessCreationParameters.cpp
index 1e7435c..9eca0ef 100644
--- a/Source/WebKit/Shared/WebProcessCreationParameters.cpp
+++ b/Source/WebKit/Shared/WebProcessCreationParameters.cpp
@@ -90,6 +90,7 @@
     encoder << textCheckerState;
     encoder << fullKeyboardAccessEnabled;
     encoder << defaultRequestTimeoutInterval;
+    encoder << backForwardCacheCapacity;
 #if PLATFORM(COCOA)
     encoder << uiProcessBundleIdentifier;
     encoder << uiProcessSDKVersion;
@@ -269,6 +270,8 @@
         return false;
     if (!decoder.decode(parameters.defaultRequestTimeoutInterval))
         return false;
+    if (!decoder.decode(parameters.backForwardCacheCapacity))
+        return false;
 #if PLATFORM(COCOA)
     if (!decoder.decode(parameters.uiProcessBundleIdentifier))
         return false;
diff --git a/Source/WebKit/Shared/WebProcessCreationParameters.h b/Source/WebKit/Shared/WebProcessCreationParameters.h
index 1ece81c..f980911 100644
--- a/Source/WebKit/Shared/WebProcessCreationParameters.h
+++ b/Source/WebKit/Shared/WebProcessCreationParameters.h
@@ -114,6 +114,7 @@
     CacheModel cacheModel;
 
     double defaultRequestTimeoutInterval { INT_MAX };
+    unsigned backForwardCacheCapacity { 0 };
 
     bool shouldAlwaysUseComplexTextCodePath { false };
     bool shouldEnableMemoryPressureReliefLogging { false };
diff --git a/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp b/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
index e98ec0e..8b0b430 100644
--- a/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
+++ b/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
@@ -32,6 +32,7 @@
 #include "Logging.h"
 #include "PageClient.h"
 #include "URLSchemeTaskParameters.h"
+#include "WebBackForwardCacheEntry.h"
 #include "WebBackForwardList.h"
 #include "WebBackForwardListItem.h"
 #include "WebErrors.h"
@@ -161,8 +162,8 @@
     RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "goToBackForwardItem: pageProxyID = %" PRIu64 " webPageID = %" PRIu64, m_page.identifier().toUInt64(), m_webPageID.toUInt64());
 
     auto itemStates = m_page.backForwardList().filteredItemStates([this, targetItem = &item](auto& item) {
-        if (auto* page = item.suspendedPage()) {
-            if (&page->process() == m_process.ptr())
+        if (auto* backForwardCacheEntry = item.backForwardCacheEntry()) {
+            if (backForwardCacheEntry->processIdentifier() == m_process->coreProcessIdentifier())
                 return false;
         }
         return &item != targetItem;
diff --git a/Source/WebKit/UIProcess/SuspendedPageProxy.cpp b/Source/WebKit/UIProcess/SuspendedPageProxy.cpp
index 8358d2f..7f89cee 100644
--- a/Source/WebKit/UIProcess/SuspendedPageProxy.cpp
+++ b/Source/WebKit/UIProcess/SuspendedPageProxy.cpp
@@ -81,7 +81,6 @@
         messageNames.get().add("DidNavigateWithNavigationData");
         messageNames.get().add("DidReachLayoutMilestone");
         messageNames.get().add("DidRestoreScrollPosition");
-        messageNames.get().add("DidSaveToPageCache");
         messageNames.get().add("DidStartProgress");
         messageNames.get().add("DidStartProvisionalLoadForFrame");
         messageNames.get().add("EditorStateChanged");
@@ -136,18 +135,6 @@
     m_process->decrementSuspendedPageCount();
 }
 
-void SuspendedPageProxy::setBackForwardListItem(WebBackForwardListItem& item)
-{
-    ASSERT(!m_backForwardListItem);
-    m_backForwardListItem = &item;
-}
-
-void SuspendedPageProxy::clearBackForwardListItem()
-{
-    ASSERT(m_backForwardListItem);
-    m_backForwardListItem = nullptr;
-}
-
 WebBackForwardCache& SuspendedPageProxy::backForwardCache() const
 {
     return process().processPool().backForwardCache();
@@ -245,12 +232,8 @@
 
 void SuspendedPageProxy::suspensionTimedOut()
 {
-    if (!m_backForwardListItem)
-        return;
-
     RELEASE_LOG_ERROR(ProcessSwapping, "%p - SuspendedPageProxy::suspensionTimedOut() destroying the suspended page because it failed to suspend in time", this);
-    ASSERT(m_backForwardListItem->suspendedPage() == this);
-    backForwardCache().removeEntry(*m_backForwardListItem); // Will destroy |this|.
+    backForwardCache().removeEntry(*this); // Will destroy |this|.
 }
 
 void SuspendedPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder& decoder)
diff --git a/Source/WebKit/UIProcess/SuspendedPageProxy.h b/Source/WebKit/UIProcess/SuspendedPageProxy.h
index 9f3ae33..764bedc 100644
--- a/Source/WebKit/UIProcess/SuspendedPageProxy.h
+++ b/Source/WebKit/UIProcess/SuspendedPageProxy.h
@@ -56,10 +56,6 @@
     WebProcessProxy& process() const { return m_process.get(); }
     WebCore::FrameIdentifier mainFrameID() const { return m_mainFrameID; }
 
-    void setBackForwardListItem(WebBackForwardListItem&);
-    void clearBackForwardListItem();
-
-    WebBackForwardListItem* backForwardListItem() { return m_backForwardListItem; }
     WebBackForwardCache& backForwardCache() const;
 
     bool pageIsClosedOrClosing() const;
@@ -88,7 +84,6 @@
     WebPageProxy& m_page;
     WebCore::PageIdentifier m_webPageID;
     Ref<WebProcessProxy> m_process;
-    WebBackForwardListItem* m_backForwardListItem { nullptr };
     WebCore::FrameIdentifier m_mainFrameID;
     bool m_isClosed { false };
     ShouldDelayClosingUntilEnteringAcceleratedCompositingMode m_shouldDelayClosingUntilEnteringAcceleratedCompositingMode { ShouldDelayClosingUntilEnteringAcceleratedCompositingMode::No };
diff --git a/Source/WebKit/UIProcess/WebBackForwardCache.cpp b/Source/WebKit/UIProcess/WebBackForwardCache.cpp
index 4648764..40ff1c6 100644
--- a/Source/WebKit/UIProcess/WebBackForwardCache.cpp
+++ b/Source/WebKit/UIProcess/WebBackForwardCache.cpp
@@ -26,17 +26,75 @@
 #include "config.h"
 #include "WebBackForwardCache.h"
 
+#include "Logging.h"
 #include "SuspendedPageProxy.h"
+#include "WebBackForwardCacheEntry.h"
 #include "WebBackForwardListItem.h"
 #include "WebPageProxy.h"
+#include "WebProcessMessages.h"
+#include "WebProcessPool.h"
 #include "WebProcessProxy.h"
 #include "WebsiteDataStore.h"
 
 namespace WebKit {
 
-WebBackForwardCache::WebBackForwardCache() = default;
+class EntryWithSuspendedPage final : public WebBackForwardCacheEntry {
+public:
+    EntryWithSuspendedPage(WebBackForwardCache& backForwardCache, std::unique_ptr<SuspendedPageProxy>&& suspendedPage)
+        : WebBackForwardCacheEntry(backForwardCache)
+        , m_suspendedPage(WTFMove(suspendedPage))
+    {
+    }
 
-WebBackForwardCache::~WebBackForwardCache() = default;
+    SuspendedPageProxy* suspendedPage() const final { return m_suspendedPage.get(); }
+    std::unique_ptr<SuspendedPageProxy> takeSuspendedPage() final { return std::exchange(m_suspendedPage, nullptr); }
+    WebCore::ProcessIdentifier processIdentifier() const final { return process().coreProcessIdentifier(); }
+    WebProcessProxy& process() const final { return m_suspendedPage->process(); }
+
+private:
+    std::unique_ptr<SuspendedPageProxy> m_suspendedPage;
+};
+
+class EntryWithoutSuspendedPage final : public WebBackForwardCacheEntry {
+public:
+    EntryWithoutSuspendedPage(WebBackForwardCache& backForwardCache, const WebCore::BackForwardItemIdentifier& backForwardItemID, WebCore::ProcessIdentifier processIdentifier)
+        : WebBackForwardCacheEntry(backForwardCache)
+        , m_processIdentifier(processIdentifier)
+        , m_backForwardItemID(backForwardItemID)
+    {
+    }
+
+    ~EntryWithoutSuspendedPage()
+    {
+        auto& process = this->process();
+        process.sendWithAsyncReply(Messages::WebProcess::ClearCachedPage(m_backForwardItemID), [token = process.throttler().backgroundActivityToken()] { });
+    }
+
+    WebCore::ProcessIdentifier processIdentifier() const final { return m_processIdentifier; }
+    WebProcessProxy& process() const final
+    {
+        auto* process = WebProcessProxy::processForIdentifier(m_processIdentifier);
+        ASSERT(process);
+        return *process;
+    }
+
+private:
+    SuspendedPageProxy* suspendedPage() const final { return nullptr; }
+    std::unique_ptr<SuspendedPageProxy> takeSuspendedPage() final { return nullptr; }
+
+    WebCore::ProcessIdentifier m_processIdentifier;
+    WebCore::BackForwardItemIdentifier m_backForwardItemID;
+};
+
+WebBackForwardCache::WebBackForwardCache(WebProcessPool& processPool)
+    : m_processPool(processPool)
+{
+}
+
+WebBackForwardCache::~WebBackForwardCache()
+{
+    clear();
+}
 
 inline void WebBackForwardCache::removeOldestEntry()
 {
@@ -46,48 +104,85 @@
 
 void WebBackForwardCache::setCapacity(unsigned capacity)
 {
+    if (m_capacity == capacity)
+        return;
+
     m_capacity = capacity;
     while (size() > capacity)
         removeOldestEntry();
+
+    m_processPool.sendToAllProcesses(Messages::WebProcess::SetBackForwardCacheCapacity(m_capacity));
 }
 
-void WebBackForwardCache::addEntry(WebBackForwardListItem& item, std::unique_ptr<SuspendedPageProxy>&& suspendedPage)
+void WebBackForwardCache::addEntry(WebBackForwardListItem& item, std::unique_ptr<WebBackForwardCacheEntry>&& backForwardCacheEntry)
 {
     ASSERT(capacity());
+    ASSERT(backForwardCacheEntry);
 
-    item.setSuspendedPage(WTFMove(suspendedPage));
-    m_itemsWithCachedPage.add(&item);
+    if (item.backForwardCacheEntry()) {
+        ASSERT(m_itemsWithCachedPage.contains(&item));
+        m_itemsWithCachedPage.removeFirst(&item);
+    }
+
+    item.setBackForwardCacheEntry(WTFMove(backForwardCacheEntry));
+    m_itemsWithCachedPage.append(&item);
 
     if (size() > capacity())
         removeOldestEntry();
     ASSERT(size() <= capacity());
+
+    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::addEntry: item: %s, hasSuspendedPage: %d, size: %u / %u", item.itemID().string().utf8().data(), !!item.suspendedPage(), size(), capacity());
+}
+
+void WebBackForwardCache::addEntry(WebBackForwardListItem& item, std::unique_ptr<SuspendedPageProxy>&& suspendedPage)
+{
+    addEntry(item, makeUnique<EntryWithSuspendedPage>(*this, WTFMove(suspendedPage)));
+}
+
+void WebBackForwardCache::addEntry(WebBackForwardListItem& item, WebCore::ProcessIdentifier processIdentifier)
+{
+    addEntry(item, makeUnique<EntryWithoutSuspendedPage>(*this, item.itemID(), WTFMove(processIdentifier)));
 }
 
 void WebBackForwardCache::removeEntry(WebBackForwardListItem& item)
 {
     ASSERT(m_itemsWithCachedPage.contains(&item));
-    m_itemsWithCachedPage.remove(&item);
-    item.setSuspendedPage(nullptr);
+    m_itemsWithCachedPage.removeFirst(&item);
+    item.setBackForwardCacheEntry(nullptr);
+    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::removeEntry: item: %s, size: %u / %u", item.itemID().string().utf8().data(), size(), capacity());
 }
 
-std::unique_ptr<SuspendedPageProxy> WebBackForwardCache::takeEntry(WebBackForwardListItem& item)
+void WebBackForwardCache::removeEntry(SuspendedPageProxy& suspendedPage)
 {
+    removeEntriesMatching([&suspendedPage](auto& item) {
+        return item.suspendedPage() == &suspendedPage;
+    });
+}
+
+std::unique_ptr<SuspendedPageProxy> WebBackForwardCache::takeSuspendedPage(WebBackForwardListItem& item)
+{
+    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::takeSuspendedPage: item: %s", item.itemID().string().utf8().data());
+
     ASSERT(m_itemsWithCachedPage.contains(&item));
-    m_itemsWithCachedPage.remove(&item);
-    return item.takeSuspendedPage();
+    ASSERT(item.backForwardCacheEntry());
+    auto suspendedPage = item.backForwardCacheEntry()->takeSuspendedPage();
+    ASSERT(suspendedPage);
+    removeEntry(item);
+    return suspendedPage;
 }
 
 void WebBackForwardCache::removeEntriesForProcess(WebProcessProxy& process)
 {
-    removeEntriesMatching([&process](auto& item) {
-        return &item.suspendedPage()->process() == &process;
+    removeEntriesMatching([processIdentifier = process.coreProcessIdentifier()](auto& entry) {
+        ASSERT(entry.backForwardCacheEntry());
+        return entry.backForwardCacheEntry()->processIdentifier() == processIdentifier;
     });
 }
 
 void WebBackForwardCache::removeEntriesForSession(PAL::SessionID sessionID)
 {
     removeEntriesMatching([sessionID](auto& item) {
-        return item.suspendedPage()->process().websiteDataStore().sessionID() == sessionID;
+        return item.backForwardCacheEntry()->process().websiteDataStore().sessionID() == sessionID;
     });
 }
 
@@ -100,21 +195,21 @@
 
 void WebBackForwardCache::removeEntriesMatching(const Function<bool(WebBackForwardListItem&)>& matches)
 {
-    for (auto it = m_itemsWithCachedPage.begin(); it != m_itemsWithCachedPage.end();) {
-        auto current = it;
-        ++it;
-        if (matches(**current)) {
-            (*current)->setSuspendedPage(nullptr);
-            m_itemsWithCachedPage.remove(current);
+    m_itemsWithCachedPage.removeAllMatching([&](auto* item) {
+        if (matches(*item)) {
+            item->setBackForwardCacheEntry(nullptr);
+            return true;
         }
-    }
+        return false;
+    });
 }
 
 void WebBackForwardCache::clear()
 {
+    RELEASE_LOG(BackForwardCache, "WebBackForwardCache::clear");
     auto itemsWithCachedPage = WTFMove(m_itemsWithCachedPage);
     for (auto* item : itemsWithCachedPage)
-        item->setSuspendedPage(nullptr);
+        item->setBackForwardCacheEntry(nullptr);
 }
 
 } // namespace WebKit.
diff --git a/Source/WebKit/UIProcess/WebBackForwardCache.h b/Source/WebKit/UIProcess/WebBackForwardCache.h
index 4df19ad..c1e115a 100644
--- a/Source/WebKit/UIProcess/WebBackForwardCache.h
+++ b/Source/WebKit/UIProcess/WebBackForwardCache.h
@@ -25,21 +25,24 @@
 
 #pragma once
 
+#include <WebCore/ProcessIdentifier.h>
 #include <pal/SessionID.h>
 #include <wtf/Forward.h>
-#include <wtf/ListHashSet.h>
+#include <wtf/Vector.h>
 
 namespace WebKit {
 
 class SuspendedPageProxy;
+class WebBackForwardCacheEntry;
 class WebBackForwardListItem;
 class WebPageProxy;
+class WebProcessPool;
 class WebProcessProxy;
 
 class WebBackForwardCache {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    WebBackForwardCache();
+    explicit WebBackForwardCache(WebProcessPool&);
     ~WebBackForwardCache();
 
     void setCapacity(unsigned);
@@ -52,15 +55,19 @@
     void removeEntriesForSession(PAL::SessionID);
 
     void addEntry(WebBackForwardListItem&, std::unique_ptr<SuspendedPageProxy>&&);
+    void addEntry(WebBackForwardListItem&, WebCore::ProcessIdentifier);
     void removeEntry(WebBackForwardListItem&);
-    std::unique_ptr<SuspendedPageProxy> takeEntry(WebBackForwardListItem&);
+    void removeEntry(SuspendedPageProxy&);
+    std::unique_ptr<SuspendedPageProxy> takeSuspendedPage(WebBackForwardListItem&);
 
 private:
     void removeOldestEntry();
     void removeEntriesMatching(const Function<bool(WebBackForwardListItem&)>&);
+    void addEntry(WebBackForwardListItem&, std::unique_ptr<WebBackForwardCacheEntry>&&);
 
+    WebProcessPool& m_processPool;
     unsigned m_capacity { 0 };
-    ListHashSet<WebBackForwardListItem*> m_itemsWithCachedPage;
+    Vector<WebBackForwardListItem*, 2> m_itemsWithCachedPage;
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebBackForwardCacheEntry.h b/Source/WebKit/UIProcess/WebBackForwardCacheEntry.h
new file mode 100644
index 0000000..d57a313
--- /dev/null
+++ b/Source/WebKit/UIProcess/WebBackForwardCacheEntry.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <WebCore/ProcessIdentifier.h>
+#include <wtf/Forward.h>
+
+namespace WebKit {
+
+class SuspendedPageProxy;
+class WebBackForwardCache;
+class WebProcessProxy;
+
+class WebBackForwardCacheEntry {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    virtual ~WebBackForwardCacheEntry() = default;
+
+    WebBackForwardCache& backForwardCache() const { return m_backForwardCache; }
+
+    virtual SuspendedPageProxy* suspendedPage() const = 0;
+    virtual std::unique_ptr<SuspendedPageProxy> takeSuspendedPage() = 0;
+    virtual WebCore::ProcessIdentifier processIdentifier() const = 0;
+    virtual WebProcessProxy& process() const = 0;
+
+protected:
+    explicit WebBackForwardCacheEntry(WebBackForwardCache& backForwardCache)
+        : m_backForwardCache(backForwardCache)
+    {
+    }
+
+private:
+    WebBackForwardCache& m_backForwardCache;
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp
index e1c5c10..7f89fb9 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.cpp
+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp
@@ -2971,7 +2971,9 @@
             // Make sure the process to be used for the navigation does not get shutDown now due to destroying SuspendedPageProxy or ProvisionalPageProxy objects.
             auto preventNavigationProcessShutdown = processForNavigation->makeScopePreventingShutdown();
 
-            auto suspendedPage = destinationSuspendedPage ? backForwardCache().takeEntry(*destinationSuspendedPage->backForwardListItem()) : nullptr;
+            ASSERT(!destinationSuspendedPage || navigation->targetItem());
+            auto suspendedPage = destinationSuspendedPage ? backForwardCache().takeSuspendedPage(*navigation->targetItem()) : nullptr;
+            ASSERT(suspendedPage.get() == destinationSuspendedPage);
             if (suspendedPage && suspendedPage->pageIsClosedOrClosing())
                 suspendedPage = nullptr;
 
@@ -8053,11 +8055,6 @@
 }
 #endif // PLATFORM(GTK)
 
-void WebPageProxy::didSaveToPageCache()
-{
-    m_process->didSaveToPageCache();
-}
-
 void WebPageProxy::setScrollPinningBehavior(ScrollPinningBehavior pinning)
 {
     if (m_scrollPinningBehavior == pinning)
diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h
index a69488d..848f968 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.h
+++ b/Source/WebKit/UIProcess/WebPageProxy.h
@@ -1278,8 +1278,6 @@
 
     void didFinishCheckingText(uint64_t requestID, const Vector<WebCore::TextCheckingResult>&);
     void didCancelCheckingText(uint64_t requestID);
-
-    void didSaveToPageCache();
         
     void setScrollPinningBehavior(WebCore::ScrollPinningBehavior);
     WebCore::ScrollPinningBehavior scrollPinningBehavior() const { return m_scrollPinningBehavior; }
diff --git a/Source/WebKit/UIProcess/WebPageProxy.messages.in b/Source/WebKit/UIProcess/WebPageProxy.messages.in
index 83937d2..2d0bff8 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.messages.in
+++ b/Source/WebKit/UIProcess/WebPageProxy.messages.in
@@ -453,8 +453,6 @@
 
     DidUpdateActivityState()
 
-    DidSaveToPageCache()
-
 #if ENABLE(WEB_CRYPTO)
     WrapCryptoKey(Vector<uint8_t> key) -> (bool succeeded, Vector<uint8_t> wrappedKey) Synchronous
     UnwrapCryptoKey(Vector<uint8_t> wrappedKey) -> (bool succeeded, Vector<uint8_t> key) Synchronous
diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp
index e360081..c06d6c6 100644
--- a/Source/WebKit/UIProcess/WebProcessPool.cpp
+++ b/Source/WebKit/UIProcess/WebProcessPool.cpp
@@ -236,7 +236,7 @@
     , m_foregroundWebProcessCounter([this](RefCounterEvent) { updateProcessAssertions(); })
     , m_backgroundWebProcessCounter([this](RefCounterEvent) { updateProcessAssertions(); })
 #endif
-    , m_backForwardCache(makeUniqueRef<WebBackForwardCache>())
+    , m_backForwardCache(makeUniqueRef<WebBackForwardCache>(*this))
     , m_webProcessCache(makeUniqueRef<WebProcessCache>(*this))
 {
     static std::once_flag onceFlag;
@@ -783,13 +783,6 @@
     s_invalidMessageCallback(toAPI(API::String::create(messageNameStringBuilder.toString()).ptr()));
 }
 
-void WebProcessPool::processDidCachePage(WebProcessProxy* process)
-{
-    if (m_processWithPageCache && m_processWithPageCache != process)
-        m_processWithPageCache->releasePageCache();
-    m_processWithPageCache = process;
-}
-
 void WebProcessPool::resolvePathsForSandboxExtensions()
 {
     m_resolvedPaths.injectedBundlePath = resolvePathForSandboxExtension(injectedBundlePath());
@@ -974,6 +967,8 @@
 
     parameters.defaultRequestTimeoutInterval = API::URLRequest::defaultTimeoutInterval();
 
+    parameters.backForwardCacheCapacity = backForwardCache().capacity();
+
 #if ENABLE(NOTIFICATIONS)
     // FIXME: There should be a generic way for supplements to add to the intialization parameters.
     parameters.notificationPermissions = supplement<WebNotificationManagerProxy>()->notificationPermissions();
@@ -1127,8 +1122,6 @@
     // FIXME (Multi-WebProcess): <rdar://problem/12239765> Some of the invalidation calls of the other supplements are still necessary in multi-process mode, but they should only affect data structures pertaining to the process being disconnected.
     // Clearing everything causes assertion failures, so it's less trouble to skip that for now.
     RefPtr<WebProcessProxy> protect(process);
-    if (m_processWithPageCache == process)
-        m_processWithPageCache = nullptr;
 
     m_backForwardCache->removeEntriesForProcess(*process);
 
diff --git a/Source/WebKit/UIProcess/WebProcessPool.h b/Source/WebKit/UIProcess/WebProcessPool.h
index 9e1af72..78bdc04 100644
--- a/Source/WebKit/UIProcess/WebProcessPool.h
+++ b/Source/WebKit/UIProcess/WebProcessPool.h
@@ -409,8 +409,6 @@
     static void setInvalidMessageCallback(void (*)(WKStringRef));
     static void didReceiveInvalidMessage(const IPC::StringReference& messageReceiverName, const IPC::StringReference& messageName);
 
-    void processDidCachePage(WebProcessProxy*);
-
     bool isURLKnownHSTSHost(const String& urlString) const;
     void resetHSTSHosts();
     void resetHSTSHostsAddedAfterDate(double startDateIntervalSince1970);
@@ -603,7 +601,6 @@
     WebProcessProxy* m_prewarmedProcess { nullptr };
     WebProcessProxy* m_dummyProcessProxy { nullptr }; // A lightweight WebProcessProxy without backing process.
 
-    WebProcessProxy* m_processWithPageCache { nullptr };
 #if ENABLE(SERVICE_WORKER)
     using RegistrableDomainWithSessionID = std::pair<WebCore::RegistrableDomain, PAL::SessionID>;
     HashMap<RegistrableDomainWithSessionID, WebProcessProxy*> m_serviceWorkerProcesses;
diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp
index fb8e8ef..5038dec 100644
--- a/Source/WebKit/UIProcess/WebProcessProxy.cpp
+++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp
@@ -631,6 +631,13 @@
         return;
 
     item->setPageState(PageState { itemState.pageState });
+
+    if (!!item->backForwardCacheEntry() != itemState.hasCachedPage) {
+        if (itemState.hasCachedPage)
+            processPool().backForwardCache().addEntry(*item, coreProcessIdentifier());
+        else if (!item->suspendedPage())
+            processPool().backForwardCache().removeEntry(*item);
+    }
 }
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
@@ -987,17 +994,6 @@
         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
 }
 
-void WebProcessProxy::didSaveToPageCache()
-{
-    m_processPool->processDidCachePage(this);
-}
-
-void WebProcessProxy::releasePageCache()
-{
-    if (canSendMessage())
-        send(Messages::WebProcess::ReleasePageCache(), 0);
-}
-
 void WebProcessProxy::windowServerConnectionStateChanged()
 {
     for (const auto& page : m_pageMap.values())
diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h
index c07b1ee..a97399e 100644
--- a/Source/WebKit/UIProcess/WebProcessProxy.h
+++ b/Source/WebKit/UIProcess/WebProcessProxy.h
@@ -190,9 +190,6 @@
 
     static bool fullKeyboardAccessEnabled();
 
-    void didSaveToPageCache();
-    void releasePageCache();
-
     void fetchWebsiteData(PAL::SessionID, OptionSet<WebsiteDataType>, CompletionHandler<void(WebsiteData)>&&);
     void deleteWebsiteData(PAL::SessionID, OptionSet<WebsiteDataType>, WallTime modifiedSince, CompletionHandler<void()>&&);
     void deleteWebsiteDataForOrigins(PAL::SessionID, OptionSet<WebsiteDataType>, const Vector<WebCore::SecurityOriginData>&, CompletionHandler<void()>&&);
diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj
index f2bb573..bf16311 100644
--- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj
+++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj
@@ -918,6 +918,7 @@
 		46BEB6E322FBB21A00269867 /* TransientLocalStorageNamespace.h in Headers */ = {isa = PBXBuildFile; fileRef = 46BEB6E122FBB21A00269867 /* TransientLocalStorageNamespace.h */; };
 		46C392292316EC4D008EED9B /* WebPageProxyIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 46C392282316EC4D008EED9B /* WebPageProxyIdentifier.h */; };
 		46DF063C1F3905F8001980BB /* NetworkCORSPreflightChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 46DF063A1F3905E5001980BB /* NetworkCORSPreflightChecker.h */; };
+		46F9B26323526EF3006FE5FA /* WebBackForwardCacheEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 46F9B26223526ED0006FE5FA /* WebBackForwardCacheEntry.h */; };
 		4A3CC18B19B0640F00D14AEF /* UserMediaPermissionRequestManagerProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A410F3A19AF7B04002EBAB5 /* UserMediaPermissionRequestManagerProxy.h */; };
 		4A3CC18D19B0641900D14AEF /* UserMediaPermissionRequestProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A410F3C19AF7B04002EBAB5 /* UserMediaPermissionRequestProxy.h */; };
 		4A3CC18F19B07B8A00D14AEF /* WKUserMediaPermissionRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A410F3619AF7AC3002EBAB5 /* WKUserMediaPermissionRequest.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -3240,6 +3241,7 @@
 		46C392282316EC4D008EED9B /* WebPageProxyIdentifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebPageProxyIdentifier.h; sourceTree = "<group>"; };
 		46DF06391F3905E5001980BB /* NetworkCORSPreflightChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCORSPreflightChecker.cpp; sourceTree = "<group>"; };
 		46DF063A1F3905E5001980BB /* NetworkCORSPreflightChecker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCORSPreflightChecker.h; sourceTree = "<group>"; };
+		46F9B26223526ED0006FE5FA /* WebBackForwardCacheEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebBackForwardCacheEntry.h; sourceTree = "<group>"; };
 		4A410F3519AF7AC3002EBAB5 /* WKUserMediaPermissionRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKUserMediaPermissionRequest.cpp; sourceTree = "<group>"; };
 		4A410F3619AF7AC3002EBAB5 /* WKUserMediaPermissionRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKUserMediaPermissionRequest.h; sourceTree = "<group>"; };
 		4A410F3919AF7B04002EBAB5 /* UserMediaPermissionRequestManagerProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserMediaPermissionRequestManagerProxy.cpp; sourceTree = "<group>"; };
@@ -7830,6 +7832,7 @@
 				1A60224918C16B0800C3E8C9 /* VisitedLinkStore.messages.in */,
 				4603011A234BE31D009C8217 /* WebBackForwardCache.cpp */,
 				4603011B234BE31E009C8217 /* WebBackForwardCache.h */,
+				46F9B26223526ED0006FE5FA /* WebBackForwardCacheEntry.h */,
 				BC72BA1B11E64907001EB4EA /* WebBackForwardList.cpp */,
 				BC72BA1C11E64907001EB4EA /* WebBackForwardList.h */,
 				F036978715F4BF0500C3A80E /* WebColorPicker.cpp */,
@@ -9864,6 +9867,7 @@
 				1C0A19471C8FF1A800FE0EBB /* WebAutomationSessionProxy.h in Headers */,
 				1C0A19541C8FFDFB00FE0EBB /* WebAutomationSessionProxyMessages.h in Headers */,
 				1C0A195C1C916E1B00FE0EBB /* WebAutomationSessionProxyScriptSource.h in Headers */,
+				46F9B26323526EF3006FE5FA /* WebBackForwardCacheEntry.h in Headers */,
 				BC72BA1E11E64907001EB4EA /* WebBackForwardList.h in Headers */,
 				518D2CAE12D5153B003BB93B /* WebBackForwardListItem.h in Headers */,
 				BC72B9FB11E6476B001EB4EA /* WebBackForwardListProxy.h in Headers */,
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/SessionStateConversion.cpp b/Source/WebKit/WebProcess/WebCoreSupport/SessionStateConversion.cpp
index ac722a5..0eca4c1 100644
--- a/Source/WebKit/WebProcess/WebCoreSupport/SessionStateConversion.cpp
+++ b/Source/WebKit/WebProcess/WebCoreSupport/SessionStateConversion.cpp
@@ -115,6 +115,7 @@
     state.pageState.mainFrameState = toFrameState(historyItem);
     state.pageState.shouldOpenExternalURLsPolicy = historyItem.shouldOpenExternalURLsPolicy();
     state.pageState.sessionStateObject = historyItem.stateObject();
+    state.hasCachedPage = historyItem.isInPageCache();
     return state;
 }
 
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
index 9fa15e0..cced11f 100644
--- a/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
@@ -1533,16 +1533,6 @@
 #endif
 }
 
-void WebFrameLoaderClient::didSaveToPageCache()
-{
-    WebPage* webPage = m_frame->page();
-    if (!webPage)
-        return;
-
-    if (m_frame->isMainFrame())
-        webPage->send(Messages::WebPageProxy::DidSaveToPageCache());
-}
-
 void WebFrameLoaderClient::didRestoreFromPageCache()
 {
     m_frameCameFromPageCache = true;
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h b/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h
index db752d5..afa17a4 100644
--- a/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h
+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h
@@ -206,7 +206,6 @@
 #endif
     void transitionToCommittedForNewPage() final;
 
-    void didSaveToPageCache() final;
     void didRestoreFromPageCache() final;
 
     void dispatchDidBecomeFrameset(bool) final;
diff --git a/Source/WebKit/WebProcess/WebProcess.cpp b/Source/WebKit/WebProcess/WebProcess.cpp
index e3430c2..accd337 100644
--- a/Source/WebKit/WebProcess/WebProcess.cpp
+++ b/Source/WebKit/WebProcess/WebProcess.cpp
@@ -386,6 +386,8 @@
 
     setDefaultRequestTimeoutInterval(parameters.defaultRequestTimeoutInterval);
 
+    setBackForwardCacheCapacity(parameters.backForwardCacheCapacity);
+
     setAlwaysUsesComplexTextCodePath(parameters.shouldAlwaysUseComplexTextCodePath);
 
     setShouldUseFontSmoothing(parameters.shouldUseFontSmoothing);
@@ -1292,11 +1294,6 @@
     }
 }
 
-void WebProcess::releasePageCache()
-{
-    PageCache::singleton().pruneToSizeNow(0, PruningReason::MemoryPressure);
-}
-
 void WebProcess::fetchWebsiteData(OptionSet<WebsiteDataType> websiteDataTypes, CompletionHandler<void(WebsiteData&&)>&& completionHandler)
 {
     WebsiteData websiteData;
@@ -1777,6 +1774,21 @@
     return false;
 }
 
+void WebProcess::setBackForwardCacheCapacity(unsigned capacity)
+{
+    PageCache::singleton().setMaxSize(capacity);
+}
+
+void WebProcess::clearCachedPage(BackForwardItemIdentifier backForwardItemID, CompletionHandler<void()>&& completionHandler)
+{
+    HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID);
+    if (!item)
+        return completionHandler();
+
+    PageCache::singleton().remove(*item);
+    completionHandler();
+}
+
 LibWebRTCNetwork& WebProcess::libWebRTCNetwork()
 {
     if (!m_libWebRTCNetwork)
diff --git a/Source/WebKit/WebProcess/WebProcess.h b/Source/WebKit/WebProcess/WebProcess.h
index ae1f603..798d086 100644
--- a/Source/WebKit/WebProcess/WebProcess.h
+++ b/Source/WebKit/WebProcess/WebProcess.h
@@ -86,6 +86,7 @@
 class PageGroup;
 class ResourceRequest;
 class UserGestureToken;
+struct BackForwardItemIdentifier;
 struct MessagePortIdentifier;
 struct MessageWithMessagePorts;
 struct MockMediaDevice;
@@ -368,14 +369,15 @@
     void registerServiceWorkerClients();
 #endif
 
-    void releasePageCache();
-
     void fetchWebsiteData(OptionSet<WebsiteDataType>, CompletionHandler<void(WebsiteData&&)>&&);
     void deleteWebsiteData(OptionSet<WebsiteDataType>, WallTime modifiedSince, CompletionHandler<void()>&&);
     void deleteWebsiteDataForOrigins(OptionSet<WebsiteDataType>, const Vector<WebCore::SecurityOriginData>& origins, CompletionHandler<void()>&&);
 
     void setMemoryCacheDisabled(bool);
 
+    void setBackForwardCacheCapacity(unsigned);
+    void clearCachedPage(WebCore::BackForwardItemIdentifier, CompletionHandler<void()>&&);
+
 #if ENABLE(SERVICE_CONTROLS)
     void setEnabledServices(bool hasImageServices, bool hasSelectionServices, bool hasRichContentServices);
 #endif
diff --git a/Source/WebKit/WebProcess/WebProcess.messages.in b/Source/WebKit/WebProcess/WebProcess.messages.in
index cead016..2476c43 100644
--- a/Source/WebKit/WebProcess/WebProcess.messages.in
+++ b/Source/WebKit/WebProcess/WebProcess.messages.in
@@ -75,8 +75,6 @@
     SetInjectedBundleParameters(IPC::DataReference parameters);
     HandleInjectedBundleMessage(String messageName, WebKit::UserData messageBody);
 
-    ReleasePageCache()
-
     FetchWebsiteData(OptionSet<WebKit::WebsiteDataType> websiteDataTypes) -> (struct WebKit::WebsiteData websiteData) Async
     DeleteWebsiteData(OptionSet<WebKit::WebsiteDataType> websiteDataTypes, WallTime modifiedSince) -> () Async
     DeleteWebsiteDataForOrigins(OptionSet<WebKit::WebsiteDataType> websiteDataTypes, Vector<WebCore::SecurityOriginData> origins) -> () Async
@@ -153,6 +151,9 @@
 
     ClearCurrentModifierStateForTesting()
 
+    SetBackForwardCacheCapacity(unsigned capacity);
+    ClearCachedPage(struct WebCore::BackForwardItemIdentifier backForwardItemID) -> () Async
+
 #if PLATFORM(IOS_FAMILY)
     UnblockAccessibilityServer(WebKit::SandboxExtension::Handle handle)
 #endif
diff --git a/Source/WebKitLegacy/mac/ChangeLog b/Source/WebKitLegacy/mac/ChangeLog
index 2b9abc4..c581876 100644
--- a/Source/WebKitLegacy/mac/ChangeLog
+++ b/Source/WebKitLegacy/mac/ChangeLog
@@ -1,3 +1,14 @@
+2019-10-14  Chris Dumez  <cdumez@apple.com>
+
+        [WK2] Have WebBackForwardCache class coordinate page caching in all WebProcesses
+        https://bugs.webkit.org/show_bug.cgi?id=202929
+        <rdar://problem/56250421>
+
+        Reviewed by Alex Christensen.
+
+        * WebCoreSupport/WebFrameLoaderClient.h:
+        * WebCoreSupport/WebFrameLoaderClient.mm:
+
 2019-10-14  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [Clipboard API] Refactor custom pasteboard writing codepaths to handle multiple items
diff --git a/Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.h b/Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.h
index 6516c9f..c21bdcf 100644
--- a/Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.h
+++ b/Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.h
@@ -184,7 +184,6 @@
 #endif
     void transitionToCommittedForNewPage() final;
 
-    void didSaveToPageCache() final;
     void didRestoreFromPageCache() final;
 
     void dispatchDidBecomeFrameset(bool) final;
diff --git a/Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.mm b/Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.mm
index 8ae86b5..460c9a2 100644
--- a/Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.mm
+++ b/Source/WebKitLegacy/mac/WebCoreSupport/WebFrameLoaderClient.mm
@@ -1495,10 +1495,6 @@
     }
 }
 
-void WebFrameLoaderClient::didSaveToPageCache()
-{
-}
-
 void WebFrameLoaderClient::didRestoreFromPageCache()
 {
 #if PLATFORM(IOS_FAMILY)
diff --git a/Source/WebKitLegacy/win/ChangeLog b/Source/WebKitLegacy/win/ChangeLog
index 233d53b..fff92a0 100644
--- a/Source/WebKitLegacy/win/ChangeLog
+++ b/Source/WebKitLegacy/win/ChangeLog
@@ -1,3 +1,14 @@
+2019-10-14  Chris Dumez  <cdumez@apple.com>
+
+        [WK2] Have WebBackForwardCache class coordinate page caching in all WebProcesses
+        https://bugs.webkit.org/show_bug.cgi?id=202929
+        <rdar://problem/56250421>
+
+        Reviewed by Alex Christensen.
+
+        * WebCoreSupport/WebFrameLoaderClient.cpp:
+        * WebCoreSupport/WebFrameLoaderClient.h:
+
 2019-10-12  Ryosuke Niwa  <rniwa@webkit.org>
 
         requestIdleCallback is not enabled in DumpRenderTree on Windows
diff --git a/Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.cpp b/Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.cpp
index d4fb5d7..26211fa 100644
--- a/Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.cpp
+++ b/Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.cpp
@@ -992,10 +992,6 @@
     core(m_webFrame)->createView(enclosingIntRect(logicalFrame).size(), backgroundColor, /* fixedLayoutSize */ { }, /* fixedVisibleContentRect */ { });
 }
 
-void WebFrameLoaderClient::didSaveToPageCache()
-{
-}
-
 void WebFrameLoaderClient::didRestoreFromPageCache()
 {
 }
diff --git a/Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.h b/Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.h
index 33a86ce..856f525 100644
--- a/Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.h
+++ b/Source/WebKitLegacy/win/WebCoreSupport/WebFrameLoaderClient.h
@@ -176,7 +176,6 @@
     void didFinishLoad() override;
     void prepareForDataSourceReplacement() override;
 
-    void didSaveToPageCache() override;
     void didRestoreFromPageCache() override;
 
     void dispatchDidBecomeFrameset(bool) override;