Changeset 214392 in webkit


Ignore:
Timestamp:
Mar 24, 2017 6:13:23 PM (7 years ago)
Author:
dbates@webkit.org
Message:

media/restore-from-page-cache.html causes NoEventDispatchAssertion::isEventAllowedInMainThread() assertion failure
https://bugs.webkit.org/show_bug.cgi?id=170087
<rdar://problem/31254822>

Reviewed by Simon Fraser.

Reduce the scope of code that should never dispatch DOM events so as to allow updating contents size
after restoring a page from the page cache.

In r214014 we instantiate a NoEventDispatchAssertion in FrameLoader::commitProvisionalLoad()
around the call to CachedPage::restore() to assert when a DOM event is dispatched during
page restoration as such events can cause re-entrancy into the page cache. As it turns out
it is sufficient to ensure that no DOM events are dispatched after restoring all cached frames
as opposed to after CachedPage::restore() returns.

Also rename Document::enqueue{Pageshow, Popstate}Event() to dispatch{Pageshow, Popstate}Event(),
respectively, since they synchronously dispatch events :(. We hope in the future to make them
asynchronously dispatch events.

  • dom/Document.cpp:

(WebCore::Document::implicitClose): Update for renaming.
(WebCore::Document::statePopped): Ditto.
(WebCore::Document::dispatchPageshowEvent): Renamed; formerly named enqueuePageshowEvent().
(WebCore::Document::dispatchPopstateEvent): Renamed; formerly named enqueuePopstateEvent().
(WebCore::Document::enqueuePageshowEvent): Deleted.
(WebCore::Document::enqueuePopstateEvent): Deleted.

  • dom/Document.h:
  • history/CachedPage.cpp:

(WebCore::firePageShowAndPopStateEvents): Moved logic from FrameLoader::didRestoreFromCachedPage() to here.
(WebCore::CachedPage::restore): Modified to call firePageShowAndPopStateEvents().

  • loader/FrameLoader.cpp:

(WebCore::FrameLoader::commitProvisionalLoad): Removed use of NoEventDispatchAssertion RAII object. We
will instantiate it in CachedPage::restore() with a smaller scope.
(WebCore::FrameLoader::didRestoreFromCachedPage): Deleted; moved logic from here to WebCore::firePageShowAndPopStateEvents().

  • loader/FrameLoader.h:
Location:
trunk/Source/WebCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r214388 r214392  
     12017-03-24  Daniel Bates  <dabates@apple.com>
     2
     3        media/restore-from-page-cache.html causes NoEventDispatchAssertion::isEventAllowedInMainThread() assertion failure
     4        https://bugs.webkit.org/show_bug.cgi?id=170087
     5        <rdar://problem/31254822>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Reduce the scope of code that should never dispatch DOM events so as to allow updating contents size
     10        after restoring a page from the page cache.
     11
     12        In r214014 we instantiate a NoEventDispatchAssertion in FrameLoader::commitProvisionalLoad()
     13        around the call to CachedPage::restore() to assert when a DOM event is dispatched during
     14        page restoration as such events can cause re-entrancy into the page cache. As it turns out
     15        it is sufficient to ensure that no DOM events are dispatched after restoring all cached frames
     16        as opposed to after CachedPage::restore() returns.
     17
     18        Also rename Document::enqueue{Pageshow, Popstate}Event() to dispatch{Pageshow, Popstate}Event(),
     19        respectively, since they synchronously dispatch events :(. We hope in the future to make them
     20        asynchronously dispatch events.
     21
     22        * dom/Document.cpp:
     23        (WebCore::Document::implicitClose): Update for renaming.
     24        (WebCore::Document::statePopped): Ditto.
     25        (WebCore::Document::dispatchPageshowEvent): Renamed; formerly named enqueuePageshowEvent().
     26        (WebCore::Document::dispatchPopstateEvent): Renamed; formerly named enqueuePopstateEvent().
     27        (WebCore::Document::enqueuePageshowEvent): Deleted.
     28        (WebCore::Document::enqueuePopstateEvent): Deleted.
     29        * dom/Document.h:
     30        * history/CachedPage.cpp:
     31        (WebCore::firePageShowAndPopStateEvents): Moved logic from FrameLoader::didRestoreFromCachedPage() to here.
     32        (WebCore::CachedPage::restore): Modified to call firePageShowAndPopStateEvents().
     33        * loader/FrameLoader.cpp:
     34        (WebCore::FrameLoader::commitProvisionalLoad): Removed use of NoEventDispatchAssertion RAII object. We
     35        will instantiate it in CachedPage::restore() with a smaller scope.
     36        (WebCore::FrameLoader::didRestoreFromCachedPage): Deleted; moved logic from here to WebCore::firePageShowAndPopStateEvents().
     37        * loader/FrameLoader.h:
     38
    1392017-03-24  Ryan Haddad  <ryanhaddad@apple.com>
    240
  • trunk/Source/WebCore/dom/Document.cpp

    r214388 r214392  
    26452645
    26462646    dispatchWindowLoadEvent();
    2647     enqueuePageshowEvent(PageshowEventNotPersisted);
     2647    dispatchPageshowEvent(PageshowEventNotPersisted);
    26482648    if (m_pendingStateObject)
    2649         enqueuePopstateEvent(WTFMove(m_pendingStateObject));
     2649        dispatchPopstateEvent(WTFMove(m_pendingStateObject));
    26502650
    26512651    if (f)
     
    52365236    // defer firing of popstate until we're in the complete state.
    52375237    if (m_readyState == Complete)
    5238         enqueuePopstateEvent(WTFMove(stateObject));
     5238        dispatchPopstateEvent(WTFMove(stateObject));
    52395239    else
    52405240        m_pendingStateObject = WTFMove(stateObject);
     
    54615461}
    54625462
    5463 void Document::enqueuePageshowEvent(PageshowEventPersistence persisted)
     5463void Document::dispatchPageshowEvent(PageshowEventPersistence persisted)
    54645464{
    54655465    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36334 Pageshow event needs to fire asynchronously.
     
    54725472}
    54735473
    5474 void Document::enqueuePopstateEvent(RefPtr<SerializedScriptValue>&& stateObject)
     5474void Document::dispatchPopstateEvent(RefPtr<SerializedScriptValue>&& stateObject)
    54755475{
    54765476    dispatchWindowEvent(PopStateEvent::create(WTFMove(stateObject), m_domWindow ? m_domWindow->history() : nullptr));
  • trunk/Source/WebCore/dom/Document.h

    r214333 r214392  
    10591059    void enqueueDocumentEvent(Ref<Event>&&);
    10601060    void enqueueOverflowEvent(Ref<Event>&&);
    1061     void enqueuePageshowEvent(PageshowEventPersistence);
     1061    void dispatchPageshowEvent(PageshowEventPersistence);
    10621062    void enqueueHashchangeEvent(const String& oldURL, const String& newURL);
    1063     void enqueuePopstateEvent(RefPtr<SerializedScriptValue>&& stateObject);
     1063    void dispatchPopstateEvent(RefPtr<SerializedScriptValue>&& stateObject);
    10641064    DocumentEventQueue& eventQueue() const final { return m_eventQueue; }
    10651065
  • trunk/Source/WebCore/history/CachedPage.cpp

    r211569 r214392  
    3131#include "FocusController.h"
    3232#include "FrameView.h"
     33#include "HistoryController.h"
     34#include "HistoryItem.h"
    3335#include "MainFrame.h"
     36#include "NoEventDispatchAssertion.h"
    3437#include "Node.h"
    3538#include "Page.h"
     39#include "PageTransitionEvent.h"
    3640#include "Settings.h"
    3741#include "VisitedLinkState.h"
     
    7074}
    7175
     76static void firePageShowAndPopStateEvents(Page& page)
     77{
     78    // Dispatching JavaScript events can cause frame destruction.
     79    auto& mainFrame = page.mainFrame();
     80    Vector<Ref<Frame>> childFrames;
     81    for (auto* child = mainFrame.tree().traverseNextInPostOrderWithWrap(true); child; child = child->tree().traverseNextInPostOrderWithWrap(false))
     82        childFrames.append(*child);
     83
     84    for (auto& child : childFrames) {
     85        if (!child->tree().isDescendantOf(&mainFrame))
     86            continue;
     87        auto* document = child->document();
     88        if (!document)
     89            continue;
     90
     91        // FIXME: Update Page Visibility state here.
     92        // https://bugs.webkit.org/show_bug.cgi?id=116770
     93        document->dispatchPageshowEvent(PageshowEventPersisted);
     94
     95        auto* historyItem = child->loader().history().currentItem();
     96        if (historyItem && historyItem->stateObject())
     97            document->dispatchPopstateEvent(historyItem->stateObject());
     98    }
     99}
     100
    72101void CachedPage::restore(Page& page)
    73102{
     
    76105    ASSERT(!page.subframeCount());
    77106
    78     m_cachedMainFrame->open();
     107    {
     108        // Do not dispatch DOM events as their JavaScript listeners could cause the page to be put
     109        // into the page cache before we have finished restoring it from the page cache.
     110        NoEventDispatchAssertion noEventDispatchAssertion;
     111
     112        m_cachedMainFrame->open();
     113    }
    79114   
    80115    // Restore the focus appearance for the focused element.
     
    117152    }
    118153
     154    firePageShowAndPopStateEvents(page);
     155
    119156    clear();
    120157}
  • trunk/Source/WebCore/loader/FrameLoader.cpp

    r214365 r214392  
    8787#include "MemoryCache.h"
    8888#include "MemoryRelease.h"
    89 #include "NoEventDispatchAssertion.h"
    9089#include "Page.h"
    9190#include "PageCache.h"
     
    18671866        std::optional<HasInsecureContent> hasInsecureContent = cachedPage->cachedMainFrame()->hasInsecureContent();
    18681867
    1869         {
    1870             // Do not dispatch DOM events as their JavaScript listeners could cause the page to be put
    1871             // into the page cache before we have finished restoring it from the page cache.
    1872             NoEventDispatchAssertion assertNoEventDispatch;
    1873 
    1874             // FIXME: This API should be turned around so that we ground CachedPage into the Page.
    1875             cachedPage->restore(*m_frame.page());
    1876         }
     1868        // FIXME: This API should be turned around so that we ground CachedPage into the Page.
     1869        cachedPage->restore(*m_frame.page());
    18771870
    18781871        dispatchDidCommitLoad(hasInsecureContent);
    1879 
    1880         didRestoreFromCachedPage();
    18811872
    18821873#if PLATFORM(IOS)
     
    21102101        window->setStatus(String());
    21112102        window->setDefaultStatus(String());
    2112     }
    2113 }
    2114 
    2115 void FrameLoader::didRestoreFromCachedPage()
    2116 {
    2117     // Dispatching JavaScript events can cause frame destruction.
    2118     auto& mainFrame = m_frame.page()->mainFrame();
    2119     Vector<Ref<Frame>> childFrames;
    2120     for (auto* child = mainFrame.tree().traverseNextInPostOrderWithWrap(true); child; child = child->tree().traverseNextInPostOrderWithWrap(false))
    2121         childFrames.append(*child);
    2122 
    2123     for (auto& child : childFrames) {
    2124         if (!child->tree().isDescendantOf(&mainFrame))
    2125             continue;
    2126         auto* document = child->document();
    2127         if (!document)
    2128             continue;
    2129 
    2130         // FIXME: Update Page Visibility state here.
    2131         // https://bugs.webkit.org/show_bug.cgi?id=116770
    2132         document->enqueuePageshowEvent(PageshowEventPersisted);
    2133 
    2134         auto* historyItem = child->loader().history().currentItem();
    2135         if (historyItem && historyItem->stateObject())
    2136             document->enqueuePopstateEvent(historyItem->stateObject());
    21372103    }
    21382104}
  • trunk/Source/WebCore/loader/FrameLoader.h

    r214194 r214392  
    348348    void closeOldDataSources();
    349349    void willRestoreFromCachedPage();
    350     void didRestoreFromCachedPage();
    351350
    352351    bool shouldReloadToHandleUnreachableURL(DocumentLoader*);
Note: See TracChangeset for help on using the changeset viewer.