| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 checkpoint->treeBuilderState = | 474 checkpoint->treeBuilderState = |
| 475 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); | 475 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); |
| 476 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; | 476 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; |
| 477 checkpoint->preloadScannerCheckpoint = | 477 checkpoint->preloadScannerCheckpoint = |
| 478 lastChunkBeforeScript->preloadScannerCheckpoint; | 478 lastChunkBeforeScript->preloadScannerCheckpoint; |
| 479 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); | 479 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); |
| 480 // FIXME: This should be passed in instead of cleared. | 480 // FIXME: This should be passed in instead of cleared. |
| 481 m_input.current().clear(); | 481 m_input.current().clear(); |
| 482 | 482 |
| 483 ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); | 483 ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); |
| 484 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::resumeFrom, | 484 m_loadingTaskRunner->postTask( |
| 485 m_backgroundParser, | 485 BLINK_FROM_HERE, |
| 486 WTF::passed(std::move(checkpoint))); | 486 WTF::bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, |
| 487 WTF::passed(std::move(checkpoint)))); |
| 487 } | 488 } |
| 488 | 489 |
| 489 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( | 490 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( |
| 490 std::unique_ptr<TokenizedChunk> popChunk) { | 491 std::unique_ptr<TokenizedChunk> popChunk) { |
| 491 TRACE_EVENT_WITH_FLOW0( | 492 TRACE_EVENT_WITH_FLOW0( |
| 492 "blink,loading", | 493 "blink,loading", |
| 493 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", | 494 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", |
| 494 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); | 495 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); |
| 495 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); | 496 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); |
| 496 | 497 |
| 497 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); | 498 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); |
| 498 SECURITY_DCHECK(!inPumpSession()); | 499 SECURITY_DCHECK(!inPumpSession()); |
| 499 ASSERT(!isParsingFragment()); | 500 ASSERT(!isParsingFragment()); |
| 500 DCHECK(!isPaused()); | 501 DCHECK(!isPaused()); |
| 501 ASSERT(!isStopped()); | 502 ASSERT(!isStopped()); |
| 502 ASSERT(shouldUseThreading()); | 503 ASSERT(shouldUseThreading()); |
| 503 ASSERT(!m_tokenizer); | 504 ASSERT(!m_tokenizer); |
| 504 ASSERT(!m_token); | 505 ASSERT(!m_token); |
| 505 DCHECK(!m_lastChunkBeforePause); | 506 DCHECK(!m_lastChunkBeforePause); |
| 506 | 507 |
| 507 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); | 508 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); |
| 508 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); | 509 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); |
| 509 size_t elementTokenCount = 0; | 510 size_t elementTokenCount = 0; |
| 510 | 511 |
| 511 postTaskToLookaheadParser(Asynchronous, | 512 m_loadingTaskRunner->postTask( |
| 512 &BackgroundHTMLParser::startedChunkWithCheckpoint, | 513 BLINK_FROM_HERE, |
| 513 m_backgroundParser, chunk->inputCheckpoint); | 514 WTF::bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, |
| 515 m_backgroundParser, chunk->inputCheckpoint)); |
| 514 | 516 |
| 515 for (const auto& xssInfo : chunk->xssInfos) { | 517 for (const auto& xssInfo : chunk->xssInfos) { |
| 516 m_textPosition = xssInfo->m_textPosition; | 518 m_textPosition = xssInfo->m_textPosition; |
| 517 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 519 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
| 518 if (isStopped()) | 520 if (isStopped()) |
| 519 break; | 521 break; |
| 520 } | 522 } |
| 521 // XSSAuditorDelegate can detach the parser if it decides to block the entire | 523 // XSSAuditorDelegate can detach the parser if it decides to block the entire |
| 522 // current document. | 524 // current document. |
| 523 if (isDetached()) | 525 if (isDetached()) |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 651 | 653 |
| 652 void HTMLDocumentParser::forcePlaintextForTextDocument() { | 654 void HTMLDocumentParser::forcePlaintextForTextDocument() { |
| 653 if (shouldUseThreading()) { | 655 if (shouldUseThreading()) { |
| 654 // This method is called before any data is appended, so we have to start | 656 // This method is called before any data is appended, so we have to start |
| 655 // the background parser ourselves. | 657 // the background parser ourselves. |
| 656 if (!m_haveBackgroundParser) | 658 if (!m_haveBackgroundParser) |
| 657 startBackgroundParser(); | 659 startBackgroundParser(); |
| 658 | 660 |
| 659 // This task should be synchronous, because otherwise synchronous | 661 // This task should be synchronous, because otherwise synchronous |
| 660 // tokenizing can happen before plaintext is forced. | 662 // tokenizing can happen before plaintext is forced. |
| 661 postTaskToLookaheadParser( | 663 m_backgroundParser->forcePlaintextForTextDocument(); |
| 662 Synchronous, &BackgroundHTMLParser::forcePlaintextForTextDocument, | |
| 663 m_backgroundParser); | |
| 664 } else | 664 } else |
| 665 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); | 665 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); |
| 666 } | 666 } |
| 667 | 667 |
| 668 void HTMLDocumentParser::pumpTokenizer() { | 668 void HTMLDocumentParser::pumpTokenizer() { |
| 669 ASSERT(!isStopped()); | 669 ASSERT(!isStopped()); |
| 670 ASSERT(m_tokenizer); | 670 ASSERT(m_tokenizer); |
| 671 ASSERT(m_token); | 671 ASSERT(m_token); |
| 672 | 672 |
| 673 PumpSession session(m_pumpSessionNestingLevel); | 673 PumpSession session(m_pumpSessionNestingLevel); |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 849 ->getBackgroundHtmlParserOutstandingTokenLimit()) { | 849 ->getBackgroundHtmlParserOutstandingTokenLimit()) { |
| 850 config->outstandingTokenLimit = | 850 config->outstandingTokenLimit = |
| 851 document() | 851 document() |
| 852 ->settings() | 852 ->settings() |
| 853 ->getBackgroundHtmlParserOutstandingTokenLimit(); | 853 ->getBackgroundHtmlParserOutstandingTokenLimit(); |
| 854 } | 854 } |
| 855 if (document()->settings()->getBackgroundHtmlParserPendingTokenLimit()) { | 855 if (document()->settings()->getBackgroundHtmlParserPendingTokenLimit()) { |
| 856 config->pendingTokenLimit = | 856 config->pendingTokenLimit = |
| 857 document()->settings()->getBackgroundHtmlParserPendingTokenLimit(); | 857 document()->settings()->getBackgroundHtmlParserPendingTokenLimit(); |
| 858 } | 858 } |
| 859 config->shouldCoalesceChunks = | |
| 860 document()->settings()->getParseHTMLOnMainThreadCoalesceChunks(); | |
| 861 } | 859 } |
| 862 | 860 |
| 863 ASSERT(config->xssAuditor->isSafeToSendToAnotherThread()); | 861 ASSERT(config->xssAuditor->isSafeToSendToAnotherThread()); |
| 864 | 862 |
| 865 // The background parser is created on the main thread, but may otherwise | 863 // The background parser is created on the main thread, but may otherwise |
| 866 // only be used from the parser thread. | 864 // only be used from the parser thread. |
| 867 m_backgroundParser = | 865 m_backgroundParser = |
| 868 BackgroundHTMLParser::create(std::move(config), m_loadingTaskRunner); | 866 BackgroundHTMLParser::create(std::move(config), m_loadingTaskRunner); |
| 869 // TODO(csharrison): This is a hack to initialize MediaValuesCached on the | 867 // TODO(csharrison): This is a hack to initialize MediaValuesCached on the |
| 870 // correct thread. We should get rid of it. | 868 // correct thread. We should get rid of it. |
| 871 postTaskToLookaheadParser( | 869 m_backgroundParser->init( |
| 872 Synchronous, &BackgroundHTMLParser::init, m_backgroundParser, | 870 document()->url(), CachedDocumentParameters::create(document()), |
| 873 document()->url(), | |
| 874 WTF::passed(CachedDocumentParameters::create(document())), | |
| 875 MediaValuesCached::MediaValuesCachedData(*document())); | 871 MediaValuesCached::MediaValuesCachedData(*document())); |
| 876 } | 872 } |
| 877 | 873 |
| 878 void HTMLDocumentParser::stopBackgroundParser() { | 874 void HTMLDocumentParser::stopBackgroundParser() { |
| 879 ASSERT(shouldUseThreading()); | 875 ASSERT(shouldUseThreading()); |
| 880 ASSERT(m_haveBackgroundParser); | 876 ASSERT(m_haveBackgroundParser); |
| 881 | 877 |
| 882 if (m_haveBackgroundParser && document()->frame() && | 878 if (m_haveBackgroundParser && document()->frame() && |
| 883 document()->frame()->frameScheduler()) | 879 document()->frame()->frameScheduler()) |
| 884 document()->frame()->frameScheduler()->setDocumentParsingInBackground( | 880 document()->frame()->frameScheduler()->setDocumentParsingInBackground( |
| 885 false); | 881 false); |
| 886 | 882 |
| 887 m_haveBackgroundParser = false; | 883 m_haveBackgroundParser = false; |
| 888 | 884 |
| 889 // Make this sync, as lsan triggers on some unittests if the task runner is | 885 // Make this sync, as lsan triggers on some unittests if the task runner is |
| 890 // used. Note that these lifetimes will be much more concrete if | 886 // used. |
| 891 // ParseHTMLOnMainThread lands (the lookahead parser will be a member). | 887 m_backgroundParser->stop(); |
| 892 postTaskToLookaheadParser(Synchronous, &BackgroundHTMLParser::stop, | |
| 893 m_backgroundParser); | |
| 894 m_weakFactory.revokeAll(); | 888 m_weakFactory.revokeAll(); |
| 895 } | 889 } |
| 896 | 890 |
| 897 void HTMLDocumentParser::append(const String& inputSource) { | 891 void HTMLDocumentParser::append(const String& inputSource) { |
| 898 if (isStopped()) | 892 if (isStopped()) |
| 899 return; | 893 return; |
| 900 | 894 |
| 901 // We should never reach this point if we're using a parser thread, as | 895 // We should never reach this point if we're using a parser thread, as |
| 902 // appendBytes() will directly ship the data to the thread. | 896 // appendBytes() will directly ship the data to the thread. |
| 903 ASSERT(!shouldUseThreading()); | 897 ASSERT(!shouldUseThreading()); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 999 flush(); | 993 flush(); |
| 1000 if (isDetached()) | 994 if (isDetached()) |
| 1001 return; | 995 return; |
| 1002 | 996 |
| 1003 // Empty documents never got an append() call, and thus have never started a | 997 // Empty documents never got an append() call, and thus have never started a |
| 1004 // background parser. In those cases, we ignore shouldUseThreading() and fall | 998 // background parser. In those cases, we ignore shouldUseThreading() and fall |
| 1005 // through to the non-threading case. | 999 // through to the non-threading case. |
| 1006 if (m_haveBackgroundParser) { | 1000 if (m_haveBackgroundParser) { |
| 1007 if (!m_input.haveSeenEndOfFile()) | 1001 if (!m_input.haveSeenEndOfFile()) |
| 1008 m_input.closeWithoutMarkingEndOfFile(); | 1002 m_input.closeWithoutMarkingEndOfFile(); |
| 1009 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::finish, | 1003 m_loadingTaskRunner->postTask( |
| 1010 m_backgroundParser); | 1004 BLINK_FROM_HERE, |
| 1005 WTF::bind(&BackgroundHTMLParser::finish, m_backgroundParser)); |
| 1011 return; | 1006 return; |
| 1012 } | 1007 } |
| 1013 | 1008 |
| 1014 if (!m_tokenizer) { | 1009 if (!m_tokenizer) { |
| 1015 ASSERT(!m_token); | 1010 ASSERT(!m_token); |
| 1016 // We're finishing before receiving any data. Rather than booting up the | 1011 // We're finishing before receiving any data. Rather than booting up the |
| 1017 // background parser just to spin it down, we finish parsing synchronously. | 1012 // background parser just to spin it down, we finish parsing synchronously. |
| 1018 m_token = WTF::wrapUnique(new HTMLToken); | 1013 m_token = WTF::wrapUnique(new HTMLToken); |
| 1019 m_tokenizer = HTMLTokenizer::create(m_options); | 1014 m_tokenizer = HTMLTokenizer::create(m_options); |
| 1020 } | 1015 } |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1199 double bytesReceivedTime = monotonicallyIncreasingTimeMS(); | 1194 double bytesReceivedTime = monotonicallyIncreasingTimeMS(); |
| 1200 if (!m_haveBackgroundParser) | 1195 if (!m_haveBackgroundParser) |
| 1201 startBackgroundParser(); | 1196 startBackgroundParser(); |
| 1202 | 1197 |
| 1203 std::unique_ptr<Vector<char>> buffer = | 1198 std::unique_ptr<Vector<char>> buffer = |
| 1204 WTF::makeUnique<Vector<char>>(length); | 1199 WTF::makeUnique<Vector<char>>(length); |
| 1205 memcpy(buffer->data(), data, length); | 1200 memcpy(buffer->data(), data, length); |
| 1206 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 1201 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
| 1207 "HTMLDocumentParser::appendBytes", "size", (unsigned)length); | 1202 "HTMLDocumentParser::appendBytes", "size", (unsigned)length); |
| 1208 | 1203 |
| 1209 LookaheadParserTaskSynchrony policy = | 1204 m_loadingTaskRunner->postTask( |
| 1210 document()->settings() && | 1205 BLINK_FROM_HERE, |
| 1211 document()->settings()->getParseHTMLOnMainThreadSyncTokenize() | 1206 WTF::bind(&BackgroundHTMLParser::appendRawBytesFromMainThread, |
| 1212 ? Synchronous | 1207 m_backgroundParser, WTF::passed(std::move(buffer)), |
| 1213 : Asynchronous; | 1208 bytesReceivedTime)); |
| 1214 postTaskToLookaheadParser( | |
| 1215 policy, &BackgroundHTMLParser::appendRawBytesFromMainThread, | |
| 1216 m_backgroundParser, WTF::passed(std::move(buffer)), bytesReceivedTime); | |
| 1217 return; | 1209 return; |
| 1218 } | 1210 } |
| 1219 | 1211 |
| 1220 DecodedDataDocumentParser::appendBytes(data, length); | 1212 DecodedDataDocumentParser::appendBytes(data, length); |
| 1221 } | 1213 } |
| 1222 | 1214 |
| 1223 void HTMLDocumentParser::flush() { | 1215 void HTMLDocumentParser::flush() { |
| 1224 // If we've got no decoder, we never received any data. | 1216 // If we've got no decoder, we never received any data. |
| 1225 if (isDetached() || needsDecoder()) | 1217 if (isDetached() || needsDecoder()) |
| 1226 return; | 1218 return; |
| 1227 | 1219 |
| 1228 if (shouldUseThreading()) { | 1220 if (shouldUseThreading()) { |
| 1229 // In some cases, flush() is called without any invocation of appendBytes. | 1221 // In some cases, flush() is called without any invocation of appendBytes. |
| 1230 // Fallback to synchronous parsing in that case. | 1222 // Fallback to synchronous parsing in that case. |
| 1231 if (!m_haveBackgroundParser) { | 1223 if (!m_haveBackgroundParser) { |
| 1232 m_shouldUseThreading = false; | 1224 m_shouldUseThreading = false; |
| 1233 m_token = WTF::wrapUnique(new HTMLToken); | 1225 m_token = WTF::wrapUnique(new HTMLToken); |
| 1234 m_tokenizer = HTMLTokenizer::create(m_options); | 1226 m_tokenizer = HTMLTokenizer::create(m_options); |
| 1235 DecodedDataDocumentParser::flush(); | 1227 DecodedDataDocumentParser::flush(); |
| 1236 return; | 1228 return; |
| 1237 } | 1229 } |
| 1238 | 1230 |
| 1239 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::flush, | 1231 m_loadingTaskRunner->postTask( |
| 1240 m_backgroundParser); | 1232 BLINK_FROM_HERE, |
| 1233 WTF::bind(&BackgroundHTMLParser::flush, m_backgroundParser)); |
| 1241 } else { | 1234 } else { |
| 1242 DecodedDataDocumentParser::flush(); | 1235 DecodedDataDocumentParser::flush(); |
| 1243 } | 1236 } |
| 1244 } | 1237 } |
| 1245 | 1238 |
| 1246 void HTMLDocumentParser::setDecoder( | 1239 void HTMLDocumentParser::setDecoder( |
| 1247 std::unique_ptr<TextResourceDecoder> decoder) { | 1240 std::unique_ptr<TextResourceDecoder> decoder) { |
| 1248 ASSERT(decoder); | 1241 ASSERT(decoder); |
| 1249 DecodedDataDocumentParser::setDecoder(std::move(decoder)); | 1242 DecodedDataDocumentParser::setDecoder(std::move(decoder)); |
| 1250 | 1243 |
| 1251 if (m_haveBackgroundParser) { | 1244 if (m_haveBackgroundParser) { |
| 1252 postTaskToLookaheadParser(Asynchronous, &BackgroundHTMLParser::setDecoder, | 1245 m_loadingTaskRunner->postTask( |
| 1253 m_backgroundParser, WTF::passed(takeDecoder())); | 1246 BLINK_FROM_HERE, |
| 1247 WTF::bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, |
| 1248 WTF::passed(takeDecoder()))); |
| 1254 } | 1249 } |
| 1255 } | 1250 } |
| 1256 | 1251 |
| 1257 void HTMLDocumentParser::documentElementAvailable() { | 1252 void HTMLDocumentParser::documentElementAvailable() { |
| 1258 TRACE_EVENT0("blink,loader", "HTMLDocumentParser::documentElementAvailable"); | 1253 TRACE_EVENT0("blink,loader", "HTMLDocumentParser::documentElementAvailable"); |
| 1259 DCHECK(document()->documentElement()); | 1254 DCHECK(document()->documentElement()); |
| 1260 fetchQueuedPreloads(); | 1255 fetchQueuedPreloads(); |
| 1261 } | 1256 } |
| 1262 | 1257 |
| 1263 std::unique_ptr<HTMLPreloadScanner> HTMLDocumentParser::createPreloadScanner() { | 1258 std::unique_ptr<HTMLPreloadScanner> HTMLDocumentParser::createPreloadScanner() { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1335 ("PreloadScanner.DocumentWrite.ExecutionTime.Success", 1, 10000, 50)); | 1330 ("PreloadScanner.DocumentWrite.ExecutionTime.Success", 1, 10000, 50)); |
| 1336 successHistogram.count(duration); | 1331 successHistogram.count(duration); |
| 1337 } else { | 1332 } else { |
| 1338 DEFINE_STATIC_LOCAL( | 1333 DEFINE_STATIC_LOCAL( |
| 1339 CustomCountHistogram, failureHistogram, | 1334 CustomCountHistogram, failureHistogram, |
| 1340 ("PreloadScanner.DocumentWrite.ExecutionTime.Failure", 1, 10000, 50)); | 1335 ("PreloadScanner.DocumentWrite.ExecutionTime.Failure", 1, 10000, 50)); |
| 1341 failureHistogram.count(duration); | 1336 failureHistogram.count(duration); |
| 1342 } | 1337 } |
| 1343 } | 1338 } |
| 1344 | 1339 |
| 1345 template <typename FunctionType, typename... Ps> | |
| 1346 void HTMLDocumentParser::postTaskToLookaheadParser( | |
| 1347 LookaheadParserTaskSynchrony synchronyPolicy, | |
| 1348 FunctionType function, | |
| 1349 Ps&&... parameters) { | |
| 1350 if (!RuntimeEnabledFeatures::parseHTMLOnMainThreadEnabled()) { | |
| 1351 HTMLParserThread::shared()->postTask( | |
| 1352 crossThreadBind(function, std::forward<Ps>(parameters)...)); | |
| 1353 return; | |
| 1354 } | |
| 1355 | |
| 1356 // Some messages to the lookahead parser should be synchronous. Otherwise, | |
| 1357 // just post to the loading task runner. | |
| 1358 switch (synchronyPolicy) { | |
| 1359 case Synchronous: | |
| 1360 (*WTF::bind(function, std::forward<Ps>(parameters)...))(); | |
| 1361 return; | |
| 1362 case Asynchronous: | |
| 1363 m_loadingTaskRunner->postTask( | |
| 1364 BLINK_FROM_HERE, | |
| 1365 WTF::bind(function, std::forward<Ps>(parameters)...)); | |
| 1366 return; | |
| 1367 } | |
| 1368 NOTREACHED(); | |
| 1369 } | |
| 1370 | |
| 1371 } // namespace blink | 1340 } // namespace blink |
| OLD | NEW |