Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (199866 => 199867)
--- trunk/Source/_javascript_Core/ChangeLog 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-04-22 05:08:28 UTC (rev 199867)
@@ -1,3 +1,51 @@
+2016-04-21 Benjamin Poulain <bpoul...@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):
+
2016-04-21 Benjamin Poulain <bpoul...@webkit.org>
[JSC] Commute FDiv-by-constant into FMul-by-reciprocal when it is safe
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (199866 => 199867)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2016-04-22 05:08:28 UTC (rev 199867)
@@ -1314,11 +1314,24 @@
break;
}
- if (node->op() == CompareEq && leftConst.isString() && rightConst.isString()) {
+ if (leftConst.isString() && rightConst.isString()) {
const StringImpl* a = asString(leftConst)->tryGetValueImpl();
const StringImpl* b = asString(rightConst)->tryGetValueImpl();
if (a && b) {
- setConstant(node, jsBoolean(WTF::equal(a, b)));
+ 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));
break;
}
}
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (199866 => 199867)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2016-04-22 05:08:28 UTC (rev 199867)
@@ -1145,6 +1145,11 @@
case CompareLessEq:
case CompareGreater:
case CompareGreaterEq:
+ if (node->isBinaryUseKind(StringUse)) {
+ read(HeapObjectCount);
+ write(HeapObjectCount);
+ return;
+ }
if (!node->isBinaryUseKind(UntypedUse)) {
def(PureValue(node));
return;
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (199866 => 199867)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2016-04-22 05:08:28 UTC (rev 199867)
@@ -468,14 +468,6 @@
node->clearFlags(NodeMustGenerate);
break;
}
- 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;
- }
if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
fixEdge<StringIdentUse>(node->child1());
fixEdge<StringIdentUse>(node->child2());
@@ -488,6 +480,15 @@
node->clearFlags(NodeMustGenerate);
break;
}
+
+ 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;
+ }
if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
fixEdge<ObjectUse>(node->child1());
fixEdge<ObjectUse>(node->child2());
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (199866 => 199867)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2016-04-22 05:08:28 UTC (rev 199867)
@@ -1342,6 +1342,58 @@
return exec->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min());
}
+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));
+}
+
void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set)
{
VM& vm = exec->vm();
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (199866 => 199867)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2016-04-22 05:08:28 UTC (rev 199867)
@@ -146,6 +146,14 @@
char* JIT_OPERATION operationFindSwitchImmTargetForDouble(ExecState*, EncodedJSValue, size_t tableIndex);
char* JIT_OPERATION operationSwitchString(ExecState*, size_t tableIndex, JSString*);
int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState*, size_t tableIndex, JSString*);
+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*);
void JIT_OPERATION operationNotifyWrite(ExecState*, WatchpointSet*);
void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState*) WTF_INTERNAL;
int32_t JIT_OPERATION operationSizeOfVarargs(ExecState*, EncodedJSValue arguments, int32_t firstVarArgOffset);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (199866 => 199867)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2016-04-22 05:08:28 UTC (rev 199867)
@@ -1484,13 +1484,12 @@
else if (node->isBinaryUseKind(Int52RepUse))
compilePeepHoleInt52Branch(node, branchNode, condition);
#endif // USE(JSVALUE64)
- else if (node->isBinaryUseKind(DoubleRepUse))
+ else if (node->isBinaryUseKind(StringUse) || node->isBinaryUseKind(StringIdentUse)) {
+ // Use non-peephole comparison, for now.
+ return false;
+ } else if (node->isBinaryUseKind(DoubleRepUse))
compilePeepHoleDoubleBranch(node, branchNode, doubleCondition);
else if (node->op() == CompareEq) {
- if (node->isBinaryUseKind(StringUse) || node->isBinaryUseKind(StringIdentUse)) {
- // Use non-peephole comparison, for now.
- return false;
- }
if (node->isBinaryUseKind(BooleanUse))
compilePeepHoleBooleanBranch(node, branchNode, condition);
else if (node->isBinaryUseKind(SymbolUse))
@@ -4921,23 +4920,29 @@
compileDoubleCompare(node, doubleCondition);
return false;
}
-
+
+ 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;
+ }
+
if (node->op() == CompareEq) {
- if (node->isBinaryUseKind(StringUse)) {
- compileStringEquality(node);
- return false;
- }
-
if (node->isBinaryUseKind(BooleanUse)) {
compileBooleanCompare(node, condition);
return false;
}
- if (node->isBinaryUseKind(StringIdentUse)) {
- compileStringIdentEquality(node);
- return false;
- }
-
if (node->isBinaryUseKind(SymbolUse)) {
compileSymbolEquality(node);
return false;
@@ -5386,6 +5391,76 @@
unblessedBooleanResult(rightTempGPR, node);
}
+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);
+}
+
void SpeculativeJIT::compileStringZeroLength(Node* node)
{
SpeculateCellOperand str(this, node->child1());
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (199866 => 199867)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2016-04-22 05:08:28 UTC (rev 199867)
@@ -1076,6 +1076,16 @@
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallSetResult(operation, result);
}
+ 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);
+ }
JITCompiler::Call callOperation(C_JITOperation_EJssJssJss operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
{
m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
@@ -2402,6 +2412,8 @@
void compileInt52Compare(Node*, MacroAssembler::RelationalCondition);
void compileBooleanCompare(Node*, MacroAssembler::RelationalCondition);
void compileDoubleCompare(Node*, MacroAssembler::DoubleCondition);
+ void compileStringCompare(Node*, MacroAssembler::RelationalCondition);
+ void compileStringIdentCompare(Node*, MacroAssembler::RelationalCondition);
bool compileStrictEq(Node*);
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (199866 => 199867)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2016-04-22 05:08:28 UTC (rev 199867)
@@ -416,6 +416,10 @@
break;
if (node->isBinaryUseKind(DoubleRepUse))
break;
+ if (node->isBinaryUseKind(StringIdentUse))
+ break;
+ if (node->isBinaryUseKind(StringUse))
+ break;
if (node->isBinaryUseKind(UntypedUse))
break;
return CannotCompile;
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (199866 => 199867)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2016-04-22 05:08:28 UTC (rev 199867)
@@ -4794,6 +4794,8 @@
[&] (LValue left, LValue right) {
return m_out.doubleLessThan(left, right);
},
+ operationCompareStringImplLess,
+ operationCompareStringLess,
operationCompareLess);
}
@@ -4806,6 +4808,8 @@
[&] (LValue left, LValue right) {
return m_out.doubleLessThanOrEqual(left, right);
},
+ operationCompareStringImplLessEq,
+ operationCompareStringLessEq,
operationCompareLessEq);
}
@@ -4818,6 +4822,8 @@
[&] (LValue left, LValue right) {
return m_out.doubleGreaterThan(left, right);
},
+ operationCompareStringImplGreater,
+ operationCompareStringGreater,
operationCompareGreater);
}
@@ -4830,6 +4836,8 @@
[&] (LValue left, LValue right) {
return m_out.doubleGreaterThanOrEqual(left, right);
},
+ operationCompareStringImplGreaterEq,
+ operationCompareStringGreaterEq,
operationCompareGreaterEq);
}
@@ -7531,7 +7539,9 @@
template<typename IntFunctor, typename DoubleFunctor>
void compare(
const IntFunctor& intFunctor, const DoubleFunctor& doubleFunctor,
- S_JITOperation_EJJ helperFunction)
+ C_JITOperation_TT stringIdentFunction,
+ C_JITOperation_B_EJssJss stringFunction,
+ S_JITOperation_EJJ fallbackFunction)
{
if (m_node->isBinaryUseKind(Int32Use)) {
LValue left = lowInt32(m_node->child1());
@@ -7554,9 +7564,29 @@
setBoolean(doubleFunctor(left, right));
return;
}
-
+
+ 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;
+ }
+
if (m_node->isBinaryUseKind(UntypedUse)) {
- nonSpeculativeCompare(intFunctor, helperFunction);
+ nonSpeculativeCompare(intFunctor, fallbackFunction);
return;
}
Modified: trunk/Source/_javascript_Core/ftl/FTLOutput.h (199866 => 199867)
--- trunk/Source/_javascript_Core/ftl/FTLOutput.h 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/ftl/FTLOutput.h 2016-04-22 05:08:28 UTC (rev 199867)
@@ -383,6 +383,14 @@
template<typename... Args>
LValue call(LType type, LValue function, LValue arg1, Args... args) { return m_block->appendNew<B3::CCallValue>(m_proc, type, origin(), function, arg1, args...); }
+ 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...);
+ }
+
template<typename FunctionType>
LValue operation(FunctionType function) { return constIntPtr(bitwise_cast<void*>(function)); }
@@ -470,15 +478,6 @@
private:
OrderMaker<LBasicBlock> m_blockOrder;
-
- 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...);
- }
-
};
template<typename... Params>
Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (199866 => 199867)
--- trunk/Source/_javascript_Core/jit/JITOperations.h 2016-04-22 04:46:53 UTC (rev 199866)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h 2016-04-22 05:08:28 UTC (rev 199867)
@@ -176,6 +176,8 @@
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJscZ)(ExecState*, JSScope*, int32_t);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssSt)(ExecState*, JSString*, Structure*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssJss)(ExecState*, JSString*, JSString*);
+typedef uintptr_t JIT_OPERATION (*C_JITOperation_B_EJssJss)(ExecState*, JSString*, JSString*);
+typedef uintptr_t JIT_OPERATION (*C_JITOperation_TT)(StringImpl*, StringImpl*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EJssJssJss)(ExecState*, JSString*, JSString*, JSString*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EL)(ExecState*, JSLexicalEnvironment*);
typedef JSCell* JIT_OPERATION (*C_JITOperation_EO)(ExecState*, JSObject*);
Added: trunk/Source/_javascript_Core/tests/stress/string-compare.js (0 => 199867)
--- trunk/Source/_javascript_Core/tests/stress/string-compare.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/string-compare.js 2016-04-22 05:08:28 UTC (rev 199867)
@@ -0,0 +1,78 @@
+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?";
+ }
+ `)
+ }
+ }
+}
\ No newline at end of file