| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google, Inc. All Rights Reserved. | 2 * Copyright (C) 2013 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 | 86 |
| 87 void BackgroundHTMLParser::start(PassRefPtr<WeakReference<BackgroundHTMLParser>>
reference, std::unique_ptr<Configuration> config, const KURL& documentURL, std:
:unique_ptr<CachedDocumentParameters> cachedDocumentParameters, const MediaValue
sCached::MediaValuesCachedData& mediaValuesCachedData, std::unique_ptr<WebTaskRu
nner> loadingTaskRunner) | 87 void BackgroundHTMLParser::start(PassRefPtr<WeakReference<BackgroundHTMLParser>>
reference, std::unique_ptr<Configuration> config, const KURL& documentURL, std:
:unique_ptr<CachedDocumentParameters> cachedDocumentParameters, const MediaValue
sCached::MediaValuesCachedData& mediaValuesCachedData, std::unique_ptr<WebTaskRu
nner> loadingTaskRunner) |
| 88 { | 88 { |
| 89 new BackgroundHTMLParser(reference, std::move(config), documentURL, std::mov
e(cachedDocumentParameters), mediaValuesCachedData, std::move(loadingTaskRunner)
); | 89 new BackgroundHTMLParser(reference, std::move(config), documentURL, std::mov
e(cachedDocumentParameters), mediaValuesCachedData, std::move(loadingTaskRunner)
); |
| 90 // Caller must free by calling stop(). | 90 // Caller must free by calling stop(). |
| 91 } | 91 } |
| 92 | 92 |
| 93 BackgroundHTMLParser::Configuration::Configuration() | 93 BackgroundHTMLParser::Configuration::Configuration() |
| 94 : outstandingTokenLimit(defaultOutstandingTokenLimit) | 94 : outstandingTokenLimit(defaultOutstandingTokenLimit) |
| 95 , pendingTokenLimit(defaultPendingTokenLimit) | 95 , pendingTokenLimit(defaultPendingTokenLimit) |
| 96 , shouldCoalesceChunks(false) |
| 96 { | 97 { |
| 97 } | 98 } |
| 98 | 99 |
| 99 BackgroundHTMLParser::BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHT
MLParser>> reference, std::unique_ptr<Configuration> config, const KURL& documen
tURL, std::unique_ptr<CachedDocumentParameters> cachedDocumentParameters, const
MediaValuesCached::MediaValuesCachedData& mediaValuesCachedData, std::unique_ptr
<WebTaskRunner> loadingTaskRunner) | 100 BackgroundHTMLParser::BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHT
MLParser>> reference, std::unique_ptr<Configuration> config, const KURL& documen
tURL, std::unique_ptr<CachedDocumentParameters> cachedDocumentParameters, const
MediaValuesCached::MediaValuesCachedData& mediaValuesCachedData, std::unique_ptr
<WebTaskRunner> loadingTaskRunner) |
| 100 : m_weakFactory(reference, this) | 101 : m_weakFactory(reference, this) |
| 101 , m_token(wrapUnique(new HTMLToken)) | 102 , m_token(wrapUnique(new HTMLToken)) |
| 102 , m_tokenizer(HTMLTokenizer::create(config->options)) | 103 , m_tokenizer(HTMLTokenizer::create(config->options)) |
| 103 , m_treeBuilderSimulator(config->options) | 104 , m_treeBuilderSimulator(config->options) |
| 104 , m_options(config->options) | 105 , m_options(config->options) |
| 105 , m_outstandingTokenLimit(config->outstandingTokenLimit) | 106 , m_outstandingTokenLimit(config->outstandingTokenLimit) |
| 106 , m_parser(config->parser) | 107 , m_parser(config->parser) |
| 107 , m_pendingTokens(wrapUnique(new CompactHTMLTokenStream)) | 108 , m_pendingTokens(wrapUnique(new CompactHTMLTokenStream)) |
| 108 , m_pendingTokenLimit(config->pendingTokenLimit) | 109 , m_pendingTokenLimit(config->pendingTokenLimit) |
| 109 , m_xssAuditor(std::move(config->xssAuditor)) | 110 , m_xssAuditor(std::move(config->xssAuditor)) |
| 110 , m_preloadScanner(wrapUnique(new TokenPreloadScanner(documentURL, std::move
(cachedDocumentParameters), mediaValuesCachedData))) | 111 , m_preloadScanner(wrapUnique(new TokenPreloadScanner(documentURL, std::move
(cachedDocumentParameters), mediaValuesCachedData))) |
| 111 , m_decoder(std::move(config->decoder)) | 112 , m_decoder(std::move(config->decoder)) |
| 112 , m_loadingTaskRunner(std::move(loadingTaskRunner)) | 113 , m_loadingTaskRunner(std::move(loadingTaskRunner)) |
| 113 , m_tokenizedChunkQueue(config->tokenizedChunkQueue.release()) | 114 , m_tokenizedChunkQueue(config->tokenizedChunkQueue.release()) |
| 114 , m_startingScript(false) | 115 , m_startingScript(false) |
| 115 , m_lastBytesReceivedTime(0.0) | 116 , m_lastBytesReceivedTime(0.0) |
| 117 , m_shouldCoalesceChunks(config->shouldCoalesceChunks) |
| 116 { | 118 { |
| 117 ASSERT(m_outstandingTokenLimit > 0); | 119 ASSERT(m_outstandingTokenLimit > 0); |
| 118 ASSERT(m_pendingTokenLimit > 0); | 120 ASSERT(m_pendingTokenLimit > 0); |
| 119 ASSERT(m_outstandingTokenLimit >= m_pendingTokenLimit); | 121 ASSERT(m_outstandingTokenLimit >= m_pendingTokenLimit); |
| 120 } | 122 } |
| 121 | 123 |
| 122 BackgroundHTMLParser::~BackgroundHTMLParser() | 124 BackgroundHTMLParser::~BackgroundHTMLParser() |
| 123 { | 125 { |
| 124 } | 126 } |
| 125 | 127 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 | 220 |
| 219 void BackgroundHTMLParser::pumpTokenizer() | 221 void BackgroundHTMLParser::pumpTokenizer() |
| 220 { | 222 { |
| 221 TRACE_EVENT0("loading", "BackgroundHTMLParser::pumpTokenizer"); | 223 TRACE_EVENT0("loading", "BackgroundHTMLParser::pumpTokenizer"); |
| 222 HTMLTreeBuilderSimulator::SimulatedToken simulatedToken = HTMLTreeBuilderSim
ulator::OtherToken; | 224 HTMLTreeBuilderSimulator::SimulatedToken simulatedToken = HTMLTreeBuilderSim
ulator::OtherToken; |
| 223 | 225 |
| 224 // No need to start speculating until the main thread has almost caught up. | 226 // No need to start speculating until the main thread has almost caught up. |
| 225 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit) | 227 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit) |
| 226 return; | 228 return; |
| 227 | 229 |
| 230 bool shouldNotifyMainThread = false; |
| 228 while (true) { | 231 while (true) { |
| 229 if (m_xssAuditor->isEnabled()) | 232 if (m_xssAuditor->isEnabled()) |
| 230 m_sourceTracker.start(m_input.current(), m_tokenizer.get(), *m_token
); | 233 m_sourceTracker.start(m_input.current(), m_tokenizer.get(), *m_token
); |
| 231 | 234 |
| 232 if (!m_tokenizer->nextToken(m_input.current(), *m_token)) { | 235 if (!m_tokenizer->nextToken(m_input.current(), *m_token)) { |
| 233 // We've reached the end of our current input. | 236 // We've reached the end of our current input. |
| 234 sendTokensToMainThread(); | 237 shouldNotifyMainThread |= queueChunkForMainThread(); |
| 235 break; | 238 break; |
| 236 } | 239 } |
| 237 | 240 |
| 238 if (m_xssAuditor->isEnabled()) | 241 if (m_xssAuditor->isEnabled()) |
| 239 m_sourceTracker.end(m_input.current(), m_tokenizer.get(), *m_token); | 242 m_sourceTracker.end(m_input.current(), m_tokenizer.get(), *m_token); |
| 240 | 243 |
| 241 { | 244 { |
| 242 TextPosition position = TextPosition(m_input.current().currentLine()
, m_input.current().currentColumn()); | 245 TextPosition position = TextPosition(m_input.current().currentLine()
, m_input.current().currentColumn()); |
| 243 | 246 |
| 244 if (std::unique_ptr<XSSInfo> xssInfo = m_xssAuditor->filterToken(Fil
terTokenRequest(*m_token, m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { | 247 if (std::unique_ptr<XSSInfo> xssInfo = m_xssAuditor->filterToken(Fil
terTokenRequest(*m_token, m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { |
| 245 xssInfo->m_textPosition = position; | 248 xssInfo->m_textPosition = position; |
| 246 m_pendingXSSInfos.append(std::move(xssInfo)); | 249 m_pendingXSSInfos.append(std::move(xssInfo)); |
| 247 } | 250 } |
| 248 | 251 |
| 249 CompactHTMLToken token(m_token.get(), position); | 252 CompactHTMLToken token(m_token.get(), position); |
| 250 | 253 |
| 251 bool shouldEvaluateForDocumentWrite = false; | 254 bool shouldEvaluateForDocumentWrite = false; |
| 252 m_preloadScanner->scan(token, m_input.current(), m_pendingPreloads,
&m_viewportDescription, &shouldEvaluateForDocumentWrite); | 255 m_preloadScanner->scan(token, m_input.current(), m_pendingPreloads,
&m_viewportDescription, &shouldEvaluateForDocumentWrite); |
| 253 | 256 |
| 254 simulatedToken = m_treeBuilderSimulator.simulate(token, m_tokenizer.
get()); | 257 simulatedToken = m_treeBuilderSimulator.simulate(token, m_tokenizer.
get()); |
| 255 | 258 |
| 256 // Break chunks before a script tag is inserted and flag the chunk a
s starting a script | 259 // Break chunks before a script tag is inserted and flag the chunk a
s starting a script |
| 257 // so the main parser can decide if it should yield before processin
g the chunk. | 260 // so the main parser can decide if it should yield before processin
g the chunk. |
| 258 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptStart) { | 261 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptStart) { |
| 259 sendTokensToMainThread(); | 262 shouldNotifyMainThread |= queueChunkForMainThread(); |
| 260 m_startingScript = true; | 263 m_startingScript = true; |
| 261 } | 264 } |
| 262 | 265 |
| 263 m_pendingTokens->append(token); | 266 m_pendingTokens->append(token); |
| 264 if (shouldEvaluateForDocumentWrite) { | 267 if (shouldEvaluateForDocumentWrite) { |
| 265 m_likelyDocumentWriteScriptIndices.append(m_pendingTokens->size(
) - 1); | 268 m_likelyDocumentWriteScriptIndices.append(m_pendingTokens->size(
) - 1); |
| 266 } | 269 } |
| 267 } | 270 } |
| 268 | 271 |
| 269 m_token->clear(); | 272 m_token->clear(); |
| 270 | 273 |
| 271 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptEnd || m_pendingTo
kens->size() >= m_pendingTokenLimit) { | 274 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptEnd || m_pendingTo
kens->size() >= m_pendingTokenLimit) { |
| 272 sendTokensToMainThread(); | 275 shouldNotifyMainThread |= queueChunkForMainThread(); |
| 273 // If we're far ahead of the main thread, yield for a bit to avoid c
onsuming too much memory. | 276 // If we're far ahead of the main thread, yield for a bit to avoid c
onsuming too much memory. |
| 274 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit) | 277 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit) |
| 275 break; | 278 break; |
| 276 } | 279 } |
| 280 |
| 281 if (!m_shouldCoalesceChunks && shouldNotifyMainThread) { |
| 282 runOnMainThread(&HTMLDocumentParser::notifyPendingTokenizedChunks, m
_parser); |
| 283 shouldNotifyMainThread = false; |
| 284 } |
| 285 } |
| 286 // Wait to notify the main thread about the chunks until we're at the |
| 287 // limit. This lets the background parser generate lots of valuable |
| 288 // preloads before anything expensive (extensions, scripts) take up time |
| 289 // on the main thread. A busy main thread can cause preload delays. |
| 290 if (shouldNotifyMainThread) { |
| 291 runOnMainThread(&HTMLDocumentParser::notifyPendingTokenizedChunks, m_par
ser); |
| 277 } | 292 } |
| 278 } | 293 } |
| 279 | 294 |
| 280 void BackgroundHTMLParser::sendTokensToMainThread() | 295 bool BackgroundHTMLParser::queueChunkForMainThread() |
| 281 { | 296 { |
| 282 if (m_pendingTokens->isEmpty()) | 297 if (m_pendingTokens->isEmpty()) |
| 283 return; | 298 return false; |
| 284 | 299 |
| 285 #if ENABLE(ASSERT) | 300 #if ENABLE(ASSERT) |
| 286 checkThatTokensAreSafeToSendToAnotherThread(m_pendingTokens.get()); | 301 checkThatTokensAreSafeToSendToAnotherThread(m_pendingTokens.get()); |
| 287 checkThatPreloadsAreSafeToSendToAnotherThread(m_pendingPreloads); | 302 checkThatPreloadsAreSafeToSendToAnotherThread(m_pendingPreloads); |
| 288 checkThatXSSInfosAreSafeToSendToAnotherThread(m_pendingXSSInfos); | 303 checkThatXSSInfosAreSafeToSendToAnotherThread(m_pendingXSSInfos); |
| 289 #endif | 304 #endif |
| 290 | 305 |
| 291 double chunkStartTime = monotonicallyIncreasingTimeMS(); | 306 double chunkStartTime = monotonicallyIncreasingTimeMS(); |
| 292 std::unique_ptr<HTMLDocumentParser::TokenizedChunk> chunk = wrapUnique(new H
TMLDocumentParser::TokenizedChunk); | 307 std::unique_ptr<HTMLDocumentParser::TokenizedChunk> chunk = wrapUnique(new H
TMLDocumentParser::TokenizedChunk); |
| 293 TRACE_EVENT_WITH_FLOW0("blink,loading", "BackgroundHTMLParser::sendTokensToM
ainThread", chunk.get(), TRACE_EVENT_FLAG_FLOW_OUT); | 308 TRACE_EVENT_WITH_FLOW0("blink,loading", "BackgroundHTMLParser::sendTokensToM
ainThread", chunk.get(), TRACE_EVENT_FLAG_FLOW_OUT); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 309 chunk->tokens = std::move(m_pendingTokens); | 324 chunk->tokens = std::move(m_pendingTokens); |
| 310 chunk->startingScript = m_startingScript; | 325 chunk->startingScript = m_startingScript; |
| 311 chunk->likelyDocumentWriteScriptIndices.swap(m_likelyDocumentWriteScriptIndi
ces); | 326 chunk->likelyDocumentWriteScriptIndices.swap(m_likelyDocumentWriteScriptIndi
ces); |
| 312 m_startingScript = false; | 327 m_startingScript = false; |
| 313 | 328 |
| 314 bool isEmpty = m_tokenizedChunkQueue->enqueue(std::move(chunk)); | 329 bool isEmpty = m_tokenizedChunkQueue->enqueue(std::move(chunk)); |
| 315 | 330 |
| 316 DEFINE_STATIC_LOCAL(CustomCountHistogram, chunkEnqueueTime, ("Parser.ChunkEn
queueTime", 1, 10000, 50)); | 331 DEFINE_STATIC_LOCAL(CustomCountHistogram, chunkEnqueueTime, ("Parser.ChunkEn
queueTime", 1, 10000, 50)); |
| 317 chunkEnqueueTime.count(monotonicallyIncreasingTimeMS() - chunkStartTime); | 332 chunkEnqueueTime.count(monotonicallyIncreasingTimeMS() - chunkStartTime); |
| 318 | 333 |
| 319 if (isEmpty) { | |
| 320 runOnMainThread(&HTMLDocumentParser::notifyPendingTokenizedChunks, m_par
ser); | |
| 321 } | |
| 322 | 334 |
| 323 m_pendingTokens = wrapUnique(new CompactHTMLTokenStream); | 335 m_pendingTokens = wrapUnique(new CompactHTMLTokenStream); |
| 336 return isEmpty; |
| 324 } | 337 } |
| 325 | 338 |
| 326 // If the background parser is already running on the main thread, then it is | 339 // If the background parser is already running on the main thread, then it is |
| 327 // not necessary to post a task to the main thread to run asynchronously. The | 340 // not necessary to post a task to the main thread to run asynchronously. The |
| 328 // main parser deals with chunking up its own work. | 341 // main parser deals with chunking up its own work. |
| 329 // TODO(csharrison): This is a pretty big hack because we don't actually need a | 342 // TODO(csharrison): This is a pretty big hack because we don't actually need a |
| 330 // CrossThreadClosure in these cases. This is just experimental. | 343 // CrossThreadClosure in these cases. This is just experimental. |
| 331 template <typename FunctionType, typename... Ps> | 344 template <typename FunctionType, typename... Ps> |
| 332 void BackgroundHTMLParser::runOnMainThread(FunctionType function, Ps&&... parame
ters) | 345 void BackgroundHTMLParser::runOnMainThread(FunctionType function, Ps&&... parame
ters) |
| 333 { | 346 { |
| 334 if (isMainThread()) { | 347 if (isMainThread()) { |
| 335 (*WTF::bind(function, std::forward<Ps>(parameters)...))(); | 348 (*WTF::bind(function, std::forward<Ps>(parameters)...))(); |
| 336 } else { | 349 } else { |
| 337 m_loadingTaskRunner->postTask(BLINK_FROM_HERE, crossThreadBind(function,
std::forward<Ps>(parameters)...)); | 350 m_loadingTaskRunner->postTask(BLINK_FROM_HERE, crossThreadBind(function,
std::forward<Ps>(parameters)...)); |
| 338 } | 351 } |
| 339 } | 352 } |
| 340 | 353 |
| 341 } // namespace blink | 354 } // namespace blink |
| OLD | NEW |