[DFG] More ArrayIndexOf fixups for various types
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Jun 2017 02:46:08 +0000 (02:46 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 20 Jun 2017 02:46:08 +0000 (02:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173176

Reviewed by Saam Barati.

JSTests:

* stress/array-indexof-arraystorage.js: Added.
(shouldBe):
(indexOfInt32Other):
(indexOfInt32Cell):
(indexOfInt32Boolean):
(indexOfDoubleOther):
(indexOfDoubleCell):
(indexOfDoubleBoolean):
(indexOfInt32):
(indexOfDouble):
* stress/array-indexof-constant-folding.js: Added.
(shouldBe):
(indexOfInt32Other):
(indexOfInt32Cell):
(indexOfInt32Boolean):
(indexOfDoubleOther):
(indexOfDoubleCell):
(indexOfDoubleBoolean):
* stress/array-indexof-hole-and-other.js: Added.
(shouldBe):
(indexOf):
* stress/array-indexof-other.js: Added.
(shouldBe):
(indexOfInt32):
(indexOfDouble):
(indexOfString):
(indexOfObject):
* stress/array-indexof-symbol.js: Added.
(shouldBe):
(indexOfInt32):
(indexOfDouble):
(indexOfString):
(indexOfObject):

Source/JavaScriptCore:

This patch further expands coverage of ArrayIndexOf optimization in DFG and FTL.

1. We attempt to fold ArrayIndexOf to constant (-1) if we know that its array
never contains the given search value.

2. We support Symbol and Other specialization additionally. Especially, Other is
useful because null/undefined can be used as a sentinel value.

One interesting thing is that Array.prototype.indexOf does not consider holes as
undefineds. Thus,

    var array = [,,,,,,,];
    array.indexOf(undefined); // => -1

This can be trivially achieved in JSC because Empty and Undefined are different values.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupArrayIndexOf):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArrayIndexOf):
(JSC::DFG::SpeculativeJIT::speculateOther):
* dfg/DFGSpeculativeJIT.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileArrayIndexOf):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@218525 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/array-indexof-arraystorage.js [new file with mode: 0644]
JSTests/stress/array-indexof-constant-folding.js [new file with mode: 0644]
JSTests/stress/array-indexof-hole-and-other.js [new file with mode: 0644]
JSTests/stress/array-indexof-other.js [new file with mode: 0644]
JSTests/stress/array-indexof-symbol.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

index 48970b7..94cf9c8 100644 (file)
@@ -1,3 +1,44 @@
+2017-06-13  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG] More ArrayIndexOf fixups for various types
+        https://bugs.webkit.org/show_bug.cgi?id=173176
+
+        Reviewed by Saam Barati.
+
+        * stress/array-indexof-arraystorage.js: Added.
+        (shouldBe):
+        (indexOfInt32Other):
+        (indexOfInt32Cell):
+        (indexOfInt32Boolean):
+        (indexOfDoubleOther):
+        (indexOfDoubleCell):
+        (indexOfDoubleBoolean):
+        (indexOfInt32):
+        (indexOfDouble):
+        * stress/array-indexof-constant-folding.js: Added.
+        (shouldBe):
+        (indexOfInt32Other):
+        (indexOfInt32Cell):
+        (indexOfInt32Boolean):
+        (indexOfDoubleOther):
+        (indexOfDoubleCell):
+        (indexOfDoubleBoolean):
+        * stress/array-indexof-hole-and-other.js: Added.
+        (shouldBe):
+        (indexOf):
+        * stress/array-indexof-other.js: Added.
+        (shouldBe):
+        (indexOfInt32):
+        (indexOfDouble):
+        (indexOfString):
+        (indexOfObject):
+        * stress/array-indexof-symbol.js: Added.
+        (shouldBe):
+        (indexOfInt32):
+        (indexOfDouble):
+        (indexOfString):
+        (indexOfObject):
+
 2017-06-19  Joseph Pecoraro  <pecoraro@apple.com>
 
         test262: Completion values for control flow do not match the spec
