Index: Source/core/html/parser/HTMLDocumentParser.cpp |
diff --git a/Source/core/html/parser/HTMLDocumentParser.cpp b/Source/core/html/parser/HTMLDocumentParser.cpp |
index ff73092b2cbfbcead0f72a109aa85434652e03d4..6f6c39eaa888aa910d8f8075367232651601d07d 100644 |
--- a/Source/core/html/parser/HTMLDocumentParser.cpp |
+++ b/Source/core/html/parser/HTMLDocumentParser.cpp |
@@ -33,13 +33,16 @@ |
#include "core/html/parser/AtomicHTMLToken.h" |
#include "core/html/parser/BackgroundHTMLParser.h" |
#include "core/html/parser/HTMLParserScheduler.h" |
-#include "core/html/parser/HTMLParserThread.h" |
#include "core/html/parser/HTMLScriptRunner.h" |
#include "core/html/parser/HTMLTreeBuilder.h" |
#include "core/inspector/InspectorInstrumentation.h" |
#include "core/frame/Frame.h" |
+#include "core/loader/DocumentLoader.h" |
#include "platform/SharedBuffer.h" |
+#include "platform/Task.h" |
#include "platform/TraceEvent.h" |
+#include "public/platform/WebParserResourceBridge.h" |
+#include "public/platform/WebThread.h" |
#include "wtf/Functional.h" |
namespace WebCore { |
@@ -74,8 +77,6 @@ static HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElem |
HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors) |
: ScriptableDocumentParser(document) |
, m_options(document) |
- , m_token(m_options.useThreading ? nullptr : adoptPtr(new HTMLToken)) |
- , m_tokenizer(m_options.useThreading ? nullptr : HTMLTokenizer::create(m_options)) |
, m_scriptRunner(HTMLScriptRunner::create(document, this)) |
, m_treeBuilder(HTMLTreeBuilder::create(this, document, parserContentPolicy(), reportErrors, m_options)) |
, m_parserScheduler(HTMLParserScheduler::create(this)) |
@@ -84,10 +85,17 @@ HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors |
, m_preloader(adoptPtr(new HTMLResourcePreloader(document))) |
, m_isPinnedToMainThread(false) |
, m_endWasDelayed(false) |
- , m_haveBackgroundParser(false) |
, m_pumpSessionNestingLevel(0) |
+ , m_parserThread(0) |
+ , m_parserThreadIsStandalone(false) |
{ |
- ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); |
+ if (shouldUseThreading()) |
+ startBackgroundParser(); |
abarth-chromium
2013/12/18 18:28:49
Does this integrate correctly with m_isPinnedToMai
oystein (OOO til 10th of July)
2014/01/13 23:19:50
As far as I can tell so far, parsers which aren't
|
+ |
+ if (!m_parserThread) { |
+ m_token = adoptPtr(new HTMLToken); |
+ m_tokenizer = HTMLTokenizer::create(m_options); |
+ } |
} |
// FIXME: Member variables should be grouped into self-initializing structs to |
@@ -102,8 +110,9 @@ HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* cont |
, m_weakFactory(this) |
, m_isPinnedToMainThread(true) |
, m_endWasDelayed(false) |
- , m_haveBackgroundParser(false) |
, m_pumpSessionNestingLevel(0) |
+ , m_parserThread(0) |
+ , m_parserThreadIsStandalone(false) |
{ |
ASSERT(!shouldUseThreading()); |
bool reportErrors = false; // For now document fragment parsing never reports errors. |
@@ -117,7 +126,7 @@ HTMLDocumentParser::~HTMLDocumentParser() |
ASSERT(!m_pumpSessionNestingLevel); |
ASSERT(!m_preloadScanner); |
ASSERT(!m_insertionPreloadScanner); |
- ASSERT(!m_haveBackgroundParser); |
+ ASSERT(!m_parserThread); |
// FIXME: We should be able to ASSERT(m_speculations.isEmpty()), |
// but there are cases where that's not true currently. For example, |
// we we're told to stop parsing before we've consumed all the input. |
@@ -125,7 +134,7 @@ HTMLDocumentParser::~HTMLDocumentParser() |
void HTMLDocumentParser::pinToMainThread() |
{ |
- ASSERT(!m_haveBackgroundParser); |
+ ASSERT(!m_parserThread); |
ASSERT(!m_isPinnedToMainThread); |
m_isPinnedToMainThread = true; |
if (!m_tokenizer) { |
@@ -137,7 +146,7 @@ void HTMLDocumentParser::pinToMainThread() |
void HTMLDocumentParser::detach() |
{ |
- if (m_haveBackgroundParser) |
+ if (m_parserThread) |
stopBackgroundParser(); |
DocumentParser::detach(); |
if (m_scriptRunner) |
@@ -154,7 +163,7 @@ void HTMLDocumentParser::stopParsing() |
{ |
DocumentParser::stopParsing(); |
m_parserScheduler.clear(); // Deleting the scheduler will clear any timers. |
- if (m_haveBackgroundParser) |
+ if (m_parserThread) |
stopBackgroundParser(); |
} |
@@ -164,7 +173,7 @@ void HTMLDocumentParser::prepareToStopParsing() |
{ |
// FIXME: It may not be correct to disable this for the background parser. |
// That means hasInsertionPoint() may not be correct in some cases. |
- ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); |
+ ASSERT(!hasInsertionPoint() || m_parserThread); |
// pumpTokenizer can cause this parser to be detached from the Document, |
// but we need to ensure it isn't deleted yet. |
@@ -173,7 +182,7 @@ void HTMLDocumentParser::prepareToStopParsing() |
// NOTE: This pump should only ever emit buffered character tokens, |
// so ForceSynchronous vs. AllowYield should be meaningless. |
if (m_tokenizer) { |
- ASSERT(!m_haveBackgroundParser); |
+ ASSERT(!m_parserThread); |
pumpTokenizerIfPossible(ForceSynchronous); |
} |
@@ -201,7 +210,7 @@ bool HTMLDocumentParser::isParsingFragment() const |
bool HTMLDocumentParser::processingData() const |
{ |
- return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser; |
+ return isScheduledForResume() || inPumpSession() || m_parserThread; |
} |
void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode) |
@@ -233,7 +242,7 @@ void HTMLDocumentParser::resumeParsingAfterYield() |
// but we need to ensure it isn't deleted yet. |
RefPtr<HTMLDocumentParser> protect(this); |
- if (m_haveBackgroundParser) { |
+ if (m_parserThread) { |
pumpPendingSpeculations(); |
return; |
} |
@@ -260,7 +269,7 @@ bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& ses |
if (isStopped()) |
return false; |
- ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous); |
+ ASSERT(!m_parserThread || mode == ForceSynchronous); |
if (isWaitingForScripts()) { |
if (mode == AllowYield) |
@@ -322,6 +331,11 @@ void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser(const Docume |
document()->setEncodingData(data); |
} |
+void HTMLDocumentParser::destructResourceBridge(PassOwnPtr<blink::WebParserResourceBridge> resourceBridge) |
+{ |
+ // Here to let the resource bridge be destructed on the main thread. |
+} |
+ |
void HTMLDocumentParser::validateSpeculations(PassOwnPtr<ParsedChunk> chunk) |
{ |
ASSERT(chunk); |
@@ -377,7 +391,8 @@ void HTMLDocumentParser::discardSpeculationsAndResumeFrom(PassOwnPtr<ParsedChunk |
m_input.current().clear(); // FIXME: This should be passed in instead of cleared. |
ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, checkpoint.release())); |
+ ASSERT(m_parserThread); |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, checkpoint.release()))); |
} |
void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> popChunk) |
@@ -394,13 +409,14 @@ void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse |
ASSERT(!m_tokenizer); |
ASSERT(!m_token); |
ASSERT(!m_lastChunkBeforeScript); |
+ ASSERT(m_parserThread); |
ActiveParserSession session(contextForParsingSession()); |
OwnPtr<ParsedChunk> chunk(popChunk); |
OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release(); |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, m_backgroundParser, chunk->inputCheckpoint)); |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, m_backgroundParser, chunk->inputCheckpoint))); |
for (XSSInfoStream::const_iterator it = chunk->xssInfos.begin(); it != chunk->xssInfos.end(); ++it) { |
m_textPosition = (*it)->m_textPosition; |
@@ -491,14 +507,9 @@ void HTMLDocumentParser::pumpPendingSpeculations() |
void HTMLDocumentParser::forcePlaintextForTextDocument() |
{ |
- if (shouldUseThreading()) { |
- // This method is called before any data is appended, so we have to start |
- // the background parser ourselves. |
- if (!m_haveBackgroundParser) |
- startBackgroundParser(); |
- |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::forcePlaintextForTextDocument, m_backgroundParser)); |
- } else |
+ if (m_parserThread) |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::forcePlaintextForTextDocument, m_backgroundParser))); |
+ else |
m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); |
} |
@@ -519,7 +530,7 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) |
ASSERT(refCount() >= 2); |
ASSERT(m_tokenizer); |
ASSERT(m_token); |
- ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous); |
+ ASSERT(!m_parserThread || mode == ForceSynchronous); |
PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession()); |
@@ -634,7 +645,7 @@ void HTMLDocumentParser::insert(const SegmentedString& source) |
if (!m_tokenizer) { |
ASSERT(!inPumpSession()); |
- ASSERT(m_haveBackgroundParser || wasCreatedByScript()); |
+ ASSERT(m_parserThread || wasCreatedByScript()); |
m_token = adoptPtr(new HTMLToken); |
m_tokenizer = HTMLTokenizer::create(m_options); |
} |
@@ -660,8 +671,14 @@ void HTMLDocumentParser::insert(const SegmentedString& source) |
void HTMLDocumentParser::startBackgroundParser() |
{ |
ASSERT(shouldUseThreading()); |
- ASSERT(!m_haveBackgroundParser); |
- m_haveBackgroundParser = true; |
+ ASSERT(!m_parserThread); |
+ |
+ OwnPtr<blink::WebParserResourceBridge> resourceBridge = document()->loader()->constructParserResourceBridge(); |
+ if (!resourceBridge) |
+ return; |
+ |
+ m_parserThread = resourceBridge->getParserThread(); |
abarth-chromium
2013/12/18 18:28:49
getParserThread -> parserThread
|
+ ASSERT(m_parserThread); |
RefPtr<WeakReference<BackgroundHTMLParser> > reference = WeakReference<BackgroundHTMLParser>::createUnbound(); |
m_backgroundParser = WeakPtr<BackgroundHTMLParser>(reference); |
@@ -673,19 +690,20 @@ void HTMLDocumentParser::startBackgroundParser() |
config->xssAuditor->init(document(), &m_xssAuditorDelegate); |
config->preloadScanner = adoptPtr(new TokenPreloadScanner(document()->url().copy(), document()->devicePixelRatio())); |
config->decoder = takeDecoder(); |
+ config->resourceBridge = resourceBridge.release(); |
ASSERT(config->xssAuditor->isSafeToSendToAnotherThread()); |
ASSERT(config->preloadScanner->isSafeToSendToAnotherThread()); |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::start, reference.release(), config.release())); |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::start, reference.release(), config.release()))); |
} |
void HTMLDocumentParser::stopBackgroundParser() |
{ |
ASSERT(shouldUseThreading()); |
- ASSERT(m_haveBackgroundParser); |
- m_haveBackgroundParser = false; |
+ ASSERT(m_parserThread); |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::stop, m_backgroundParser)); |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::stop, m_backgroundParser))); |
+ m_parserThread = 0; |
m_weakFactory.revokeAll(); |
} |
@@ -696,7 +714,7 @@ void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource) |
// We should never reach this point if we're using a parser thread, |
// as appendBytes() will directly ship the data to the thread. |
- ASSERT(!shouldUseThreading()); |
+ ASSERT(!m_parserThread); |
// pumpTokenizer can cause this parser to be detached from the Document, |
// but we need to ensure it isn't deleted yet. |
@@ -743,7 +761,7 @@ void HTMLDocumentParser::end() |
ASSERT(!isDetached()); |
ASSERT(!isScheduledForResume()); |
- if (m_haveBackgroundParser) |
+ if (m_parserThread) |
stopBackgroundParser(); |
// Informs the the rest of WebCore that parsing is really finished (and deletes this). |
@@ -755,7 +773,7 @@ void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() |
ASSERT(isStopping()); |
// FIXME: It may not be correct to disable this for the background parser. |
// That means hasInsertionPoint() may not be correct in some cases. |
- ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); |
+ ASSERT(!hasInsertionPoint() || m_parserThread); |
if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing()) |
return; |
end(); |
@@ -795,10 +813,10 @@ void HTMLDocumentParser::finish() |
// Empty documents never got an append() call, and thus have never started |
// a background parser. In those cases, we ignore shouldUseThreading() |
// and fall through to the non-threading case. |
- if (m_haveBackgroundParser) { |
+ if (m_parserThread) { |
if (!m_input.haveSeenEndOfFile()) |
m_input.closeWithoutMarkingEndOfFile(); |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::finish, m_backgroundParser)); |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::finish, m_backgroundParser))); |
return; |
} |
@@ -829,7 +847,7 @@ bool HTMLDocumentParser::isExecutingScript() const |
OrdinalNumber HTMLDocumentParser::lineNumber() const |
{ |
- if (m_haveBackgroundParser) |
+ if (m_parserThread) |
return m_textPosition.m_line; |
return m_input.current().currentLine(); |
@@ -837,7 +855,7 @@ OrdinalNumber HTMLDocumentParser::lineNumber() const |
TextPosition HTMLDocumentParser::textPosition() const |
{ |
- if (m_haveBackgroundParser) |
+ if (m_parserThread) |
return m_textPosition; |
const SegmentedString& currentString = m_input.current(); |
@@ -868,7 +886,7 @@ void HTMLDocumentParser::resumeParsingAfterScriptExecution() |
ASSERT(!isExecutingScript()); |
ASSERT(!isWaitingForScripts()); |
- if (m_haveBackgroundParser) { |
+ if (m_parserThread) { |
validateSpeculations(m_lastChunkBeforeScript.release()); |
ASSERT(!m_lastChunkBeforeScript); |
// processParsedChunkFromBackgroundParser can cause this parser to be detached from the Document, |
@@ -967,29 +985,41 @@ void HTMLDocumentParser::appendBytes(const char* data, size_t length) |
if (!length || isDetached()) |
return; |
- if (shouldUseThreading()) { |
- if (!m_haveBackgroundParser) |
- startBackgroundParser(); |
+ if (m_parserThread) { |
+ if (m_parserThreadIsStandalone) |
+ return; // If this is set, the parser thread will receive the data directly. |
OwnPtr<Vector<char> > buffer = adoptPtr(new Vector<char>(length)); |
memcpy(buffer->data(), data, length); |
TRACE_EVENT1("net", "HTMLDocumentParser::appendBytes", "size", (unsigned)length); |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::appendBytes, m_backgroundParser, buffer.release())); |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::appendBytes, m_backgroundParser, buffer.release()))); |
return; |
} |
DecodedDataDocumentParser::appendBytes(data, length); |
} |
+void HTMLDocumentParser::parserResourceMessageFilterAdded() |
+{ |
+ if (isDetached()) |
+ return; |
+ |
+ ASSERT(m_parserThread && !needsDecoder()); |
+ // At this point the background parser will start receiving data chunks directly |
+ // from the I/O thread and we no longer need to pass it any data. |
+ m_parserThreadIsStandalone = true; |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::resourceFilterAdded, m_backgroundParser))); |
+} |
+ |
void HTMLDocumentParser::flush() |
{ |
// If we've got no decoder, we never received any data. |
if (isDetached() || needsDecoder()) |
return; |
- if (m_haveBackgroundParser) |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::flush, m_backgroundParser)); |
+ if (m_parserThread) |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::flush, m_backgroundParser))); |
else |
DecodedDataDocumentParser::flush(); |
} |
@@ -998,8 +1028,8 @@ void HTMLDocumentParser::setDecoder(PassOwnPtr<TextResourceDecoder> decoder) |
{ |
DecodedDataDocumentParser::setDecoder(decoder); |
- if (m_haveBackgroundParser) |
- HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, takeDecoder())); |
+ if (m_parserThread) |
+ m_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, takeDecoder()))); |
} |
} |