Title: [151890] branches/dfgFourthTier
Revision
151890
Author
[email protected]
Date
2013-06-23 21:05:45 -0700 (Sun, 23 Jun 2013)

Log Message

fourthTier: DFG should optimize identifier string equality
https://bugs.webkit.org/show_bug.cgi?id=117920

Source/_javascript_Core: 

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):

LayoutTests: 

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.

Modified Paths

Added Paths

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&);
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to