| Differences between
and this patch
- a/WebCore/WebCore.xcodeproj/project.pbxproj +1 lines
Lines 21305-21310 a/WebCore/WebCore.xcodeproj/project.pbxproj_sec1
21305
			isa = PBXProject;
21305
			isa = PBXProject;
21306
			buildConfigurationList = 149C284308902B11008A9EFC /* Build configuration list for PBXProject "WebCore" */;
21306
			buildConfigurationList = 149C284308902B11008A9EFC /* Build configuration list for PBXProject "WebCore" */;
21307
			compatibilityVersion = "Xcode 2.4";
21307
			compatibilityVersion = "Xcode 2.4";
21308
			developmentRegion = English;
21308
			hasScannedForEncodings = 1;
21309
			hasScannedForEncodings = 1;
21309
			knownRegions = (
21310
			knownRegions = (
21310
				English,
21311
				English,
- a/WebCore/benchmarks/parser/html-parser.html -57 / +3 lines
Lines 1-19 a/WebCore/benchmarks/parser/html-parser.html_sec1
1
<!DOCTYPE html>
1
<!DOCTYPE html>
2
<body>
2
<body>
3
<pre id="log"></pre>
3
<script src="resources/performance-test.js"></script>
4
<script>
4
<script>
5
function log(text) {
6
    document.getElementById("log").innerText += text + "\n";
7
    window.scrollTo(document.body.height);
8
}
9
10
function loadFile(path) {
11
    var xhr = new XMLHttpRequest();
12
    xhr.open("GET", path, false);
13
    xhr.send(null);
14
    return xhr.responseText;
15
}
16
17
var spec = loadFile("resources/html5.html");
5
var spec = loadFile("resources/html5.html");
18
6
19
function parse(html) {
7
function parse(html) {
Lines 27-79 function parse(html) { a/WebCore/benchmarks/parser/html-parser.html_sec2
27
    document.body.removeChild(iframe)
15
    document.body.removeChild(iframe)
28
}
16
}
29
17
30
var runCount = 20;
18
function runParsingTest() {
31
var completedRuns = -1; // Discard the any runs < 0.
32
var times = [];
33
34
function computeAverage(values) {
35
    var sum = 0;
36
    for (var i = 0; i < values.length; i++)
37
        sum += values[i];
38
    return sum / values.length;
39
}
40
41
function computeStdev(values) {
42
    var average = computeAverage(values);
43
    var sumOfSquaredDeviations = 0;
44
    for (var i = 0; i < values.length; ++i) {
45
        var deviation = values[i] - average;
46
        sumOfSquaredDeviations += deviation * deviation;
47
    }
48
    return Math.sqrt(sumOfSquaredDeviations / values.length);
49
}
50
51
function logStatistics(times) {
52
    log("");
53
    log("avg " + computeAverage(times));
54
    log("stdev " + computeStdev(times));
55
}
56
57
function run() {
58
    var start = new Date();
59
    for (var i = 0; i < 10; ++i)
19
    for (var i = 0; i < 10; ++i)
60
        parse(spec);
20
        parse(spec);
61
    var time = new Date() - start;
62
    completedRuns++;
63
    if (completedRuns <= 0) {
64
        log("Ignoring warm-up run (" + time + ")");
65
    } else {
66
        times.push(time);
67
        log(time);
68
    }
69
    if (completedRuns < runCount) {
70
        window.setTimeout(run, 0);
71
    } else {
72
        logStatistics(times);
73
    }
74
}
21
}
75
22
76
log("Running " + runCount + " times");
23
runPerformanceTest(runParsingTest);
77
run();
78
</script>
24
</script>
79
</body>
25
</body>
- a/WebCore/benchmarks/parser/resources/performance-test.js +76 lines
Line 0 a/WebCore/benchmarks/parser/resources/performance-test.js_sec1
1
// A basic performance testing harness.
2
3
function loadFile(path) {
4
    var xhr = new XMLHttpRequest();
5
    xhr.open("GET", path, false);
6
    xhr.send(null);
7
    return xhr.responseText;
8
}
9
10
var logDiv;
11
12
function setupLogging() {
13
    logDiv = document.createElement("pre");
14
    document.body.appendChild(logDiv);
15
}
16
17
function log(text) {
18
    logDiv.innerText += text + "\n";
19
    window.scrollTo(document.body.height);
20
}
21
22
// FIXME: We should make it possible to configure runCount.
23
var runCount = 20;
24
var completedRuns = -1; // Discard the any runs < 0.
25
var times = [];
26
27
function computeAverage(values) {
28
    var sum = 0;
29
    for (var i = 0; i < values.length; i++)
30
        sum += values[i];
31
    return sum / values.length;
32
}
33
34
function computeStdev(values) {
35
    var average = computeAverage(values);
36
    var sumOfSquaredDeviations = 0;
37
    for (var i = 0; i < values.length; ++i) {
38
        var deviation = values[i] - average;
39
        sumOfSquaredDeviations += deviation * deviation;
40
    }
41
    return Math.sqrt(sumOfSquaredDeviations / values.length);
42
}
43
44
function logStatistics(times) {
45
    log("");
46
    log("avg " + computeAverage(times));
47
    log("stdev " + computeStdev(times));
48
}
49
50
var testFunction;
51
52
function runPerformanceTest(testFunction) {
53
    setupLogging()
54
55
    log("Running " + runCount + " times");
56
    window.testFunction = testFunction;
57
    runOneTest();
58
}
59
60
function runOneTest() {
61
    var start = new Date();
62
    window.testFunction();
63
    var time = new Date() - start;
64
    completedRuns++;
65
    if (completedRuns <= 0) {
66
        log("Ignoring warm-up run (" + time + ")");
67
    } else {
68
        times.push(time);
69
        log(time);
70
    }
71
    if (completedRuns < runCount) {
72
        window.setTimeout(runOneTest, 0);
73
    } else {
74
        logStatistics(times);
75
    }
76
}
- a/WebCore/benchmarks/parser/tiny-innerHTML.html +15 lines
Line 0 a/WebCore/benchmarks/parser/tiny-innerHTML.html_sec1
1
<!DOCTYPE html>
2
<body>
3
<div id="testDiv" style="display: none"></div>
4
<script src="resources/performance-test.js"></script>
5
<script>
6
var testDiv = document.getElementById("testDiv");
7
function runInnerHTMLTest() {
8
    for (var x = 0; x < 100000; x++) {
9
        testDiv.innerHTML = "This is a tiny HTML document";
10
    }
11
}
12
13
runPerformanceTest(runInnerHTMLTest);
14
</script>
15
</body>
- a/WebCore/html/parser/HTMLTreeBuilder.cpp -3 / +52 lines
Lines 388-393 void HTMLTreeBuilder::detach() a/WebCore/html/parser/HTMLTreeBuilder.cpp_sec1
388
    m_tree.detach();
388
    m_tree.detach();
389
}
389
}
390
390
391
// NOTE: HTML5 requires that we use a dummy document when parsing
392
// document fragments.  However, creating a new Document element
393
// for each fragment is very slow (Document() does too much work, and
394
// innerHTML is a common call).  So we use a shared dummy document.
395
// This sharing works because there can only ever be one fragment
396
// parser at any time.  Fragment parsing is synchronous and done
397
// only from the main thread.  It should be impossible for javascript
398
// (or anything else) to ever hold a reference to the dummy document.
399
// See https://bugs.webkit.org/show_bug.cgi?id=48719
400
class DummyDocumentFactory : Noncopyable {
401
public:
402
    // Use an explicit create/release here to ASSERT this sharing is safe.
403
    static HTMLDocument* createDummyDocument();
404
    static void releaseDocument(HTMLDocument*);
405
406
private:
407
    static HTMLDocument* s_sharedDummyDocument;
408
    static int s_sharedDummyDocumentMutex;
409
};
410
411
HTMLDocument* DummyDocumentFactory::createDummyDocument()
412
{
413
    if (!s_sharedDummyDocument) {
414
        s_sharedDummyDocument = HTMLDocument::create(0, KURL()).releaseRef();
415
        s_sharedDummyDocumentMutex = 0;
416
    }
417
    ASSERT(!s_sharedDummyDocumentMutex);
418
    ASSERT(!s_sharedDummyDocument->hasChildNodes());
419
    s_sharedDummyDocumentMutex++;
420
    return s_sharedDummyDocument;
421
}
422
423
void DummyDocumentFactory::releaseDocument(HTMLDocument* dummyDocument)
424
{
425
    ASSERT(s_sharedDummyDocument == dummyDocument);
426
    s_sharedDummyDocumentMutex--;
427
    ASSERT(!s_sharedDummyDocumentMutex);
428
    dummyDocument->removeAllChildren();
429
}
430
431
HTMLDocument* DummyDocumentFactory::s_sharedDummyDocument = 0;
432
int DummyDocumentFactory::s_sharedDummyDocumentMutex = 0;
433
    
391
HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext()
434
HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext()
392
    : m_fragment(0)
435
    : m_fragment(0)
393
    , m_contextElement(0)
436
    , m_contextElement(0)
Lines 396-422 HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext() a/WebCore/html/parser/HTMLTreeBuilder.cpp_sec2
396
}
439
}
397
440
398
HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission)
441
HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission)
399
    : m_dummyDocumentForFragmentParsing(HTMLDocument::create(0, KURL(), fragment->document()->baseURI()))
