Changeset 140478 in webkit
- Timestamp:
- Jan 22, 2013, 3:14:56 PM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r140475 r140478 1 2013-01-22 Adam Barth <abarth@webkit.org> 2 3 The BackgroundHTMLParser shouldn't pause when waiting for scripts 4 https://bugs.webkit.org/show_bug.cgi?id=107584 5 6 Reviewed by Eric Seidel. 7 8 Previously, the BackgroundHTMLParser would pause itself when it 9 encountered a scrip tag and wait for a signal from the main thread to 10 continue. After this patch, the BackgroundHTMLParser continues ahead 11 and the main thread keeps a queue of pending tokens. 12 13 This patch brings us closer to speculative parsing because when the 14 BackgroundHTMLParser is continuing ahead, it is speculating that it is 15 in the correct state. A future patch will let us abort incorret 16 speculations and resume from an eariler point in the input stream. 17 18 * html/parser/BackgroundHTMLParser.cpp: 19 (WebCore::checkThatTokensAreSafeToSendToAnotherThread): 20 (WebCore::BackgroundHTMLParser::BackgroundHTMLParser): 21 (WebCore::BackgroundHTMLParser::simulateTreeBuilder): 22 (WebCore::BackgroundHTMLParser::pumpTokenizer): 23 (WebCore::TokenDelivery::TokenDelivery): 24 (TokenDelivery): 25 (WebCore::TokenDelivery::execute): 26 (WebCore::BackgroundHTMLParser::sendTokensToMainThread): 27 * html/parser/BackgroundHTMLParser.h: 28 (BackgroundHTMLParser): 29 * html/parser/CompactHTMLToken.h: 30 (WebCore): 31 * html/parser/HTMLDocumentParser.cpp: 32 (WebCore::HTMLDocumentParser::didReceiveTokensFromBackgroundParser): 33 (WebCore): 34 (WebCore::HTMLDocumentParser::processTokensFromBackgroundParser): 35 (WebCore::HTMLDocumentParser::resumeParsingAfterScriptExecution): 36 * html/parser/HTMLDocumentParser.h: 37 (HTMLDocumentParser): 38 1 39 2013-01-22 Simon Fraser <simon.fraser@apple.com> 2 40 -
trunk/Source/WebCore/html/parser/BackgroundHTMLParser.cpp
r140467 r140478 46 46 #ifndef NDEBUG 47 47 48 static void checkThatTokensAreSafeToSendToAnotherThread(const Vector<CompactHTMLToken>&tokens)49 { 50 for (size_t i = 0; i < tokens .size(); ++i)51 ASSERT(tokens [i].isSafeToSendToAnotherThread());48 static void checkThatTokensAreSafeToSendToAnotherThread(const CompactHTMLTokenStream* tokens) 49 { 50 for (size_t i = 0; i < tokens->size(); ++i) 51 ASSERT(tokens->at(i).isSafeToSendToAnotherThread()); 52 52 } 53 53 … … 93 93 94 94 BackgroundHTMLParser::BackgroundHTMLParser(const HTMLParserOptions& options, ParserIdentifier identifier) 95 : m_isPausedWaitingForScripts(false) 96 , m_inForeignContent(false) 95 : m_inForeignContent(false) 97 96 , m_tokenizer(HTMLTokenizer::create(options)) 98 97 , m_options(options) 99 98 , m_parserIdentifer(identifier) 99 , m_pendingTokens(adoptPtr(new CompactHTMLTokenStream)) 100 100 { 101 101 } … … 104 104 { 105 105 m_input.append(SegmentedString(input)); 106 pumpTokenizer();107 }108 109 void BackgroundHTMLParser::continueParsing()110 {111 m_isPausedWaitingForScripts = false;112 106 pumpTokenizer(); 113 107 } … … 130 124 } 131 125 132 voidBackgroundHTMLParser::simulateTreeBuilder(const CompactHTMLToken& token)126 bool BackgroundHTMLParser::simulateTreeBuilder(const CompactHTMLToken& token) 133 127 { 134 128 if (token.type() == HTMLTokenTypes::StartTag) { … … 159 153 m_inForeignContent = false; 160 154 if (threadSafeMatch(tagName, scriptTag)) 161 m_isPausedWaitingForScripts = true;155 return false; 162 156 } 163 157 164 158 // FIXME: Need to set setForceNullCharacterReplacement based on m_inForeignContent as well. 165 159 m_tokenizer->setShouldAllowCDATA(m_inForeignContent); 160 return true; 166 161 } 167 162 168 163 void BackgroundHTMLParser::pumpTokenizer() 169 164 { 170 if (m_isPausedWaitingForScripts)171 return;172 173 165 while (m_tokenizer->nextToken(m_input, m_token)) { 174 m_pendingTokens .append(CompactHTMLToken(m_token, TextPosition(m_input.currentLine(), m_input.currentColumn())));166 m_pendingTokens->append(CompactHTMLToken(m_token, TextPosition(m_input.currentLine(), m_input.currentColumn()))); 175 167 m_token.clear(); 176 168 177 simulateTreeBuilder(m_pendingTokens.last()); 178 179 if (m_isPausedWaitingForScripts) 180 break; 181 182 if (m_pendingTokens.size() >= pendingTokenLimit) 169 if (!simulateTreeBuilder(m_pendingTokens->last()) || m_pendingTokens->size() >= pendingTokenLimit) 183 170 sendTokensToMainThread(); 184 171 } … … 192 179 TokenDelivery() 193 180 : identifier(0) 194 , isPausedWaitingForScripts(false)195 181 { 196 182 } 197 183 198 184 ParserIdentifier identifier; 199 Vector<CompactHTMLToken> tokens; 200 // FIXME: This bool will be replaced by a CheckPoint object once 201 // we implement speculative parsing. Then the main thread will decide 202 // to either accept the speculative tokens we've already given it 203 // (or ask for them, depending on who ends up owning them), or send 204 // us a "reset to checkpoint message". 205 bool isPausedWaitingForScripts; 206 185 OwnPtr<CompactHTMLTokenStream> tokens; 207 186 static void execute(void* context) 208 187 { … … 210 189 HTMLDocumentParser* parser = parserMap().mainThreadParsers().get(delivery->identifier); 211 190 if (parser) 212 parser->didReceiveTokensFromBackgroundParser(delivery->tokens , delivery->isPausedWaitingForScripts);191 parser->didReceiveTokensFromBackgroundParser(delivery->tokens.release()); 213 192 // FIXME: Ideally we wouldn't need to call delete manually. Instead 214 193 // we would like an API where the message queue owns the tasks and … … 220 199 void BackgroundHTMLParser::sendTokensToMainThread() 221 200 { 222 if (m_pendingTokens.isEmpty()) { 223 ASSERT(!m_isPausedWaitingForScripts); 201 if (m_pendingTokens->isEmpty()) 224 202 return; 225 }226 203 227 204 #ifndef NDEBUG 228 checkThatTokensAreSafeToSendToAnotherThread(m_pendingTokens );205 checkThatTokensAreSafeToSendToAnotherThread(m_pendingTokens.get()); 229 206 #endif 230 207 231 208 TokenDelivery* delivery = new TokenDelivery; 232 209 delivery->identifier = m_parserIdentifer; 233 delivery->tokens.swap(m_pendingTokens); 234 delivery->isPausedWaitingForScripts = m_isPausedWaitingForScripts; 210 delivery->tokens = m_pendingTokens.release(); 235 211 callOnMainThread(TokenDelivery::execute, delivery); 212 213 m_pendingTokens = adoptPtr(new CompactHTMLTokenStream); 236 214 } 237 215 … … 254 232 } 255 233 256 void BackgroundHTMLParser::continuePartial(ParserIdentifier identifier)257 {258 if (BackgroundHTMLParser* parser = parserMap().backgroundParsers().get(identifier))259 parser->continueParsing();260 }261 262 234 void BackgroundHTMLParser::finishPartial(ParserIdentifier identifier) 263 235 { -
trunk/Source/WebCore/html/parser/BackgroundHTMLParser.h
r140446 r140478 43 43 public: 44 44 void append(const String&); 45 void continueParsing();46 45 void finish(); 47 46 … … 54 53 static void stopPartial(ParserIdentifier); 55 54 static void appendPartial(ParserIdentifier, const String& input); 56 static void continuePartial(ParserIdentifier);57 55 static void finishPartial(ParserIdentifier); 58 56 … … 62 60 void markEndOfFile(); 63 61 void pumpTokenizer(); 64 voidsimulateTreeBuilder(const CompactHTMLToken&);62 bool simulateTreeBuilder(const CompactHTMLToken&); 65 63 66 64 void sendTokensToMainThread(); … … 68 66 SegmentedString m_input; 69 67 HTMLToken m_token; 70 bool m_isPausedWaitingForScripts;71 68 bool m_inForeignContent; // FIXME: We need a stack of foreign content markers. 72 69 OwnPtr<HTMLTokenizer> m_tokenizer; 73 70 HTMLParserOptions m_options; 74 71 ParserIdentifier m_parserIdentifer; 75 Vector<CompactHTMLToken> m_pendingTokens;72 OwnPtr<CompactHTMLTokenStream> m_pendingTokens; 76 73 }; 77 74 -
trunk/Source/WebCore/html/parser/CompactHTMLToken.h
r140473 r140478 82 82 }; 83 83 84 typedef Vector<CompactHTMLToken> CompactHTMLTokenStream; 85 84 86 } 85 87 -
trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp
r140467 r140478 263 263 #if ENABLE(THREADED_HTML_PARSER) 264 264 265 void HTMLDocumentParser::didReceiveTokensFromBackgroundParser(const Vector<CompactHTMLToken>& tokens, bool threadIsWaitingForScripts) 265 void HTMLDocumentParser::didReceiveTokensFromBackgroundParser(PassOwnPtr<CompactHTMLTokenStream> tokens) 266 { 267 if (isWaitingForScripts()) { 268 m_pendingTokens.append(tokens); 269 return; 270 } 271 ASSERT(m_pendingTokens.isEmpty()); 272 processTokensFromBackgroundParser(tokens); 273 } 274 275 void HTMLDocumentParser::processTokensFromBackgroundParser(PassOwnPtr<CompactHTMLTokenStream> tokens) 266 276 { 267 277 ASSERT(shouldUseThreading()); … … 273 283 // FIXME: Add support for InspectorInstrumentation. 274 284 275 for (Vector<CompactHTMLToken>::const_iterator it = tokens .begin(); it != tokens.end(); ++it) {285 for (Vector<CompactHTMLToken>::const_iterator it = tokens->begin(); it != tokens->end(); ++it) { 276 286 ASSERT(!isWaitingForScripts()); 277 287 … … 287 297 288 298 if (isWaitingForScripts()) { 289 ASSERT( threadIsWaitingForScripts); // We expect that the thread is waiting for us.299 ASSERT(it + 1 == tokens->end()); // The </script> is assumed to be the last token of this bunch. 290 300 runScriptsForPausedTreeBuilder(); 291 if (!isWaitingForScripts()) {292 ParserIdentifier identifier = ParserMap::identifierForParser(this);293 HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::continuePartial, identifier));294 }295 ASSERT(it + 1 == tokens.end()); // The </script> is assumed to be the last token of this bunch.296 301 return; 297 302 } … … 302 307 // attemptToEnd() instead. 303 308 if (it->type() == HTMLTokenTypes::EndOfFile) { 304 ASSERT(it + 1 == tokens .end()); // The EOF is assumed to be the last token of this bunch.309 ASSERT(it + 1 == tokens->end()); // The EOF is assumed to be the last token of this bunch. 305 310 prepareToStopParsing(); 306 311 return; 307 312 } 308 }309 310 // If we got here and the parser thread is still waiting for scripts, then it paused unnecessarily311 // (as can happen with a stray </script> tag), and we need to tell it to continue.312 if (threadIsWaitingForScripts) {313 ParserIdentifier identifier = ParserMap::identifierForParser(this);314 HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::continuePartial, identifier));315 313 } 316 314 } … … 660 658 #if ENABLE(THREADED_HTML_PARSER) 661 659 if (shouldUseThreading()) { 662 ParserIdentifier identifier = ParserMap::identifierForParser(this); 663 HTMLParserThread::shared()->postTask(bind(&BackgroundHTMLParser::continuePartial, identifier)); 660 while (!m_pendingTokens.isEmpty()) { 661 processTokensFromBackgroundParser(m_pendingTokens.takeFirst()); 662 if (isWaitingForScripts()) 663 return; 664 } 664 665 return; 665 666 } -
trunk/Source/WebCore/html/parser/HTMLDocumentParser.h
r140467 r140478 38 38 #include "Timer.h" 39 39 #include "XSSAuditor.h" 40 #include <wtf/Deque.h> 40 41 #include <wtf/OwnPtr.h> 41 42 #include <wtf/text/TextPosition.h> … … 81 82 82 83 #if ENABLE(THREADED_HTML_PARSER) 83 void didReceiveTokensFromBackgroundParser( const Vector<CompactHTMLToken>&, bool threadIsWaitingForScripts);84 void didReceiveTokensFromBackgroundParser(PassOwnPtr<CompactHTMLTokenStream>); 84 85 #endif 85 86 … … 123 124 void startBackgroundParser(); 124 125 void stopBackgroundParser(); 126 void processTokensFromBackgroundParser(PassOwnPtr<CompactHTMLTokenStream>); 125 127 #endif 126 128 … … 168 170 XSSAuditor m_xssAuditor; 169 171 172 #if ENABLE(THREADED_HTML_PARSER) 173 Deque<OwnPtr<CompactHTMLTokenStream> > m_pendingTokens; 174 #endif 175 170 176 bool m_endWasDelayed; 171 177 bool m_haveBackgroundParser;
Note:
See TracChangeset
for help on using the changeset viewer.