<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[237257] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/237257">237257</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2018-10-18 08:33:54 -0700 (Thu, 18 Oct 2018)</dd>
</dl>

<h3>Log Message</h3>
<pre>[PSON] Cap number of SuspendedPageProxy objects and allow a WebPageProxy to have more than one
https://bugs.webkit.org/show_bug.cgi?id=190688
<rdar://problem/45354095>

Reviewed by Antti Koivisto.

Source/WebKit:

Cap number of SuspendedPageProxy objects to 3 to avoid accumulating too many "suspended" processes.

Also allow a WebPageProxy to have more than one SuspendedPageProxy so that PageCache now works for
more than 1 history navigation (up to 3 with the suspended page limit in this patch).

The following cleanup / refactoring was made to support this:
- The SuspendedPageProxy objects are now owned by the WebProcessPool instead of the WebPageProxy.
  The WebProcessPool is in charge of limiting the number of SuspendedPageProxy objects by dropping
  the oldest one whenever a WebPageProxy tries to add a new one and we've already reached the limit.
- WebProcessProxy no longer needs to know anything about suspended pages, which simplifies the
  code quite a bit. Instead, the SuspendedPageProxy objects now register themselves as
  IPC::MessageReceivers with their WebProcessProxy. The SuspendedPageProxy also take care of
  calling maybeShutdown() on their WebProcessProxy when they get destroyed.

* UIProcess/SuspendedPageProxy.cpp:
(WebKit::SuspendedPageProxy::~SuspendedPageProxy):
(WebKit::SuspendedPageProxy::tearDownDrawingAreaInWebProcess):
(WebKit::SuspendedPageProxy::unsuspend):
(WebKit::SuspendedPageProxy::didFinishLoad):
(WebKit::SuspendedPageProxy::didReceiveSyncMessage):
* UIProcess/SuspendedPageProxy.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::suspendCurrentPageIfPossible):
(WebKit::WebPageProxy::swapToWebProcess):
(WebKit::WebPageProxy::close):
(WebKit::WebPageProxy::continueNavigationInNewProcess):
(WebKit::WebPageProxy::didCompletePageTransition):
(WebKit::WebPageProxy::enterAcceleratedCompositingMode):
* UIProcess/WebPageProxy.h:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::disconnectProcess):
(WebKit::WebProcessPool::processForNavigationInternal):
(WebKit::WebProcessPool::addSuspendedPageProxy):
(WebKit::WebProcessPool::removeAllSuspendedPageProxiesForPage):
(WebKit::WebProcessPool::takeSuspendedPageProxy):
(WebKit::WebProcessPool::hasSuspendedPageProxyFor):
* UIProcess/WebProcessPool.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::didReceiveMessage):
(WebKit::WebProcessProxy::processDidTerminateOrFailedToLaunch):
(WebKit::WebProcessProxy::canTerminateChildProcess):
(WebKit::WebProcessProxy::requestTermination):
* UIProcess/WebProcessProxy.h:

Tools:

