<!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  &lt;benjamin@webkit.org&gt;
+
+        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  &lt;beidson@apple.com&gt;
</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 &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit] [style]&quot;).length is 2
+PASS document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit] [style]&quot;)[0].id is &quot;target1&quot;
+PASS document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit] [style]&quot;)[1].id is &quot;target2&quot;
+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>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;display:none&quot;&gt;
+  &lt;div data-foobar&gt;
+    &lt;div data-webkit&gt;&lt;div&gt;
+    &lt;div data-webkit&gt;
+      &lt;div&gt;
+        &lt;div data-webkit&gt;&lt;div&gt;
+        &lt;div data-webkit&gt;&lt;p id=&quot;target1&quot;&gt;Target 1&lt;/p&gt;&lt;div&gt;
+        &lt;div data-webkit&gt;&lt;div&gt;
+      &lt;div&gt;
+    &lt;div&gt;
+    &lt;div data-webkit&gt;&lt;div&gt;
+  &lt;div&gt;
+  &lt;div data-foobar&gt;
+    &lt;div data-webkit&gt;
+      &lt;div&gt;
+        &lt;div data-webkit&gt;&lt;p id=&quot;target2&quot;&gt;Target 2&lt;/p&gt;&lt;div&gt;
+      &lt;div&gt;
+    &lt;div&gt;
+  &lt;div&gt;
+&lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+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(&quot;[data-foobar]&gt;[data-webkit] [style]&quot;).length', '2');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit] [style]&quot;)[0].id', 'target1');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit] [style]&quot;)[1].id', 'target2');
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</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 &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit]&gt;[data-html]&gt;pre [style]&quot;).length is 3
+PASS document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit]&gt;[data-html]&gt;pre [style]&quot;)[0].id is &quot;target1&quot;
+PASS document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit]&gt;[data-html]&gt;pre [style]&quot;)[1].id is &quot;target2&quot;
+PASS document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit]&gt;[data-html]&gt;pre [style]&quot;)[2].id is &quot;target3&quot;
+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>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;display:none&quot;&gt;
+&lt;!-- Fails on the [data-html]. --&gt;
+&lt;div data-webkit data-foobar&gt;
+  &lt;div data-webkit&gt;
+    &lt;div data-webkit&gt;
+      &lt;div data-webkit&gt;
+        &lt;pre data-webkit&gt;
+          &lt;blockquote data-webkit&gt;&lt;span data-webkit&gt;Fail.&lt;/span&gt;&lt;/blockquote&gt;
+        &lt;/pre&gt;
+      &lt;/div&gt;
+    &lt;/div&gt;
+  &lt;div&gt;
+&lt;div&gt;
+
+&lt;!-- Fails on the &lt;div&gt; tag. --&gt;
+&lt;div data-webkit&gt;
+  &lt;div data-webkit data-html&gt;
+    &lt;div data-webkit&gt;
+      &lt;pre data-webkit&gt;
+        &lt;blockquote data-webkit&gt;&lt;span data-webkit&gt;Fail.&lt;/span&gt;&lt;/blockquote&gt;
+      &lt;/pre&gt;
+    &lt;/div&gt;
+  &lt;div&gt;
+&lt;/div&gt;
+
+&lt;!-- Simple matches. --&gt;
+&lt;div data-foobar&gt;
+  &lt;div data-webkit&gt;
+    &lt;div data-webkit data-html&gt;
+      &lt;pre data-webkit&gt;
+        &lt;blockquote data-webkit&gt;&lt;span id=&quot;target1&quot;&gt;Target 1&lt;/span&gt;&lt;/blockquote&gt;
+      &lt;/pre&gt;
+    &lt;/div&gt;
+  &lt;div&gt;
+&lt;div&gt;
+&lt;div data-webkit data-foobar&gt;
+  &lt;div data-webkit&gt;
+    &lt;div data-webkit data-html&gt;
+      &lt;pre data-webkit&gt;
+        &lt;pre data-webkit&gt;
+          &lt;blockquote data-webkit&gt;&lt;span id=&quot;target2&quot;&gt;Target 2&lt;/span&gt;&lt;/blockquote&gt;
+        &lt;/pre&gt;
+      &lt;/pre&gt;
+    &lt;/div&gt;
+  &lt;div&gt;
+&lt;div&gt;
+
+&lt;!-- Multiple failures before a match. --&gt;
+&lt;div data-padding data-webkit data-foobar&gt;
+  &lt;div data-webkit data-padding&gt;
+    &lt;div data-html data-webkit data-padding&gt;
+      &lt;pre data-webkit data-padding&gt;
+
+        &lt;!-- This subtree lacks the [data-webkit] on the third level. --&gt;
+        &lt;div data-html data-padding&gt;
+          &lt;div data-html data-webkit data-padding&gt;
+            &lt;pre data-webkit data-padding&gt;
+
+              &lt;!-- This subtree lacks the [data-html] on the second level. --&gt;
+              &lt;div data-webkit data-padding&gt;
+                &lt;div data-webkit data-padding&gt;
+                  &lt;pre data-webkit data-padding&gt;
+                    &lt;blockquote data-webkit data-padding&gt;&lt;span id=&quot;target3&quot;&gt;Target 3&lt;/span&gt;&lt;/blockquote&gt;
+                  &lt;/pre&gt;
+                &lt;/div&gt;
+              &lt;/div&gt;
+
+            &lt;/pre&gt;
+          &lt;/div&gt;
+        &lt;div&gt;
+
+      &lt;/pre&gt;
+    &lt;/div&gt;
+  &lt;div&gt;
+&lt;div&gt;
+
+&lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+description('Test backtracking of matching attributes with multiple child selector relations.');
+
+// Define the style dynamically to test lazy attributes.
+var allTargetSpans = document.querySelectorAll('blockquote&gt;span');
+for (var i = 0; i &lt; allTargetSpans.length; ++i)
+    allTargetSpans[i].style.textDecoration='underline';
+
+shouldBe('document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit]&gt;[data-html]&gt;pre [style]&quot;).length', '3');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit]&gt;[data-html]&gt;pre [style]&quot;)[0].id', 'target1');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit]&gt;[data-html]&gt;pre [style]&quot;)[1].id', 'target2');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foobar]&gt;[data-webkit]&gt;[data-html]&gt;pre [style]&quot;)[2].id', 'target3');
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</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 &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.querySelectorAll(&quot;[data-foo][data-bar]&gt;[data-webkit][data-padding]&gt;div&gt;pre span[style]&quot;).length is 3
+PASS document.querySelectorAll(&quot;[data-foo][data-bar]&gt;[data-webkit][data-padding]&gt;div&gt;pre span[style]&quot;)[0].id is &quot;target1&quot;
+PASS document.querySelectorAll(&quot;[data-foo][data-bar]&gt;[data-webkit][data-padding]&gt;div&gt;pre span[style]&quot;)[1].id is &quot;target2&quot;
+PASS document.querySelectorAll(&quot;[data-foo][data-bar]&gt;[data-webkit][data-padding]&gt;div&gt;pre span[style]&quot;)[2].id is &quot;target3&quot;
+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>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;display:none&quot;&gt;
+&lt;!-- Fails on the &lt;li&gt; tag. There is extra [data-webkit][data-padding] preventing the match. --&gt;
+&lt;ul data-foo data-bar&gt;
+  &lt;li data-webkit data-padding&gt;
+    &lt;div data-webkit data-padding&gt;
+      &lt;div data-webkit data-padding&gt;
+        &lt;pre data-webkit data-padding&gt;
+          &lt;blockquote&gt;&lt;span&gt;Fail.&lt;/span&gt;&lt;/blockquote&gt;
+        &lt;/pre&gt;
+      &lt;/div&gt;
+    &lt;/div&gt;
+  &lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;!-- Fails on the the root, [data-foo] is missing. --&gt;
+&lt;div data-webkit data-padding data-bar&gt;
+  &lt;li data-webkit data-padding&gt;
+    &lt;div data-webkit data-padding&gt;
+      &lt;pre data-webkit data-padding&gt;
+        &lt;blockquote&gt;&lt;span&gt;Fail.&lt;/span&gt;&lt;/blockquote&gt;
+      &lt;/pre&gt;
+    &lt;/div&gt;
+  &lt;/li&gt;
+&lt;/div&gt;
+
+&lt;!-- Simple matches. --&gt;
+&lt;ul data-webkit data-padding data-foo data-bar&gt;
+  &lt;li data-webkit data-padding&gt;
+    &lt;div data-webkit data-padding&gt;
+      &lt;pre data-webkit data-padding&gt;
+        &lt;blockquote&gt;&lt;span id=&quot;target1&quot;&gt;Target 1&lt;/span&gt;&lt;/blockquote&gt;
+      &lt;/pre&gt;
+    &lt;/div&gt;
+  &lt;/li&gt;
+&lt;/ul&gt;
+&lt;ul data-foo data-bar&gt;
+  &lt;li data-webkit data-padding&gt;
+    &lt;div data-webkit data-padding&gt;
+      &lt;pre data-webkit data-padding&gt;
+        &lt;pre data-webkit data-padding&gt;
+          &lt;blockquote&gt;&lt;span id=&quot;target2&quot;&gt;Target 2&lt;/span&gt;&lt;/blockquote&gt;
+        &lt;/pre&gt;
+      &lt;/pre&gt;
+    &lt;/div&gt;
+  &lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;!-- Multiple failures before a match. --&gt;
+&lt;ul data-foo data-bar&gt;
+  &lt;li data-webkit data-padding&gt;
+    &lt;div data-webkit data-padding&gt;
+      &lt;pre data-webkit data-padding&gt;
+
+        &lt;!-- This subtree lacks the [data-foo] on the root. --&gt;
+        &lt;li data-webkit data-padding data-bar&gt;
+          &lt;div data-webkit data-padding&gt;
+            &lt;div data-webkit data-padding&gt;
+
+              &lt;!-- This subtree lacks the [data-webkit] in [data-webkit][data-padding]&gt;div&gt;pre. --&gt;
+              &lt;div data-padding&gt;
+                &lt;div data-webkit data-padding&gt;
+                  &lt;pre data-webkit data-padding&gt;
+                    &lt;blockquote&gt;&lt;span id=&quot;target3&quot;&gt;Target 3&lt;/span&gt;&lt;/blockquote&gt;
+                  &lt;/pre&gt;
+                &lt;/div&gt;
+              &lt;/div&gt;
+
+            &lt;/div&gt;
+          &lt;/div&gt;
+        &lt;/li&gt;
+
+      &lt;/pre&gt;
+    &lt;/div&gt;
+  &lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+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&gt;span');
+for (var i = 0; i &lt; allTargetSpans.length; ++i)
+    allTargetSpans[i].style.textDecoration='underline';
+
+shouldBe('document.querySelectorAll(&quot;[data-foo][data-bar]&gt;[data-webkit][data-padding]&gt;div&gt;pre span[style]&quot;).length', '3');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foo][data-bar]&gt;[data-webkit][data-padding]&gt;div&gt;pre span[style]&quot;)[0].id', 'target1');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foo][data-bar]&gt;[data-webkit][data-padding]&gt;div&gt;pre span[style]&quot;)[1].id', 'target2');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foo][data-bar]&gt;[data-webkit][data-padding]&gt;div&gt;pre span[style]&quot;)[2].id', 'target3');
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</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 &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS document.querySelectorAll(&quot;[data-foo][data-bar]&gt;li [style]&quot;).length is 2
+PASS document.querySelectorAll(&quot;[data-foo][data-bar]&gt;li [style]&quot;)[0].id is &quot;target1&quot;
+PASS document.querySelectorAll(&quot;[data-foo][data-bar]&gt;li [style]&quot;)[1].id is &quot;target2&quot;
+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>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div style=&quot;display:none&quot;&gt;
+  &lt;ul data-foo data-bar&gt;
+    &lt;li&gt;&lt;/li&gt;
+    &lt;li&gt;
+      &lt;ol&gt;
+        &lt;li&gt;&lt;/li&gt;
+        &lt;li&gt;&lt;p id=&quot;target1&quot;&gt;Target 1&lt;/p&gt;&lt;/li&gt;
+        &lt;li&gt;&lt;/li&gt;
+      &lt;/ol&gt;
+    &lt;/li&gt;
+    &lt;li&gt;&lt;/li&gt;
+  &lt;/ul&gt;
+  &lt;ul data-foo data-bar&gt;
+    &lt;li&gt;
+      &lt;li&gt;
+        &lt;li&gt;&lt;p id=&quot;target2&quot;&gt;Target 2&lt;/p&gt;&lt;/li&gt;
+      &lt;/li&gt;
+    &lt;/li&gt;
+  &lt;/ul&gt;
+&lt;/div&gt;
+&lt;/body&gt;
+&lt;script&gt;
+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(&quot;[data-foo][data-bar]&gt;li [style]&quot;).length', '2');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foo][data-bar]&gt;li [style]&quot;)[0].id', 'target1');
+shouldBeEqualToString('document.querySelectorAll(&quot;[data-foo][data-bar]&gt;li [style]&quot;)[1].id', 'target2');
+&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/html&gt;
</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  &lt;benjamin@webkit.org&gt;
+
+        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  &lt;enrica@apple.com&gt;
</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&lt;T&gt; 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&lt;T&gt; releaseBuffer()
</span><span class="cx">     {
</span><span class="lines">@@ -574,6 +577,7 @@
</span><span class="cx">     Vector&amp; operator=(Vector&amp;&amp;);
</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  &lt;benjamin@webkit.org&gt;
+
+        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  &lt;beidson@apple.com&gt;
</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 &lt;JavaScriptCore/MacroAssembler.h&gt;
</span><del>-#include &lt;wtf/Deque.h&gt;
</del><ins>+#include &lt;StackAllocator.h&gt;
+#include &lt;wtf/HashSet.h&gt;
</ins><span class="cx"> #include &lt;wtf/Vector.h&gt;
</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&lt;JSC::MacroAssembler::RegisterID&gt;(*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&lt;JSC::MacroAssembler::RegisterID, 8&gt;&amp; allocatedRegisters() const { return m_allocatedRegisters; }
</del><ins>+    void reserveCalleeSavedRegisters(StackAllocator&amp; stack, unsigned count)
+    {
+        unsigned finalSize = m_calleeSavedRegisters.size() + count;
+        RELEASE_ASSERT(finalSize &lt;= WTF_ARRAY_LENGTH(calleeSavedRegisters));
+        for (unsigned i = m_calleeSavedRegisters.size(); i &lt; 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&amp; stack)
+    {
+        for (unsigned i = m_calleeSavedRegisters.size(); i &gt; 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&lt;JSC::MacroAssembler::RegisterID, registerCount&gt;&amp; allocatedRegisters() const { return m_allocatedRegisters; }
+
</ins><span class="cx"> private:
</span><del>-    Deque&lt;JSC::MacroAssembler::RegisterID, WTF_ARRAY_LENGTH(callerSavedRegisters)&gt; m_registers;
-    Vector&lt;JSC::MacroAssembler::RegisterID, WTF_ARRAY_LENGTH(callerSavedRegisters)&gt; m_allocatedRegisters;
</del><ins>+    HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt; m_registers;
+    Vector&lt;JSC::MacroAssembler::RegisterID, registerCount&gt; m_allocatedRegisters;
+    Vector&lt;StackAllocator::StackReference, WTF_ARRAY_LENGTH(calleeSavedRegisters)&gt; 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 &lt; 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 &quot;CSSSelector.h&quot;
</span><span class="cx"> #include &quot;Element.h&quot;
</span><ins>+#include &quot;ElementData.h&quot;
</ins><span class="cx"> #include &quot;FunctionCall.h&quot;
</span><ins>+#include &quot;HTMLNames.h&quot;
</ins><span class="cx"> #include &quot;NodeRenderStyle.h&quot;
</span><span class="cx"> #include &quot;QualifiedName.h&quot;
</span><span class="cx"> #include &quot;RegisterAllocator.h&quot;
</span><span class="cx"> #include &quot;RenderElement.h&quot;
</span><span class="cx"> #include &quot;RenderStyle.h&quot;
</span><ins>+#include &quot;SVGElement.h&quot;
</ins><span class="cx"> #include &quot;StackAllocator.h&quot;
</span><ins>+#include &quot;StyledElement.h&quot;
</ins><span class="cx"> #include &lt;JavaScriptCore/LinkBuffer.h&gt;
</span><span class="cx"> #include &lt;JavaScriptCore/MacroAssembler.h&gt;
</span><span class="cx"> #include &lt;JavaScriptCore/VM.h&gt;
</span><ins>+#include &lt;wtf/HashMap.h&gt;
</ins><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -103,9 +108,11 @@
</span><span class="cx">     const AtomicString* id;
</span><span class="cx">     Vector&lt;const AtomicStringImpl*, 1&gt; classNames;
</span><span class="cx">     HashSet&lt;unsigned&gt; pseudoClasses;
</span><ins>+    Vector&lt;const CSSSelector*&gt; attributes;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> typedef JSC::MacroAssembler Assembler;
</span><ins>+typedef Vector&lt;SelectorFragment, 8&gt; 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&amp; failureCases, const SelectorFragment&amp;);
</span><span class="cx">     void generateElementDataMatching(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp;);
</span><ins>+    void generateSynchronizeStyleAttribute(Assembler::RegisterID elementDataArraySizeAndFlags);
+    void generateSynchronizeAllAnimatedSVGAttribute(Assembler::RegisterID elementDataArraySizeAndFlags);
+    void generateElementAttributesMatching(Assembler::JumpList&amp; failureCases, const LocalRegister&amp; elementDataAddress, const SelectorFragment&amp;);
+    void generateElementAttributeMatching(Assembler::JumpList&amp; failureCases, Assembler::RegisterID currentAttributeAddress, Assembler::RegisterID decIndexRegister, const CSSSelector* attributeSelector);
</ins><span class="cx">     void generateElementHasTagName(Assembler::JumpList&amp; failureCases, const QualifiedName&amp; nameToMatch);
</span><span class="cx">     void generateElementHasId(Assembler::JumpList&amp; failureCases, const LocalRegister&amp; elementDataAddress, const AtomicString&amp; idToMatch);
</span><span class="cx">     void generateElementHasClasses(Assembler::JumpList&amp; failureCases, const LocalRegister&amp; elementDataAddress, const Vector&lt;const AtomicStringImpl*&gt;&amp; classNames);
</span><span class="lines">@@ -151,7 +162,7 @@
</span><span class="cx">     Vector&lt;std::pair&lt;Assembler::Call, JSC::FunctionPtr&gt;&gt; m_functionCalls;
</span><span class="cx"> 
</span><span class="cx">     FunctionType m_functionType;
</span><del>-    Vector&lt;SelectorFragment, 8&gt; 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&amp; 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 &lt; selectorFragments.size(); ++selectorFragmentIndex) {
+        const SelectorFragment&amp; selectorFragment = selectorFragments[selectorFragmentIndex];
+        const Vector&lt;const CSSSelector*&gt;&amp; attributes = selectorFragment.attributes;
+
+        for (unsigned attributeIndex = 0; attributeIndex &lt; 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-&gt;attribute().prefix() != starAtom &amp;&amp; !attributeSelector-&gt;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&amp; codeRef)
</span><span class="cx"> {
</span><span class="cx">     if (m_selectorFragments.isEmpty() &amp;&amp; !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 &lt; 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 &amp;&amp; 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(&amp;m_assembler);
</span><span class="cx">             m_assembler.move(Assembler::TrustedImm32(0), returnRegister);
</span><ins>+
+            if (!reservedCalleeSavedRegisters)
+                m_assembler.ret();
+            else
+                skipFailureCase.link(&amp;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(&amp;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(&amp;m_assembler);
</del><ins>+            skipFailureCase.link(&amp;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&amp; failureCases, const SelectorFragment&amp; fragment)
</span><span class="cx"> {
</span><del>-    if (!fragment.id &amp;&amp; fragment.classNames.isEmpty())
</del><ins>+    if (!fragment.id &amp;&amp; fragment.classNames.isEmpty() &amp;&amp; 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&amp; assembler, Assembler::RegisterID nodeAddress)
+{
+    return assembler.branchTest32(condition, Assembler::Address(nodeAddress, Node::nodeFlagsMemoryOffset()), Assembler::TrustedImm32(Node::flagIsHTML()));
+}
+
+static inline bool canMatchStyleAttribute(const SelectorFragment&amp; fragment)
+{
+    for (unsigned i = 0; i &lt; fragment.attributes.size(); ++i) {
+        const CSSSelector* attributeSelector = fragment.attributes[i];
+        const QualifiedName&amp; attributeName = attributeSelector-&gt;attribute();
+        if (Attribute::nameMatchesFilter(HTMLNames::styleAttr, attributeName.prefix(), attributeName.localName(), attributeName.namespaceURI())
+            || Attribute::nameMatchesFilter(HTMLNames::styleAttr, attributeName.prefix(), attributeSelector-&gt;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(&amp;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(&amp;m_assembler);
+}
+
+void SelectorCodeGenerator::generateElementAttributesMatching(Assembler::JumpList&amp; failureCases, const LocalRegister&amp; elementDataAddress, const SelectorFragment&amp; 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(&amp;m_assembler);
+        m_assembler.urshift32(elementDataArraySizeAndFlags, Assembler::TrustedImm32(ElementData::arraySizeOffset()), attributeArrayLength);
+        m_assembler.add64(Assembler::TrustedImm32(ShareableElementData::attributeArrayMemoryOffset()), elementDataAddress, attributeArrayPointer);
+    }
+
+    skipShareable.link(&amp;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 &lt; 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&amp; 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-&gt;attributeCanonicalLocalName().impl();
+    const AtomicStringImpl* localName = attributeSelector-&gt;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(&amp;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-&gt;attribute().prefix() != starAtom;
+    if (shouldCheckNamespace) {
+        Assembler::Jump nameDoesNotMatch = m_assembler.branchPtr(Assembler::NotEqual, Assembler::Address(qualifiedNameImpl, QualifiedName::QualifiedNameImpl::localNameMemoryOffset()), localNameToMatch);
+
+        const AtomicStringImpl* namespaceURI = attributeSelector-&gt;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(&amp;m_assembler);
+    } else
+        successCases.append(m_assembler.branchPtr(Assembler::Equal, Assembler::Address(qualifiedNameImpl, QualifiedName::QualifiedNameImpl::localNameMemoryOffset()), localNameToMatch));
+
+    // If we reached the last element -&gt; 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, &amp;m_assembler);
+    successCases.link(&amp;m_assembler);
+}
+
</ins><span class="cx"> inline void SelectorCodeGenerator::generateElementHasTagName(Assembler::JumpList&amp; failureCases, const QualifiedName&amp; 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&amp; namespaceURI() const { return m_name.namespaceURI(); }
</span><span class="cx"> 
</span><span class="cx">     const QualifiedName&amp; 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&amp;, const AtomicString&amp; filterPrefix, const AtomicString&amp; filterLocalName, const AtomicString&amp; filterNamespaceURI);
</ins><span class="cx">     bool matches(const AtomicString&amp; prefix, const AtomicString&amp; localName, const AtomicString&amp; namespaceURI) const;
</span><span class="cx"> 
</span><span class="cx">     void setValue(const AtomicString&amp; 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&amp; prefix, const AtomicString&amp; localName, const AtomicString&amp; namespaceURI) const
</del><ins>+inline bool Attribute::nameMatchesFilter(const QualifiedName&amp; name, const AtomicString&amp; filterPrefix, const AtomicString&amp; filterLocalName, const AtomicString&amp; filterNamespaceURI)
</ins><span class="cx"> {
</span><del>-    if (localName != this-&gt;localName())
</del><ins>+    if (filterLocalName != name.localName())
</ins><span class="cx">         return false;
</span><del>-    return prefix == starAtom || namespaceURI == this-&gt;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&amp; prefix, const AtomicString&amp; localName, const AtomicString&amp; 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 &amp; 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&amp;);
</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&amp;);
</span><span class="cx">     explicit UniqueElementData(const UniqueElementData&amp;);
</span><span class="cx"> 
</span><ins>+    static ptrdiff_t attributeVectorMemoryOffset() { return OBJECT_OFFSETOF(UniqueElementData, m_attributeVector); }
+
</ins><span class="cx">     mutable RefPtr&lt;StyleProperties&gt; m_presentationAttributeStyle;
</span><del>-    Vector&lt;Attribute, 4&gt; m_attributeVector;
</del><ins>+    typedef Vector&lt;Attribute, 4&gt; 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()-&gt;styleAttributeIsDirty());
-    elementData()-&gt;setStyleAttributeIsDirty(false);
-    if (const StyleProperties* inlineStyle = this-&gt;inlineStyle())
-        const_cast&lt;StyledElement*&gt;(this)-&gt;setSynchronizedLazyAttribute(styleAttr, inlineStyle-&gt;asText());
</del><ins>+    ASSERT(styledElement-&gt;elementData());
+    ASSERT(styledElement-&gt;elementData()-&gt;styleAttributeIsDirty());
+    styledElement-&gt;elementData()-&gt;setStyleAttributeIsDirty(false);
+    if (const StyleProperties* inlineStyle = styledElement-&gt;inlineStyle())
+        styledElement-&gt;setSynchronizedLazyAttribute(styleAttr, inlineStyle-&gt;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&lt;StyledElement*&gt;(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 &lt;zimmermann@kde.org&gt;
</span><span class="cx">  * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis &lt;buis@kde.org&gt;
</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 &lt;alp@atoker.com&gt;
</span><span class="cx">  * Copyright (C) 2009 Cameron McCormack &lt;cam@mcc.id.au&gt;
</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-&gt;elementData());
+    ASSERT(svgElement-&gt;elementData()-&gt;animatedSVGAttributesAreDirty());
+
+    svgElement-&gt;localAttributeToPropertyMap().synchronizeProperties(svgElement);
+    svgElement-&gt;elementData()-&gt;setAnimatedSVGAttributesAreDirty(false);
+}
+
</ins><span class="cx"> void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName&amp; name) const
</span><span class="cx"> {
</span><span class="cx">     if (!elementData() || !elementData()-&gt;animatedSVGAttributesAreDirty())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     SVGElement* nonConstThis = const_cast&lt;SVGElement*&gt;(this);
</span><del>-    if (name == anyQName()) {
-        nonConstThis-&gt;localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
-        elementData()-&gt;setAnimatedSVGAttributesAreDirty(false);
-    } else
</del><ins>+    if (name == anyQName())
+        synchronizeAllAnimatedSVGAttribute(nonConstThis);
+    else
</ins><span class="cx">         nonConstThis-&gt;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 &lt;zimmermann@kde.org&gt;
</span><span class="cx">  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis &lt;buis@kde.org&gt;
</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&amp;) const;
</span><ins>+    static void synchronizeAllAnimatedSVGAttribute(SVGElement*);
</ins><span class="cx">  
</span><span class="cx">     virtual PassRefPtr&lt;RenderStyle&gt; customStyleForRenderer() override;
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>