442
    : m_dummyDocumentForFragmentParsing(DummyDocumentFactory::createDummyDocument())
400
    , m_fragment(fragment)
443
    , m_fragment(fragment)
401
    , m_contextElement(contextElement)
444
    , m_contextElement(contextElement)
402
    , m_scriptingPermission(scriptingPermission)
445
    , m_scriptingPermission(scriptingPermission)
403
{
446
{
404
    m_dummyDocumentForFragmentParsing->setCompatibilityMode(fragment->document()->compatibilityMode());
447
    m_dummyDocumentForFragmentParsing->setCompatibilityMode(fragment->document()->compatibilityMode());
448
    // Setting the baseURL should work the same as it would have had we passed
449
    // it during HTMLDocument() construction, since the new document is empty.
450
    m_dummyDocumentForFragmentParsing->setURL(fragment->document()->baseURI());
405
}
451
}
406
452
407
Document* HTMLTreeBuilder::FragmentParsingContext::document() const
453
Document* HTMLTreeBuilder::FragmentParsingContext::document() const
408
{
454
{
409
    ASSERT(m_fragment);
455
    ASSERT(m_fragment);
410
    return m_dummyDocumentForFragmentParsing.get();
456
    return m_dummyDocumentForFragmentParsing;
411
}
457
}
412
458
413
void HTMLTreeBuilder::FragmentParsingContext::finished()
459
void HTMLTreeBuilder::FragmentParsingContext::finished()
414
{
460
{
415
    // Populate the DocumentFragment with the parsed content now that we're done.
461
    // Populate the DocumentFragment with the parsed content now that we're done.
416
    ContainerNode* root = m_dummyDocumentForFragmentParsing.get();
462
    ContainerNode* root = m_dummyDocumentForFragmentParsing;
417
    if (m_contextElement)
463
    if (m_contextElement)
418
        root = m_dummyDocumentForFragmentParsing->documentElement();
464
        root = m_dummyDocumentForFragmentParsing->documentElement();
419
    m_fragment->takeAllChildrenFrom(root);
465
    m_fragment->takeAllChildrenFrom(root);
466
    ASSERT(!m_dummyDocumentForFragmentParsing->hasChildNodes());
467
    DummyDocumentFactory::releaseDocument(m_dummyDocumentForFragmentParsing);
468
    m_dummyDocumentForFragmentParsing = 0;
420
}
469
}
421
470
422
HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext()
471
HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext()
- a/WebCore/html/parser/HTMLTreeBuilder.h -1 / +3 lines
Lines 216-222 private: a/WebCore/html/parser/HTMLTreeBuilder.h_sec1
216
        void finished();
216
        void finished();
217
217
218
    private:
218
    private:
219
        RefPtr<Document> m_dummyDocumentForFragmentParsing;
219
        // Use a shared dummy document to avoid expensive Document creation.
220
        // Hold a raw pointer to the document since there is no need to ref it.
221
        HTMLDocument* m_dummyDocumentForFragmentParsing;
220
        DocumentFragment* m_fragment;
222
        DocumentFragment* m_fragment;
221
        Element* m_contextElement;
223
        Element* m_contextElement;
222
224

Return to Bug 48719