Chromium Code Reviews| 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 18 matching lines...) Expand all Loading... | |
| 29 #include "core/HTMLNames.h" | 29 #include "core/HTMLNames.h" |
| 30 #include "core/html/parser/HTMLDocumentParser.h" | 30 #include "core/html/parser/HTMLDocumentParser.h" |
| 31 #include "core/html/parser/TextResourceDecoder.h" | 31 #include "core/html/parser/TextResourceDecoder.h" |
| 32 #include "core/html/parser/XSSAuditor.h" | 32 #include "core/html/parser/XSSAuditor.h" |
| 33 #include "platform/Task.h" | 33 #include "platform/Task.h" |
| 34 #include "platform/ThreadSafeFunctional.h" | 34 #include "platform/ThreadSafeFunctional.h" |
| 35 #include "public/platform/Platform.h" | 35 #include "public/platform/Platform.h" |
| 36 #include "public/platform/WebScheduler.h" | 36 #include "public/platform/WebScheduler.h" |
| 37 #include "wtf/text/TextPosition.h" | 37 #include "wtf/text/TextPosition.h" |
| 38 | 38 |
| 39 #include <algorithm> | |
| 40 | |
| 39 namespace blink { | 41 namespace blink { |
| 40 | 42 |
| 41 // On a network with high latency and high bandwidth, using a device | 43 // On a network with high latency and high bandwidth, using a device |
| 42 // with a fast CPU, we could end up speculatively tokenizing | 44 // with a fast CPU, we could end up speculatively tokenizing |
| 43 // the whole document, well ahead of when the main-thread actually needs it. | 45 // the whole document, well ahead of when the main-thread actually needs it. |
| 44 // This is a waste of memory (and potentially time if the speculation fails). | 46 // This is a waste of memory (and potentially time if the speculation fails). |
| 45 // So we limit our outstanding tokens arbitrarily to 10,000. | 47 // So we limit our outstanding tokens arbitrarily to 10,000. |
| 46 // Our maximal memory spent speculating will be approximately: | 48 // Our maximal memory spent speculating will be approximately: |
| 47 // (outstandingTokenLimit + pendingTokenLimit) * sizeof(CompactToken) | 49 // (defaultOutstandingTokenLimit + defaultPendingTokenLimit) * |
| 50 // sizeof(CompactToken) | |
| 48 // We use a separate low and high water mark to avoid constantly topping | 51 // We use a separate low and high water mark to avoid constantly topping |
| 49 // off the main thread's token buffer. | 52 // off the main thread's token buffer. |
| 50 // At time of writing, this is (10000 + 1000) * 28 bytes = ~308kb of memory. | 53 // At time of writing, this is (10000 + 1000) * 28 bytes = ~308kb of memory. |
| 51 // These numbers have not been tuned. | 54 // These numbers have not been tuned. |
| 52 static const size_t outstandingTokenLimit = 10000; | 55 static const size_t defaultOutstandingTokenLimit = 10000; |
| 53 | 56 |
| 54 // We limit our chucks to 1000 tokens, to make sure the main | 57 // We limit our chucks to 1000 tokens, to make sure the main |
| 55 // thread is never waiting on the parser thread for tokens. | 58 // thread is never waiting on the parser thread for tokens. |
| 56 // This was tuned in https://bugs.webkit.org/show_bug.cgi?id=110408. | 59 // This was tuned in https://bugs.webkit.org/show_bug.cgi?id=110408. |
| 57 static const size_t pendingTokenLimit = 1000; | 60 static const size_t defaultPendingTokenLimit = 1000; |
| 58 | 61 |
| 59 using namespace HTMLNames; | 62 using namespace HTMLNames; |
| 60 | 63 |
| 61 #if ENABLE(ASSERT) | 64 #if ENABLE(ASSERT) |
| 62 | 65 |
| 63 static void checkThatTokensAreSafeToSendToAnotherThread(const CompactHTMLTokenSt ream* tokens) | 66 static void checkThatTokensAreSafeToSendToAnotherThread(const CompactHTMLTokenSt ream* tokens) |
| 64 { | 67 { |
| 65 for (size_t i = 0; i < tokens->size(); ++i) | 68 for (size_t i = 0; i < tokens->size(); ++i) |
| 66 ASSERT(tokens->at(i).isSafeToSendToAnotherThread()); | 69 ASSERT(tokens->at(i).isSafeToSendToAnotherThread()); |
| 67 } | 70 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 79 } | 82 } |
| 80 | 83 |
| 81 #endif | 84 #endif |
| 82 | 85 |
| 83 void BackgroundHTMLParser::start(PassRefPtr<WeakReference<BackgroundHTMLParser>> reference, PassOwnPtr<Configuration> config, WebScheduler* scheduler) | 86 void BackgroundHTMLParser::start(PassRefPtr<WeakReference<BackgroundHTMLParser>> reference, PassOwnPtr<Configuration> config, WebScheduler* scheduler) |
| 84 { | 87 { |
| 85 new BackgroundHTMLParser(reference, config, scheduler); | 88 new BackgroundHTMLParser(reference, config, scheduler); |
| 86 // Caller must free by calling stop(). | 89 // Caller must free by calling stop(). |
| 87 } | 90 } |
| 88 | 91 |
| 92 BackgroundHTMLParser::Configuration::Configuration() | |
| 93 : outstandingTokenLimit(defaultOutstandingTokenLimit) | |
| 94 , pendingTokenLimit(defaultPendingTokenLimit) | |
| 95 { | |
| 96 } | |
| 97 | |
| 89 BackgroundHTMLParser::BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHT MLParser>> reference, PassOwnPtr<Configuration> config, WebScheduler* scheduler) | 98 BackgroundHTMLParser::BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHT MLParser>> reference, PassOwnPtr<Configuration> config, WebScheduler* scheduler) |
| 90 : m_weakFactory(reference, this) | 99 : m_weakFactory(reference, this) |
| 91 , m_token(adoptPtr(new HTMLToken)) | 100 , m_token(adoptPtr(new HTMLToken)) |
| 92 , m_tokenizer(HTMLTokenizer::create(config->options)) | 101 , m_tokenizer(HTMLTokenizer::create(config->options)) |
| 93 , m_treeBuilderSimulator(config->options) | 102 , m_treeBuilderSimulator(config->options) |
| 94 , m_options(config->options) | 103 , m_options(config->options) |
| 104 , m_outstandingTokenLimit(std::max(config->outstandingTokenLimit, config->pe ndingTokenLimit)) | |
|
Nate Chapin
2015/06/11 18:48:23
Why take the max of the two here? Should we assert
Bryan McQuade
2015/06/12 14:12:59
Yes, that's clearer. Agree. I've made this change.
| |
| 95 , m_parser(config->parser) | 105 , m_parser(config->parser) |
| 96 , m_pendingTokens(adoptPtr(new CompactHTMLTokenStream)) | 106 , m_pendingTokens(adoptPtr(new CompactHTMLTokenStream)) |
| 107 , m_pendingTokenLimit(config->pendingTokenLimit) | |
| 97 , m_xssAuditor(config->xssAuditor.release()) | 108 , m_xssAuditor(config->xssAuditor.release()) |
| 98 , m_preloadScanner(config->preloadScanner.release()) | 109 , m_preloadScanner(config->preloadScanner.release()) |
| 99 , m_decoder(config->decoder.release()) | 110 , m_decoder(config->decoder.release()) |
| 100 , m_scheduler(scheduler) | 111 , m_scheduler(scheduler) |
| 101 , m_startingScript(false) | 112 , m_startingScript(false) |
| 102 { | 113 { |
| 114 ASSERT(m_outstandingTokenLimit > 0); | |
| 115 ASSERT(m_pendingTokenLimit > 0); | |
| 103 } | 116 } |
| 104 | 117 |
| 105 BackgroundHTMLParser::~BackgroundHTMLParser() | 118 BackgroundHTMLParser::~BackgroundHTMLParser() |
| 106 { | 119 { |
| 107 } | 120 } |
| 108 | 121 |
| 109 void BackgroundHTMLParser::appendRawBytesFromParserThread(const char* data, int dataLength) | 122 void BackgroundHTMLParser::appendRawBytesFromParserThread(const char* data, int dataLength) |
| 110 { | 123 { |
| 111 ASSERT(m_decoder); | 124 ASSERT(m_decoder); |
| 112 updateDocument(m_decoder->decode(data, dataLength)); | 125 updateDocument(m_decoder->decode(data, dataLength)); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 198 ASSERT(!m_input.current().isClosed()); | 211 ASSERT(!m_input.current().isClosed()); |
| 199 m_input.append(String(&kEndOfFileMarker, 1)); | 212 m_input.append(String(&kEndOfFileMarker, 1)); |
| 200 m_input.close(); | 213 m_input.close(); |
| 201 } | 214 } |
| 202 | 215 |
| 203 void BackgroundHTMLParser::pumpTokenizer() | 216 void BackgroundHTMLParser::pumpTokenizer() |
| 204 { | 217 { |
| 205 HTMLTreeBuilderSimulator::SimulatedToken simulatedToken = HTMLTreeBuilderSim ulator::OtherToken; | 218 HTMLTreeBuilderSimulator::SimulatedToken simulatedToken = HTMLTreeBuilderSim ulator::OtherToken; |
| 206 | 219 |
| 207 // No need to start speculating until the main thread has almost caught up. | 220 // No need to start speculating until the main thread has almost caught up. |
| 208 if (m_input.totalCheckpointTokenCount() > outstandingTokenLimit) | 221 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit) |
| 209 return; | 222 return; |
| 210 | 223 |
| 211 while (true) { | 224 while (true) { |
| 212 m_sourceTracker.start(m_input.current(), m_tokenizer.get(), *m_token); | 225 m_sourceTracker.start(m_input.current(), m_tokenizer.get(), *m_token); |
| 213 if (!m_tokenizer->nextToken(m_input.current(), *m_token)) { | 226 if (!m_tokenizer->nextToken(m_input.current(), *m_token)) { |
| 214 // We've reached the end of our current input. | 227 // We've reached the end of our current input. |
| 215 sendTokensToMainThread(); | 228 sendTokensToMainThread(); |
| 216 break; | 229 break; |
| 217 } | 230 } |
| 218 m_sourceTracker.end(m_input.current(), m_tokenizer.get(), *m_token); | 231 m_sourceTracker.end(m_input.current(), m_tokenizer.get(), *m_token); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 235 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptStart) { | 248 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptStart) { |
| 236 sendTokensToMainThread(); | 249 sendTokensToMainThread(); |
| 237 m_startingScript = true; | 250 m_startingScript = true; |
| 238 } | 251 } |
| 239 | 252 |
| 240 m_pendingTokens->append(token); | 253 m_pendingTokens->append(token); |
| 241 } | 254 } |
| 242 | 255 |
| 243 m_token->clear(); | 256 m_token->clear(); |
| 244 | 257 |
| 245 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptEnd || m_pendingTo kens->size() >= pendingTokenLimit) { | 258 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptEnd || m_pendingTo kens->size() >= m_pendingTokenLimit) { |
| 246 sendTokensToMainThread(); | 259 sendTokensToMainThread(); |
| 247 // If we're far ahead of the main thread, yield for a bit to avoid c onsuming too much memory. | 260 // If we're far ahead of the main thread, yield for a bit to avoid c onsuming too much memory. |
| 248 if (m_input.totalCheckpointTokenCount() > outstandingTokenLimit) | 261 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit) |
| 249 break; | 262 break; |
| 250 } | 263 } |
| 251 } | 264 } |
| 252 } | 265 } |
| 253 | 266 |
| 254 void BackgroundHTMLParser::sendTokensToMainThread() | 267 void BackgroundHTMLParser::sendTokensToMainThread() |
| 255 { | 268 { |
| 256 if (m_pendingTokens->isEmpty()) | 269 if (m_pendingTokens->isEmpty()) |
| 257 return; | 270 return; |
| 258 | 271 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 274 m_startingScript = false; | 287 m_startingScript = false; |
| 275 | 288 |
| 276 m_scheduler->postLoadingTask( | 289 m_scheduler->postLoadingTask( |
| 277 FROM_HERE, | 290 FROM_HERE, |
| 278 new Task(threadSafeBind(&HTMLDocumentParser::didReceiveParsedChunkFromBa ckgroundParser, AllowCrossThreadAccess(m_parser), chunk.release()))); | 291 new Task(threadSafeBind(&HTMLDocumentParser::didReceiveParsedChunkFromBa ckgroundParser, AllowCrossThreadAccess(m_parser), chunk.release()))); |
| 279 | 292 |
| 280 m_pendingTokens = adoptPtr(new CompactHTMLTokenStream); | 293 m_pendingTokens = adoptPtr(new CompactHTMLTokenStream); |
| 281 } | 294 } |
| 282 | 295 |
| 283 } | 296 } |
| OLD | NEW |