<!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>[166537] trunk/Source/WebCore</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/166537">166537</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2014-03-31 15:19:04 -0700 (Mon, 31 Mar 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>CSS JIT: compile the first-child pseudo class
https://bugs.webkit.org/show_bug.cgi?id=130954

Reviewed by Andreas Kling.

* css/ElementRuleCollector.cpp:
(WebCore::ElementRuleCollector::collectMatchingRules):
The compiler use the context's style directly when resolving style. An error introduced
in the rule collector would cause a crash in the compiled code which would be hard to debug.
Add an assertion early in the stack to catch errors where it is easier to debug them.

* css/StyleResolver.cpp:
(WebCore::StyleResolver::State::initForStyleResolve):
* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::addPseudoType):
(WebCore::SelectorCompiler::SelectorCodeGenerator::SelectorCodeGenerator):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateWalkToPreviousAdjacentElement):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateWalkToPreviousAdjacent):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateDirectAdjacentTreeWalker):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateIndirectAdjacentTreeWalker):
Refactor those to be able to reuse the code getting a sibling element preceding the current element.

(WebCore::SelectorCompiler::SelectorCodeGenerator::jumpIfNotResolvingStyle):
Extract the code checking the current mode from SelectorCodeGenerator::markParentElementIfResolvingStyle()
in a separate function. This will be useful for all the pseudo class with marking.

(WebCore::SelectorCompiler::SelectorCodeGenerator::markParentElementIfResolvingStyle):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementMatching):
(WebCore::SelectorCompiler::setFirstChildState):
This is the slow path for when the first-child pseudo class is on a fragment that is not
the rightmost.
The reason to use a slow path is accessing renderStyle() is not trivial and this case isn't not
as common. We should improve this later.

(WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsFirstChild):
This is just implementing the test for first-child plus the tree marking. Nothing fancy,
this is basically the same thing as SelectorChecker.

* dom/Element.cpp:
(WebCore::Element::setChildrenAffectedByFirstChildRules):
* dom/Element.h:
C++ fallback to set the flag, to be improved later with the other flags.

* rendering/style/RenderStyle.h:
I accidentaly put noninheritedFlagsMemoryOffset() as private in the RenderStyle refactoring.