diff --git a/JSTests/stress/array-indexof-arraystorage.js b/JSTests/stress/array-indexof-arraystorage.js
new file mode 100644 (file)
index 0000000..0686f04
--- /dev/null
@@ -0,0 +1,85 @@
+// ArrayIndexOf intrinsic does not support ArrayStorage.
+// Thus, if ArrayStorage comes, we should not use that intrinsic.
+
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+(function () {
+    function indexOfInt32Other(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32Other);
+
+    function indexOfInt32Cell(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32Cell);
+
+    function indexOfInt32Boolean(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32Boolean);
+
+    function indexOfDoubleOther(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDoubleOther);
+
+    function indexOfDoubleCell(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDoubleCell);
+
+    function indexOfDoubleBoolean(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDoubleBoolean);
+
+    function indexOfInt32(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32);
+
+    function indexOfDouble(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDouble);
+
+    var key = {};
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+    var doubleArray = [0, 1, 2, 3, 4.2, 5, 6, 7, 8, 9, 10.5, 11, 12];
+
+    ensureArrayStorage(int32Array);
+    ensureArrayStorage(doubleArray);
+
+    for (var i = 0; i < 1e4; ++i) {
+        shouldBe(indexOfInt32Other(int32Array, null, 0), -1);
+        shouldBe(indexOfInt32Other(int32Array, undefined, 0), -1);
+        shouldBe(indexOfInt32Cell(int32Array, key, 0), -1);
+        shouldBe(indexOfInt32Cell(int32Array, Symbol("Cocoa"), 0), -1);
+        shouldBe(indexOfInt32Cell(int32Array, "Cocoa", 0), -1);
+        shouldBe(indexOfInt32Boolean(int32Array, true, 0), -1);
+        shouldBe(indexOfInt32Boolean(int32Array, false, 0), -1);
+        shouldBe(indexOfInt32(int32Array, 12, 0), 12);
+
+        shouldBe(indexOfDoubleOther(doubleArray, null, 0), -1);
+        shouldBe(indexOfDoubleOther(doubleArray, undefined, 0), -1);
+        shouldBe(indexOfDoubleCell(doubleArray, key, 0), -1);
+        shouldBe(indexOfDoubleCell(doubleArray, Symbol("Cocoa"), 0), -1);
+        shouldBe(indexOfDoubleCell(doubleArray, "Cocoa", 0), -1);
+        shouldBe(indexOfDoubleBoolean(doubleArray, true, 0), -1);
+        shouldBe(indexOfDoubleBoolean(doubleArray, false, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, 12, 0), 12);
+    }
+}());
diff --git a/JSTests/stress/array-indexof-constant-folding.js b/JSTests/stress/array-indexof-constant-folding.js
new file mode 100644 (file)
index 0000000..527880e
--- /dev/null
@@ -0,0 +1,72 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+(function () {
+    function indexOfInt32Other(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32Other);
+
+    function indexOfInt32Cell(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32Cell);
+
+    function indexOfInt32Boolean(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32Boolean);
+
+    function indexOfDoubleOther(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDoubleOther);
+
+    function indexOfDoubleCell(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDoubleCell);
+
+    function indexOfDoubleBoolean(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDoubleBoolean);
+
+    var key = {};
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+    var doubleArray = [0, 1, 2, 3, 4.2, 5, 6, 7, 8, 9, 10.5, 11, 12];
+
+    for (var i = 0; i < 1e4; ++i) {
+        shouldBe(indexOfInt32Other(int32Array, null, 0), -1);
+        shouldBe(indexOfInt32Other(int32Array, undefined, 0), -1);
+        shouldBe(indexOfInt32Cell(int32Array, key, 0), -1);
+        shouldBe(indexOfInt32Cell(int32Array, Symbol("Cocoa"), 0), -1);
+        shouldBe(indexOfInt32Cell(int32Array, "Cocoa", 0), -1);
+        shouldBe(indexOfInt32Boolean(int32Array, true, 0), -1);
+        shouldBe(indexOfInt32Boolean(int32Array, false, 0), -1);
+
+        shouldBe(indexOfDoubleOther(doubleArray, null, 0), -1);
+        shouldBe(indexOfDoubleOther(doubleArray, undefined, 0), -1);
+        shouldBe(indexOfDoubleCell(doubleArray, key, 0), -1);
+        shouldBe(indexOfDoubleCell(doubleArray, Symbol("Cocoa"), 0), -1);
+        shouldBe(indexOfDoubleCell(doubleArray, "Cocoa", 0), -1);
+        shouldBe(indexOfDoubleBoolean(doubleArray, true, 0), -1);
+        shouldBe(indexOfDoubleBoolean(doubleArray, false, 0), -1);
+    }
+
+    shouldBe(indexOfInt32Other(int32Array, 1, 0), 1);
+    shouldBe(indexOfInt32Cell(int32Array, 1, 0), 1);
+    shouldBe(indexOfInt32Boolean(int32Array, 1, 0), 1);
+    shouldBe(indexOfDoubleOther(doubleArray, 1, 0), 1);
+    shouldBe(indexOfDoubleCell(doubleArray, 1, 0), 1);
+    shouldBe(indexOfDoubleBoolean(doubleArray, 1, 0), 1);
+}());
diff --git a/JSTests/stress/array-indexof-hole-and-other.js b/JSTests/stress/array-indexof-hole-and-other.js
new file mode 100644 (file)
index 0000000..cb87f12
--- /dev/null
@@ -0,0 +1,38 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+(function () {
+    function indexOf(array, value)
+    {
+        return array.indexOf(value);
+    }
+    noInline(indexOf);
+
+    var array = new Array(100);
+
+    for (var i = 0; i < 1e4; ++i) {
+        shouldBe(indexOf(array, undefined), -1);
+        shouldBe(indexOf(array, null), -1);
+    }
+}());
+
+(function () {
+    function indexOf(array, value)
+    {
+        return array.indexOf(value);
+    }
+    noInline(indexOf);
+
+    var array = new Array(100);
+    array.push({});
+
+    for (var i = 0; i < 1e4; ++i) {
+        shouldBe(indexOf(array, undefined), -1);
+        shouldBe(indexOf(array, null), -1);
+    }
+}());
+
+
diff --git a/JSTests/stress/array-indexof-other.js b/JSTests/stress/array-indexof-other.js
new file mode 100644 (file)
index 0000000..422362a
--- /dev/null
@@ -0,0 +1,50 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+(function () {
+    function indexOfInt32(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32);
+
+    function indexOfDouble(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDouble);
+
+    function indexOfString(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfString);
+
+    function indexOfObject(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfObject);
+
+    var key = {};
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+    var doubleArray = [0, 1, 2, 3, 4.2, 5, 6, 7, 8, 9, 10.5, 11, 12];
+    var stringArray = [ "cocoa", "cappuccino", "matcha", "rize", "kilimanjaro" ];
+    var objectArray = [ {}, {}, {}, {}, {}, key, {}, {}, {}, null, undefined ];
+
+    for (var i = 0; i < 1e5; ++i) {
+        shouldBe(indexOfInt32(int32Array, null, 0), -1);
+        shouldBe(indexOfInt32(int32Array, undefined, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, null, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, undefined, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, null, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, undefined, 0), -1);
+        shouldBe(indexOfString(stringArray, null, 0), -1);
+        shouldBe(indexOfString(stringArray, undefined, 0), -1);
+        shouldBe(indexOfObject(objectArray, null, 0), 9);
+        shouldBe(indexOfObject(objectArray, undefined, 0), 10);
+    }
+}());
diff --git a/JSTests/stress/array-indexof-symbol.js b/JSTests/stress/array-indexof-symbol.js
new file mode 100644 (file)
index 0000000..9cc2cac
--- /dev/null
@@ -0,0 +1,52 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+(function () {
+    function indexOfInt32(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfInt32);
+
+    function indexOfDouble(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfDouble);
+
+    function indexOfString(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfString);
+
+    function indexOfObject(array, value, index)
+    {
+        return array.indexOf(value, index);
+    }
+    noInline(indexOfObject);
+
+    var key = {};
+    var cocoa = Symbol("Cocoa");
+    var cappuccino = Symbol("Cappuccino");
+    var int32Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+    var doubleArray = [0, 1, 2, 3, 4.2, 5, 6, 7, 8, 9, 10.5, 11, 12];
+    var stringArray = [ "cocoa", "cappuccino", "matcha", "rize", "kilimanjaro" ];
+    var objectArray = [ {}, {}, {}, {}, {}, key, {}, {}, {}, cocoa, cappuccino ];
+
+    for (var i = 0; i < 1e5; ++i) {
+        shouldBe(indexOfInt32(int32Array, null, 0), -1);
+        shouldBe(indexOfInt32(int32Array, undefined, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, null, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, undefined, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, null, 0), -1);
+        shouldBe(indexOfDouble(doubleArray, undefined, 0), -1);
+        shouldBe(indexOfString(stringArray, null, 0), -1);
+        shouldBe(indexOfString(stringArray, undefined, 0), -1);
+        shouldBe(indexOfObject(objectArray, cocoa, 0), 9);
+        shouldBe(indexOfObject(objectArray, cappuccino, 0), 10);
+    }
+}());
index ce1e57d..156627d 100644 (file)
@@ -1,3 +1,36 @@
+2017-06-13  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [DFG] More ArrayIndexOf fixups for various types
+        https://bugs.webkit.org/show_bug.cgi?id=173176
+
+        Reviewed by Saam Barati.
+
+        This patch further expands coverage of ArrayIndexOf optimization in DFG and FTL.
+
+        1. We attempt to fold ArrayIndexOf to constant (-1) if we know that its array
+        never contains the given search value.
+
+        2. We support Symbol and Other specialization additionally. Especially, Other is
+        useful because null/undefined can be used as a sentinel value.
+
+        One interesting thing is that Array.prototype.indexOf does not consider holes as
+        undefineds. Thus,
+
+            var array = [,,,,,,,];
+            array.indexOf(undefined); // => -1
+
+        This can be trivially achieved in JSC because Empty and Undefined are different values.
+
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixupArrayIndexOf):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArrayIndexOf):
+        (JSC::DFG::SpeculativeJIT::speculateOther):
+        * dfg/DFGSpeculativeJIT.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileArrayIndexOf):
+
 2017-06-19  Caio Lima  <ticaiolima@gmail.com>
 
         [ARMv6][DFG] ARM MacroAssembler is always emitting cmn when immediate is 0
