[PSON] Introduce a WebContent Process cache
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Feb 2019 19:06:12 +0000 (19:06 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 14 Feb 2019 19:06:12 +0000 (19:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194594
<rdar://problem/46793397>

Reviewed by Geoff Garen.

Source/WebCore:

Update localizable strings.

* en.lproj/Localizable.strings:

Source/WebKit:

Introduce a WebContent Process cache to reduce the number of process launches when
process swap on navigation is enabled, and to reduce the power cost of the feature.

If a WebProcess loaded pages from a single registrable domain then it is eligible
for the cache. When process-swapping on navigation to a new registrable domain, we
now attempt to retrieve a process from the cache for the domain in question instead
of always launching a new one.

The WebProcess cache currently has the following attributes:
- It may contains 4 processes per GB of RAM the machine has, up to 30 processes.
- WebProcesses automatically get evicted from the cache after 30 minutes.
- If the application is no longer the active app, then the cache will get cleared
  after 5 minutes.
- WebProcesses that are in the cache are reported as "(Cached)" in Activity Monitor.

The WebProcess cache is currently disabled by default and can by enabled by the
client via SPI.

* Shared/WebBackForwardListItem.cpp:
(WebKit::WebBackForwardListItem::WebBackForwardListItem):
* Shared/WebBackForwardListItem.h:
(WebKit::WebBackForwardListItem::lastProcessIdentifier const):
(WebKit::WebBackForwardListItem::setLastProcessIdentifier):
Add new lastProcessIdentifier data member that reflects which process this item
was last loaded in. It is normally identical to the identifier of the process
that created the item but it gets overriden in case of cross-site client-side
redirect, since a new process takes over the item in this case.

* Sources.txt:
Add new source file.

* UIProcess/API/APIProcessPoolConfiguration.cpp:
(API::ProcessPoolConfiguration::copy):
* UIProcess/API/APIProcessPoolConfiguration.h:
* UIProcess/API/C/WKContextConfigurationRef.cpp:
(WKContextConfigurationUsesWebProcessCache):
(WKContextConfigurationSetUsesWebProcessCache):
* UIProcess/API/C/WKContextConfigurationRef.h:
* UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h:
* UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm:
(-[_WKProcessPoolConfiguration setUsesWebProcessCache:]):
(-[_WKProcessPoolConfiguration usesWebProcessCache]):
Add new SPI to enable the WebProcess cache.

* UIProcess/API/Cocoa/WKProcessPool.mm:
(-[WKProcessPool _webProcessCountIgnoringPrewarmedAndCached]):
* UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
Add new SPI for testing which returns the number of WebProcesses ignoring
both prewarmed and cached ones.

* UIProcess/Cocoa/WebProcessPoolCocoa.mm:
(WebKit::WebProcessPool::registerNotificationObservers):
(WebKit::WebProcessPool::unregisterNotificationObservers):
Add application active state observers as the WebProcess cache gets cleared
when the application resigns active state for more than 5 minutes.

* UIProcess/ProvisionalPageProxy.cpp:
(WebKit::ProvisionalPageProxy::loadRequest):
When doing a load in a new process with the BackForwardList locked (i.e. client-side
redirect), make sure we update the last process identifier for the BackForwardListItem.
This is important because the logic in WebProcessPool::processForNavigation() relies on
this identifier to select which process to do the history navigation into, and we want
to do the load in the post-redirect process, not the pre-redirect one.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didStartProvisionalLoadForFrameShared):
Tell the WebProcess whenever a main frame provisional load is started, providing the URL.

* UIProcess/WebProcessCache.cpp: Added.
(WebKit::WebProcessCache::WebProcessCache):
(WebKit::WebProcessCache::addProcess):
(WebKit::WebProcessCache::takeProcess):
(WebKit::WebProcessCache::updateMaximumSize):
(WebKit::WebProcessCache::clear):
(WebKit::WebProcessCache::setApplicationIsActive):
(WebKit::WebProcessCache::evictProcess):
(WebKit::WebProcessCache::CachedProcess::CachedProcess):
(WebKit::WebProcessCache::CachedProcess::~CachedProcess):
(WebKit::WebProcessCache::CachedProcess::takeProcess):
(WebKit::WebProcessCache::CachedProcess::evictionTimerFired):
* UIProcess/WebProcessCache.h: Added.
(WebKit::WebProcessCache::maximumSize):
(WebKit::WebProcessCache::size const):
(WebKit::WebProcessCache::CachedProcess::process):
Add process cache implementation.

* UIProcess/WebProcessPool.cpp:
(WebKit::m_webProcessCache):
WebProcessCache is stored on the WebProcessPool via m_webProcessCache data member.

(WebKit::WebProcessPool::~WebProcessPool):
Clear the WebProcess cache in the destructor.

(WebKit::WebProcessPool::setApplicationIsActive):
Notify the WebProcessCache whenever the application's active state changes.

(WebKit::WebProcessPool::createWebPage):
If the state of PSON changes via the experimental features menu, dynamically
update the WebProcessCache's size. This is needed because the cache is disabled
when PSON is disabled.

(WebKit::WebProcessPool::handleMemoryPressureWarning):
Clear the WebProcess cache on memory pressure.

(WebKit::WebProcessPool::processForNavigationInternal):
Query the WebProcessCache before attempting to create a new WebProcess for a cross-site
navigation.

(WebKit::WebProcessPool::findReusableSuspendedPageProcess):
This logic was split out of processForNavigationInternal() to reduce the size
of the method.

* UIProcess/WebProcessPool.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::setIsInProcessCache):
Update the isInProcessCache flag on the WebProcessProxy and send an IPC to the WebContent
process so that it can update its name in Activity Monitor.
We also need to stop holding a strong reference to the WebProcessPool whenever the process
is in the cache, similarly to what we do for pre-warmed processes, given that such processes
should not keep the process pool alive.

(WebKit::WebProcessProxy::addExistingWebPage):
Assert that we never try to add a page to a cached process, it should be taken out of the
cache before use.

(WebKit::WebProcessProxy::hasProvisionalPageWithID const):
(WebKit::WebProcessProxy::isAllowedToUpdateBackForwardItem const):
(WebKit::WebProcessProxy::updateBackForwardItem):
In case of client-side redirects, the previous process would sometimes send an IPC causing
the UIProcess' backforward list item to get updated with the pre-redirect URL after we've
already redirected. This previously would be unlikely to occur because we do not suspend
client-redirect pages and their process would normally exit before getting a chance to send
the IPC. However, with the process cache, the bug became obvious as the process would stay
alive and send up the "bad" IPC. To address the issue, we now only let the IPC update the
item if the item's page is (still) associated with the process. In the future, we may want
to update the IPC so that it gets sent to the WebPageProxy instead of the WebProcessProxy.

(WebKit::WebProcessProxy::processDidTerminateOrFailedToLaunch):
If a cached WebProcess crashes, remove it from the cache so that we do not attempt to use
it for a load later.

(WebKit::WebProcessProxy::canBeAddedToWebProcessCache const):
Only cache WebProcesses that have loaded a single registrable domain. Also prevent caching
for service worker and inspector processes.

(WebKit::WebProcessProxy::maybeShutDown):
If the process is cacheable, add it to the cache instead of shutting it down right away.

(WebKit::WebProcessProxy::canTerminateAuxiliaryProcess):
Make sure we do not attempt to terminate a processes that is in the cache.

(WebKit::WebProcessProxy::didStartProvisionalLoadForMainFrame):
Whenever a main frame provisional load starts, make sure we update the process's associated
registrable domain. nullopt indicates that there is no associated domain yet. Null string
indicates that the process is associated with several registrable domain and is therefore
not eligible for caching.

* UIProcess/WebProcessProxy.h:
(WebKit::WebProcessProxy::registrableDomain const):
(WebKit::WebProcessProxy::isInProcessCache const):
(WebKit::WebProcessProxy::provisionalPageCount const):
Add convenience getters.

* WebKit.xcodeproj/project.pbxproj:
Add new files to project.

* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::setIsInProcessCache):
* WebProcess/WebProcess.h:
* WebProcess/WebProcess.messages.in:
* WebProcess/cocoa/WebProcessCocoa.mm:
(WebKit::WebProcess::updateProcessName):
Update the WebProcess' name in Activity Monitor whenever it goes into or out of the WebProcess
cache.

Tools:

Update API tests to turn on the WebContent Process cache.

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@241556 268f45cc-cd09-0410-ab3c-d52691b4dbfc

31 files changed:
Source/WebCore/ChangeLog
Source/WebCore/en.lproj/Localizable.strings
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebBackForwardListItem.cpp
Source/WebKit/Shared/WebBackForwardListItem.h
Source/WebKit/Sources.txt
Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp
Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h
Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.cpp
Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.h
Source/WebKit/UIProcess/API/C/WKPage.cpp
Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm
Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h
Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h
Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm
Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm
Source/WebKit/UIProcess/ProvisionalPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebProcessCache.cpp [new file with mode: 0644]
Source/WebKit/UIProcess/WebProcessCache.h [new file with mode: 0644]
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/UIProcess/WebProcessPool.h
Source/WebKit/UIProcess/WebProcessProxy.cpp
Source/WebKit/UIProcess/WebProcessProxy.h
Source/WebKit/WebKit.xcodeproj/project.pbxproj
Source/WebKit/WebProcess/WebProcess.cpp
Source/WebKit/WebProcess/WebProcess.h
Source/WebKit/WebProcess/WebProcess.messages.in
Source/WebKit/WebProcess/cocoa/WebProcessCocoa.mm
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm

index bf6eae5..5edffae 100644 (file)
@@ -1,3 +1,15 @@
+2019-02-14  Chris Dumez  <cdumez@apple.com>
+
+        [PSON] Introduce a WebContent Process cache
+        https://bugs.webkit.org/show_bug.cgi?id=194594
+        <rdar://problem/46793397>
+
+        Reviewed by Geoff Garen.
+
+        Update localizable strings.
+
+        * en.lproj/Localizable.strings:
+
 2019-02-14  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r241486.
index fbe299e..f144191 100644 (file)
@@ -47,6 +47,9 @@
 "%@ Web Content" = "%@ Web Content";
 
 /* Visible name of the web process. The argument is the application name. */
+"%@ Web Content (Cached)" = "%@ Web Content (Cached)";
+
+/* Visible name of the web process. The argument is the application name. */
 "%@ Web Content (Prewarmed)" = "%@ Web Content (Prewarmed)";
 
 /* Visible name of Web Inspector's web process. The argument is the application name. */
