<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[163850] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/163850">163850</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-02-10 18:41:00 -0800 (Mon, 10 Feb 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Add the basic infrastructure to compile attributes matching in selectors
https://bugs.webkit.org/show_bug.cgi?id=128484
Reviewed by Gavin Barraclough.
Source/WebCore:
Tests: fast/selectors/querySelector-attribute-match-with-child-backtracking.html
fast/selectors/querySelector-long-attribute-match-with-child-backtracking.html
fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking.html
fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking.html
Add the infrastructure to match attributes. This only add basic support for the 'Set' match
type, the other match types will have to be built on top.
* cssjit/RegisterAllocator.h:
(WebCore::RegisterAllocator::availableRegisterCount):
(WebCore::RegisterAllocator::allocateRegister):
(WebCore::RegisterAllocator::deallocateRegister):
(WebCore::RegisterAllocator::reserveCalleeSavedRegisters):
(WebCore::RegisterAllocator::restoreCalleeSavedRegisters):
(WebCore::RegisterAllocator::allocatedRegisters):
(WebCore::RegisterAllocator::RegisterAllocator):
(WebCore::RegisterAllocator::~RegisterAllocator):
In the worst case, matching attributes can take up to 10 registers. On x86_64, we have
8 caller-saved registers. The extra 2 registers are simply added by taking callee-saved registers.
RegisterAllocator is modified to know support saving and restoring callee saved registers.
The list of available registers is changed from a vector to a HashSet because the registers
are removed from arbitrary locations in restoreCalleeSavedRegisters(). The m_allocatedRegisters
remain a vector since the allocation/release pattern remain ordered.
* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::SelectorCodeGenerator::SelectorCodeGenerator):
(WebCore::SelectorCompiler::minimumRegisterRequirements):
This new utility finds the minimum number of registers needed to compile the input. In most
cases we have plenty enough. In rare cases we need to saved a few registers to the stack.
(WebCore::SelectorCompiler::SelectorCodeGenerator::compile):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementDataMatching):
(WebCore::SelectorCompiler::testIsHTMLFlagOnNode):
(WebCore::SelectorCompiler::canMatchStyleAttribute):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateSynchronizeStyleAttribute):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateSynchronizeAllAnimatedSVGAttribute):
The style attribute and certain SVG attributes can be modified lazily. In those cases,
the element needs to be updated before querying the attributes.
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementAttributesMatching):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementAttributeMatching):
Generate the attribute matching. For each CSSSelector matching an attribute, we generate
a loop over all the attributes of the element, maching the particular CSSSelector.
This makes no attempt at grouping related queries since those do not seem to happen a lot
in practice.
* dom/Attribute.h:
(WebCore::Attribute::nameMemoryOffset):
(WebCore::Attribute::nameMatchesFilter):
(WebCore::Attribute::matches):
* dom/ElementData.h:
(WebCore::ElementData::isUniqueFlag):
(WebCore::ElementData::arraySizeAndFlagsMemoryOffset):
(WebCore::ElementData::styleAttributeIsDirtyFlag):
(WebCore::ElementData::animatedSVGAttributesAreDirtyFlag):
(WebCore::ElementData::arraySizeOffset):
(WebCore::ShareableElementData::attributeArrayMemoryOffset):
(WebCore::UniqueElementData::attributeVectorMemoryOffset):
* dom/Node.h:
(WebCore::Node::flagIsHTML):
* dom/StyledElement.cpp:
(WebCore::StyledElement::synchronizeStyleAttributeInternal):
* dom/StyledElement.h:
(WebCore::StyledElement::synchronizeStyleAttributeInternal):
* svg/SVGElement.cpp:
(WebCore::SVGElement::synchronizeAllAnimatedSVGAttribute):
(WebCore::SVGElement::synchronizeAnimatedSVGAttribute):
* svg/SVGElement.h:
Source/WTF:
* wtf/Vector.h:
(WTF::VectorBufferBase::bufferMemoryOffset):
(WTF::Vector::sizeMemoryOffset):
(WTF::Vector::dataMemoryOffset):
Expose the memory offsets of Vector::size() and the memory buffer pointer for the JIT.
LayoutTests:
Tests the various cases requiring more register than what is available from the caller-saved pool.
* fast/selectors/querySelector-attribute-match-with-child-backtracking-expected.txt: Added.
* fast/selectors/querySelector-attribute-match-with-child-backtracking.html: Added.
* fast/selectors/querySelector-long-attribute-match-with-child-backtracking-expected.txt: Added.
* fast/selectors/querySelector-long-attribute-match-with-child-backtracking.html: Added.
* fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking-expected.txt: Added.
* fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking.html: Added.
* fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking-expected.txt: Added.
* fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking.html: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfVectorh">trunk/Source/WTF/wtf/Vector.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssjitRegisterAllocatorh">trunk/Source/WebCore/cssjit/RegisterAllocator.h</a></li>
<li><a href="#trunkSourceWebCorecssjitSelectorCompilercpp">trunk/Source/WebCore/cssjit/SelectorCompiler.cpp</a></li>
<li><a href="#trunkSourceWebCoredomAttributeh">trunk/Source/WebCore/dom/Attribute.h</a></li>
<li><a href="#trunkSourceWebCoredomElementDatah">trunk/Source/WebCore/dom/ElementData.h</a></li>
<li><a href="#trunkSourceWebCoredomNodeh">trunk/Source/WebCore/dom/Node.h</a></li>
<li><a href="#trunkSourceWebCoredomStyledElementcpp">trunk/Source/WebCore/dom/StyledElement.cpp</a></li>
<li><a href="#trunkSourceWebCoredomStyledElementh">trunk/Source/WebCore/dom/StyledElement.h</a></li>
<li><a href="#trunkSourceWebCoresvgSVGElementcpp">trunk/Source/WebCore/svg/SVGElement.cpp</a></li>
<li><a href="#trunkSourceWebCoresvgSVGElementh">trunk/Source/WebCore/svg/SVGElement.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectorattributematchwithchildbacktrackingexpectedtxt">trunk/LayoutTests/fast/selectors/querySelector-attribute-match-with-child-backtracking-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectorattributematchwithchildbacktrackinghtml">trunk/LayoutTests/fast/selectors/querySelector-attribute-match-with-child-backtracking.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectorlongattributematchwithchildbacktrackingexpectedtxt">trunk/LayoutTests/fast/selectors/querySelector-long-attribute-match-with-child-backtracking-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectorlongattributematchwithchildbacktrackinghtml">trunk/LayoutTests/fast/selectors/querySelector-long-attribute-match-with-child-backtracking.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectorlongmultipleattributematchwithchildbacktrackingexpectedtxt">trunk/LayoutTests/fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectorlongmultipleattributematchwithchildbacktrackinghtml">trunk/LayoutTests/fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking.html</a></li>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectormultipleattributematchwithchildbacktrackingexpectedtxt">trunk/LayoutTests/fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastselectorsquerySelectormultipleattributematchwithchildbacktrackinghtml">trunk/LayoutTests/fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/LayoutTests/ChangeLog        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2014-02-10 Benjamin Poulain <benjamin@webkit.org>
+
+ Add the basic infrastructure to compile attributes matching in selectors
+ https://bugs.webkit.org/show_bug.cgi?id=128484
+
+ Reviewed by Gavin Barraclough.
+
+ Tests the various cases requiring more register than what is available from the caller-saved pool.
+
+ * fast/selectors/querySelector-attribute-match-with-child-backtracking-expected.txt: Added.
+ * fast/selectors/querySelector-attribute-match-with-child-backtracking.html: Added.
+ * fast/selectors/querySelector-long-attribute-match-with-child-backtracking-expected.txt: Added.
+ * fast/selectors/querySelector-long-attribute-match-with-child-backtracking.html: Added.
+ * fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking-expected.txt: Added.
+ * fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking.html: Added.
+ * fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking-expected.txt: Added.
+ * fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking.html: Added.
+
</ins><span class="cx"> 2014-02-10 Brady Eidson <beidson@apple.com>
</span><span class="cx">
</span><span class="cx"> IDB: storage/indexeddb/mozilla/indexes.html fails
</span></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectorattributematchwithchildbacktrackingexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-attribute-match-with-child-backtracking-expected.txt (0 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-attribute-match-with-child-backtracking-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-attribute-match-with-child-backtracking-expected.txt        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+Test backtracking of matching attributes with a single child selector relation.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.querySelectorAll("[data-foobar]>[data-webkit] [style]").length is 2
+PASS document.querySelectorAll("[data-foobar]>[data-webkit] [style]")[0].id is "target1"
+PASS document.querySelectorAll("[data-foobar]>[data-webkit] [style]")[1].id is "target2"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectorattributematchwithchildbacktrackinghtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-attribute-match-with-child-backtracking.html (0 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-attribute-match-with-child-backtracking.html         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-attribute-match-with-child-backtracking.html        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div style="display:none">
+ <div data-foobar>
+ <div data-webkit><div>
+ <div data-webkit>
+ <div>
+ <div data-webkit><div>
+ <div data-webkit><p id="target1">Target 1</p><div>
+ <div data-webkit><div>
+ <div>
+ <div>
+ <div data-webkit><div>
+ <div>
+ <div data-foobar>
+ <div data-webkit>
+ <div>
+ <div data-webkit><p id="target2">Target 2</p><div>
+ <div>
+ <div>
+ <div>
+</div>
+</body>
+<script>
+description('Test backtracking of matching attributes with a single child selector relation.');
+
+// Define the style dynamically to test lazy attributes.
+document.getElementById('target1').style.textDecoration='underline';
+document.getElementById('target2').style.textDecoration='underline';
+
+shouldBe('document.querySelectorAll("[data-foobar]>[data-webkit] [style]").length', '2');
+shouldBeEqualToString('document.querySelectorAll("[data-foobar]>[data-webkit] [style]")[0].id', 'target1');
+shouldBeEqualToString('document.querySelectorAll("[data-foobar]>[data-webkit] [style]")[1].id', 'target2');
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectorlongattributematchwithchildbacktrackingexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-long-attribute-match-with-child-backtracking-expected.txt (0 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-long-attribute-match-with-child-backtracking-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-long-attribute-match-with-child-backtracking-expected.txt        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+Test backtracking of matching attributes with multiple child selector relations.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.querySelectorAll("[data-foobar]>[data-webkit]>[data-html]>pre [style]").length is 3
+PASS document.querySelectorAll("[data-foobar]>[data-webkit]>[data-html]>pre [style]")[0].id is "target1"
+PASS document.querySelectorAll("[data-foobar]>[data-webkit]>[data-html]>pre [style]")[1].id is "target2"
+PASS document.querySelectorAll("[data-foobar]>[data-webkit]>[data-html]>pre [style]")[2].id is "target3"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectorlongattributematchwithchildbacktrackinghtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-long-attribute-match-with-child-backtracking.html (0 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-long-attribute-match-with-child-backtracking.html         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-long-attribute-match-with-child-backtracking.html        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -0,0 +1,99 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div style="display:none">
+<!-- Fails on the [data-html]. -->
+<div data-webkit data-foobar>
+ <div data-webkit>
+ <div data-webkit>
+ <div data-webkit>
+ <pre data-webkit>
+ <blockquote data-webkit><span data-webkit>Fail.</span></blockquote>
+ </pre>
+ </div>
+ </div>
+ <div>
+<div>
+
+<!-- Fails on the <div> tag. -->
+<div data-webkit>
+ <div data-webkit data-html>
+ <div data-webkit>
+ <pre data-webkit>
+ <blockquote data-webkit><span data-webkit>Fail.</span></blockquote>
+ </pre>
+ </div>
+ <div>
+</div>
+
+<!-- Simple matches. -->
+<div data-foobar>
+ <div data-webkit>
+ <div data-webkit data-html>
+ <pre data-webkit>
+ <blockquote data-webkit><span id="target1">Target 1</span></blockquote>
+ </pre>
+ </div>
+ <div>
+<div>
+<div data-webkit data-foobar>
+ <div data-webkit>
+ <div data-webkit data-html>
+ <pre data-webkit>
+ <pre data-webkit>
+ <blockquote data-webkit><span id="target2">Target 2</span></blockquote>
+ </pre>
+ </pre>
+ </div>
+ <div>
+<div>
+
+<!-- Multiple failures before a match. -->
+<div data-padding data-webkit data-foobar>
+ <div data-webkit data-padding>
+ <div data-html data-webkit data-padding>
+ <pre data-webkit data-padding>
+
+ <!-- This subtree lacks the [data-webkit] on the third level. -->
+ <div data-html data-padding>
+ <div data-html data-webkit data-padding>
+ <pre data-webkit data-padding>
+
+ <!-- This subtree lacks the [data-html] on the second level. -->
+ <div data-webkit data-padding>
+ <div data-webkit data-padding>
+ <pre data-webkit data-padding>
+ <blockquote data-webkit data-padding><span id="target3">Target 3</span></blockquote>
+ </pre>
+ </div>
+ </div>
+
+ </pre>
+ </div>
+ <div>
+
+ </pre>
+ </div>
+ <div>
+<div>
+
+</div>
+</body>
+<script>
+description('Test backtracking of matching attributes with multiple child selector relations.');
+
+// Define the style dynamically to test lazy attributes.
+var allTargetSpans = document.querySelectorAll('blockquote>span');
+for (var i = 0; i < allTargetSpans.length; ++i)
+ allTargetSpans[i].style.textDecoration='underline';
+
+shouldBe('document.querySelectorAll("[data-foobar]>[data-webkit]>[data-html]>pre [style]").length', '3');
+shouldBeEqualToString('document.querySelectorAll("[data-foobar]>[data-webkit]>[data-html]>pre [style]")[0].id', 'target1');
+shouldBeEqualToString('document.querySelectorAll("[data-foobar]>[data-webkit]>[data-html]>pre [style]")[1].id', 'target2');
+shouldBeEqualToString('document.querySelectorAll("[data-foobar]>[data-webkit]>[data-html]>pre [style]")[2].id', 'target3');
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectorlongmultipleattributematchwithchildbacktrackingexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking-expected.txt (0 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking-expected.txt        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+Test backtracking of matching multiple attribute with multiple child selector relations.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.querySelectorAll("[data-foo][data-bar]>[data-webkit][data-padding]>div>pre span[style]").length is 3
+PASS document.querySelectorAll("[data-foo][data-bar]>[data-webkit][data-padding]>div>pre span[style]")[0].id is "target1"
+PASS document.querySelectorAll("[data-foo][data-bar]>[data-webkit][data-padding]>div>pre span[style]")[1].id is "target2"
+PASS document.querySelectorAll("[data-foo][data-bar]>[data-webkit][data-padding]>div>pre span[style]")[2].id is "target3"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectorlongmultipleattributematchwithchildbacktrackinghtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking.html (0 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking.html         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking.html        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -0,0 +1,99 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div style="display:none">
+<!-- Fails on the <li> tag. There is extra [data-webkit][data-padding] preventing the match. -->
+<ul data-foo data-bar>
+ <li data-webkit data-padding>
+ <div data-webkit data-padding>
+ <div data-webkit data-padding>
+ <pre data-webkit data-padding>
+ <blockquote><span>Fail.</span></blockquote>
+ </pre>
+ </div>
+ </div>
+ </li>
+</ul>
+
+<!-- Fails on the the root, [data-foo] is missing. -->
+<div data-webkit data-padding data-bar>
+ <li data-webkit data-padding>
+ <div data-webkit data-padding>
+ <pre data-webkit data-padding>
+ <blockquote><span>Fail.</span></blockquote>
+ </pre>
+ </div>
+ </li>
+</div>
+
+<!-- Simple matches. -->
+<ul data-webkit data-padding data-foo data-bar>
+ <li data-webkit data-padding>
+ <div data-webkit data-padding>
+ <pre data-webkit data-padding>
+ <blockquote><span id="target1">Target 1</span></blockquote>
+ </pre>
+ </div>
+ </li>
+</ul>
+<ul data-foo data-bar>
+ <li data-webkit data-padding>
+ <div data-webkit data-padding>
+ <pre data-webkit data-padding>
+ <pre data-webkit data-padding>
+ <blockquote><span id="target2">Target 2</span></blockquote>
+ </pre>
+ </pre>
+ </div>
+ </li>
+</ul>
+
+<!-- Multiple failures before a match. -->
+<ul data-foo data-bar>
+ <li data-webkit data-padding>
+ <div data-webkit data-padding>
+ <pre data-webkit data-padding>
+
+ <!-- This subtree lacks the [data-foo] on the root. -->
+ <li data-webkit data-padding data-bar>
+ <div data-webkit data-padding>
+ <div data-webkit data-padding>
+
+ <!-- This subtree lacks the [data-webkit] in [data-webkit][data-padding]>div>pre. -->
+ <div data-padding>
+ <div data-webkit data-padding>
+ <pre data-webkit data-padding>
+ <blockquote><span id="target3">Target 3</span></blockquote>
+ </pre>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ </li>
+
+ </pre>
+ </div>
+ </li>
+</ul>
+
+</div>
+</body>
+<script>
+description('Test backtracking of matching multiple attribute with multiple child selector relations.');
+
+// Define the style dynamically to test lazy attributes.
+var allTargetSpans = document.querySelectorAll('blockquote>span');
+for (var i = 0; i < allTargetSpans.length; ++i)
+ allTargetSpans[i].style.textDecoration='underline';
+
+shouldBe('document.querySelectorAll("[data-foo][data-bar]>[data-webkit][data-padding]>div>pre span[style]").length', '3');
+shouldBeEqualToString('document.querySelectorAll("[data-foo][data-bar]>[data-webkit][data-padding]>div>pre span[style]")[0].id', 'target1');
+shouldBeEqualToString('document.querySelectorAll("[data-foo][data-bar]>[data-webkit][data-padding]>div>pre span[style]")[1].id', 'target2');
+shouldBeEqualToString('document.querySelectorAll("[data-foo][data-bar]>[data-webkit][data-padding]>div>pre span[style]")[2].id', 'target3');
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectormultipleattributematchwithchildbacktrackingexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking-expected.txt (0 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking-expected.txt        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+Test backtracking of matching multiple attribute with a single child selector relation.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.querySelectorAll("[data-foo][data-bar]>li [style]").length is 2
+PASS document.querySelectorAll("[data-foo][data-bar]>li [style]")[0].id is "target1"
+PASS document.querySelectorAll("[data-foo][data-bar]>li [style]")[1].id is "target2"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastselectorsquerySelectormultipleattributematchwithchildbacktrackinghtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking.html (0 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking.html         (rev 0)
+++ trunk/LayoutTests/fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking.html        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+<!doctype html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div style="display:none">
+ <ul data-foo data-bar>
+ <li></li>
+ <li>
+ <ol>
+ <li></li>
+ <li><p id="target1">Target 1</p></li>
+ <li></li>
+ </ol>
+ </li>
+ <li></li>
+ </ul>
+ <ul data-foo data-bar>
+ <li>
+ <li>
+ <li><p id="target2">Target 2</p></li>
+ </li>
+ </li>
+ </ul>
+</div>
+</body>
+<script>
+description('Test backtracking of matching multiple attribute with a single child selector relation.');
+
+// Define the style dynamically to test lazy attributes.
+document.getElementById('target1').style.textDecoration='underline';
+document.getElementById('target2').style.textDecoration='underline';
+
+shouldBe('document.querySelectorAll("[data-foo][data-bar]>li [style]").length', '2');
+shouldBeEqualToString('document.querySelectorAll("[data-foo][data-bar]>li [style]")[0].id', 'target1');
+shouldBeEqualToString('document.querySelectorAll("[data-foo][data-bar]>li [style]")[1].id', 'target2');
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</html>
</ins></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WTF/ChangeLog        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2014-02-10 Benjamin Poulain <benjamin@webkit.org>
+
+ Add the basic infrastructure to compile attributes matching in selectors
+ https://bugs.webkit.org/show_bug.cgi?id=128484
+
+ Reviewed by Gavin Barraclough.
+
+ * wtf/Vector.h:
+ (WTF::VectorBufferBase::bufferMemoryOffset):
+ (WTF::Vector::sizeMemoryOffset):
+ (WTF::Vector::dataMemoryOffset):
+ Expose the memory offsets of Vector::size() and the memory buffer pointer for the JIT.
+
</ins><span class="cx"> 2014-02-10 Enrica Casucci <enrica@apple.com>
</span><span class="cx">
</span><span class="cx"> copyShortASCIIString crashes on iOS after r163793.
</span></span></pre></div>
<a id="trunkSourceWTFwtfVectorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Vector.h (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Vector.h        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WTF/wtf/Vector.h        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * This library is free software; you can redistribute it and/or
</span><span class="cx"> * modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -306,6 +306,7 @@
</span><span class="cx">
</span><span class="cx"> T* buffer() { return m_buffer; }
</span><span class="cx"> const T* buffer() const { return m_buffer; }
</span><ins>+ static ptrdiff_t bufferMemoryOffset() { return OBJECT_OFFSETOF(VectorBufferBase, m_buffer); }
</ins><span class="cx"> size_t capacity() const { return m_capacity; }
</span><span class="cx">
</span><span class="cx"> MallocPtr<T> releaseBuffer()
</span><span class="lines">@@ -383,6 +384,7 @@
</span><span class="cx">
</span><span class="cx"> using Base::buffer;
</span><span class="cx"> using Base::capacity;
</span><ins>+ using Base::bufferMemoryOffset;
</ins><span class="cx">
</span><span class="cx"> using Base::releaseBuffer;
</span><span class="cx">
</span><span class="lines">@@ -487,6 +489,7 @@
</span><span class="cx">
</span><span class="cx"> using Base::buffer;
</span><span class="cx"> using Base::capacity;
</span><ins>+ using Base::bufferMemoryOffset;
</ins><span class="cx">
</span><span class="cx"> MallocPtr<T> releaseBuffer()
</span><span class="cx"> {
</span><span class="lines">@@ -574,6 +577,7 @@
</span><span class="cx"> Vector& operator=(Vector&&);
</span><span class="cx">
</span><span class="cx"> size_t size() const { return m_size; }
</span><ins>+ static ptrdiff_t sizeMemoryOffset() { return OBJECT_OFFSETOF(Vector, m_size); }
</ins><span class="cx"> size_t capacity() const { return Base::capacity(); }
</span><span class="cx"> bool isEmpty() const { return !size(); }
</span><span class="cx">
</span><span class="lines">@@ -607,6 +611,7 @@
</span><span class="cx">
</span><span class="cx"> T* data() { return Base::buffer(); }
</span><span class="cx"> const T* data() const { return Base::buffer(); }
</span><ins>+ static ptrdiff_t dataMemoryOffset() { return Base::bufferMemoryOffset(); }
</ins><span class="cx">
</span><span class="cx"> iterator begin() { return data(); }
</span><span class="cx"> iterator end() { return begin() + m_size; }
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/ChangeLog        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -1,3 +1,82 @@
</span><ins>+2014-02-10 Benjamin Poulain <benjamin@webkit.org>
+
+ Add the basic infrastructure to compile attributes matching in selectors
+ https://bugs.webkit.org/show_bug.cgi?id=128484
+
+ Reviewed by Gavin Barraclough.
+
+ Tests: fast/selectors/querySelector-attribute-match-with-child-backtracking.html
+ fast/selectors/querySelector-long-attribute-match-with-child-backtracking.html
+ fast/selectors/querySelector-long-multiple-attribute-match-with-child-backtracking.html
+ fast/selectors/querySelector-multiple-attribute-match-with-child-backtracking.html
+
+ Add the infrastructure to match attributes. This only add basic support for the 'Set' match
+ type, the other match types will have to be built on top.
+
+ * cssjit/RegisterAllocator.h:
+ (WebCore::RegisterAllocator::availableRegisterCount):
+ (WebCore::RegisterAllocator::allocateRegister):
+ (WebCore::RegisterAllocator::deallocateRegister):
+ (WebCore::RegisterAllocator::reserveCalleeSavedRegisters):
+ (WebCore::RegisterAllocator::restoreCalleeSavedRegisters):
+ (WebCore::RegisterAllocator::allocatedRegisters):
+ (WebCore::RegisterAllocator::RegisterAllocator):
+ (WebCore::RegisterAllocator::~RegisterAllocator):
+ In the worst case, matching attributes can take up to 10 registers. On x86_64, we have
+ 8 caller-saved registers. The extra 2 registers are simply added by taking callee-saved registers.
+
+ RegisterAllocator is modified to know support saving and restoring callee saved registers.
+ The list of available registers is changed from a vector to a HashSet because the registers
+ are removed from arbitrary locations in restoreCalleeSavedRegisters(). The m_allocatedRegisters
+ remain a vector since the allocation/release pattern remain ordered.
+
+ * cssjit/SelectorCompiler.cpp:
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::SelectorCodeGenerator):
+
+ (WebCore::SelectorCompiler::minimumRegisterRequirements):
+ This new utility finds the minimum number of registers needed to compile the input. In most
+ cases we have plenty enough. In rare cases we need to saved a few registers to the stack.
+
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::compile):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementDataMatching):
+ (WebCore::SelectorCompiler::testIsHTMLFlagOnNode):
+ (WebCore::SelectorCompiler::canMatchStyleAttribute):
+
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSynchronizeStyleAttribute):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSynchronizeAllAnimatedSVGAttribute):
+ The style attribute and certain SVG attributes can be modified lazily. In those cases,
+ the element needs to be updated before querying the attributes.
+
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementAttributesMatching):
+ (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementAttributeMatching):
+ Generate the attribute matching. For each CSSSelector matching an attribute, we generate
+ a loop over all the attributes of the element, maching the particular CSSSelector.
+ This makes no attempt at grouping related queries since those do not seem to happen a lot
+ in practice.
+
+ * dom/Attribute.h:
+ (WebCore::Attribute::nameMemoryOffset):
+ (WebCore::Attribute::nameMatchesFilter):
+ (WebCore::Attribute::matches):
+ * dom/ElementData.h:
+ (WebCore::ElementData::isUniqueFlag):
+ (WebCore::ElementData::arraySizeAndFlagsMemoryOffset):
+ (WebCore::ElementData::styleAttributeIsDirtyFlag):
+ (WebCore::ElementData::animatedSVGAttributesAreDirtyFlag):
+ (WebCore::ElementData::arraySizeOffset):
+ (WebCore::ShareableElementData::attributeArrayMemoryOffset):
+ (WebCore::UniqueElementData::attributeVectorMemoryOffset):
+ * dom/Node.h:
+ (WebCore::Node::flagIsHTML):
+ * dom/StyledElement.cpp:
+ (WebCore::StyledElement::synchronizeStyleAttributeInternal):
+ * dom/StyledElement.h:
+ (WebCore::StyledElement::synchronizeStyleAttributeInternal):
+ * svg/SVGElement.cpp:
+ (WebCore::SVGElement::synchronizeAllAnimatedSVGAttribute):
+ (WebCore::SVGElement::synchronizeAnimatedSVGAttribute):
+ * svg/SVGElement.h:
+
</ins><span class="cx"> 2014-02-10 Brady Eidson <beidson@apple.com>
</span><span class="cx">
</span><span class="cx"> IDB: storage/indexeddb/mozilla/indexes.html fails
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitRegisterAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/RegisterAllocator.h (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/RegisterAllocator.h        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/cssjit/RegisterAllocator.h        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -29,7 +29,8 @@
</span><span class="cx"> #if ENABLE(CSS_SELECTOR_JIT)
</span><span class="cx">
</span><span class="cx"> #include <JavaScriptCore/MacroAssembler.h>
</span><del>-#include <wtf/Deque.h>
</del><ins>+#include <StackAllocator.h>
+#include <wtf/HashSet.h>
</ins><span class="cx"> #include <wtf/Vector.h>
</span><span class="cx">
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -45,6 +46,13 @@
</span><span class="cx"> JSC::X86Registers::r10,
</span><span class="cx"> JSC::X86Registers::r11
</span><span class="cx"> };
</span><ins>+static const JSC::MacroAssembler::RegisterID calleeSavedRegisters[] = {
+ JSC::X86Registers::r12,
+ JSC::X86Registers::r13,
+ JSC::X86Registers::r14,
+ JSC::X86Registers::r15
+};
+static const unsigned registerCount = WTF_ARRAY_LENGTH(callerSavedRegisters) + WTF_ARRAY_LENGTH(calleeSavedRegisters);
</ins><span class="cx"> #else
</span><span class="cx"> #error RegisterAllocator has no defined registers for the architecture.
</span><span class="cx"> #endif
</span><span class="lines">@@ -52,12 +60,15 @@
</span><span class="cx"> class RegisterAllocator {
</span><span class="cx"> public:
</span><span class="cx"> RegisterAllocator();
</span><ins>+ ~RegisterAllocator();
</ins><span class="cx">
</span><ins>+ unsigned availableRegisterCount() const { return m_registers.size(); }
+
</ins><span class="cx"> JSC::MacroAssembler::RegisterID allocateRegister()
</span><span class="cx"> {
</span><del>- RELEASE_ASSERT(!m_registers.isEmpty());
-
- JSC::MacroAssembler::RegisterID registerID = m_registers.takeFirst();
</del><ins>+ auto first = m_registers.begin();
+ JSC::MacroAssembler::RegisterID registerID = static_cast<JSC::MacroAssembler::RegisterID>(*first);
+ RELEASE_ASSERT(m_registers.remove(first));
</ins><span class="cx"> ASSERT(!m_allocatedRegisters.contains(registerID));
</span><span class="cx"> m_allocatedRegisters.append(registerID);
</span><span class="cx"> return registerID;
</span><span class="lines">@@ -65,13 +76,8 @@
</span><span class="cx">
</span><span class="cx"> void allocateRegister(JSC::MacroAssembler::RegisterID registerID)
</span><span class="cx"> {
</span><ins>+ RELEASE_ASSERT(m_registers.remove(registerID));
</ins><span class="cx"> ASSERT(!m_allocatedRegisters.contains(registerID));
</span><del>- for (auto it = m_registers.begin(), end = m_registers.end(); it != end; ++it) {
- if (*it == registerID) {
- m_registers.remove(it);
- break;
- }
- }
</del><span class="cx"> m_allocatedRegisters.append(registerID);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -81,14 +87,36 @@
</span><span class="cx"> // Most allocation/deallocation happen in stack-like order. In the common case, this
</span><span class="cx"> // just removes the last item.
</span><span class="cx"> m_allocatedRegisters.remove(m_allocatedRegisters.reverseFind(registerID));
</span><del>- m_registers.append(registerID);
</del><ins>+ RELEASE_ASSERT(m_registers.add(registerID).isNewEntry);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- const Vector<JSC::MacroAssembler::RegisterID, 8>& allocatedRegisters() const { return m_allocatedRegisters; }
</del><ins>+ void reserveCalleeSavedRegisters(StackAllocator& stack, unsigned count)
+ {
+ unsigned finalSize = m_calleeSavedRegisters.size() + count;
+ RELEASE_ASSERT(finalSize <= WTF_ARRAY_LENGTH(calleeSavedRegisters));
+ for (unsigned i = m_calleeSavedRegisters.size(); i < finalSize; ++i) {
+ JSC::MacroAssembler::RegisterID registerId = calleeSavedRegisters[i];
+ m_calleeSavedRegisters.append(stack.push(registerId));
+ m_registers.add(registerId);
+ }
+ }
</ins><span class="cx">
</span><ins>+ void restoreCalleeSavedRegisters(StackAllocator& stack)
+ {
+ for (unsigned i = m_calleeSavedRegisters.size(); i > 0 ; --i) {
+ JSC::MacroAssembler::RegisterID registerId = calleeSavedRegisters[i - 1];
+ stack.pop(m_calleeSavedRegisters[i - 1], registerId);
+ RELEASE_ASSERT(m_registers.remove(registerId));
+ }
+ m_calleeSavedRegisters.clear();
+ }
+
+ const Vector<JSC::MacroAssembler::RegisterID, registerCount>& allocatedRegisters() const { return m_allocatedRegisters; }
+
</ins><span class="cx"> private:
</span><del>- Deque<JSC::MacroAssembler::RegisterID, WTF_ARRAY_LENGTH(callerSavedRegisters)> m_registers;
- Vector<JSC::MacroAssembler::RegisterID, WTF_ARRAY_LENGTH(callerSavedRegisters)> m_allocatedRegisters;
</del><ins>+ HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> m_registers;
+ Vector<JSC::MacroAssembler::RegisterID, registerCount> m_allocatedRegisters;
+ Vector<StackAllocator::StackReference, WTF_ARRAY_LENGTH(calleeSavedRegisters)> m_calleeSavedRegisters;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> class LocalRegister {
</span><span class="lines">@@ -117,9 +145,14 @@
</span><span class="cx"> inline RegisterAllocator::RegisterAllocator()
</span><span class="cx"> {
</span><span class="cx"> for (unsigned i = 0; i < WTF_ARRAY_LENGTH(callerSavedRegisters); ++i)
</span><del>- m_registers.append(callerSavedRegisters[i]);
</del><ins>+ m_registers.add(callerSavedRegisters[i]);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+inline RegisterAllocator::~RegisterAllocator()
+{
+ RELEASE_ASSERT(m_calleeSavedRegisters.isEmpty());
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx">
</span><span class="cx"> #endif // ENABLE(CSS_SELECTOR_JIT)
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitSelectorCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -30,16 +30,21 @@
</span><span class="cx">
</span><span class="cx"> #include "CSSSelector.h"
</span><span class="cx"> #include "Element.h"
</span><ins>+#include "ElementData.h"
</ins><span class="cx"> #include "FunctionCall.h"
</span><ins>+#include "HTMLNames.h"
</ins><span class="cx"> #include "NodeRenderStyle.h"
</span><span class="cx"> #include "QualifiedName.h"
</span><span class="cx"> #include "RegisterAllocator.h"
</span><span class="cx"> #include "RenderElement.h"
</span><span class="cx"> #include "RenderStyle.h"
</span><ins>+#include "SVGElement.h"
</ins><span class="cx"> #include "StackAllocator.h"
</span><ins>+#include "StyledElement.h"
</ins><span class="cx"> #include <JavaScriptCore/LinkBuffer.h>
</span><span class="cx"> #include <JavaScriptCore/MacroAssembler.h>
</span><span class="cx"> #include <JavaScriptCore/VM.h>
</span><ins>+#include <wtf/HashMap.h>
</ins><span class="cx"> #include <wtf/HashSet.h>
</span><span class="cx"> #include <wtf/Vector.h>
</span><span class="cx">
</span><span class="lines">@@ -103,9 +108,11 @@
</span><span class="cx"> const AtomicString* id;
</span><span class="cx"> Vector<const AtomicStringImpl*, 1> classNames;
</span><span class="cx"> HashSet<unsigned> pseudoClasses;
</span><ins>+ Vector<const CSSSelector*> attributes;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> typedef JSC::MacroAssembler Assembler;
</span><ins>+typedef Vector<SelectorFragment, 8> SelectorFragmentList;
</ins><span class="cx">
</span><span class="cx"> class SelectorCodeGenerator {
</span><span class="cx"> public:
</span><span class="lines">@@ -139,6 +146,10 @@
</span><span class="cx"> // Element properties matchers.
</span><span class="cx"> void generateElementMatching(Assembler::JumpList& failureCases, const SelectorFragment&);
</span><span class="cx"> void generateElementDataMatching(Assembler::JumpList& failureCases, const SelectorFragment&);
</span><ins>+ void generateSynchronizeStyleAttribute(Assembler::RegisterID elementDataArraySizeAndFlags);
+ void generateSynchronizeAllAnimatedSVGAttribute(Assembler::RegisterID elementDataArraySizeAndFlags);
+ void generateElementAttributesMatching(Assembler::JumpList& failureCases, const LocalRegister& elementDataAddress, const SelectorFragment&);
+ void generateElementAttributeMatching(Assembler::JumpList& failureCases, Assembler::RegisterID currentAttributeAddress, Assembler::RegisterID decIndexRegister, const CSSSelector* attributeSelector);
</ins><span class="cx"> void generateElementHasTagName(Assembler::JumpList& failureCases, const QualifiedName& nameToMatch);
</span><span class="cx"> void generateElementHasId(Assembler::JumpList& failureCases, const LocalRegister& elementDataAddress, const AtomicString& idToMatch);
</span><span class="cx"> void generateElementHasClasses(Assembler::JumpList& failureCases, const LocalRegister& elementDataAddress, const Vector<const AtomicStringImpl*>& classNames);
</span><span class="lines">@@ -151,7 +162,7 @@
</span><span class="cx"> Vector<std::pair<Assembler::Call, JSC::FunctionPtr>> m_functionCalls;
</span><span class="cx">
</span><span class="cx"> FunctionType m_functionType;
</span><del>- Vector<SelectorFragment, 8> m_selectorFragments;
</del><ins>+ SelectorFragmentList m_selectorFragments;
</ins><span class="cx"> bool m_selectorCannotMatchAnything;
</span><span class="cx">
</span><span class="cx"> StackAllocator::StackReference m_checkingContextStackReference;
</span><span class="lines">@@ -255,9 +266,11 @@
</span><span class="cx"> if (m_functionType == FunctionType::CannotCompile)
</span><span class="cx"> goto CannotHandleSelector;
</span><span class="cx"> break;
</span><ins>+ case CSSSelector::Set:
+ fragment.attributes.append(selector);
+ break;
</ins><span class="cx"> case CSSSelector::Unknown:
</span><span class="cx"> case CSSSelector::Exact:
</span><del>- case CSSSelector::Set:
</del><span class="cx"> case CSSSelector::List:
</span><span class="cx"> case CSSSelector::Hyphen:
</span><span class="cx"> case CSSSelector::PseudoElement:
</span><span class="lines">@@ -296,11 +309,51 @@
</span><span class="cx"> m_selectorFragments.clear();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static inline unsigned minimumRegisterRequirements(const SelectorFragmentList& selectorFragments)
+{
+ // Strict minimum to match anything interesting:
+ // Element + BacktrackingRegister + ElementData + a pointer to values + an index on that pointer + the value we expect;
+ unsigned minimum = 6;
+
+ // Attributes cause some register pressure.
+ for (unsigned selectorFragmentIndex = 0; selectorFragmentIndex < selectorFragments.size(); ++selectorFragmentIndex) {
+ const SelectorFragment& selectorFragment = selectorFragments[selectorFragmentIndex];
+ const Vector<const CSSSelector*>& attributes = selectorFragment.attributes;
+
+ for (unsigned attributeIndex = 0; attributeIndex < attributes.size(); ++attributeIndex) {
+ // Element + ElementData + scratchRegister + attributeArrayPointer + expectedLocalName + qualifiedNameImpl.
+ unsigned attributeMinimum = 6;
+ if (selectorFragment.traversalBacktrackingAction == BacktrackingAction::JumpToDescendantTail
+ || selectorFragment.matchingBacktrackingAction == BacktrackingAction::JumpToDescendantTail)
+ attributeMinimum += 1; // If there is a DescendantTail, there is a backtracking register.
+
+ if (attributes.size() != 1)
+ attributeMinimum += 2; // For the local copy of the counter and attributeArrayPointer.
+
+ const CSSSelector* attributeSelector = attributes[attributeIndex];
+ if (attributeSelector->attribute().prefix() != starAtom && !attributeSelector->attribute().namespaceURI().isNull())
+ attributeMinimum += 1; // Additional register for the expected namespace.
+
+ minimum = std::max(minimum, attributeMinimum);
+ }
+ }
+
+ return minimum;
+}
+
</ins><span class="cx"> inline SelectorCompilationStatus SelectorCodeGenerator::compile(JSC::VM* vm, JSC::MacroAssemblerCodeRef& codeRef)
</span><span class="cx"> {
</span><span class="cx"> if (m_selectorFragments.isEmpty() && !m_selectorCannotMatchAnything)
</span><span class="cx"> return SelectorCompilationStatus::CannotCompile;
</span><span class="cx">
</span><ins>+ bool reservedCalleeSavedRegisters = false;
+ unsigned availableRegisterCount = m_registerAllocator.availableRegisterCount();
+ unsigned minimumRegisterCountForAttributes = minimumRegisterRequirements(m_selectorFragments);
+ if (availableRegisterCount < minimumRegisterCountForAttributes) {
+ reservedCalleeSavedRegisters = true;
+ m_registerAllocator.reserveCalleeSavedRegisters(m_stackAllocator, minimumRegisterCountForAttributes - availableRegisterCount);
+ }
+
</ins><span class="cx"> m_registerAllocator.allocateRegister(elementAddressRegister);
</span><span class="cx">
</span><span class="cx"> if (m_functionType == FunctionType::SelectorCheckerWithCheckingContext)
</span><span class="lines">@@ -332,21 +385,36 @@
</span><span class="cx">
</span><span class="cx"> m_registerAllocator.deallocateRegister(elementAddressRegister);
</span><span class="cx">
</span><del>- if (m_functionType == FunctionType::SimpleSelectorChecker) {
- if (!m_selectorCannotMatchAnything) {
- // Success.
- m_assembler.move(Assembler::TrustedImm32(1), returnRegister);
</del><ins>+ if (m_functionType == FunctionType::SimpleSelectorChecker && m_selectorCannotMatchAnything) {
+ m_assembler.move(Assembler::TrustedImm32(0), returnRegister);
+ m_assembler.ret();
+ } else if (m_functionType == FunctionType::SimpleSelectorChecker) {
+ // Success.
+ m_assembler.move(Assembler::TrustedImm32(1), returnRegister);
+ if (!reservedCalleeSavedRegisters)
</ins><span class="cx"> m_assembler.ret();
</span><del>- }
</del><span class="cx">
</span><span class="cx"> // Failure.
</span><del>- if (m_selectorCannotMatchAnything || !failureCases.empty()) {
</del><ins>+ if (!failureCases.empty()) {
+ Assembler::Jump skipFailureCase;
+ if (reservedCalleeSavedRegisters)
+ skipFailureCase = m_assembler.jump();
+
</ins><span class="cx"> failureCases.link(&m_assembler);
</span><span class="cx"> m_assembler.move(Assembler::TrustedImm32(0), returnRegister);
</span><ins>+
+ if (!reservedCalleeSavedRegisters)
+ m_assembler.ret();
+ else
+ skipFailureCase.link(&m_assembler);
+ }
+ if (reservedCalleeSavedRegisters) {
+ m_registerAllocator.restoreCalleeSavedRegisters(m_stackAllocator);
</ins><span class="cx"> m_assembler.ret();
</span><span class="cx"> }
</span><span class="cx"> } else {
</span><span class="cx"> ASSERT(m_functionType == FunctionType::SelectorCheckerWithCheckingContext);
</span><ins>+ ASSERT(!m_selectorCannotMatchAnything);
</ins><span class="cx">
</span><span class="cx"> // Success.
</span><span class="cx"> m_assembler.move(Assembler::TrustedImm32(1), returnRegister);
</span><span class="lines">@@ -359,17 +427,17 @@
</span><span class="cx">
</span><span class="cx"> // Failure.
</span><span class="cx"> if (!failureCases.empty()) {
</span><del>- Assembler::Jump jumpToReturn = m_assembler.jump();
</del><ins>+ Assembler::Jump skipFailureCase = m_assembler.jump();
</ins><span class="cx">
</span><span class="cx"> failureCases.link(&m_assembler);
</span><span class="cx"> failureStack.discard();
</span><span class="cx"> m_assembler.move(Assembler::TrustedImm32(0), returnRegister);
</span><span class="cx">
</span><del>- jumpToReturn.link(&m_assembler);
</del><ins>+ skipFailureCase.link(&m_assembler);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> m_stackAllocator.merge(std::move(successStack), std::move(failureStack));
</span><del>-
</del><ins>+ m_registerAllocator.restoreCalleeSavedRegisters(m_stackAllocator);
</ins><span class="cx"> m_assembler.ret();
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -787,7 +855,7 @@
</span><span class="cx">
</span><span class="cx"> void SelectorCodeGenerator::generateElementDataMatching(Assembler::JumpList& failureCases, const SelectorFragment& fragment)
</span><span class="cx"> {
</span><del>- if (!fragment.id && fragment.classNames.isEmpty())
</del><ins>+ if (!fragment.id && fragment.classNames.isEmpty() && fragment.attributes.isEmpty())
</ins><span class="cx"> return;
</span><span class="cx">
</span><span class="cx"> // Generate:
</span><span class="lines">@@ -802,8 +870,168 @@
</span><span class="cx"> generateElementHasId(failureCases, elementDataAddress, *fragment.id);
</span><span class="cx"> if (!fragment.classNames.isEmpty())
</span><span class="cx"> generateElementHasClasses(failureCases, elementDataAddress, fragment.classNames);
</span><ins>+ if (!fragment.attributes.isEmpty())
+ generateElementAttributesMatching(failureCases, elementDataAddress, fragment);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+static inline Assembler::Jump testIsHTMLFlagOnNode(Assembler::ResultCondition condition, Assembler& assembler, Assembler::RegisterID nodeAddress)
+{
+ return assembler.branchTest32(condition, Assembler::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), Assembler::TrustedImm32(Node::flagIsHTML()));
+}
+
+static inline bool canMatchStyleAttribute(const SelectorFragment& fragment)
+{
+ for (unsigned i = 0; i < fragment.attributes.size(); ++i) {
+ const CSSSelector* attributeSelector = fragment.attributes[i];
+ const QualifiedName& attributeName = attributeSelector->attribute();
+ if (Attribute::nameMatchesFilter(HTMLNames::styleAttr, attributeName.prefix(), attributeName.localName(), attributeName.namespaceURI())
+ || Attribute::nameMatchesFilter(HTMLNames::styleAttr, attributeName.prefix(), attributeSelector->attributeCanonicalLocalName(), attributeName.namespaceURI())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SelectorCodeGenerator::generateSynchronizeStyleAttribute(Assembler::RegisterID elementDataArraySizeAndFlags)
+{
+ // The style attribute is updated lazily based on the flag styleAttributeIsDirty.
+ Assembler::Jump styleAttributeNotDirty = m_assembler.branchTest32(Assembler::Zero, elementDataArraySizeAndFlags, Assembler::TrustedImm32(ElementData::styleAttributeIsDirtyFlag()));
+
+ FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
+ functionCall.setFunctionAddress(StyledElement::synchronizeStyleAttributeInternal);
+ Assembler::RegisterID elementAddress = elementAddressRegister;
+ functionCall.setFirstArgument(elementAddress);
+ functionCall.call();
+
+ styleAttributeNotDirty.link(&m_assembler);
+}
+
+void SelectorCodeGenerator::generateSynchronizeAllAnimatedSVGAttribute(Assembler::RegisterID elementDataArraySizeAndFlags)
+{
+ // SVG attributes can be updated lazily depending on the flag AnimatedSVGAttributesAreDirty. We need to check
+ // that first.
+ Assembler::Jump animatedSVGAttributesNotDirty = m_assembler.branchTest32(Assembler::Zero, elementDataArraySizeAndFlags, Assembler::TrustedImm32(ElementData::animatedSVGAttributesAreDirtyFlag()));
+
+ FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
+ functionCall.setFunctionAddress(SVGElement::synchronizeAllAnimatedSVGAttribute);
+ Assembler::RegisterID elementAddress = elementAddressRegister;
+ functionCall.setFirstArgument(elementAddress);
+ functionCall.call();
+
+ animatedSVGAttributesNotDirty.link(&m_assembler);
+}
+
+void SelectorCodeGenerator::generateElementAttributesMatching(Assembler::JumpList& failureCases, const LocalRegister& elementDataAddress, const SelectorFragment& fragment)
+{
+ LocalRegister scratchRegister(m_registerAllocator);
+ Assembler::RegisterID elementDataArraySizeAndFlags = scratchRegister;
+ Assembler::RegisterID attributeArrayLength = scratchRegister;
+
+ m_assembler.load32(Assembler::Address(elementDataAddress, ElementData::arraySizeAndFlagsMemoryOffset()), elementDataArraySizeAndFlags);
+
+ if (canMatchStyleAttribute(fragment))
+ generateSynchronizeStyleAttribute(elementDataArraySizeAndFlags);
+
+ // FIXME: Systematically generating the function call for animatable SVG attributes causes a runtime penaltly. We should instead
+ // filter from the list of SVGElement::isAnimatableAttribute at runtime when compiling.
+ generateSynchronizeAllAnimatedSVGAttribute(elementDataArraySizeAndFlags);
+
+ // Attributes can be stored either in a separate vector for UniqueElementData, or after the elementData itself
+ // for ShareableElementData.
+ LocalRegister attributeArrayPointer(m_registerAllocator);
+ Assembler::Jump isShareableElementData = m_assembler.branchTest32(Assembler::Zero, elementDataArraySizeAndFlags, Assembler::TrustedImm32(ElementData::isUniqueFlag()));
+ {
+ ptrdiff_t attributeVectorOffset = UniqueElementData::attributeVectorMemoryOffset();
+ m_assembler.loadPtr(Assembler::Address(elementDataAddress, attributeVectorOffset + UniqueElementData::AttributeVector::dataMemoryOffset()), attributeArrayPointer);
+ m_assembler.load32(Assembler::Address(elementDataAddress, attributeVectorOffset + UniqueElementData::AttributeVector::sizeMemoryOffset()), attributeArrayLength);
+ }
+ Assembler::Jump skipShareable = m_assembler.jump();
+
+ {
+ isShareableElementData.link(&m_assembler);
+ m_assembler.urshift32(elementDataArraySizeAndFlags, Assembler::TrustedImm32(ElementData::arraySizeOffset()), attributeArrayLength);
+ m_assembler.add64(Assembler::TrustedImm32(ShareableElementData::attributeArrayMemoryOffset()), elementDataAddress, attributeArrayPointer);
+ }
+
+ skipShareable.link(&m_assembler);
+
+ // If there are no attributes, fail immediately.
+ failureCases.append(m_assembler.branchTest32(Assembler::Zero, attributeArrayLength));
+
+ unsigned attributeCount = fragment.attributes.size();
+ for (unsigned i = 0; i < attributeCount; ++i) {
+ Assembler::RegisterID decIndexRegister;
+ Assembler::RegisterID currentAttributeAddress;
+
+ bool isLastAttribute = i == (attributeCount - 1);
+ if (!isLastAttribute) {
+ // We need to make a copy to let the next iterations use the values.
+ currentAttributeAddress = m_registerAllocator.allocateRegister();
+ decIndexRegister = m_registerAllocator.allocateRegister();
+ m_assembler.move(attributeArrayPointer, currentAttributeAddress);
+ m_assembler.move(attributeArrayLength, decIndexRegister);
+ } else {
+ currentAttributeAddress = attributeArrayPointer;
+ decIndexRegister = attributeArrayLength;
+ }
+
+ generateElementAttributeMatching(failureCases, currentAttributeAddress, decIndexRegister, fragment.attributes[i]);
+
+ if (!isLastAttribute) {
+ m_registerAllocator.deallocateRegister(decIndexRegister);
+ m_registerAllocator.deallocateRegister(currentAttributeAddress);
+ }
+ }
+}
+
+void SelectorCodeGenerator::generateElementAttributeMatching(Assembler::JumpList& failureCases, Assembler::RegisterID currentAttributeAddress, Assembler::RegisterID decIndexRegister, const CSSSelector* attributeSelector)
+{
+ // Get the localName used for comparison. HTML elements use a lowercase local name known in selectors as canonicalLocalName.
+ LocalRegister localNameToMatch(m_registerAllocator);
+
+ // In general, canonicalLocalName and localName are the same. When they differ, we have to check if the node is HTML to know
+ // which one to use.
+ const AtomicStringImpl* canonicalLocalName = attributeSelector->attributeCanonicalLocalName().impl();
+ const AtomicStringImpl* localName = attributeSelector->attribute().localName().impl();
+ if (canonicalLocalName == localName)
+ m_assembler.move(Assembler::TrustedImmPtr(canonicalLocalName), localNameToMatch);
+ else {
+ m_assembler.move(Assembler::TrustedImmPtr(canonicalLocalName), localNameToMatch);
+ Assembler::Jump elementIsHTML = testIsHTMLFlagOnNode(Assembler::NonZero, m_assembler, elementAddressRegister);
+ m_assembler.move(Assembler::TrustedImmPtr(localName), localNameToMatch);
+ elementIsHTML.link(&m_assembler);
+ }
+
+ Assembler::JumpList successCases;
+ Assembler::Label loopStart(m_assembler.label());
+
+ LocalRegister qualifiedNameImpl(m_registerAllocator);
+ m_assembler.loadPtr(Assembler::Address(currentAttributeAddress, Attribute::nameMemoryOffset()), qualifiedNameImpl);
+
+ bool shouldCheckNamespace = attributeSelector->attribute().prefix() != starAtom;
+ if (shouldCheckNamespace) {
+ Assembler::Jump nameDoesNotMatch = m_assembler.branchPtr(Assembler::NotEqual, Assembler::Address(qualifiedNameImpl, QualifiedName::QualifiedNameImpl::localNameMemoryOffset()), localNameToMatch);
+
+ const AtomicStringImpl* namespaceURI = attributeSelector->attribute().namespaceURI().impl();
+ if (namespaceURI) {
+ LocalRegister namespaceToMatch(m_registerAllocator);
+ m_assembler.move(Assembler::TrustedImmPtr(namespaceURI), namespaceToMatch);
+ successCases.append(m_assembler.branchPtr(Assembler::Equal, Assembler::Address(qualifiedNameImpl, QualifiedName::QualifiedNameImpl::namespaceMemoryOffset()), namespaceToMatch));
+ } else
+ successCases.append(m_assembler.branchTestPtr(Assembler::Zero, Assembler::Address(qualifiedNameImpl, QualifiedName::QualifiedNameImpl::namespaceMemoryOffset())));
+ nameDoesNotMatch.link(&m_assembler);
+ } else
+ successCases.append(m_assembler.branchPtr(Assembler::Equal, Assembler::Address(qualifiedNameImpl, QualifiedName::QualifiedNameImpl::localNameMemoryOffset()), localNameToMatch));
+
+ // If we reached the last element -> failure.
+ failureCases.append(m_assembler.branchSub32(Assembler::Zero, Assembler::TrustedImm32(1), decIndexRegister));
+
+ // Otherwise just loop over.
+ m_assembler.addPtr(Assembler::TrustedImm32(sizeof(Attribute)), currentAttributeAddress);
+ m_assembler.jump().linkTo(loopStart, &m_assembler);
+ successCases.link(&m_assembler);
+}
+
</ins><span class="cx"> inline void SelectorCodeGenerator::generateElementHasTagName(Assembler::JumpList& failureCases, const QualifiedName& nameToMatch)
</span><span class="cx"> {
</span><span class="cx"> if (nameToMatch == anyQName())
</span></span></pre></div>
<a id="trunkSourceWebCoredomAttributeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Attribute.h (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Attribute.h        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/dom/Attribute.h        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> * (C) 1999 Antti Koivisto (koivisto@kde.org)
</span><span class="cx"> * (C) 2001 Peter Kelly (pmk@post.com)
</span><span class="cx"> * (C) 2001 Dirk Mueller (mueller@kde.org)
</span><del>- * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2012 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2012, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * This library is free software; you can redistribute it and/or
</span><span class="cx"> * modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -49,8 +49,10 @@
</span><span class="cx"> const AtomicString& namespaceURI() const { return m_name.namespaceURI(); }
</span><span class="cx">
</span><span class="cx"> const QualifiedName& name() const { return m_name; }
</span><ins>+ static ptrdiff_t nameMemoryOffset() { return OBJECT_OFFSETOF(Attribute, m_name); }
</ins><span class="cx">
</span><span class="cx"> bool isEmpty() const { return m_value.isEmpty(); }
</span><ins>+ static bool nameMatchesFilter(const QualifiedName&, const AtomicString& filterPrefix, const AtomicString& filterLocalName, const AtomicString& filterNamespaceURI);
</ins><span class="cx"> bool matches(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI) const;
</span><span class="cx">
</span><span class="cx"> void setValue(const AtomicString& value) { m_value = value; }
</span><span class="lines">@@ -72,13 +74,18 @@
</span><span class="cx"> AtomicString m_value;
</span><span class="cx"> };
</span><span class="cx">
</span><del>-inline bool Attribute::matches(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI) const
</del><ins>+inline bool Attribute::nameMatchesFilter(const QualifiedName& name, const AtomicString& filterPrefix, const AtomicString& filterLocalName, const AtomicString& filterNamespaceURI)
</ins><span class="cx"> {
</span><del>- if (localName != this->localName())
</del><ins>+ if (filterLocalName != name.localName())
</ins><span class="cx"> return false;
</span><del>- return prefix == starAtom || namespaceURI == this->namespaceURI();
</del><ins>+ return filterPrefix == starAtom || filterNamespaceURI == name.namespaceURI();
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+inline bool Attribute::matches(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI) const
+{
+ return nameMatchesFilter(m_name, prefix, localName, namespaceURI);
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx">
</span><span class="cx"> #endif // Attribute_h
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ElementData.h (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ElementData.h        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/dom/ElementData.h        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -113,7 +113,14 @@
</span><span class="cx"> bool isEquivalent(const ElementData* other) const;
</span><span class="cx">
</span><span class="cx"> bool isUnique() const { return m_arraySizeAndFlags & s_flagIsUnique; }
</span><ins>+ static uint32_t isUniqueFlag() { return s_flagIsUnique; }
</ins><span class="cx">
</span><ins>+ static ptrdiff_t arraySizeAndFlagsMemoryOffset() { return OBJECT_OFFSETOF(ElementData, m_arraySizeAndFlags); }
+ static inline uint32_t styleAttributeIsDirtyFlag() { return s_flagStyleAttributeIsDirty; }
+ static uint32_t animatedSVGAttributesAreDirtyFlag() { return s_flagAnimatedSVGAttributesAreDirty; }
+
+ static uint32_t arraySizeOffset() { return s_flagCount; }
+
</ins><span class="cx"> private:
</span><span class="cx"> mutable uint32_t m_arraySizeAndFlags;
</span><span class="cx">
</span><span class="lines">@@ -186,6 +193,8 @@
</span><span class="cx"> explicit ShareableElementData(const UniqueElementData&);
</span><span class="cx"> ~ShareableElementData();
</span><span class="cx">
</span><ins>+ static ptrdiff_t attributeArrayMemoryOffset() { return OBJECT_OFFSETOF(ShareableElementData, m_attributeArray); }
+
</ins><span class="cx"> Attribute m_attributeArray[0];
</span><span class="cx"> };
</span><span class="cx">
</span><span class="lines">@@ -209,8 +218,11 @@
</span><span class="cx"> explicit UniqueElementData(const ShareableElementData&);
</span><span class="cx"> explicit UniqueElementData(const UniqueElementData&);
</span><span class="cx">
</span><ins>+ static ptrdiff_t attributeVectorMemoryOffset() { return OBJECT_OFFSETOF(UniqueElementData, m_attributeVector); }
+
</ins><span class="cx"> mutable RefPtr<StyleProperties> m_presentationAttributeStyle;
</span><del>- Vector<Attribute, 4> m_attributeVector;
</del><ins>+ typedef Vector<Attribute, 4> AttributeVector;
+ AttributeVector m_attributeVector;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> inline void ElementData::deref()
</span></span></pre></div>
<a id="trunkSourceWebCoredomNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Node.h (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Node.h        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/dom/Node.h        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -561,6 +561,7 @@
</span><span class="cx"> #if ENABLE(CSS_SELECTOR_JIT)
</span><span class="cx"> static ptrdiff_t nodeFlagsMemoryOffset() { return OBJECT_OFFSETOF(Node, m_nodeFlags); }
</span><span class="cx"> static int32_t flagIsElement() { return IsElementFlag; }
</span><ins>+ static int32_t flagIsHTML() { return IsHTMLFlag; }
</ins><span class="cx"> static int32_t flagIsLink() { return IsLinkFlag; }
</span><span class="cx"> #endif // ENABLE(CSS_SELECTOR_JIT)
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoredomStyledElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/StyledElement.cpp (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/StyledElement.cpp        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/dom/StyledElement.cpp        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> * (C) 1999 Antti Koivisto (koivisto@kde.org)
</span><span class="cx"> * (C) 2001 Peter Kelly (pmk@post.com)
</span><span class="cx"> * (C) 2001 Dirk Mueller (mueller@kde.org)
</span><del>- * Copyright (C) 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2004, 2005, 2006, 2008, 2010, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * This library is free software; you can redistribute it and/or
</span><span class="cx"> * modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -118,13 +118,13 @@
</span><span class="cx"> return cleaner;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void StyledElement::synchronizeStyleAttributeInternal() const
</del><ins>+void StyledElement::synchronizeStyleAttributeInternal(StyledElement* styledElement)
</ins><span class="cx"> {
</span><del>- ASSERT(elementData());
- ASSERT(elementData()->styleAttributeIsDirty());
- elementData()->setStyleAttributeIsDirty(false);
- if (const StyleProperties* inlineStyle = this->inlineStyle())
- const_cast<StyledElement*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
</del><ins>+ ASSERT(styledElement->elementData());
+ ASSERT(styledElement->elementData()->styleAttributeIsDirty());
+ styledElement->elementData()->setStyleAttributeIsDirty(false);
+ if (const StyleProperties* inlineStyle = styledElement->inlineStyle())
+ styledElement->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> StyledElement::~StyledElement()
</span></span></pre></div>
<a id="trunkSourceWebCoredomStyledElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/StyledElement.h (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/StyledElement.h        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/dom/StyledElement.h        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> * (C) 1999 Antti Koivisto (koivisto@kde.org)
</span><span class="cx"> * (C) 2001 Peter Kelly (pmk@post.com)
</span><span class="cx"> * (C) 2001 Dirk Mueller (mueller@kde.org)
</span><del>- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * This library is free software; you can redistribute it and/or
</span><span class="cx"> * modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -55,7 +55,8 @@
</span><span class="cx"> bool removeInlineStyleProperty(CSSPropertyID);
</span><span class="cx"> void removeAllInlineStyleProperties();
</span><span class="cx">
</span><del>- void synchronizeStyleAttributeInternal() const;
</del><ins>+ static void synchronizeStyleAttributeInternal(StyledElement*);
+ void synchronizeStyleAttributeInternal() const { StyledElement::synchronizeStyleAttributeInternal(const_cast<StyledElement*>(this)); }
</ins><span class="cx">
</span><span class="cx"> virtual CSSStyleDeclaration* style() override final;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGElement.cpp (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGElement.cpp        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/svg/SVGElement.cpp        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx"> * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
</span><span class="cx"> * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis@kde.org>
</span><del>- * Copyright (C) 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2008, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> * Copyright (C) 2008 Alp Toker <alp@atoker.com>
</span><span class="cx"> * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
</span><span class="cx"> * Copyright (C) 2013 Samsung Electronics. All rights reserved.
</span><span class="lines">@@ -729,16 +729,24 @@
</span><span class="cx"> svgAttributeChanged(name);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void SVGElement::synchronizeAllAnimatedSVGAttribute(SVGElement* svgElement)
+{
+ ASSERT(svgElement->elementData());
+ ASSERT(svgElement->elementData()->animatedSVGAttributesAreDirty());
+
+ svgElement->localAttributeToPropertyMap().synchronizeProperties(svgElement);
+ svgElement->elementData()->setAnimatedSVGAttributesAreDirty(false);
+}
+
</ins><span class="cx"> void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
</span><span class="cx"> {
</span><span class="cx"> if (!elementData() || !elementData()->animatedSVGAttributesAreDirty())
</span><span class="cx"> return;
</span><span class="cx">
</span><span class="cx"> SVGElement* nonConstThis = const_cast<SVGElement*>(this);
</span><del>- if (name == anyQName()) {
- nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
- elementData()->setAnimatedSVGAttributesAreDirty(false);
- } else
</del><ins>+ if (name == anyQName())
+ synchronizeAllAnimatedSVGAttribute(nonConstThis);
+ else
</ins><span class="cx"> nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name);
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoresvgSVGElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/svg/SVGElement.h (163849 => 163850)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/svg/SVGElement.h        2014-02-11 02:29:22 UTC (rev 163849)
+++ trunk/Source/WebCore/svg/SVGElement.h        2014-02-11 02:41:00 UTC (rev 163850)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx"> * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
</span><span class="cx"> * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
</span><del>- * Copyright (C) 2009 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2009, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> * Copyright (C) 2013 Samsung Electronics. All rights reserved.
</span><span class="cx"> *
</span><span class="cx"> * This library is free software; you can redistribute it and/or
</span><span class="lines">@@ -110,6 +110,7 @@
</span><span class="cx"> void setCorrespondingElement(SVGElement*);
</span><span class="cx">
</span><span class="cx"> void synchronizeAnimatedSVGAttribute(const QualifiedName&) const;
</span><ins>+ static void synchronizeAllAnimatedSVGAttribute(SVGElement*);
</ins><span class="cx">
</span><span class="cx"> virtual PassRefPtr<RenderStyle> customStyleForRenderer() override;
</span><span class="cx">
</span></span></pre>
</div>
</div>
</body>
</html>