index 89e583d..b99b3c0 100644 (file)
@@ -1023,44 +1023,9 @@ private:
             break;
         }
 
-        case ArrayIndexOf: {
-            Edge& array = m_graph.varArgChild(node, 0);
-            Edge& storage = m_graph.varArgChild(node, node->numChildren() == 3 ? 2 : 3);
-            blessArrayOperation(array, Edge(), storage);
-            ASSERT_WITH_MESSAGE(storage.node(), "blessArrayOperation for ArrayIndexOf must set Butterfly for storage edge.");
-
-            fixEdge<KnownCellUse>(array);
-            if (node->numChildren() == 4)
-                fixEdge<Int32Use>(m_graph.varArgChild(node, 2));
-
-            Edge& searchElement = m_graph.varArgChild(node, 1);
-            // FIXME: We have a chance to constant-fold this node to -1 by
-            // emitting non number edge filters.
-            // https://bugs.webkit.org/show_bug.cgi?id=173176
-            switch (node->arrayMode().type()) {
-            case Array::Double: {
-                if (searchElement->shouldSpeculateNumber())
-                    fixEdge<DoubleRepUse>(searchElement);
-                break;
-            }
-            case Array::Int32: {
-                if (searchElement->shouldSpeculateInt32())
-                    fixEdge<Int32Use>(searchElement);
-                break;
-            }
-            case Array::Contiguous: {
-                if (searchElement->shouldSpeculateString())
-                    fixEdge<StringUse>(searchElement);
-                else if (searchElement->shouldSpeculateObject())
-                    fixEdge<ObjectUse>(searchElement);
-                break;
-            }
-            default:
-                RELEASE_ASSERT_NOT_REACHED();
-                break;
-            }
+        case ArrayIndexOf:
+            fixupArrayIndexOf(node);
             break;
-        }
             
         case RegExpExec:
         case RegExpTest: {
@@ -3051,6 +3016,77 @@ private:
         fixup(node->child3(), 1);
     }
 
