Chromium Code Reviews| 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 |
| 11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
| 12 * | 12 * |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "core/html/parser/HTMLDocumentParser.h" | 26 #include "core/html/parser/HTMLDocumentParser.h" |
| 27 | 27 |
| 28 #include <memory> | |
| 28 #include "bindings/core/v8/DocumentWriteEvaluator.h" | 29 #include "bindings/core/v8/DocumentWriteEvaluator.h" |
| 29 #include "core/HTMLNames.h" | 30 #include "core/HTMLNames.h" |
| 30 #include "core/css/MediaValuesCached.h" | 31 #include "core/css/MediaValuesCached.h" |
| 31 #include "core/css/resolver/StyleResolver.h" | 32 #include "core/css/resolver/StyleResolver.h" |
| 32 #include "core/dom/DocumentFragment.h" | 33 #include "core/dom/DocumentFragment.h" |
| 33 #include "core/dom/Element.h" | 34 #include "core/dom/Element.h" |
| 34 #include "core/dom/TaskRunnerHelper.h" | 35 #include "core/dom/TaskRunnerHelper.h" |
| 35 #include "core/frame/LocalFrame.h" | 36 #include "core/frame/LocalFrame.h" |
| 36 #include "core/frame/Settings.h" | 37 #include "core/frame/Settings.h" |
| 37 #include "core/html/HTMLDocument.h" | 38 #include "core/html/HTMLDocument.h" |
| 38 #include "core/html/parser/AtomicHTMLToken.h" | 39 #include "core/html/parser/AtomicHTMLToken.h" |
| 39 #include "core/html/parser/BackgroundHTMLParser.h" | 40 #include "core/html/parser/BackgroundHTMLParser.h" |
| 40 #include "core/html/parser/HTMLParserScheduler.h" | 41 #include "core/html/parser/HTMLParserScheduler.h" |
| 41 #include "core/html/parser/HTMLParserScriptRunner.h" | 42 #include "core/html/parser/HTMLParserScriptRunner.h" |
| 42 #include "core/html/parser/HTMLResourcePreloader.h" | 43 #include "core/html/parser/HTMLResourcePreloader.h" |
| 43 #include "core/html/parser/HTMLTreeBuilder.h" | 44 #include "core/html/parser/HTMLTreeBuilder.h" |
| 44 #include "core/inspector/InspectorInstrumentation.h" | 45 #include "core/inspector/InspectorInstrumentation.h" |
| 45 #include "core/inspector/InspectorTraceEvents.h" | 46 #include "core/inspector/InspectorTraceEvents.h" |
| 46 #include "core/loader/DocumentLoader.h" | 47 #include "core/loader/DocumentLoader.h" |
| 47 #include "core/loader/LinkLoader.h" | 48 #include "core/loader/LinkLoader.h" |
| 48 #include "core/loader/NavigationScheduler.h" | 49 #include "core/loader/NavigationScheduler.h" |
| 49 #include "platform/CrossThreadFunctional.h" | 50 #include "platform/CrossThreadFunctional.h" |
| 50 #include "platform/Histogram.h" | 51 #include "platform/Histogram.h" |
| 51 #include "platform/SharedBuffer.h" | 52 #include "platform/SharedBuffer.h" |
| 52 #include "platform/WebFrameScheduler.h" | 53 #include "platform/WebFrameScheduler.h" |
| 53 #include "platform/heap/Handle.h" | 54 #include "platform/heap/Handle.h" |
| 55 #include "platform/heap/Persistent.h" | |
| 54 #include "platform/instrumentation/tracing/TraceEvent.h" | 56 #include "platform/instrumentation/tracing/TraceEvent.h" |
| 55 #include "platform/loader/fetch/ResourceFetcher.h" | 57 #include "platform/loader/fetch/ResourceFetcher.h" |
| 56 #include "public/platform/Platform.h" | 58 #include "public/platform/Platform.h" |
| 57 #include "public/platform/WebLoadingBehaviorFlag.h" | 59 #include "public/platform/WebLoadingBehaviorFlag.h" |
| 58 #include "public/platform/WebScheduler.h" | 60 #include "public/platform/WebScheduler.h" |
| 59 #include "public/platform/WebThread.h" | 61 #include "public/platform/WebThread.h" |
| 60 #include "wtf/AutoReset.h" | 62 #include "wtf/AutoReset.h" |
| 61 #include "wtf/PtrUtil.h" | 63 #include "wtf/PtrUtil.h" |
| 62 #include <memory> | |
| 63 | 64 |
| 64 namespace blink { | 65 namespace blink { |
| 65 | 66 |
| 66 using namespace HTMLNames; | 67 using namespace HTMLNames; |
| 67 | 68 |
| 68 // This is a direct transcription of step 4 from: | 69 // This is a direct transcription of step 4 from: |
| 69 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#frag ment-case | 70 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#frag ment-case |
| 70 static HTMLTokenizer::State tokenizerStateForContextElement( | 71 static HTMLTokenizer::State tokenizerStateForContextElement( |
| 71 Element* contextElement, | 72 Element* contextElement, |
| 72 bool reportErrors, | 73 bool reportErrors, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 ParserSynchronizationPolicy syncPolicy) | 125 ParserSynchronizationPolicy syncPolicy) |
| 125 : ScriptableDocumentParser(document, contentPolicy), | 126 : ScriptableDocumentParser(document, contentPolicy), |
| 126 m_options(&document), | 127 m_options(&document), |
| 127 m_reentryPermit(HTMLParserReentryPermit::create()), | 128 m_reentryPermit(HTMLParserReentryPermit::create()), |
| 128 m_token(syncPolicy == ForceSynchronousParsing | 129 m_token(syncPolicy == ForceSynchronousParsing |
| 129 ? WTF::wrapUnique(new HTMLToken) | 130 ? WTF::wrapUnique(new HTMLToken) |
| 130 : nullptr), | 131 : nullptr), |
| 131 m_tokenizer(syncPolicy == ForceSynchronousParsing | 132 m_tokenizer(syncPolicy == ForceSynchronousParsing |
| 132 ? HTMLTokenizer::create(m_options) | 133 ? HTMLTokenizer::create(m_options) |
| 133 : nullptr), | 134 : nullptr), |
| 134 m_loadingTaskRunner( | |
| 135 TaskRunnerHelper::get(TaskType::Networking, &document)), | |
| 136 m_parserScheduler( | 135 m_parserScheduler( |
| 137 syncPolicy == AllowAsynchronousParsing | 136 syncPolicy == AllowAsynchronousParsing |
| 138 ? HTMLParserScheduler::create(this, m_loadingTaskRunner.get()) | 137 ? HTMLParserScheduler::create( |
| 138 this, | |
| 139 TaskRunnerHelper::get(TaskType::Networking, &document)) | |
| 139 : nullptr), | 140 : nullptr), |
| 140 m_xssAuditorDelegate(&document), | 141 m_xssAuditorDelegate(&document), |
| 141 m_weakFactory(this), | |
| 142 m_preloader(HTMLResourcePreloader::create(document)), | 142 m_preloader(HTMLResourcePreloader::create(document)), |
| 143 m_tokenizedChunkQueue(TokenizedChunkQueue::create()), | 143 m_tokenizedChunkQueue(TokenizedChunkQueue::create()), |
| 144 m_evaluator(DocumentWriteEvaluator::create(document)), | 144 m_evaluator(DocumentWriteEvaluator::create(document)), |
| 145 m_pendingCSPMetaToken(nullptr), | 145 m_pendingCSPMetaToken(nullptr), |
| 146 m_shouldUseThreading(syncPolicy == AllowAsynchronousParsing), | 146 m_shouldUseThreading(syncPolicy == AllowAsynchronousParsing), |
| 147 m_endWasDelayed(false), | 147 m_endWasDelayed(false), |
| 148 m_haveBackgroundParser(false), | |
| 149 m_tasksWereSuspended(false), | 148 m_tasksWereSuspended(false), |
| 150 m_pumpSessionNestingLevel(0), | 149 m_pumpSessionNestingLevel(0), |
| 151 m_pumpSpeculationsSessionNestingLevel(0), | 150 m_pumpSpeculationsSessionNestingLevel(0), |
| 152 m_isParsingAtLineNumber(false), | 151 m_isParsingAtLineNumber(false), |
| 153 m_triedLoadingLinkHeaders(false), | 152 m_triedLoadingLinkHeaders(false), |
| 154 m_addedPendingStylesheetInBody(false), | 153 m_addedPendingStylesheetInBody(false), |
| 155 m_isWaitingForStylesheets(false) { | 154 m_isWaitingForStylesheets(false) { |
| 156 ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); | 155 DCHECK(shouldUseThreading() || (m_token && m_tokenizer)); |
| 157 // Threading is not allowed in prefetch mode. | 156 // Threading is not allowed in prefetch mode. |
| 158 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); | 157 DCHECK(!document.isPrefetchOnly() || !shouldUseThreading()); |
| 159 } | 158 } |
| 160 | 159 |
| 161 HTMLDocumentParser::~HTMLDocumentParser() {} | 160 HTMLDocumentParser::~HTMLDocumentParser() {} |
| 162 | 161 |
| 163 void HTMLDocumentParser::dispose() { | |
| 164 // In Oilpan, HTMLDocumentParser can die together with Document, and detach() | |
| 165 // is not called in this case. | |
| 166 if (m_haveBackgroundParser) | |
| 167 stopBackgroundParser(); | |
| 168 } | |
| 169 | |
| 170 DEFINE_TRACE(HTMLDocumentParser) { | 162 DEFINE_TRACE(HTMLDocumentParser) { |
| 171 visitor->trace(m_treeBuilder); | 163 visitor->trace(m_treeBuilder); |
| 172 visitor->trace(m_parserScheduler); | 164 visitor->trace(m_parserScheduler); |
| 173 visitor->trace(m_xssAuditorDelegate); | 165 visitor->trace(m_xssAuditorDelegate); |
| 174 visitor->trace(m_scriptRunner); | 166 visitor->trace(m_scriptRunner); |
| 167 visitor->trace(m_backgroundParser); | |
| 175 visitor->trace(m_preloader); | 168 visitor->trace(m_preloader); |
| 176 ScriptableDocumentParser::trace(visitor); | 169 ScriptableDocumentParser::trace(visitor); |
| 177 HTMLParserScriptRunnerHost::trace(visitor); | 170 HTMLParserScriptRunnerHost::trace(visitor); |
| 178 } | 171 } |
| 179 | 172 |
| 180 void HTMLDocumentParser::detach() { | 173 void HTMLDocumentParser::detach() { |
| 181 if (!isParsingFragment() && m_tokenizedChunkQueue.get() && | 174 if (!isParsingFragment() && m_tokenizedChunkQueue.get() && |
| 182 m_tokenizedChunkQueue->peakPendingChunkCount()) { | 175 m_tokenizedChunkQueue->peakPendingChunkCount()) { |
| 183 DEFINE_STATIC_LOCAL(CustomCountHistogram, peakPendingChunkHistogram, | 176 DEFINE_STATIC_LOCAL(CustomCountHistogram, peakPendingChunkHistogram, |
| 184 ("Parser.PeakPendingChunkCount", 1, 1000, 50)); | 177 ("Parser.PeakPendingChunkCount", 1, 1000, 50)); |
| 185 peakPendingChunkHistogram.count( | 178 peakPendingChunkHistogram.count( |
| 186 m_tokenizedChunkQueue->peakPendingChunkCount()); | 179 m_tokenizedChunkQueue->peakPendingChunkCount()); |
| 187 DEFINE_STATIC_LOCAL(CustomCountHistogram, peakPendingTokenHistogram, | 180 DEFINE_STATIC_LOCAL(CustomCountHistogram, peakPendingTokenHistogram, |
| 188 ("Parser.PeakPendingTokenCount", 1, 100000, 50)); | 181 ("Parser.PeakPendingTokenCount", 1, 100000, 50)); |
| 189 peakPendingTokenHistogram.count( | 182 peakPendingTokenHistogram.count( |
| 190 m_tokenizedChunkQueue->peakPendingTokenCount()); | 183 m_tokenizedChunkQueue->peakPendingTokenCount()); |
| 191 } | 184 } |
| 192 | 185 |
| 193 if (m_haveBackgroundParser) | 186 m_backgroundParser.clear(); |
| 194 stopBackgroundParser(); | |
| 195 DocumentParser::detach(); | 187 DocumentParser::detach(); |
| 196 if (m_scriptRunner) | 188 if (m_scriptRunner) |
| 197 m_scriptRunner->detach(); | 189 m_scriptRunner->detach(); |
| 198 m_treeBuilder->detach(); | 190 m_treeBuilder->detach(); |
| 199 // FIXME: It seems wrong that we would have a preload scanner here. Yet during | 191 // FIXME: It seems wrong that we would have a preload scanner here. Yet during |
| 200 // fast/dom/HTMLScriptElement/script-load-events.html we do. | 192 // fast/dom/HTMLScriptElement/script-load-events.html we do. |
| 201 m_preloadScanner.reset(); | 193 m_preloadScanner.reset(); |
| 202 m_insertionPreloadScanner.reset(); | 194 m_insertionPreloadScanner.reset(); |
| 203 if (m_parserScheduler) { | 195 if (m_parserScheduler) { |
| 204 m_parserScheduler->detach(); | 196 m_parserScheduler->detach(); |
| 205 m_parserScheduler.clear(); | 197 m_parserScheduler.clear(); |
| 206 } | 198 } |
| 207 // Oilpan: It is important to clear m_token to deallocate backing memory of | 199 // Oilpan: It is important to clear m_token to deallocate backing memory of |
| 208 // HTMLToken::m_data and let the allocator reuse the memory for | 200 // HTMLToken::m_data and let the allocator reuse the memory for |
| 209 // HTMLToken::m_data of a next HTMLDocumentParser. We need to clear | 201 // HTMLToken::m_data of a next HTMLDocumentParser. We need to clear |
| 210 // m_tokenizer first because m_tokenizer has a raw pointer to m_token. | 202 // m_tokenizer first because m_tokenizer has a raw pointer to m_token. |
| 211 m_tokenizer.reset(); | 203 m_tokenizer.reset(); |
| 212 m_token.reset(); | 204 m_token.reset(); |
| 213 } | 205 } |
| 214 | 206 |
| 215 void HTMLDocumentParser::stopParsing() { | 207 void HTMLDocumentParser::stopParsing() { |
| 216 DocumentParser::stopParsing(); | 208 DocumentParser::stopParsing(); |
| 217 if (m_parserScheduler) { | 209 if (m_parserScheduler) { |
| 218 m_parserScheduler->detach(); | 210 m_parserScheduler->detach(); |
| 219 m_parserScheduler.clear(); | 211 m_parserScheduler.clear(); |
| 220 } | 212 } |
| 221 if (m_haveBackgroundParser) | 213 m_backgroundParser.clear(); |
| 222 stopBackgroundParser(); | |
| 223 } | 214 } |
| 224 | 215 |
| 225 // This kicks off "Once the user agent stops parsing" as described by: | 216 // This kicks off "Once the user agent stops parsing" as described by: |
| 226 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the- end | 217 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the- end |
| 227 void HTMLDocumentParser::prepareToStopParsing() { | 218 void HTMLDocumentParser::prepareToStopParsing() { |
| 228 // FIXME: It may not be correct to disable this for the background parser. | 219 // FIXME: It may not be correct to disable this for the background parser. |
| 229 // That means hasInsertionPoint() may not be correct in some cases. | 220 // That means hasInsertionPoint() may not be correct in some cases. |
| 230 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); | 221 DCHECK(!hasInsertionPoint() || m_backgroundParser); |
| 231 | 222 |
| 232 // NOTE: This pump should only ever emit buffered character tokens. | 223 // NOTE: This pump should only ever emit buffered character tokens. |
| 233 if (m_tokenizer) { | 224 if (m_tokenizer) { |
| 234 ASSERT(!m_haveBackgroundParser); | 225 DCHECK(!m_backgroundParser); |
| 235 pumpTokenizerIfPossible(); | 226 pumpTokenizerIfPossible(); |
| 236 } | 227 } |
| 237 | 228 |
| 238 if (isStopped()) | 229 if (isStopped()) |
| 239 return; | 230 return; |
| 240 | 231 |
| 241 DocumentParser::prepareToStopParsing(); | 232 DocumentParser::prepareToStopParsing(); |
| 242 | 233 |
| 243 // We will not have a scriptRunner when parsing a DocumentFragment. | 234 // We will not have a scriptRunner when parsing a DocumentFragment. |
| 244 if (m_scriptRunner) | 235 if (m_scriptRunner) |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 263 | 254 |
| 264 pumpTokenizer(); | 255 pumpTokenizer(); |
| 265 } | 256 } |
| 266 | 257 |
| 267 bool HTMLDocumentParser::isScheduledForResume() const { | 258 bool HTMLDocumentParser::isScheduledForResume() const { |
| 268 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); | 259 return m_parserScheduler && m_parserScheduler->isScheduledForResume(); |
| 269 } | 260 } |
| 270 | 261 |
| 271 // Used by HTMLParserScheduler | 262 // Used by HTMLParserScheduler |
| 272 void HTMLDocumentParser::resumeParsingAfterYield() { | 263 void HTMLDocumentParser::resumeParsingAfterYield() { |
| 273 ASSERT(shouldUseThreading()); | 264 DCHECK(shouldUseThreading()); |
| 274 ASSERT(m_haveBackgroundParser); | 265 DCHECK(m_backgroundParser); |
| 275 | 266 |
| 276 checkIfBodyStlyesheetAdded(); | 267 checkIfBodyStlyesheetAdded(); |
| 277 if (isStopped() || isPaused()) | 268 if (isStopped() || isPaused()) |
| 278 return; | 269 return; |
| 279 | 270 |
| 280 pumpPendingSpeculations(); | 271 pumpPendingSpeculations(); |
| 281 } | 272 } |
| 282 | 273 |
| 283 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() { | 274 void HTMLDocumentParser::runScriptsForPausedTreeBuilder() { |
| 284 ASSERT(scriptingContentIsAllowed(getParserContentPolicy())); | 275 DCHECK(scriptingContentIsAllowed(getParserContentPolicy())); |
| 285 | 276 |
| 286 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); | 277 TextPosition scriptStartPosition = TextPosition::belowRangePosition(); |
| 287 Element* scriptElement = | 278 Element* scriptElement = |
| 288 m_treeBuilder->takeScriptToProcess(scriptStartPosition); | 279 m_treeBuilder->takeScriptToProcess(scriptStartPosition); |
| 289 // We will not have a scriptRunner when parsing a DocumentFragment. | 280 // We will not have a scriptRunner when parsing a DocumentFragment. |
| 290 if (m_scriptRunner) | 281 if (m_scriptRunner) |
| 291 m_scriptRunner->processScriptElement(scriptElement, scriptStartPosition); | 282 m_scriptRunner->processScriptElement(scriptElement, scriptStartPosition); |
| 292 checkIfBodyStlyesheetAdded(); | 283 checkIfBodyStlyesheetAdded(); |
| 293 } | 284 } |
| 294 | 285 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 353 for (auto& request : chunk->preloads) { | 344 for (auto& request : chunk->preloads) { |
| 354 // Link rel preloads don't need to wait for AppCache but they | 345 // Link rel preloads don't need to wait for AppCache but they |
| 355 // should probably wait for CSP. | 346 // should probably wait for CSP. |
| 356 if (!m_pendingCSPMetaToken && request->isLinkRelPreload()) | 347 if (!m_pendingCSPMetaToken && request->isLinkRelPreload()) |
| 357 linkRelPreloads.push_back(std::move(request)); | 348 linkRelPreloads.push_back(std::move(request)); |
| 358 else | 349 else |
| 359 m_queuedPreloads.push_back(std::move(request)); | 350 m_queuedPreloads.push_back(std::move(request)); |
| 360 } | 351 } |
| 361 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { | 352 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { |
| 362 const CompactHTMLToken& token = chunk->tokens->at(index); | 353 const CompactHTMLToken& token = chunk->tokens->at(index); |
| 363 ASSERT(token.type() == HTMLToken::TokenType::Character); | 354 DCHECK(token.type() == HTMLToken::TokenType::Character); |
| 364 m_queuedDocumentWriteScripts.push_back(token.data()); | 355 m_queuedDocumentWriteScripts.push_back(token.data()); |
| 365 } | 356 } |
| 366 } | 357 } |
| 367 m_preloader->takeAndPreload(linkRelPreloads); | 358 m_preloader->takeAndPreload(linkRelPreloads); |
| 368 } else { | 359 } else { |
| 369 // We can safely assume that there are no queued preloads request after the | 360 // We can safely assume that there are no queued preloads request after the |
| 370 // document element is available, as we empty the queue immediately after | 361 // document element is available, as we empty the queue immediately after |
| 371 // the document element is created in documentElementAvailable(). | 362 // the document element is created in documentElementAvailable(). |
| 372 ASSERT(m_queuedPreloads.isEmpty()); | 363 DCHECK(m_queuedPreloads.isEmpty()); |
| 373 ASSERT(m_queuedDocumentWriteScripts.isEmpty()); | 364 DCHECK(m_queuedDocumentWriteScripts.isEmpty()); |
| 374 // Loop through the chunks to generate preloads before any document.write | 365 // Loop through the chunks to generate preloads before any document.write |
| 375 // script evaluation takes place. Preloading these scripts is valuable and | 366 // script evaluation takes place. Preloading these scripts is valuable and |
| 376 // comparably cheap, while evaluating JS can be expensive. | 367 // comparably cheap, while evaluating JS can be expensive. |
| 377 for (auto& chunk : pendingChunks) | 368 for (auto& chunk : pendingChunks) |
| 378 m_preloader->takeAndPreload(chunk->preloads); | 369 m_preloader->takeAndPreload(chunk->preloads); |
| 379 for (auto& chunk : pendingChunks) { | 370 for (auto& chunk : pendingChunks) { |
| 380 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { | 371 for (auto& index : chunk->likelyDocumentWriteScriptIndices) { |
| 381 const CompactHTMLToken& token = chunk->tokens->at(index); | 372 const CompactHTMLToken& token = chunk->tokens->at(index); |
| 382 ASSERT(token.type() == HTMLToken::TokenType::Character); | 373 DCHECK(token.type() == HTMLToken::TokenType::Character); |
| 383 evaluateAndPreloadScriptForDocumentWrite(token.data()); | 374 evaluateAndPreloadScriptForDocumentWrite(token.data()); |
| 384 } | 375 } |
| 385 } | 376 } |
| 386 } | 377 } |
| 387 | 378 |
| 388 for (auto& chunk : pendingChunks) | 379 for (auto& chunk : pendingChunks) |
| 389 m_speculations.append(std::move(chunk)); | 380 m_speculations.append(std::move(chunk)); |
| 390 | 381 |
| 391 if (!isPaused() && !isScheduledForResume()) { | 382 if (!isPaused() && !isScheduledForResume()) { |
| 392 if (m_tasksWereSuspended) | 383 if (m_tasksWereSuspended) |
| 393 m_parserScheduler->forceResumeAfterYield(); | 384 m_parserScheduler->forceResumeAfterYield(); |
| 394 else | 385 else |
| 395 m_parserScheduler->scheduleForResume(); | 386 m_parserScheduler->scheduleForResume(); |
| 396 } | 387 } |
| 397 } | 388 } |
| 398 | 389 |
| 399 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( | 390 void HTMLDocumentParser::didReceiveEncodingDataFromBackgroundParser( |
| 400 const DocumentEncodingData& data) { | 391 const DocumentEncodingData& data) { |
| 392 if (!isParsing()) | |
|
Charlie Harrison
2017/02/08 23:48:01
This is necessary because now the bg parser is a m
Yoav Weiss
2017/02/14 06:45:47
ok
| |
| 393 return; | |
| 401 document()->setEncodingData(data); | 394 document()->setEncodingData(data); |
| 402 } | 395 } |
| 403 | 396 |
| 404 void HTMLDocumentParser::validateSpeculations( | 397 void HTMLDocumentParser::validateSpeculations( |
| 405 std::unique_ptr<TokenizedChunk> chunk) { | 398 std::unique_ptr<TokenizedChunk> chunk) { |
| 406 ASSERT(chunk); | 399 DCHECK(chunk); |
| 407 // TODO(kouhei): We should simplify codepath here by disallowing | 400 // TODO(kouhei): We should simplify codepath here by disallowing |
| 408 // validateSpeculations | 401 // validateSpeculations |
| 409 // while isPaused, and m_lastChunkBeforePause can simply be | 402 // while isPaused, and m_lastChunkBeforePause can simply be |
| 410 // pushed to m_speculations. | 403 // pushed to m_speculations. |
| 411 if (isPaused()) { | 404 if (isPaused()) { |
| 412 // We're waiting on a network script or stylesheet, just save the chunk, | 405 // We're waiting on a network script or stylesheet, just save the chunk, |
| 413 // we'll get a second validateSpeculations call after the script or | 406 // we'll get a second validateSpeculations call after the script or |
| 414 // stylesheet completes. This call should have been made immediately after | 407 // stylesheet completes. This call should have been made immediately after |
| 415 // runScriptsForPausedTreeBuilder in the script case which may have started | 408 // runScriptsForPausedTreeBuilder in the script case which may have started |
| 416 // a network load and left us waiting. | 409 // a network load and left us waiting. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 432 // Currently we're only smart enough to reuse the speculation buffer if the | 425 // Currently we're only smart enough to reuse the speculation buffer if the |
| 433 // tokenizer both starts and ends in the DataState. That state is simplest | 426 // tokenizer both starts and ends in the DataState. That state is simplest |
| 434 // because the HTMLToken is always in the Uninitialized state. We should | 427 // because the HTMLToken is always in the Uninitialized state. We should |
| 435 // consider whether we can reuse the speculation buffer in other states, but | 428 // consider whether we can reuse the speculation buffer in other states, but |
| 436 // we'd likely need to do something more sophisticated with the HTMLToken. | 429 // we'd likely need to do something more sophisticated with the HTMLToken. |
| 437 if (chunk->tokenizerState == HTMLTokenizer::DataState && | 430 if (chunk->tokenizerState == HTMLTokenizer::DataState && |
| 438 tokenizer->getState() == HTMLTokenizer::DataState && | 431 tokenizer->getState() == HTMLTokenizer::DataState && |
| 439 m_input.current().isEmpty() && | 432 m_input.current().isEmpty() && |
| 440 chunk->treeBuilderState == | 433 chunk->treeBuilderState == |
| 441 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) { | 434 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get())) { |
| 442 ASSERT(token->isUninitialized()); | 435 DCHECK(token->isUninitialized()); |
| 443 return; | 436 return; |
| 444 } | 437 } |
| 445 | 438 |
| 446 discardSpeculationsAndResumeFrom(std::move(chunk), std::move(token), | 439 discardSpeculationsAndResumeFrom(std::move(chunk), std::move(token), |
| 447 std::move(tokenizer)); | 440 std::move(tokenizer)); |
| 448 } | 441 } |
| 449 | 442 |
| 450 void HTMLDocumentParser::discardSpeculationsAndResumeFrom( | 443 void HTMLDocumentParser::discardSpeculationsAndResumeFrom( |
| 451 std::unique_ptr<TokenizedChunk> lastChunkBeforeScript, | 444 std::unique_ptr<TokenizedChunk> lastChunkBeforeScript, |
| 452 std::unique_ptr<HTMLToken> token, | 445 std::unique_ptr<HTMLToken> token, |
| 453 std::unique_ptr<HTMLTokenizer> tokenizer) { | 446 std::unique_ptr<HTMLTokenizer> tokenizer) { |
| 454 m_weakFactory.revokeAll(); | |
| 455 | |
| 456 size_t discardedTokenCount = 0; | 447 size_t discardedTokenCount = 0; |
| 457 for (const auto& speculation : m_speculations) { | 448 for (const auto& speculation : m_speculations) { |
| 458 discardedTokenCount += speculation->tokens->size(); | 449 discardedTokenCount += speculation->tokens->size(); |
| 459 } | 450 } |
| 460 DEFINE_STATIC_LOCAL(CustomCountHistogram, discardedTokenCountHistogram, | 451 DEFINE_STATIC_LOCAL(CustomCountHistogram, discardedTokenCountHistogram, |
| 461 ("Parser.DiscardedTokenCount", 1, 100000, 50)); | 452 ("Parser.DiscardedTokenCount", 1, 100000, 50)); |
| 462 discardedTokenCountHistogram.count(discardedTokenCount); | 453 discardedTokenCountHistogram.count(discardedTokenCount); |
| 463 | 454 |
| 464 m_speculations.clear(); | 455 m_speculations.clear(); |
| 465 m_pendingCSPMetaToken = nullptr; | 456 m_pendingCSPMetaToken = nullptr; |
| 466 m_queuedPreloads.clear(); | 457 m_queuedPreloads.clear(); |
| 467 | 458 |
| 468 std::unique_ptr<BackgroundHTMLParser::Checkpoint> checkpoint = | 459 std::unique_ptr<BackgroundHTMLParser::Checkpoint> checkpoint = |
| 469 WTF::wrapUnique(new BackgroundHTMLParser::Checkpoint); | 460 WTF::wrapUnique(new BackgroundHTMLParser::Checkpoint); |
| 470 checkpoint->parser = m_weakFactory.createWeakPtr(); | |
| 471 checkpoint->token = std::move(token); | 461 checkpoint->token = std::move(token); |
| 472 checkpoint->tokenizer = std::move(tokenizer); | 462 checkpoint->tokenizer = std::move(tokenizer); |
| 473 checkpoint->treeBuilderState = | 463 checkpoint->treeBuilderState = |
| 474 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); | 464 HTMLTreeBuilderSimulator::stateFor(m_treeBuilder.get()); |
| 475 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; | 465 checkpoint->inputCheckpoint = lastChunkBeforeScript->inputCheckpoint; |
| 476 checkpoint->preloadScannerCheckpoint = | 466 checkpoint->preloadScannerCheckpoint = |
| 477 lastChunkBeforeScript->preloadScannerCheckpoint; | 467 lastChunkBeforeScript->preloadScannerCheckpoint; |
| 478 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); | 468 checkpoint->unparsedInput = m_input.current().toString().isolatedCopy(); |
| 479 // FIXME: This should be passed in instead of cleared. | 469 // FIXME: This should be passed in instead of cleared. |
| 480 m_input.current().clear(); | 470 m_input.current().clear(); |
| 481 | 471 |
| 482 ASSERT(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); | 472 DCHECK(checkpoint->unparsedInput.isSafeToSendToAnotherThread()); |
| 483 m_loadingTaskRunner->postTask( | 473 m_backgroundParser->resumeFrom(std::move(checkpoint)); |
| 484 BLINK_FROM_HERE, | |
| 485 WTF::bind(&BackgroundHTMLParser::resumeFrom, m_backgroundParser, | |
| 486 WTF::passed(std::move(checkpoint)))); | |
| 487 } | 474 } |
| 488 | 475 |
| 489 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( | 476 size_t HTMLDocumentParser::processTokenizedChunkFromBackgroundParser( |
| 490 std::unique_ptr<TokenizedChunk> popChunk) { | 477 std::unique_ptr<TokenizedChunk> popChunk) { |
| 491 TRACE_EVENT_WITH_FLOW0( | 478 TRACE_EVENT_WITH_FLOW0( |
| 492 "blink,loading", | 479 "blink,loading", |
| 493 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", | 480 "HTMLDocumentParser::processTokenizedChunkFromBackgroundParser", |
| 494 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); | 481 popChunk.get(), TRACE_EVENT_FLAG_FLOW_IN); |
| 495 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); | 482 AutoReset<bool> hasLineNumber(&m_isParsingAtLineNumber, true); |
| 496 | 483 |
| 497 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); | 484 SECURITY_DCHECK(m_pumpSpeculationsSessionNestingLevel == 1); |
| 498 SECURITY_DCHECK(!inPumpSession()); | 485 SECURITY_DCHECK(!inPumpSession()); |
| 499 ASSERT(!isParsingFragment()); | 486 DCHECK(!isParsingFragment()); |
| 500 DCHECK(!isPaused()); | 487 DCHECK(!isPaused()); |
| 501 ASSERT(!isStopped()); | 488 DCHECK(!isStopped()); |
| 502 ASSERT(shouldUseThreading()); | 489 DCHECK(shouldUseThreading()); |
| 503 ASSERT(!m_tokenizer); | 490 DCHECK(!m_tokenizer); |
| 504 ASSERT(!m_token); | 491 DCHECK(!m_token); |
| 505 DCHECK(!m_lastChunkBeforePause); | 492 DCHECK(!m_lastChunkBeforePause); |
| 506 | 493 |
| 507 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); | 494 std::unique_ptr<TokenizedChunk> chunk(std::move(popChunk)); |
| 508 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); | 495 std::unique_ptr<CompactHTMLTokenStream> tokens = std::move(chunk->tokens); |
| 509 size_t elementTokenCount = 0; | 496 size_t elementTokenCount = 0; |
| 510 | 497 |
| 511 m_loadingTaskRunner->postTask( | 498 m_backgroundParser->startedChunkWithCheckpoint(chunk->inputCheckpoint); |
| 512 BLINK_FROM_HERE, | |
| 513 WTF::bind(&BackgroundHTMLParser::startedChunkWithCheckpoint, | |
| 514 m_backgroundParser, chunk->inputCheckpoint)); | |
| 515 | 499 |
| 516 for (const auto& xssInfo : chunk->xssInfos) { | 500 for (const auto& xssInfo : chunk->xssInfos) { |
| 517 m_textPosition = xssInfo->m_textPosition; | 501 m_textPosition = xssInfo->m_textPosition; |
| 518 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 502 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
| 519 if (isStopped()) | 503 if (isStopped()) |
| 520 break; | 504 break; |
| 521 } | 505 } |
| 522 // XSSAuditorDelegate can detach the parser if it decides to block the entire | 506 // XSSAuditorDelegate can detach the parser if it decides to block the entire |
| 523 // current document. | 507 // current document. |
| 524 if (isDetached()) | 508 if (isDetached()) |
| 525 return elementTokenCount; | 509 return elementTokenCount; |
| 526 | 510 |
| 527 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); | 511 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); |
| 528 it != tokens->end(); ++it) { | 512 it != tokens->end(); ++it) { |
| 529 ASSERT(!isWaitingForScripts()); | 513 DCHECK(!isWaitingForScripts()); |
| 530 | 514 |
| 531 if (!chunk->startingScript && | 515 if (!chunk->startingScript && |
| 532 (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag)) | 516 (it->type() == HTMLToken::StartTag || it->type() == HTMLToken::EndTag)) |
| 533 elementTokenCount++; | 517 elementTokenCount++; |
| 534 | 518 |
| 535 if (document()->frame() && | 519 if (document()->frame() && |
| 536 document()->frame()->navigationScheduler().locationChangePending()) { | 520 document()->frame()->navigationScheduler().locationChangePending()) { |
| 537 // To match main-thread parser behavior (which never checks | 521 // To match main-thread parser behavior (which never checks |
| 538 // locationChangePending on the EOF path) we peek to see if this chunk has | 522 // locationChangePending on the EOF path) we peek to see if this chunk has |
| 539 // an EOF and process it anyway. | 523 // an EOF and process it anyway. |
| 540 if (tokens->back().type() == HTMLToken::EndOfFile) { | 524 if (tokens->back().type() == HTMLToken::EndOfFile) { |
| 541 ASSERT( | 525 DCHECK( |
| 542 m_speculations | 526 m_speculations |
| 543 .isEmpty()); // There should never be any chunks after the EOF. | 527 .isEmpty()); // There should never be any chunks after the EOF. |
| 544 prepareToStopParsing(); | 528 prepareToStopParsing(); |
| 545 } | 529 } |
| 546 break; | 530 break; |
| 547 } | 531 } |
| 548 | 532 |
| 549 m_textPosition = it->textPosition(); | 533 m_textPosition = it->textPosition(); |
| 550 | 534 |
| 551 constructTreeFromCompactHTMLToken(*it); | 535 constructTreeFromCompactHTMLToken(*it); |
| 552 | 536 |
| 553 if (isStopped()) | 537 if (isStopped()) |
| 554 break; | 538 break; |
| 555 | 539 |
| 556 // Preloads were queued if there was a <meta> csp token in a tokenized | 540 // Preloads were queued if there was a <meta> csp token in a tokenized |
| 557 // chunk. | 541 // chunk. |
| 558 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { | 542 if (m_pendingCSPMetaToken && it == m_pendingCSPMetaToken) { |
| 559 m_pendingCSPMetaToken = nullptr; | 543 m_pendingCSPMetaToken = nullptr; |
| 560 fetchQueuedPreloads(); | 544 fetchQueuedPreloads(); |
| 561 } | 545 } |
| 562 | 546 |
| 563 if (isPaused()) { | 547 if (isPaused()) { |
| 564 // The script or stylesheet should be the last token of this bunch. | 548 // The script or stylesheet should be the last token of this bunch. |
| 565 ASSERT(it + 1 == tokens->end()); | 549 DCHECK(it + 1 == tokens->end()); |
| 566 if (isWaitingForScripts()) | 550 if (isWaitingForScripts()) |
| 567 runScriptsForPausedTreeBuilder(); | 551 runScriptsForPausedTreeBuilder(); |
| 568 validateSpeculations(std::move(chunk)); | 552 validateSpeculations(std::move(chunk)); |
| 569 break; | 553 break; |
| 570 } | 554 } |
| 571 | 555 |
| 572 if (it->type() == HTMLToken::EndOfFile) { | 556 if (it->type() == HTMLToken::EndOfFile) { |
| 573 // The EOF is assumed to be the last token of this bunch. | 557 // The EOF is assumed to be the last token of this bunch. |
| 574 ASSERT(it + 1 == tokens->end()); | 558 DCHECK(it + 1 == tokens->end()); |
| 575 // There should never be any chunks after the EOF. | 559 // There should never be any chunks after the EOF. |
| 576 ASSERT(m_speculations.isEmpty()); | 560 DCHECK(m_speculations.isEmpty()); |
| 577 prepareToStopParsing(); | 561 prepareToStopParsing(); |
| 578 break; | 562 break; |
| 579 } | 563 } |
| 580 | 564 |
| 581 ASSERT(!m_tokenizer); | 565 DCHECK(!m_tokenizer); |
| 582 ASSERT(!m_token); | 566 DCHECK(!m_token); |
| 583 } | 567 } |
| 584 | 568 |
| 585 // Make sure all required pending text nodes are emitted before returning. | 569 // Make sure all required pending text nodes are emitted before returning. |
| 586 // This leaves "script", "style" and "svg" nodes text nodes intact. | 570 // This leaves "script", "style" and "svg" nodes text nodes intact. |
| 587 if (!isStopped()) | 571 if (!isStopped()) |
| 588 m_treeBuilder->flush(FlushIfAtTextLimit); | 572 m_treeBuilder->flush(FlushIfAtTextLimit); |
| 589 | 573 |
| 590 m_isParsingAtLineNumber = false; | 574 m_isParsingAtLineNumber = false; |
| 591 | 575 |
| 592 return elementTokenCount; | 576 return elementTokenCount; |
| 593 } | 577 } |
| 594 | 578 |
| 595 void HTMLDocumentParser::pumpPendingSpeculations() { | 579 void HTMLDocumentParser::pumpPendingSpeculations() { |
| 596 // If this assert fails, you need to call validateSpeculations to make sure | 580 // If this assert fails, you need to call validateSpeculations to make sure |
| 597 // m_tokenizer and m_token don't have state that invalidates m_speculations. | 581 // m_tokenizer and m_token don't have state that invalidates m_speculations. |
| 598 ASSERT(!m_tokenizer); | 582 DCHECK(!m_tokenizer); |
| 599 ASSERT(!m_token); | 583 DCHECK(!m_token); |
| 600 DCHECK(!m_lastChunkBeforePause); | 584 DCHECK(!m_lastChunkBeforePause); |
| 601 DCHECK(!isPaused()); | 585 DCHECK(!isPaused()); |
| 602 ASSERT(!isStopped()); | 586 DCHECK(!isStopped()); |
| 603 ASSERT(!isScheduledForResume()); | 587 DCHECK(!isScheduledForResume()); |
| 604 ASSERT(!inPumpSession()); | 588 DCHECK(!inPumpSession()); |
| 605 | 589 |
| 606 // FIXME: Here should never be reached when there is a blocking script, | 590 // FIXME: Here should never be reached when there is a blocking script, |
| 607 // but it happens in unknown scenarios. See https://crbug.com/440901 | 591 // but it happens in unknown scenarios. See https://crbug.com/440901 |
| 608 if (isWaitingForScripts()) { | 592 if (isWaitingForScripts()) { |
| 609 m_parserScheduler->scheduleForResume(); | 593 m_parserScheduler->scheduleForResume(); |
| 610 return; | 594 return; |
| 611 } | 595 } |
| 612 | 596 |
| 613 // Do not allow pumping speculations in nested event loops. | 597 // Do not allow pumping speculations in nested event loops. |
| 614 if (m_pumpSpeculationsSessionNestingLevel) { | 598 if (m_pumpSpeculationsSessionNestingLevel) { |
| 615 m_parserScheduler->scheduleForResume(); | 599 m_parserScheduler->scheduleForResume(); |
| 616 return; | 600 return; |
| 617 } | 601 } |
| 618 | 602 |
| 619 // FIXME: Pass in current input length. | 603 // FIXME: Pass in current input length. |
| 620 TRACE_EVENT_BEGIN1("devtools.timeline", "ParseHTML", "beginData", | 604 TRACE_EVENT_BEGIN1("devtools.timeline", "ParseHTML", "beginData", |
| 621 InspectorParseHtmlEvent::beginData( | 605 InspectorParseHtmlEvent::beginData( |
| 622 document(), lineNumber().zeroBasedInt())); | 606 document(), lineNumber().zeroBasedInt())); |
| 623 | 607 |
| 624 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); | 608 SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); |
| 625 while (!m_speculations.isEmpty()) { | 609 while (!m_speculations.isEmpty()) { |
| 626 ASSERT(!isScheduledForResume()); | 610 DCHECK(!isScheduledForResume()); |
| 627 size_t elementTokenCount = | 611 size_t elementTokenCount = |
| 628 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); | 612 processTokenizedChunkFromBackgroundParser(m_speculations.takeFirst()); |
| 629 session.addedElementTokens(elementTokenCount); | 613 session.addedElementTokens(elementTokenCount); |
| 630 | 614 |
| 631 // Always check isParsing first as m_document may be null. Surprisingly, | 615 // Always check isParsing first as m_document may be null. Surprisingly, |
| 632 // isScheduledForResume() may be set here as a result of | 616 // isScheduledForResume() may be set here as a result of |
| 633 // processTokenizedChunkFromBackgroundParser running arbitrary javascript | 617 // processTokenizedChunkFromBackgroundParser running arbitrary javascript |
| 634 // which invokes nested event loops. (e.g. inspector breakpoints) | 618 // which invokes nested event loops. (e.g. inspector breakpoints) |
| 635 checkIfBodyStlyesheetAdded(); | 619 checkIfBodyStlyesheetAdded(); |
| 636 if (!isParsing() || isPaused() || isScheduledForResume()) | 620 if (!isParsing() || isPaused() || isScheduledForResume()) |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 647 InspectorParseHtmlEvent::endData(lineNumber().zeroBasedInt() - 1)); | 631 InspectorParseHtmlEvent::endData(lineNumber().zeroBasedInt() - 1)); |
| 648 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), | 632 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), |
| 649 "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", | 633 "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", |
| 650 InspectorUpdateCountersEvent::data()); | 634 InspectorUpdateCountersEvent::data()); |
| 651 } | 635 } |
| 652 | 636 |
| 653 void HTMLDocumentParser::forcePlaintextForTextDocument() { | 637 void HTMLDocumentParser::forcePlaintextForTextDocument() { |
| 654 if (shouldUseThreading()) { | 638 if (shouldUseThreading()) { |
| 655 // This method is called before any data is appended, so we have to start | 639 // This method is called before any data is appended, so we have to start |
| 656 // the background parser ourselves. | 640 // the background parser ourselves. |
| 657 if (!m_haveBackgroundParser) | 641 if (!m_backgroundParser) |
| 658 startBackgroundParser(); | 642 startBackgroundParser(); |
| 659 | 643 |
| 660 // This task should be synchronous, because otherwise synchronous | 644 // This task should be synchronous, because otherwise synchronous |
| 661 // tokenizing can happen before plaintext is forced. | 645 // tokenizing can happen before plaintext is forced. |
| 662 m_backgroundParser->forcePlaintextForTextDocument(); | 646 m_backgroundParser->forcePlaintextForTextDocument(); |
| 663 } else | 647 } else |
| 664 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); | 648 m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); |
| 665 } | 649 } |
| 666 | 650 |
| 667 void HTMLDocumentParser::pumpTokenizer() { | 651 void HTMLDocumentParser::pumpTokenizer() { |
| 668 ASSERT(!isStopped()); | 652 DCHECK(!isStopped()); |
| 669 ASSERT(m_tokenizer); | 653 DCHECK(m_tokenizer); |
| 670 ASSERT(m_token); | 654 DCHECK(m_token); |
| 671 | 655 |
| 672 PumpSession session(m_pumpSessionNestingLevel); | 656 PumpSession session(m_pumpSessionNestingLevel); |
| 673 | 657 |
| 674 // We tell the InspectorInstrumentation about every pump, even if we end up | 658 // We tell the InspectorInstrumentation about every pump, even if we end up |
| 675 // pumping nothing. It can filter out empty pumps itself. | 659 // pumping nothing. It can filter out empty pumps itself. |
| 676 // FIXME: m_input.current().length() is only accurate if we end up parsing the | 660 // FIXME: m_input.current().length() is only accurate if we end up parsing the |
| 677 // whole buffer in this pump. We should pass how much we parsed as part of | 661 // whole buffer in this pump. We should pass how much we parsed as part of |
| 678 // didWriteHTML instead of willWriteHTML. | 662 // didWriteHTML instead of willWriteHTML. |
| 679 TRACE_EVENT_BEGIN1( | 663 TRACE_EVENT_BEGIN1( |
| 680 "devtools.timeline", "ParseHTML", "beginData", | 664 "devtools.timeline", "ParseHTML", "beginData", |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 701 token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { | 685 token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { |
| 702 m_xssAuditorDelegate.didBlockScript(*xssInfo); | 686 m_xssAuditorDelegate.didBlockScript(*xssInfo); |
| 703 // If we're in blocking mode, we might stop the parser in | 687 // If we're in blocking mode, we might stop the parser in |
| 704 // 'didBlockScript()'. In that case, exit early. | 688 // 'didBlockScript()'. In that case, exit early. |
| 705 if (!isParsing()) | 689 if (!isParsing()) |
| 706 return; | 690 return; |
| 707 } | 691 } |
| 708 } | 692 } |
| 709 | 693 |
| 710 constructTreeFromHTMLToken(); | 694 constructTreeFromHTMLToken(); |
| 711 ASSERT(isStopped() || token().isUninitialized()); | 695 DCHECK(isStopped() || token().isUninitialized()); |
| 712 } | 696 } |
| 713 | 697 |
| 714 if (isStopped()) | 698 if (isStopped()) |
| 715 return; | 699 return; |
| 716 | 700 |
| 717 // There should only be PendingText left since the tree-builder always flushes | 701 // There should only be PendingText left since the tree-builder always flushes |
| 718 // the task queue before returning. In case that ever changes, crash. | 702 // the task queue before returning. In case that ever changes, crash. |
| 719 m_treeBuilder->flush(FlushAlways); | 703 m_treeBuilder->flush(FlushAlways); |
| 720 RELEASE_ASSERT(!isStopped()); | 704 CHECK(!isStopped()); |
| 721 | 705 |
| 722 if (isPaused()) { | 706 if (isPaused()) { |
| 723 ASSERT(m_tokenizer->getState() == HTMLTokenizer::DataState); | 707 DCHECK(m_tokenizer->getState() == HTMLTokenizer::DataState); |
| 724 | 708 |
| 725 ASSERT(m_preloader); | 709 DCHECK(m_preloader); |
| 726 // TODO(kouhei): m_preloader should be always available for synchronous | 710 // TODO(kouhei): m_preloader should be always available for synchronous |
| 727 // parsing case, adding paranoia if for speculative crash fix for | 711 // parsing case, adding paranoia if for speculative crash fix for |
| 728 // crbug.com/465478 | 712 // crbug.com/465478 |
| 729 if (m_preloader) { | 713 if (m_preloader) { |
| 730 if (!m_preloadScanner) { | 714 if (!m_preloadScanner) { |
| 731 m_preloadScanner = createPreloadScanner(); | 715 m_preloadScanner = createPreloadScanner(); |
| 732 m_preloadScanner->appendToEnd(m_input.current()); | 716 m_preloadScanner->appendToEnd(m_input.current()); |
| 733 } | 717 } |
| 734 scanAndPreload(m_preloadScanner.get()); | 718 scanAndPreload(m_preloadScanner.get()); |
| 735 } | 719 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 757 token().clear(); | 741 token().clear(); |
| 758 | 742 |
| 759 m_treeBuilder->constructTree(&atomicToken); | 743 m_treeBuilder->constructTree(&atomicToken); |
| 760 checkIfBodyStlyesheetAdded(); | 744 checkIfBodyStlyesheetAdded(); |
| 761 | 745 |
| 762 // FIXME: constructTree may synchronously cause Document to be detached. | 746 // FIXME: constructTree may synchronously cause Document to be detached. |
| 763 if (!m_token) | 747 if (!m_token) |
| 764 return; | 748 return; |
| 765 | 749 |
| 766 if (!token().isUninitialized()) { | 750 if (!token().isUninitialized()) { |
| 767 ASSERT(token().type() == HTMLToken::Character); | 751 DCHECK(token().type() == HTMLToken::Character); |
| 768 token().clear(); | 752 token().clear(); |
| 769 } | 753 } |
| 770 } | 754 } |
| 771 | 755 |
| 772 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( | 756 void HTMLDocumentParser::constructTreeFromCompactHTMLToken( |
| 773 const CompactHTMLToken& compactToken) { | 757 const CompactHTMLToken& compactToken) { |
| 774 AtomicHTMLToken token(compactToken); | 758 AtomicHTMLToken token(compactToken); |
| 775 m_treeBuilder->constructTree(&token); | 759 m_treeBuilder->constructTree(&token); |
| 776 checkIfBodyStlyesheetAdded(); | 760 checkIfBodyStlyesheetAdded(); |
| 777 } | 761 } |
| 778 | 762 |
| 779 bool HTMLDocumentParser::hasInsertionPoint() { | 763 bool HTMLDocumentParser::hasInsertionPoint() { |
| 780 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our | 764 // FIXME: The wasCreatedByScript() branch here might not be fully correct. Our |
| 781 // model of the EOF character differs slightly from the one in the spec | 765 // model of the EOF character differs slightly from the one in the spec |
| 782 // because our treatment is uniform between network-sourced and script-sourced | 766 // because our treatment is uniform between network-sourced and script-sourced |
| 783 // input streams whereas the spec treats them differently. | 767 // input streams whereas the spec treats them differently. |
| 784 return m_input.hasInsertionPoint() || | 768 return m_input.hasInsertionPoint() || |
| 785 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); | 769 (wasCreatedByScript() && !m_input.haveSeenEndOfFile()); |
| 786 } | 770 } |
| 787 | 771 |
| 788 void HTMLDocumentParser::insert(const SegmentedString& source) { | 772 void HTMLDocumentParser::insert(const SegmentedString& source) { |
| 789 if (isStopped()) | 773 if (isStopped()) |
| 790 return; | 774 return; |
| 791 | 775 |
| 792 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", | 776 TRACE_EVENT1("blink", "HTMLDocumentParser::insert", "source_length", |
| 793 source.length()); | 777 source.length()); |
| 794 | 778 |
| 795 if (!m_tokenizer) { | 779 if (!m_tokenizer) { |
| 796 ASSERT(!inPumpSession()); | 780 DCHECK(!inPumpSession()); |
| 797 ASSERT(m_haveBackgroundParser || wasCreatedByScript()); | 781 DCHECK(m_backgroundParser || wasCreatedByScript()); |
| 798 m_token = WTF::wrapUnique(new HTMLToken); | 782 m_token = WTF::wrapUnique(new HTMLToken); |
| 799 m_tokenizer = HTMLTokenizer::create(m_options); | 783 m_tokenizer = HTMLTokenizer::create(m_options); |
| 800 } | 784 } |
| 801 | 785 |
| 802 SegmentedString excludedLineNumberSource(source); | 786 SegmentedString excludedLineNumberSource(source); |
| 803 excludedLineNumberSource.setExcludeLineNumbers(); | 787 excludedLineNumberSource.setExcludeLineNumbers(); |
| 804 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); | 788 m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); |
| 805 pumpTokenizerIfPossible(); | 789 pumpTokenizerIfPossible(); |
| 806 | 790 |
| 807 if (isPaused()) { | 791 if (isPaused()) { |
| 808 // Check the document.write() output with a separate preload scanner as | 792 // Check the document.write() output with a separate preload scanner as |
| 809 // the main scanner can't deal with insertions. | 793 // the main scanner can't deal with insertions. |
| 810 if (!m_insertionPreloadScanner) | 794 if (!m_insertionPreloadScanner) |
| 811 m_insertionPreloadScanner = createPreloadScanner(); | 795 m_insertionPreloadScanner = createPreloadScanner(); |
| 812 m_insertionPreloadScanner->appendToEnd(source); | 796 m_insertionPreloadScanner->appendToEnd(source); |
| 813 scanAndPreload(m_insertionPreloadScanner.get()); | 797 scanAndPreload(m_insertionPreloadScanner.get()); |
| 814 } | 798 } |
| 815 | 799 |
| 816 endIfDelayed(); | 800 endIfDelayed(); |
| 817 } | 801 } |
| 818 | 802 |
| 819 void HTMLDocumentParser::startBackgroundParser() { | 803 void HTMLDocumentParser::startBackgroundParser() { |
| 820 ASSERT(!isStopped()); | 804 DCHECK(!isStopped()); |
| 821 ASSERT(shouldUseThreading()); | 805 DCHECK(shouldUseThreading()); |
| 822 ASSERT(!m_haveBackgroundParser); | 806 DCHECK(!m_backgroundParser); |
| 823 ASSERT(document()); | 807 DCHECK(document()); |
| 824 m_haveBackgroundParser = true; | |
| 825 | 808 |
| 826 // TODO(alexclarke): Remove WebFrameScheduler::setDocumentParsingInBackground | 809 // TODO(csharrison): Remove WebFrameScheduler::setDocumentParsingInBackground. |
| 827 // when background parser goes away. | |
| 828 if (document()->frame() && document()->frame()->frameScheduler()) | 810 if (document()->frame() && document()->frame()->frameScheduler()) |
| 829 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); | 811 document()->frame()->frameScheduler()->setDocumentParsingInBackground(true); |
| 830 | 812 |
| 831 // Make sure that a resolver is set up, so that the correct viewport | 813 // Make sure that a resolver is set up, so that the correct viewport |
| 832 // dimensions will be fed to the background parser and preload scanner. | 814 // dimensions will be fed to the background parser and preload scanner. |
| 833 if (document()->loader()) | 815 if (document()->loader()) |
| 834 document()->ensureStyleResolver(); | 816 document()->ensureStyleResolver(); |
| 835 | 817 |
| 836 std::unique_ptr<BackgroundHTMLParser::Configuration> config = | 818 std::unique_ptr<BackgroundHTMLParser::Configuration> config = |
| 837 WTF::wrapUnique(new BackgroundHTMLParser::Configuration); | 819 WTF::wrapUnique(new BackgroundHTMLParser::Configuration); |
| 838 config->options = m_options; | 820 config->options = m_options; |
| 839 config->parser = m_weakFactory.createWeakPtr(); | |
| 840 config->xssAuditor = WTF::wrapUnique(new XSSAuditor); | 821 config->xssAuditor = WTF::wrapUnique(new XSSAuditor); |
| 841 config->xssAuditor->init(document(), &m_xssAuditorDelegate); | 822 config->xssAuditor->init(document(), &m_xssAuditorDelegate); |
| 842 | 823 |
| 843 config->decoder = takeDecoder(); | 824 config->decoder = takeDecoder(); |
| 844 config->tokenizedChunkQueue = m_tokenizedChunkQueue.get(); | 825 config->tokenizedChunkQueue = m_tokenizedChunkQueue.get(); |
| 845 if (document()->settings()) { | 826 if (document()->settings()) { |
| 846 if (document() | 827 if (document() |
| 847 ->settings() | 828 ->settings() |
| 848 ->getBackgroundHtmlParserOutstandingTokenLimit()) { | 829 ->getBackgroundHtmlParserOutstandingTokenLimit()) { |
| 849 config->outstandingTokenLimit = | 830 config->outstandingTokenLimit = |
| 850 document() | 831 document() |
| 851 ->settings() | 832 ->settings() |
| 852 ->getBackgroundHtmlParserOutstandingTokenLimit(); | 833 ->getBackgroundHtmlParserOutstandingTokenLimit(); |
| 853 } | 834 } |
| 854 if (document()->settings()->getBackgroundHtmlParserPendingTokenLimit()) { | 835 if (document()->settings()->getBackgroundHtmlParserPendingTokenLimit()) { |
| 855 config->pendingTokenLimit = | 836 config->pendingTokenLimit = |
| 856 document()->settings()->getBackgroundHtmlParserPendingTokenLimit(); | 837 document()->settings()->getBackgroundHtmlParserPendingTokenLimit(); |
| 857 } | 838 } |
| 858 } | 839 } |
| 859 | 840 |
| 860 ASSERT(config->xssAuditor->isSafeToSendToAnotherThread()); | 841 DCHECK(config->xssAuditor->isSafeToSendToAnotherThread()); |
| 861 | 842 |
| 862 // The background parser is created on the main thread, but may otherwise | |
| 863 // only be used from the parser thread. | |
| 864 m_backgroundParser = | 843 m_backgroundParser = |
| 865 BackgroundHTMLParser::create(std::move(config), m_loadingTaskRunner); | 844 BackgroundHTMLParser::create(this, *document(), std::move(config)); |
| 866 // TODO(csharrison): This is a hack to initialize MediaValuesCached on the | |
| 867 // correct thread. We should get rid of it. | |
| 868 m_backgroundParser->init( | |
| 869 document()->url(), CachedDocumentParameters::create(document()), | |
| 870 MediaValuesCached::MediaValuesCachedData(*document())); | |
| 871 } | |
| 872 | |
| 873 void HTMLDocumentParser::stopBackgroundParser() { | |
| 874 ASSERT(shouldUseThreading()); | |
| 875 ASSERT(m_haveBackgroundParser); | |
| 876 | |
| 877 if (m_haveBackgroundParser && document()->frame() && | |
| 878 document()->frame()->frameScheduler()) | |
| 879 document()->frame()->frameScheduler()->setDocumentParsingInBackground( | |
| 880 false); | |
| 881 | |
| 882 m_haveBackgroundParser = false; | |
| 883 | |
| 884 // Make this sync, as lsan triggers on some unittests if the task runner is | |
| 885 // used. | |
| 886 m_backgroundParser->stop(); | |
| 887 m_weakFactory.revokeAll(); | |
| 888 } | 845 } |
| 889 | 846 |
| 890 void HTMLDocumentParser::append(const String& inputSource) { | 847 void HTMLDocumentParser::append(const String& inputSource) { |
| 891 if (isStopped()) | 848 if (isStopped()) |
| 892 return; | 849 return; |
| 893 | 850 |
| 894 // We should never reach this point if we're using a parser thread, as | 851 // We should never reach this point if we're using a parser thread, as |
| 895 // appendBytes() will directly ship the data to the thread. | 852 // appendBytes() will directly ship the data to the thread. |
| 896 ASSERT(!shouldUseThreading()); | 853 DCHECK(!shouldUseThreading()); |
| 897 | 854 |
| 898 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 855 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
| 899 "HTMLDocumentParser::append", "size", inputSource.length()); | 856 "HTMLDocumentParser::append", "size", inputSource.length()); |
| 900 const SegmentedString source(inputSource); | 857 const SegmentedString source(inputSource); |
| 901 | 858 |
| 902 if (document()->isPrefetchOnly()) { | 859 if (document()->isPrefetchOnly()) { |
| 903 if (!m_preloadScanner) | 860 if (!m_preloadScanner) |
| 904 m_preloadScanner = createPreloadScanner(); | 861 m_preloadScanner = createPreloadScanner(); |
| 905 | 862 |
| 906 m_preloadScanner->appendToEnd(source); | 863 m_preloadScanner->appendToEnd(source); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 931 // this data in a less-nested write(). | 888 // this data in a less-nested write(). |
| 932 return; | 889 return; |
| 933 } | 890 } |
| 934 | 891 |
| 935 pumpTokenizerIfPossible(); | 892 pumpTokenizerIfPossible(); |
| 936 | 893 |
| 937 endIfDelayed(); | 894 endIfDelayed(); |
| 938 } | 895 } |
| 939 | 896 |
| 940 void HTMLDocumentParser::end() { | 897 void HTMLDocumentParser::end() { |
| 941 ASSERT(!isDetached()); | 898 DCHECK(!isDetached()); |
| 942 ASSERT(!isScheduledForResume()); | 899 DCHECK(!isScheduledForResume()); |
| 943 | 900 |
| 944 if (m_haveBackgroundParser) | 901 m_backgroundParser.clear(); |
| 945 stopBackgroundParser(); | |
| 946 | 902 |
| 947 // Informs the the rest of WebCore that parsing is really finished (and | 903 // Informs the the rest of WebCore that parsing is really finished (and |
| 948 // deletes this). | 904 // deletes this). |
| 949 m_treeBuilder->finished(); | 905 m_treeBuilder->finished(); |
| 950 | 906 |
| 951 DocumentParser::stopParsing(); | 907 DocumentParser::stopParsing(); |
| 952 } | 908 } |
| 953 | 909 |
| 954 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { | 910 void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd() { |
| 955 ASSERT(isStopping()); | 911 DCHECK(isStopping()); |
| 956 // FIXME: It may not be correct to disable this for the background parser. | 912 // FIXME: It may not be correct to disable this for the background parser. |
| 957 // That means hasInsertionPoint() may not be correct in some cases. | 913 // That means hasInsertionPoint() may not be correct in some cases. |
| 958 ASSERT(!hasInsertionPoint() || m_haveBackgroundParser); | 914 DCHECK(!hasInsertionPoint() || m_backgroundParser); |
| 959 if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing()) | 915 if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing()) |
| 960 return; | 916 return; |
| 961 end(); | 917 end(); |
| 962 } | 918 } |
| 963 | 919 |
| 964 void HTMLDocumentParser::attemptToEnd() { | 920 void HTMLDocumentParser::attemptToEnd() { |
| 965 // finish() indicates we will not receive any more data. If we are waiting on | 921 // finish() indicates we will not receive any more data. If we are waiting on |
| 966 // an external script to load, we can't finish parsing quite yet. | 922 // an external script to load, we can't finish parsing quite yet. |
| 967 | 923 |
| 968 if (shouldDelayEnd()) { | 924 if (shouldDelayEnd()) { |
| 969 m_endWasDelayed = true; | 925 m_endWasDelayed = true; |
| 970 return; | 926 return; |
| 971 } | 927 } |
| 972 prepareToStopParsing(); | 928 prepareToStopParsing(); |
| 973 } | 929 } |
| 974 | 930 |
| 975 void HTMLDocumentParser::endIfDelayed() { | 931 void HTMLDocumentParser::endIfDelayed() { |
| 976 // If we've already been detached, don't bother ending. | 932 // If we've already been detached, don't bother ending. |
| 977 if (isDetached()) | 933 if (isDetached()) |
| 978 return; | 934 return; |
| 979 | 935 |
| 980 if (!m_endWasDelayed || shouldDelayEnd()) | 936 if (!m_endWasDelayed || shouldDelayEnd()) |
| 981 return; | 937 return; |
| 982 | 938 |
| 983 m_endWasDelayed = false; | 939 m_endWasDelayed = false; |
| 984 prepareToStopParsing(); | 940 prepareToStopParsing(); |
| 985 } | 941 } |
| 986 | 942 |
| 987 void HTMLDocumentParser::finish() { | 943 void HTMLDocumentParser::finish() { |
| 988 // FIXME: We should ASSERT(!m_parserStopped) here, since it does not makes | 944 // FIXME: We should DCHECK(!m_parserStopped) here, since it does not makes |
| 989 // sense to call any methods on DocumentParser once it's been stopped. | 945 // sense to call any methods on DocumentParser once it's been stopped. |
| 990 // However, FrameLoader::stop calls DocumentParser::finish unconditionally. | 946 // However, FrameLoader::stop calls DocumentParser::finish unconditionally. |
| 991 | 947 |
| 992 flush(); | 948 flush(); |
| 993 if (isDetached()) | 949 if (isDetached()) |
| 994 return; | 950 return; |
| 995 | 951 |
| 996 // Empty documents never got an append() call, and thus have never started a | 952 // Empty documents never got an append() call, and thus have never started a |
| 997 // background parser. In those cases, we ignore shouldUseThreading() and fall | 953 // background parser. In those cases, we ignore shouldUseThreading() and fall |
| 998 // through to the non-threading case. | 954 // through to the non-threading case. |
| 999 if (m_haveBackgroundParser) { | 955 if (m_backgroundParser) { |
| 1000 if (!m_input.haveSeenEndOfFile()) | 956 if (!m_input.haveSeenEndOfFile()) |
| 1001 m_input.closeWithoutMarkingEndOfFile(); | 957 m_input.closeWithoutMarkingEndOfFile(); |
| 1002 m_loadingTaskRunner->postTask( | 958 m_backgroundParser->finish(); |
| 1003 BLINK_FROM_HERE, | |
| 1004 WTF::bind(&BackgroundHTMLParser::finish, m_backgroundParser)); | |
| 1005 return; | 959 return; |
| 1006 } | 960 } |
| 1007 | 961 |
| 1008 if (!m_tokenizer) { | 962 if (!m_tokenizer) { |
| 1009 ASSERT(!m_token); | 963 DCHECK(!m_token); |
| 1010 // We're finishing before receiving any data. Rather than booting up the | 964 // We're finishing before receiving any data. Rather than booting up the |
| 1011 // background parser just to spin it down, we finish parsing synchronously. | 965 // background parser just to spin it down, we finish parsing synchronously. |
| 1012 m_token = WTF::wrapUnique(new HTMLToken); | 966 m_token = WTF::wrapUnique(new HTMLToken); |
| 1013 m_tokenizer = HTMLTokenizer::create(m_options); | 967 m_tokenizer = HTMLTokenizer::create(m_options); |
| 1014 } | 968 } |
| 1015 | 969 |
| 1016 // We're not going to get any more data off the network, so we tell the input | 970 // We're not going to get any more data off the network, so we tell the input |
| 1017 // stream we've reached the end of file. finish() can be called more than | 971 // stream we've reached the end of file. finish() can be called more than |
| 1018 // once, if the first time does not call end(). | 972 // once, if the first time does not call end(). |
| 1019 if (!m_input.haveSeenEndOfFile()) | 973 if (!m_input.haveSeenEndOfFile()) |
| 1020 m_input.markEndOfFile(); | 974 m_input.markEndOfFile(); |
| 1021 | 975 |
| 1022 attemptToEnd(); | 976 attemptToEnd(); |
| 1023 } | 977 } |
| 1024 | 978 |
| 1025 bool HTMLDocumentParser::isExecutingScript() const { | 979 bool HTMLDocumentParser::isExecutingScript() const { |
| 1026 if (!m_scriptRunner) | 980 if (!m_scriptRunner) |
| 1027 return false; | 981 return false; |
| 1028 return m_scriptRunner->isExecutingScript(); | 982 return m_scriptRunner->isExecutingScript(); |
| 1029 } | 983 } |
| 1030 | 984 |
| 1031 bool HTMLDocumentParser::isParsingAtLineNumber() const { | 985 bool HTMLDocumentParser::isParsingAtLineNumber() const { |
| 1032 return m_isParsingAtLineNumber && | 986 return m_isParsingAtLineNumber && |
| 1033 ScriptableDocumentParser::isParsingAtLineNumber(); | 987 ScriptableDocumentParser::isParsingAtLineNumber(); |
| 1034 } | 988 } |
| 1035 | 989 |
| 1036 OrdinalNumber HTMLDocumentParser::lineNumber() const { | 990 OrdinalNumber HTMLDocumentParser::lineNumber() const { |
| 1037 if (m_haveBackgroundParser) | 991 if (m_backgroundParser) |
| 1038 return m_textPosition.m_line; | 992 return m_textPosition.m_line; |
| 1039 | 993 |
| 1040 return m_input.current().currentLine(); | 994 return m_input.current().currentLine(); |
| 1041 } | 995 } |
| 1042 | 996 |
| 1043 TextPosition HTMLDocumentParser::textPosition() const { | 997 TextPosition HTMLDocumentParser::textPosition() const { |
| 1044 if (m_haveBackgroundParser) | 998 if (m_backgroundParser) |
| 1045 return m_textPosition; | 999 return m_textPosition; |
| 1046 | 1000 |
| 1047 const SegmentedString& currentString = m_input.current(); | 1001 const SegmentedString& currentString = m_input.current(); |
| 1048 OrdinalNumber line = currentString.currentLine(); | 1002 OrdinalNumber line = currentString.currentLine(); |
| 1049 OrdinalNumber column = currentString.currentColumn(); | 1003 OrdinalNumber column = currentString.currentColumn(); |
| 1050 | 1004 |
| 1051 return TextPosition(line, column); | 1005 return TextPosition(line, column); |
| 1052 } | 1006 } |
| 1053 | 1007 |
| 1054 bool HTMLDocumentParser::isWaitingForScripts() const { | 1008 bool HTMLDocumentParser::isWaitingForScripts() const { |
| 1055 // When the TreeBuilder encounters a </script> tag, it returns to the | 1009 // When the TreeBuilder encounters a </script> tag, it returns to the |
| 1056 // HTMLDocumentParser where the script is transfered from the treebuilder to | 1010 // HTMLDocumentParser where the script is transfered from the treebuilder to |
| 1057 // the script runner. The script runner will hold the script until its loaded | 1011 // the script runner. The script runner will hold the script until its loaded |
| 1058 // and run. During any of this time, we want to count ourselves as "waiting | 1012 // and run. During any of this time, we want to count ourselves as "waiting |
| 1059 // for a script" and thus run the preload scanner, as well as delay completion | 1013 // for a script" and thus run the preload scanner, as well as delay completion |
| 1060 // of parsing. | 1014 // of parsing. |
| 1061 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); | 1015 bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript(); |
| 1062 bool scriptRunnerHasBlockingScript = | 1016 bool scriptRunnerHasBlockingScript = |
| 1063 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); | 1017 m_scriptRunner && m_scriptRunner->hasParserBlockingScript(); |
| 1064 // Since the parser is paused while a script runner has a blocking script, it | 1018 // Since the parser is paused while a script runner has a blocking script, it |
| 1065 // should never be possible to end up with both objects holding a blocking | 1019 // should never be possible to end up with both objects holding a blocking |
| 1066 // script. | 1020 // script. |
| 1067 ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); | 1021 DCHECK(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript)); |
| 1068 // If either object has a blocking script, the parser should be paused. | 1022 // If either object has a blocking script, the parser should be paused. |
| 1069 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || | 1023 return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || |
| 1070 m_reentryPermit->parserPauseFlag(); | 1024 m_reentryPermit->parserPauseFlag(); |
| 1071 } | 1025 } |
| 1072 | 1026 |
| 1073 void HTMLDocumentParser::resumeParsingAfterPause() { | 1027 void HTMLDocumentParser::resumeParsingAfterPause() { |
| 1074 ASSERT(!isExecutingScript()); | 1028 DCHECK(!isExecutingScript()); |
| 1075 DCHECK(!isPaused()); | 1029 DCHECK(!isPaused()); |
| 1076 | 1030 |
| 1077 checkIfBodyStlyesheetAdded(); | 1031 checkIfBodyStlyesheetAdded(); |
| 1078 if (isPaused()) | 1032 if (isPaused()) |
| 1079 return; | 1033 return; |
| 1080 | 1034 |
| 1081 if (m_haveBackgroundParser) { | 1035 if (m_backgroundParser) { |
| 1082 if (m_lastChunkBeforePause) { | 1036 if (m_lastChunkBeforePause) { |
| 1083 validateSpeculations(std::move(m_lastChunkBeforePause)); | 1037 validateSpeculations(std::move(m_lastChunkBeforePause)); |
| 1084 DCHECK(!m_lastChunkBeforePause); | 1038 DCHECK(!m_lastChunkBeforePause); |
| 1085 pumpPendingSpeculations(); | 1039 pumpPendingSpeculations(); |
| 1086 } | 1040 } |
| 1087 return; | 1041 return; |
| 1088 } | 1042 } |
| 1089 | 1043 |
| 1090 m_insertionPreloadScanner.reset(); | 1044 m_insertionPreloadScanner.reset(); |
| 1091 if (m_tokenizer) { | 1045 if (m_tokenizer) { |
| 1092 pumpTokenizerIfPossible(); | 1046 pumpTokenizerIfPossible(); |
| 1093 } | 1047 } |
| 1094 endIfDelayed(); | 1048 endIfDelayed(); |
| 1095 } | 1049 } |
| 1096 | 1050 |
| 1097 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan() { | 1051 void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan() { |
| 1098 ASSERT(m_preloadScanner); | 1052 DCHECK(m_preloadScanner); |
| 1099 m_preloadScanner->appendToEnd(m_input.current()); | 1053 m_preloadScanner->appendToEnd(m_input.current()); |
| 1100 scanAndPreload(m_preloadScanner.get()); | 1054 scanAndPreload(m_preloadScanner.get()); |
| 1101 } | 1055 } |
| 1102 | 1056 |
| 1103 void HTMLDocumentParser::notifyScriptLoaded(PendingScript* pendingScript) { | 1057 void HTMLDocumentParser::notifyScriptLoaded(PendingScript* pendingScript) { |
| 1104 ASSERT(m_scriptRunner); | 1058 DCHECK(m_scriptRunner); |
| 1105 ASSERT(!isExecutingScript()); | 1059 DCHECK(!isExecutingScript()); |
| 1106 | 1060 |
| 1107 if (isStopped()) { | 1061 if (isStopped()) { |
| 1108 return; | 1062 return; |
| 1109 } | 1063 } |
| 1110 | 1064 |
| 1111 if (isStopping()) { | 1065 if (isStopping()) { |
| 1112 attemptToRunDeferredScriptsAndEnd(); | 1066 attemptToRunDeferredScriptsAndEnd(); |
| 1113 return; | 1067 return; |
| 1114 } | 1068 } |
| 1115 | 1069 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1165 ParserContentPolicy parserContentPolicy) { | 1119 ParserContentPolicy parserContentPolicy) { |
| 1166 HTMLDocumentParser* parser = | 1120 HTMLDocumentParser* parser = |
| 1167 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); | 1121 HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); |
| 1168 parser->append(source); | 1122 parser->append(source); |
| 1169 parser->finish(); | 1123 parser->finish(); |
| 1170 // Allows ~DocumentParser to assert it was detached before destruction. | 1124 // Allows ~DocumentParser to assert it was detached before destruction. |
| 1171 parser->detach(); | 1125 parser->detach(); |
| 1172 } | 1126 } |
| 1173 | 1127 |
| 1174 void HTMLDocumentParser::suspendScheduledTasks() { | 1128 void HTMLDocumentParser::suspendScheduledTasks() { |
| 1175 ASSERT(!m_tasksWereSuspended); | 1129 DCHECK(!m_tasksWereSuspended); |
| 1176 m_tasksWereSuspended = true; | 1130 m_tasksWereSuspended = true; |
| 1177 if (m_parserScheduler) | 1131 if (m_parserScheduler) |
| 1178 m_parserScheduler->suspend(); | 1132 m_parserScheduler->suspend(); |
| 1179 } | 1133 } |
| 1180 | 1134 |
| 1181 void HTMLDocumentParser::resumeScheduledTasks() { | 1135 void HTMLDocumentParser::resumeScheduledTasks() { |
| 1182 ASSERT(m_tasksWereSuspended); | 1136 DCHECK(m_tasksWereSuspended); |
| 1183 m_tasksWereSuspended = false; | 1137 m_tasksWereSuspended = false; |
| 1184 if (m_parserScheduler) | 1138 if (m_parserScheduler) |
| 1185 m_parserScheduler->resume(); | 1139 m_parserScheduler->resume(); |
| 1186 } | 1140 } |
| 1187 | 1141 |
| 1188 void HTMLDocumentParser::appendBytes(const char* data, size_t length) { | 1142 void HTMLDocumentParser::appendBytes(const char* data, size_t length) { |
| 1189 if (!length || isStopped()) | 1143 if (!length || isStopped()) |
| 1190 return; | 1144 return; |
| 1191 | 1145 |
| 1192 if (shouldUseThreading()) { | 1146 if (shouldUseThreading()) { |
| 1193 double bytesReceivedTime = monotonicallyIncreasingTimeMS(); | 1147 double bytesReceivedTime = monotonicallyIncreasingTimeMS(); |
| 1194 if (!m_haveBackgroundParser) | 1148 if (!m_backgroundParser) |
| 1195 startBackgroundParser(); | 1149 startBackgroundParser(); |
| 1196 | 1150 |
| 1197 std::unique_ptr<Vector<char>> buffer = | 1151 std::unique_ptr<Vector<char>> buffer = |
| 1198 WTF::makeUnique<Vector<char>>(length); | 1152 WTF::makeUnique<Vector<char>>(length); |
| 1199 memcpy(buffer->data(), data, length); | 1153 memcpy(buffer->data(), data, length); |
| 1200 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), | 1154 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), |
| 1201 "HTMLDocumentParser::appendBytes", "size", (unsigned)length); | 1155 "HTMLDocumentParser::appendBytes", "size", (unsigned)length); |
| 1202 | 1156 |
| 1203 m_loadingTaskRunner->postTask( | 1157 m_backgroundParser->appendRawBytesFromMainThread(std::move(buffer), |
| 1204 BLINK_FROM_HERE, | 1158 bytesReceivedTime); |
| 1205 WTF::bind(&BackgroundHTMLParser::appendRawBytesFromMainThread, | |
| 1206 m_backgroundParser, WTF::passed(std::move(buffer)), | |
| 1207 bytesReceivedTime)); | |
| 1208 return; | 1159 return; |
| 1209 } | 1160 } |
| 1210 | 1161 |
| 1211 DecodedDataDocumentParser::appendBytes(data, length); | 1162 DecodedDataDocumentParser::appendBytes(data, length); |
| 1212 } | 1163 } |
| 1213 | 1164 |
| 1214 void HTMLDocumentParser::flush() { | 1165 void HTMLDocumentParser::flush() { |
| 1215 // If we've got no decoder, we never received any data. | 1166 // If we've got no decoder, we never received any data. |
| 1216 if (isDetached() || needsDecoder()) | 1167 if (isDetached() || needsDecoder()) |
| 1217 return; | 1168 return; |
| 1218 | 1169 |
| 1219 if (shouldUseThreading()) { | 1170 if (shouldUseThreading()) { |
| 1220 // In some cases, flush() is called without any invocation of appendBytes. | 1171 // In some cases, flush() is called without any invocation of appendBytes. |
| 1221 // Fallback to synchronous parsing in that case. | 1172 // Fallback to synchronous parsing in that case. |
| 1222 if (!m_haveBackgroundParser) { | 1173 if (!m_backgroundParser) { |
| 1223 m_shouldUseThreading = false; | 1174 m_shouldUseThreading = false; |
| 1224 m_token = WTF::wrapUnique(new HTMLToken); | 1175 m_token = WTF::wrapUnique(new HTMLToken); |
| 1225 m_tokenizer = HTMLTokenizer::create(m_options); | 1176 m_tokenizer = HTMLTokenizer::create(m_options); |
| 1226 DecodedDataDocumentParser::flush(); | 1177 DecodedDataDocumentParser::flush(); |
| 1227 return; | 1178 return; |
| 1228 } | 1179 } |
| 1229 | 1180 m_backgroundParser->flush(); |
| 1230 m_loadingTaskRunner->postTask( | |
| 1231 BLINK_FROM_HERE, | |
| 1232 WTF::bind(&BackgroundHTMLParser::flush, m_backgroundParser)); | |
| 1233 } else { | 1181 } else { |
| 1234 DecodedDataDocumentParser::flush(); | 1182 DecodedDataDocumentParser::flush(); |
| 1235 } | 1183 } |
| 1236 } | 1184 } |
| 1237 | 1185 |
| 1238 void HTMLDocumentParser::setDecoder( | 1186 void HTMLDocumentParser::setDecoder( |
| 1239 std::unique_ptr<TextResourceDecoder> decoder) { | 1187 std::unique_ptr<TextResourceDecoder> decoder) { |
| 1240 ASSERT(decoder); | 1188 DCHECK(decoder); |
| 1241 DecodedDataDocumentParser::setDecoder(std::move(decoder)); | 1189 DecodedDataDocumentParser::setDecoder(std::move(decoder)); |
| 1242 | 1190 |
| 1243 if (m_haveBackgroundParser) { | 1191 if (m_backgroundParser) |
| 1244 m_loadingTaskRunner->postTask( | 1192 m_backgroundParser->setDecoder(takeDecoder()); |
| 1245 BLINK_FROM_HERE, | |
| 1246 WTF::bind(&BackgroundHTMLParser::setDecoder, m_backgroundParser, | |
| 1247 WTF::passed(takeDecoder()))); | |
| 1248 } | |
| 1249 } | 1193 } |
| 1250 | 1194 |
| 1251 void HTMLDocumentParser::documentElementAvailable() { | 1195 void HTMLDocumentParser::documentElementAvailable() { |
| 1252 TRACE_EVENT0("blink,loader", "HTMLDocumentParser::documentElementAvailable"); | 1196 TRACE_EVENT0("blink,loader", "HTMLDocumentParser::documentElementAvailable"); |
| 1253 DCHECK(document()->documentElement()); | 1197 DCHECK(document()->documentElement()); |
| 1254 fetchQueuedPreloads(); | 1198 fetchQueuedPreloads(); |
| 1255 } | 1199 } |
| 1256 | 1200 |
| 1257 std::unique_ptr<HTMLPreloadScanner> HTMLDocumentParser::createPreloadScanner() { | 1201 std::unique_ptr<HTMLPreloadScanner> HTMLDocumentParser::createPreloadScanner() { |
| 1258 return HTMLPreloadScanner::create( | 1202 return HTMLPreloadScanner::create( |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1330 successHistogram.count(duration); | 1274 successHistogram.count(duration); |
| 1331 } else { | 1275 } else { |
| 1332 DEFINE_STATIC_LOCAL( | 1276 DEFINE_STATIC_LOCAL( |
| 1333 CustomCountHistogram, failureHistogram, | 1277 CustomCountHistogram, failureHistogram, |
| 1334 ("PreloadScanner.DocumentWrite.ExecutionTime.Failure", 1, 10000, 50)); | 1278 ("PreloadScanner.DocumentWrite.ExecutionTime.Failure", 1, 10000, 50)); |
| 1335 failureHistogram.count(duration); | 1279 failureHistogram.count(duration); |
| 1336 } | 1280 } |
| 1337 } | 1281 } |
| 1338 | 1282 |
| 1339 } // namespace blink | 1283 } // namespace blink |
| OLD | NEW |