<!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 <bpoulain@apple.com> 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<AbstractStateType>::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 <bpoulain@apple.com>
+
+ [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<AbstractStateType>::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 <bpoulain@webkit.org>
</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->op() == CompareEq && leftConst.isString() && rightConst.isString()) {
</del><ins>+ if (leftConst.isString() && rightConst.isString()) {
</ins><span class="cx"> const StringImpl* a = asString(leftConst)->tryGetValueImpl();
</span><span class="cx"> const StringImpl* b = asString(rightConst)->tryGetValueImpl();
</span><span class="cx"> if (a && b) {
</span><del>- setConstant(node, jsBoolean(WTF::equal(a, b)));
</del><ins>+ bool result;
+ if (node->op() == CompareEq)
+ result = WTF::equal(a, b);
+ else if (node->op() == CompareLess)
+ result = codePointCompare(a, b) < 0;
+ else if (node->op() == CompareLessEq)
+ result = codePointCompare(a, b) <= 0;
+ else if (node->op() == CompareGreater)
+ result = codePointCompare(a, b) > 0;
+ else if (node->op() == CompareGreaterEq)
+ result = codePointCompare(a, b) >= 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->isBinaryUseKind(StringUse)) {
+ read(HeapObjectCount);
+ write(HeapObjectCount);
+ return;
+ }
</ins><span class="cx"> if (!node->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->clearFlags(NodeMustGenerate);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- if (node->op() != CompareEq)
- break;
- if (Node::shouldSpeculateSymbol(node->child1().node(), node->child2().node())) {
- fixEdge<SymbolUse>(node->child1());
- fixEdge<SymbolUse>(node->child2());
- node->clearFlags(NodeMustGenerate);
- break;
- }
</del><span class="cx"> if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
</span><span class="cx"> fixEdge<StringIdentUse>(node->child1());
</span><span class="cx"> fixEdge<StringIdentUse>(node->child2());
</span><span class="lines">@@ -488,6 +480,15 @@
</span><span class="cx"> node->clearFlags(NodeMustGenerate);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+
+ if (node->op() != CompareEq)
+ break;
+ if (Node::shouldSpeculateSymbol(node->child1().node(), node->child2().node())) {
+ fixEdge<SymbolUse>(node->child1());
+ fixEdge<SymbolUse>(node->child2());
+ node->clearFlags(NodeMustGenerate);
+ break;
+ }
</ins><span class="cx"> if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
</span><span class="cx"> fixEdge<ObjectUse>(node->child1());
</span><span class="cx"> fixEdge<ObjectUse>(node->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->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min());
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+uintptr_t JIT_OPERATION operationCompareStringImplLess(StringImpl* a, StringImpl* b)
+{
+ return codePointCompare(a, b) < 0;
+}
+
+uintptr_t JIT_OPERATION operationCompareStringImplLessEq(StringImpl* a, StringImpl* b)
+{
+ return codePointCompare(a, b) <= 0;
+}
+
+uintptr_t JIT_OPERATION operationCompareStringImplGreater(StringImpl* a, StringImpl* b)
+{
+ return codePointCompare(a, b) > 0;
+}
+
+uintptr_t JIT_OPERATION operationCompareStringImplGreaterEq(StringImpl* a, StringImpl* b)
+{
+ return codePointCompare(a, b) >= 0;
+}
+
+uintptr_t JIT_OPERATION operationCompareStringLess(ExecState* exec, JSString* a, JSString* b)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ return codePointCompareLessThan(asString(a)->value(exec), asString(b)->value(exec));
+}
+
+uintptr_t JIT_OPERATION operationCompareStringLessEq(ExecState* exec, JSString* a, JSString* b)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ return !codePointCompareLessThan(asString(b)->value(exec), asString(a)->value(exec));
+}
+
+uintptr_t JIT_OPERATION operationCompareStringGreater(ExecState* exec, JSString* a, JSString* b)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ return codePointCompareLessThan(asString(b)->value(exec), asString(a)->value(exec));
+}
+
+uintptr_t JIT_OPERATION operationCompareStringGreaterEq(ExecState* exec, JSString* a, JSString* b)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+
+ return !codePointCompareLessThan(asString(a)->value(exec), asString(b)->value(exec));
+}
+
</ins><span class="cx"> void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set)
</span><span class="cx"> {
</span><span class="cx"> VM& vm = exec->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->isBinaryUseKind(Int52RepUse))
</span><span class="cx"> compilePeepHoleInt52Branch(node, branchNode, condition);
</span><span class="cx"> #endif // USE(JSVALUE64)
</span><del>- else if (node->isBinaryUseKind(DoubleRepUse))
</del><ins>+ else if (node->isBinaryUseKind(StringUse) || node->isBinaryUseKind(StringIdentUse)) {
+ // Use non-peephole comparison, for now.
+ return false;
+ } else if (node->isBinaryUseKind(DoubleRepUse))
</ins><span class="cx"> compilePeepHoleDoubleBranch(node, branchNode, doubleCondition);
</span><span class="cx"> else if (node->op() == CompareEq) {
</span><del>- if (node->isBinaryUseKind(StringUse) || node->isBinaryUseKind(StringIdentUse)) {
- // Use non-peephole comparison, for now.
- return false;
- }
</del><span class="cx"> if (node->isBinaryUseKind(BooleanUse))
</span><span class="cx"> compilePeepHoleBooleanBranch(node, branchNode, condition);
</span><span class="cx"> else if (node->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->isBinaryUseKind(StringUse)) {
+ if (node->op() == CompareEq)
+ compileStringEquality(node);
+ else
+ compileStringCompare(node, condition);
+ return false;
+ }
+
+ if (node->isBinaryUseKind(StringIdentUse)) {
+ if (node->op() == CompareEq)
+ compileStringIdentEquality(node);
+ else
+ compileStringIdentCompare(node, condition);
+ return false;
+ }
+
</ins><span class="cx"> if (node->op() == CompareEq) {
</span><del>- if (node->isBinaryUseKind(StringUse)) {
- compileStringEquality(node);
- return false;
- }
-
</del><span class="cx"> if (node->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->isBinaryUseKind(StringIdentUse)) {
- compileStringIdentEquality(node);
- return false;
- }
-
</del><span class="cx"> if (node->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->child1());
+ SpeculateCellOperand right(this, node->child2());
+ GPRReg leftGPR = left.gpr();
+ GPRReg rightGPR = right.gpr();
+
+ speculateString(node->child1(), leftGPR);
+ speculateString(node->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->child1());
+ SpeculateCellOperand right(this, node->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->child1(), leftGPR);
+ speculateString(node->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->child1(), leftGPR, leftTempGPR);
+ speculateStringIdentAndLoadStorage(node->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->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->isBinaryUseKind(DoubleRepUse))
</span><span class="cx"> break;
</span><ins>+ if (node->isBinaryUseKind(StringIdentUse))
+ break;
+ if (node->isBinaryUseKind(StringUse))
+ break;
</ins><span class="cx"> if (node->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"> [&] (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"> [&] (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"> [&] (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"> [&] (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<typename IntFunctor, typename DoubleFunctor>
</span><span class="cx"> void compare(
</span><span class="cx"> const IntFunctor& intFunctor, const DoubleFunctor& 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->isBinaryUseKind(Int32Use)) {
</span><span class="cx"> LValue left = lowInt32(m_node->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->isBinaryUseKind(StringIdentUse)) {
+ LValue left = lowStringIdent(m_node->child1());
+ LValue right = lowStringIdent(m_node->child2());
+ setBoolean(m_out.callWithoutSideEffects(m_out.boolean, stringIdentFunction, left, right));
+ return;
+ }
+
+ if (m_node->isBinaryUseKind(StringUse)) {
+ LValue left = lowCell(m_node->child1());
+ LValue right = lowCell(m_node->child2());
+ speculateString(m_node->child1(), left);
+ speculateString(m_node->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->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<typename... Args>
</span><span class="cx"> LValue call(LType type, LValue function, LValue arg1, Args... args) { return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function, arg1, args...); }
</span><span class="cx">
</span><ins>+ template<typename Function, typename... Args>
+ LValue callWithoutSideEffects(B3::Type type, Function function, LValue arg1, Args... args)
+ {
+ return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), B3::Effects::none(),
+ m_block->appendNew<B3::ConstPtrValue>(m_proc, origin(), bitwise_cast<void*>(function)),
+ arg1, args...);
+ }
+
</ins><span class="cx"> template<typename FunctionType>
</span><span class="cx"> LValue operation(FunctionType function) { return constIntPtr(bitwise_cast<void*>(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<LBasicBlock> m_blockOrder;
</span><del>-
- template<typename Function, typename... Args>
- LValue callWithoutSideEffects(B3::Type type, Function function, LValue arg1, Args... args)
- {
- return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), B3::Effects::none(),
- m_block->appendNew<B3::ConstPtrValue>(m_proc, origin(), bitwise_cast<void*>(function)),
- arg1, args...);
- }
-
</del><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> template<typename... Params>
</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 = [
+ "",
+ "0",
+ "1",
+ "a",
+ "aa",
+]
+
+let operators = ["<", "<=", ">", ">=", "==", "!=", "===", "!=="];
+
+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("'" + left + "'" + operator + "'" + right + "'");
+ eval(`
+ for (let i = 0; i < 1e3; ++i) {
+ let stringIdentResult = compareStringIdent('${left}', '${right}');
+ if (stringIdentResult !== ${expected})
+ throw "Failed compareStringIdent('${left}', '${right}'), got " + stringIdentResult + " expected ${expected}";
+ let resolvedLeftString = makeString('${left}');
+ let resovledRightString = makeString('${right}');
+ let stringStringResult = compareStringString(resolvedLeftString, resovledRightString);
+ if (stringStringResult !== ${expected})
+ throw "Failed compareStringString('${left}', '${right}'), got " + stringStringResult + " expected ${expected}";
+ stringStringResult = compareStringString(makeString('${left}'), makeString('${right}'));
+ if (stringStringResult !== ${expected})
+ throw "Failed compareStringString('${left}', '${right}'), got " + stringStringResult + " expected ${expected}";
+
+ if (compareStringIdentString(makeString('${left}'), '${right}') !== ${expected})
+ throw "Failed compareStringIdentString('${left}', '${right}'), expected was ${expected}";
+ if (compareStringStringIdent('${left}', makeString('${right}')) !== ${expected})
+ throw "Failed compareStringStringIdent('${left}', '${right}'), expected was ${expected}";
+
+ if (('${left}' ${operator} '${right}') !== ${expected})
+ throw "Failed constant folding of ('${left}' ${operator} '${right}'). How do you even fail constant folding?";
+ }
+ `)
+ }
+ }
+}
</ins><span class="cx">\ No newline at end of file
</span></span></pre>
</div>
</div>
</body>
</html>