+    void fixupArrayIndexOf(Node* node)
+    {
+        Edge& array = m_graph.varArgChild(node, 0);
+        Edge& storage = m_graph.varArgChild(node, node->numChildren() == 3 ? 2 : 3);
+        blessArrayOperation(array, Edge(), storage);
+        ASSERT_WITH_MESSAGE(storage.node(), "blessArrayOperation for ArrayIndexOf must set Butterfly for storage edge.");
+
+        Edge& searchElement = m_graph.varArgChild(node, 1);
+
+        // Constant folding.
+        switch (node->arrayMode().type()) {
+        case Array::Double:
+        case Array::Int32: {
+            if (searchElement->shouldSpeculateCell()) {
+                m_insertionSet.insertNode(m_indexInBlock, SpecNone, Check, node->origin, Edge(searchElement.node(), CellUse));
+                m_graph.convertToConstant(node, jsNumber(-1));
+                observeUseKindOnNode<CellUse>(searchElement.node());
+                return;
+            }
+
+            if (searchElement->shouldSpeculateOther()) {
+                m_insertionSet.insertNode(m_indexInBlock, SpecNone, Check, node->origin, Edge(searchElement.node(), OtherUse));
+                m_graph.convertToConstant(node, jsNumber(-1));
+                observeUseKindOnNode<OtherUse>(searchElement.node());
+                return;
+            }
+
+            if (searchElement->shouldSpeculateBoolean()) {
+                m_insertionSet.insertNode(m_indexInBlock, SpecNone, Check, node->origin, Edge(searchElement.node(), BooleanUse));
+                m_graph.convertToConstant(node, jsNumber(-1));
+                observeUseKindOnNode<BooleanUse>(searchElement.node());
+                return;
+            }
+            break;
+        }
+        default:
+            break;
+        }
+
+        fixEdge<KnownCellUse>(array);
+        if (node->numChildren() == 4)
+            fixEdge<Int32Use>(m_graph.varArgChild(node, 2));
+
+        switch (node->arrayMode().type()) {
+        case Array::Double: {
+            if (searchElement->shouldSpeculateNumber())
+                fixEdge<DoubleRepUse>(searchElement);
+            return;
+        }
+        case Array::Int32: {
+            if (searchElement->shouldSpeculateInt32())
+                fixEdge<Int32Use>(searchElement);
+            return;
+        }
+        case Array::Contiguous: {
+            if (searchElement->shouldSpeculateString())
+                fixEdge<StringUse>(searchElement);
+            else if (searchElement->shouldSpeculateSymbol())
+                fixEdge<SymbolUse>(searchElement);
+            else if (searchElement->shouldSpeculateOther())
+                fixEdge<OtherUse>(searchElement);
+            else if (searchElement->shouldSpeculateObject())
+                fixEdge<ObjectUse>(searchElement);
+            return;
+        }
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return;
+        }
+    }
+
     void fixupChecksInBlock(BasicBlock* block)
     {
         if (!block)
index ffaab13..02c77a4 100644 (file)
@@ -7479,7 +7479,9 @@ void SpeculativeJIT::compileArrayIndexOf(Node* node)
     Edge& searchElementEdge = m_jit.graph().varArgChild(node, 1);
     switch (searchElementEdge.useKind()) {
     case Int32Use:
-    case ObjectUse: {
+    case ObjectUse:
+    case SymbolUse:
+    case OtherUse: {
         auto emitLoop = [&] (auto emitCompare) {
 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
             m_jit.clearRegisterAllocationOffsets();
@@ -7502,11 +7504,6 @@ void SpeculativeJIT::compileArrayIndexOf(Node* node)
             int32Result(indexGPR, node);
         };
 
-#if USE(JSVALUE32_64)
-        GPRTemporary temp(this);
-        GPRReg tempGPR = temp.gpr();
-#endif
-
         if (searchElementEdge.useKind() == Int32Use) {
             ASSERT(node->arrayMode().type() == Array::Int32);
 #if USE(JSVALUE64)
@@ -7517,6 +7514,9 @@ void SpeculativeJIT::compileArrayIndexOf(Node* node)
 #else
             SpeculateInt32Operand searchElement(this, searchElementEdge);
             GPRReg searchElementGPR = searchElement.gpr();
+
+            GPRTemporary temp(this);
+            GPRReg tempGPR = temp.gpr();
 #endif
             emitLoop([&] () {
 #if USE(JSVALUE64)
@@ -7529,25 +7529,58 @@ void SpeculativeJIT::compileArrayIndexOf(Node* node)
 #endif
                 return found;
             });
-        } else {
+            return;
+        }
+
+        if (searchElementEdge.useKind() == OtherUse) {
             ASSERT(node->arrayMode().type() == Array::Contiguous);
-            SpeculateCellOperand searchElement(this, searchElementEdge);
-            GPRReg searchElementGPR = searchElement.gpr();
-            speculateObject(searchElementEdge, searchElementGPR);
+            JSValueOperand searchElement(this, searchElementEdge, ManualOperandSpeculation);
+            GPRTemporary temp(this);
+
+            JSValueRegs searchElementRegs = searchElement.jsValueRegs();
+            GPRReg tempGPR = temp.gpr();
+            speculateOther(searchElementEdge, searchElementRegs, tempGPR);
 
             emitLoop([&] () {
 #if USE(JSVALUE64)
-                auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
+                auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementRegs.payloadGPR());
 #else
-                auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::CellTag));
-                m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
-                auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
-                skip.link(&m_jit);
+                m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), tempGPR);
+                auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementRegs.tagGPR());
 #endif
                 return found;
             });
