Bug 1387243 Part 1: Split nsDocument::EndLoad into a part that runs unconditionally, and a part that runs only when there is a matching BeginLoad call. draft
authorBrad Werth <bwerth@mozilla.com>
Thu, 03 Aug 2017 16:27:22 -0700
changeset 644327 9a904a5145b8db548554822d88977ab07d9614c4
parent 644286 ef58f965a5b562ee34b4fb4e72cc07adfd1304d2
child 725577 9d3bd35f3dccae104df0335502c9be76c61b2338
push id73401
push userbwerth@mozilla.com
push dateThu, 10 Aug 2017 20:42:58 +0000
bugs1387243
milestone57.0a1
Bug 1387243 Part 1: Split nsDocument::EndLoad into a part that runs unconditionally, and a part that runs only when there is a matching BeginLoad call. MozReview-Commit-ID: 8Pn6i2f0cez
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1348,16 +1348,17 @@ nsIDocument::nsIDocument()
     mGetUserFontSetCalled(false),
     mPostedFlushUserFontSet(false),
     mDidFireDOMContentLoaded(true),
     mHasScrollLinkedEffect(false),
     mFrameRequestCallbacksScheduled(false),
     mIsTopLevelContentDocument(false),
     mIsContentDocument(false),
     mMightHaveStaleServoData(false),
+    mDidCallBeginLoad(false),
     mIsScopedStyleEnabled(eScopedStyle_Unknown),
     mCompatMode(eCompatibility_FullStandards),
     mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
     mStyleBackendType(StyleBackendType::None),
 #ifdef MOZILLA_INTERNAL_API
     mVisibilityState(dom::VisibilityState::Hidden),
 #else
     mDummy(0),
@@ -5156,16 +5157,19 @@ nsDocument::EndUpdate(nsUpdateType aUpda
   MaybeEndOutermostXBLUpdate();
 
   MaybeInitializeFinalizeFrameLoaders();
 }
 
 void
 nsDocument::BeginLoad()
 {
+  MOZ_ASSERT(!mDidCallBeginLoad);
+  mDidCallBeginLoad = true;
+
   // Block onload here to prevent having to deal with blocking and
   // unblocking it while we know the document is loading.
   BlockOnload();
   mDidFireDOMContentLoaded = false;
   BlockDOMContentLoaded();
 
   if (mScriptLoader) {
     mScriptLoader->BeginDeferringScripts();
@@ -5414,26 +5418,44 @@ nsDocument::DispatchContentLoadedEvents(
   }
 
   UnblockOnload(true);
 }
 
 void
 nsDocument::EndLoad()
 {
+  // EndLoad may have been called without a matching call to BeginLoad, in the
+  // case of a failed parse (for example, due to timeout). In such a case, we
+  // still want to execute part of this code to do appropriate cleanup, but we
+  // gate part of it because it is intended to match 1-for-1 with calls to
+  // BeginLoad. We have an explicit flag bit for this purpose, since it's
+  // complicated and error prone to derive this condition from other related
+  // flags that can be manipulated outside of a BeginLoad/EndLoad pair.
+
+  // Part 1: Code that always executes to cleanup end of parsing, whether
+  // that parsing was successful or not.
+
   // Drop the ref to our parser, if any, but keep hold of the sink so that we
   // can flush it from FlushPendingNotifications as needed.  We might have to
   // do that to get a StartLayout() to happen.
   if (mParser) {
     mWeakSink = do_GetWeakReference(mParser->GetContentSink());
     mParser = nullptr;
   }
 
   NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
 
+  // Part 2: Code that only executes when this EndLoad matches a BeginLoad.
+
+  if (!mDidCallBeginLoad) {
+    return;
+  }
+  mDidCallBeginLoad = false;
+
   UnblockDOMContentLoaded();
 }
 
 void
 nsDocument::UnblockDOMContentLoaded()
 {
   MOZ_ASSERT(mBlockDOMContentLoaded);
   if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) {
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3301,16 +3301,19 @@ protected:
   bool mIsTopLevelContentDocument : 1;
 
   bool mIsContentDocument : 1;
 
   // True if there may be Servo element data on Elements in the document that
   // were created for a pres shell that no longer exists.
   bool mMightHaveStaleServoData : 1;
 
+  // True if we have called BeginLoad and are expecting a paired EndLoad call.
+  bool mDidCallBeginLoad : 1;
+
   // Whether <style scoped> support is enabled in this document.
   enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
   unsigned int mIsScopedStyleEnabled : 2;
 
   // Compatibility mode
   nsCompatibility mCompatMode;
 
   // Our readyState