index 9df9cd5..008f9d6 100644 (file)
@@ -1,3 +1,186 @@
+2019-02-14  Chris Dumez  <cdumez@apple.com>
+
+        [PSON] Introduce a WebContent Process cache
+        https://bugs.webkit.org/show_bug.cgi?id=194594
+        <rdar://problem/46793397>
+
+        Reviewed by Geoff Garen.
+
+        Introduce a WebContent Process cache to reduce the number of process launches when
+        process swap on navigation is enabled, and to reduce the power cost of the feature.
+
+        If a WebProcess loaded pages from a single registrable domain then it is eligible
+        for the cache. When process-swapping on navigation to a new registrable domain, we
+        now attempt to retrieve a process from the cache for the domain in question instead
+        of always launching a new one.
+
+        The WebProcess cache currently has the following attributes:
+        - It may contains 4 processes per GB of RAM the machine has, up to 30 processes.
+        - WebProcesses automatically get evicted from the cache after 30 minutes.
+        - If the application is no longer the active app, then the cache will get cleared
+          after 5 minutes.
+        - WebProcesses that are in the cache are reported as "(Cached)" in Activity Monitor.
+
+        The WebProcess cache is currently disabled by default and can by enabled by the
+        client via SPI.
+
+        * Shared/WebBackForwardListItem.cpp:
+        (WebKit::WebBackForwardListItem::WebBackForwardListItem):
+        * Shared/WebBackForwardListItem.h:
+        (WebKit::WebBackForwardListItem::lastProcessIdentifier const):
+        (WebKit::WebBackForwardListItem::setLastProcessIdentifier):
+        Add new lastProcessIdentifier data member that reflects which process this item
+        was last loaded in. It is normally identical to the identifier of the process
+        that created the item but it gets overriden in case of cross-site client-side
+        redirect, since a new process takes over the item in this case.
+
+        * Sources.txt:
+        Add new source file.
+
+        * UIProcess/API/APIProcessPoolConfiguration.cpp:
+        (API::ProcessPoolConfiguration::copy):
+        * UIProcess/API/APIProcessPoolConfiguration.h:
+        * UIProcess/API/C/WKContextConfigurationRef.cpp:
+        (WKContextConfigurationUsesWebProcessCache):
+        (WKContextConfigurationSetUsesWebProcessCache):
+        * UIProcess/API/C/WKContextConfigurationRef.h:
+        * UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h:
+        * UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm:
+        (-[_WKProcessPoolConfiguration setUsesWebProcessCache:]):
+        (-[_WKProcessPoolConfiguration usesWebProcessCache]):
+        Add new SPI to enable the WebProcess cache.
+
+        * UIProcess/API/Cocoa/WKProcessPool.mm:
+        (-[WKProcessPool _webProcessCountIgnoringPrewarmedAndCached]):
+        * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+        Add new SPI for testing which returns the number of WebProcesses ignoring
+        both prewarmed and cached ones.
+
+        * UIProcess/Cocoa/WebProcessPoolCocoa.mm:
+        (WebKit::WebProcessPool::registerNotificationObservers):
+        (WebKit::WebProcessPool::unregisterNotificationObservers):
+        Add application active state observers as the WebProcess cache gets cleared
+        when the application resigns active state for more than 5 minutes.
+
+        * UIProcess/ProvisionalPageProxy.cpp:
+        (WebKit::ProvisionalPageProxy::loadRequest):
+        When doing a load in a new process with the BackForwardList locked (i.e. client-side
+        redirect), make sure we update the last process identifier for the BackForwardListItem.
+        This is important because the logic in WebProcessPool::processForNavigation() relies on
+        this identifier to select which process to do the history navigation into, and we want
+        to do the load in the post-redirect process, not the pre-redirect one.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::didStartProvisionalLoadForFrameShared):
+        Tell the WebProcess whenever a main frame provisional load is started, providing the URL.
+
+        * UIProcess/WebProcessCache.cpp: Added.
+        (WebKit::WebProcessCache::WebProcessCache):
+        (WebKit::WebProcessCache::addProcess):
+        (WebKit::WebProcessCache::takeProcess):
+        (WebKit::WebProcessCache::updateMaximumSize):
+        (WebKit::WebProcessCache::clear):
+        (WebKit::WebProcessCache::setApplicationIsActive):
+        (WebKit::WebProcessCache::evictProcess):
+        (WebKit::WebProcessCache::CachedProcess::CachedProcess):
+        (WebKit::WebProcessCache::CachedProcess::~CachedProcess):
+        (WebKit::WebProcessCache::CachedProcess::takeProcess):
+        (WebKit::WebProcessCache::CachedProcess::evictionTimerFired):
+        * UIProcess/WebProcessCache.h: Added.
+        (WebKit::WebProcessCache::maximumSize):
+        (WebKit::WebProcessCache::size const):
+        (WebKit::WebProcessCache::CachedProcess::process):
+        Add process cache implementation.
+
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::m_webProcessCache):
+        WebProcessCache is stored on the WebProcessPool via m_webProcessCache data member.
+
+        (WebKit::WebProcessPool::~WebProcessPool):
+        Clear the WebProcess cache in the destructor.
+
+        (WebKit::WebProcessPool::setApplicationIsActive):
+        Notify the WebProcessCache whenever the application's active state changes.
+
+        (WebKit::WebProcessPool::createWebPage):
+        If the state of PSON changes via the experimental features menu, dynamically
+        update the WebProcessCache's size. This is needed because the cache is disabled
+        when PSON is disabled.
+
+        (WebKit::WebProcessPool::handleMemoryPressureWarning):
+        Clear the WebProcess cache on memory pressure.
+
+        (WebKit::WebProcessPool::processForNavigationInternal):
+        Query the WebProcessCache before attempting to create a new WebProcess for a cross-site
+        navigation.
+
+        (WebKit::WebProcessPool::findReusableSuspendedPageProcess):
+        This logic was split out of processForNavigationInternal() to reduce the size
+        of the method.
+
+        * UIProcess/WebProcessPool.h:
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::setIsInProcessCache):
+        Update the isInProcessCache flag on the WebProcessProxy and send an IPC to the WebContent
+        process so that it can update its name in Activity Monitor.
+        We also need to stop holding a strong reference to the WebProcessPool whenever the process
+        is in the cache, similarly to what we do for pre-warmed processes, given that such processes
+        should not keep the process pool alive.
+
+        (WebKit::WebProcessProxy::addExistingWebPage):
+        Assert that we never try to add a page to a cached process, it should be taken out of the
+        cache before use.
+
+        (WebKit::WebProcessProxy::hasProvisionalPageWithID const):
+        (WebKit::WebProcessProxy::isAllowedToUpdateBackForwardItem const):
+        (WebKit::WebProcessProxy::updateBackForwardItem):
+        In case of client-side redirects, the previous process would sometimes send an IPC causing
+        the UIProcess' backforward list item to get updated with the pre-redirect URL after we've
+        already redirected. This previously would be unlikely to occur because we do not suspend
+        client-redirect pages and their process would normally exit before getting a chance to send
+        the IPC. However, with the process cache, the bug became obvious as the process would stay
+        alive and send up the "bad" IPC. To address the issue, we now only let the IPC update the
+        item if the item's page is (still) associated with the process. In the future, we may want
+        to update the IPC so that it gets sent to the WebPageProxy instead of the WebProcessProxy.
+
+        (WebKit::WebProcessProxy::processDidTerminateOrFailedToLaunch):
+        If a cached WebProcess crashes, remove it from the cache so that we do not attempt to use
+        it for a load later.
+
+        (WebKit::WebProcessProxy::canBeAddedToWebProcessCache const):
+        Only cache WebProcesses that have loaded a single registrable domain. Also prevent caching
+        for service worker and inspector processes.
+
+        (WebKit::WebProcessProxy::maybeShutDown):
+        If the process is cacheable, add it to the cache instead of shutting it down right away.
+
+        (WebKit::WebProcessProxy::canTerminateAuxiliaryProcess):
+        Make sure we do not attempt to terminate a processes that is in the cache.
+
+        (WebKit::WebProcessProxy::didStartProvisionalLoadForMainFrame):
+        Whenever a main frame provisional load starts, make sure we update the process's associated
+        registrable domain. nullopt indicates that there is no associated domain yet. Null string
+        indicates that the process is associated with several registrable domain and is therefore
+        not eligible for caching.
+
+        * UIProcess/WebProcessProxy.h:
+        (WebKit::WebProcessProxy::registrableDomain const):
+        (WebKit::WebProcessProxy::isInProcessCache const):
+        (WebKit::WebProcessProxy::provisionalPageCount const):
+        Add convenience getters.
+
+        * WebKit.xcodeproj/project.pbxproj:
+        Add new files to project.
+
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::setIsInProcessCache):
+        * WebProcess/WebProcess.h:
+        * WebProcess/WebProcess.messages.in:
+        * WebProcess/cocoa/WebProcessCocoa.mm:
+        (WebKit::WebProcess::updateProcessName):
+        Update the WebProcess' name in Activity Monitor whenever it goes into or out of the WebProcess
+        cache.
+
 2019-02-14  Per Arne Vollan  <pvollan@apple.com>
 
         [iOS] Open sandbox for certain calls.
