Drop the render tree for documents in the page cache.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Jan 2017 21:16:09 +0000 (21:16 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 2 Jan 2017 21:16:09 +0000 (21:16 +0000)
<https://webkit.org/b/121798>

Reviewed by Antti Koivisto.

To save memory and reduce complexity, have documents tear down their render tree
when entering the page cache. I've wanted to do this for a long time and it seems
like we can actually do it now.

This patch will enable a number of clean-ups since it's no longer valid for renderers
to exist while the document is in page cache.

* dom/Document.cpp:
(WebCore::Document::destroyRenderTree): Remove assertion that we're not in the page cache
since we will now be tearing down render trees right as they enter the page cache.

* dom/PageCache.cpp:
(WebCore::destroyRenderTree):
(WebCore::PageCache::addIfCacheable): Tear down the render tree right before setting
the in-cache flag. The render tree is destroyed in bottom-up order to ensure that the
main frame renderers die last.

* history/CachedFrame.cpp:
(WebCore::CachedFrameBase::restore):
* page/FrameView.h:
* page/FrameView.cpp:
(WebCore::FrameView::didRestoreFromPageCache): Update the scollable area set after restoring
a frame from the page cache. This dirties the scrolling tree, which was covered by tests.

* page/animation/AnimationBase.cpp:
(WebCore::AnimationBase::setNeedsStyleRecalc):
* page/animation/AnimationController.cpp:
(WebCore::AnimationController::cancelAnimations): Make these no-ops if called
while the render tree is being torn down. This fixes some assertion failures
on layout tests and avoids pointless style invalidation.

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

Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/history/CachedFrame.cpp
Source/WebCore/history/PageCache.cpp
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/FrameView.h
Source/WebCore/page/animation/AnimationBase.cpp
Source/WebCore/page/animation/AnimationController.cpp

index d5576d4..fee798e 100644 (file)
@@ -1,5 +1,43 @@
 2017-01-02  Andreas Kling  <akling@apple.com>
 
+        Drop the render tree for documents in the page cache.
+        <https://webkit.org/b/121798>
+
+        Reviewed by Antti Koivisto.
+
+        To save memory and reduce complexity, have documents tear down their render tree
+        when entering the page cache. I've wanted to do this for a long time and it seems
+        like we can actually do it now.
+
+        This patch will enable a number of clean-ups since it's no longer valid for renderers
+        to exist while the document is in page cache.
+
+        * dom/Document.cpp:
+        (WebCore::Document::destroyRenderTree): Remove assertion that we're not in the page cache
+        since we will now be tearing down render trees right as they enter the page cache.
+
+        * dom/PageCache.cpp:
+        (WebCore::destroyRenderTree):
+        (WebCore::PageCache::addIfCacheable): Tear down the render tree right before setting
+        the in-cache flag. The render tree is destroyed in bottom-up order to ensure that the
+        main frame renderers die last.
+
+        * history/CachedFrame.cpp:
+        (WebCore::CachedFrameBase::restore):
+        * page/FrameView.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::didRestoreFromPageCache): Update the scollable area set after restoring
+        a frame from the page cache. This dirties the scrolling tree, which was covered by tests.
+
+        * page/animation/AnimationBase.cpp:
+        (WebCore::AnimationBase::setNeedsStyleRecalc):
+        * page/animation/AnimationController.cpp:
+        (WebCore::AnimationController::cancelAnimations): Make these no-ops if called
+        while the render tree is being torn down. This fixes some assertion failures
+        on layout tests and avoids pointless style invalidation.
+
+2017-01-02  Andreas Kling  <akling@apple.com>
+
         Discard media controls JS/CSS caches under memory pressure.
         <https://webkit.org/b/166639>
 