+            return;
         }
-        break;
+
+        ASSERT(node->arrayMode().type() == Array::Contiguous);
+        SpeculateCellOperand searchElement(this, searchElementEdge);
+        GPRReg searchElementGPR = searchElement.gpr();
+
+        if (searchElementEdge.useKind() == ObjectUse)
+            speculateObject(searchElementEdge, searchElementGPR);
+        else {
+            ASSERT(searchElementEdge.useKind() == SymbolUse);
+            speculateSymbol(searchElementEdge, searchElementGPR);
+        }
+
+#if USE(JSVALUE32_64)
+        GPRTemporary temp(this);
+        GPRReg tempGPR = temp.gpr();
+#endif
+
+        emitLoop([&] () {
+#if USE(JSVALUE64)
+            auto found = m_jit.branch64(CCallHelpers::Equal, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), searchElementGPR);
+#else
+            auto skip = m_jit.branch32(CCallHelpers::NotEqual, MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, TagOffset), TrustedImm32(JSValue::CellTag));
+            m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, PayloadOffset), tempGPR);
+            auto found = m_jit.branch32(CCallHelpers::Equal, tempGPR, searchElementGPR);
+            skip.link(&m_jit);
+#endif
+            return found;
+        });
+        return;
     }
 
     case DoubleRepUse: {
@@ -7576,7 +7609,7 @@ void SpeculativeJIT::compileArrayIndexOf(Node* node)
         m_jit.move(TrustedImm32(-1), indexGPR);
         found.link(&m_jit);
         int32Result(indexGPR, node);
-        break;
+        return;
     }
 
     case StringUse: {
@@ -7593,7 +7626,7 @@ void SpeculativeJIT::compileArrayIndexOf(Node* node)
         m_jit.exceptionCheck();
 
         int32Result(lengthGPR, node);
-        break;
+        return;
     }
 
     case UntypedUse: {
@@ -7617,12 +7650,12 @@ void SpeculativeJIT::compileArrayIndexOf(Node* node)
         m_jit.exceptionCheck();
 
         int32Result(lengthGPR, node);
-        break;
+        return;
     }
 
     default:
         RELEASE_ASSERT_NOT_REACHED();
