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 84c9197c309a3f36d5ee241d57a959ea31b771b2..a87b8f65af0aee6d1efdd991eb1ac31b0d6206e1 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/WebThread.h" |
| +#include "public/platform/WebThreadedResourceProvider.h" |
| #include "wtf/Functional.h" |
| namespace WebCore { |
| @@ -71,6 +74,25 @@ static HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElem |
| return HTMLTokenizer::DataState; |
| } |
| +class ParserResourceForegroundClient : public blink::WebThreadedResourceForegroundClient { |
| +public: |
| + ParserResourceForegroundClient(WeakPtr<HTMLDocumentParser> parser) |
| + : m_parser(parser) |
| + { |
| + } |
| + |
| + // WebThreadedResourceForegroundClient |
| + virtual void didSwitchedToBackgroundClient() OVERRIDE FINAL { |
|
darin (slow to review)
2014/02/16 07:12:27
nit: opening paren should be on the next line per
|
| + if (m_parser.get()) |
| + m_parser.get()->didSwitchedToBackgroundClient(); |
|
darin (slow to review)
2014/02/16 07:12:27
nit: "didSwitched..." should be "didSwitch..."
|
| + } |
| + |
| +private: |
| + WeakPtr<HTMLDocumentParser> m_parser; |
| +}; |
| + |
| +blink::WebThread* HTMLDocumentParser::s_parserThread = 0; |
| + |
| HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors) |
| : ScriptableDocumentParser(document) |
| , m_options(document) |
| @@ -86,6 +108,7 @@ HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors |
| , m_endWasDelayed(false) |
| , m_haveBackgroundParser(false) |
| , m_pumpSessionNestingLevel(0) |
| + , m_parserThreadIsStandalone(false) |
| { |
| ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); |
| } |
| @@ -104,6 +127,7 @@ HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* cont |
| , m_endWasDelayed(false) |
| , m_haveBackgroundParser(false) |
| , m_pumpSessionNestingLevel(0) |
| + , m_parserThreadIsStandalone(false) |
| { |
| ASSERT(!shouldUseThreading()); |
| bool reportErrors = false; // For now document fragment parsing never reports errors. |
| @@ -322,6 +346,11 @@ void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser(const Docume |
| document()->setEncodingData(data); |
| } |
| +void HTMLDocumentParser::destroyResourceProvider(PassOwnPtr<blink::WebThreadedResourceProvider> resourceProvider) |
| +{ |
| + // Here to let the resource bridge be destructed on the main thread. |
|
darin (slow to review)
2014/02/16 07:12:27
nit: I think this is a reference to ResourceLoader
|
| +} |
| + |
| void HTMLDocumentParser::validateSpeculations(PassOwnPtr<ParsedChunk> chunk) |
| { |
| ASSERT(chunk); |
| @@ -377,7 +406,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(s_parserThread); |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, checkpoint.release()))); |
| } |
| void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> popChunk) |
| @@ -394,13 +424,14 @@ void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse |
| ASSERT(!m_tokenizer); |
| ASSERT(!m_token); |
| ASSERT(!m_lastChunkBeforeScript); |
| + ASSERT(s_parserThread); |
| ActiveParserSession session(contextForParsingSession()); |
| OwnPtr<ParsedChunk> chunk(popChunk); |
| OwnPtr<CompactHTMLTokenStream> tokens = chunk->tokens.release(); |
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, m_backgroundParser, chunk->inputCheckpoint)); |
| + s_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 +522,12 @@ 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(); |
| + if (shouldUseThreading() && !m_haveBackgroundParser) |
| + startBackgroundParser(); |
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::forcePlaintextForTextDocument, m_backgroundParser)); |
| - } else |
| + if (m_haveBackgroundParser) |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::forcePlaintextForTextDocument, m_backgroundParser))); |
| + else |
| m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); |
| } |
| @@ -662,6 +691,26 @@ void HTMLDocumentParser::startBackgroundParser() |
| ASSERT(!isStopped()); |
| ASSERT(shouldUseThreading()); |
| ASSERT(!m_haveBackgroundParser); |
| + |
| + OwnPtr<blink::WebThreadedResourceProvider> resourceProvider = document()->loader()->createThreadedResourceProvider(); |
| + if (resourceProvider) { |
| + // The resource provider is responsible for destroying the client we create here. |
| + resourceProvider->setForegroundClient(new ParserResourceForegroundClient(m_weakFactory.createWeakPtr())); |
| + if (!s_parserThread) |
| + s_parserThread = resourceProvider->resourceProviderThread(); |
|
darin (slow to review)
2014/02/16 07:12:27
nit: perhaps it would be better to have Blink crea
|
| + ASSERT(s_parserThread && s_parserThread == resourceProvider->resourceProviderThread()); |
| + } |
| + |
| + if (!s_parserThread) { |
| + // If we don't have a thread object, we can't use threading and must |
| + // fall back to singlethreaded mode by having our own tokenizer. |
| + if (!m_token) |
| + m_token = adoptPtr(new HTMLToken); |
| + if (!m_tokenizer) |
| + m_tokenizer = HTMLTokenizer::create(m_options); |
| + return; |
| + } |
| + |
| m_haveBackgroundParser = true; |
| RefPtr<WeakReference<BackgroundHTMLParser> > reference = WeakReference<BackgroundHTMLParser>::createUnbound(); |
| @@ -674,19 +723,21 @@ void HTMLDocumentParser::startBackgroundParser() |
| config->xssAuditor->init(document(), &m_xssAuditorDelegate); |
| config->preloadScanner = adoptPtr(new TokenPreloadScanner(document()->url().copy(), document()->devicePixelRatio())); |
| config->decoder = takeDecoder(); |
| + config->resourceProvider = resourceProvider.release(); |
| ASSERT(config->xssAuditor->isSafeToSendToAnotherThread()); |
| ASSERT(config->preloadScanner->isSafeToSendToAnotherThread()); |
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::start, reference.release(), config.release())); |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::start, reference.release(), config.release()))); |
| } |
| void HTMLDocumentParser::stopBackgroundParser() |
| { |
| ASSERT(shouldUseThreading()); |
| ASSERT(m_haveBackgroundParser); |
| + ASSERT(s_parserThread); |
| m_haveBackgroundParser = false; |
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::stop, m_backgroundParser)); |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::stop, m_backgroundParser))); |
| m_weakFactory.revokeAll(); |
| } |
| @@ -697,7 +748,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_haveBackgroundParser); |
| // pumpTokenizer can cause this parser to be detached from the Document, |
| // but we need to ensure it isn't deleted yet. |
| @@ -799,7 +850,7 @@ void HTMLDocumentParser::finish() |
| if (m_haveBackgroundParser) { |
| if (!m_input.haveSeenEndOfFile()) |
| m_input.closeWithoutMarkingEndOfFile(); |
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::finish, m_backgroundParser)); |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::finish, m_backgroundParser))); |
| return; |
| } |
| @@ -968,21 +1019,38 @@ void HTMLDocumentParser::appendBytes(const char* data, size_t length) |
| if (!length || isStopped()) |
| return; |
| - if (shouldUseThreading()) { |
| - if (!m_haveBackgroundParser) |
| - startBackgroundParser(); |
| + if (shouldUseThreading() && !m_haveBackgroundParser) |
| + startBackgroundParser(); |
| + |
| + if (m_haveBackgroundParser) { |
| + 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())); |
| + ASSERT(s_parserThread); |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::appendBytes, m_backgroundParser, buffer.release()))); |
| return; |
| } |
| DecodedDataDocumentParser::appendBytes(data, length); |
| } |
| +void HTMLDocumentParser::didSwitchedToBackgroundClient() |
| +{ |
| + if (isDetached()) |
| + return; |
| + |
| + ASSERT(s_parserThread); |
| + ASSERT(m_haveBackgroundParser); |
| + // 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; |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::didSwitchedToBackgroundClient, m_backgroundParser))); |
| +} |
| + |
| void HTMLDocumentParser::flush() |
| { |
| // If we've got no decoder, we never received any data. |
| @@ -990,7 +1058,7 @@ void HTMLDocumentParser::flush() |
| return; |
| if (m_haveBackgroundParser) |
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::flush, m_backgroundParser)); |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::flush, m_backgroundParser))); |
| else |
| DecodedDataDocumentParser::flush(); |
| } |
| @@ -1001,7 +1069,7 @@ void HTMLDocumentParser::setDecoder(PassOwnPtr<TextResourceDecoder> decoder) |
| DecodedDataDocumentParser::setDecoder(decoder); |
| if (m_haveBackgroundParser) |
| - HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, takeDecoder())); |
| + s_parserThread->postTask(new Task(bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, takeDecoder()))); |
| } |
| } |