Backed out changeset aa30bc1b369b (bug 1763076) for causing assertion failure in parser/html/nsHtml5TreeOpExecutor.cpp CLOSED TREE

This commit is contained in:
Molnar Sandor 2022-04-19 14:41:03 +03:00
parent e70200b735
commit 622b026960
16 changed files with 81 additions and 293 deletions

View file

@ -19,11 +19,8 @@ class nsAHtml5TreeOpSink {
/** /**
* Flush the operations from the tree operations from the argument * Flush the operations from the tree operations from the argument
* queue into this sink unconditionally. * queue into this sink unconditionally.
*
* Returns `true` on success and `false` on OOM.
*/ */
[[nodiscard]] virtual bool MoveOpsFrom( virtual void MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) = 0;
nsTArray<nsHtml5TreeOperation>& aOpQueue) = 0;
}; };
#endif /* nsAHtml5TreeOpSink_h */ #endif /* nsAHtml5TreeOpSink_h */

View file

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsHtml5Highlighter.h" #include "nsHtml5Highlighter.h"
#include "ErrorList.h"
#include "nsDebug.h" #include "nsDebug.h"
#include "nsHtml5AttributeName.h" #include "nsHtml5AttributeName.h"
#include "nsHtml5Tokenizer.h" #include "nsHtml5Tokenizer.h"
@ -463,7 +462,7 @@ int32_t nsHtml5Highlighter::Transition(int32_t aState, bool aReconsume,
return aState; return aState;
} }
[[nodiscard]] bool nsHtml5Highlighter::End() { void nsHtml5Highlighter::End() {
switch (mState) { switch (mState) {
case nsHtml5Tokenizer::COMMENT_END: case nsHtml5Tokenizer::COMMENT_END:
case nsHtml5Tokenizer::COMMENT_END_BANG: case nsHtml5Tokenizer::COMMENT_END_BANG:
@ -502,7 +501,7 @@ int32_t nsHtml5Highlighter::Transition(int32_t aState, bool aReconsume,
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed."); NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(mozilla::AsVariant(opStreamEnded())); treeOp->Init(mozilla::AsVariant(opStreamEnded()));
return FlushOps().isOk(); FlushOps();
} }
void nsHtml5Highlighter::SetBuffer(nsHtml5UTF16Buffer* aBuffer) { void nsHtml5Highlighter::SetBuffer(nsHtml5UTF16Buffer* aBuffer) {
@ -619,19 +618,10 @@ void nsHtml5Highlighter::FlushCurrent() {
FlushChars(); FlushChars();
} }
bool nsHtml5Highlighter::ShouldFlushOps() { bool nsHtml5Highlighter::FlushOps() {
// Arbitrary threshold that doesn't have an exact justification.
// The general idea is to flush much, much sooner than reaching
// the maximum size of `nsTArray`.
return mOpQueue.Length() > 100000;
}
mozilla::Result<bool, nsresult> nsHtml5Highlighter::FlushOps() {
bool hasOps = !mOpQueue.IsEmpty(); bool hasOps = !mOpQueue.IsEmpty();
if (hasOps) { if (hasOps) {
if (!mOpSink->MoveOpsFrom(mOpQueue)) { mOpSink->MoveOpsFrom(mOpQueue);
return Err(NS_ERROR_OUT_OF_MEMORY);
}
} }
return hasOps; return hasOps;
} }

View file

@ -62,10 +62,8 @@ class nsHtml5Highlighter {
/** /**
* Report end of file. * Report end of file.
*
* Returns `true` normally and `false` on OOM.
*/ */
[[nodiscard]] bool End(); void End();
/** /**
* Set the current buffer being tokenized * Set the current buffer being tokenized
@ -79,21 +77,12 @@ class nsHtml5Highlighter {
*/ */
void DropBuffer(int32_t aPos); void DropBuffer(int32_t aPos);
/**
* Query whether there are some many ops in the queue
* that they should be flushed now.
*
* @return true if FlushOps() should be called now
*/
bool ShouldFlushOps();
/** /**
* Flush the tree ops into the sink. * Flush the tree ops into the sink.
* *
* @return Ok(true) if there were ops to flush, Ok(false) * @return true if there were ops to flush
* if there were no ops to flush and Err() on OOM.
*/ */
mozilla::Result<bool, nsresult> FlushOps(); bool FlushOps();
/** /**
* Linkify the current attribute value if the attribute name is one of * Linkify the current attribute value if the attribute name is one of

View file

@ -332,10 +332,7 @@ nsresult nsHtml5Parser::Parse(const nsAString& aSourceBuffer, void* aKey,
} }
if (mTreeBuilder->HasScript()) { if (mTreeBuilder->HasScript()) {
auto r = mTreeBuilder->Flush(); // Move ops to the executor mTreeBuilder->Flush(); // Move ops to the executor
if (r.isErr()) {
return executor->MarkAsBroken(r.unwrapErr());
}
rv = executor->FlushDocumentWrite(); // run the ops rv = executor->FlushDocumentWrite(); // run the ops
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Flushing tree ops can cause all sorts of things. // Flushing tree ops can cause all sorts of things.
@ -395,10 +392,7 @@ nsresult nsHtml5Parser::Parse(const nsAString& aSourceBuffer, void* aKey,
NS_ASSERTION(!stackBuffer.hasMore(), NS_ASSERTION(!stackBuffer.hasMore(),
"Buffer wasn't tokenized to completion?"); "Buffer wasn't tokenized to completion?");
// Scripting semantics require a forced tree builder flush here // Scripting semantics require a forced tree builder flush here
auto r = mTreeBuilder->Flush(); // Move ops to the executor mTreeBuilder->Flush(); // Move ops to the executor
if (r.isErr()) {
return executor->MarkAsBroken(r.unwrapErr());
}
rv = executor->FlushDocumentWrite(); // run the ops rv = executor->FlushDocumentWrite(); // run the ops
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} else if (stackBuffer.hasMore()) { } else if (stackBuffer.hasMore()) {
@ -448,10 +442,7 @@ nsresult nsHtml5Parser::Parse(const nsAString& aSourceBuffer, void* aKey,
} }
} }
auto r = mDocWriteSpeculativeTreeBuilder->Flush(); mDocWriteSpeculativeTreeBuilder->Flush();
if (r.isErr()) {
return executor->MarkAsBroken(r.unwrapErr());
}
mDocWriteSpeculativeTreeBuilder->DropHandles(); mDocWriteSpeculativeTreeBuilder->DropHandles();
executor->FlushSpeculativeLoads(); executor->FlushSpeculativeLoads();
} }
@ -557,10 +548,7 @@ nsresult nsHtml5Parser::ParseUntilBlocked() {
mTreeBuilder->StreamEnded(); mTreeBuilder->StreamEnded();
} }
} }
auto r = mTreeBuilder->Flush(); mTreeBuilder->Flush();
if (r.isErr()) {
return mExecutor->MarkAsBroken(r.unwrapErr());
}
mExecutor->FlushDocumentWrite(); mExecutor->FlushDocumentWrite();
// The below call does memory cleanup, so call it even if the // The below call does memory cleanup, so call it even if the
// parser has been marked as broken. // parser has been marked as broken.
@ -573,20 +561,14 @@ nsresult nsHtml5Parser::ParseUntilBlocked() {
if (GetStreamParser()) { if (GetStreamParser()) {
if (mReturnToStreamParserPermitted && if (mReturnToStreamParserPermitted &&
!mExecutor->IsScriptExecuting()) { !mExecutor->IsScriptExecuting()) {
auto r = mTreeBuilder->Flush(); mTreeBuilder->Flush();
if (r.isErr()) {
return mExecutor->MarkAsBroken(r.unwrapErr());
}
mReturnToStreamParserPermitted = false; mReturnToStreamParserPermitted = false;
GetStreamParser()->ContinueAfterScriptsOrEncodingCommitment( GetStreamParser()->ContinueAfterScriptsOrEncodingCommitment(
mTokenizer.get(), mTreeBuilder.get(), mLastWasCR); mTokenizer.get(), mTreeBuilder.get(), mLastWasCR);
} }
} else { } else {
// Script-created parser // Script-created parser
auto r = mTreeBuilder->Flush(); mTreeBuilder->Flush();
if (r.isErr()) {
return mExecutor->MarkAsBroken(r.unwrapErr());
}
// No need to flush the executor, because the executor is already // No need to flush the executor, because the executor is already
// in a flush // in a flush
NS_ASSERTION(mExecutor->IsInFlushLoop(), NS_ASSERTION(mExecutor->IsInFlushLoop(),
@ -622,10 +604,7 @@ nsresult nsHtml5Parser::ParseUntilBlocked() {
mRootContextLineNumber = mTokenizer->getLineNumber(); mRootContextLineNumber = mTokenizer->getLineNumber();
} }
if (mTreeBuilder->HasScript()) { if (mTreeBuilder->HasScript()) {
auto r = mTreeBuilder->Flush(); mTreeBuilder->Flush();
if (r.isErr()) {
return mExecutor->MarkAsBroken(r.unwrapErr());
}
rv = mExecutor->FlushDocumentWrite(); rv = mExecutor->FlushDocumentWrite();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }

View file

@ -20,11 +20,10 @@ nsHtml5Speculation::~nsHtml5Speculation() {
MOZ_COUNT_DTOR(nsHtml5Speculation); MOZ_COUNT_DTOR(nsHtml5Speculation);
} }
[[nodiscard]] bool nsHtml5Speculation::MoveOpsFrom( void nsHtml5Speculation::MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) {
nsTArray<nsHtml5TreeOperation>& aOpQueue) { mOpQueue.AppendElements(std::move(aOpQueue));
return !!mOpQueue.AppendElements(std::move(aOpQueue), mozilla::fallible_t());
} }
[[nodiscard]] bool nsHtml5Speculation::FlushToSink(nsAHtml5TreeOpSink* aSink) { void nsHtml5Speculation::FlushToSink(nsAHtml5TreeOpSink* aSink) {
return aSink->MoveOpsFrom(mOpQueue); aSink->MoveOpsFrom(mOpQueue);
} }

View file

@ -33,10 +33,9 @@ class nsHtml5Speculation final : public nsAHtml5TreeOpSink {
* Flush the operations from the tree operations from the argument * Flush the operations from the tree operations from the argument
* queue unconditionally. * queue unconditionally.
*/ */
[[nodiscard]] virtual bool MoveOpsFrom( virtual void MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) override;
nsTArray<nsHtml5TreeOperation>& aOpQueue) override;
[[nodiscard]] bool FlushToSink(nsAHtml5TreeOpSink* aSink); void FlushToSink(nsAHtml5TreeOpSink* aSink);
private: private:
/** /**

View file

@ -12,7 +12,6 @@
#include <new> #include <new>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "ErrorList.h"
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
#include "js/GCAPI.h" #include "js/GCAPI.h"
#include "mozilla/ArrayIterator.h" #include "mozilla/ArrayIterator.h"
@ -776,15 +775,9 @@ nsresult nsHtml5StreamParser::SniffStreamBytes(Span<const uint8_t> aFromSegment,
MOZ_ASSERT(mLookingForMetaCharset); MOZ_ASSERT(mLookingForMetaCharset);
if (mMode == VIEW_SOURCE_HTML) { if (mMode == VIEW_SOURCE_HTML) {
auto r = mTokenizer->FlushViewSource(); mTokenizer->FlushViewSource();
if (r.isErr()) {
return r.unwrapErr();
}
}
auto r = mTreeBuilder->Flush();
if (r.isErr()) {
return r.unwrapErr();
} }
mTreeBuilder->Flush();
// Encoding committer flushes the ops on the main thread. // Encoding committer flushes the ops on the main thread.
mozilla::MutexAutoLock speculationAutoLock(mSpeculationMutex); mozilla::MutexAutoLock speculationAutoLock(mSpeculationMutex);
@ -930,16 +923,10 @@ nsresult nsHtml5StreamParser::WriteStreamBytes(
mCharsetSource = source; mCharsetSource = source;
if (encoding != mEncoding) { if (encoding != mEncoding) {
mEncoding = encoding; mEncoding = encoding;
nsresult rv = ReDecodeLocalFile(); ReDecodeLocalFile();
if (NS_FAILED(rv)) {
return rv;
}
} else { } else {
MOZ_ASSERT(mEncoding == UTF_8_ENCODING); MOZ_ASSERT(mEncoding == UTF_8_ENCODING);
nsresult rv = CommitLocalFileToEncoding(); CommitLocalFileToEncoding();
if (NS_FAILED(rv)) {
return rv;
}
} }
} }
return NS_OK; return NS_OK;
@ -947,7 +934,7 @@ nsresult nsHtml5StreamParser::WriteStreamBytes(
} }
} }
[[nodiscard]] nsresult nsHtml5StreamParser::ReDecodeLocalFile() { void nsHtml5StreamParser::ReDecodeLocalFile() {
MOZ_ASSERT(mDecodingLocalFileWithoutTokenizing && !mLookingForMetaCharset); MOZ_ASSERT(mDecodingLocalFileWithoutTokenizing && !mLookingForMetaCharset);
MOZ_ASSERT(mFirstBufferOfMetaScan); MOZ_ASSERT(mFirstBufferOfMetaScan);
MOZ_ASSERT(mCharsetSource == kCharsetFromFinalAutoDetectionFile || MOZ_ASSERT(mCharsetSource == kCharsetFromFinalAutoDetectionFile ||
@ -981,19 +968,12 @@ nsresult nsHtml5StreamParser::WriteStreamBytes(
} }
if (mMode == VIEW_SOURCE_HTML) { if (mMode == VIEW_SOURCE_HTML) {
auto r = mTokenizer->FlushViewSource(); mTokenizer->FlushViewSource();
if (r.isErr()) {
return r.unwrapErr();
} }
} mTreeBuilder->Flush();
auto r = mTreeBuilder->Flush();
if (r.isErr()) {
return r.unwrapErr();
}
return NS_OK;
} }
[[nodiscard]] nsresult nsHtml5StreamParser::CommitLocalFileToEncoding() { void nsHtml5StreamParser::CommitLocalFileToEncoding() {
MOZ_ASSERT(mDecodingLocalFileWithoutTokenizing && !mLookingForMetaCharset); MOZ_ASSERT(mDecodingLocalFileWithoutTokenizing && !mLookingForMetaCharset);
MOZ_ASSERT(mFirstBufferOfMetaScan); MOZ_ASSERT(mFirstBufferOfMetaScan);
mDecodingLocalFileWithoutTokenizing = false; mDecodingLocalFileWithoutTokenizing = false;
@ -1019,16 +999,9 @@ nsresult nsHtml5StreamParser::WriteStreamBytes(
mForceAutoDetection = false; // To stop feeding the detector mForceAutoDetection = false; // To stop feeding the detector
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource, true); mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource, true);
if (mMode == VIEW_SOURCE_HTML) { if (mMode == VIEW_SOURCE_HTML) {
auto r = mTokenizer->FlushViewSource(); mTokenizer->FlushViewSource();
if (r.isErr()) {
return r.unwrapErr();
} }
} mTreeBuilder->Flush();
auto r = mTreeBuilder->Flush();
if (r.isErr()) {
return r.unwrapErr();
}
return NS_OK;
} }
class MaybeRunCollector : public Runnable { class MaybeRunCollector : public Runnable {
@ -1136,10 +1109,7 @@ nsresult nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest) {
mTemplatePushedOrHeadPopped); // Needed to force 1024-byte sniffing mTemplatePushedOrHeadPopped); // Needed to force 1024-byte sniffing
// Flush the ops to put them where ContinueAfterScriptsOrEncodingCommitment // Flush the ops to put them where ContinueAfterScriptsOrEncodingCommitment
// can find them. // can find them.
auto r = mTreeBuilder->Flush(); mTreeBuilder->Flush();
if (r.isErr()) {
return mExecutor->MarkAsBroken(r.unwrapErr());
}
} else if (mMode == VIEW_SOURCE_PLAIN) { } else if (mMode == VIEW_SOURCE_PLAIN) {
nsAutoString viewSourceTitle; nsAutoString viewSourceTitle;
CopyUTF8toUTF16(mViewSourceTitle, viewSourceTitle); CopyUTF8toUTF16(mViewSourceTitle, viewSourceTitle);
@ -1150,10 +1120,7 @@ nsresult nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest) {
mTemplatePushedOrHeadPopped); // Needed to force 1024-byte sniffing mTemplatePushedOrHeadPopped); // Needed to force 1024-byte sniffing
// Flush the ops to put them where ContinueAfterScriptsOrEncodingCommitment // Flush the ops to put them where ContinueAfterScriptsOrEncodingCommitment
// can find them. // can find them.
auto r = mTreeBuilder->Flush(); mTreeBuilder->Flush();
if (r.isErr()) {
return mExecutor->MarkAsBroken(r.unwrapErr());
}
} else if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) { } else if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
// Generate and flush the View Source document up to and including the // Generate and flush the View Source document up to and including the
// pre element start. // pre element start.
@ -1163,10 +1130,7 @@ nsresult nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest) {
} }
// Flush the ops to put them where ContinueAfterScriptsOrEncodingCommitment // Flush the ops to put them where ContinueAfterScriptsOrEncodingCommitment
// can find them. // can find them.
auto r = mTokenizer->FlushViewSource(); mTokenizer->FlushViewSource();
if (r.isErr()) {
return mExecutor->MarkAsBroken(r.unwrapErr());
}
} }
/* /*
@ -1292,11 +1256,7 @@ void nsHtml5StreamParser::DoStopRequest() {
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource, false); mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource, false);
for (auto&& buffer : mBufferedBytes) { for (auto&& buffer : mBufferedBytes) {
nsresult rv = WriteStreamBytes(buffer); Unused << WriteStreamBytes(buffer);
if (NS_FAILED(rv)) {
MarkAsBroken(rv);
return;
}
} }
} else if (!mUnicodeDecoder) { } else if (!mUnicodeDecoder) {
nsresult rv; nsresult rv;
@ -1356,20 +1316,12 @@ void nsHtml5StreamParser::DoStopRequest() {
mCharsetSource = source; mCharsetSource = source;
if (encoding != mEncoding) { if (encoding != mEncoding) {
mEncoding = encoding; mEncoding = encoding;
nsresult rv = ReDecodeLocalFile(); ReDecodeLocalFile();
if (NS_FAILED(rv)) {
MarkAsBroken(rv);
return;
}
DoStopRequest(); DoStopRequest();
return; return;
} }
MOZ_ASSERT(mEncoding == UTF_8_ENCODING); MOZ_ASSERT(mEncoding == UTF_8_ENCODING);
nsresult rv = CommitLocalFileToEncoding(); CommitLocalFileToEncoding();
if (NS_FAILED(rv)) {
MarkAsBroken(rv);
return;
}
} }
break; break;
} }
@ -1781,23 +1733,6 @@ void nsHtml5StreamParser::PostLoadFlusher() {
if (NS_FAILED(DispatchToMain(runnable.forget()))) { if (NS_FAILED(DispatchToMain(runnable.forget()))) {
NS_WARNING("failed to dispatch load flush event"); NS_WARNING("failed to dispatch load flush event");
} }
if ((mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) &&
mTokenizer->ShouldFlushViewSource()) {
auto r = mTreeBuilder->Flush(); // delete useless ops
MOZ_ASSERT(r.isOk(), "Should have null sink with View Source");
r = mTokenizer->FlushViewSource();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return;
}
if (r.unwrap()) {
nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
if (NS_FAILED(DispatchToMain(runnable.forget()))) {
NS_WARNING("failed to dispatch executor flush event");
}
}
}
} }
void nsHtml5StreamParser::FlushTreeOpsAndDisarmTimer() { void nsHtml5StreamParser::FlushTreeOpsAndDisarmTimer() {
@ -1812,15 +1747,9 @@ void nsHtml5StreamParser::FlushTreeOpsAndDisarmTimer() {
mFlushTimerArmed = false; mFlushTimerArmed = false;
} }
if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) { if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
auto r = mTokenizer->FlushViewSource(); mTokenizer->FlushViewSource();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
}
}
auto r = mTreeBuilder->Flush();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
} }
mTreeBuilder->Flush();
nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher); nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
if (NS_FAILED(DispatchToMain(runnable.forget()))) { if (NS_FAILED(DispatchToMain(runnable.forget()))) {
NS_WARNING("failed to dispatch executor flush event"); NS_WARNING("failed to dispatch executor flush event");
@ -2235,17 +2164,9 @@ bool nsHtml5StreamParser::ProcessLookingForMetaCharset(bool aEof) {
mCharsetSource = mEncodingSwitchSource; mCharsetSource = mEncodingSwitchSource;
if (mMode == VIEW_SOURCE_HTML) { if (mMode == VIEW_SOURCE_HTML) {
auto r = mTokenizer->FlushViewSource(); mTokenizer->FlushViewSource();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return false;
}
}
auto r = mTreeBuilder->Flush();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return false;
} }
mTreeBuilder->Flush();
if (mEncoding != needsEncodingSwitchTo) { if (mEncoding != needsEncodingSwitchTo) {
// Speculation failed // Speculation failed
@ -2284,11 +2205,7 @@ bool nsHtml5StreamParser::ProcessLookingForMetaCharset(bool aEof) {
"Must have set mLookingForMetaCharset to false to report data " "Must have set mLookingForMetaCharset to false to report data "
"to dev tools below"); "to dev tools below");
for (auto&& buffer : mBufferedBytes) { for (auto&& buffer : mBufferedBytes) {
nsresult rv = WriteStreamBytes(buffer); WriteStreamBytes(buffer);
if (NS_FAILED(rv)) {
MarkAsBroken(rv);
return false;
}
} }
} }
} else if (!mLookingForMetaCharset && !mDecodingLocalFileWithoutTokenizing) { } else if (!mLookingForMetaCharset && !mDecodingLocalFileWithoutTokenizing) {
@ -2313,17 +2230,9 @@ bool nsHtml5StreamParser::ProcessLookingForMetaCharset(bool aEof) {
mBufferedBytes.Clear(); mBufferedBytes.Clear();
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource, true); mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource, true);
if (mMode == VIEW_SOURCE_HTML) { if (mMode == VIEW_SOURCE_HTML) {
auto r = mTokenizer->FlushViewSource(); mTokenizer->FlushViewSource();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return false;
}
}
auto r = mTreeBuilder->Flush();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return false;
} }
mTreeBuilder->Flush();
} }
} }
return rewound; return rewound;
@ -2446,9 +2355,7 @@ void nsHtml5StreamParser::ParseAvailableData() {
} else { } else {
mTreeBuilder->StreamEnded(); mTreeBuilder->StreamEnded();
if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) { if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
if (!mTokenizer->EndViewSource()) { mTokenizer->EndViewSource();
MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
}
} }
} }
} }
@ -2489,17 +2396,9 @@ void nsHtml5StreamParser::ParseAvailableData() {
speculation->GetStartLineNumber()); speculation->GetStartLineNumber());
if (mLookingForMetaCharset) { if (mLookingForMetaCharset) {
if (mMode == VIEW_SOURCE_HTML) { if (mMode == VIEW_SOURCE_HTML) {
auto r = mTokenizer->FlushViewSource(); mTokenizer->FlushViewSource();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return;
}
}
auto r = mTreeBuilder->Flush();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return;
} }
mTreeBuilder->Flush();
} else { } else {
FlushTreeOpsAndDisarmTimer(); FlushTreeOpsAndDisarmTimer();
} }
@ -2559,10 +2458,7 @@ void nsHtml5StreamParser::ContinueAfterScriptsOrEncodingCommitment(
// XML View Source never needs this kind of encoding commitment. // XML View Source never needs this kind of encoding commitment.
// We need to take the ops here so that they end up in the queue before // We need to take the ops here so that they end up in the queue before
// the ops that we take from a speculation later in this method. // the ops that we take from a speculation later in this method.
if (!mExecutor->TakeOpsFromStage()) { mExecutor->TakeOpsFromStage();
mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
return;
}
} else { } else {
#ifdef DEBUG #ifdef DEBUG
mExecutor->AssertStageEmpty(); mExecutor->AssertStageEmpty();
@ -2599,10 +2495,7 @@ void nsHtml5StreamParser::ContinueAfterScriptsOrEncodingCommitment(
if (mSpeculations.Length() > 1) { if (mSpeculations.Length() > 1) {
// the first speculation isn't the current speculation, so there's // the first speculation isn't the current speculation, so there's
// no need to bother the parser thread. // no need to bother the parser thread.
if (!speculation->FlushToSink(mExecutor)) { speculation->FlushToSink(mExecutor);
mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
return;
}
MOZ_ASSERT(!mExecutor->IsScriptExecuting(), MOZ_ASSERT(!mExecutor->IsScriptExecuting(),
"ParseUntilBlocked() was supposed to ensure we don't come " "ParseUntilBlocked() was supposed to ensure we don't come "
"here when scripts are executing."); "here when scripts are executing.");
@ -2677,10 +2570,7 @@ void nsHtml5StreamParser::ContinueAfterScriptsOrEncodingCommitment(
} else { } else {
// We've got a successful speculation and at least a moment ago it was // We've got a successful speculation and at least a moment ago it was
// the current speculation // the current speculation
if (!mSpeculations.ElementAt(0)->FlushToSink(mExecutor)) { mSpeculations.ElementAt(0)->FlushToSink(mExecutor);
mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
return;
}
MOZ_ASSERT(!mExecutor->IsScriptExecuting(), MOZ_ASSERT(!mExecutor->IsScriptExecuting(),
"ParseUntilBlocked() was supposed to ensure we don't come " "ParseUntilBlocked() was supposed to ensure we don't come "
"here when scripts are executing."); "here when scripts are executing.");
@ -2699,11 +2589,7 @@ void nsHtml5StreamParser::ContinueAfterScriptsOrEncodingCommitment(
// any pending ops straight to the executor, because otherwise // any pending ops straight to the executor, because otherwise
// they remain unflushed until we get more data from the network. // they remain unflushed until we get more data from the network.
mTreeBuilder->SetOpSink(mExecutor); mTreeBuilder->SetOpSink(mExecutor);
auto r = mTreeBuilder->Flush(true); mTreeBuilder->Flush(true);
if (r.isErr()) {
mExecutor->MarkAsBroken(r.unwrapErr());
return;
}
mTreeBuilder->SetOpSink(mExecutor->GetStage()); mTreeBuilder->SetOpSink(mExecutor->GetStage());
} }
mExecutor->StartReadingFromStage(); mExecutor->StartReadingFromStage();
@ -2799,17 +2685,8 @@ void nsHtml5StreamParser::TimerFlush() {
} }
if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) { if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
auto r = mTreeBuilder->Flush(); // delete useless ops mTreeBuilder->Flush(); // delete useless ops
if (r.isErr()) { if (mTokenizer->FlushViewSource()) {
MarkAsBroken(r.unwrapErr());
return;
}
r = mTokenizer->FlushViewSource();
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return;
}
if (r.unwrap()) {
nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher); nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
if (NS_FAILED(DispatchToMain(runnable.forget()))) { if (NS_FAILED(DispatchToMain(runnable.forget()))) {
NS_WARNING("failed to dispatch executor flush event"); NS_WARNING("failed to dispatch executor flush event");
@ -2818,12 +2695,7 @@ void nsHtml5StreamParser::TimerFlush() {
} else { } else {
// we aren't speculating and we don't know when new data is // we aren't speculating and we don't know when new data is
// going to arrive. Send data to the main thread. // going to arrive. Send data to the main thread.
auto r = mTreeBuilder->Flush(true); if (mTreeBuilder->Flush(true)) {
if (r.isErr()) {
MarkAsBroken(r.unwrapErr());
return;
}
if (r.unwrap()) {
nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher); nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
if (NS_FAILED(DispatchToMain(runnable.forget()))) { if (NS_FAILED(DispatchToMain(runnable.forget()))) {
NS_WARNING("failed to dispatch executor flush event"); NS_WARNING("failed to dispatch executor flush event");
@ -2838,12 +2710,8 @@ void nsHtml5StreamParser::MarkAsBroken(nsresult aRv) {
Terminate(); Terminate();
mTreeBuilder->MarkAsBroken(aRv); mTreeBuilder->MarkAsBroken(aRv);
auto r = mTreeBuilder->Flush(false); mozilla::DebugOnly<bool> hadOps = mTreeBuilder->Flush(false);
if (r.isOk()) { MOZ_ASSERT(hadOps, "Should have had the markAsBroken op!");
MOZ_ASSERT(r.unwrap(), "Should have had the markAsBroken op!");
} else {
MOZ_CRASH("OOM prevents propagation of OOM state");
}
nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher); nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
if (NS_FAILED(DispatchToMain(runnable.forget()))) { if (NS_FAILED(DispatchToMain(runnable.forget()))) {
NS_WARNING("failed to dispatch executor flush event"); NS_WARNING("failed to dispatch executor flush event");

View file

@ -412,13 +412,13 @@ class nsHtml5StreamParser final : public nsISupports {
* to UTF-8 as the non-speculative encoding and start processing * to UTF-8 as the non-speculative encoding and start processing
* the decoded data. * the decoded data.
*/ */
[[nodiscard]] nsresult CommitLocalFileToEncoding(); void CommitLocalFileToEncoding();
/** /**
* When speculatively decoding from file: URL as UTF-8, redecode * When speculatively decoding from file: URL as UTF-8, redecode
* using fallback and then continue normally with the fallback. * using fallback and then continue normally with the fallback.
*/ */
[[nodiscard]] nsresult ReDecodeLocalFile() REQUIRES(mTokenizerMutex); void ReDecodeLocalFile() REQUIRES(mTokenizerMutex);
/** /**
* Potentially guess the encoding using mozilla::EncodingDetector. * Potentially guess the encoding using mozilla::EncodingDetector.

View file

@ -82,13 +82,7 @@ void nsHtml5Tokenizer::EnableViewSource(nsHtml5Highlighter* aHighlighter) {
mViewSource = WrapUnique(aHighlighter); mViewSource = WrapUnique(aHighlighter);
} }
bool nsHtml5Tokenizer::ShouldFlushViewSource() { bool nsHtml5Tokenizer::FlushViewSource() { return mViewSource->FlushOps(); }
return mViewSource->ShouldFlushOps();
}
mozilla::Result<bool, nsresult> nsHtml5Tokenizer::FlushViewSource() {
return mViewSource->FlushOps();
}
void nsHtml5Tokenizer::StartViewSource(const nsAutoString& aTitle) { void nsHtml5Tokenizer::StartViewSource(const nsAutoString& aTitle) {
mViewSource->Start(aTitle); mViewSource->Start(aTitle);
@ -98,9 +92,7 @@ void nsHtml5Tokenizer::StartViewSourceCharacters() {
mViewSource->StartCharacters(); mViewSource->StartCharacters();
} }
[[nodiscard]] bool nsHtml5Tokenizer::EndViewSource() { void nsHtml5Tokenizer::EndViewSource() { mViewSource->End(); }
return mViewSource->End();
}
void nsHtml5Tokenizer::SetViewSourceOpSink(nsAHtml5TreeOpSink* aOpSink) { void nsHtml5Tokenizer::SetViewSourceOpSink(nsAHtml5TreeOpSink* aOpSink) {
mViewSource->SetOpSink(aOpSink); mViewSource->SetOpSink(aOpSink);

View file

@ -34,15 +34,13 @@ void StartPlainText();
void EnableViewSource(nsHtml5Highlighter* aHighlighter); void EnableViewSource(nsHtml5Highlighter* aHighlighter);
bool ShouldFlushViewSource(); bool FlushViewSource();
mozilla::Result<bool, nsresult> FlushViewSource();
void StartViewSource(const nsAutoString& aTitle); void StartViewSource(const nsAutoString& aTitle);
void StartViewSourceCharacters(); void StartViewSourceCharacters();
[[nodiscard]] bool EndViewSource(); void EndViewSource();
void RewindViewSource(); void RewindViewSource();

View file

@ -4,7 +4,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ErrorList.h"
#include "nsError.h" #include "nsError.h"
#include "mozilla/CheckedInt.h" #include "mozilla/CheckedInt.h"
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
@ -1202,7 +1201,7 @@ bool nsHtml5TreeBuilder::HasScript() {
return mOpQueue.ElementAt(len - 1).IsRunScript(); return mOpQueue.ElementAt(len - 1).IsRunScript();
} }
mozilla::Result<bool, nsresult> nsHtml5TreeBuilder::Flush(bool aDiscretionary) { bool nsHtml5TreeBuilder::Flush(bool aDiscretionary) {
if (MOZ_UNLIKELY(mBuilder)) { if (MOZ_UNLIKELY(mBuilder)) {
MOZ_ASSERT_UNREACHABLE("Must never flush with builder."); MOZ_ASSERT_UNREACHABLE("Must never flush with builder.");
return false; return false;
@ -1231,9 +1230,7 @@ mozilla::Result<bool, nsresult> nsHtml5TreeBuilder::Flush(bool aDiscretionary) {
"Tree builder is broken but the op in queue is not marked " "Tree builder is broken but the op in queue is not marked "
"as broken."); "as broken.");
} }
if (!mOpSink->MoveOpsFrom(mOpQueue)) { mOpSink->MoveOpsFrom(mOpQueue);
return Err(NS_ERROR_OUT_OF_MEMORY);
}
} }
return hasOps; return hasOps;
} }

View file

@ -110,12 +110,7 @@ void SetOpSink(nsAHtml5TreeOpSink* aOpSink) { mOpSink = aOpSink; }
void ClearOps() { mOpQueue.Clear(); } void ClearOps() { mOpQueue.Clear(); }
/** bool Flush(bool aDiscretionary = false);
* Flushes tree ops.
* @return Ok(true) if there were ops to flush, Ok(false)
* if there were no ops to flush and Err() on OOM.
*/
mozilla::Result<bool, nsresult> Flush(bool aDiscretionary = false);
void FlushLoads(); void FlushLoads();

View file

@ -22,7 +22,6 @@
#include "mozilla/StaticPrefs_view_source.h" #include "mozilla/StaticPrefs_view_source.h"
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
#include "mozilla/css/Loader.h" #include "mozilla/css/Loader.h"
#include "mozilla/fallible.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDocShell.h" #include "nsDocShell.h"
#include "nsError.h" #include "nsError.h"
@ -141,8 +140,7 @@ nsHtml5TreeOpExecutor::~nsHtml5TreeOpExecutor() {
} }
} }
} }
MOZ_ASSERT(NS_FAILED(mBroken) || mOpQueue.IsEmpty(), NS_ASSERTION(mOpQueue.IsEmpty(), "Somehow there's stuff in the op queue.");
"Somehow there's stuff in the op queue.");
} }
// nsIContentSink // nsIContentSink
@ -611,12 +609,7 @@ void nsHtml5TreeOpExecutor::RunFlushLoop() {
nsTArray<nsHtml5SpeculativeLoad> speculativeLoadQueue; nsTArray<nsHtml5SpeculativeLoad> speculativeLoadQueue;
MOZ_RELEASE_ASSERT(mFlushState == eNotFlushing, MOZ_RELEASE_ASSERT(mFlushState == eNotFlushing,
"mOpQueue modified during flush."); "mOpQueue modified during flush.");
if (!mStage.MoveOpsAndSpeculativeLoadsTo(mOpQueue, mStage.MoveOpsAndSpeculativeLoadsTo(mOpQueue, speculativeLoadQueue);
speculativeLoadQueue)) {
MarkAsBroken(nsresult::NS_ERROR_OUT_OF_MEMORY);
return;
}
// Make sure speculative loads never start after the corresponding // Make sure speculative loads never start after the corresponding
// normal loads for the same URLs. // normal loads for the same URLs.
nsHtml5SpeculativeLoad* start = speculativeLoadQueue.Elements(); nsHtml5SpeculativeLoad* start = speculativeLoadQueue.Elements();
@ -850,9 +843,7 @@ void nsHtml5TreeOpExecutor::CommitToInternalEncoding() {
false); false);
} }
[[nodiscard]] bool nsHtml5TreeOpExecutor::TakeOpsFromStage() { void nsHtml5TreeOpExecutor::TakeOpsFromStage() { mStage.MoveOpsTo(mOpQueue); }
return mStage.MoveOpsTo(mOpQueue);
}
// copied from HTML content sink // copied from HTML content sink
bool nsHtml5TreeOpExecutor::IsScriptEnabled() { bool nsHtml5TreeOpExecutor::IsScriptEnabled() {
@ -1046,11 +1037,11 @@ nsHtml5Parser* nsHtml5TreeOpExecutor::GetParser() {
return static_cast<nsHtml5Parser*>(mParser.get()); return static_cast<nsHtml5Parser*>(mParser.get());
} }
[[nodiscard]] bool nsHtml5TreeOpExecutor::MoveOpsFrom( void nsHtml5TreeOpExecutor::MoveOpsFrom(
nsTArray<nsHtml5TreeOperation>& aOpQueue) { nsTArray<nsHtml5TreeOperation>& aOpQueue) {
MOZ_RELEASE_ASSERT(mFlushState == eNotFlushing, MOZ_RELEASE_ASSERT(mFlushState == eNotFlushing,
"Ops added to mOpQueue during tree op execution."); "Ops added to mOpQueue during tree op execution.");
return !!mOpQueue.AppendElements(std::move(aOpQueue), mozilla::fallible_t()); mOpQueue.AppendElements(std::move(aOpQueue));
} }
void nsHtml5TreeOpExecutor::ClearOpQueue() { void nsHtml5TreeOpExecutor::ClearOpQueue() {

View file

@ -184,7 +184,7 @@ class nsHtml5TreeOpExecutor final
void CommitToInternalEncoding(); void CommitToInternalEncoding();
[[nodiscard]] bool TakeOpsFromStage(); void TakeOpsFromStage();
void MaybeSuspend(); void MaybeSuspend();
@ -220,8 +220,7 @@ class nsHtml5TreeOpExecutor final
* Flush the operations from the tree operations from the argument * Flush the operations from the tree operations from the argument
* queue unconditionally. (This is for the main thread case.) * queue unconditionally. (This is for the main thread case.)
*/ */
[[nodiscard]] virtual bool MoveOpsFrom( virtual void MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) override;
nsTArray<nsHtml5TreeOperation>& aOpQueue) override;
void ClearOpQueue(); void ClearOpQueue();

View file

@ -10,26 +10,22 @@ nsHtml5TreeOpStage::nsHtml5TreeOpStage() : mMutex("nsHtml5TreeOpStage mutex") {}
nsHtml5TreeOpStage::~nsHtml5TreeOpStage() {} nsHtml5TreeOpStage::~nsHtml5TreeOpStage() {}
bool nsHtml5TreeOpStage::MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) { void nsHtml5TreeOpStage::MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) {
mozilla::MutexAutoLock autoLock(mMutex); mozilla::MutexAutoLock autoLock(mMutex);
return !!mOpQueue.AppendElements(std::move(aOpQueue), mozilla::fallible_t()); mOpQueue.AppendElements(std::move(aOpQueue));
} }
[[nodiscard]] bool nsHtml5TreeOpStage::MoveOpsAndSpeculativeLoadsTo( void nsHtml5TreeOpStage::MoveOpsAndSpeculativeLoadsTo(
nsTArray<nsHtml5TreeOperation>& aOpQueue, nsTArray<nsHtml5TreeOperation>& aOpQueue,
nsTArray<nsHtml5SpeculativeLoad>& aSpeculativeLoadQueue) { nsTArray<nsHtml5SpeculativeLoad>& aSpeculativeLoadQueue) {
mozilla::MutexAutoLock autoLock(mMutex); mozilla::MutexAutoLock autoLock(mMutex);
if (!aOpQueue.AppendElements(std::move(mOpQueue), mozilla::fallible_t())) { aOpQueue.AppendElements(std::move(mOpQueue));
return false;
};
aSpeculativeLoadQueue.AppendElements(std::move(mSpeculativeLoadQueue)); aSpeculativeLoadQueue.AppendElements(std::move(mSpeculativeLoadQueue));
return true;
} }
[[nodiscard]] bool nsHtml5TreeOpStage::MoveOpsTo( void nsHtml5TreeOpStage::MoveOpsTo(nsTArray<nsHtml5TreeOperation>& aOpQueue) {
nsTArray<nsHtml5TreeOperation>& aOpQueue) {
mozilla::MutexAutoLock autoLock(mMutex); mozilla::MutexAutoLock autoLock(mMutex);
return !!aOpQueue.AppendElements(std::move(mOpQueue), mozilla::fallible_t()); aOpQueue.AppendElements(std::move(mOpQueue));
} }
void nsHtml5TreeOpStage::MoveSpeculativeLoadsFrom( void nsHtml5TreeOpStage::MoveSpeculativeLoadsFrom(

View file

@ -21,18 +21,17 @@ class nsHtml5TreeOpStage : public nsAHtml5TreeOpSink {
* Flush the operations from the tree operations from the argument * Flush the operations from the tree operations from the argument
* queue unconditionally. * queue unconditionally.
*/ */
[[nodiscard]] virtual bool MoveOpsFrom( virtual void MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) override;
nsTArray<nsHtml5TreeOperation>& aOpQueue) override;
/** /**
* Retrieve the staged operations into the argument. * Retrieve the staged operations into the argument.
*/ */
[[nodiscard]] bool MoveOpsTo(nsTArray<nsHtml5TreeOperation>& aOpQueue); void MoveOpsTo(nsTArray<nsHtml5TreeOperation>& aOpQueue);
/** /**
* Retrieve the staged operations and speculative loads into the arguments. * Retrieve the staged operations and speculative loads into the arguments.
*/ */
[[nodiscard]] bool MoveOpsAndSpeculativeLoadsTo( void MoveOpsAndSpeculativeLoadsTo(
nsTArray<nsHtml5TreeOperation>& aOpQueue, nsTArray<nsHtml5TreeOperation>& aOpQueue,
nsTArray<nsHtml5SpeculativeLoad>& aSpeculativeLoadQueue); nsTArray<nsHtml5SpeculativeLoad>& aSpeculativeLoadQueue);