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

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

<h3>Log Message</h3>
<pre>Cherry-pick <a href="http://trac.webkit.org/projects/webkit/changeset/247555">r247555</a>. rdar://problem/53254411

    Prewarm local storage in the NetworkProcess to reduce WebContent process hangs
    https://bugs.webkit.org/show_bug.cgi?id=199879
    <rdar://problem/53217757>

    Reviewed by Ryosuke Niwa.

    Source/WebCore:

    When JS accesses window.localStorage for the first time, we end up doing a
    synchronous IPC to the network process to pull in all items in the local
    storage for the origin. If the network process does not have this data in
    memory, it has to read it from a database on disk, which may take a significant
    amount of time and hang the WebContent process during this time.

    To alleviate this problem, this patch introduces prewarming on the local storage
    in the network process when loading a given origin in the WebContent process.
    This way, in most cases, when the JS accesses window.localStorage for the first
    time, the synchronous IPC to the network process returns much faster (measured
    50-100ms for a very large database, down from 250-300ms), as it only needs to
    IPC the data over, without the need to fetch it from disk.

    As a safety net to avoid excessive prewarming, we currently prewarm at most 5
    security origins per page load.

    * loader/DocumentLoader.cpp:
    (WebCore::DocumentLoader::commitData):
    * page/DOMWindow.cpp:
    (WebCore::DOMWindow::prewarmLocalStorageIfNecessary):
    * page/DOMWindow.h:
    * page/Frame.cpp:
    (WebCore::Frame::didPrewarmLocalStorage):
    (WebCore::Frame::mayPrewarmLocalStorage const):
    * page/Frame.h:
    * storage/Storage.cpp:
    (WebCore::Storage::prewarm):
    * storage/Storage.h:
    * storage/StorageArea.h:
    (WebCore::StorageArea::prewarm):

    Source/WebKit:

    * NetworkProcess/WebStorage/StorageManager.cpp:
    (WebKit::StorageManager::prewarm):
    (WebKit::StorageManager::getValues):
    * NetworkProcess/WebStorage/StorageManager.h:
    * NetworkProcess/WebStorage/StorageManager.messages.in:
    * WebProcess/WebStorage/StorageAreaImpl.cpp:
    (WebKit::StorageAreaImpl::prewarm):
    * WebProcess/WebStorage/StorageAreaImpl.h:
    * WebProcess/WebStorage/StorageAreaMap.cpp:
    (WebKit::StorageAreaMap::loadValuesIfNeeded):
    (WebKit::StorageAreaMap::prewarm):
    * WebProcess/WebStorage/StorageAreaMap.h:

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247555 268f45cc-cd09-0410-ab3c-d52691b4dbfc</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari608branchSourceWebCoreChangeLog">branches/safari-608-branch/Source/WebCore/ChangeLog</a></li>
<li><a href="#branchessafari608branchSourceWebCoreloaderDocumentLoadercpp">branches/safari-608-branch/Source/WebCore/loader/DocumentLoader.cpp</a></li>
<li><a href="#branchessafari608branchSourceWebCorepageDOMWindowcpp">branches/safari-608-branch/Source/WebCore/page/DOMWindow.cpp</a></li>
<li><a href="#branchessafari608branchSourceWebCorepageDOMWindowh">branches/safari-608-branch/Source/WebCore/page/DOMWindow.h</a></li>
<li><a href="#branchessafari608branchSourceWebCorepageFramecpp">branches/safari-608-branch/Source/WebCore/page/Frame.cpp</a></li>
<li><a href="#branchessafari608branchSourceWebCorepageFrameh">branches/safari-608-branch/Source/WebCore/page/Frame.h</a></li>
<li><a href="#branchessafari608branchSourceWebCorestorageStoragecpp">branches/safari-608-branch/Source/WebCore/storage/Storage.cpp</a></li>
<li><a href="#branchessafari608branchSourceWebCorestorageStorageh">branches/safari-608-branch/Source/WebCore/storage/Storage.h</a></li>
<li><a href="#branchessafari608branchSourceWebCorestorageStorageAreah">branches/safari-608-branch/Source/WebCore/storage/StorageArea.h</a></li>
<li><a href="#branchessafari608branchSourceWebKitChangeLog">branches/safari-608-branch/Source/WebKit/ChangeLog</a></li>
<li><a href="#branchessafari608branchSourceWebKitNetworkProcessWebStorageStorageManagercpp">branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.cpp</a></li>
<li><a href="#branchessafari608branchSourceWebKitNetworkProcessWebStorageStorageManagerh">branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.h</a></li>
<li><a href="#branchessafari608branchSourceWebKitNetworkProcessWebStorageStorageManagermessagesin">branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.messages.in</a></li>
<li><a href="#branchessafari608branchSourceWebKitWebProcessWebStorageStorageAreaImplcpp">branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.cpp</a></li>
<li><a href="#branchessafari608branchSourceWebKitWebProcessWebStorageStorageAreaImplh">branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.h</a></li>
<li><a href="#branchessafari608branchSourceWebKitWebProcessWebStorageStorageAreaMapcpp">branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp</a></li>
<li><a href="#branchessafari608branchSourceWebKitWebProcessWebStorageStorageAreaMaph">branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari608branchSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/ChangeLog (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/ChangeLog      2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/ChangeLog 2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -1,3 +1,103 @@
</span><ins>+2019-07-18  Kocsen Chung  <kocsen_chung@apple.com>
+
+        Cherry-pick r247555. rdar://problem/53254411
+
+    Prewarm local storage in the NetworkProcess to reduce WebContent process hangs
+    https://bugs.webkit.org/show_bug.cgi?id=199879
+    <rdar://problem/53217757>
+    
+    Reviewed by Ryosuke Niwa.
+    
+    Source/WebCore:
+    
+    When JS accesses window.localStorage for the first time, we end up doing a
+    synchronous IPC to the network process to pull in all items in the local
+    storage for the origin. If the network process does not have this data in
+    memory, it has to read it from a database on disk, which may take a significant
+    amount of time and hang the WebContent process during this time.
+    
+    To alleviate this problem, this patch introduces prewarming on the local storage
+    in the network process when loading a given origin in the WebContent process.
+    This way, in most cases, when the JS accesses window.localStorage for the first
+    time, the synchronous IPC to the network process returns much faster (measured
+    50-100ms for a very large database, down from 250-300ms), as it only needs to
+    IPC the data over, without the need to fetch it from disk.
+    
+    As a safety net to avoid excessive prewarming, we currently prewarm at most 5
+    security origins per page load.
+    
+    * loader/DocumentLoader.cpp:
+    (WebCore::DocumentLoader::commitData):
+    * page/DOMWindow.cpp:
+    (WebCore::DOMWindow::prewarmLocalStorageIfNecessary):
+    * page/DOMWindow.h:
+    * page/Frame.cpp:
+    (WebCore::Frame::didPrewarmLocalStorage):
+    (WebCore::Frame::mayPrewarmLocalStorage const):
+    * page/Frame.h:
+    * storage/Storage.cpp:
+    (WebCore::Storage::prewarm):
+    * storage/Storage.h:
+    * storage/StorageArea.h:
+    (WebCore::StorageArea::prewarm):
+    
+    Source/WebKit:
+    
+    * NetworkProcess/WebStorage/StorageManager.cpp:
+    (WebKit::StorageManager::prewarm):
+    (WebKit::StorageManager::getValues):
+    * NetworkProcess/WebStorage/StorageManager.h:
+    * NetworkProcess/WebStorage/StorageManager.messages.in:
+    * WebProcess/WebStorage/StorageAreaImpl.cpp:
+    (WebKit::StorageAreaImpl::prewarm):
+    * WebProcess/WebStorage/StorageAreaImpl.h:
+    * WebProcess/WebStorage/StorageAreaMap.cpp:
+    (WebKit::StorageAreaMap::loadValuesIfNeeded):
+    (WebKit::StorageAreaMap::prewarm):
+    * WebProcess/WebStorage/StorageAreaMap.h:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247555 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-07-17  Chris Dumez  <cdumez@apple.com>
+
+            Prewarm local storage in the NetworkProcess to reduce WebContent process hangs
+            https://bugs.webkit.org/show_bug.cgi?id=199879
+            <rdar://problem/53217757>
+
+            Reviewed by Ryosuke Niwa.
+
+            When JS accesses window.localStorage for the first time, we end up doing a
+            synchronous IPC to the network process to pull in all items in the local
+            storage for the origin. If the network process does not have this data in
+            memory, it has to read it from a database on disk, which may take a significant
+            amount of time and hang the WebContent process during this time.
+
+            To alleviate this problem, this patch introduces prewarming on the local storage
+            in the network process when loading a given origin in the WebContent process.
+            This way, in most cases, when the JS accesses window.localStorage for the first
+            time, the synchronous IPC to the network process returns much faster (measured
+            50-100ms for a very large database, down from 250-300ms), as it only needs to
+            IPC the data over, without the need to fetch it from disk.
+
+            As a safety net to avoid excessive prewarming, we currently prewarm at most 5
+            security origins per page load.
+
+            * loader/DocumentLoader.cpp:
+            (WebCore::DocumentLoader::commitData):
+            * page/DOMWindow.cpp:
+            (WebCore::DOMWindow::prewarmLocalStorageIfNecessary):
+            * page/DOMWindow.h:
+            * page/Frame.cpp:
+            (WebCore::Frame::didPrewarmLocalStorage):
+            (WebCore::Frame::mayPrewarmLocalStorage const):
+            * page/Frame.h:
+            * storage/Storage.cpp:
+            (WebCore::Storage::prewarm):
+            * storage/Storage.h:
+            * storage/StorageArea.h:
+            (WebCore::StorageArea::prewarm):
+
</ins><span class="cx"> 2019-07-17  Kocsen Chung  <kocsen_chung@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Cherry-pick r247544. rdar://problem/53230040
</span></span></pre></div>
<a id="branchessafari608branchSourceWebCoreloaderDocumentLoadercpp"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/loader/DocumentLoader.cpp (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/loader/DocumentLoader.cpp      2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/loader/DocumentLoader.cpp 2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -1084,6 +1084,9 @@
</span><span class="cx">         if (!isLoading())
</span><span class="cx">             return;
</span><span class="cx"> 
</span><ins>+        if (auto* window = m_frame->document()->domWindow())
+            window->prewarmLocalStorageIfNecessary();
+
</ins><span class="cx">         bool userChosen;
</span><span class="cx">         String encoding;
</span><span class="cx">         if (overrideEncoding().isNull()) {
</span></span></pre></div>
<a id="branchessafari608branchSourceWebCorepageDOMWindowcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/page/DOMWindow.cpp (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/page/DOMWindow.cpp     2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/page/DOMWindow.cpp        2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -423,6 +423,29 @@
</span><span class="cx">     m_performance = nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void DOMWindow::prewarmLocalStorageIfNecessary()
+{
+    auto* page = this->page();
+
+    // No need to prewarm for ephemeral sessions since the data is in memory only.
+    if (!page || page->usesEphemeralSession())
+        return;
+
+    if (!page->mainFrame().mayPrewarmLocalStorage())
+        return;
+
+    auto localStorageResult = this->localStorage();
+    if (localStorageResult.hasException())
+        return;
+
+    auto* localStorage = localStorageResult.returnValue();
+    if (!localStorage)
+        return;
+
+    if (localStorage->prewarm())
+        page->mainFrame().didPrewarmLocalStorage();
+}
+
</ins><span class="cx"> DOMWindow::~DOMWindow()
</span><span class="cx"> {
</span><span class="cx">     if (m_suspendedForDocumentSuspension)
</span></span></pre></div>
<a id="branchessafari608branchSourceWebCorepageDOMWindowh"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/page/DOMWindow.h (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/page/DOMWindow.h       2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/page/DOMWindow.h  2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -181,6 +181,8 @@
</span><span class="cx"> 
</span><span class="cx">     void showModalDialog(const String& urlString, const String& dialogFeaturesString, DOMWindow& activeWindow, DOMWindow& firstWindow, const WTF::Function<void(DOMWindow&)>& prepareDialogFunction);
</span><span class="cx"> 
</span><ins>+    void prewarmLocalStorageIfNecessary();
+
</ins><span class="cx">     void alert(const String& message = emptyString());
</span><span class="cx">     bool confirm(const String& message);
</span><span class="cx">     String prompt(const String& message, const String& defaultValue);
</span></span></pre></div>
<a id="branchessafari608branchSourceWebCorepageFramecpp"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/page/Frame.cpp (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/page/Frame.cpp 2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/page/Frame.cpp    2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -117,6 +117,9 @@
</span><span class="cx"> 
</span><span class="cx"> DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame"));
</span><span class="cx"> 
</span><ins>+// We prewarm local storage for at most 5 origins in a given page.
+static const unsigned maxlocalStoragePrewarmingCount { 5 };
+
</ins><span class="cx"> static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
</span><span class="cx"> {
</span><span class="cx">     if (!ownerElement)
</span><span class="lines">@@ -992,6 +995,19 @@
</span><span class="cx">         tree().removeChild(*child);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Frame::didPrewarmLocalStorage()
+{
+    ASSERT(isMainFrame());
+    ASSERT(m_localStoragePrewarmingCount < maxlocalStoragePrewarmingCount);
+    ++m_localStoragePrewarmingCount;
+}
+
+bool Frame::mayPrewarmLocalStorage() const
+{
+    ASSERT(isMainFrame());
+    return m_localStoragePrewarmingCount < maxlocalStoragePrewarmingCount;
+}
+
</ins><span class="cx"> void Frame::selfOnlyRef()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainFrame());
</span></span></pre></div>
<a id="branchessafari608branchSourceWebCorepageFrameh"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/page/Frame.h (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/page/Frame.h   2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/page/Frame.h      2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -290,6 +290,9 @@
</span><span class="cx">     bool isURLAllowed(const URL&) const;
</span><span class="cx">     WEBCORE_EXPORT bool isAlwaysOnLoggingAllowed() const;
</span><span class="cx"> 
</span><ins>+    void didPrewarmLocalStorage();
+    bool mayPrewarmLocalStorage() const;
+
</ins><span class="cx"> // ========
</span><span class="cx"> 
</span><span class="cx">     void selfOnlyRef();
</span><span class="lines">@@ -349,6 +352,7 @@
</span><span class="cx">     unsigned m_navigationDisableCount { 0 };
</span><span class="cx">     unsigned m_selfOnlyRefCount { 0 };
</span><span class="cx">     bool m_hasHadUserInteraction { false };
</span><ins>+    unsigned m_localStoragePrewarmingCount { 0 };
</ins><span class="cx"> 
</span><span class="cx"> protected:
</span><span class="cx">     UniqueRef<EventHandler> m_eventHandler;
</span></span></pre></div>
<a id="branchessafari608branchSourceWebCorestorageStoragecpp"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/storage/Storage.cpp (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/storage/Storage.cpp    2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/storage/Storage.cpp       2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -97,6 +97,11 @@
</span><span class="cx">     return { };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Storage::prewarm()
+{
+    return m_storageArea->prewarm();
+}
+
</ins><span class="cx"> ExceptionOr<void> Storage::clear()
</span><span class="cx"> {
</span><span class="cx">     auto* frame = this->frame();
</span></span></pre></div>
<a id="branchessafari608branchSourceWebCorestorageStorageh"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/storage/Storage.h (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/storage/Storage.h      2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/storage/Storage.h 2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -46,6 +46,7 @@
</span><span class="cx">     ExceptionOr<void> removeItem(const String& key);
</span><span class="cx">     ExceptionOr<void> clear();
</span><span class="cx">     bool contains(const String& key) const;
</span><ins>+    bool prewarm();
</ins><span class="cx"> 
</span><span class="cx">     // Bindings support functions.
</span><span class="cx">     bool isSupportedPropertyName(const String&) const;
</span></span></pre></div>
<a id="branchessafari608branchSourceWebCorestorageStorageAreah"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebCore/storage/StorageArea.h (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebCore/storage/StorageArea.h  2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebCore/storage/StorageArea.h     2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -58,6 +58,7 @@
</span><span class="cx">     virtual void incrementAccessCount() { }
</span><span class="cx">     virtual void decrementAccessCount() { }
</span><span class="cx">     virtual void closeDatabaseIfIdle() { }
</span><ins>+    virtual bool prewarm() { return false; }
</ins><span class="cx"> 
</span><span class="cx">     virtual const SecurityOriginData& securityOrigin() const = 0;
</span><span class="cx"> };
</span></span></pre></div>
<a id="branchessafari608branchSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebKit/ChangeLog (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebKit/ChangeLog       2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebKit/ChangeLog  2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -1,3 +1,85 @@
</span><ins>+2019-07-18  Kocsen Chung  <kocsen_chung@apple.com>
+
+        Cherry-pick r247555. rdar://problem/53254411
+
+    Prewarm local storage in the NetworkProcess to reduce WebContent process hangs
+    https://bugs.webkit.org/show_bug.cgi?id=199879
+    <rdar://problem/53217757>
+    
+    Reviewed by Ryosuke Niwa.
+    
+    Source/WebCore:
+    
+    When JS accesses window.localStorage for the first time, we end up doing a
+    synchronous IPC to the network process to pull in all items in the local
+    storage for the origin. If the network process does not have this data in
+    memory, it has to read it from a database on disk, which may take a significant
+    amount of time and hang the WebContent process during this time.
+    
+    To alleviate this problem, this patch introduces prewarming on the local storage
+    in the network process when loading a given origin in the WebContent process.
+    This way, in most cases, when the JS accesses window.localStorage for the first
+    time, the synchronous IPC to the network process returns much faster (measured
+    50-100ms for a very large database, down from 250-300ms), as it only needs to
+    IPC the data over, without the need to fetch it from disk.
+    
+    As a safety net to avoid excessive prewarming, we currently prewarm at most 5
+    security origins per page load.
+    
+    * loader/DocumentLoader.cpp:
+    (WebCore::DocumentLoader::commitData):
+    * page/DOMWindow.cpp:
+    (WebCore::DOMWindow::prewarmLocalStorageIfNecessary):
+    * page/DOMWindow.h:
+    * page/Frame.cpp:
+    (WebCore::Frame::didPrewarmLocalStorage):
+    (WebCore::Frame::mayPrewarmLocalStorage const):
+    * page/Frame.h:
+    * storage/Storage.cpp:
+    (WebCore::Storage::prewarm):
+    * storage/Storage.h:
+    * storage/StorageArea.h:
+    (WebCore::StorageArea::prewarm):
+    
+    Source/WebKit:
+    
+    * NetworkProcess/WebStorage/StorageManager.cpp:
+    (WebKit::StorageManager::prewarm):
+    (WebKit::StorageManager::getValues):
+    * NetworkProcess/WebStorage/StorageManager.h:
+    * NetworkProcess/WebStorage/StorageManager.messages.in:
+    * WebProcess/WebStorage/StorageAreaImpl.cpp:
+    (WebKit::StorageAreaImpl::prewarm):
+    * WebProcess/WebStorage/StorageAreaImpl.h:
+    * WebProcess/WebStorage/StorageAreaMap.cpp:
+    (WebKit::StorageAreaMap::loadValuesIfNeeded):
+    (WebKit::StorageAreaMap::prewarm):
+    * WebProcess/WebStorage/StorageAreaMap.h:
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247555 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2019-07-17  Chris Dumez  <cdumez@apple.com>
+
+            Prewarm local storage in the NetworkProcess to reduce WebContent process hangs
+            https://bugs.webkit.org/show_bug.cgi?id=199879
+            <rdar://problem/53217757>
+
+            Reviewed by Ryosuke Niwa.
+
+            * NetworkProcess/WebStorage/StorageManager.cpp:
+            (WebKit::StorageManager::prewarm):
+            (WebKit::StorageManager::getValues):
+            * NetworkProcess/WebStorage/StorageManager.h:
+            * NetworkProcess/WebStorage/StorageManager.messages.in:
+            * WebProcess/WebStorage/StorageAreaImpl.cpp:
+            (WebKit::StorageAreaImpl::prewarm):
+            * WebProcess/WebStorage/StorageAreaImpl.h:
+            * WebProcess/WebStorage/StorageAreaMap.cpp:
+            (WebKit::StorageAreaMap::loadValuesIfNeeded):
+            (WebKit::StorageAreaMap::prewarm):
+            * WebProcess/WebStorage/StorageAreaMap.h:
+
</ins><span class="cx"> 2019-07-17  Kocsen Chung  <kocsen_chung@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Cherry-pick r247559. rdar://problem/53230035
</span></span></pre></div>
<a id="branchessafari608branchSourceWebKitNetworkProcessWebStorageStorageManagercpp"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.cpp (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.cpp    2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.cpp       2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -65,11 +65,11 @@
</span><span class="cx"> 
</span><span class="cx">     bool isEphemeral() const { return !m_localStorageNamespace; }
</span><span class="cx"> 
</span><ins>+    void openDatabaseAndImportItemsIfNeeded() const;
+
</ins><span class="cx"> private:
</span><span class="cx">     explicit StorageArea(LocalStorageNamespace*, const SecurityOriginData&, unsigned quotaInBytes);
</span><span class="cx"> 
</span><del>-    void openDatabaseAndImportItemsIfNeeded() const;
-
</del><span class="cx">     void dispatchEvents(IPC::Connection::UniqueID sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& oldValue, const String& newValue, const String& urlString) const;
</span><span class="cx"> 
</span><span class="cx">     // Will be null if the storage area belongs to a session storage namespace or the storage area is in an ephemeral session.
</span><span class="lines">@@ -845,9 +845,16 @@
</span><span class="cx">     m_storageAreasByConnection.remove(connectionAndStorageMapIDPair);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void StorageManager::getValues(IPC::Connection& connection, WebCore::SecurityOriginData&& securityOriginData, uint64_t storageMapID, uint64_t storageMapSeed, GetValuesCallback&& completionHandler)
</del><ins>+void StorageManager::prewarm(IPC::Connection& connection, uint64_t storageMapID)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!RunLoop::isMain());
</span><ins>+    if (auto* storageArea = findStorageArea(connection, storageMapID))
+        storageArea->openDatabaseAndImportItemsIfNeeded();
+}
+
+void StorageManager::getValues(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageMapSeed, GetValuesCallback&& completionHandler)
+{
+    ASSERT(!RunLoop::isMain());
</ins><span class="cx">     auto* storageArea = findStorageArea(connection, storageMapID);
</span><span class="cx"> 
</span><span class="cx">     // This is a session storage area for a page that has already been closed. Ignore it.
</span></span></pre></div>
<a id="branchessafari608branchSourceWebKitNetworkProcessWebStorageStorageManagerh"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.h (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.h      2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.h 2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -86,7 +86,8 @@
</span><span class="cx">     void createSessionStorageMap(IPC::Connection&, uint64_t storageMapID, uint64_t storageNamespaceID, WebCore::SecurityOriginData&&);
</span><span class="cx">     void destroyStorageMap(IPC::Connection&, uint64_t storageMapID);
</span><span class="cx"> 
</span><del>-    void getValues(IPC::Connection&, WebCore::SecurityOriginData&&, uint64_t storageMapID, uint64_t storageMapSeed, GetValuesCallback&&);
</del><ins>+    void getValues(IPC::Connection&, uint64_t storageMapID, uint64_t storageMapSeed, GetValuesCallback&&);
+    void prewarm(IPC::Connection&, uint64_t storageMapID);
</ins><span class="cx">     void setItem(IPC::Connection&, WebCore::SecurityOriginData&&, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& value, const String& urlString);
</span><span class="cx">     void setItems(IPC::Connection&, uint64_t storageMapID, const HashMap<String, String>& items);
</span><span class="cx">     void removeItem(IPC::Connection&, WebCore::SecurityOriginData&&, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString);
</span></span></pre></div>
<a id="branchessafari608branchSourceWebKitNetworkProcessWebStorageStorageManagermessagesin"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.messages.in (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.messages.in    2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebKit/NetworkProcess/WebStorage/StorageManager.messages.in       2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -26,7 +26,8 @@
</span><span class="cx">     CreateSessionStorageMap(uint64_t storageMapID, uint64_t storageNamespaceID, struct WebCore::SecurityOriginData securityOriginData) WantsConnection
</span><span class="cx">     DestroyStorageMap(uint64_t storageMapID) WantsConnection
</span><span class="cx"> 
</span><del>-    GetValues(struct WebCore::SecurityOriginData securityOriginData, uint64_t storageMapID, uint64_t storageMapSeed) -> (HashMap<String, String> values) Synchronous WantsConnection
</del><ins>+    Prewarm(uint64_t storageMapID) WantsConnection
+    GetValues(uint64_t storageMapID, uint64_t storageMapSeed) -> (HashMap<String, String> values) Synchronous WantsConnection
</ins><span class="cx"> 
</span><span class="cx">     SetItem(struct WebCore::SecurityOriginData securityOriginData, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, String key, String value, String urlString) WantsConnection
</span><span class="cx">     SetItems(uint64_t storageMapID, HashMap<String, String> items) WantsConnection
</span></span></pre></div>
<a id="branchessafari608branchSourceWebKitWebProcessWebStorageStorageAreaImplcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.cpp (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.cpp       2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.cpp  2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -73,6 +73,11 @@
</span><span class="cx">     return m_storageAreaMap->item(key);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool StorageAreaImpl::prewarm()
+{
+    return m_storageAreaMap->prewarm();
+}
+
</ins><span class="cx"> void StorageAreaImpl::setItem(Frame* sourceFrame, const String& key, const String& value, bool& quotaException)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!value.isNull());
</span></span></pre></div>
<a id="branchessafari608branchSourceWebKitWebProcessWebStorageStorageAreaImplh"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.h (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.h 2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.h    2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -61,6 +61,7 @@
</span><span class="cx">     void decrementAccessCount() override;
</span><span class="cx">     void closeDatabaseIfIdle() override;
</span><span class="cx">     const WebCore::SecurityOriginData& securityOrigin() const override;
</span><ins>+    bool prewarm() final;
</ins><span class="cx"> 
</span><span class="cx">     uint64_t m_storageAreaID;
</span><span class="cx">     Ref<StorageAreaMap> m_storageAreaMap;
</span></span></pre></div>
<a id="branchessafari608branchSourceWebKitWebProcessWebStorageStorageAreaMapcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp        2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp   2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -178,7 +178,7 @@
</span><span class="cx">     // FIXME: This should use a special sendSync flag to indicate that we don't want to process incoming messages while waiting for a reply.
</span><span class="cx">     // (This flag does not yet exist). Since loadValuesIfNeeded() ends up being called from within JavaScript code, processing incoming synchronous messages
</span><span class="cx">     // could lead to weird reentrency bugs otherwise.
</span><del>-    WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManager::GetValues(m_securityOrigin->data(), m_storageMapID, m_currentSeed), Messages::StorageManager::GetValues::Reply(values), 0);
</del><ins>+    WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManager::GetValues(m_storageMapID, m_currentSeed), Messages::StorageManager::GetValues::Reply(values), 0);
</ins><span class="cx"> 
</span><span class="cx">     m_storageMap = StorageMap::create(m_quotaInBytes);
</span><span class="cx">     m_storageMap->importItems(WTFMove(values));
</span><span class="lines">@@ -187,6 +187,17 @@
</span><span class="cx">     m_hasPendingGetValues = true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool StorageAreaMap::prewarm()
+{
+    if (m_didPrewarm || m_storageMap)
+        return false;
+    m_didPrewarm = true;
+
+    connect();
+    WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::StorageManager::Prewarm(m_storageMapID), 0);
+    return true;
+}
+
</ins><span class="cx"> void StorageAreaMap::didGetValues(uint64_t storageMapSeed)
</span><span class="cx"> {
</span><span class="cx">     if (m_currentSeed != storageMapSeed)
</span></span></pre></div>
<a id="branchessafari608branchSourceWebKitWebProcessWebStorageStorageAreaMaph"></a>
<div class="modfile"><h4>Modified: branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h (247616 => 247617)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h  2019-07-18 20:25:53 UTC (rev 247616)
+++ branches/safari-608-branch/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h     2019-07-18 20:26:03 UTC (rev 247617)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx">     void removeItem(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key);
</span><span class="cx">     void clear(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea);
</span><span class="cx">     bool contains(const String& key);
</span><ins>+    bool prewarm();
</ins><span class="cx"> 
</span><span class="cx">     // IPC::MessageReceiver
</span><span class="cx">     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
</span><span class="lines">@@ -104,6 +105,7 @@
</span><span class="cx">     HashCountedSet<String> m_pendingValueChanges;
</span><span class="cx"> 
</span><span class="cx">     bool m_isDisconnected { true };
</span><ins>+    bool m_didPrewarm { false };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre>
</div>
</div>

</body>
</html>