Diff
Modified: branches/dfgFourthTier/LayoutTests/ChangeLog (151889 => 151890)
--- branches/dfgFourthTier/LayoutTests/ChangeLog 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/LayoutTests/ChangeLog 2013-06-24 04:05:45 UTC (rev 151890)
@@ -1,5 +1,26 @@
2013-06-23 Filip Pizlo <[email protected]>
+ fourthTier: DFG should optimize identifier string equality
+ https://bugs.webkit.org/show_bug.cgi?id=117920
+
+ Reviewed by Sam Weinig.
+
+ Add a benchmark for string equality where there is a long identifier, and
+ also add a benchmark for non-identifier string equality (since the previous
+ test for string equality was really identifier equality).
+
+ * fast/js/regress/script-tests/string-long-ident-equality.js: Added.
+ (foo):
+ * fast/js/regress/script-tests/string-var-equality.js: Added.
+ (addFoo):
+ (foo):
+ * fast/js/regress/string-long-ident-equality-expected.txt: Added.
+ * fast/js/regress/string-long-ident-equality.html: Added.
+ * fast/js/regress/string-var-equality-expected.txt: Added.
+ * fast/js/regress/string-var-equality.html: Added.
+
+2013-06-23 Filip Pizlo <[email protected]>
+
Merge trunk r147965.
2013-04-08 Filip Pizlo <[email protected]>
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-long-ident-equality.js (0 => 151890)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-long-ident-equality.js (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-long-ident-equality.js 2013-06-24 04:05:45 UTC (rev 151890)
@@ -0,0 +1,16 @@
+var array = [ "agdsagdwd", "bgbgbgbga", "cb3w53bq4", "dwerweeww" ];
+
+function foo(array, s) {
+ for (var i = 0; i < array.length; ++i) {
+ if (array[i] == s)
+ return true;
+ }
+ return false;
+}
+
+var result = 0;
+for (var i = 0; i < 1000000; ++i)
+ result += foo(array, "cb3w53bq4");
+
+if (result != 1000000)
+ throw "Bad result: " + result;
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-var-equality.js (0 => 151890)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-var-equality.js (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/script-tests/string-var-equality.js 2013-06-24 04:05:45 UTC (rev 151890)
@@ -0,0 +1,23 @@
+var array = [ "a", "b", "c", "d" ];
+
+function addFoo(x) { return x + "foo"; }
+
+for (var i = 0; i < array.length; ++i)
+ array[i] = addFoo(array[i]);
+
+function foo(array, s) {
+ for (var i = 0; i < array.length; ++i) {
+ if (array[i] == s)
+ return true;
+ }
+ return false;
+}
+
+var dFoo = addFoo("d");
+
+var result = 0;
+for (var i = 0; i < 1000000; ++i)
+ result += foo(array, dFoo);
+
+if (result != 1000000)
+ throw "Bad result: " + result;
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/string-long-ident-equality-expected.txt (0 => 151890)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/string-long-ident-equality-expected.txt (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/string-long-ident-equality-expected.txt 2013-06-24 04:05:45 UTC (rev 151890)
@@ -0,0 +1,10 @@
+JSRegress/string-long-ident-equality
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/string-long-ident-equality.html (0 => 151890)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/string-long-ident-equality.html (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/string-long-ident-equality.html 2013-06-24 04:05:45 UTC (rev 151890)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/string-var-equality-expected.txt (0 => 151890)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/string-var-equality-expected.txt (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/string-var-equality-expected.txt 2013-06-24 04:05:45 UTC (rev 151890)
@@ -0,0 +1,10 @@
+JSRegress/string-var-equality
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: branches/dfgFourthTier/LayoutTests/fast/js/regress/string-var-equality.html (0 => 151890)
--- branches/dfgFourthTier/LayoutTests/fast/js/regress/string-var-equality.html (rev 0)
+++ branches/dfgFourthTier/LayoutTests/fast/js/regress/string-var-equality.html 2013-06-24 04:05:45 UTC (rev 151890)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>
Modified: branches/dfgFourthTier/Source/_javascript_Core/ChangeLog (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/ChangeLog 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/ChangeLog 2013-06-24 04:05:45 UTC (rev 151890)
@@ -1,5 +1,59 @@
2013-06-23 Filip Pizlo <[email protected]>
+ fourthTier: DFG should optimize identifier string equality
+ https://bugs.webkit.org/show_bug.cgi?id=117920
+
+ Reviewed by Sam Weinig.
+
+ This is a 20% speed-up for string equality comparisons when both strings are
+ identifiers.
+
+ This is important for two reasons:
+
+ 1) Using strings as enumerations is an idiom. A great example is typeof. It
+ would be great if this performed better.
+
+ 2) When I implement switch_string in the DFG, it would be great to optimize
+ the case where the switched-on value is an identifier. That would involve
+ a simple binary switch rather than a more complicated trie-switch over
+ characters.
+
+ * bytecode/SpeculatedType.cpp:
+ (JSC::dumpSpeculation):
+ (JSC::speculationToAbbreviatedString):
+ (JSC::speculationFromCell):
+ * bytecode/SpeculatedType.h:
+ (JSC):
+ (JSC::isStringIdentSpeculation):
+ (JSC::isStringSpeculation):
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::executeEffects):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::shouldSpeculateStringIdent):
+ (Node):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
+ (JSC::DFG::SpeculativeJIT::compare):
+ (JSC::DFG::SpeculativeJIT::compileStrictEq):
+ (JSC::DFG::SpeculativeJIT::compileStringEquality):
+ (JSC::DFG::SpeculativeJIT::compileStringIdentEquality):
+ (DFG):
+ (JSC::DFG::SpeculativeJIT::speculateString):
+ (JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage):
+ (JSC::DFG::SpeculativeJIT::speculateStringIdent):
+ (JSC::DFG::SpeculativeJIT::speculate):
+ * dfg/DFGSpeculativeJIT.h:
+ (SpeculativeJIT):
+ * dfg/DFGUseKind.cpp:
+ (WTF::printInternal):
+ * dfg/DFGUseKind.h:
+ (JSC::DFG::typeFilterFor):
+ (JSC::DFG::isCell):
+
+2013-06-23 Filip Pizlo <[email protected]>
+
Merge trunk r147965.
2013-04-08 Filip Pizlo <[email protected]>
Modified: branches/dfgFourthTier/Source/_javascript_Core/bytecode/SpeculatedType.cpp (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/bytecode/SpeculatedType.cpp 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/bytecode/SpeculatedType.cpp 2013-06-24 04:05:45 UTC (rev 151890)
@@ -138,10 +138,19 @@
isTop = false;
}
- if (value & SpecString)
+ if ((value & SpecString) == SpecString)
myOut.print("String");
- else
- isTop = false;
+ else {
+ if (value & SpecStringIdent)
+ myOut.print("Stringident");
+ else
+ isTop = false;
+
+ if (value & SpecStringVar)
+ myOut.print("Stringvar");
+ else
+ isTop = false;
+ }
}
if (value & SpecInt32)
@@ -149,16 +158,20 @@
else
isTop = false;
- if (value & SpecDoubleReal)
- myOut.print("Doublereal");
- else
- isTop = false;
+ if ((value & SpecDouble) == SpecDouble)
+ myOut.print("Double");
+ else {
+ if (value & SpecDoubleReal)
+ myOut.print("Doublereal");
+ else
+ isTop = false;
+
+ if (value & SpecDoubleNaN)
+ myOut.print("Doublenan");
+ else
+ isTop = false;
+ }
- if (value & SpecDoubleNaN)
- myOut.print("Doublenan");
- else
- isTop = false;
-
if (value & SpecBoolean)
myOut.print("Bool");
else
@@ -186,6 +199,8 @@
return "<Final>";
if (isArraySpeculation(prediction))
return "<Array>";
+ if (isStringIdentSpeculation(prediction))
+ return "<StringIdent>";
if (isStringSpeculation(prediction))
return "<String>";
if (isFunctionSpeculation(prediction))
@@ -291,6 +306,13 @@
SpeculatedType speculationFromCell(JSCell* cell)
{
+ if (JSString* string = jsDynamicCast<JSString*>(cell)) {
+ if (const StringImpl* impl = string->tryGetValueImpl()) {
+ if (impl->isIdentifier())
+ return SpecStringIdent;
+ }
+ return SpecStringVar;
+ }
return speculationFromStructure(cell->structure());
}
Modified: branches/dfgFourthTier/Source/_javascript_Core/bytecode/SpeculatedType.h (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/bytecode/SpeculatedType.h 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/bytecode/SpeculatedType.h 2013-06-24 04:05:45 UTC (rev 151890)
@@ -53,9 +53,11 @@
static const SpeculatedType SpecStringObject = 0x00004000; // It's definitely a StringObject.
static const SpeculatedType SpecObjectOther = 0x00008000; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
static const SpeculatedType SpecObject = 0x0000ffff; // Bitmask used for testing for any kind of object prediction.
-static const SpeculatedType SpecString = 0x00010000; // It's definitely a JSString.
-static const SpeculatedType SpecCellOther = 0x00020000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString.
-static const SpeculatedType SpecCell = 0x0003ffff; // It's definitely a JSCell.
+static const SpeculatedType SpecStringIdent = 0x00010000; // It's definitely a JSString, and it's an identifier.
+static const SpeculatedType SpecStringVar = 0x00020000; // It's definitely a JSString, and it's not an identifier.
+static const SpeculatedType SpecString = 0x00030000; // It's definitely a JSString.
+static const SpeculatedType SpecCellOther = 0x00040000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString.
+static const SpeculatedType SpecCell = 0x0007ffff; // It's definitely a JSCell.
static const SpeculatedType SpecInt32 = 0x00800000; // It's definitely an Int32.
static const SpeculatedType SpecDoubleReal = 0x01000000; // It's definitely a non-NaN double.
static const SpeculatedType SpecDoubleNaN = 0x02000000; // It's definitely a NaN.
@@ -107,9 +109,14 @@
return !!value && (value & FixedIndexedStorageMask) == value;
}
+inline bool isStringIdentSpeculation(SpeculatedType value)
+{
+ return value == SpecStringIdent;
+}
+
inline bool isStringSpeculation(SpeculatedType value)
{
- return value == SpecString;
+ return !!value && (value & SpecString) == value;
}
inline bool isArraySpeculation(SpeculatedType value)
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGAbstractState.cpp (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2013-06-24 04:05:45 UTC (rev 151890)
@@ -796,30 +796,40 @@
JSValue leftConst = forNode(node->child1()).value();
JSValue rightConst = forNode(node->child2()).value();
- if (leftConst && rightConst && leftConst.isNumber() && rightConst.isNumber()) {
- double a = leftConst.asNumber();
- double b = rightConst.asNumber();
- switch (node->op()) {
- case CompareLess:
- constantWasSet = trySetConstant(node, jsBoolean(a < b));
- break;
- case CompareLessEq:
- constantWasSet = trySetConstant(node, jsBoolean(a <= b));
- break;
- case CompareGreater:
- constantWasSet = trySetConstant(node, jsBoolean(a > b));
- break;
- case CompareGreaterEq:
- constantWasSet = trySetConstant(node, jsBoolean(a >= b));
- break;
- case CompareEq:
- constantWasSet = trySetConstant(node, jsBoolean(a == b));
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- constantWasSet = false;
- break;
+ if (leftConst && rightConst) {
+ if (leftConst.isNumber() && rightConst.isNumber()) {
+ double a = leftConst.asNumber();
+ double b = rightConst.asNumber();
+ switch (node->op()) {
+ case CompareLess:
+ constantWasSet = trySetConstant(node, jsBoolean(a < b));
+ break;
+ case CompareLessEq:
+ constantWasSet = trySetConstant(node, jsBoolean(a <= b));
+ break;
+ case CompareGreater:
+ constantWasSet = trySetConstant(node, jsBoolean(a > b));
+ break;
+ case CompareGreaterEq:
+ constantWasSet = trySetConstant(node, jsBoolean(a >= b));
+ break;
+ case CompareEq:
+ constantWasSet = trySetConstant(node, jsBoolean(a == b));
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ constantWasSet = false;
+ break;
+ }
}
+
+ if (!constantWasSet && node->op() == CompareEq
+ && leftConst.isString() && rightConst.isString()) {
+ const StringImpl* a = asString(leftConst)->tryGetValueImpl();
+ const StringImpl* b = asString(rightConst)->tryGetValueImpl();
+ if (a && b)
+ constantWasSet = trySetConstant(node, jsBoolean(WTF::equal(a, b)));
+ }
}
if (!constantWasSet && (node->op() == CompareEqConstant || node->op() == CompareEq)) {
@@ -853,10 +863,20 @@
Node* rightNode = node->child2().node();
JSValue left = forNode(leftNode).value();
JSValue right = forNode(rightNode).value();
- if (left && right && left.isNumber() && right.isNumber()
- && trySetConstant(node, jsBoolean(left.asNumber() == right.asNumber()))) {
- m_foundConstants = true;
- break;
+ if (left && right) {
+ if (left.isNumber() && right.isNumber()
+ && trySetConstant(node, jsBoolean(left.asNumber() == right.asNumber()))) {
+ m_foundConstants = true;
+ break;
+ }
+ if (left.isString() && right.isString()) {
+ const StringImpl* a = asString(left)->tryGetValueImpl();
+ const StringImpl* b = asString(right)->tryGetValueImpl();
+ if (a && b && trySetConstant(node, jsBoolean(WTF::equal(a, b)))) {
+ m_foundConstants = true;
+ break;
+ }
+ }
}
forNode(node).setType(SpecBoolean);
node->setCanExit(true); // This is overly conservative.
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2013-06-24 04:05:45 UTC (rev 151890)
@@ -304,6 +304,11 @@
}
if (node->op() != CompareEq)
break;
+ if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
+ setUseKindAndUnboxIfProfitable<StringIdentUse>(node->child1());
+ setUseKindAndUnboxIfProfitable<StringIdentUse>(node->child2());
+ break;
+ }
if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
setUseKindAndUnboxIfProfitable<StringUse>(node->child2());
@@ -342,6 +347,11 @@
fixDoubleEdge<NumberUse>(node->child2());
break;
}
+ if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
+ setUseKindAndUnboxIfProfitable<StringIdentUse>(node->child1());
+ setUseKindAndUnboxIfProfitable<StringIdentUse>(node->child2());
+ break;
+ }
if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && GPRInfo::numberOfRegisters >= 7) {
setUseKindAndUnboxIfProfitable<StringUse>(node->child1());
setUseKindAndUnboxIfProfitable<StringUse>(node->child2());
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGNode.h (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGNode.h 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGNode.h 2013-06-24 04:05:45 UTC (rev 151890)
@@ -1192,6 +1192,11 @@
return isBooleanSpeculation(prediction());
}
+ bool shouldSpeculateStringIdent()
+ {
+ return isStringIdentSpeculation(prediction());
+ }
+
bool shouldSpeculateString()
{
return isStringSpeculation(prediction());
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2013-06-24 04:05:45 UTC (rev 151890)
@@ -1514,7 +1514,7 @@
else if (node->isBinaryUseKind(NumberUse))
compilePeepHoleDoubleBranch(node, branchNode, doubleCondition);
else if (node->op() == CompareEq) {
- if (node->isBinaryUseKind(StringUse)) {
+ if (node->isBinaryUseKind(StringUse) || node->isBinaryUseKind(StringIdentUse)) {
// Use non-peephole comparison, for now.
return false;
}
@@ -3627,6 +3627,11 @@
return false;
}
+ if (node->isBinaryUseKind(StringIdentUse)) {
+ compileStringIdentEquality(node);
+ return false;
+ }
+
if (node->isBinaryUseKind(ObjectUse)) {
compileObjectEquality(node);
return false;
@@ -3761,6 +3766,11 @@
return false;
}
+ case StringIdentUse: {
+ compileStringIdentEquality(node);
+ return false;
+ }
+
case ObjectUse: {
unsigned branchIndexInBlock = detectPeepHoleBranch();
if (branchIndexInBlock != UINT_MAX) {
@@ -3808,21 +3818,13 @@
JITCompiler::JumpList falseCase;
JITCompiler::JumpList slowCase;
- DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(leftGPR), node->child1(), SpecString, m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(leftGPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ speculateString(node->child1(), leftGPR);
// It's safe to branch around the type check below, since proving that the values are
// equal does indeed prove that the right value is a string.
trueCase.append(m_jit.branchPtr(MacroAssembler::Equal, leftGPR, rightGPR));
- DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(rightGPR), node->child2(), SpecString, m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(rightGPR, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ speculateString(node->child2(), rightGPR);
m_jit.load32(MacroAssembler::Address(leftGPR, JSString::offsetOfLength()), lengthGPR);
@@ -3891,6 +3893,37 @@
#endif
}
+void SpeculativeJIT::compileStringIdentEquality(Node* node)
+{
+ SpeculateCellOperand left(this, node->child1());
+ SpeculateCellOperand right(this, node->child2());
+ GPRTemporary leftTemp(this);
+ GPRTemporary rightTemp(this);
+
+ GPRReg leftGPR = left.gpr();
+ GPRReg rightGPR = right.gpr();
+ GPRReg leftTempGPR = leftTemp.gpr();
+ GPRReg rightTempGPR = rightTemp.gpr();
+
+ JITCompiler::JumpList trueCase;
+ JITCompiler::JumpList falseCase;
+
+ speculateString(node->child1(), leftGPR);
+ speculateString(node->child2(), rightGPR);
+
+ speculateStringIdentAndLoadStorage(node->child1(), leftGPR, leftTempGPR);
+ speculateStringIdentAndLoadStorage(node->child2(), rightGPR, rightTempGPR);
+
+ m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, leftTempGPR);
+
+#if USE(JSVALUE64)
+ m_jit.or32(TrustedImm32(ValueFalse), leftTempGPR);
+ jsValueResult(leftTempGPR, node, DataFormatJSBoolean);
+#else
+ booleanResult(leftTempGPR, node);
+#endif
+}
+
void SpeculativeJIT::compileGetIndexedPropertyStorage(Node* node)
{
SpeculateCellOperand base(this, node->child1());
@@ -4453,18 +4486,61 @@
#endif
}
+void SpeculativeJIT::speculateString(Edge edge, GPRReg cell)
+{
+ DFG_TYPE_CHECK(
+ JSValueSource::unboxedCell(cell), edge, SpecString, m_jit.branchPtr(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(cell, JSCell::structureOffset()),
+ MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+}
+
+void SpeculativeJIT::speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage)
+{
+ m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), storage);
+
+ if (!needsTypeCheck(edge, SpecStringIdent))
+ return;
+
+ speculationCheck(
+ BadType, JSValueSource::unboxedCell(string), edge,
+ m_jit.branchTestPtr(MacroAssembler::Zero, storage));
+ speculationCheck(
+ BadType, JSValueSource::unboxedCell(string), edge, m_jit.branchTest32(
+ MacroAssembler::Zero,
+ MacroAssembler::Address(storage, StringImpl::flagsOffset()),
+ MacroAssembler::TrustedImm32(StringImpl::flagIsIdentifier())));
+
+ m_state.filter(edge, SpecStringIdent);
+}
+
+void SpeculativeJIT::speculateStringIdent(Edge edge, GPRReg string)
+{
+ if (!needsTypeCheck(edge, SpecStringIdent))
+ return;
+
+ GPRTemporary temp(this);
+ speculateStringIdentAndLoadStorage(edge, string, temp.gpr());
+}
+
+void SpeculativeJIT::speculateStringIdent(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecStringIdent))
+ return;
+
+ SpeculateCellOperand operand(this, edge);
+ GPRReg gpr = operand.gpr();
+ speculateString(edge, gpr);
+ speculateStringIdent(edge, gpr);
+}
+
void SpeculativeJIT::speculateString(Edge edge)
{
if (!needsTypeCheck(edge, SpecString))
return;
SpeculateCellOperand operand(this, edge);
- GPRReg gpr = operand.gpr();
- DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(gpr), edge, SpecString, m_jit.branchPtr(
- MacroAssembler::NotEqual,
- MacroAssembler::Address(gpr, JSCell::structureOffset()),
- MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get())));
+ speculateString(edge, operand.gpr());
}
void SpeculativeJIT::speculateStringObject(GPRReg gpr)
@@ -4593,6 +4669,9 @@
case ObjectOrOtherUse:
speculateObjectOrOther(edge);
break;
+ case StringIdentUse:
+ speculateStringIdent(edge);
+ break;
case StringUse:
speculateString(edge);
break;
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2013-06-24 04:05:45 UTC (rev 151890)
@@ -1859,6 +1859,7 @@
void compileObjectOrOtherLogicalNot(Edge value);
void compileLogicalNot(Node*);
void compileStringEquality(Node*);
+ void compileStringIdentEquality(Node*);
void emitObjectOrOtherBranch(Edge value, BlockIndex taken, BlockIndex notTaken);
void emitBranch(Node*);
void emitSwitchIntJump(SwitchData*, GPRReg value, GPRReg scratch);
@@ -2046,6 +2047,10 @@
void speculateCell(Edge);
void speculateObject(Edge);
void speculateObjectOrOther(Edge);
+ void speculateString(Edge edge, GPRReg cell);
+ void speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage);
+ void speculateStringIdent(Edge edge, GPRReg string);
+ void speculateStringIdent(Edge);
void speculateString(Edge);
template<typename StructureLocationType>
void speculateStringObjectForStructure(StructureLocationType);
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGUseKind.cpp (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGUseKind.cpp 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGUseKind.cpp 2013-06-24 04:05:45 UTC (rev 151890)
@@ -68,6 +68,9 @@
case ObjectOrOtherUse:
out.print("ObjectOrOther");
break;
+ case StringIdentUse:
+ out.print("StringIdent");
+ break;
case StringUse:
out.print("String");
break;
Modified: branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGUseKind.h (151889 => 151890)
--- branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGUseKind.h 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/_javascript_Core/dfg/DFGUseKind.h 2013-06-24 04:05:45 UTC (rev 151890)
@@ -47,6 +47,7 @@
KnownCellUse,
ObjectUse,
ObjectOrOtherUse,
+ StringIdentUse,
StringUse,
KnownStringUse,
StringObjectUse,
@@ -78,6 +79,8 @@
return SpecObject;
case ObjectOrOtherUse:
return SpecObject | SpecOther;
+ case StringIdentUse:
+ return SpecStringIdent;
case StringUse:
case KnownStringUse:
return SpecString;
@@ -145,6 +148,7 @@
case CellUse:
case KnownCellUse:
case ObjectUse:
+ case StringIdentUse:
case StringUse:
case KnownStringUse:
case StringObjectUse:
Modified: branches/dfgFourthTier/Source/WTF/wtf/text/StringImpl.h (151889 => 151890)
--- branches/dfgFourthTier/Source/WTF/wtf/text/StringImpl.h 2013-06-24 01:41:11 UTC (rev 151889)
+++ branches/dfgFourthTier/Source/WTF/wtf/text/StringImpl.h 2013-06-24 04:05:45 UTC (rev 151890)
@@ -443,6 +443,7 @@
static unsigned flagsOffset() { return OBJECT_OFFSETOF(StringImpl, m_hashAndFlags); }
static unsigned flagIs8Bit() { return s_hashFlag8BitBuffer; }
+ static unsigned flagIsIdentifier() { return s_hashFlagIsIdentifier; }
static unsigned dataOffset() { return OBJECT_OFFSETOF(StringImpl, m_data8); }
static PassRefPtr<StringImpl> createWithTerminatingNullCharacter(const StringImpl&);