Diff
Modified: trunk/Source/WebKit/ChangeLog (230976 => 230977)
--- trunk/Source/WebKit/ChangeLog 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/ChangeLog 2018-04-24 23:19:25 UTC (rev 230977)
@@ -1,3 +1,50 @@
+2018-04-24 Saam Barati <[email protected]>
+
+ Keep around a pre-warmed process when doing process swap on navigation
+ https://bugs.webkit.org/show_bug.cgi?id=184765
+ <rdar://problem/39685099>
+
+ Reviewed by Ryosuke Niwa and Brady Eidson.
+
+ This patch makes it so that WebProcessPool prewarms a process when process
+ swap on navigation is turned on. When we do a process swap on navigation,
+ we first try to grab a prewarmed process before creating a new one.
+
+ We try to be smart about when to create these processes. The initial heuristic
+ that this patch chooses is when we reach the DidFirstVisuallyNonEmptyLayout
+ layout milestone. We're going to try to improve on this heuristic in:
+ https://bugs.webkit.org/show_bug.cgi?id=184899
+
+ This is a 40% progression on PLT with process swap on navigation turned on.
+
+ * UIProcess/API/Cocoa/WKProcessPool.mm:
+ (-[WKProcessPool _prewarmedWebProcessCount]):
+ (-[WKProcessPool _webProcessCountIgnoringPrewarmed]):
+ * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+ * UIProcess/ServiceWorkerProcessProxy.cpp:
+ (WebKit::ServiceWorkerProcessProxy::ServiceWorkerProcessProxy):
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::notifyProcessPoolToPrewarm):
+ (WebKit::WebPageProxy::didFirstVisuallyNonEmptyLayoutForFrame):
+ * UIProcess/WebPageProxy.h:
+ * UIProcess/WebProcessPool.cpp:
+ (WebKit::WebProcessPool::createNewWebProcess):
+ (WebKit::WebProcessPool::tryTakePrewarmedProcess):
+ (WebKit::WebProcessPool::warmInitialProcess):
+ (WebKit::WebProcessPool::disconnectProcess):
+ (WebKit::WebProcessPool::createWebPage):
+ (WebKit::WebProcessPool::didReachGoodTimeToPrewarm):
+ (WebKit::WebProcessPool::processForNavigation):
+ * UIProcess/WebProcessPool.h:
+ * UIProcess/WebProcessProxy.cpp:
+ (WebKit::WebProcessProxy::create):
+ (WebKit::WebProcessProxy::WebProcessProxy):
+ (WebKit::m_isInPrewarmedPool):
+ (WebKit::m_userMediaCaptureManagerProxy): Deleted.
+ * UIProcess/WebProcessProxy.h:
+ (WebKit::WebProcessProxy::isInPrewarmedPool const):
+ (WebKit::WebProcessProxy::setIsInPrewarmedPool):
+
2018-04-24 Commit Queue <[email protected]>
Unreviewed, rolling out r230971.
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm 2018-04-24 23:19:25 UTC (rev 230977)
@@ -459,6 +459,21 @@
return _processPool->processes().size();
}
+- (size_t)_prewarmedWebProcessCount
+{
+ size_t result = 0;
+ for (auto& process : _processPool->processes()) {
+ if (process->isInPrewarmedPool())
+ ++result;
+ }
+ return result;
+}
+
+- (size_t)_webProcessCountIgnoringPrewarmed
+{
+ return [self _webProcessCount] - [self _prewarmedWebProcessCount];
+}
+
- (size_t)_webPageContentProcessCount
{
auto allWebProcesses = _processPool->processes();
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h 2018-04-24 23:19:25 UTC (rev 230977)
@@ -89,6 +89,8 @@
// Test only.
- (size_t)_webProcessCount WK_API_AVAILABLE(macosx(10.13), ios(11.0));
+- (size_t)_prewarmedWebProcessCount WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (size_t)_webProcessCountIgnoringPrewarmed 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(WK_MAC_TBA), ios(WK_IOS_TBA));
- (void)_syncNetworkProcessCookies WK_API_AVAILABLE(macosx(10.13), ios(11.0));
Modified: trunk/Source/WebKit/UIProcess/ServiceWorkerProcessProxy.cpp (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/ServiceWorkerProcessProxy.cpp 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/ServiceWorkerProcessProxy.cpp 2018-04-24 23:19:25 UTC (rev 230977)
@@ -50,7 +50,7 @@
}
ServiceWorkerProcessProxy::ServiceWorkerProcessProxy(WebProcessPool& pool, const SecurityOriginData& securityOrigin, WebsiteDataStore& store)
- : WebProcessProxy { pool, store }
+ : WebProcessProxy { pool, store, IsInPrewarmedPool::No }
, m_securityOrigin(securityOrigin)
, m_serviceWorkerPageID(generatePageID())
{
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2018-04-24 23:19:25 UTC (rev 230977)
@@ -506,6 +506,11 @@
return m_isValid;
}
+void WebPageProxy::notifyProcessPoolToPrewarm()
+{
+ m_process->processPool().didReachGoodTimeToPrewarm();
+}
+
void WebPageProxy::setPreferences(WebPreferences& preferences)
{
if (&preferences == m_preferences.ptr())
@@ -3845,8 +3850,10 @@
m_loaderClient->didFirstVisuallyNonEmptyLayoutForFrame(*this, *frame, m_process->transformHandlesToObjects(userData.object()).get());
- if (frame->isMainFrame())
+ if (frame->isMainFrame()) {
m_pageClient.didFirstVisuallyNonEmptyLayoutForMainFrame();
+ notifyProcessPoolToPrewarm();
+ }
}
void WebPageProxy::didLayoutForCustomContentProvider()
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.h 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h 2018-04-24 23:19:25 UTC (rev 230977)
@@ -1302,6 +1302,8 @@
WebPageProxy(PageClient&, WebProcessProxy&, uint64_t pageID, Ref<API::PageConfiguration>&&);
void platformInitialize();
+ void notifyProcessPoolToPrewarm();
+
RefPtr<API::Navigation> goToBackForwardItem(WebBackForwardListItem&, WebCore::FrameLoadType);
void updateActivityState(WebCore::ActivityState::Flags flagsToUpdate = WebCore::ActivityState::AllFlags);
Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2018-04-24 23:19:25 UTC (rev 230977)
@@ -736,12 +736,14 @@
platformResolvePathsForSandboxExtensions();
}
-WebProcessProxy& WebProcessPool::createNewWebProcess(WebsiteDataStore& websiteDataStore)
+WebProcessProxy& WebProcessPool::createNewWebProcess(WebsiteDataStore& websiteDataStore, WebProcessProxy::IsInPrewarmedPool isInPrewarmedPool)
{
- auto processProxy = WebProcessProxy::create(*this, websiteDataStore);
+ auto processProxy = WebProcessProxy::create(*this, websiteDataStore, isInPrewarmedPool);
auto& process = processProxy.get();
initializeNewWebProcess(process, websiteDataStore);
m_processes.append(WTFMove(processProxy));
+ if (isInPrewarmedPool == WebProcessProxy::IsInPrewarmedPool::Yes)
+ ++m_prewarmedProcessCount;
if (m_serviceWorkerProcessesTerminationTimer.isActive())
m_serviceWorkerProcessesTerminationTimer.stop();
@@ -749,6 +751,26 @@
return process;
}
+RefPtr<WebProcessProxy> WebProcessPool::tryTakePrewarmedProcess(WebsiteDataStore& websiteDataStore)
+{
+ if (!m_prewarmedProcessCount)
+ return nullptr;
+
+ for (const auto& process : m_processes) {
+ if (process->isInPrewarmedPool()) {
+ --m_prewarmedProcessCount;
+ process->setIsInPrewarmedPool(false);
+ if (&process->websiteDataStore() != &websiteDataStore)
+ process->send(Messages::WebProcess::AddWebsiteDataStore(websiteDataStore.parameters()), 0);
+ return process.get();
+ }
+ }
+
+ ASSERT_NOT_REACHED();
+ m_prewarmedProcessCount = 0;
+ return nullptr;
+}
+
#if PLATFORM(MAC)
static void displayReconfigurationCallBack(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo)
{
@@ -926,7 +948,7 @@
void WebProcessPool::warmInitialProcess()
{
- if (m_haveInitialEmptyProcess) {
+ if (m_prewarmedProcessCount) {
ASSERT(!m_processes.isEmpty());
return;
}
@@ -936,9 +958,7 @@
if (!m_websiteDataStore)
m_websiteDataStore = API::WebsiteDataStore::defaultDataStore().ptr();
- createNewWebProcess(m_websiteDataStore->websiteDataStore());
-
- m_haveInitialEmptyProcess = true;
+ createNewWebProcess(m_websiteDataStore->websiteDataStore(), WebProcessProxy::IsInPrewarmedPool::Yes);
}
void WebProcessPool::enableProcessTermination()
@@ -994,8 +1014,8 @@
{
ASSERT(m_processes.contains(process));
- if (m_haveInitialEmptyProcess && process == m_processes.last())
- m_haveInitialEmptyProcess = false;
+ if (process->isInPrewarmedPool())
+ --m_prewarmedProcessCount;
// FIXME (Multi-WebProcess): <rdar://problem/12239765> Some of the invalidation calls of the other supplements are still necessary in multi-process mode, but they should only affect data structures pertaining to the process being disconnected.
// Clearing everything causes assertion failures, so it's less trouble to skip that for now.
@@ -1082,14 +1102,14 @@
}
RefPtr<WebProcessProxy> process;
- if (m_haveInitialEmptyProcess) {
- process = m_processes.last();
- m_haveInitialEmptyProcess = false;
- } else if (pageConfiguration->relatedPage()) {
+ if (pageConfiguration->relatedPage()) {
// Sharing processes, e.g. when creating the page via window.open().
process = &pageConfiguration->relatedPage()->process();
- } else
- process = &createNewWebProcessRespectingProcessCountLimit(pageConfiguration->websiteDataStore()->websiteDataStore());
+ } else {
+ process = tryTakePrewarmedProcess(pageConfiguration->websiteDataStore()->websiteDataStore());
+ if (!process)
+ process = &createNewWebProcessRespectingProcessCountLimit(pageConfiguration->websiteDataStore()->websiteDataStore());
+ }
#if ENABLE(SERVICE_WORKER)
ASSERT(!is<ServiceWorkerProcessProxy>(*process));
@@ -1228,6 +1248,17 @@
}
}
+void WebProcessPool::didReachGoodTimeToPrewarm()
+{
+ if (!m_configuration->processSwapsOnNavigation())
+ return;
+ if (!m_websiteDataStore)
+ m_websiteDataStore = API::WebsiteDataStore::defaultDataStore().ptr();
+ static constexpr size_t maxPrewarmCount = 1;
+ while (m_prewarmedProcessCount < maxPrewarmCount)
+ createNewWebProcess(m_websiteDataStore->websiteDataStore(), WebProcessProxy::IsInPrewarmedPool::Yes);
+}
+
void WebProcessPool::populateVisitedLinks()
{
m_historyClient->populateVisitedLinks(*this);
@@ -2019,6 +2050,8 @@
return page.process();
action = ""
+ if (RefPtr<WebProcessProxy> process = tryTakePrewarmedProcess(page.websiteDataStore()))
+ return process.releaseNonNull();
return createNewWebProcess(page.websiteDataStore());
}
Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/WebProcessPool.h 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h 2018-04-24 23:19:25 UTC (rev 230977)
@@ -106,8 +106,7 @@
int webProcessThroughputQOS();
#endif
-class WebProcessPool final : public API::ObjectImpl<API::Object::Type::ProcessPool>, private IPC::MessageReceiver
- {
+class WebProcessPool final : public API::ObjectImpl<API::Object::Type::ProcessPool>, private IPC::MessageReceiver {
public:
static Ref<WebProcessPool> create(API::ProcessPoolConfiguration&);
@@ -449,6 +448,7 @@
Ref<WebProcessProxy> processForNavigation(WebPageProxy&, const API::Navigation&, WebCore::PolicyAction&);
void registerSuspendedPageProxy(SuspendedPageProxy&);
void unregisterSuspendedPageProxy(SuspendedPageProxy&);
+ void didReachGoodTimeToPrewarm();
private:
void platformInitialize();
@@ -456,7 +456,9 @@
void platformInitializeWebProcess(WebProcessCreationParameters&);
void platformInvalidateContext();
- WebProcessProxy& createNewWebProcess(WebsiteDataStore&);
+ RefPtr<WebProcessProxy> tryTakePrewarmedProcess(WebsiteDataStore&);
+
+ WebProcessProxy& createNewWebProcess(WebsiteDataStore&, WebProcessProxy::IsInPrewarmedPool = WebProcessProxy::IsInPrewarmedPool::No);
void initializeNewWebProcess(WebProcessProxy&, WebsiteDataStore&);
void requestWebContentStatistics(StatisticsRequest*);
@@ -516,7 +518,7 @@
IPC::MessageReceiverMap m_messageReceiverMap;
Vector<RefPtr<WebProcessProxy>> m_processes;
- bool m_haveInitialEmptyProcess { false };
+ unsigned m_prewarmedProcessCount { 0 };
WebProcessProxy* m_processWithPageCache { nullptr };
#if ENABLE(SERVICE_WORKER)
Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp 2018-04-24 23:19:25 UTC (rev 230977)
@@ -105,14 +105,14 @@
return pageMap;
}
-Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore& websiteDataStore)
+Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore& websiteDataStore, IsInPrewarmedPool isInPrewarmedPool)
{
- auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore));
+ auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore, isInPrewarmedPool));
proxy->connect();
return proxy;
}
-WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore& websiteDataStore)
+WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore& websiteDataStore, IsInPrewarmedPool isInPrewarmedPool)
: ChildProcessProxy(processPool.alwaysRunsAtBackgroundPriority())
, m_responsivenessTimer(*this)
, m_backgroundResponsivenessTimer(*this)
@@ -126,6 +126,7 @@
#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
, m_userMediaCaptureManagerProxy(std::make_unique<UserMediaCaptureManagerProxy>(*this))
#endif
+ , m_isInPrewarmedPool(isInPrewarmedPool == IsInPrewarmedPool::Yes)
{
auto result = allProcesses().add(coreProcessIdentifier(), this);
ASSERT_UNUSED(result, result.isNewEntry);
Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.h (230976 => 230977)
--- trunk/Source/WebKit/UIProcess/WebProcessProxy.h 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.h 2018-04-24 23:19:25 UTC (rev 230977)
@@ -97,7 +97,12 @@
typedef HashMap<uint64_t, WebPageProxy*> WebPageProxyMap;
typedef HashMap<uint64_t, RefPtr<API::UserInitiatedAction>> UserInitiatedActionMap;
- static Ref<WebProcessProxy> create(WebProcessPool&, WebsiteDataStore&);
+ enum class IsInPrewarmedPool {
+ No,
+ Yes
+ };
+
+ static Ref<WebProcessProxy> create(WebProcessPool&, WebsiteDataStore&, IsInPrewarmedPool);
~WebProcessProxy();
WebConnection* webConnection() const { return m_webConnection.get(); }
@@ -213,9 +218,12 @@
void releaseBackgroundActivityTokenForFullscreenInput();
#endif
+ bool isInPrewarmedPool() const { return m_isInPrewarmedPool; }
+ void setIsInPrewarmedPool(bool isInPrewarmedPool) { m_isInPrewarmedPool = isInPrewarmedPool; }
+
protected:
static uint64_t generatePageID();
- WebProcessProxy(WebProcessPool&, WebsiteDataStore&);
+ WebProcessProxy(WebProcessPool&, WebsiteDataStore&, IsInPrewarmedPool);
// ChildProcessProxy
void getLaunchOptions(ProcessLauncher::LaunchOptions&) override;
@@ -340,6 +348,7 @@
HashMap<uint64_t, CompletionHandler<void(WebCore::MessagePortChannelProvider::HasActivity)>> m_localPortActivityCompletionHandlers;
bool m_hasCommittedAnyProvisionalLoads { false };
+ bool m_isInPrewarmedPool;
#if ENABLE(EXTRA_ZOOM_MODE)
ProcessThrottler::BackgroundActivityToken m_backgroundActivityTokenForFullscreenFormControls;
Modified: trunk/Tools/ChangeLog (230976 => 230977)
--- trunk/Tools/ChangeLog 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Tools/ChangeLog 2018-04-24 23:19:25 UTC (rev 230977)
@@ -1,3 +1,13 @@
+2018-04-24 Saam Barati <[email protected]>
+
+ Keep around a pre-warmed process when doing process swap on navigation
+ https://bugs.webkit.org/show_bug.cgi?id=184765
+ <rdar://problem/39685099>
+
+ Reviewed by Ryosuke Niwa and Brady Eidson.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
2018-04-24 Aakash Jain <[email protected]>
[build.webkit.org] unit-tests fail when passwords.json is missing
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (230976 => 230977)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm 2018-04-24 23:06:26 UTC (rev 230976)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm 2018-04-24 23:19:25 UTC (rev 230977)
@@ -785,7 +785,7 @@
EXPECT_EQ(3u, seenPIDs.size());
// But only 2 of those processes should still be alive
- EXPECT_EQ(2u, [processPool _webProcessCount]);
+ EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
}
static const char* pageCache1Bytes = R"PSONRESOURCE(
@@ -826,7 +826,7 @@
auto pidAfterLoad1 = [webView _webProcessIdentifier];
- EXPECT_EQ(1u, [processPool _webProcessCount]);
+ EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
@@ -836,7 +836,7 @@
auto pidAfterLoad2 = [webView _webProcessIdentifier];
- EXPECT_EQ(2u, [processPool _webProcessCount]);
+ EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
EXPECT_NE(pidAfterLoad1, pidAfterLoad2);
[webView goBack];
@@ -847,7 +847,7 @@
auto pidAfterLoad3 = [webView _webProcessIdentifier];
- EXPECT_EQ(2u, [processPool _webProcessCount]);
+ EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
EXPECT_EQ(pidAfterLoad1, pidAfterLoad3);
EXPECT_EQ(1u, [receivedMessages count]);
EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]);
@@ -861,7 +861,7 @@
auto pidAfterLoad4 = [webView _webProcessIdentifier];
- EXPECT_EQ(2u, [processPool _webProcessCount]);
+ EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
EXPECT_EQ(pidAfterLoad2, pidAfterLoad4);
EXPECT_EQ(2u, [receivedMessages count]);
EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]);
@@ -868,6 +868,40 @@
EXPECT_EQ(2u, seenPIDs.size());
}
+TEST(ProcessSwap, NumberOfPrewarmedProcesses)
+{
+ auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
+ [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+ auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
+
+ auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ [webViewConfiguration setProcessPool:processPool.get()];
+ auto handler = adoptNS([[PSONScheme alloc] init]);
+ [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
+
+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+ auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
+ [webView setNavigationDelegate:delegate.get()];
+
+ NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host1/main.html"]];
+ [webView loadRequest:request];
+ TestWebKitAPI::Util::run(&done);
+ done = false;
+
+ EXPECT_EQ(2u, [processPool _webProcessCount]);
+ EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
+ EXPECT_EQ(1u, [processPool _prewarmedWebProcessCount]);
+
+ request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host3/main.html"]];
+ [webView loadRequest:request];
+ TestWebKitAPI::Util::run(&done);
+ done = false;
+
+ EXPECT_EQ(3u, [processPool _webProcessCount]);
+ EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
+ EXPECT_EQ(1u, [processPool _prewarmedWebProcessCount]);
+}
+
static const char* visibilityBytes = R"PSONRESOURCE(
<script>
window.addEventListener('pageshow', function(event) {