Extended API test coverage to confirm that:
- We do not accumulate more than 3 suspended processes.
- We can navigate back 3 times and use the page cache for each of these loads.

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitUIProcessSuspendedPageProxycpp">trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessSuspendedPageProxyh">trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebPageProxycpp">trunk/Source/WebKit/UIProcess/WebPageProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebPageProxyh">trunk/Source/WebKit/UIProcess/WebPageProxy.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessPoolcpp">trunk/Source/WebKit/UIProcess/WebProcessPool.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessPoolh">trunk/Source/WebKit/UIProcess/WebProcessPool.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessProxycpp">trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessProxyh">trunk/Source/WebKit/UIProcess/WebProcessProxy.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitCocoaProcessSwapOnNavigationmm">trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/ChangeLog       2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -1,3 +1,55 @@
</span><ins>+2018-10-18  Chris Dumez  <cdumez@apple.com>
+
+        [PSON] Cap number of SuspendedPageProxy objects and allow a WebPageProxy to have more than one
+        https://bugs.webkit.org/show_bug.cgi?id=190688
+        <rdar://problem/45354095>
+
+        Reviewed by Antti Koivisto.
+
+        Cap number of SuspendedPageProxy objects to 3 to avoid accumulating too many "suspended" processes.
+
+        Also allow a WebPageProxy to have more than one SuspendedPageProxy so that PageCache now works for
+        more than 1 history navigation (up to 3 with the suspended page limit in this patch).
+
+        The following cleanup / refactoring was made to support this:
+        - The SuspendedPageProxy objects are now owned by the WebProcessPool instead of the WebPageProxy.
+          The WebProcessPool is in charge of limiting the number of SuspendedPageProxy objects by dropping
+          the oldest one whenever a WebPageProxy tries to add a new one and we've already reached the limit.
+        - WebProcessProxy no longer needs to know anything about suspended pages, which simplifies the
+          code quite a bit. Instead, the SuspendedPageProxy objects now register themselves as
+          IPC::MessageReceivers with their WebProcessProxy. The SuspendedPageProxy also take care of
+          calling maybeShutdown() on their WebProcessProxy when they get destroyed.
+
+        * UIProcess/SuspendedPageProxy.cpp:
+        (WebKit::SuspendedPageProxy::~SuspendedPageProxy):
+        (WebKit::SuspendedPageProxy::tearDownDrawingAreaInWebProcess):
+        (WebKit::SuspendedPageProxy::unsuspend):
+        (WebKit::SuspendedPageProxy::didFinishLoad):
+        (WebKit::SuspendedPageProxy::didReceiveSyncMessage):
+        * UIProcess/SuspendedPageProxy.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::suspendCurrentPageIfPossible):
+        (WebKit::WebPageProxy::swapToWebProcess):
+        (WebKit::WebPageProxy::close):
+        (WebKit::WebPageProxy::continueNavigationInNewProcess):
+        (WebKit::WebPageProxy::didCompletePageTransition):
+        (WebKit::WebPageProxy::enterAcceleratedCompositingMode):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::disconnectProcess):
+        (WebKit::WebProcessPool::processForNavigationInternal):
+        (WebKit::WebProcessPool::addSuspendedPageProxy):
+        (WebKit::WebProcessPool::removeAllSuspendedPageProxiesForPage):
+        (WebKit::WebProcessPool::takeSuspendedPageProxy):
+        (WebKit::WebProcessPool::hasSuspendedPageProxyFor):
+        * UIProcess/WebProcessPool.h:
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::didReceiveMessage):
+        (WebKit::WebProcessProxy::processDidTerminateOrFailedToLaunch):
+        (WebKit::WebProcessProxy::canTerminateChildProcess):
+        (WebKit::WebProcessProxy::requestTermination):
+        * UIProcess/WebProcessProxy.h:
+
</ins><span class="cx"> 2018-10-17  Wenson Hsieh  <wenson_hsieh@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Enable the datalist element by default on iOS and macOS
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessSuspendedPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp     2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp        2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -81,44 +81,44 @@
</span><span class="cx">     , m_origin(SecurityOriginData::fromURL({ { }, item.url() }))
</span><span class="cx"> {
</span><span class="cx">     item.setSuspendedPage(*this);
</span><del>-    m_process->processPool().registerSuspendedPageProxy(*this);
</del><ins>+    m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID(), *this);
+
</ins><span class="cx">     m_process->send(Messages::WebPage::SetIsSuspended(true), m_page.pageID());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SuspendedPageProxy::~SuspendedPageProxy()
</span><span class="cx"> {
</span><del>-    if (auto process = m_process) {
-        process->send(Messages::WebPage::SetIsSuspended(false), m_page.pageID());
-        process->suspendedPageWasDestroyed(*this);
-        process->processPool().unregisterSuspendedPageProxy(*this);
-    }
-}
</del><ins>+    if (!m_isSuspended)
+        return;
</ins><span class="cx"> 
</span><del>-void SuspendedPageProxy::webProcessDidClose(WebProcessProxy& process)
-{
-    ASSERT_UNUSED(process, &process == m_process);
</del><ins>+    // If the suspended page was not consumed before getting destroyed, then close the corresponding page
+    // on the WebProcess side.
+    m_process->send(Messages::WebPage::Close(), m_page.pageID());
+    m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID());
</ins><span class="cx"> 
</span><del>-    m_process->processPool().unregisterSuspendedPageProxy(*this);
-    m_process = nullptr;
-
-    // This will destroy |this|.
-    m_page.suspendedPageClosed(*this);
</del><ins>+    // We call maybeShutDown() asynchronously since the SuspendedPage is currently being removed from the WebProcessPool
+    // and we want to avoid re-entering WebProcessPool methods.
+    RunLoop::main().dispatch([process = m_process.copyRef()] {
+        process->maybeShutDown();
+    });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SuspendedPageProxy::destroyWebPageInWebProcess()
</del><ins>+void SuspendedPageProxy::tearDownDrawingAreaInWebProcess()
</ins><span class="cx"> {
</span><del>-    m_process->send(Messages::WebPage::Close(), m_page.pageID());
-    m_page.suspendedPageClosed(*this);
</del><ins>+    m_process->send(Messages::WebPage::TearDownDrawingAreaForSuspend(), m_page.pageID());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SuspendedPageProxy::tearDownDrawingAreaInWebProcess()
</del><ins>+void SuspendedPageProxy::unsuspend()
</ins><span class="cx"> {
</span><del>-    m_process->send(Messages::WebPage::TearDownDrawingAreaForSuspend(), m_page.pageID());
</del><ins>+    ASSERT(m_isSuspended);
+
+    m_isSuspended = false;
+    m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID());
+    m_process->send(Messages::WebPage::SetIsSuspended(false), m_page.pageID());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SuspendedPageProxy::didFinishLoad()
</span><span class="cx"> {
</span><del>-    ASSERT(m_process);
</del><span class="cx">     LOG(ProcessSwapping, "SuspendedPageProxy %s from process %i finished transition to suspended", loggingString(), m_process->processIdentifier());
</span><span class="cx"> 
</span><span class="cx"> #if !LOG_DISABLED
</span><span class="lines">@@ -142,6 +142,10 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SuspendedPageProxy::didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&)
+{
+}
+
</ins><span class="cx"> #if !LOG_DISABLED
</span><span class="cx"> const char* SuspendedPageProxy::loggingString() const
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessSuspendedPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h       2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h  2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -36,22 +36,20 @@
</span><span class="cx"> class WebPageProxy;
</span><span class="cx"> class WebProcessProxy;
</span><span class="cx"> 
</span><del>-class SuspendedPageProxy : public CanMakeWeakPtr<SuspendedPageProxy> {
</del><ins>+class SuspendedPageProxy final: public IPC::MessageReceiver, public CanMakeWeakPtr<SuspendedPageProxy> {
</ins><span class="cx"> public:
</span><span class="cx">     SuspendedPageProxy(WebPageProxy&, Ref<WebProcessProxy>&&, WebBackForwardListItem&, uint64_t mainFrameID);
</span><span class="cx">     ~SuspendedPageProxy();
</span><span class="cx"> 
</span><del>-    void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
-
</del><span class="cx">     WebPageProxy& page() const { return m_page; }
</span><del>-    WebProcessProxy* process() const { return m_process.get(); }
</del><ins>+    WebProcessProxy& process() { return m_process.get(); }
</ins><span class="cx">     uint64_t mainFrameID() const { return m_mainFrameID; }
</span><span class="cx">     const WebCore::SecurityOriginData& origin() const { return m_origin; }
</span><span class="cx"> 
</span><del>-    void webProcessDidClose(WebProcessProxy&);
-    void destroyWebPageInWebProcess();
</del><span class="cx">     void tearDownDrawingAreaInWebProcess();
</span><span class="cx"> 
</span><ins>+    void unsuspend();
+
</ins><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">     const char* loggingString() const;
</span><span class="cx"> #endif
</span><span class="lines">@@ -59,11 +57,17 @@
</span><span class="cx"> private:
</span><span class="cx">     void didFinishLoad();
</span><span class="cx"> 
</span><ins>+    // IPC::MessageReceiver
+    void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
+    void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) final;
+
</ins><span class="cx">     WebPageProxy& m_page;
</span><del>-    RefPtr<WebProcessProxy> m_process;
</del><ins>+    Ref<WebProcessProxy> m_process;
</ins><span class="cx">     uint64_t m_mainFrameID;
</span><span class="cx">     WebCore::SecurityOriginData m_origin;
</span><span class="cx"> 
</span><ins>+    bool m_isSuspended { true };
+
</ins><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">     bool m_finishedSuspending { false };
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp   2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp      2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -711,40 +711,42 @@
</span><span class="cx">     finishAttachingToWebProcess();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-SuspendedPageProxy* WebPageProxy::maybeCreateSuspendedPage(WebProcessProxy& process, API::Navigation& navigation, uint64_t mainFrameID)
</del><ins>+void WebPageProxy::suspendCurrentPageIfPossible(API::Navigation& navigation, std::optional<uint64_t> mainFrameID)
</ins><span class="cx"> {
</span><del>-    ASSERT(!m_suspendedPage || m_suspendedPage->process() != &process);
</del><ins>+    if (!mainFrameID)
+        return;
</ins><span class="cx"> 
</span><span class="cx">     auto* currentItem = navigation.fromItem();
</span><span class="cx">     if (!currentItem) {
</span><del>-        LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " unable to create suspended page for process pid %i - No current back/forward item", pageID(), process.processIdentifier());
-        return nullptr;
</del><ins>+        LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " unable to create suspended page for process pid %i - No current back/forward item", pageID(), m_process->processIdentifier());
+        return;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_suspendedPage = std::make_unique<SuspendedPageProxy>(*this, process, *currentItem, mainFrameID);
</del><ins>+    auto suspendedPage = std::make_unique<SuspendedPageProxy>(*this, m_process.copyRef(), *currentItem, *mainFrameID);
+    m_lastSuspendedPage = makeWeakPtr(suspendedPage.get());
+    m_process->processPool().addSuspendedPageProxy(WTFMove(suspendedPage));
</ins><span class="cx"> 
</span><del>-    LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " created suspended page %s for process pid %i, back/forward item %s" PRIu64, pageID(), m_suspendedPage->loggingString(), process.processIdentifier(), currentItem->itemID().logString());
-
-    return m_suspendedPage.get();
</del><ins>+    LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " created suspended page %s for process pid %i, back/forward item %s" PRIu64, pageID(), m_lastSuspendedPage->loggingString(), m_process->processIdentifier(), currentItem->itemID().logString());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPageProxy::suspendedPageClosed(SuspendedPageProxy& page)
-{
-    ASSERT_UNUSED(page, &page == m_suspendedPage.get());
-    m_suspendedPage = nullptr;
-}
-
</del><span class="cx"> void WebPageProxy::swapToWebProcess(Ref<WebProcessProxy>&& process, API::Navigation& navigation, std::optional<uint64_t> mainFrameIDInPreviousProcess)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_isClosed);
</span><span class="cx">     RELEASE_LOG_IF_ALLOWED(Process, "%p WebPageProxy::swapToWebProcess\n", this);
</span><span class="cx"> 
</span><del>-    // If the process we're attaching to is kept alive solely by our current suspended page,
-    // we need to maintain that by temporarily keeping the suspended page alive.
-    auto currentSuspendedPage = WTFMove(m_suspendedPage);
-    if (mainFrameIDInPreviousProcess)
-        m_process->suspendWebPageProxy(*this, navigation, *mainFrameIDInPreviousProcess);
</del><ins>+    std::unique_ptr<SuspendedPageProxy> destinationSuspendedPage;
+    if (auto* backForwardListItem = navigation.targetItem()) {
+        if (backForwardListItem->suspendedPage() && &backForwardListItem->suspendedPage()->process() == process.ptr()) {
+            destinationSuspendedPage = this->process().processPool().takeSuspendedPageProxy(*backForwardListItem->suspendedPage());
+            ASSERT(destinationSuspendedPage);
+            destinationSuspendedPage->unsuspend();
+        }
+    }
</ins><span class="cx"> 
</span><ins>+    m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
+    suspendCurrentPageIfPossible(navigation, mainFrameIDInPreviousProcess);
+    m_process->removeWebPage(*this, m_pageID);
+
</ins><span class="cx">     m_process = WTFMove(process);
</span><span class="cx">     m_isValid = true;
</span><span class="cx"> 
</span><span class="lines">@@ -752,10 +754,11 @@
</span><span class="cx">     // WebPageProxy::didCreateMainFrame() will not be called to initialize m_mainFrame. In such
</span><span class="cx">     // case, we need to initialize m_mainFrame to reflect the fact the the WebProcess' WebPage
</span><span class="cx">     // already exists and already has a main frame.
</span><del>-    if (currentSuspendedPage && currentSuspendedPage->process() == m_process.ptr()) {
</del><ins>+    if (destinationSuspendedPage) {
</ins><span class="cx">         ASSERT(!m_mainFrame);
</span><del>-        m_mainFrame = WebFrameProxy::create(this, currentSuspendedPage->mainFrameID());
-        m_process->frameCreated(currentSuspendedPage->mainFrameID(), *m_mainFrame);
</del><ins>+        ASSERT(&destinationSuspendedPage->process() == m_process.ptr());
+        m_mainFrame = WebFrameProxy::create(this, destinationSuspendedPage->mainFrameID());
+        m_process->frameCreated(destinationSuspendedPage->mainFrameID(), *m_mainFrame);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     finishAttachingToWebProcess();
</span><span class="lines">@@ -928,6 +931,8 @@
</span><span class="cx"> 
</span><span class="cx">     m_webProcessLifetimeTracker.pageWasInvalidated();
</span><span class="cx"> 
</span><ins>+    m_process->processPool().removeAllSuspendedPageProxiesForPage(*this);
+
</ins><span class="cx">     m_process->send(Messages::WebPage::Close(), m_pageID);
</span><span class="cx">     m_process->removeWebPage(*this, m_pageID);
</span><span class="cx">     m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
</span><span class="lines">@@ -2554,7 +2559,7 @@
</span><span class="cx"> 
</span><span class="cx">         auto itemStates = m_backForwardList->filteredItemStates([this, targetItem = item](WebBackForwardListItem& item) {
</span><span class="cx">             if (auto* page = item.suspendedPage()) {
</span><del>-                if (page->process() == m_process.ptr())
</del><ins>+                if (&page->process() == m_process.ptr())
</ins><span class="cx">                     return false;
</span><span class="cx">             }
</span><span class="cx">             return &item != targetItem;
</span><span class="lines">@@ -3490,7 +3495,7 @@
</span><span class="cx"> void WebPageProxy::didCompletePageTransition(bool isInitialEmptyDocument)
</span><span class="cx"> {
</span><span class="cx">     // Attach drawing area for the initial empty document only if this is not a process swap.
</span><del>-    if (isInitialEmptyDocument && m_suspendedPage)
</del><ins>+    if (isInitialEmptyDocument && m_lastSuspendedPage)
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(MAC)
</span><span class="lines">@@ -3500,8 +3505,8 @@
</span><span class="cx">     // Drawing area for the suspended page will be torn down when the attach completes.
</span><span class="cx">     m_drawingArea->attachInWebProcess();
</span><span class="cx"> #else
</span><del>-    if (m_suspendedPage)
-        m_suspendedPage->tearDownDrawingAreaInWebProcess();
</del><ins>+    if (m_lastSuspendedPage)
+        m_lastSuspendedPage->tearDownDrawingAreaInWebProcess();
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -6395,8 +6400,8 @@
</span><span class="cx">     pageClient().enterAcceleratedCompositingMode(layerTreeContext);
</span><span class="cx"> 
</span><span class="cx">     // We have completed the page transition and can tear down the layers in the suspended process.
</span><del>-    if (m_suspendedPage)
-        m_suspendedPage->tearDownDrawingAreaInWebProcess();
</del><ins>+    if (m_lastSuspendedPage)
+        m_lastSuspendedPage->tearDownDrawingAreaInWebProcess();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPageProxy::exitAcceleratedCompositingMode()
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebPageProxy.h     2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h        2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -1355,10 +1355,6 @@
</span><span class="cx"> 
</span><span class="cx">     WebPreferencesStore preferencesStore() const;
</span><span class="cx"> 
</span><del>-    SuspendedPageProxy* maybeCreateSuspendedPage(WebProcessProxy&, API::Navigation&, uint64_t mainFrameID);
-    SuspendedPageProxy* suspendedPage() const { return m_suspendedPage.get(); }
-    void suspendedPageClosed(SuspendedPageProxy&);
-
</del><span class="cx">     void setDefersLoadingForTesting(bool);
</span><span class="cx"> 
</span><span class="cx">     WebCore::IntRect syncRootViewToScreen(const WebCore::IntRect& viewRect);
</span><span class="lines">@@ -1379,6 +1375,8 @@
</span><span class="cx">     void updateThrottleState();
</span><span class="cx">     void updateHiddenPageThrottlingAutoIncreases();
</span><span class="cx"> 
</span><ins>+    void suspendCurrentPageIfPossible(API::Navigation&, std::optional<uint64_t> mainFrameID);
+
</ins><span class="cx">     enum class ResetStateReason {
</span><span class="cx">         PageInvalidated,
</span><span class="cx">         WebProcessExited,
</span><span class="lines">@@ -2260,10 +2258,8 @@
</span><span class="cx"> 
</span><span class="cx">     std::optional<MonotonicTime> m_pageLoadStart;
</span><span class="cx"> 
</span><del>-    // FIXME: Support more than one suspended page per WebPageProxy,
-    // and have a global collection of them per process pool
-    // (e.g. for that process pool's page cache)
-    std::unique_ptr<SuspendedPageProxy> m_suspendedPage;
</del><ins>+    // FIXME: We should try and get rid of this data member.
+    WeakPtr<SuspendedPageProxy> m_lastSuspendedPage;
</ins><span class="cx"> 
</span><span class="cx">     RunLoop::Timer<WebPageProxy> m_resetRecentCrashCountTimer;
</span><span class="cx">     unsigned m_recentCrashCount { 0 };
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessPoolcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp    2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -124,7 +124,8 @@
</span><span class="cx"> 
</span><span class="cx"> DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, processPoolCounter, ("WebProcessPool"));
</span><span class="cx"> 
</span><del>-static const Seconds serviceWorkerTerminationDelay { 5_s };
</del><ins>+const Seconds serviceWorkerTerminationDelay { 5_s };
+const unsigned maximumSuspendedPagesCount { 3 };
</ins><span class="cx"> 
</span><span class="cx"> static uint64_t generateListenerIdentifier()
</span><span class="cx"> {
</span><span class="lines">@@ -1022,6 +1023,10 @@
</span><span class="cx">     if (m_processWithPageCache == process)
</span><span class="cx">         m_processWithPageCache = nullptr;
</span><span class="cx"> 
</span><ins>+    m_suspendedPages.removeAllMatching([process](auto& suspendedPage) {
+        return &suspendedPage->process() == process;
+    });
+
</ins><span class="cx"> #if ENABLE(SERVICE_WORKER)
</span><span class="cx">     if (is<ServiceWorkerProcessProxy>(*process)) {
</span><span class="cx">         auto* removedProcess = m_serviceWorkerProcesses.take(downcast<ServiceWorkerProcessProxy>(*process).securityOrigin());
</span><span class="lines">@@ -1291,6 +1296,8 @@
</span><span class="cx">     if (m_prewarmedProcess)
</span><span class="cx">         m_prewarmedProcess->shutDown();
</span><span class="cx">     ASSERT(!m_prewarmedProcess);
</span><ins>+
+    m_suspendedPages.clear();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(NETSCAPE_PLUGIN_API)
</span><span class="lines">@@ -2117,10 +2124,9 @@
</span><span class="cx"> 
</span><span class="cx">     if (auto* backForwardListItem = navigation.targetItem()) {
</span><span class="cx">         if (auto* suspendedPage = backForwardListItem->suspendedPage()) {
</span><del>-            ASSERT(suspendedPage->process());
</del><span class="cx">             action = PolicyAction::Suspend;
</span><span class="cx">             reason = "Using target back/forward item's process"_s;
</span><del>-            return *suspendedPage->process();
</del><ins>+            return suspendedPage->process();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // If the target back/forward item and the current back/forward item originated
</span><span class="lines">@@ -2171,10 +2177,7 @@
</span><span class="cx">                 // In the case where this WebProcess has a SuspendedPageProxy for this WebPage, we can throw it away to support
</span><span class="cx">                 // WebProcess re-use.
</span><span class="cx">                 // In the future it would be great to refactor-out this limitation.
</span><del>-                if (auto* suspendedPage = page.suspendedPage()) {
-                    LOG(ProcessSwapping, "(ProcessSwapping) Destroying suspended page for that swap");
-                    suspendedPage->destroyWebPageInWebProcess();
-                }
</del><ins>+                page.process().processPool().removeAllSuspendedPageProxiesForPage(page);
</ins><span class="cx"> 
</span><span class="cx">                 return makeRef(*process);
</span><span class="cx">             }
</span><span class="lines">@@ -2191,30 +2194,33 @@
</span><span class="cx">     return createNewWebProcess(page.websiteDataStore());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebProcessPool::registerSuspendedPageProxy(SuspendedPageProxy& page)
</del><ins>+void WebProcessPool::addSuspendedPageProxy(std::unique_ptr<SuspendedPageProxy>&& suspendedPage)
</ins><span class="cx"> {
</span><del>-    auto& vector = m_suspendedPages.ensure(page.origin(), [] {
-        return Vector<SuspendedPageProxy*> { };
-    }).iterator->value;
</del><ins>+    if (m_suspendedPages.size() >= maximumSuspendedPagesCount)
+        m_suspendedPages.removeFirst();
</ins><span class="cx"> 
</span><del>-    vector.append(&page);
</del><ins>+    m_suspendedPages.append(WTFMove(suspendedPage));
+}
</ins><span class="cx"> 
</span><del>-#if !LOG_DISABLED
-    if (vector.size() > 5)
-        LOG(ProcessSwapping, "Security origin %s now has %zu suspended pages (this seems unexpected)", page.origin().debugString().utf8().data(), vector.size());
-#endif
</del><ins>+void WebProcessPool::removeAllSuspendedPageProxiesForPage(WebPageProxy& page)
+{
+    m_suspendedPages.removeAllMatching([&page](auto& suspendedPage) {
+        return &suspendedPage->page() == &page;
+    });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebProcessPool::unregisterSuspendedPageProxy(SuspendedPageProxy& page)
</del><ins>+std::unique_ptr<SuspendedPageProxy> WebProcessPool::takeSuspendedPageProxy(SuspendedPageProxy& suspendedPage)
</ins><span class="cx"> {
</span><del>-    auto iterator = m_suspendedPages.find(page.origin());
-    ASSERT(iterator != m_suspendedPages.end());
</del><ins>+    return m_suspendedPages.takeFirst([&suspendedPage](auto& item) {
+        return item.get() == &suspendedPage;
+    });
+}
</ins><span class="cx"> 
</span><del>-    auto result = iterator->value.removeFirst(&page);
-    ASSERT_UNUSED(result, result);
-
-    if (iterator->value.isEmpty())
-        m_suspendedPages.remove(iterator);
</del><ins>+bool WebProcessPool::hasSuspendedPageProxyFor(WebProcessProxy& process)
+{
+    return m_suspendedPages.findIf([&process](auto& suspendedPage) {
+        return &suspendedPage->process() == &process;
+    }) != m_suspendedPages.end();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebProcessPool::addMockMediaDevice(const MockMediaDevice& device)
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessPoolh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebProcessPool.h   2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h      2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -440,8 +440,13 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     Ref<WebProcessProxy> processForNavigation(WebPageProxy&, const API::Navigation&, ProcessSwapRequestedByClient, WebCore::PolicyAction&, String& reason);
</span><del>-    void registerSuspendedPageProxy(SuspendedPageProxy&);
-    void unregisterSuspendedPageProxy(SuspendedPageProxy&);
</del><ins>+
+    // SuspendedPageProxy management.
+    void addSuspendedPageProxy(std::unique_ptr<SuspendedPageProxy>&&);
+    void removeAllSuspendedPageProxiesForPage(WebPageProxy&);
+    std::unique_ptr<SuspendedPageProxy> takeSuspendedPageProxy(SuspendedPageProxy&);
+    bool hasSuspendedPageProxyFor(WebProcessProxy&);
+
</ins><span class="cx">     void didReachGoodTimeToPrewarm();
</span><span class="cx"> 
</span><span class="cx">     void didCollectPrewarmInformation(const String& registrableDomain, const WebCore::PrewarmInformation&);
</span><span class="lines">@@ -703,7 +708,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    HashMap<WebCore::SecurityOriginData, Vector<SuspendedPageProxy*>> m_suspendedPages;
</del><ins>+    Deque<std::unique_ptr<SuspendedPageProxy>> m_suspendedPages;
</ins><span class="cx">     HashMap<String, RefPtr<WebProcessProxy>> m_swappedProcessesPerRegistrableDomain;
</span><span class="cx"> 
</span><span class="cx">     HashMap<String, std::unique_ptr<WebCore::PrewarmInformation>> m_prewarmInformationPerRegistrableDomain;
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp        2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp   2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -34,7 +34,6 @@
</span><span class="cx"> #include "Logging.h"
</span><span class="cx"> #include "PluginInfoStore.h"
</span><span class="cx"> #include "PluginProcessManager.h"
</span><del>-#include "SuspendedPageProxy.h"
</del><span class="cx"> #include "TextChecker.h"
</span><span class="cx"> #include "TextCheckerState.h"
</span><span class="cx"> #include "UIMessagePortChannelProvider.h"
</span><span class="lines">@@ -444,27 +443,6 @@
</span><span class="cx">     updateBackgroundResponsivenessTimer();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebProcessProxy::suspendWebPageProxy(WebPageProxy& webPage, API::Navigation& navigation, uint64_t mainFrameID)
-{
-    if (auto* suspendedPage = webPage.maybeCreateSuspendedPage(*this, navigation, mainFrameID)) {
-        LOG(ProcessSwapping, "WebProcessProxy pid %i added suspended page %s", processIdentifier(), suspendedPage->loggingString());
-        m_suspendedPageMap.set(webPage.pageID(), suspendedPage);
-    }
-
-    removeWebPage(webPage, webPage.pageID());
-    removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), webPage.pageID());
-}
-
-void WebProcessProxy::suspendedPageWasDestroyed(SuspendedPageProxy& suspendedPage)
-{
-    LOG(ProcessSwapping, "WebProcessProxy pid %i suspended page %s was destroyed", processIdentifier(), suspendedPage.loggingString());
-
-    ASSERT(m_suspendedPageMap.contains(suspendedPage.page().pageID()));
-    m_suspendedPageMap.remove(suspendedPage.page().pageID());
-
-    maybeShutDown();
-}
-
</del><span class="cx"> void WebProcessProxy::markIsNoLongerInPrewarmedPool()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_isPrewarmed);
</span><span class="lines">@@ -673,15 +651,6 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // WebPageProxy messages are normally handled by the normal "dispatchMessage" up above.
-    // If they were not handled there, then they may potentially be handled by SuspendedPageProxy objects.
-    if (decoder.messageReceiverName() == Messages::WebPageProxy::messageReceiverName()) {
-        if (auto* suspendedPage = m_suspendedPageMap.get(decoder.destinationID())) {
-            suspendedPage->didReceiveMessage(connection, decoder);
-            return;
-        }
-    }
-
</del><span class="cx">     // FIXME: Add unhandled message logging.
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -729,11 +698,6 @@
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    for (auto* suspendedPage : copyToVectorOf<SuspendedPageProxy*>(m_suspendedPageMap.values()))
-        suspendedPage->webProcessDidClose(*this);
-
-    m_suspendedPageMap.clear();
-
</del><span class="cx">     for (auto& page : pages)
</span><span class="cx">         page->processDidTerminate(ProcessTerminationReason::Crash);
</span><span class="cx"> }
</span><span class="lines">@@ -901,7 +865,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool WebProcessProxy::canTerminateChildProcess()
</span><span class="cx"> {
</span><del>-    if (!m_pageMap.isEmpty() || !m_suspendedPageMap.isEmpty())
</del><ins>+    if (!m_pageMap.isEmpty() || m_processPool->hasSuspendedPageProxyFor(*this))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     if (!m_processPool->shouldTerminate(this))
</span><span class="lines">@@ -1015,11 +979,6 @@
</span><span class="cx"> 
</span><span class="cx">     shutDown();
</span><span class="cx"> 
</span><del>-    for (auto* suspendedPage : copyToVectorOf<SuspendedPageProxy*>(m_suspendedPageMap.values()))
-        suspendedPage->webProcessDidClose(*this);
-
-    m_suspendedPageMap.clear();
-
</del><span class="cx">     for (auto& page : pages)
</span><span class="cx">         page->processDidTerminate(reason);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.h (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebProcessProxy.h  2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.h     2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -67,7 +67,6 @@
</span><span class="cx"> class NetworkProcessProxy;
</span><span class="cx"> class ObjCObjectGraph;
</span><span class="cx"> class PageClient;
</span><del>-class SuspendedPageProxy;
</del><span class="cx"> class UserMediaCaptureManagerProxy;
</span><span class="cx"> class VisitedLinkStore;
</span><span class="cx"> class WebBackForwardListItem;
</span><span class="lines">@@ -208,9 +207,6 @@
</span><span class="cx">     void didCommitProvisionalLoad() { m_hasCommittedAnyProvisionalLoads = true; }
</span><span class="cx">     bool hasCommittedAnyProvisionalLoads() const { return m_hasCommittedAnyProvisionalLoads; }
</span><span class="cx"> 
</span><del>-    void suspendWebPageProxy(WebPageProxy&, API::Navigation&, uint64_t mainFrameID);
-    void suspendedPageWasDestroyed(SuspendedPageProxy&);
-
</del><span class="cx"> #if PLATFORM(WATCHOS)
</span><span class="cx">     void takeBackgroundActivityTokenForFullscreenInput();
</span><span class="cx">     void releaseBackgroundActivityTokenForFullscreenInput();
</span><span class="lines">@@ -232,6 +228,7 @@
</span><span class="cx">     // Called when the web process has crashed or we know that it will terminate soon.
</span><span class="cx">     // Will potentially cause the WebProcessProxy object to be freed.
</span><span class="cx">     void shutDown();
</span><ins>+    void maybeShutDown();
</ins><span class="cx"> 
</span><span class="cx"> protected:
</span><span class="cx">     static uint64_t generatePageID();
</span><span class="lines">@@ -251,8 +248,6 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    void maybeShutDown();
-
</del><span class="cx">     // IPC message handlers.
</span><span class="cx">     void updateBackForwardItem(const BackForwardListItemState&);
</span><span class="cx">     void didDestroyFrame(uint64_t);
</span><span class="lines">@@ -361,7 +356,6 @@
</span><span class="cx">     HashSet<String> m_localPathsWithAssumedReadAccess;
</span><span class="cx"> 
</span><span class="cx">     WebPageProxyMap m_pageMap;
</span><del>-    HashMap<uint64_t, SuspendedPageProxy*> m_suspendedPageMap;
</del><span class="cx">     WebFrameProxyMap m_frameMap;
</span><span class="cx">     UserInitiatedActionMap m_userInitiatedActionMap;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Tools/ChangeLog       2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2018-10-18  Chris Dumez  <cdumez@apple.com>
+
+        [PSON] Cap number of SuspendedPageProxy objects and allow a WebPageProxy to have more than one
+        https://bugs.webkit.org/show_bug.cgi?id=190688
+        <rdar://problem/45354095>
+
+        Reviewed by Antti Koivisto.
+
+        Extended API test coverage to confirm that:
+        - We do not accumulate more than 3 suspended processes.
+        - We can navigate back 3 times and use the page cache for each of these loads.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
</ins><span class="cx"> 2018-10-17  Wenson Hsieh  <wenson_hsieh@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Enable the datalist element by default on iOS and macOS
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitCocoaProcessSwapOnNavigationmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (237256 => 237257)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm   2018-10-18 15:19:10 UTC (rev 237256)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm      2018-10-18 15:33:54 UTC (rev 237257)
</span><span class="lines">@@ -412,6 +412,7 @@
</span><span class="cx">     EXPECT_EQ(numberOfDecidePolicyCalls, 2);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// We currently keep 3 suspended pages around so we can go back 3 times and use the page cache for each load.
</ins><span class="cx"> TEST(ProcessSwap, Back)
</span><span class="cx"> {
</span><span class="cx">     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
</span><span class="lines">@@ -422,6 +423,8 @@
</span><span class="cx">     [webViewConfiguration setProcessPool:processPool.get()];
</span><span class="cx">     auto handler = adoptNS([[PSONScheme alloc] init]);
</span><span class="cx">     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes];
</span><ins>+    [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:testBytes];
+    [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:testBytes];
</ins><span class="cx">     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
</span><span class="cx"> 
</span><span class="cx">     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
</span><span class="lines">@@ -439,7 +442,7 @@
</span><span class="cx">     TestWebKitAPI::Util::run(&done);
</span><span class="cx">     done = false;
</span><span class="cx"> 
</span><del>-    auto pid1 = [webView _webProcessIdentifier];
</del><ins>+    auto webkitPID = [webView _webProcessIdentifier];
</ins><span class="cx"> 
</span><span class="cx">     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
</span><span class="cx">     [webView loadRequest:request];
</span><span class="lines">@@ -447,30 +450,70 @@
</span><span class="cx">     TestWebKitAPI::Util::run(&done);
</span><span class="cx">     done = false;
</span><span class="cx"> 
</span><del>-    auto pid2 = [webView _webProcessIdentifier];
</del><ins>+    auto applePID = [webView _webProcessIdentifier];
+    EXPECT_NE(webkitPID, applePID);
</ins><span class="cx"> 
</span><del>-    [webView goBack];
</del><ins>+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
+    [webView loadRequest:request];
</ins><span class="cx"> 
</span><ins>+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto googlePID = [webView _webProcessIdentifier];
+    EXPECT_NE(applePID, googlePID);
+
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.bing.com/main.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto bingPID = [webView _webProcessIdentifier];
+    EXPECT_NE(googlePID, bingPID);
+
+    [webView goBack]; // Back to google.com.
+
</ins><span class="cx">     TestWebKitAPI::Util::run(&receivedMessage);
</span><span class="cx">     receivedMessage = false;
</span><span class="cx">     TestWebKitAPI::Util::run(&done);
</span><span class="cx">     done = false;
</span><span class="cx"> 
</span><del>-    auto pid3 = [webView _webProcessIdentifier];
</del><ins>+    auto pidAfterFirstBackNavigation = [webView _webProcessIdentifier];
+    EXPECT_EQ(googlePID, pidAfterFirstBackNavigation);
</ins><span class="cx"> 
</span><del>-    // 3 loads, 3 decidePolicy calls (e.g. any load that performs a process swap should not have generated an
</del><ins>+    [webView goBack]; // Back to apple.com.
+
+    TestWebKitAPI::Util::run(&receivedMessage);
+    receivedMessage = false;
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pidAfterSecondBackNavigation = [webView _webProcessIdentifier];
+    EXPECT_EQ(applePID, pidAfterSecondBackNavigation);
+
+    [webView goBack]; // Back to webkit.org.
+
+    TestWebKitAPI::Util::run(&receivedMessage);
+    receivedMessage = false;
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pidAfterThirdBackNavigation = [webView _webProcessIdentifier];
+    EXPECT_EQ(webkitPID, pidAfterThirdBackNavigation);
+
+    // 7 loads, 7 decidePolicy calls (e.g. any load that performs a process swap should not have generated an
</ins><span class="cx">     // additional decidePolicy call as a result of the process swap)
</span><del>-    EXPECT_EQ(numberOfDecidePolicyCalls, 3);
</del><ins>+    EXPECT_EQ(7, numberOfDecidePolicyCalls);
</ins><span class="cx"> 
</span><del>-    EXPECT_EQ([receivedMessages count], 2u);
-    EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"PageShow called. Persisted: false, and window.history.state is: null"]);
-    EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"PageShow called. Persisted: true, and window.history.state is: onloadCalled"]);
</del><ins>+    EXPECT_EQ(6u, [receivedMessages count]);
+    EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[0]);
+    EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[1]);
+    EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[2]);
+    EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[3]);
+    EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[4]);
+    EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[5]);
</ins><span class="cx"> 
</span><del>-    EXPECT_EQ(2u, seenPIDs.size());
-
-    EXPECT_FALSE(pid1 == pid2);
-    EXPECT_FALSE(pid2 == pid3);
-    EXPECT_TRUE(pid1 == pid3);
</del><ins>+    EXPECT_EQ(4u, seenPIDs.size());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> TEST(ProcessSwap, BackWithoutSuspendedPage)
</span><span class="lines">@@ -1114,7 +1157,7 @@
</span><span class="cx">     EXPECT_EQ(1u, seenPIDs.size());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-TEST(ProcessSwap, OnePreviousProcessRemains)
</del><ins>+TEST(ProcessSwap, ThreePreviousProcessesRemains)
</ins><span class="cx"> {
</span><span class="cx">     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
</span><span class="cx">     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
</span><span class="lines">@@ -1147,11 +1190,23 @@
</span><span class="cx">     TestWebKitAPI::Util::run(&done);
</span><span class="cx">     done = false;
</span><span class="cx"> 
</span><del>-    // Navigations to 3 different domains, we expect to have seen 3 different PIDs
-    EXPECT_EQ(3u, seenPIDs.size());
</del><ins>+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.bing.com/main.html"]];
+    [webView loadRequest:request];
</ins><span class="cx"> 
</span><del>-    // But only 2 of those processes should still be alive
-    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
</del><ins>+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.yahoo.com/main.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    // Navigations to 5 different domains, we expect to have seen 5 different PIDs
+    EXPECT_EQ(5u, seenPIDs.size());
+
+    // But only 4 of those processes should still be alive (1 visible, 3 suspended).
+    EXPECT_EQ(4u, [processPool _webProcessCountIgnoringPrewarmed]);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static const char* pageCache1Bytes = R"PSONRESOURCE(
</span></span></pre>
</div>
</div>

</body>
</html>