Chromium Code Reviews| 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()))); |
| } |
| } |