Also update the flags accessor to make them easier to work with from the compiler. In particular,
setFirstChildStateFlags() sets both isUnique and firstChild. Currently the JIT does not need to access
the value so individual flags are made private.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssElementRuleCollectorcpp">trunk/Source/WebCore/css/ElementRuleCollector.cpp</a></li>
<li><a href="#trunkSourceWebCorecssStyleResolvercpp">trunk/Source/WebCore/css/StyleResolver.cpp</a></li>
<li><a href="#trunkSourceWebCorecssjitSelectorCompilercpp">trunk/Source/WebCore/cssjit/SelectorCompiler.cpp</a></li>
<li><a href="#trunkSourceWebCoredomElementcpp">trunk/Source/WebCore/dom/Element.cpp</a></li>
<li><a href="#trunkSourceWebCoredomElementh">trunk/Source/WebCore/dom/Element.h</a></li>
<li><a href="#trunkSourceWebCorerenderingstyleRenderStyleh">trunk/Source/WebCore/rendering/style/RenderStyle.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (166536 => 166537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-03-31 22:17:55 UTC (rev 166536)
+++ trunk/Source/WebCore/ChangeLog        2014-03-31 22:19:04 UTC (rev 166537)
</span><span class="lines">@@ -1,3 +1,55 @@
</span><ins>+2014-03-31  Benjamin Poulain  &lt;benjamin@webkit.org&gt;
+
+        CSS JIT: compile the first-child pseudo class
+        https://bugs.webkit.org/show_bug.cgi?id=130954
+
+        Reviewed by Andreas Kling.
+
+        * css/ElementRuleCollector.cpp:
+        (WebCore::ElementRuleCollector::collectMatchingRules):
+        The compiler use the context's style directly when resolving style. An error introduced
+        in the rule collector would cause a crash in the compiled code which would be hard to debug.
+        Add an assertion early in the stack to catch errors where it is easier to debug them.
+
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::State::initForStyleResolve):
+        * cssjit/SelectorCompiler.cpp:
+        (WebCore::SelectorCompiler::addPseudoType):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::SelectorCodeGenerator):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateWalkToPreviousAdjacentElement):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateWalkToPreviousAdjacent):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateDirectAdjacentTreeWalker):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateIndirectAdjacentTreeWalker):
+        Refactor those to be able to reuse the code getting a sibling element preceding the current element.
+
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::jumpIfNotResolvingStyle):
+        Extract the code checking the current mode from SelectorCodeGenerator::markParentElementIfResolvingStyle()
+        in a separate function. This will be useful for all the pseudo class with marking.
+
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::markParentElementIfResolvingStyle):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementMatching):
+        (WebCore::SelectorCompiler::setFirstChildState):
+        This is the slow path for when the first-child pseudo class is on a fragment that is not
+        the rightmost.
+        The reason to use a slow path is accessing renderStyle() is not trivial and this case isn't not
+        as common. We should improve this later.
+
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementIsFirstChild):
+        This is just implementing the test for first-child plus the tree marking. Nothing fancy,
+        this is basically the same thing as SelectorChecker.
+
+        * dom/Element.cpp:
+        (WebCore::Element::setChildrenAffectedByFirstChildRules):
+        * dom/Element.h:
+        C++ fallback to set the flag, to be improved later with the other flags.
+
+        * rendering/style/RenderStyle.h:
+        I accidentaly put noninheritedFlagsMemoryOffset() as private in the RenderStyle refactoring.
+
+        Also update the flags accessor to make them easier to work with from the compiler. In particular,
+        setFirstChildStateFlags() sets both isUnique and firstChild. Currently the JIT does not need to access
+        the value so individual flags are made private.
+
</ins><span class="cx"> 2014-03-31  Dean Jackson  &lt;dino@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Remove WEB_ANIMATIONS
</span></span></pre></div>
<a id="trunkSourceWebCorecssElementRuleCollectorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/ElementRuleCollector.cpp (166536 => 166537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/ElementRuleCollector.cpp        2014-03-31 22:17:55 UTC (rev 166536)
+++ trunk/Source/WebCore/css/ElementRuleCollector.cpp        2014-03-31 22:19:04 UTC (rev 166537)
</span><span class="lines">@@ -145,6 +145,7 @@
</span><span class="cx"> void ElementRuleCollector::collectMatchingRules(const MatchRequest&amp; matchRequest, StyleResolver::RuleRange&amp; ruleRange)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(matchRequest.ruleSet);
</span><ins>+    ASSERT_WITH_MESSAGE(!(m_mode == SelectorChecker::ResolvingStyle &amp;&amp; !m_style), &quot;When resolving style, the SelectorChecker must have a style to set the pseudo elements and/or to do marking. The SelectorCompiler also rely on that behavior.&quot;);
</ins><span class="cx"> 
</span><span class="cx">     const AtomicString&amp; pseudoId = m_element.shadowPseudoId();
</span><span class="cx">     if (!pseudoId.isEmpty())
</span></span></pre></div>
<a id="trunkSourceWebCorecssStyleResolvercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/StyleResolver.cpp (166536 => 166537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/StyleResolver.cpp        2014-03-31 22:17:55 UTC (rev 166536)
+++ trunk/Source/WebCore/css/StyleResolver.cpp        2014-03-31 22:19:04 UTC (rev 166537)
</span><span class="lines">@@ -419,7 +419,7 @@
</span><span class="cx">     RenderStyle* docStyle = document.renderStyle();
</span><span class="cx">     m_rootElementStyle = docElement &amp;&amp; e != docElement ? docElement-&gt;renderStyle() : docStyle;
</span><span class="cx"> 
</span><del>-    m_style = 0;
</del><ins>+    m_style = nullptr;
</ins><span class="cx">     m_pendingImageProperties.clear();
</span><span class="cx">     m_fontDirty = false;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitSelectorCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (166536 => 166537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2014-03-31 22:17:55 UTC (rev 166536)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2014-03-31 22:19:04 UTC (rev 166537)
</span><span class="lines">@@ -49,6 +49,7 @@
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><ins>+#include &lt;wtf/text/CString.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> namespace SelectorCompiler {
</span><span class="lines">@@ -155,6 +156,7 @@
</span><span class="cx">     void generateParentElementTreeWalker(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp;);
</span><span class="cx">     void generateAncestorTreeWalker(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp;);
</span><span class="cx"> 
</span><ins>+    void generateWalkToPreviousAdjacentElement(Assembler::JumpList&amp; failureCases, Assembler::RegisterID);
</ins><span class="cx">     void generateWalkToPreviousAdjacent(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp;);
</span><span class="cx">     void generateDirectAdjacentTreeWalker(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp;);
</span><span class="cx">     void generateIndirectAdjacentTreeWalker(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp;);
</span><span class="lines">@@ -169,6 +171,7 @@
</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><span class="cx">     void generateElementFunctionCallTest(Assembler::JumpList&amp; failureCases, JSC::FunctionPtr);
</span><ins>+    void generateElementIsFirstChild(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp;);
</ins><span class="cx">     void generateSynchronizeStyleAttribute(Assembler::RegisterID elementDataArraySizeAndFlags);
</span><span class="cx">     void generateSynchronizeAllAnimatedSVGAttribute(Assembler::RegisterID elementDataArraySizeAndFlags);
</span><span class="cx">     void generateElementAttributesMatching(Assembler::JumpList&amp; failureCases, const LocalRegister&amp; elementDataAddress, const SelectorFragment&amp;);
</span><span class="lines">@@ -181,6 +184,9 @@
</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="cx">     void generateElementIsLink(Assembler::JumpList&amp; failureCases);
</span><span class="cx"> 
</span><ins>+    // Helpers.
+    Assembler::Jump jumpIfNotResolvingStyle(Assembler::RegisterID checkingContextRegister);
+
</ins><span class="cx">     Assembler m_assembler;
</span><span class="cx">     RegisterAllocator m_registerAllocator;
</span><span class="cx">     StackAllocator m_stackAllocator;
</span><span class="lines">@@ -238,7 +244,7 @@
</span><span class="cx">     return std::max(a, b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline FunctionType addPseudoType(CSSSelector::PseudoType type, SelectorFragment&amp; pseudoClasses)
</del><ins>+static inline FunctionType addPseudoType(CSSSelector::PseudoType type, SelectorFragment&amp; pseudoClasses, SelectorContext selectorContext)
</ins><span class="cx"> {
</span><span class="cx">     switch (type) {
</span><span class="cx">     // Unoptimized pseudo selector. They are just function call to a simple testing function.
</span><span class="lines">@@ -304,6 +310,12 @@
</span><span class="cx">         pseudoClasses.pseudoClasses.add(type);
</span><span class="cx">         return FunctionType::SimpleSelectorChecker;
</span><span class="cx"> 
</span><ins>+    case CSSSelector::PseudoFirstChild:
+        pseudoClasses.pseudoClasses.add(type);
+        if (selectorContext == SelectorContext::QuerySelector)
+            return FunctionType::SimpleSelectorChecker;
+        return FunctionType::SelectorCheckerWithCheckingContext;
+
</ins><span class="cx">     default:
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="lines">@@ -345,7 +357,7 @@
</span><span class="cx">             fragment.classNames.append(selector-&gt;value().impl());
</span><span class="cx">             break;
</span><span class="cx">         case CSSSelector::PseudoClass:
</span><del>-            m_functionType = mostRestrictiveFunctionType(m_functionType, addPseudoType(selector-&gt;pseudoType(), fragment));
</del><ins>+            m_functionType = mostRestrictiveFunctionType(m_functionType, addPseudoType(selector-&gt;pseudoType(), fragment, m_selectorContext));
</ins><span class="cx">             if (m_functionType == FunctionType::CannotCompile || m_functionType == FunctionType::CannotMatchAnything)
</span><span class="cx">                 return;
</span><span class="cx">             break;
</span><span class="lines">@@ -769,6 +781,14 @@
</span><span class="cx">     tagMatchingLocalFailureCases.linkTo(loopStart, &amp;m_assembler);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void SelectorCodeGenerator::generateWalkToPreviousAdjacentElement(Assembler::JumpList&amp; failureCases, Assembler::RegisterID workRegister)
+{
+    Assembler::Label loopStart = m_assembler.label();
+    m_assembler.loadPtr(Assembler::Address(workRegister, Node::previousSiblingMemoryOffset()), workRegister);
+    failureCases.append(m_assembler.branchTestPtr(Assembler::Zero, workRegister));
+    testIsElementFlagOnNode(Assembler::Zero, m_assembler, workRegister).linkTo(loopStart, &amp;m_assembler);
+}
+
</ins><span class="cx"> void SelectorCodeGenerator::generateWalkToPreviousAdjacent(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp; fragment)
</span><span class="cx"> {
</span><span class="cx">     //    do {
</span><span class="lines">@@ -788,10 +808,9 @@
</span><span class="cx">     } else
</span><span class="cx">         previousSibling = elementAddressRegister;
</span><span class="cx"> 
</span><del>-    Assembler::Label loopStart = m_assembler.label();
-    m_assembler.loadPtr(Assembler::Address(previousSibling, Node::previousSiblingMemoryOffset()), previousSibling);
-    failureCases.append(m_assembler.branchTestPtr(Assembler::Zero, previousSibling));
-    testIsElementFlagOnNode(Assembler::Zero, m_assembler, previousSibling).linkTo(loopStart, &amp;m_assembler);
</del><ins>+    Assembler::JumpList traversalFailureCases;
+    generateWalkToPreviousAdjacentElement(traversalFailureCases, previousSibling);
+    linkFailures(failureCases, fragment.traversalBacktrackingAction, traversalFailureCases);
</ins><span class="cx"> 
</span><span class="cx">     // On success, move previousSibling over to elementAddressRegister if we could not work on elementAddressRegister directly.
</span><span class="cx">     if (!useTailOnTraversalFailure) {
</span><span class="lines">@@ -804,9 +823,7 @@
</span><span class="cx"> {
</span><span class="cx">     markParentElementIfResolvingStyle(Element::setChildrenAffectedByDirectAdjacentRules);
</span><span class="cx"> 
</span><del>-    Assembler::JumpList traversalFailureCases;
-    generateWalkToPreviousAdjacent(traversalFailureCases, fragment);
-    linkFailures(failureCases, fragment.traversalBacktrackingAction, traversalFailureCases);
</del><ins>+    generateWalkToPreviousAdjacent(failureCases, fragment);
</ins><span class="cx"> 
</span><span class="cx">     Assembler::JumpList matchingFailureCases;
</span><span class="cx">     generateElementMatching(matchingFailureCases, fragment);
</span><span class="lines">@@ -822,9 +839,7 @@
</span><span class="cx"> 
</span><span class="cx">     Assembler::Label loopStart(m_assembler.label());
</span><span class="cx"> 
</span><del>-    Assembler::JumpList traversalFailureCases;
-    generateWalkToPreviousAdjacent(traversalFailureCases, fragment);
-    linkFailures(failureCases, fragment.traversalBacktrackingAction, traversalFailureCases);
</del><ins>+    generateWalkToPreviousAdjacent(failureCases, fragment);
</ins><span class="cx"> 
</span><span class="cx">     if (fragment.backtrackingFlags &amp; BacktrackingFlag::IndirectAdjacentEntryPoint)
</span><span class="cx">         m_indirectAdjacentEntryPoint = m_assembler.label();
</span><span class="lines">@@ -834,6 +849,18 @@
</span><span class="cx">     localFailureCases.linkTo(loopStart, &amp;m_assembler);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Assembler::Jump SelectorCodeGenerator::jumpIfNotResolvingStyle(Assembler::RegisterID checkingContext)
+{
+    RELEASE_ASSERT(m_selectorContext == SelectorContext::RuleCollector);
+
+    // Get the checking context.
+    unsigned offsetToCheckingContext = m_stackAllocator.offsetToStackReference(m_checkingContextStackReference);
+    m_assembler.loadPtr(Assembler::Address(Assembler::stackPointerRegister, offsetToCheckingContext), checkingContext);
+
+    // If we not resolving style, skip the whole marking.
+    return m_assembler.branch8(Assembler::NotEqual, Assembler::Address(checkingContext, OBJECT_OFFSETOF(CheckingContext, resolvingMode)), Assembler::TrustedImm32(SelectorChecker::ResolvingStyle));
+}
+
</ins><span class="cx"> void SelectorCodeGenerator::markParentElementIfResolvingStyle(JSC::FunctionPtr markingFunction)
</span><span class="cx"> {
</span><span class="cx">     if (m_selectorContext == SelectorContext::QuerySelector)
</span><span class="lines">@@ -843,19 +870,15 @@
</span><span class="cx">     //         Element* parent = element-&gt;parentNode();
</span><span class="cx">     //         markingFunction(parent);
</span><span class="cx">     //     }
</span><del>-    Assembler::JumpList failedToGetParent;
</del><ins>+
</ins><span class="cx">     Assembler::Jump notResolvingStyle;
</span><span class="cx">     {
</span><del>-        // Get the checking context.
-        unsigned offsetToCheckingContext = m_stackAllocator.offsetToStackReference(m_checkingContextStackReference);
</del><span class="cx">         LocalRegister checkingContext(m_registerAllocator);
</span><del>-        m_assembler.loadPtr(Assembler::Address(Assembler::stackPointerRegister, offsetToCheckingContext), checkingContext);
-
-        // If we not resolving style, skip the whole marking.
-        notResolvingStyle = m_assembler.branch8(Assembler::NotEqual, Assembler::Address(checkingContext, OBJECT_OFFSETOF(CheckingContext, resolvingMode)), Assembler::TrustedImm32(SelectorChecker::ResolvingStyle));
</del><ins>+        notResolvingStyle = jumpIfNotResolvingStyle(checkingContext);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Get the parent element in a temporary register.
</span><ins>+    Assembler::JumpList failedToGetParent;
</ins><span class="cx">     Assembler::RegisterID parentElement = m_registerAllocator.allocateRegister();
</span><span class="cx">     generateWalkToParentElement(failedToGetParent, parentElement);
</span><span class="cx"> 
</span><span class="lines">@@ -963,6 +986,9 @@
</span><span class="cx">         generateElementFunctionCallTest(failureCases, fragment.unoptimizedPseudoClasses[i]);
</span><span class="cx"> 
</span><span class="cx">     generateElementDataMatching(failureCases, fragment);
</span><ins>+
+    if (fragment.pseudoClasses.contains(CSSSelector::PseudoFirstChild))
+        generateElementIsFirstChild(failureCases, fragment);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SelectorCodeGenerator::generateElementDataMatching(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp; fragment)
</span><span class="lines">@@ -1381,6 +1407,82 @@
</span><span class="cx">     failureCases.append(functionCall.callAndBranchOnCondition(Assembler::Zero));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static void setFirstChildState(Element* element)
+{
+    if (RenderStyle* style = element-&gt;renderStyle())
+        style-&gt;setFirstChildState();
+}
+
+void SelectorCodeGenerator::generateElementIsFirstChild(Assembler::JumpList&amp; failureCases, const SelectorFragment&amp; fragment)
+{
+    if (m_selectorContext == SelectorContext::QuerySelector) {
+        Assembler::JumpList successCase;
+        LocalRegister previousSibling(m_registerAllocator);
+        m_assembler.move(elementAddressRegister, previousSibling);
+        generateWalkToPreviousAdjacentElement(successCase, previousSibling);
+        failureCases.append(m_assembler.jump());
+        successCase.link(&amp;m_assembler);
+        LocalRegister parent(m_registerAllocator);
+        generateWalkToParentElement(failureCases, parent);
+        return;
+    }
+
+    Assembler::RegisterID parentElement = m_registerAllocator.allocateRegister();
+    generateWalkToParentElement(failureCases, parentElement);
+
+    // Zero in isFirstChildRegister is the success case. The register is set to non-zero if a sibling if found.
+    LocalRegister isFirstChildRegister(m_registerAllocator);
+    m_assembler.move(Assembler::TrustedImm32(0), isFirstChildRegister);
+
+    {
+        Assembler::JumpList successCase;
+        LocalRegister previousSibling(m_registerAllocator);
+        m_assembler.move(elementAddressRegister, previousSibling);
+        generateWalkToPreviousAdjacentElement(successCase, previousSibling);
+
+        // If there was a sibling element, the element was not the first child -&gt; failure case.
+        m_assembler.move(Assembler::TrustedImm32(1), isFirstChildRegister);
+
+        successCase.link(&amp;m_assembler);
+    }
+
+    LocalRegister checkingContext(m_registerAllocator);
+    Assembler::Jump notResolvingStyle = jumpIfNotResolvingStyle(checkingContext);
+
+    m_registerAllocator.deallocateRegister(parentElement);
+    FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
+    functionCall.setFunctionAddress(Element::setChildrenAffectedByFirstChildRules);
+    functionCall.setOneArgument(parentElement);
+    functionCall.call();
+
+    // The parent marking is unconditional. If the matching is not a success, we can now fail.
+    // Otherwise we need to apply setFirstChildState() on the RenderStyle.
+    failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isFirstChildRegister));
+
+    if (fragment.relationToRightFragment == FragmentRelation::Rightmost) {
+        LocalRegister childStyle(m_registerAllocator);
+        m_assembler.loadPtr(Assembler::Address(checkingContext, OBJECT_OFFSETOF(CheckingContext, elementStyle)), childStyle);
+
+        // FIXME: We should look into doing something smart in MacroAssembler instead.
+        LocalRegister flags(m_registerAllocator);
+        Assembler::Address flagAddress(childStyle, RenderStyle::noninheritedFlagsMemoryOffset() + RenderStyle::NonInheritedFlags::flagsMemoryOffset());
+        m_assembler.load64(flagAddress, flags);
+        LocalRegister isFirstChildStateFlagImmediate(m_registerAllocator);
+        m_assembler.move(Assembler::TrustedImm64(RenderStyle::NonInheritedFlags::setFirstChildStateFlags()), isFirstChildStateFlagImmediate);
+        m_assembler.or64(isFirstChildStateFlagImmediate, flags);
+        m_assembler.store64(flags, flagAddress);
+    } else {
+        FunctionCall functionCall(m_assembler, m_registerAllocator, m_stackAllocator, m_functionCalls);
+        functionCall.setFunctionAddress(setFirstChildState);
+        Assembler::RegisterID elementAddress = elementAddressRegister;
+        functionCall.setOneArgument(elementAddress);
+        functionCall.call();
+    }
+
+    notResolvingStyle.link(&amp;m_assembler);
+    failureCases.append(m_assembler.branchTest32(Assembler::NonZero, isFirstChildRegister));
+}
+
</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="trunkSourceWebCoredomElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.cpp (166536 => 166537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.cpp        2014-03-31 22:17:55 UTC (rev 166536)
+++ trunk/Source/WebCore/dom/Element.cpp        2014-03-31 22:19:04 UTC (rev 166537)
</span><span class="lines">@@ -2066,6 +2066,11 @@
</span><span class="cx">     ensureElementRareData().setChildrenAffectedByDrag(true);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Element::setChildrenAffectedByFirstChildRules(Element* element)
+{
+    element-&gt;setChildrenAffectedByFirstChildRules();
+}
+
</ins><span class="cx"> void Element::setChildrenAffectedByDirectAdjacentRules(Element* element)
</span><span class="cx"> {
</span><span class="cx">     element-&gt;setChildrenAffectedByDirectAdjacentRules();
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.h (166536 => 166537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.h        2014-03-31 22:17:55 UTC (rev 166536)
+++ trunk/Source/WebCore/dom/Element.h        2014-03-31 22:19:04 UTC (rev 166537)
</span><span class="lines">@@ -372,6 +372,7 @@
</span><span class="cx">     void setChildrenAffectedByHover() { setFlag(ChildrenAffectedByHoverRulesFlag); }
</span><span class="cx">     void setChildrenAffectedByActive();
</span><span class="cx">     void setChildrenAffectedByDrag();
</span><ins>+    static void setChildrenAffectedByFirstChildRules(Element*);
</ins><span class="cx">     void setChildrenAffectedByFirstChildRules() { setFlag(ChildrenAffectedByFirstChildRulesFlag); }
</span><span class="cx">     void setChildrenAffectedByLastChildRules() { setFlag(ChildrenAffectedByLastChildRulesFlag); }
</span><span class="cx">     static void setChildrenAffectedByDirectAdjacentRules(Element*);
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingstyleRenderStyleh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/style/RenderStyle.h (166536 => 166537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/style/RenderStyle.h        2014-03-31 22:17:55 UTC (rev 166536)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.h        2014-03-31 22:19:04 UTC (rev 166537)
</span><span class="lines">@@ -278,13 +278,12 @@
</span><span class="cx">         static ETableLayout initialTableLayout() { return TAUTO; }
</span><span class="cx"> 
</span><span class="cx">         static ptrdiff_t flagsMemoryOffset() { return OBJECT_OFFSETOF(NonInheritedFlags, m_flags); }
</span><del>-        static uint8_t flagIsUnique() { return isUniqueOffset; }
-        static uint8_t flagEmptyState() { return emptyStateOffset; }
-        static uint8_t flagFirstChildState() { return firstChildStateOffset; }
-        static uint8_t flagLastChildState() { return lastChildStateOffset; }
-        static uint8_t flagAffectedByHover() { return affectedByHoverOffset; }
-        static uint8_t flagAffectedByActive() { return affectedByActiveOffset; }
-        static uint8_t flagAffectedByDrag() { return affectedByDragOffset; }
</del><ins>+        static uint64_t flagEmptyState() { return oneBitMask &lt;&lt; emptyStateOffset; }
+        static uint64_t setFirstChildStateFlags() { return flagFirstChildState() | flagIsUnique(); }
+        static uint64_t flagLastChildState() { return oneBitMask &lt;&lt; lastChildStateOffset; }
+        static uint64_t flagAffectedByHover() { return oneBitMask &lt;&lt; affectedByHoverOffset; }
+        static uint64_t flagAffectedByActive() { return oneBitMask &lt;&lt; affectedByActiveOffset; }
+        static uint64_t flagAffectedByDrag() { return oneBitMask &lt;&lt; affectedByDragOffset; }
</ins><span class="cx">     private:
</span><span class="cx">         void updateBoolean(bool isSet, uint64_t offset)
</span><span class="cx">         {
</span><span class="lines">@@ -311,6 +310,9 @@
</span><span class="cx">             return static_cast&lt;unsigned&gt;((m_flags &gt;&gt; offset) &amp; positionIndependentMask);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        static uint64_t flagIsUnique() { return oneBitMask &lt;&lt; isUniqueOffset; }
+        static uint64_t flagFirstChildState() { return oneBitMask &lt;&lt; firstChildStateOffset; }
+
</ins><span class="cx">         // To type the bit mask properly on 64bits.
</span><span class="cx">         static const uint64_t oneBitMask = 0x1;
</span><span class="cx"> 
</span><span class="lines">@@ -1942,6 +1944,8 @@
</span><span class="cx">     static Isolation initialIsolation() { return IsolationAuto; }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    static ptrdiff_t noninheritedFlagsMemoryOffset() { return OBJECT_OFFSETOF(RenderStyle, noninherited_flags); }
+
</ins><span class="cx"> private:
</span><span class="cx">     bool changeRequiresLayout(const RenderStyle*, unsigned&amp; changedContextSensitiveProperties) const;
</span><span class="cx">     bool changeRequiresPositionedLayoutOnly(const RenderStyle*, unsigned&amp; changedContextSensitiveProperties) const;
</span><span class="lines">@@ -2025,8 +2029,6 @@
</span><span class="cx">     Color lightingColor() const { return svgStyle().lightingColor(); }
</span><span class="cx"> 
</span><span class="cx">     void appendContent(std::unique_ptr&lt;ContentData&gt;);
</span><del>-
-    static ptrdiff_t noninheritedFlagsMemoryOffset() { return OBJECT_OFFSETOF(RenderStyle, noninherited_flags); }
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline int adjustForAbsoluteZoom(int value, const RenderStyle&amp; style)
</span></span></pre>
</div>
</div>

</body>
</html>