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