index 665496d..d287715 100644 (file)
@@ -2202,7 +2202,6 @@ void Document::frameDestroyed()
 void Document::destroyRenderTree()
 {
     ASSERT(hasLivingRenderTree());
-    ASSERT(m_pageCacheState != InPageCache);
 
     SetForScope<bool> change(m_renderTreeBeingDestroyed, true);
 
index 2946003..f2c90f4 100644 (file)
@@ -130,6 +130,7 @@ void CachedFrameBase::restore()
         m_document->page()->chrome().client().needTouchEvents(true);
 #endif
 
+    frame.view()->didRestoreFromPageCache();
 }
 
 CachedFrame::CachedFrame(Frame& frame)
index eb61a34..6d00437 100644 (file)
@@ -364,6 +364,20 @@ static void setPageCacheState(Page& page, Document::PageCacheState pageCacheStat
     }
 }
 
+// When entering page cache, tear down the render tree before setting the in-cache flag.
+// This maintains the invariant that render trees are never present in the page cache.
+// Note that destruction happens bottom-up so that the main frame's tree dies last.
+static void destroyRenderTree(MainFrame& mainFrame)
+{
+    for (Frame* frame = mainFrame.tree().traversePreviousWithWrap(true); frame; frame = frame->tree().traversePreviousWithWrap(false)) {
+        if (!frame->document())
+            continue;
+        auto& document = *frame->document();
+        if (document.hasLivingRenderTree())
+            document.destroyRenderTree();
+    }
+}
+
 static void firePageHideEventRecursively(Frame& frame)
 {
     auto* document = frame.document();
@@ -407,6 +421,8 @@ void PageCache::addIfCacheable(HistoryItem& item, Page* page)
         return;
     }
 
+    destroyRenderTree(page->mainFrame());
+
     setPageCacheState(*page, Document::InPageCache);
 
     // Make sure we no longer fire any JS events past this point.
index 9605cf0..77075fd 100644 (file)
@@ -636,6 +636,13 @@ Ref<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
     return ScrollView::createScrollbar(orientation);
 }
 
+void FrameView::didRestoreFromPageCache()
+{
+    // When restoring from page cache, the main frame stays in place while subframes get swapped in.
+    // We update the scrollable area set to ensure that scrolling data structures get invalidated.
+    updateScrollableAreaSet();
+}
+
 void FrameView::setContentsSize(const IntSize& size)
 {
     if (size == contentsSize())
index 81806ee..23a7fd1 100644 (file)
@@ -587,6 +587,8 @@ public:
 
     bool shouldPlaceBlockDirectionScrollbarOnLeft() const final;
 
+    void didRestoreFromPageCache();
+
 protected:
     bool scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) override;
     void scrollContentsSlowPath(const IntRect& updateRect) override;
index 6eabc34..1c47e3d 100644 (file)
@@ -89,9 +89,11 @@ AnimationBase::AnimationBase(const Animation& animation, RenderElement* renderer
 
 void AnimationBase::setNeedsStyleRecalc(Element* element)
 {
-    ASSERT(!element || element->document().pageCacheState() == Document::NotInPageCache);
-    if (element)
-        element->invalidateStyleAndLayerComposition();
+    if (!element || element->document().renderTreeBeingDestroyed())
+        return;
+
+    ASSERT(element->document().pageCacheState() == Document::NotInPageCache);
+    element->invalidateStyleAndLayerComposition();
 }
 
 double AnimationBase::duration() const
index e5cb0eb..bbb6f3e 100644 (file)
@@ -588,9 +588,10 @@ void AnimationController::cancelAnimations(RenderElement& renderer)
         return;
 
     Element* element = renderer.element();
-    ASSERT(!element || element->document().pageCacheState() == Document::NotInPageCache);
-    if (element)
-        element->invalidateStyleAndLayerComposition();
+    if (!element || element->document().renderTreeBeingDestroyed())
+        return;
+    ASSERT(element->document().pageCacheState() == Document::NotInPageCache);
+    element->invalidateStyleAndLayerComposition();
 }
 
 bool AnimationController::updateAnimations(RenderElement& renderer, const RenderStyle& newStyle, std::unique_ptr<RenderStyle>& animatedStyle)