-        break;
+        return;
     }
 }
 
@@ -8915,17 +8948,28 @@ void SpeculativeJIT::speculateNotCell(Edge edge)
     speculateNotCell(edge, operand.jsValueRegs());
 }
 
+void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs, GPRReg tempGPR)
+{
+    DFG_TYPE_CHECK(regs, edge, SpecOther, m_jit.branchIfNotOther(regs, tempGPR));
+}
+
+void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs)
+{
+    if (!needsTypeCheck(edge, SpecOther))
+        return;
+
+    GPRTemporary temp(this);
+    GPRReg tempGPR = temp.gpr();
+    speculateOther(edge, regs, tempGPR);
+}
+
 void SpeculativeJIT::speculateOther(Edge edge)
 {
     if (!needsTypeCheck(edge, SpecOther))
         return;
     
     JSValueOperand operand(this, edge, ManualOperandSpeculation);
-    GPRTemporary temp(this);
-    GPRReg tempGPR = temp.gpr();
-    typeCheck(
-        operand.jsValueRegs(), edge, SpecOther,
-        m_jit.branchIfNotOther(operand.jsValueRegs(), tempGPR));
+    speculateOther(edge, operand.jsValueRegs());
 }
 
 void SpeculativeJIT::speculateMisc(Edge edge, JSValueRegs regs)