index 03b43f1..9dbb36a 100644 (file)
@@ -43,6 +43,7 @@ Ref<WebBackForwardListItem> WebBackForwardListItem::create(BackForwardListItemSt
 WebBackForwardListItem::WebBackForwardListItem(BackForwardListItemState&& backForwardListItemState, uint64_t pageID)
     : m_itemState(WTFMove(backForwardListItemState))
     , m_pageID(pageID)
+    , m_lastProcessIdentifier(m_itemState.identifier.processIdentifier)
 {
     auto result = allItems().add(m_itemState.identifier, this);
     ASSERT_UNUSED(result, result.isNewEntry);
index bff0c88..872ef18 100644 (file)
@@ -56,6 +56,9 @@ public:
     const BackForwardListItemState& itemState() { return m_itemState; }
     uint64_t pageID() const { return m_pageID; }
 
+    WebCore::ProcessIdentifier lastProcessIdentifier() const { return m_lastProcessIdentifier; }
+    void setLastProcessIdentifier(const WebCore::ProcessIdentifier& identifier) { m_lastProcessIdentifier = identifier; }
+
     void setPageState(PageState pageState) { m_itemState.pageState = WTFMove(pageState); }
     const PageState& pageState() const { return m_itemState.pageState; }
 
@@ -84,6 +87,7 @@ private:
 
     BackForwardListItemState m_itemState;
     uint64_t m_pageID;
+    WebCore::ProcessIdentifier m_lastProcessIdentifier;
     WeakPtr<SuspendedPageProxy> m_suspendedPage;
 };
 
index 6673f3d..59cef83 100644 (file)
@@ -277,6 +277,7 @@ UIProcess/WebPageInspectorTargetAgent.cpp
 UIProcess/WebPageProxy.cpp
 UIProcess/WebPasteboardProxy.cpp
 UIProcess/WebPreferences.cpp
+UIProcess/WebProcessCache.cpp
 UIProcess/WebProcessLifetimeObserver.cpp
 UIProcess/WebProcessLifetimeTracker.cpp
 UIProcess/WebProcessPool.cpp
index d17978e..23cf035 100644 (file)
@@ -124,6 +124,7 @@ Ref<ProcessPoolConfiguration> ProcessPoolConfiguration::copy()
     copy->m_alwaysKeepAndReuseSwappedProcesses = this->m_alwaysKeepAndReuseSwappedProcesses;
     copy->m_processSwapsOnWindowOpenWithOpener = this->m_processSwapsOnWindowOpenWithOpener;
     copy->m_isAutomaticProcessWarmingEnabledByClient = this->m_isAutomaticProcessWarmingEnabledByClient;
+    copy->m_usesWebProcessCache = this->m_usesWebProcessCache;
 #if ENABLE(PROXIMITY_NETWORKING)
     copy->m_wirelessContextIdentifier = this->m_wirelessContextIdentifier;
 #endif
index e3a6a77..a016612 100644 (file)
@@ -67,6 +67,9 @@ public:
     bool wasAutomaticProcessWarmingSetByClient() const { return !!m_isAutomaticProcessWarmingEnabledByClient; }
     void setIsAutomaticProcessWarmingEnabled(bool value) { m_isAutomaticProcessWarmingEnabledByClient = value; }
 
+    void setUsesWebProcessCache(bool value) { m_usesWebProcessCache = value; }
+    bool usesWebProcessCache() const { return m_usesWebProcessCache; }
+
     bool clientWouldBenefitFromAutomaticProcessPrewarming() const { return m_clientWouldBenefitFromAutomaticProcessPrewarming; }
     void setClientWouldBenefitFromAutomaticProcessPrewarming(bool value) { m_clientWouldBenefitFromAutomaticProcessPrewarming = value; }
 
@@ -223,6 +226,7 @@ private:
     bool m_alwaysKeepAndReuseSwappedProcesses { false };
     bool m_processSwapsOnWindowOpenWithOpener { false };
     Optional<bool> m_isAutomaticProcessWarmingEnabledByClient;
+    bool m_usesWebProcessCache { false };
     bool m_clientWouldBenefitFromAutomaticProcessPrewarming { false };
     WTF::String m_customWebContentServiceBundleIdentifier;
     bool m_isJITEnabled { true };
index 338c0dd..1765314 100644 (file)
@@ -188,6 +188,16 @@ void WKContextConfigurationSetPrewarmsProcessesAutomatically(WKContextConfigurat
     toImpl(configuration)->setIsAutomaticProcessWarmingEnabled(prewarms);
 }
 
+bool WKContextConfigurationUsesWebProcessCache(WKContextConfigurationRef configuration)
+{
+    return toImpl(configuration)->usesWebProcessCache();
+}
+
+void WKContextConfigurationSetUsesWebProcessCache(WKContextConfigurationRef configuration, bool uses)
+{
+    toImpl(configuration)->setUsesWebProcessCache(uses);
+}
+
 bool WKContextConfigurationAlwaysKeepAndReuseSwappedProcesses(WKContextConfigurationRef configuration)
 {
     return toImpl(configuration)->alwaysKeepAndReuseSwappedProcesses();
index ad3e7a1..93985ad 100644 (file)
@@ -78,6 +78,9 @@ WK_EXPORT void WKContextConfigurationSetProcessSwapsOnNavigation(WKContextConfig
 WK_EXPORT bool WKContextConfigurationPrewarmsProcessesAutomatically(WKContextConfigurationRef configuration);
 WK_EXPORT void WKContextConfigurationSetPrewarmsProcessesAutomatically(WKContextConfigurationRef configuration, bool prewarms);
 
+WK_EXPORT bool WKContextConfigurationUsesWebProcessCache(WKContextConfigurationRef configuration);
+WK_EXPORT void WKContextConfigurationSetUsesWebProcessCache(WKContextConfigurationRef configuration, bool uses);
+
 WK_EXPORT bool WKContextConfigurationAlwaysKeepAndReuseSwappedProcesses(WKContextConfigurationRef configuration);
 WK_EXPORT void WKContextConfigurationSetAlwaysKeepAndReuseSwappedProcesses(WKContextConfigurationRef configuration, bool keepAndReuse);
 
index 563a438..adfc815 100644 (file)
@@ -65,6 +65,8 @@
 #include "WKPageRenderingProgressEventsInternal.h"
 #include "WKPluginInformation.h"
 #include "WebBackForwardList.h"
+#include "WebContextMenu.h"
+#include "WebContextMenuItem.h"
 #include "WebFormClient.h"
 #include "WebImage.h"
 #include "WebInspectorProxy.h"
index 298b44e..c345cd9 100644 (file)
@@ -39,6 +39,7 @@
 #import "WKWebViewInternal.h"
 #import "WebCertificateInfo.h"
 #import "WebCookieManagerProxy.h"
+#import "WebProcessCache.h"
 #import "WebProcessMessages.h"
 #import "WebProcessPool.h"
 #import "_WKAutomationDelegate.h"
@@ -475,6 +476,11 @@ static NSDictionary *policiesHashMapToDictionary(const HashMap<String, HashMap<S
     return [self _webProcessCount] - ([self _hasPrewarmedWebProcess] ? 1 : 0);
 }
 
+- (size_t)_webProcessCountIgnoringPrewarmedAndCached
+{
+    return [self _webProcessCount] - ([self _hasPrewarmedWebProcess] ? 1 : 0) - _processPool->webProcessCache().size();
+}
+
 - (size_t)_webPageContentProcessCount
 {
     auto allWebProcesses = _processPool->processes();
index 470dd53..075f719 100644 (file)
@@ -96,6 +96,7 @@
 - (size_t)_webProcessCount WK_API_AVAILABLE(macosx(10.13), ios(11.0));
 - (BOOL)_hasPrewarmedWebProcess WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (size_t)_webProcessCountIgnoringPrewarmed WK_API_AVAILABLE(macosx(10.14), ios(12.0));
+- (size_t)_webProcessCountIgnoringPrewarmedAndCached WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (size_t)_pluginProcessCount WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
 - (size_t)_serviceWorkerProcessCount WK_API_AVAILABLE(macosx(10.14), ios(12.0));
 - (void)_syncNetworkProcessCookies WK_API_AVAILABLE(macosx(10.13), ios(11.0));
index f671d7b..40500d9 100644 (file)
@@ -67,6 +67,7 @@ WK_CLASS_AVAILABLE(macosx(10.10), ios(8.0))
 @property (nonatomic) BOOL alwaysKeepAndReuseSwappedProcesses WK_API_AVAILABLE(macosx(10.14), ios(12.0));
 @property (nonatomic) BOOL processSwapsOnWindowOpenWithOpener WK_API_AVAILABLE(macosx(10.14), ios(12.0));
 @property (nonatomic) BOOL prewarmsProcessesAutomatically WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+@property (nonatomic) BOOL usesWebProcessCache WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 @property (nonatomic) BOOL pageCacheEnabled WK_API_AVAILABLE(macosx(10.14), ios(12.0));
 @property (nonatomic) BOOL suppressesConnectionTerminationOnSystemChange WK_API_AVAILABLE(macosx(10.14), ios(12.0));
 @property (nonatomic, getter=isJITEnabled) BOOL JITEnabled WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
index 8a36781..01bf6a5 100644 (file)
     return _processPoolConfiguration->isAutomaticProcessWarmingEnabled();
 }
 
+- (void)setUsesWebProcessCache:(BOOL)value
+{
+    _processPoolConfiguration->setUsesWebProcessCache(value);
+}
+
+- (BOOL)usesWebProcessCache
+{
+    return _processPoolConfiguration->usesWebProcessCache();
+}
+
 - (void)setAlwaysKeepAndReuseSwappedProcesses:(BOOL)swaps
 {
     _processPoolConfiguration->setAlwaysKeepAndReuseSwappedProcesses(swaps);
index 70c91a6..98746c3 100644 (file)
@@ -418,6 +418,14 @@ void WebProcessPool::registerNotificationObservers()
     }];
 #endif
 
+    m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidBecomeActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
+        setApplicationIsActive(true);
+    }];
+
+    m_deactivationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidResignActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
+        setApplicationIsActive(false);
+    }];
+
 #endif // !PLATFORM(IOS_FAMILY)
 }
 
@@ -433,6 +441,8 @@ void WebProcessPool::unregisterNotificationObservers()
 #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
     [[NSNotificationCenter defaultCenter] removeObserver:m_scrollerStyleNotificationObserver.get()];
 #endif
+    [[NSNotificationCenter defaultCenter] removeObserver:m_activationObserver.get()];
+    [[NSNotificationCenter defaultCenter] removeObserver:m_deactivationObserver.get()];
 #endif // !PLATFORM(IOS_FAMILY)
 }
 
index a3f5711..b66ff9b 100644 (file)
@@ -154,6 +154,12 @@ void ProvisionalPageProxy::loadRequest(API::Navigation& navigation, WebCore::Res
 {
     RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "loadRequest: pageID = %" PRIu64, m_page.pageID());
 
+    // If this is a client-side redirect continuing in a new process, then the new process will overwrite the fromItem's URL. In this case,
+    // we need to make sure we update fromItem's processIdentifier as we want future navigations to this BackForward item to happen in the
+    // new process.
+    if (navigation.fromItem() && navigation.lockBackForwardList() == WebCore::LockBackForwardList::Yes)
+        navigation.fromItem()->setLastProcessIdentifier(m_process->coreProcessIdentifier());
+
     m_page.loadRequestWithNavigationShared(m_process.copyRef(), navigation, WTFMove(request), shouldOpenExternalURLsPolicy, userData, WebCore::ShouldTreatAsContinuingLoad::Yes, WTFMove(websitePolicies));
 }
 
