12011-02-14 Tony Gentilcore <tonyg@chromium.org>
2
3 Reviewed by NOBODY (OOPS!).
4
5 Let the parser yield for layout before running scripts
6 https://bugs.webkit.org/show_bug.cgi?id=54355
7
8 Prior to this patch, the parser would yield to perform a layout/paint before running a
9 script only if the script or a stylesheet blocking the script is not loaded yet. Since we
10 don't preload scan into the body while parsing the head, typically we'll block on a script
11 early in the body that causes us to yield to do the first paint within a reasonable time.
12
13 However, I'm planning to change the PreloadScanner to scan into the body from the head.
14 That significantly improves overall load time, but would hurt first paint time because
15 fewer scripts would be blocked during parsing and thus wouldn't yield.
16
17 This change causes us to yield before running scripts if we haven't painted yet (regardless
18 of whether or not the script is loaded). In addition to allowing the above mentioned
19 PreloadScanner change to be implemented without regressing first paint time, this also
20 improves first paint time by itself.
21
22 I tested Alexa's top 45 websites using Web Page Replay to control the content and simulate
23 bandwidth. This patch improved average first paint time by 1% over an unlimited connection,
24 6% over a 1Mbps connection and 11% over a 5Mbps connection. There was no statistically
25 signifcant change in page load time.
26
27 Within the pages tested, 33 had no statistically significant change in time to first paint,
28 12 improved, and none regressed. Of the improved, some of the standouts from the 1Mbps set
29 are: 20% on youtube, 37% on wiki, 27% on ebay, 13% on cnn, 16% on espn, 74% on sohu.
30
31 * html/parser/HTMLDocumentParser.cpp:
32 (WebCore::HTMLDocumentParser::resumeParsingAfterYield): The scheduler may not call this
33 method when resuming from a yield before a token or a yield before a script. So it checks
34 whether the parser is paused (waiting for a script) and runs scripts first.
35 (WebCore::HTMLDocumentParser::runScriptsForPausedTreeBuilder): Moved setPaused bit into this
36 method so that resumeParsingAfterYield doesn't have to duplicate it from the pumpTokenizer
37 loop.
38 (WebCore::HTMLDocumentParser::pumpTokenizer): After taking each </script> from the
39 tokenizer, give the scheduler a chance to determine whether to yield before running that
40 script.
41 (WebCore::HTMLDocumentParser::isWaitingForScripts): Inline this method since it is now call
42 for every token processed.
43 * html/parser/HTMLDocumentParser.h:
44 * html/parser/HTMLParserScheduler.cpp:
45 (WebCore::isLayoutTimerActive): Added a FIXME because r52919 changed minimumLayoutDelay()
46 to return m_extraLayoutDelay instead of 0 as a minimum. So checking !minimumLayoutDelay()
47 no longer works. The fix is to change it to check minimumLayoutDelay() ==
48 m_extraLayoutDelay. But this is all the more reason to move this method onto Document. I'll
49 do this in a follow up.
50 (WebCore::HTMLParserScheduler::shouldRunScriptNow): Added.
51 * html/parser/HTMLParserScheduler.h:
52 * page/FrameView.h:
53 (WebCore::FrameView::hasEverPainted): Added.
54