index 1430610..6d88428 100644 (file)
@@ -3008,6 +3008,8 @@ public:
     void speculateSymbol(Edge);
     void speculateNotCell(Edge, JSValueRegs);
     void speculateNotCell(Edge);
+    void speculateOther(Edge, JSValueRegs, GPRReg temp);
+    void speculateOther(Edge, JSValueRegs);
     void speculateOther(Edge);
     void speculateMisc(Edge, JSValueRegs);
     void speculateMisc(Edge);
index 08fb81c..8b892ea 100644 (file)
@@ -4072,6 +4072,8 @@ private:
         switch (searchElementEdge.useKind()) {
         case Int32Use:
         case ObjectUse:
+        case SymbolUse:
+        case OtherUse:
         case DoubleRepUse: {
             LBasicBlock loopHeader = m_out.newBlock();
             LBasicBlock loopBody = m_out.newBlock();
@@ -4080,16 +4082,32 @@ private:
             LBasicBlock continuation = m_out.newBlock();
 
             LValue searchElement;
-            if (searchElementEdge.useKind() == Int32Use) {
+            switch (searchElementEdge.useKind()) {
+            case Int32Use:
                 ASSERT(m_node->arrayMode().type() == Array::Int32);
                 speculate(searchElementEdge);
                 searchElement = lowJSValue(searchElementEdge, ManualOperandSpeculation);
-            } else if (searchElementEdge.useKind() == ObjectUse) {
+                break;
+            case ObjectUse:
                 ASSERT(m_node->arrayMode().type() == Array::Contiguous);
                 searchElement = lowObject(searchElementEdge);
-            } else {
+                break;
+            case SymbolUse:
+                ASSERT(m_node->arrayMode().type() == Array::Contiguous);
+                searchElement = lowSymbol(searchElementEdge);
+                break;
+            case OtherUse:
+                ASSERT(m_node->arrayMode().type() == Array::Contiguous);
+                speculate(searchElementEdge);
+                searchElement = lowJSValue(searchElementEdge, ManualOperandSpeculation);
+                break;
+            case DoubleRepUse:
                 ASSERT(m_node->arrayMode().type() == Array::Double);
                 searchElement = lowDouble(searchElementEdge);
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
             }
 
             startIndex = m_out.zeroExtPtr(startIndex);
@@ -4104,18 +4122,30 @@ private:
 
             m_out.appendTo(loopBody, loopNext);
             ValueFromBlock foundResult = m_out.anchor(index);
-            if (searchElementEdge.useKind() == Int32Use) {
+            switch (searchElementEdge.useKind()) {
+            case Int32Use: {
                 // Empty value is ignored because of TagTypeNumber.
                 LValue value = m_out.load64(m_out.baseIndex(m_heaps.indexedInt32Properties, storage, index));
                 m_out.branch(m_out.equal(value, searchElement), unsure(continuation), unsure(loopNext));
-            } else if (searchElementEdge.useKind() == ObjectUse) {
-                // Empty value never matches against object pointers.
+                break;
+            }
+            case ObjectUse:
+            case SymbolUse:
+            case OtherUse: {
+                // Empty value never matches against non-empty JS values.
                 LValue value = m_out.load64(m_out.baseIndex(m_heaps.indexedContiguousProperties, storage, index));
                 m_out.branch(m_out.equal(value, searchElement), unsure(continuation), unsure(loopNext));
-            } else {
+                break;
+            }
+            case DoubleRepUse: {
                 // Empty value is ignored because of NaN.
                 LValue value = m_out.loadDouble(m_out.baseIndex(m_heaps.indexedDoubleProperties, storage, index));
                 m_out.branch(m_out.doubleEqual(value, searchElement), unsure(continuation), unsure(loopNext));
+                break;
+            }
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
             }
 
             m_out.appendTo(loopNext, notFound);