<!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>[199867] trunk/Source/JavaScriptCore</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/199867">199867</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-04-21 22:08:28 -0700 (Thu, 21 Apr 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[JSC] Add primitive String support to compare operators
https://bugs.webkit.org/show_bug.cgi?id=156783

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2016-04-21
Reviewed by Geoffrey Garen.

Just the basics.
We should eventually inline some of the simplest cases.

This is a 2% improvement on Longspider. It is unfortunately neutral
for Sunspider on my machine because most of the comparison are from
baseline.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileStringCompare):
(JSC::DFG::SpeculativeJIT::compileStringIdentCompare):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileCompareLess):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareLessEq):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareGreater):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareGreaterEq):
(JSC::FTL::DFG::LowerDFGToB3::compare):
* ftl/FTLOutput.h:
(JSC::FTL::Output::callWithoutSideEffects):
* jit/JITOperations.h:
* tests/stress/string-compare.js: Added.
(makeRope):
(makeString):
(let.operator.of.operators.eval.compareStringIdent):
(let.operator.of.operators.compareStringString):
(let.operator.of.operators.compareStringIdentString):
(let.operator.of.operators.compareStringStringIdent):
(let.operator.of.operators.let.left.of.typeCases.let.right.of.typeCases.eval):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationsh">trunk/Source/JavaScriptCore/dfg/DFGOperations.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOutputh">trunk/Source/JavaScriptCore/ftl/FTLOutput.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationsh">trunk/Source/JavaScriptCore/jit/JITOperations.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressstringcomparejs">trunk/Source/JavaScriptCore/tests/stress/string-compare.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2016-04-21  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [JSC] Add primitive String support to compare operators
+        https://bugs.webkit.org/show_bug.cgi?id=156783
+
+        Reviewed by Geoffrey Garen.
+
+        Just the basics.
+        We should eventually inline some of the simplest cases.
+
+        This is a 2% improvement on Longspider. It is unfortunately neutral
+        for Sunspider on my machine because most of the comparison are from
+        baseline.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compare):
+        (JSC::DFG::SpeculativeJIT::compileStringCompare):
+        (JSC::DFG::SpeculativeJIT::compileStringIdentCompare):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::callOperation):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareLess):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareLessEq):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareGreater):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareGreaterEq):
+        (JSC::FTL::DFG::LowerDFGToB3::compare):
+        * ftl/FTLOutput.h:
+        (JSC::FTL::Output::callWithoutSideEffects):
+        * jit/JITOperations.h:
+        * tests/stress/string-compare.js: Added.
+        (makeRope):
+        (makeString):
+        (let.operator.of.operators.eval.compareStringIdent):
+        (let.operator.of.operators.compareStringString):
+        (let.operator.of.operators.compareStringIdentString):
+        (let.operator.of.operators.compareStringStringIdent):
+        (let.operator.of.operators.let.left.of.typeCases.let.right.of.typeCases.eval):
+
</ins><span class="cx"> 2016-04-21  Benjamin Poulain  &lt;bpoulain@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] Commute FDiv-by-constant into FMul-by-reciprocal when it is safe
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -1314,11 +1314,24 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">             
</span><del>-            if (node-&gt;op() == CompareEq &amp;&amp; leftConst.isString() &amp;&amp; rightConst.isString()) {
</del><ins>+            if (leftConst.isString() &amp;&amp; rightConst.isString()) {
</ins><span class="cx">                 const StringImpl* a = asString(leftConst)-&gt;tryGetValueImpl();
</span><span class="cx">                 const StringImpl* b = asString(rightConst)-&gt;tryGetValueImpl();
</span><span class="cx">                 if (a &amp;&amp; b) {
</span><del>-                    setConstant(node, jsBoolean(WTF::equal(a, b)));
</del><ins>+                    bool result;
+                    if (node-&gt;op() == CompareEq)
+                        result = WTF::equal(a, b);
+                    else if (node-&gt;op() == CompareLess)
+                        result = codePointCompare(a, b) &lt; 0;
+                    else if (node-&gt;op() == CompareLessEq)
+                        result = codePointCompare(a, b) &lt;= 0;
+                    else if (node-&gt;op() == CompareGreater)
+                        result = codePointCompare(a, b) &gt; 0;
+                    else if (node-&gt;op() == CompareGreaterEq)
+                        result = codePointCompare(a, b) &gt;= 0;
+                    else
+                        RELEASE_ASSERT_NOT_REACHED();
+                    setConstant(node, jsBoolean(result));
</ins><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -1145,6 +1145,11 @@
</span><span class="cx">     case CompareLessEq:
</span><span class="cx">     case CompareGreater:
</span><span class="cx">     case CompareGreaterEq:
</span><ins>+        if (node-&gt;isBinaryUseKind(StringUse)) {
+            read(HeapObjectCount);
+            write(HeapObjectCount);
+            return;
+        }
</ins><span class="cx">         if (!node-&gt;isBinaryUseKind(UntypedUse)) {
</span><span class="cx">             def(PureValue(node));
</span><span class="cx">             return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -468,14 +468,6 @@
</span><span class="cx">                 node-&gt;clearFlags(NodeMustGenerate);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            if (node-&gt;op() != CompareEq)
-                break;
-            if (Node::shouldSpeculateSymbol(node-&gt;child1().node(), node-&gt;child2().node())) {
-                fixEdge&lt;SymbolUse&gt;(node-&gt;child1());
-                fixEdge&lt;SymbolUse&gt;(node-&gt;child2());
-                node-&gt;clearFlags(NodeMustGenerate);
-                break;
-            }
</del><span class="cx">             if (node-&gt;child1()-&gt;shouldSpeculateStringIdent() &amp;&amp; node-&gt;child2()-&gt;shouldSpeculateStringIdent()) {
</span><span class="cx">                 fixEdge&lt;StringIdentUse&gt;(node-&gt;child1());
</span><span class="cx">                 fixEdge&lt;StringIdentUse&gt;(node-&gt;child2());
</span><span class="lines">@@ -488,6 +480,15 @@
</span><span class="cx">                 node-&gt;clearFlags(NodeMustGenerate);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+
+            if (node-&gt;op() != CompareEq)
+                break;
+            if (Node::shouldSpeculateSymbol(node-&gt;child1().node(), node-&gt;child2().node())) {
+                fixEdge&lt;SymbolUse&gt;(node-&gt;child1());
+                fixEdge&lt;SymbolUse&gt;(node-&gt;child2());
+                node-&gt;clearFlags(NodeMustGenerate);
+                break;
+            }
</ins><span class="cx">             if (node-&gt;child1()-&gt;shouldSpeculateObject() &amp;&amp; node-&gt;child2()-&gt;shouldSpeculateObject()) {
</span><span class="cx">                 fixEdge&lt;ObjectUse&gt;(node-&gt;child1());
</span><span class="cx">                 fixEdge&lt;ObjectUse&gt;(node-&gt;child2());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -1342,6 +1342,58 @@
</span><span class="cx">     return exec-&gt;codeBlock()-&gt;stringSwitchJumpTable(tableIndex).offsetForValue(string-&gt;value(exec).impl(), std::numeric_limits&lt;int32_t&gt;::min());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+uintptr_t JIT_OPERATION operationCompareStringImplLess(StringImpl* a, StringImpl* b)
+{
+    return codePointCompare(a, b) &lt; 0;
+}
+
+uintptr_t JIT_OPERATION operationCompareStringImplLessEq(StringImpl* a, StringImpl* b)
+{
+    return codePointCompare(a, b) &lt;= 0;
+}
+
+uintptr_t JIT_OPERATION operationCompareStringImplGreater(StringImpl* a, StringImpl* b)
+{
+    return codePointCompare(a, b) &gt; 0;
+}
+
+uintptr_t JIT_OPERATION operationCompareStringImplGreaterEq(StringImpl* a, StringImpl* b)
+{
+    return codePointCompare(a, b) &gt;= 0;
+}
+
+uintptr_t JIT_OPERATION operationCompareStringLess(ExecState* exec, JSString* a, JSString* b)
+{
+    VM&amp; vm = exec-&gt;vm();
+    NativeCallFrameTracer tracer(&amp;vm, exec);
+
+    return codePointCompareLessThan(asString(a)-&gt;value(exec), asString(b)-&gt;value(exec));
+}
+
+uintptr_t JIT_OPERATION operationCompareStringLessEq(ExecState* exec, JSString* a, JSString* b)
+{
+    VM&amp; vm = exec-&gt;vm();
+    NativeCallFrameTracer tracer(&amp;vm, exec);
+
+    return !codePointCompareLessThan(asString(b)-&gt;value(exec), asString(a)-&gt;value(exec));
+}
+
+uintptr_t JIT_OPERATION operationCompareStringGreater(ExecState* exec, JSString* a, JSString* b)
+{
+    VM&amp; vm = exec-&gt;vm();
+    NativeCallFrameTracer tracer(&amp;vm, exec);
+
+    return codePointCompareLessThan(asString(b)-&gt;value(exec), asString(a)-&gt;value(exec));
+}
+
+uintptr_t JIT_OPERATION operationCompareStringGreaterEq(ExecState* exec, JSString* a, JSString* b)
+{
+    VM&amp; vm = exec-&gt;vm();
+    NativeCallFrameTracer tracer(&amp;vm, exec);
+
+    return !codePointCompareLessThan(asString(a)-&gt;value(exec), asString(b)-&gt;value(exec));
+}
+
</ins><span class="cx"> void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set)
</span><span class="cx"> {
</span><span class="cx">     VM&amp; vm = exec-&gt;vm();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.h (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.h        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -146,6 +146,14 @@
</span><span class="cx"> char* JIT_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex);
</span><span class="cx"> char* JIT_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*);
</span><span class="cx"> int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState*, size_t tableIndex, JSString*);
</span><ins>+uintptr_t JIT_OPERATION operationCompareStringImplLess(StringImpl*, StringImpl*);
+uintptr_t JIT_OPERATION operationCompareStringImplLessEq(StringImpl*, StringImpl*);
+uintptr_t JIT_OPERATION operationCompareStringImplGreater(StringImpl*, StringImpl*);
+uintptr_t JIT_OPERATION operationCompareStringImplGreaterEq(StringImpl*, StringImpl*);
+uintptr_t JIT_OPERATION operationCompareStringLess(ExecState*, JSString*, JSString*);
+uintptr_t JIT_OPERATION operationCompareStringLessEq(ExecState*, JSString*, JSString*);
+uintptr_t JIT_OPERATION operationCompareStringGreater(ExecState*, JSString*, JSString*);
+uintptr_t JIT_OPERATION operationCompareStringGreaterEq(ExecState*, JSString*, JSString*);
</ins><span class="cx"> void JIT_OPERATION operationNotifyWrite(ExecState*, WatchpointSet*);
</span><span class="cx"> void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState*) WTF_INTERNAL;
</span><span class="cx"> int32_t JIT_OPERATION operationSizeOfVarargs(ExecState*, EncodedJSValue arguments, int32_t firstVarArgOffset);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -1484,13 +1484,12 @@
</span><span class="cx">         else if (node-&gt;isBinaryUseKind(Int52RepUse))
</span><span class="cx">             compilePeepHoleInt52Branch(node, branchNode, condition);
</span><span class="cx"> #endif // USE(JSVALUE64)
</span><del>-        else if (node-&gt;isBinaryUseKind(DoubleRepUse))
</del><ins>+        else if (node-&gt;isBinaryUseKind(StringUse) || node-&gt;isBinaryUseKind(StringIdentUse)) {
+            // Use non-peephole comparison, for now.
+            return false;
+        } else if (node-&gt;isBinaryUseKind(DoubleRepUse))
</ins><span class="cx">             compilePeepHoleDoubleBranch(node, branchNode, doubleCondition);
</span><span class="cx">         else if (node-&gt;op() == CompareEq) {
</span><del>-            if (node-&gt;isBinaryUseKind(StringUse) || node-&gt;isBinaryUseKind(StringIdentUse)) {
-                // Use non-peephole comparison, for now.
-                return false;
-            }
</del><span class="cx">             if (node-&gt;isBinaryUseKind(BooleanUse))
</span><span class="cx">                 compilePeepHoleBooleanBranch(node, branchNode, condition);
</span><span class="cx">             else if (node-&gt;isBinaryUseKind(SymbolUse))
</span><span class="lines">@@ -4921,23 +4920,29 @@
</span><span class="cx">         compileDoubleCompare(node, doubleCondition);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    if (node-&gt;isBinaryUseKind(StringUse)) {
+        if (node-&gt;op() == CompareEq)
+            compileStringEquality(node);
+        else
+            compileStringCompare(node, condition);
+        return false;
+    }
+
+    if (node-&gt;isBinaryUseKind(StringIdentUse)) {
+        if (node-&gt;op() == CompareEq)
+            compileStringIdentEquality(node);
+        else
+            compileStringIdentCompare(node, condition);
+        return false;
+    }
+
</ins><span class="cx">     if (node-&gt;op() == CompareEq) {
</span><del>-        if (node-&gt;isBinaryUseKind(StringUse)) {
-            compileStringEquality(node);
-            return false;
-        }
-        
</del><span class="cx">         if (node-&gt;isBinaryUseKind(BooleanUse)) {
</span><span class="cx">             compileBooleanCompare(node, condition);
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (node-&gt;isBinaryUseKind(StringIdentUse)) {
-            compileStringIdentEquality(node);
-            return false;
-        }
-
</del><span class="cx">         if (node-&gt;isBinaryUseKind(SymbolUse)) {
</span><span class="cx">             compileSymbolEquality(node);
</span><span class="cx">             return false;
</span><span class="lines">@@ -5386,6 +5391,76 @@
</span><span class="cx">     unblessedBooleanResult(rightTempGPR, node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeJIT::compileStringCompare(Node* node, MacroAssembler::RelationalCondition condition)
+{
+    SpeculateCellOperand left(this, node-&gt;child1());
+    SpeculateCellOperand right(this, node-&gt;child2());
+    GPRReg leftGPR = left.gpr();
+    GPRReg rightGPR = right.gpr();
+
+    speculateString(node-&gt;child1(), leftGPR);
+    speculateString(node-&gt;child2(), rightGPR);
+
+    C_JITOperation_B_EJssJss compareFunction = nullptr;
+    if (condition == MacroAssembler::LessThan)
+        compareFunction = operationCompareStringLess;
+    else if (condition == MacroAssembler::LessThanOrEqual)
+        compareFunction = operationCompareStringLessEq;
+    else if (condition == MacroAssembler::GreaterThan)
+        compareFunction = operationCompareStringGreater;
+    else if (condition == MacroAssembler::GreaterThanOrEqual)
+        compareFunction = operationCompareStringGreaterEq;
+    else
+        RELEASE_ASSERT_NOT_REACHED();
+
+    GPRFlushedCallResult result(this);
+    GPRReg resultGPR = result.gpr();
+
+    flushRegisters();
+    callOperation(compareFunction, resultGPR, leftGPR, rightGPR);
+    m_jit.exceptionCheck();
+
+    unblessedBooleanResult(resultGPR, node);
+}
+
+void SpeculativeJIT::compileStringIdentCompare(Node* node, MacroAssembler::RelationalCondition condition)
+{
+    SpeculateCellOperand left(this, node-&gt;child1());
+    SpeculateCellOperand right(this, node-&gt;child2());
+    GPRFlushedCallResult result(this);
+    GPRTemporary leftTemp(this);
+    GPRTemporary rightTemp(this);
+
+    GPRReg leftGPR = left.gpr();
+    GPRReg rightGPR = right.gpr();
+    GPRReg resultGPR = result.gpr();
+    GPRReg leftTempGPR = leftTemp.gpr();
+    GPRReg rightTempGPR = rightTemp.gpr();
+
+    speculateString(node-&gt;child1(), leftGPR);
+    speculateString(node-&gt;child2(), rightGPR);
+
+    C_JITOperation_TT compareFunction = nullptr;
+    if (condition == MacroAssembler::LessThan)
+        compareFunction = operationCompareStringImplLess;
+    else if (condition == MacroAssembler::LessThanOrEqual)
+        compareFunction = operationCompareStringImplLessEq;
+    else if (condition == MacroAssembler::GreaterThan)
+        compareFunction = operationCompareStringImplGreater;
+    else if (condition == MacroAssembler::GreaterThanOrEqual)
+        compareFunction = operationCompareStringImplGreaterEq;
+    else
+        RELEASE_ASSERT_NOT_REACHED();
+
+    speculateStringIdentAndLoadStorage(node-&gt;child1(), leftGPR, leftTempGPR);
+    speculateStringIdentAndLoadStorage(node-&gt;child2(), rightGPR, rightTempGPR);
+
+    flushRegisters();
+    callOperation(compareFunction, resultGPR, leftTempGPR, rightTempGPR);
+
+    unblessedBooleanResult(resultGPR, node);
+}
+
</ins><span class="cx"> void SpeculativeJIT::compileStringZeroLength(Node* node)
</span><span class="cx"> {
</span><span class="cx">     SpeculateCellOperand str(this, node-&gt;child1());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -1076,6 +1076,16 @@
</span><span class="cx">         m_jit.setupArgumentsWithExecState(arg1, arg2);
</span><span class="cx">         return appendCallSetResult(operation, result);
</span><span class="cx">     }
</span><ins>+    JITCompiler::Call callOperation(C_JITOperation_B_EJssJss operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArgumentsWithExecState(arg1, arg2);
+        return appendCallSetResult(operation, result);
+    }
+    JITCompiler::Call callOperation(C_JITOperation_TT operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    {
+        m_jit.setupArguments(arg1, arg2);
+        return appendCallSetResult(operation, result);
+    }
</ins><span class="cx">     JITCompiler::Call callOperation(C_JITOperation_EJssJssJss operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
</span><span class="cx">     {
</span><span class="cx">         m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
</span><span class="lines">@@ -2402,6 +2412,8 @@
</span><span class="cx">     void compileInt52Compare(Node*, MacroAssembler::RelationalCondition);
</span><span class="cx">     void compileBooleanCompare(Node*, MacroAssembler::RelationalCondition);
</span><span class="cx">     void compileDoubleCompare(Node*, MacroAssembler::DoubleCondition);
</span><ins>+    void compileStringCompare(Node*, MacroAssembler::RelationalCondition);
+    void compileStringIdentCompare(Node*, MacroAssembler::RelationalCondition);
</ins><span class="cx">     
</span><span class="cx">     bool compileStrictEq(Node*);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -416,6 +416,10 @@
</span><span class="cx">             break;
</span><span class="cx">         if (node-&gt;isBinaryUseKind(DoubleRepUse))
</span><span class="cx">             break;
</span><ins>+        if (node-&gt;isBinaryUseKind(StringIdentUse))
+            break;
+        if (node-&gt;isBinaryUseKind(StringUse))
+            break;
</ins><span class="cx">         if (node-&gt;isBinaryUseKind(UntypedUse))
</span><span class="cx">             break;
</span><span class="cx">         return CannotCompile;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -4794,6 +4794,8 @@
</span><span class="cx">             [&amp;] (LValue left, LValue right) {
</span><span class="cx">                 return m_out.doubleLessThan(left, right);
</span><span class="cx">             },
</span><ins>+            operationCompareStringImplLess,
+            operationCompareStringLess,
</ins><span class="cx">             operationCompareLess);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -4806,6 +4808,8 @@
</span><span class="cx">             [&amp;] (LValue left, LValue right) {
</span><span class="cx">                 return m_out.doubleLessThanOrEqual(left, right);
</span><span class="cx">             },
</span><ins>+            operationCompareStringImplLessEq,
+            operationCompareStringLessEq,
</ins><span class="cx">             operationCompareLessEq);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -4818,6 +4822,8 @@
</span><span class="cx">             [&amp;] (LValue left, LValue right) {
</span><span class="cx">                 return m_out.doubleGreaterThan(left, right);
</span><span class="cx">             },
</span><ins>+            operationCompareStringImplGreater,
+            operationCompareStringGreater,
</ins><span class="cx">             operationCompareGreater);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -4830,6 +4836,8 @@
</span><span class="cx">             [&amp;] (LValue left, LValue right) {
</span><span class="cx">                 return m_out.doubleGreaterThanOrEqual(left, right);
</span><span class="cx">             },
</span><ins>+            operationCompareStringImplGreaterEq,
+            operationCompareStringGreaterEq,
</ins><span class="cx">             operationCompareGreaterEq);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -7531,7 +7539,9 @@
</span><span class="cx">     template&lt;typename IntFunctor, typename DoubleFunctor&gt;
</span><span class="cx">     void compare(
</span><span class="cx">         const IntFunctor&amp; intFunctor, const DoubleFunctor&amp; doubleFunctor,
</span><del>-        S_JITOperation_EJJ helperFunction)
</del><ins>+        C_JITOperation_TT stringIdentFunction,
+        C_JITOperation_B_EJssJss stringFunction,
+        S_JITOperation_EJJ fallbackFunction)
</ins><span class="cx">     {
</span><span class="cx">         if (m_node-&gt;isBinaryUseKind(Int32Use)) {
</span><span class="cx">             LValue left = lowInt32(m_node-&gt;child1());
</span><span class="lines">@@ -7554,9 +7564,29 @@
</span><span class="cx">             setBoolean(doubleFunctor(left, right));
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
+        if (m_node-&gt;isBinaryUseKind(StringIdentUse)) {
+            LValue left = lowStringIdent(m_node-&gt;child1());
+            LValue right = lowStringIdent(m_node-&gt;child2());
+            setBoolean(m_out.callWithoutSideEffects(m_out.boolean, stringIdentFunction, left, right));
+            return;
+        }
+
+        if (m_node-&gt;isBinaryUseKind(StringUse)) {
+            LValue left = lowCell(m_node-&gt;child1());
+            LValue right = lowCell(m_node-&gt;child2());
+            speculateString(m_node-&gt;child1(), left);
+            speculateString(m_node-&gt;child2(), right);
+
+            LValue result = vmCall(
+                m_out.boolean, m_out.operation(stringFunction),
+                m_callFrame, left, right);
+            setBoolean(result);
+            return;
+        }
+
</ins><span class="cx">         if (m_node-&gt;isBinaryUseKind(UntypedUse)) {
</span><del>-            nonSpeculativeCompare(intFunctor, helperFunction);
</del><ins>+            nonSpeculativeCompare(intFunctor, fallbackFunction);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOutputh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOutput.h (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOutput.h        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/ftl/FTLOutput.h        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -383,6 +383,14 @@
</span><span class="cx">     template&lt;typename... Args&gt;
</span><span class="cx">     LValue call(LType type, LValue function, LValue arg1, Args... args) { return m_block-&gt;appendNew&lt;B3::CCallValue&gt;(m_proc, type, origin(), function, arg1, args...); }
</span><span class="cx"> 
</span><ins>+    template&lt;typename Function, typename... Args&gt;
+    LValue callWithoutSideEffects(B3::Type type, Function function, LValue arg1, Args... args)
+    {
+        return m_block-&gt;appendNew&lt;B3::CCallValue&gt;(m_proc, type, origin(), B3::Effects::none(),
+            m_block-&gt;appendNew&lt;B3::ConstPtrValue&gt;(m_proc, origin(), bitwise_cast&lt;void*&gt;(function)),
+            arg1, args...);
+    }
+
</ins><span class="cx">     template&lt;typename FunctionType&gt;
</span><span class="cx">     LValue operation(FunctionType function) { return constIntPtr(bitwise_cast&lt;void*&gt;(function)); }
</span><span class="cx"> 
</span><span class="lines">@@ -470,15 +478,6 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     OrderMaker&lt;LBasicBlock&gt; m_blockOrder;
</span><del>-    
-    template&lt;typename Function, typename... Args&gt;
-    LValue callWithoutSideEffects(B3::Type type, Function function, LValue arg1, Args... args)
-    {
-        return m_block-&gt;appendNew&lt;B3::CCallValue&gt;(m_proc, type, origin(), B3::Effects::none(),
-            m_block-&gt;appendNew&lt;B3::ConstPtrValue&gt;(m_proc, origin(), bitwise_cast&lt;void*&gt;(function)),
-            arg1, args...);
-    }
-
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename... Params&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.h (199866 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.h        2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.h        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -176,6 +176,8 @@
</span><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_EJscZ)(ExecState*, JSScope*, int32_t);
</span><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssSt)(ExecState*, JSString*, Structure*);
</span><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssJss)(ExecState*, JSString*, JSString*);
</span><ins>+typedef uintptr_t JIT_OPERATION (*C_JITOperation_B_EJssJss)(ExecState*, JSString*, JSString*);
+typedef uintptr_t JIT_OPERATION (*C_JITOperation_TT)(StringImpl*, StringImpl*);
</ins><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssJssJss)(ExecState*, JSString*, JSString*, JSString*);
</span><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_EL)(ExecState*, JSLexicalEnvironment*);
</span><span class="cx"> typedef JSCell* JIT_OPERATION (*C_JITOperation_EO)(ExecState*, JSObject*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressstringcomparejs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/string-compare.js (0 => 199867)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/string-compare.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/string-compare.js        2016-04-22 05:08:28 UTC (rev 199867)
</span><span class="lines">@@ -0,0 +1,78 @@
</span><ins>+let typeCases = [
+    &quot;&quot;,
+    &quot;0&quot;,
+    &quot;1&quot;,
+    &quot;a&quot;,
+    &quot;aa&quot;,
+]
+
+let operators = [&quot;&lt;&quot;, &quot;&lt;=&quot;, &quot;&gt;&quot;, &quot;&gt;=&quot;, &quot;==&quot;, &quot;!=&quot;, &quot;===&quot;, &quot;!==&quot;];
+
+function makeRope(a)
+{
+    return a + a;
+}
+noInline(makeRope);
+
+function makeString(a)
+{
+    return makeRope(a).slice(a.length);
+}
+noInline(makeString);
+
+for (let operator of operators) {
+    eval(`
+        function compareStringIdent(a, b)
+        {
+            return a ${operator} b;
+        }
+        noInline(compareStringIdent);
+
+        function compareStringString(a, b)
+        {
+            return a ${operator} b;
+        }
+        noInline(compareStringString);
+
+        function compareStringIdentString(a, b)
+        {
+            return a ${operator} b;
+        }
+        noInline(compareStringIdentString);
+
+        function compareStringStringIdent(a, b)
+        {
+            return a ${operator} b;
+        }
+        noInline(compareStringStringIdent);
+    `);
+
+    for (let left of typeCases) {
+        for (let right of typeCases) {
+            let expected = eval(&quot;'&quot; + left + &quot;'&quot; + operator + &quot;'&quot; + right + &quot;'&quot;);
+            eval(`
+                 for (let i = 0; i &lt; 1e3; ++i) {
+                     let stringIdentResult = compareStringIdent('${left}', '${right}');
+                     if (stringIdentResult !== ${expected})
+                        throw &quot;Failed compareStringIdent('${left}', '${right}'), got &quot; + stringIdentResult + &quot; expected ${expected}&quot;;
+                     let resolvedLeftString = makeString('${left}');
+                     let resovledRightString = makeString('${right}');
+                     let stringStringResult = compareStringString(resolvedLeftString, resovledRightString);
+                     if (stringStringResult !== ${expected})
+                        throw &quot;Failed compareStringString('${left}', '${right}'), got &quot; + stringStringResult + &quot; expected ${expected}&quot;;
+                     stringStringResult = compareStringString(makeString('${left}'), makeString('${right}'));
+                     if (stringStringResult !== ${expected})
+                        throw &quot;Failed compareStringString('${left}', '${right}'), got &quot; + stringStringResult + &quot; expected ${expected}&quot;;
+
+                     if (compareStringIdentString(makeString('${left}'), '${right}') !== ${expected})
+                        throw &quot;Failed compareStringIdentString('${left}', '${right}'), expected was ${expected}&quot;;
+                     if (compareStringStringIdent('${left}', makeString('${right}')) !== ${expected})
+                        throw &quot;Failed compareStringStringIdent('${left}', '${right}'), expected was ${expected}&quot;;
+
+                     if (('${left}' ${operator} '${right}') !== ${expected})
+                        throw &quot;Failed constant folding of ('${left}' ${operator} '${right}'). How do you even fail constant folding?&quot;;
+                 }
+            `)
+        }
+    }
+}
</ins><span class="cx">\ No newline at end of file
</span></span></pre>
</div>
</div>

</body>
</html>