index da13f2b..174531a 100644 (file)
@@ -3834,6 +3834,7 @@ void WebPageProxy::didStartProvisionalLoadForFrameShared(Ref<WebProcessProxy>&&
     m_pageLoadState.clearPendingAPIRequestURL(transaction);
 
     if (frame->isMainFrame()) {
+        process->didStartProvisionalLoadForMainFrame(url);
         reportPageLoadResult(ResourceError { ResourceError::Type::Cancellation });
         m_pageLoadStart = MonotonicTime::now();
         m_pageLoadState.didStartProvisionalLoad(transaction, url, unreachableURL);
diff --git a/Source/WebKit/UIProcess/WebProcessCache.cpp b/Source/WebKit/UIProcess/WebProcessCache.cpp
new file mode 100644 (file)
index 0000000..756cb53
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "WebProcessCache.h"
+
+#include "Logging.h"
+#include "WebProcessPool.h"
+#include "WebProcessProxy.h"
+#include <wtf/RAMSize.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebKit {
+
+static Seconds cachedProcessLifetime { 30_min };
+static Seconds clearingDelayAfterApplicationResignsActive { 5_min };
+
+WebProcessCache::WebProcessCache(WebProcessPool& processPool)
+    : m_evictionTimer(RunLoop::main(), this, &WebProcessCache::clear)
+{
+    updateCapacity(processPool);
+}
+
+bool WebProcessCache::addProcess(const String& registrableDomain, Ref<WebProcessProxy>&& process)
+{
+    ASSERT(!registrableDomain.isEmpty());
+    ASSERT(!process->pageCount());
+    ASSERT(!process->provisionalPageCount());
+    ASSERT(!process->processPool().hasSuspendedPageFor(process));
+
+    if (!capacity())
+        return false;
+
+    if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
+        RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::addProcess(): Not caching process %i because we are under memory pressure", this, process->processIdentifier());
+        return false;
+    }
+
+    while (m_processesPerRegistrableDomain.size() >= capacity()) {
+        auto it = m_processesPerRegistrableDomain.random();
+        RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::addProcess(): Evicting process %i from WebProcess cache", this, it->value->process().processIdentifier());
+        m_processesPerRegistrableDomain.remove(it);
+    }
+
+    auto addResult = m_processesPerRegistrableDomain.ensure(registrableDomain, [process = process.copyRef()]() mutable {
+        return std::make_unique<CachedProcess>(WTFMove(process));
+    });
+    if (!addResult.isNewEntry)
+        return false;
+
+    RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::addProcess: Adding process %i to WebProcess cache, cache size: [%u / %u]", this, process->processIdentifier(), size(), capacity());
+    return true;
+}
+
+RefPtr<WebProcessProxy> WebProcessCache::takeProcess(const String& registrableDomain, WebsiteDataStore& dataStore)
+{
+    auto it = m_processesPerRegistrableDomain.find(registrableDomain);
+    if (it == m_processesPerRegistrableDomain.end())
+        return nullptr;
+
+    if (&it->value->process().websiteDataStore() != &dataStore)
+        return nullptr;
+
+    auto process = it->value->takeProcess();
+    m_processesPerRegistrableDomain.remove(it);
+    RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::takeProcess: Taking process %i from WebProcess cache, cache size: [%u / %u]", this, process->processIdentifier(), size(), capacity());
+
+    ASSERT(!process->pageCount());
+    ASSERT(!process->provisionalPageCount());
+    ASSERT(!process->processPool().hasSuspendedPageFor(process));
+
+    return WTFMove(process);
+}
+
+void WebProcessCache::updateCapacity(WebProcessPool& processPool)
+{
+    if (!processPool.configuration().processSwapsOnNavigation() || !processPool.configuration().usesWebProcessCache()) {
+        if (!processPool.configuration().processSwapsOnNavigation())
+            RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::updateCapacity: Cache is disabled because process swap on navigation is disabled", this);
+        else
+            RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::updateCapacity: Cache is disabled by client", this);
+        m_capacity = 0;
+    } else {
+        size_t memorySize = ramSize() / GB;
+
+        // Allow 4 processes in the cache per GB of RAM, up to 30 processes.
+        m_capacity = std::min<unsigned>(memorySize * 4, 30);
+        RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::updateCapacity: Cache has a capacity of %u processes", this, capacity());
+    }
+
+    if (!m_capacity)
+        clear();
+}
+
+void WebProcessCache::clear()
+{
+    if (m_processesPerRegistrableDomain.isEmpty())
+        return;
+
+    RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::clear() evicting %u processes", this, m_processesPerRegistrableDomain.size());
+    m_processesPerRegistrableDomain.clear();
+}
+
+void WebProcessCache::setApplicationIsActive(bool isActive)
+{
+    RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::setApplicationIsActive(%d)", this, isActive);
+    if (isActive)
+        m_evictionTimer.stop();
+    else if (!m_processesPerRegistrableDomain.isEmpty())
+        m_evictionTimer.startOneShot(clearingDelayAfterApplicationResignsActive);
+}
+
+void WebProcessCache::evictProcess(WebProcessProxy& process)
+{
+    auto it = m_processesPerRegistrableDomain.find(process.registrableDomain());
+    ASSERT(it != m_processesPerRegistrableDomain.end());
+    ASSERT(&it->value->process() == &process);
+
+    RELEASE_LOG(ProcessSwapping, "%p - WebProcessCache::evictProcess(): Evicting process %i from WebProcess cache because it expired", this, process.processIdentifier());
+
+    m_processesPerRegistrableDomain.remove(it);
+}
+
+WebProcessCache::CachedProcess::CachedProcess(Ref<WebProcessProxy>&& process)
+    : m_process(WTFMove(process))
+    , m_evictionTimer(RunLoop::main(), this, &CachedProcess::evictionTimerFired)
+{
+    m_process->setIsInProcessCache(true);
+    m_evictionTimer.startOneShot(cachedProcessLifetime);
+}
+
+WebProcessCache::CachedProcess::~CachedProcess()
+{
+    if (!m_process)
+        return;
+
+    ASSERT(!m_process->pageCount());
+    ASSERT(!m_process->provisionalPageCount());
+    ASSERT(!m_process->processPool().hasSuspendedPageFor(*m_process));
+
+    m_process->setIsInProcessCache(false);
+    m_process->shutDown();
+}
+
+Ref<WebProcessProxy> WebProcessCache::CachedProcess::takeProcess()
+{
+    ASSERT(m_process);
+    m_evictionTimer.stop();
+    m_process->setIsInProcessCache(false);
+    return m_process.releaseNonNull();
+}
+
+void WebProcessCache::CachedProcess::evictionTimerFired()
+{
+    ASSERT(m_process);
+    m_process->processPool().webProcessCache().evictProcess(*m_process);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebProcessCache.h b/Source/WebKit/UIProcess/WebProcessCache.h
new file mode 100644 (file)
index 0000000..fdf99aa
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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 <wtf/HashMap.h>
+#include <wtf/RunLoop.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+
+class WebProcessPool;
+class WebProcessProxy;
+class WebsiteDataStore;
+
+class WebProcessCache {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit WebProcessCache(WebProcessPool&);
+
+    bool addProcess(const String& registrableDomain, Ref<WebProcessProxy>&&);
+    RefPtr<WebProcessProxy> takeProcess(const String& registrableDomain, WebsiteDataStore&);
+
+    void updateCapacity(WebProcessPool&);
+    unsigned capacity() { return m_capacity; }
+
+    unsigned size() const { return m_processesPerRegistrableDomain.size(); }
+
+    void clear();
+    void setApplicationIsActive(bool);
+
+private:
+    void evictProcess(WebProcessProxy&);
+
+    unsigned m_capacity { 0 };
+
+    class CachedProcess {
+        WTF_MAKE_FAST_ALLOCATED;
+    public:
+        CachedProcess(Ref<WebProcessProxy>&&);
+        ~CachedProcess();
+
+        Ref<WebProcessProxy> takeProcess();
+        WebProcessProxy& process() { ASSERT(m_process); return *m_process; }
+
+    private:
+        void evictionTimerFired();
+
+        RefPtr<WebProcessProxy> m_process;
+        RunLoop::Timer<CachedProcess> m_evictionTimer;
+    };
+
+    HashMap<String, std::unique_ptr<CachedProcess>> m_processesPerRegistrableDomain;
+    RunLoop::Timer<WebProcessCache> m_evictionTimer;
+};
+
+} // namespace WebKit
index c9de7fb..7e8788a 100644 (file)
@@ -69,6 +69,7 @@
 #include "WebPageGroup.h"
 #include "WebPreferences.h"
 #include "WebPreferencesKeys.h"
+#include "WebProcessCache.h"
 #include "WebProcessCreationParameters.h"
 #include "WebProcessMessages.h"
 #include "WebProcessPoolMessages.h"
@@ -255,6 +256,7 @@ WebProcessPool::WebProcessPool(API::ProcessPoolConfiguration& configuration)
     , m_foregroundWebProcessCounter([this](RefCounterEvent) { updateProcessAssertions(); })
     , m_backgroundWebProcessCounter([this](RefCounterEvent) { updateProcessAssertions(); })
 #endif
+    , m_webProcessCache(makeUniqueRef<WebProcessCache>(*this))
 {
     static std::once_flag onceFlag;
     std::call_once(onceFlag, [] {
@@ -313,6 +315,8 @@ WebProcessPool::WebProcessPool(API::ProcessPoolConfiguration& configuration)
 
 WebProcessPool::~WebProcessPool()
 {
+    m_webProcessCache->clear();
+
     bool removed = processPools().removeFirst(this);
     ASSERT_UNUSED(removed, removed);
 
@@ -455,6 +459,11 @@ void WebProcessPool::textCheckerStateChanged()
     sendToAllProcesses(Messages::WebProcess::SetTextCheckerState(TextChecker::state()));
 }
 
+void WebProcessPool::setApplicationIsActive(bool isActive)
+{
+    m_webProcessCache->setApplicationIsActive(isActive);
+}
+
 void WebProcessPool::screenPropertiesStateChanged()
 {
 #if PLATFORM(MAC)
@@ -1154,7 +1163,11 @@ Ref<WebPageProxy> WebProcessPool::createWebPage(PageClient& pageClient, Ref<API:
         enableProcessSwapOnCrossSiteNavigation = false;
 #endif
 
+    bool wasProcessSwappingOnNavigationEnabled = m_configuration->processSwapsOnNavigation();
     m_configuration->setProcessSwapsOnNavigationFromExperimentalFeatures(enableProcessSwapOnCrossSiteNavigation);
+    if (wasProcessSwappingOnNavigationEnabled != m_configuration->processSwapsOnNavigation())
+        m_webProcessCache->updateCapacity(*this);
+
     m_configuration->setShouldCaptureAudioInUIProcess(page->preferences().captureAudioInUIProcessEnabled());
     m_configuration->setShouldCaptureVideoInUIProcess(page->preferences().captureVideoInUIProcessEnabled());
 
@@ -1319,6 +1332,10 @@ WebProcessPool::Statistics& WebProcessPool::statistics()
 
 void WebProcessPool::handleMemoryPressureWarning(Critical)
 {
+    RELEASE_LOG(PerformanceLogging, "%p - WebProcessPool::handleMemoryPressureWarning", this);
+
+    m_webProcessCache->clear();
+
     if (m_prewarmedProcess)
         m_prewarmedProcess->shutDown();
     ASSERT(!m_prewarmedProcess);
@@ -2153,14 +2170,26 @@ void WebProcessPool::processForNavigation(WebPageProxy& page, const API::Navigat
 void WebProcessPool::processForNavigationInternal(WebPageProxy& page, const API::Navigation& navigation, ProcessSwapRequestedByClient processSwapRequestedByClient, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&& completionHandler)
 {
     auto& targetURL = navigation.currentRequest().url();
+    auto registrableDomain = toRegistrableDomain(targetURL);
+
+    auto createNewProcess = [this, protectedThis = makeRef(*this), page = makeRef(page), targetURL, registrableDomain] () -> Ref<WebProcessProxy> {
+        if (auto process = webProcessCache().takeProcess(registrableDomain, page->websiteDataStore()))
+            return process.releaseNonNull();
+
+        // Check if we have a suspended page for the given registrable domain and use its process if we do, for performance reasons.
+        if (auto process = findReusableSuspendedPageProcess(registrableDomain, page)) {
+            RELEASE_LOG(ProcessSwapping, "Using WebProcess %i from a SuspendedPage", process->processIdentifier());
+            return process.releaseNonNull();
+        }
 
-    auto createNewProcess = [&] () -> Ref<WebProcessProxy> {
-        if (RefPtr<WebProcessProxy> process = tryTakePrewarmedProcess(page.websiteDataStore())) {
+        if (auto process = tryTakePrewarmedProcess(page->websiteDataStore())) {
+            RELEASE_LOG(ProcessSwapping, "Using prewarmed process %i", process->processIdentifier());
             tryPrewarmWithDomainInformation(*process, targetURL);
             return process.releaseNonNull();
         }
 
-        return createNewWebProcess(page.websiteDataStore());
+        RELEASE_LOG(ProcessSwapping, "Launching a new process");
+        return createNewWebProcess(page->websiteDataStore());
     };
 
     if (usesSingleWebProcess())
@@ -2199,12 +2228,18 @@ void WebProcessPool::processForNavigationInternal(WebPageProxy& page, const API:
             });
         }
 
-        if (RefPtr<WebProcessProxy> process = WebProcessProxy::processForIdentifier(targetItem->itemID().processIdentifier)) {
+        if (RefPtr<WebProcessProxy> process = WebProcessProxy::processForIdentifier(targetItem->lastProcessIdentifier())) {
             // FIXME: Architecturally we do not currently support multiple WebPage's with the same ID in a given WebProcess.
             // In the case where this WebProcess has a SuspendedPageProxy for this WebPage, we can throw it away to support
             // WebProcess re-use.
             removeAllSuspendedPagesForPage(page, process.get());
 
+            // Make sure we remove the process from the cache if it is in there since we're about to use it.
+            if (process->isInProcessCache()) {
+                auto removedProcess = webProcessCache().takeProcess(process->registrableDomain(), process->websiteDataStore());
+                ASSERT_UNUSED(removedProcess, removedProcess.get() == process.get());
+            }
+
             return completionHandler(process.releaseNonNull(), nullptr, "Using target back/forward item's process"_s);
         }
     }
@@ -2228,7 +2263,6 @@ void WebProcessPool::processForNavigationInternal(WebPageProxy& page, const API:
 
     String reason = "Navigation is cross-site"_s;
     
-    auto registrableDomain = toRegistrableDomain(targetURL);
     if (m_configuration->alwaysKeepAndReuseSwappedProcesses()) {
         LOG(ProcessSwapping, "(ProcessSwapping) Considering re-use of a previously cached process for domain %s", registrableDomain.utf8().data());
 
@@ -2247,22 +2281,26 @@ void WebProcessPool::processForNavigationInternal(WebPageProxy& page, const API:
         }
     }
 
-    // Check if we have a suspended page for the given registrable domain and use its process if we do, for performance reasons.
+    return completionHandler(createNewProcess(), nullptr, reason);
+}
+
+RefPtr<WebProcessProxy> WebProcessPool::findReusableSuspendedPageProcess(const String& registrableDomain, WebPageProxy& page)
+{
     auto it = m_suspendedPages.findIf([&](auto& suspendedPage) {
-        return suspendedPage->registrableDomain() == registrableDomain;
+        return suspendedPage->registrableDomain() == registrableDomain && &suspendedPage->process().websiteDataStore() == &page.websiteDataStore();
     });
-    if (it != m_suspendedPages.end()) {
-        Ref<WebProcessProxy> process = (*it)->process();
+    if (it == m_suspendedPages.end())
+        return nullptr;
 
-        // FIXME: If the SuspendedPage is for this page, then we need to destroy the suspended page as we do not support having
-        // multiple WebPages with the same ID in a given WebProcess currently (https://bugs.webkit.org/show_bug.cgi?id=191166).
-        if (&(*it)->page() == &page)
-            m_suspendedPages.remove(it);
+    Ref<WebProcessProxy> process = (*it)->process();
 
-        return completionHandler(WTFMove(process), nullptr, reason);
-    }
+    // FIXME: If the SuspendedPage is for this page, then we need to destroy the suspended page as we do not support having
+    // multiple WebPages with the same ID in a given WebProcess currently (https://bugs.webkit.org/show_bug.cgi?id=191166).
+    if (&(*it)->page() == &page)
+        m_suspendedPages.remove(it);
 
-    return completionHandler(createNewProcess(), nullptr, reason);
+
+    return WTFMove(process);
 }
 
 void WebProcessPool::addSuspendedPage(std::unique_ptr<SuspendedPageProxy>&& suspendedPage)
index e574e1d..ebff9bf 100644 (file)
@@ -101,6 +101,7 @@ class WebAutomationSession;
 class WebContextSupplement;
 class WebPageGroup;
 class WebPageProxy;
+class WebProcessCache;
 struct NetworkProcessCreationParameters;
 struct StatisticsData;
 struct WebProcessCreationParameters;
@@ -176,6 +177,8 @@ public:
 
     void processDidFinishLaunching(WebProcessProxy*);
 
+    WebProcessCache& webProcessCache() { return m_webProcessCache.get(); }
+
     // Disconnect the process from the context.
     void disconnectProcess(WebProcessProxy*);
 
@@ -464,6 +467,7 @@ public:
     void removeSuspendedPage(SuspendedPageProxy&);
     bool hasSuspendedPageFor(WebProcessProxy&, WebPageProxy* = nullptr) const;
     unsigned maxSuspendedPageCount() const { return m_maxSuspendedPageCount; }
+    RefPtr<WebProcessProxy> findReusableSuspendedPageProcess(const String&, WebPageProxy&);
 
     void didReachGoodTimeToPrewarm();
 
@@ -548,6 +552,8 @@ private:
     void unregisterNotificationObservers();
 #endif
 
+    void setApplicationIsActive(bool);
+
     void addPlugInAutoStartOriginHash(const String& pageOrigin, unsigned plugInOriginHash, PAL::SessionID);
     void plugInDidReceiveUserInteraction(unsigned plugInOriginHash, PAL::SessionID);
 
@@ -649,6 +655,8 @@ private:
 #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
     RetainPtr<NSObject> m_scrollerStyleNotificationObserver;
 #endif
+    RetainPtr<NSObject> m_activationObserver;
+    RetainPtr<NSObject> m_deactivationObserver;
 
     std::unique_ptr<HighPerformanceGraphicsUsageSampler> m_highPerformanceGraphicsUsageSampler;
     std::unique_ptr<PerActivityStateCPUUsageSampler> m_perActivityStateCPUUsageSampler;
@@ -739,6 +747,7 @@ private:
     Deque<std::unique_ptr<SuspendedPageProxy>> m_suspendedPages;
     unsigned m_maxSuspendedPageCount { 0 };
 
+    UniqueRef<WebProcessCache> m_webProcessCache;
     HashMap<String, RefPtr<WebProcessProxy>> m_swappedProcessesPerRegistrableDomain;
 
     HashMap<String, std::unique_ptr<WebCore::PrewarmInformation>> m_prewarmInformationPerRegistrableDomain;
index e686828..639b0b2 100644 (file)
@@ -46,6 +46,7 @@
 #include "WebPageGroup.h"
 #include "WebPageProxy.h"
 #include "WebPasteboardProxy.h"
+#include "WebProcessCache.h"
 #include "WebProcessMessages.h"
 #include "WebProcessPool.h"
 #include "WebProcessProxyMessages.h"
@@ -181,6 +182,23 @@ WebProcessProxy::~WebProcessProxy()
 #endif
 }
 
+void WebProcessProxy::setIsInProcessCache(bool value)
+{
+    ASSERT(m_isInProcessCache != value);
+    m_isInProcessCache = value;
+
+    send(Messages::WebProcess::SetIsInProcessCache(m_isInProcessCache), 0);
+
+    if (m_isInProcessCache) {
+        // WebProcessProxy objects normally keep the process pool alive but we do not want this to be the case
+        // for cached processes or it would leak the pool.
+        m_processPool.setIsWeak(IsWeak::Yes);
+    } else {
+        RELEASE_ASSERT(m_processPool);
+        m_processPool.setIsWeak(IsWeak::No);
+    }
+}
+
 void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
 {
     launchOptions.processType = ProcessLauncher::ProcessType::Web;
@@ -333,6 +351,7 @@ void WebProcessProxy::addExistingWebPage(WebPageProxy& webPage, uint64_t pageID,
 {
     ASSERT(!m_pageMap.contains(pageID));
     ASSERT(!globalPageMap().contains(pageID));
+    ASSERT(!m_isInProcessCache);
 
     if (beginsUsingDataStore == BeginsUsingDataStore::Yes)
         m_processPool->pageBeginUsingWebsiteDataStore(webPage);
@@ -480,10 +499,36 @@ bool WebProcessProxy::fullKeyboardAccessEnabled()
 }
 #endif
 
+bool WebProcessProxy::hasProvisionalPageWithID(uint64_t pageID) const
+{
+    for (auto* provisionalPage : m_provisionalPages) {
+        if (provisionalPage->page().pageID() == pageID)
+            return true;
+    }
+    return false;
+}
+
+bool WebProcessProxy::isAllowedToUpdateBackForwardItem(WebBackForwardListItem& item) const
+{
+    if (m_pageMap.contains(item.pageID()))
+        return true;
+
+    if (hasProvisionalPageWithID(item.pageID()))
+        return true;
+
+    if (item.suspendedPage() && item.suspendedPage()->page().pageID() == item.pageID() && &item.suspendedPage()->process() == this)
+        return true;
+
+    return false;
+}
+
 void WebProcessProxy::updateBackForwardItem(const BackForwardListItemState& itemState)
 {
-    if (auto* item = WebBackForwardListItem::itemForID(itemState.identifier))
-        item->setPageState(itemState.pageState);
+    auto* item = WebBackForwardListItem::itemForID(itemState.identifier);
+    if (!item || !isAllowedToUpdateBackForwardItem(*item))
+        return;
+
+    item->setPageState(itemState.pageState);
 }
 
 #if ENABLE(NETSCAPE_PLUGIN_API)
@@ -590,6 +635,11 @@ void WebProcessProxy::processDidTerminateOrFailedToLaunch()
     auto pages = copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values());
     auto provisionalPages = WTF::map(m_provisionalPages, [](auto* provisionalPage) { return makeWeakPtr(provisionalPage); });
 
+    if (m_isInProcessCache) {
+        auto removedProcess = processPool().webProcessCache().takeProcess(registrableDomain(), websiteDataStore());
+        ASSERT_UNUSED(removedProcess, removedProcess.get() == this);
+    }
+
     shutDown();
 
 #if ENABLE(PUBLIC_SUFFIX_LIST)
@@ -769,17 +819,34 @@ void WebProcessProxy::didDestroyUserGestureToken(uint64_t identifier)
     m_userInitiatedActionMap.remove(identifier);
 }
 
+bool WebProcessProxy::canBeAddedToWebProcessCache() const
+{
+    if (registrableDomain().isEmpty())
+        return false;
+
+    if (isServiceWorkerProcess())
+        return false;
+
+    if (WebKit::isInspectorProcessPool(processPool()))
+        return false;
+
+    return true;
+}
+
 void WebProcessProxy::maybeShutDown()
 {
     if (state() == State::Terminated || !canTerminateAuxiliaryProcess())
         return;
 
+    if (canBeAddedToWebProcessCache() && processPool().webProcessCache().addProcess(registrableDomain(), *this))
+        return;
+
     shutDown();
 }
 
 bool WebProcessProxy::canTerminateAuxiliaryProcess()
 {
-    if (!m_pageMap.isEmpty() || m_processPool->hasSuspendedPageFor(*this) || !m_provisionalPages.isEmpty())
+    if (!m_pageMap.isEmpty() || m_processPool->hasSuspendedPageFor(*this) || !m_provisionalPages.isEmpty() || m_isInProcessCache)
         return false;
 
     if (!m_processPool->shouldTerminate(this))
@@ -1344,6 +1411,23 @@ void WebProcessProxy::activePagesDomainsForTesting(CompletionHandler<void(Vector
     connection()->sendWithAsyncReply(Messages::WebProcess::GetActivePagesOriginsForTesting(), WTFMove(completionHandler));
 }
 
+void WebProcessProxy::didStartProvisionalLoadForMainFrame(const URL& url)
+{
+    // This process has been used for several registrable domains already.
+    if (m_registrableDomain && m_registrableDomain->isNull())
+        return;
+
+    auto registrableDomain = toRegistrableDomain(url);
+    if (m_registrableDomain && *m_registrableDomain != registrableDomain) {
+        // Null out registrable domain since this process has now been used for several domains.
+        m_registrableDomain = String();
+        return;
+    }
+
+    // Associate the process with this registrable domain.
+    m_registrableDomain = WTFMove(registrableDomain);
+}
+
 #if PLATFORM(WATCHOS)
 
 void WebProcessProxy::takeBackgroundActivityTokenForFullscreenInput()
index ea80979..376f3d5 100644 (file)
@@ -108,6 +108,10 @@ public:
 
     WebProcessPool& processPool() const { ASSERT(m_processPool); return *m_processPool.get(); }
 
+    String registrableDomain() const { return m_registrableDomain.valueOr(String()); }
+    void setIsInProcessCache(bool);
+    bool isInProcessCache() const { return m_isInProcessCache; }
+
     // FIXME: WebsiteDataStores should be made per-WebPageProxy throughout WebKit2
     WebsiteDataStore& websiteDataStore() const { return m_websiteDataStore.get(); }
 
@@ -126,6 +130,7 @@ public:
 
     typename WebPageProxyMap::ValuesConstIteratorRange pages() const { return m_pageMap.values(); }
     unsigned pageCount() const { return m_pageMap.size(); }
+    unsigned provisionalPageCount() const { return m_provisionalPages.size(); }
     unsigned visiblePageCount() const { return m_visiblePageCounter.value(); }
 
     void activePagesDomainsForTesting(CompletionHandler<void(Vector<String>&&)>&&); // This is what is reported to ActivityMonitor.
@@ -249,6 +254,8 @@ public:
     void shutDown();
     void maybeShutDown();
 
+    void didStartProvisionalLoadForMainFrame(const URL&);
+
 protected:
     static uint64_t generatePageID();
     WebProcessProxy(WebProcessPool&, WebsiteDataStore&, IsPrewarmed);
@@ -274,6 +281,7 @@ private:
     void didDestroyFrame(uint64_t);
     void didDestroyUserGestureToken(uint64_t);
 
+    bool canBeAddedToWebProcessCache() const;
     void shouldTerminate(bool& shouldTerminate);
 
     void createNewMessagePortChannel(const WebCore::MessagePortIdentifier& port1, const WebCore::MessagePortIdentifier& port2);
@@ -286,6 +294,9 @@ private:
     void didDeliverMessagePortMessages(uint64_t messageBatchIdentifier);
     void didCheckProcessLocalPortForActivity(uint64_t callbackIdentifier, bool isLocallyReachable);
 
+    bool hasProvisionalPageWithID(uint64_t pageID) const;
+    bool isAllowedToUpdateBackForwardItem(WebBackForwardListItem&) const;
+
     // Plugins
 #if ENABLE(NETSCAPE_PLUGIN_API)
     void getPlugins(bool refresh, Vector<WebCore::PluginInfo>& plugins, Vector<WebCore::PluginInfo>& applicationPlugins, Optional<Vector<WebCore::SupportedPluginIdentifier>>&);
@@ -371,7 +382,7 @@ private:
     BackgroundProcessResponsivenessTimer m_backgroundResponsivenessTimer;
     
     RefPtr<WebConnectionToWebProcess> m_webConnection;
-    WeakOrStrongPtr<WebProcessPool> m_processPool; // Pre-warmed processes do not hold a strong reference to their pool.
+    WeakOrStrongPtr<WebProcessPool> m_processPool; // Pre-warmed and cached processes do not hold a strong reference to their pool.
 
     bool m_mayHaveUniversalFileReadSandboxExtension; // True if a read extension for "/" was ever granted - we don't track whether WebProcess still has it.
     HashSet<String> m_localPathsWithAssumedReadAccess;
@@ -394,6 +405,9 @@ private:
 
     HashMap<String, uint64_t> m_pageURLRetainCountMap;
 
+    Optional<String> m_registrableDomain;
+    bool m_isInProcessCache { false };
+
     enum class NoOrMaybe { No, Maybe } m_isResponsive;
     Vector<WTF::Function<void(bool webProcessIsResponsive)>> m_isResponsiveCallbacks;
 
index 821a06a..82bb5c7 100644 (file)
                832AE2511BE2E8CD00FAAE10 /* NetworkCacheSpeculativeLoadManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCacheSpeculativeLoadManager.cpp; sourceTree = "<group>"; };
                832ED1891E2FE13B006BA64A /* PerActivityStateCPUUsageSampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PerActivityStateCPUUsageSampler.cpp; sourceTree = "<group>"; };
                832ED18A1E2FE13B006BA64A /* PerActivityStateCPUUsageSampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PerActivityStateCPUUsageSampler.h; sourceTree = "<group>"; };
+               83397C6622124BD100B62388 /* WebProcessCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebProcessCache.cpp; sourceTree = "<group>"; };
+               83397C6722124BD100B62388 /* WebProcessCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebProcessCache.h; sourceTree = "<group>"; };
                834B250E1A831A8D00CFB150 /* NetworkCacheFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheFileSystem.h; sourceTree = "<group>"; };
                834B25101A842C8700CFB150 /* NetworkCacheStatistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkCacheStatistics.h; sourceTree = "<group>"; };
                8360349D1ACB34D600626549 /* WebSQLiteDatabaseTracker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSQLiteDatabaseTracker.cpp; sourceTree = "<group>"; };
                                BC574E611267D080006F0F12 /* WebPopupMenuProxy.h */,
                                BCD597FE112B57BE00EC8C23 /* WebPreferences.cpp */,
                                BCD597FD112B57BE00EC8C23 /* WebPreferences.h */,
+                               83397C6622124BD100B62388 /* WebProcessCache.cpp */,
+                               83397C6722124BD100B62388 /* WebProcessCache.h */,
                                1AFA4B8D1A65A9E2006C4AB4 /* WebProcessLifetimeObserver.cpp */,
                                1AFA4B8E1A65A9E2006C4AB4 /* WebProcessLifetimeObserver.h */,
                                1AFA4B891A65A1D0006C4AB4 /* WebProcessLifetimeTracker.cpp */,
index 2822050..99e9afa 100644 (file)
@@ -285,6 +285,20 @@ void WebProcess::initializeWebProcess(WebProcessCreationParameters&& parameters)
     if (!m_suppressMemoryPressureHandler) {
         auto& memoryPressureHandler = MemoryPressureHandler::singleton();
         memoryPressureHandler.setLowMemoryHandler([this] (Critical critical, Synchronous synchronous) {
+#if PLATFORM(MAC)
+            // If this is a process we keep around for performance, kill it on memory pressure instead of trying to free up its memory.
+            if (m_processType == ProcessType::CachedWebContent || m_processType == ProcessType::PrewarmedWebContent || areAllPagesSuspended()) {
+                if (m_processType == ProcessType::CachedWebContent)
+                    RELEASE_LOG(Process, "Cached WebProcess %i is exiting due to memory pressure", getpid());
+                else if (m_processType == ProcessType::PrewarmedWebContent)
+                    RELEASE_LOG(Process, "Prewarmed WebProcess %i is exiting due to memory pressure", getpid());
+                else
+                    RELEASE_LOG(Process, "Suspended WebProcess %i is exiting due to memory pressure", getpid());
+                stopRunLoop();
+                return;
+            }
+#endif
+
             auto maintainPageCache = m_isSuspending && hasPageRequiringPageCacheWhileSuspended() ? WebCore::MaintainPageCache::Yes : WebCore::MaintainPageCache::No;
             WebCore::releaseMemory(critical, synchronous, maintainPageCache);
         });
@@ -457,6 +471,32 @@ bool WebProcess::hasPageRequiringPageCacheWhileSuspended() const
     return false;
 }
 
+bool WebProcess::areAllPagesSuspended() const
+{
+    for (auto& page : m_pageMap.values()) {
+        if (!page->isSuspended())
+            return false;
+    }
+    return true;
+}
+
+void WebProcess::setIsInProcessCache(bool isInProcessCache)
+{
+#if PLATFORM(MAC)
+    if (isInProcessCache) {
+        ASSERT(m_processType == ProcessType::WebContent);
+        m_processType = ProcessType::CachedWebContent;
+    } else {
+        ASSERT(m_processType == ProcessType::CachedWebContent);
+        m_processType = ProcessType::WebContent;
+    }
+
+    updateProcessName();
+#else
+    UNUSED_PARAM(isInProcessCache);
+#endif
+}
+
 void WebProcess::markIsNoLongerPrewarmed()
 {
 #if PLATFORM(MAC)
index b9ca2ee..49c4ac1 100644 (file)
@@ -267,6 +267,7 @@ private:
 
     void platformTerminate();
 
+    void setIsInProcessCache(bool);
     void markIsNoLongerPrewarmed();
 
     void registerURLSchemeAsEmptyDocument(const String&);
@@ -344,6 +345,7 @@ private:
     void actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend);
 
     bool hasPageRequiringPageCacheWhileSuspended() const;
+    bool areAllPagesSuspended() const;
 
     void ensureAutomationSessionProxy(const String& sessionIdentifier);
     void destroyAutomationSessionProxy();
@@ -465,7 +467,7 @@ private:
     std::unique_ptr<WebCore::CPUMonitor> m_cpuMonitor;
     Optional<double> m_cpuLimit;
 
-    enum class ProcessType { Inspector, ServiceWorker, PrewarmedWebContent, WebContent };
+    enum class ProcessType { Inspector, ServiceWorker, PrewarmedWebContent, CachedWebContent, WebContent };
     ProcessType m_processType { ProcessType::WebContent };
     String m_uiProcessName;
     String m_securityOrigin;
index 6f6ca36..3d73f2e 100644 (file)
@@ -119,6 +119,7 @@ messages -> WebProcess LegacyReceiver {
     CheckProcessLocalPortForActivity(struct WebCore::MessagePortIdentifier port, uint64_t callbackIdentifier)
     MessagesAvailableForPort(struct WebCore::MessagePortIdentifier port)
 
+    SetIsInProcessCache(bool isInProcessCache)
     MarkIsNoLongerPrewarmed()
     UpdateActivePages()
     GetActivePagesOriginsForTesting() -> (Vector<String> activeOrigins) Async
index e77f715..d162516 100644 (file)
@@ -240,6 +240,9 @@ void WebProcess::updateProcessName()
     case ProcessType::PrewarmedWebContent:
         applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ Web Content (Prewarmed)", "Visible name of the web process. The argument is the application name."), (NSString *)m_uiProcessName];
         break;
+    case ProcessType::CachedWebContent:
+        applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ Web Content (Cached)", "Visible name of the web process. The argument is the application name."), (NSString *)m_uiProcessName];
+        break;
     case ProcessType::WebContent:
         applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ Web Content", "Visible name of the web process. The argument is the application name."), (NSString *)m_uiProcessName];
         break;
index 065c83a..d9750ee 100644 (file)
@@ -1,3 +1,15 @@
+2019-02-14  Chris Dumez  <cdumez@apple.com>
+
+        [PSON] Introduce a WebContent Process cache
+        https://bugs.webkit.org/show_bug.cgi?id=194594
+        <rdar://problem/46793397>
+
+        Reviewed by Geoff Garen.
+
+        Update API tests to turn on the WebContent Process cache.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
 2019-02-14  Jiewen Tan  <jiewen_tan@apple.com>
 
         Unreviewed, build fix after r241480
index 22e1cd5..c277850 100644 (file)
@@ -432,11 +432,18 @@ window.addEventListener('pageshow', function(event) {
 
 #endif // PLATFORM(MAC)
 
-TEST(ProcessSwap, Basic)
+static RetainPtr<_WKProcessPoolConfiguration> psonProcessPoolConfiguration()
 {
     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
     processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    processPoolConfiguration.get().usesWebProcessCache = YES;
     processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
+    return processPoolConfiguration;
+}
+
+TEST(ProcessSwap, Basic)
+{
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -481,9 +488,7 @@ TEST(ProcessSwap, Basic)
 
 TEST(ProcessSwap, LoadAfterPolicyDecision)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
-    processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -519,9 +524,7 @@ TEST(ProcessSwap, LoadAfterPolicyDecision)
 
 TEST(ProcessSwap, KillWebContentProcessAfterServerRedirectPolicyDecision)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
-    processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -570,9 +573,7 @@ TEST(ProcessSwap, KillWebContentProcessAfterServerRedirectPolicyDecision)
 
 TEST(ProcessSwap, NoSwappingForeTLDPlus2)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
-    processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -607,8 +608,7 @@ TEST(ProcessSwap, NoSwappingForeTLDPlus2)
 
 TEST(ProcessSwap, Back)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -715,8 +715,7 @@ static const char* pageWithFragmentTestBytes = R"PSONRESOURCE(
 
 TEST(ProcessSwap, HistoryNavigationToFragmentURL)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -768,8 +767,7 @@ TEST(ProcessSwap, HistoryNavigationToFragmentURL)
 
 TEST(ProcessSwap, SuspendedPageDiesAfterBackForwardListItemIsGone)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -801,7 +799,7 @@ TEST(ProcessSwap, SuspendedPageDiesAfterBackForwardListItemIsGone)
     EXPECT_NE(webkitPID, applePID);
 
     // webkit.org + apple.com processes.
-    EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
 
     [webView goBack]; // Back to webkit.org.
     TestWebKitAPI::Util::run(&done);
@@ -810,7 +808,7 @@ TEST(ProcessSwap, SuspendedPageDiesAfterBackForwardListItemIsGone)
     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
 
     // webkit.org + apple.com processes.
-    EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
 
     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
     [webView loadRequest:request];
@@ -821,15 +819,14 @@ TEST(ProcessSwap, SuspendedPageDiesAfterBackForwardListItemIsGone)
     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
 
     // apple.com is not longer present in the back/forward list and there should therefore be no-suspended page for it.
-    while ([processPool _webProcessCountIgnoringPrewarmed] > 1u)
+    while ([processPool _webProcessCountIgnoringPrewarmedAndCached] > 1u)
         TestWebKitAPI::Util::spinRunLoop();
 }
 
 #if PLATFORM(MAC)
 TEST(ProcessSwap, SuspendedPagesInActivityMonitor)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -917,8 +914,7 @@ TEST(ProcessSwap, SuspendedPagesInActivityMonitor)
 
 TEST(ProcessSwap, BackWithoutSuspendedPage)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -975,8 +971,7 @@ TEST(ProcessSwap, BackWithoutSuspendedPage)
 
 TEST(ProcessSwap, BackNavigationAfterSessionRestore)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1032,8 +1027,7 @@ TEST(ProcessSwap, BackNavigationAfterSessionRestore)
 
 TEST(ProcessSwap, CrossSiteWindowOpenNoOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1072,8 +1066,7 @@ TEST(ProcessSwap, CrossSiteWindowOpenNoOpener)
 
 TEST(ProcessSwap, CrossOriginButSameSiteWindowOpenNoOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1112,8 +1105,7 @@ TEST(ProcessSwap, CrossOriginButSameSiteWindowOpenNoOpener)
 
 TEST(ProcessSwap, CrossSiteWindowOpenWithOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     processPoolConfiguration.get().processSwapsOnWindowOpenWithOpener = YES;
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
@@ -1153,8 +1145,7 @@ TEST(ProcessSwap, CrossSiteWindowOpenWithOpener)
 
 TEST(ProcessSwap, SameSiteWindowOpenNoOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1192,8 +1183,7 @@ TEST(ProcessSwap, SameSiteWindowOpenNoOpener)
 
 TEST(ProcessSwap, CrossSiteBlankTargetWithOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1232,8 +1222,7 @@ TEST(ProcessSwap, CrossSiteBlankTargetWithOpener)
 
 TEST(ProcessSwap, CrossSiteBlankTargetImplicitNoOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1272,8 +1261,7 @@ TEST(ProcessSwap, CrossSiteBlankTargetImplicitNoOpener)
 
 TEST(ProcessSwap, CrossSiteBlankTargetNoOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1312,8 +1300,7 @@ TEST(ProcessSwap, CrossSiteBlankTargetNoOpener)
 
 TEST(ProcessSwap, SameSiteBlankTargetNoOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1354,8 +1341,7 @@ TEST(ProcessSwap, SameSiteBlankTargetNoOpener)
 
 TEST(ProcessSwap, ServerRedirectFromNewWebView)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1388,8 +1374,7 @@ TEST(ProcessSwap, ServerRedirectFromNewWebView)
 
 TEST(ProcessSwap, ServerRedirect)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1435,8 +1420,7 @@ TEST(ProcessSwap, ServerRedirect)
 TEST(ProcessSwap, ServerRedirect2)
 {
     // This tests a load that *starts out* to the same origin as the previous load, but then redirects to a new origin.
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1493,8 +1477,7 @@ TEST(ProcessSwap, ServerRedirect2)
 
 TEST(ProcessSwap, TerminateProcessRightAfterSwap)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1533,8 +1516,7 @@ static const char* linkToWebKitBytes = R"PSONRESOURCE(
 
 TEST(ProcessSwap, PolicyCancelAfterServerRedirect)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1587,8 +1569,7 @@ TEST(ProcessSwap, PolicyCancelAfterServerRedirect)
 
 TEST(ProcessSwap, CrossSiteDownload)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1648,8 +1629,7 @@ static const char* systemPreviewCrossOriginTestBytes = R"PSONRESOURCE(
 
 TEST(ProcessSwap, SameOriginSystemPreview)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1685,8 +1665,7 @@ TEST(ProcessSwap, SameOriginSystemPreview)
 
 TEST(ProcessSwap, CrossOriginSystemPreview)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1725,7 +1704,7 @@ TEST(ProcessSwap, CrossOriginSystemPreview)
 enum class ShouldEnablePSON { No, Yes };
 static void runClientSideRedirectTest(ShouldEnablePSON shouldEnablePSON)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO;
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
@@ -1860,9 +1839,7 @@ TEST(ProcessSwap, CrossSiteClientSideRedirectWithPSON)
 
 TEST(ProcessSwap, CrossSiteClientSideRedirectFromFileURL)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
-    processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1891,15 +1868,14 @@ TEST(ProcessSwap, CrossSiteClientSideRedirectFromFileURL)
     auto pid2 = [webView _webProcessIdentifier];
     EXPECT_NE(pid1, pid2);
 
-    EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
     EXPECT_TRUE(willPerformClientRedirect);
     EXPECT_TRUE(didPerformClientRedirect);
 }
 
 TEST(ProcessSwap, NavigateBackAfterClientSideRedirect)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -1973,7 +1949,7 @@ TEST(ProcessSwap, NavigateBackAfterClientSideRedirect)
 
 static void runNavigationWithLockedHistoryTest(ShouldEnablePSON shouldEnablePSON)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO;
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
@@ -2072,8 +2048,7 @@ window.onload = function(evt) {
 
 TEST(ProcessSwap, SessionStorage)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2129,8 +2104,7 @@ TEST(ProcessSwap, SessionStorage)
 
 TEST(ProcessSwap, ReuseSuspendedProcess)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2190,8 +2164,7 @@ var myWorker = new Worker('worker.js');
 
 TEST(ProcessSwap, ReuseSuspendedProcessEvenIfPageCacheFails)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2243,8 +2216,7 @@ TEST(ProcessSwap, ReuseSuspendedProcessEvenIfPageCacheFails)
 
 TEST(ProcessSwap, ReuseSuspendedProcessOnBackEvenIfPageCacheFails)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2292,8 +2264,7 @@ static const char* withSubframesTestBytes = R"PSONRESOURCE(
 
 TEST(ProcessSwap, HistoryItemIDConfusion)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2358,8 +2329,7 @@ TEST(ProcessSwap, HistoryItemIDConfusion)
 
 TEST(ProcessSwap, GoToSecondItemInBackHistory)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2445,11 +2415,9 @@ enum class RetainPageInBundle { No, Yes };
 
 void testReuseSuspendedProcessForRegularNavigation(RetainPageInBundle retainPageInBundle)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     if (retainPageInBundle == RetainPageInBundle::Yes)
         [processPoolConfiguration setInjectedBundleURL:[[NSBundle mainBundle] URLForResource:@"TestWebKitAPI" withExtension:@"wkbundle"]];
-
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
     if (retainPageInBundle == RetainPageInBundle::Yes)
         [processPool _setObject:@"BundleRetainPagePlugIn" forBundleParameter:TestWebKitAPI::Util::TestPlugInClassNameParameter];
@@ -2525,8 +2493,7 @@ static const char* mainFramesOnlySubframe2 = R"PSONRESOURCE(
 
 TEST(ProcessSwap, MainFramesOnly)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2571,8 +2538,7 @@ onload = () => {
 
 TEST(ProcessSwap, PageZoomLevelAfterSwap)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2648,9 +2614,7 @@ static const char* navigateBeforePageLoadEndBytes = R"PSONRESOURCE(
 
 TEST(ProcessSwap, NavigateCrossSiteBeforePageLoadEnd)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
-    [processPoolConfiguration setPrewarmsProcessesAutomatically:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2679,8 +2643,7 @@ TEST(ProcessSwap, NavigateCrossSiteBeforePageLoadEnd)
 
 TEST(ProcessSwap, DoSameSiteNavigationAfterCrossSiteProvisionalLoadStarted)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2721,8 +2684,7 @@ TEST(ProcessSwap, DoSameSiteNavigationAfterCrossSiteProvisionalLoadStarted)
 
 TEST(ProcessSwap, SuspendedPageLimit)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2771,13 +2733,12 @@ TEST(ProcessSwap, SuspendedPageLimit)
     EXPECT_EQ(5u, seenPIDs.size());
 
     // But not all of those processes should still be alive (1 visible, maximumSuspendedPageCount suspended).
-    EXPECT_EQ([processPool _webProcessCountIgnoringPrewarmed], (1U + maximumSuspendedPageCount));
+    EXPECT_EQ([processPool _webProcessCountIgnoringPrewarmedAndCached], (1U + maximumSuspendedPageCount));
 }
 
 TEST(ProcessSwap, PageCache1)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2802,7 +2763,7 @@ TEST(ProcessSwap, PageCache1)
 
     auto pidAfterLoad1 = [webView _webProcessIdentifier];
 
-    EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
 
     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
 
@@ -2812,7 +2773,7 @@ TEST(ProcessSwap, PageCache1)
 
     auto pidAfterLoad2 = [webView _webProcessIdentifier];
 
-    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
     EXPECT_NE(pidAfterLoad1, pidAfterLoad2);
 
     [webView goBack];
@@ -2823,7 +2784,7 @@ TEST(ProcessSwap, PageCache1)
 
     auto pidAfterLoad3 = [webView _webProcessIdentifier];
 
-    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
     EXPECT_EQ(pidAfterLoad1, pidAfterLoad3);
     EXPECT_EQ(1u, [receivedMessages count]);
     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]);
@@ -2837,7 +2798,7 @@ TEST(ProcessSwap, PageCache1)
 
     auto pidAfterLoad4 = [webView _webProcessIdentifier];
 
-    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
     EXPECT_EQ(pidAfterLoad2, pidAfterLoad4);
     EXPECT_EQ(2u, [receivedMessages count]);
     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]);
@@ -2846,9 +2807,7 @@ TEST(ProcessSwap, PageCache1)
 
 TEST(ProcessSwap, NumberOfPrewarmedProcesses)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
-    [processPoolConfiguration setPrewarmsProcessesAutomatically:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2866,7 +2825,7 @@ TEST(ProcessSwap, NumberOfPrewarmedProcesses)
     done = false;
 
     EXPECT_EQ(2u, [processPool _webProcessCount]);
-    EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
     EXPECT_TRUE([processPool _hasPrewarmedWebProcess]);
 
     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
@@ -2875,7 +2834,7 @@ TEST(ProcessSwap, NumberOfPrewarmedProcesses)
     done = false;
 
     EXPECT_EQ(3u, [processPool _webProcessCount]);
-    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
+    EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
     EXPECT_TRUE([processPool _hasPrewarmedWebProcess]);
 }
 
@@ -2897,8 +2856,7 @@ window.addEventListener('pagehide', function(event) {
 
 TEST(ProcessSwap, PageShowHide)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -2989,8 +2947,7 @@ window.addEventListener('load', function(event) {
 
 TEST(ProcessSwap, LoadUnload)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3066,8 +3023,7 @@ TEST(ProcessSwap, LoadUnload)
 
 TEST(ProcessSwap, WebInspector)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3129,8 +3085,7 @@ link.href = URL.createObjectURL(blob);
 
 TEST(ProcessSwap, SameOriginBlobNavigation)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3164,8 +3119,7 @@ TEST(ProcessSwap, SameOriginBlobNavigation)
 
 TEST(ProcessSwap, CrossOriginBlobNavigation)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3223,8 +3177,7 @@ TEST(ProcessSwap, CrossOriginBlobNavigation)
 
 TEST(ProcessSwap, NavigateToAboutBlank)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3257,8 +3210,7 @@ TEST(ProcessSwap, NavigateToAboutBlank)
 
 TEST(ProcessSwap, NavigateToDataURL)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3291,9 +3243,7 @@ TEST(ProcessSwap, NavigateToDataURL)
 
 TEST(ProcessSwap, ProcessReuse)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
-    [processPoolConfiguration setAlwaysKeepAndReuseSwappedProcesses:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3338,9 +3288,7 @@ TEST(ProcessSwap, ProcessReuse)
 
 TEST(ProcessSwap, ProcessReuseeTLDPlus2)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
-    [processPoolConfiguration setAlwaysKeepAndReuseSwappedProcesses:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3385,8 +3333,7 @@ TEST(ProcessSwap, ProcessReuseeTLDPlus2)
 
 TEST(ProcessSwap, ConcurrentHistoryNavigations)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3455,8 +3402,7 @@ TEST(ProcessSwap, ConcurrentHistoryNavigations)
 
 TEST(ProcessSwap, NavigateToInvalidURL)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3507,8 +3453,7 @@ onpageshow = function(event) {
 
 TEST(ProcessSwap, NavigateToDataURLThenBack)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     processPoolConfiguration.get().pageCacheEnabled = NO;
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
@@ -3543,8 +3488,7 @@ TEST(ProcessSwap, NavigateToDataURLThenBack)
 
 TEST(ProcessSwap, NavigateCrossSiteWithPageCacheDisabled)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     processPoolConfiguration.get().pageCacheEnabled = NO;
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
@@ -3634,8 +3578,7 @@ static const char* navigateBackFromJSBytes = R"PSONRESOURCE(
 
 TEST(ProcessSwap, NavigateToCrossSiteThenBackFromJS)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     processPoolConfiguration.get().pageCacheEnabled = NO;
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
@@ -3675,8 +3618,7 @@ TEST(ProcessSwap, NavigateToCrossSiteThenBackFromJS)
 
 TEST(ProcessSwap, ClosePageAfterCrossSiteProvisionalLoad)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3734,8 +3676,7 @@ static unsigned urlChangeCount;
 
 TEST(ProcessSwap, LoadingStateAfterPolicyDecision)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3940,9 +3881,7 @@ TEST(ProcessSwap, OpenerLinkAfterAPIControlledProcessSwappingOfOpenee)
 enum class ExpectSwap { No, Yes };
 static void runProcessSwapDueToRelatedWebViewTest(NSURL* relatedViewURL, NSURL* targetURL, ExpectSwap expectSwap)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
-    processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webView1Configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -3998,9 +3937,7 @@ TEST(ProcessSwap, NoProcessSwapDueToRelatedView)
 
 TEST(ProcessSwap, TerminatedSuspendedPageProcess)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
-    processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4063,8 +4000,7 @@ TEST(ProcessSwap, TerminatedSuspendedPageProcess)
 
 TEST(ProcessSwap, NavigateBackAndForth)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4115,8 +4051,7 @@ TEST(ProcessSwap, NavigateBackAndForth)
 
 TEST(ProcessSwap, SwapOnLoadHTMLString)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4159,9 +4094,7 @@ TEST(ProcessSwap, SwapOnLoadHTMLString)
 
 TEST(ProcessSwap, UsePrewarmedProcessAfterTerminatingNetworkProcess)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
-    processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto websiteDataStoreConfiguration = adoptNS([[_WKWebsiteDataStoreConfiguration alloc] init]);
@@ -4195,8 +4128,7 @@ TEST(ProcessSwap, UsePrewarmedProcessAfterTerminatingNetworkProcess)
 
 TEST(ProcessSwap, UseSessionCookiesAfterProcessSwapInPrivateBrowsing)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
     RetainPtr<WKWebsiteDataStore> ephemeralStore = [WKWebsiteDataStore nonPersistentDataStore];
 
@@ -4255,8 +4187,7 @@ TEST(ProcessSwap, UseSessionCookiesAfterProcessSwapInPrivateBrowsing)
 
 TEST(ProcessSwap, TerminateProcessAfterProcessSwap)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4309,8 +4240,7 @@ TEST(ProcessSwap, TerminateProcessAfterProcessSwap)
 
 TEST(ProcessSwap, NavigateCrossOriginWithOpenee)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4387,8 +4317,7 @@ function saveOpenee()
 
 TEST(ProcessSwap, NavigateCrossOriginWithOpener)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4516,8 +4445,7 @@ TEST(ProcessSwap, NavigateCrossOriginWithOpener)
 
 TEST(ProcessSwap, GoBackToSuspendedPageWithMainFrameIDThatIsNotOne)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4607,8 +4535,7 @@ body {
 
 TEST(ProcessSwap, ScrollPositionRestoration)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4687,8 +4614,7 @@ TEST(ProcessSwap, ContentBlockingAfterProcessSwap)
     TestWebKitAPI::Util::run(&done);
     done = false;
 
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -4810,10 +4736,7 @@ navigator.mediaDevices.getUserMedia({video: true});
 
 TEST(ProcessSwap, GetUserMediaCaptureState)
 {
-    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
-    processPoolConfiguration.get().processSwapsOnNavigation = YES;
-    processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
-
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);