diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp
index d7b9ba1ea077..62ef31bd05b7 100644
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -156,24 +156,12 @@ nsHtml5TreeOpExecutor::WillBuildModel(nsDTDMode aDTDMode)
NS_IMETHODIMP
nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated)
{
- if (!aTerminated) {
- // This is needed to avoid unblocking loads too many times on one hand
- // and on the other hand to avoid destroying the frame constructor from
- // within an update batch. See bug 537683.
- EndDocUpdate();
-
- // If the above caused a call to nsIParser::Terminate(), let that call
- // win.
- if (!mParser) {
- return NS_OK;
- }
- }
-
if (mRunsToCompletion) {
return NS_OK;
}
- GetParser()->DropStreamParser();
+ MOZ_RELEASE_ASSERT(!IsInDocUpdate(),
+ "DidBuildModel from inside a doc update.");
// This comes from nsXMLContentSink and nsHTMLContentSink
// If this parser has been marked as broken, treat the end of parse as
@@ -211,6 +199,8 @@ nsHtml5TreeOpExecutor::DidBuildModel(bool aTerminated)
if (mStarted) {
mDocument->EndLoad();
}
+
+ GetParser()->DropStreamParser();
DropParserAndPerfHint();
#ifdef GATHER_DOCWRITE_STATISTICS
printf("UNSAFE SCRIPTS: %d\n", sUnsafeDocWrites);
@@ -482,6 +472,7 @@ nsHtml5TreeOpExecutor::RunFlushLoop()
nsIContent* scriptElement = nullptr;
bool interrupted = false;
+ bool streamEnded = false;
{
// autoFlush clears mOpQueue in its destructor unless
@@ -498,7 +489,7 @@ nsHtml5TreeOpExecutor::RunFlushLoop()
}
MOZ_ASSERT(IsInDocUpdate(),
"Tried to perform tree op outside update batch.");
- nsresult rv = iter->Perform(this, &scriptElement, &interrupted);
+ nsresult rv = iter->Perform(this, &scriptElement, &interrupted, &streamEnded);
if (NS_FAILED(rv)) {
MarkAsBroken(rv);
break;
@@ -525,7 +516,18 @@ nsHtml5TreeOpExecutor::RunFlushLoop()
return;
}
- if (scriptElement) {
+ if (streamEnded) {
+ DidBuildModel(false);
+#ifdef DEBUG
+ if (scriptElement) {
+ nsCOMPtr sele = do_QueryInterface(scriptElement);
+ if (!sele) {
+ MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to script, but SVG wasn't disabled.");
+ }
+ MOZ_ASSERT(sele->IsMalformed(), "Script wasn't marked as malformed.");
+ }
+#endif
+ } else if (scriptElement) {
// must be tail call when mFlushState is eNotFlushing
RunScript(scriptElement);
@@ -578,6 +580,7 @@ nsHtml5TreeOpExecutor::FlushDocumentWrite()
nsIContent* scriptElement = nullptr;
bool interrupted = false;
+ bool streamEnded = false;
{
// autoFlush clears mOpQueue in its destructor.
@@ -595,7 +598,7 @@ nsHtml5TreeOpExecutor::FlushDocumentWrite()
}
NS_ASSERTION(IsInDocUpdate(),
"Tried to perform tree op outside update batch.");
- rv = iter->Perform(this, &scriptElement, &interrupted);
+ rv = iter->Perform(this, &scriptElement, &interrupted, &streamEnded);
if (NS_FAILED(rv)) {
MarkAsBroken(rv);
break;
@@ -609,7 +612,18 @@ nsHtml5TreeOpExecutor::FlushDocumentWrite()
return rv;
}
- if (scriptElement) {
+ if (streamEnded) {
+ DidBuildModel(false);
+#ifdef DEBUG
+ if (scriptElement) {
+ nsCOMPtr sele = do_QueryInterface(scriptElement);
+ if (!sele) {
+ MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to script, but SVG wasn't disabled.");
+ }
+ MOZ_ASSERT(sele->IsMalformed(), "Script wasn't marked as malformed.");
+ }
+#endif
+ } else if (scriptElement) {
// must be tail call when mFlushState is eNotFlushing
RunScript(scriptElement);
}
@@ -687,21 +701,14 @@ nsHtml5TreeOpExecutor::RunScript(nsIContent* aScriptElement)
return;
}
- NS_ASSERTION(aScriptElement, "No script to run");
+ MOZ_ASSERT(mParser, "Trying to run script with a terminated parser.");
+ MOZ_ASSERT(aScriptElement, "No script to run");
nsCOMPtr sele = do_QueryInterface(aScriptElement);
if (!sele) {
MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to script, but SVG wasn't disabled.");
return;
}
- if (!mParser) {
- NS_ASSERTION(sele->IsMalformed(), "Script wasn't marked as malformed.");
- // We got here not because of an end tag but because the tree builder
- // popped an incomplete script element on EOF. Returning here to avoid
- // calling back into mParser anymore.
- return;
- }
-
if (sele->GetScriptDeferred() || sele->GetScriptAsync()) {
DebugOnly block = sele->AttemptToExecute();
NS_ASSERTION(!block, "Defer or async script tried to block.");
diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp
index 85c17b446d59..c1010502a15a 100644
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -811,7 +811,8 @@ nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode)
nsresult
nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
nsIContent** aScriptElement,
- bool* aInterrupted)
+ bool* aInterrupted,
+ bool* aStreamEnded)
{
switch(mOpCode) {
case eTreeOpUninitialized: {
@@ -1034,7 +1035,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
return NS_OK;
}
case eTreeOpStreamEnded: {
- aBuilder->DidBuildModel(false); // this causes a notifications flush anyway
+ *aStreamEnded = true;
return NS_OK;
}
case eTreeOpSetStyleLineNumber: {
diff --git a/parser/html/nsHtml5TreeOperation.h b/parser/html/nsHtml5TreeOperation.h
index b8acf2565fdc..3d9b7088765a 100644
--- a/parser/html/nsHtml5TreeOperation.h
+++ b/parser/html/nsHtml5TreeOperation.h
@@ -546,7 +546,8 @@ class nsHtml5TreeOperation final {
nsresult Perform(nsHtml5TreeOpExecutor* aBuilder,
nsIContent** aScriptElement,
- bool* aInterrupted);
+ bool* aInterrupted,
+ bool* aStreamEnded);
private:
nsHtml5TreeOperation(const nsHtml5TreeOperation&) = delete;