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