Title: [265775] trunk
Revision
265775
Author
[email protected]
Date
2020-08-17 15:10:14 -0700 (Mon, 17 Aug 2020)

Log Message

Have an OOB+SaneChain Array::Speculation
https://bugs.webkit.org/show_bug.cgi?id=215487

Reviewed by Yusuke Suzuki.

JSTests:

* microbenchmarks/oob-sane-chain-contiguous.js: Added.
* microbenchmarks/oob-sane-chain-double-read-undefined.js: Added.
* microbenchmarks/oob-sane-chain-double.js: Added.
* microbenchmarks/oob-sane-chain-int32.js: Added.
* stress/oob-sane-chain-negative-index.js: Added.

Source/_javascript_Core:

This patch adds a new ArrayMode speculation in the DFG/FTL called OutOfBoundsSaneChain.
It allows us to do fast things when we go OOB, like simply return undefined.
This is because we install watchpoints on the prototype chain to ensure they
have no indexed properties. This patch implements OutOfBoundsSaneChain on
GetByVal over Int32/Double/Contiguous original JS arrays. We can extend it in
the future to non original JS arrays if we prove their prototype is Array.prototype.
To implement this properly, we also need to ensure that the index isn't negative,
as Array.prototype/Object.prototype may have negative indexed accessors. We
do this via speculation, and if we ever recompile, and see an exit because of
this, we will stop speculating OutOfBoundsSaneChain.

This is about 20% faster on crypto-md5-SP. And ~3-4x faster on the
microbenchmarks I created.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::refine const):
(JSC::DFG::arraySpeculationToString):
* dfg/DFGArrayMode.h:
(JSC::DFG::ArrayMode::isInBoundsSaneChain const):
(JSC::DFG::ArrayMode::isOutOfBoundsSaneChain const):
(JSC::DFG::ArrayMode::isOutOfBounds const):
(JSC::DFG::ArrayMode::isEffectfulOutOfBounds const):
(JSC::DFG::ArrayMode::isInBounds const):
(JSC::DFG::ArrayMode::isSaneChain const): Deleted.
* dfg/DFGCSEPhase.cpp:
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::checkArray):
(JSC::DFG::FixupPhase::setSaneChainIfPossible):
(JSC::DFG::FixupPhase::convertToHasIndexedProperty):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
(JSC::DFG::SpeculativeJIT::compileHasIndexedProperty):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
(JSC::FTL::DFG::LowerDFGToB3::compileStringCharAt):
(JSC::FTL::DFG::LowerDFGToB3::compileHasIndexedProperty):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (265774 => 265775)


--- trunk/JSTests/ChangeLog	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/JSTests/ChangeLog	2020-08-17 22:10:14 UTC (rev 265775)
@@ -1,3 +1,16 @@
+2020-08-17  Saam Barati  <[email protected]>
+
+        Have an OOB+SaneChain Array::Speculation
+        https://bugs.webkit.org/show_bug.cgi?id=215487
+
+        Reviewed by Yusuke Suzuki.
+
+        * microbenchmarks/oob-sane-chain-contiguous.js: Added.
+        * microbenchmarks/oob-sane-chain-double-read-undefined.js: Added.
+        * microbenchmarks/oob-sane-chain-double.js: Added.
+        * microbenchmarks/oob-sane-chain-int32.js: Added.
+        * stress/oob-sane-chain-negative-index.js: Added.
+
 2020-08-16  Yusuke Suzuki  <[email protected]>
 
         Unreviewed, reduce iteration count more for non-JIT environments

Added: trunk/JSTests/microbenchmarks/oob-sane-chain-contiguous.js (0 => 265775)


--- trunk/JSTests/microbenchmarks/oob-sane-chain-contiguous.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/oob-sane-chain-contiguous.js	2020-08-17 22:10:14 UTC (rev 265775)
@@ -0,0 +1,18 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+
+function bar(a, x) {
+    return a[x];
+}
+noInline(bar);
+
+let o = {};
+let b = [o, "", , 25];
+
+for (let i = 0; i < 10000000; ++i) {
+    assert(bar(b, 0) === o);
+    assert(bar(b, 5) === undefined);
+    assert(bar(b, 2) === undefined);
+}

Added: trunk/JSTests/microbenchmarks/oob-sane-chain-double-read-undefined.js (0 => 265775)


--- trunk/JSTests/microbenchmarks/oob-sane-chain-double-read-undefined.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/oob-sane-chain-double-read-undefined.js	2020-08-17 22:10:14 UTC (rev 265775)
@@ -0,0 +1,18 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+
+function baz(a, x) {
+    return a[x];
+}
+noInline(baz);
+
+let a = [1.5, 2.5, , 3.5];
+
+for (let i = 0; i < 10000000; ++i) {
+    assert(baz(a, 0) === 1.5);
+    assert(baz(a, 5) === undefined);
+    assert(baz(a, 2) === undefined);
+}
+

Added: trunk/JSTests/microbenchmarks/oob-sane-chain-double.js (0 => 265775)


--- trunk/JSTests/microbenchmarks/oob-sane-chain-double.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/oob-sane-chain-double.js	2020-08-17 22:10:14 UTC (rev 265775)
@@ -0,0 +1,17 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+
+function foo(a, x) {
+    return a[x] * 2.5;
+}
+noInline(foo);
+
+let a = [1.5, 2.5, , 3.5];
+
+for (let i = 0; i < 10000000; ++i) {
+    assert(foo(a, 0) === 2.5 * 1.5);
+    assert(isNaN(foo(a, 5)));
+    assert(isNaN(foo(a, 2)));
+}

Added: trunk/JSTests/microbenchmarks/oob-sane-chain-int32.js (0 => 265775)


--- trunk/JSTests/microbenchmarks/oob-sane-chain-int32.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/oob-sane-chain-int32.js	2020-08-17 22:10:14 UTC (rev 265775)
@@ -0,0 +1,17 @@
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+
+function bar(a, x) {
+    return a[x];
+}
+noInline(bar);
+
+let b = [0, 1, ,  2];
+
+for (let i = 0; i < 10000000; ++i) {
+    assert(bar(b, 0) === 0);
+    assert(bar(b, 5) === undefined);
+    assert(bar(b, 2) === undefined);
+}

Added: trunk/JSTests/stress/oob-sane-chain-negative-index.js (0 => 265775)


--- trunk/JSTests/stress/oob-sane-chain-negative-index.js	                        (rev 0)
+++ trunk/JSTests/stress/oob-sane-chain-negative-index.js	2020-08-17 22:10:14 UTC (rev 265775)
@@ -0,0 +1,24 @@
+let called = false;
+Object.defineProperty(Array.prototype, "-1", {
+    get: function() {
+        called = true;
+        return 42;
+    }
+});
+function assert(b) {
+    if (!b)
+        throw new Error;
+}
+
+function baz(a, x) {
+    return a[x];
+}
+noInline(baz);
+
+let a = [1,2,3];
+
+for (let i = 0; i < 10000000; ++i) {
+    assert(baz(a, -1) === 42);
+    assert(called);
+    called = false;
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (265774 => 265775)


--- trunk/Source/_javascript_Core/ChangeLog	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-08-17 22:10:14 UTC (rev 265775)
@@ -1,3 +1,57 @@
+2020-08-17  Saam Barati  <[email protected]>
+
+        Have an OOB+SaneChain Array::Speculation
+        https://bugs.webkit.org/show_bug.cgi?id=215487
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch adds a new ArrayMode speculation in the DFG/FTL called OutOfBoundsSaneChain.
+        It allows us to do fast things when we go OOB, like simply return undefined.
+        This is because we install watchpoints on the prototype chain to ensure they
+        have no indexed properties. This patch implements OutOfBoundsSaneChain on
+        GetByVal over Int32/Double/Contiguous original JS arrays. We can extend it in
+        the future to non original JS arrays if we prove their prototype is Array.prototype. 
+        To implement this properly, we also need to ensure that the index isn't negative,
+        as Array.prototype/Object.prototype may have negative indexed accessors. We
+        do this via speculation, and if we ever recompile, and see an exit because of
+        this, we will stop speculating OutOfBoundsSaneChain.
+        
+        This is about 20% faster on crypto-md5-SP. And ~3-4x faster on the
+        microbenchmarks I created.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::ArrayMode::refine const):
+        (JSC::DFG::arraySpeculationToString):
+        * dfg/DFGArrayMode.h:
+        (JSC::DFG::ArrayMode::isInBoundsSaneChain const):
+        (JSC::DFG::ArrayMode::isOutOfBoundsSaneChain const):
+        (JSC::DFG::ArrayMode::isOutOfBounds const):
+        (JSC::DFG::ArrayMode::isEffectfulOutOfBounds const):
+        (JSC::DFG::ArrayMode::isInBounds const):
+        (JSC::DFG::ArrayMode::isSaneChain const): Deleted.
+        * dfg/DFGCSEPhase.cpp:
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::checkArray):
+        (JSC::DFG::FixupPhase::setSaneChainIfPossible):
+        (JSC::DFG::FixupPhase::convertToHasIndexedProperty):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnString):
+        (JSC::DFG::SpeculativeJIT::compileHasIndexedProperty):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
+        (JSC::FTL::DFG::LowerDFGToB3::compileStringCharAt):
+        (JSC::FTL::DFG::LowerDFGToB3::compileHasIndexedProperty):
+
 2020-08-16  Alexey Shvayka  <[email protected]>
 
         Remove OpIsObjectOrNull from ClassExprNode::emitBytecode()

Modified: trunk/Source/_javascript_Core/bytecode/ExitKind.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/bytecode/ExitKind.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/bytecode/ExitKind.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -56,6 +56,8 @@
         return "Overflow";
     case NegativeZero:
         return "NegativeZero";
+    case NegativeIndex:
+        return "NegativeIndex";
     case Int52Overflow:
         return "Int52Overflow";
     case StoreToHole:

Modified: trunk/Source/_javascript_Core/bytecode/ExitKind.h (265774 => 265775)


--- trunk/Source/_javascript_Core/bytecode/ExitKind.h	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/bytecode/ExitKind.h	2020-08-17 22:10:14 UTC (rev 265775)
@@ -39,6 +39,7 @@
     BadTypeInfoFlags, // We exited because we made an incorrect assumption about what TypeInfo flags we would see.
     Overflow, // We exited because of overflow.
     NegativeZero, // We exited because we encountered negative zero.
+    NegativeIndex, // We exited because we encountered a negative index in a place we didn't want to see it.
     Int52Overflow, // We exited because of an Int52 overflow.
     StoreToHole, // We had a store to a hole.
     LoadFromHole, // We had a load from a hole.

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2020-08-17 22:10:14 UTC (rev 265775)
@@ -2350,7 +2350,7 @@
                 // we got to the backend. So to do this right, we'd have to get the
                 // fixup phase to check the watchpoint state and then bake into the
                 // GetByVal operation the fact that we're using a watchpoint, using
-                // something like Array::SaneChain (except not quite, because that
+                // something like Array::InBoundsSaneChain (except not quite, because that
                 // implies an in-bounds access). None of this feels like it's worth it,
                 // so we're going with TOP for now. The same thing applies to
                 // clobbering the world.
@@ -2366,25 +2366,32 @@
             makeHeapTopForNode(node);
             break;
         case Array::Int32:
-            if (node->arrayMode().isOutOfBounds()) {
+            if (node->arrayMode().isEffectfulOutOfBounds()) {
                 clobberWorld();
                 makeHeapTopForNode(node);
-            } else
+            } else if (node->arrayMode().isOutOfBoundsSaneChain())
+                setNonCellTypeForNode(node, SpecInt32Only | SpecOther);
+            else
                 setNonCellTypeForNode(node, SpecInt32Only);
             break;
         case Array::Double:
-            if (node->arrayMode().isOutOfBounds()) {
+            if (node->arrayMode().isEffectfulOutOfBounds()) {
                 clobberWorld();
                 makeHeapTopForNode(node);
-            } else if (node->arrayMode().isSaneChain())
+            } else if (node->arrayMode().isInBoundsSaneChain())
                 setNonCellTypeForNode(node, SpecBytecodeDouble);
-            else
+            else if (node->arrayMode().isOutOfBoundsSaneChain()) {
+                if (!!(node->flags() & NodeBytecodeUsesAsOther))
+                    setNonCellTypeForNode(node, SpecBytecodeDouble | SpecOther);
+                else
+                    setNonCellTypeForNode(node, SpecBytecodeDouble);
+            } else
                 setNonCellTypeForNode(node, SpecDoubleReal);
             break;
         case Array::Contiguous:
         case Array::ArrayStorage:
         case Array::SlowPutArrayStorage:
-            if (node->arrayMode().isOutOfBounds())
+            if (node->arrayMode().isEffectfulOutOfBounds())
                 clobberWorld();
             makeHeapTopForNode(node);
             break;

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -260,7 +260,7 @@
             graph.registerAndWatchStructureTransition(arrayPrototypeStructure);
             graph.registerAndWatchStructureTransition(objectPrototypeStructure);
             if (globalObject->arrayPrototypeChainIsSane())
-                return withSpeculation(Array::SaneChain);
+                return withSpeculation(Array::InBoundsSaneChain);
         }
         return ArrayMode(Array::Generic, action());
     }
@@ -713,8 +713,8 @@
 const char* arraySpeculationToString(Array::Speculation speculation)
 {
     switch (speculation) {
-    case Array::SaneChain:
-        return "SaneChain";
+    case Array::InBoundsSaneChain:
+        return "InBoundsSaneChain";
     case Array::InBounds:
         return "InBounds";
     case Array::ToHole:
@@ -721,6 +721,8 @@
         return "ToHole";
     case Array::OutOfBounds:
         return "OutOfBounds";
+    case Array::OutOfBoundsSaneChain:
+        return "OutOfBoundsSaneChain";
     default:
         return "Unknown!";
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.h (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.h	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.h	2020-08-17 22:10:14 UTC (rev 265775)
@@ -89,10 +89,11 @@
 };
 
 enum Speculation : uint8_t {
-    SaneChain, // In bounds and the array prototype chain is still intact, i.e. loading a hole doesn't require special treatment.
+    InBoundsSaneChain, // In bounds and the array prototype chain is still intact, i.e. loading a hole doesn't require special treatment.
     
     InBounds, // In bounds and not loading a hole.
     ToHole, // Potentially storing to a hole.
+    OutOfBoundsSaneChain, // Out-of-bounds access, but sane chain, so there are no arbitrary effects. E.g, loading out of bounds doesn't require traversing the prototype chain if we're an original array structure.
     OutOfBounds // Out-of-bounds access and anything can happen.
 };
 enum Conversion : uint8_t {
@@ -276,15 +277,35 @@
         return arrayClass() == Array::OriginalArray || arrayClass() == Array::OriginalCopyOnWriteArray;
     }
     
-    bool isSaneChain() const
+    bool isInBoundsSaneChain() const
     {
-        return speculation() == Array::SaneChain;
+        return speculation() == Array::InBoundsSaneChain;
     }
+
+    bool isOutOfBoundsSaneChain() const
+    {
+        return speculation() == Array::OutOfBoundsSaneChain;
+    }
+
+    bool isAnySaneChain() const
+    {
+        return isInBoundsSaneChain() || isOutOfBoundsSaneChain();
+    }
     
+    bool isOutOfBounds() const
+    {
+        return speculation() == Array::OutOfBounds || speculation() == Array::OutOfBoundsSaneChain;
+    }
+
+    bool isEffectfulOutOfBounds() const
+    {
+        return speculation() == Array::OutOfBounds;
+    }
+    
     bool isInBounds() const
     {
         switch (speculation()) {
-        case Array::SaneChain:
+        case Array::InBoundsSaneChain:
         case Array::InBounds:
             return true;
         default:
@@ -297,11 +318,6 @@
         return !isInBounds();
     }
     
-    bool isOutOfBounds() const
-    {
-        return speculation() == Array::OutOfBounds;
-    }
-    
     bool isSlowPut() const
     {
         return type() == Array::SlowPutArrayStorage;

Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -550,7 +550,7 @@
                         case Array::Double: {
                             if (!mode.isInBounds())
                                 break;
-                            LocationKind kind = mode.isSaneChain() ? IndexedPropertyDoubleSaneChainLoc : IndexedPropertyDoubleLoc;
+                            LocationKind kind = mode.isInBoundsSaneChain() ? IndexedPropertyDoubleSaneChainLoc : IndexedPropertyDoubleLoc;
                             heap = HeapLocation(kind, IndexedDoubleProperties, base, index);
                             break;
                         }

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2020-08-17 22:10:14 UTC (rev 265775)
@@ -929,10 +929,11 @@
             return;
             
         case Array::Int32:
-            if (mode.isInBounds()) {
+            if (mode.isInBounds() || mode.isOutOfBoundsSaneChain()) {
                 read(Butterfly_publicLength);
                 read(IndexedInt32Properties);
-                def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
+                LocationKind kind = mode.isOutOfBoundsSaneChain() ? IndexedPropertyInt32OrOtherLoc : indexedPropertyLoc;
+                def(HeapLocation(kind, IndexedInt32Properties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
                 return;
             }
             clobberTop();
@@ -939,10 +940,16 @@
             return;
             
         case Array::Double:
-            if (mode.isInBounds()) {
+            if (mode.isInBounds() || mode.isOutOfBoundsSaneChain()) {
                 read(Butterfly_publicLength);
                 read(IndexedDoubleProperties);
-                LocationKind kind = mode.isSaneChain() ? IndexedPropertyDoubleSaneChainLoc : IndexedPropertyDoubleLoc;
+                LocationKind kind;
+                if (node->hasDoubleResult())
+                    kind = mode.isAnySaneChain() ? IndexedPropertyDoubleSaneChainLoc : IndexedPropertyDoubleLoc;
+                else {
+                    ASSERT(mode.isOutOfBoundsSaneChain());
+                    kind = IndexedPropertyDoubleOrOtherSaneChainLoc;
+                }
                 def(HeapLocation(kind, IndexedDoubleProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
                 return;
             }
@@ -950,7 +957,7 @@
             return;
             
         case Array::Contiguous:
-            if (mode.isInBounds()) {
+            if (mode.isInBounds() || mode.isOutOfBoundsSaneChain()) {
                 read(Butterfly_publicLength);
                 read(IndexedContiguousProperties);
                 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
@@ -1042,6 +1049,7 @@
             if (node->arrayMode().mayStoreToHole())
                 write(Butterfly_publicLength);
             def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, base, index), LazyNode(value));
+            def(HeapLocation(IndexedPropertyInt32OrOtherLoc, IndexedInt32Properties, base, index), LazyNode(value));
             return;
             
         case Array::Double:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -1059,8 +1059,10 @@
             switch (arrayMode.type()) {
             case Array::Contiguous:
             case Array::Double:
-                if (arrayMode.isJSArrayWithOriginalStructure() && arrayMode.speculation() == Array::InBounds) {
-                    // Check if SaneChain will work on a per-type basis. Note that:
+            case Array::Int32: {
+                Optional<Array::Speculation> saneChainSpeculation;
+                if (arrayMode.isJSArrayWithOriginalStructure()) {
+                    // Check if InBoundsSaneChain will work on a per-type basis. Note that:
                     //
                     // 1) We don't want double arrays to sometimes return undefined, since
                     // that would require a change to the return type and it would pessimise
@@ -1067,12 +1069,14 @@
                     // things a lot. So, we'd only want to do that if we actually had
                     // evidence that we could read from a hole. That's pretty annoying.
                     // Likely the best way to handle that case is with an equivalent of
-                    // SaneChain for OutOfBounds. For now we just detect when Undefined and
+                    // InBoundsSaneChain for OutOfBounds. For now we just detect when Undefined and
                     // NaN are indistinguishable according to backwards propagation, and just
-                    // use SaneChain in that case. This happens to catch a lot of cases.
+                    // use InBoundsSaneChain in that case. This happens to catch a lot of cases.
                     //
                     // 2) We don't want int32 array loads to have to do a hole check just to
-                    // coerce to Undefined, since that would mean twice the checks.
+                    // coerce to Undefined, since that would mean twice the checks. We want to
+                    // be able to say we always return Int32. FIXME: Maybe this should be profiling
+                    // based?
                     //
                     // This has two implications. First, we have to do more checks than we'd
                     // like. It's unfortunate that we have to do the hole check. Second,
@@ -1080,32 +1084,41 @@
                     // out-of-bounds slow path. We can fix that with:
                     // https://bugs.webkit.org/show_bug.cgi?id=144668
                     
-                    bool canDoSaneChain = false;
                     switch (arrayMode.type()) {
+                    case Array::Int32:
+                        if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
+                            saneChainSpeculation = Array::OutOfBoundsSaneChain;
+                        break;
                     case Array::Contiguous:
                         // This is happens to be entirely natural. We already would have
                         // returned any JSValue, and now we'll return Undefined. We still do
                         // the check but it doesn't require taking any kind of slow path.
-                        canDoSaneChain = true;
+                        if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
+                            saneChainSpeculation = Array::OutOfBoundsSaneChain;
+                        else if (arrayMode.speculation() == Array::InBounds)
+                            saneChainSpeculation = Array::InBoundsSaneChain;
                         break;
                         
                     case Array::Double:
-                        if (!(node->flags() & NodeBytecodeUsesAsOther)) {
+                        if (!(node->flags() & NodeBytecodeUsesAsOther) && arrayMode.speculation() == Array::InBounds) {
                             // Holes look like NaN already, so if the user doesn't care
                             // about the difference between Undefined and NaN then we can
                             // do this.
-                            canDoSaneChain = true;
-                        }
+                            saneChainSpeculation = Array::InBoundsSaneChain;
+                        } else if (is64Bit() && arrayMode.speculation() == Array::OutOfBounds && !m_graph.hasExitSite(node->origin.semantic, NegativeIndex))
+                            saneChainSpeculation = Array::OutOfBoundsSaneChain;
                         break;
                         
                     default:
                         break;
                     }
-                    
-                    if (canDoSaneChain)
-                        setSaneChainIfPossible(node);
                 }
+
+                if (saneChainSpeculation)
+                    setSaneChainIfPossible(node, *saneChainSpeculation);
+
                 break;
+            }
                 
             case Array::String:
                 if ((node->prediction() & ~SpecString)
@@ -1155,7 +1168,8 @@
             
             switch (arrayMode.type()) {
             case Array::Double:
-                if (!arrayMode.isOutOfBounds())
+                if (!arrayMode.isOutOfBounds()
+                    || (arrayMode.isOutOfBoundsSaneChain() && !(node->flags() & NodeBytecodeUsesAsOther)))
                     node->setResult(NodeResultDouble);
                 break;
                 
@@ -2202,7 +2216,7 @@
             // FIXME: OutOfBounds shouldn't preclude going sane chain because OOB is just false and cannot have effects.
             // See: https://bugs.webkit.org/show_bug.cgi?id=209456
             if (arrayMode.isJSArrayWithOriginalStructure() && arrayMode.speculation() == Array::InBounds)
-                setSaneChainIfPossible(node);
+                setSaneChainIfPossible(node, Array::InBoundsSaneChain);
             break;
         }
         case GetDirectPname: {
@@ -3509,7 +3523,7 @@
             m_insertionSet.insertNode(
                 m_indexInBlock, SpecNone, Check, origin, Edge(array, StringUse));
         } else {
-            // Note that we only need to be using a structure check if we opt for SaneChain, since
+            // Note that we only need to be using a structure check if we opt for InBoundsSaneChain, since
             // that needs to protect against JSArray's __proto__ being changed.
             Structure* structure = arrayMode.originalArrayStructure(m_graph, origin.semantic);
         
@@ -3551,7 +3565,7 @@
             OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
     }
 
-    void setSaneChainIfPossible(Node* node)
+    void setSaneChainIfPossible(Node* node, Array::Speculation speculation)
     {
         JSGlobalObject* globalObject = m_graph.globalObjectFor(node->origin.semantic);
         Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(vm());
@@ -3561,7 +3575,7 @@
             && globalObject->arrayPrototypeChainIsSane()) {
             m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure);
             m_graph.registerAndWatchStructureTransition(objectPrototypeStructure);
-            node->setArrayMode(node->arrayMode().withSpeculation(Array::SaneChain));
+            node->setArrayMode(node->arrayMode().withSpeculation(speculation));
             node->clearFlags(NodeMustGenerate);
         }
     }
@@ -3943,7 +3957,7 @@
         // FIXME: OutOfBounds shouldn't preclude going sane chain because OOB is just false and cannot have effects.
         // See: https://bugs.webkit.org/show_bug.cgi?id=209456
         if (arrayMode.isJSArrayWithOriginalStructure() && arrayMode.speculation() == Array::InBounds)
-            setSaneChainIfPossible(node);
+            setSaneChainIfPossible(node, Array::InBoundsSaneChain);
 
         fixEdge<CellUse>(m_graph.varArgChild(node, 0));
         fixEdge<Int32Use>(m_graph.varArgChild(node, 1));

Modified: trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGHeapLocation.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -138,10 +138,18 @@
         out.print("IndexedPropertyDoubleSaneChainLoc");
         return;
 
+    case IndexedPropertyDoubleOrOtherSaneChainLoc:
+        out.print("IndexedPropertyDoubleOrOtherSaneChainLoc");
+        return;
+
     case IndexedPropertyInt32Loc:
         out.print("IndexedPropertyInt32Loc");
         return;
 
+    case IndexedPropertyInt32OrOtherLoc:
+        out.print("IndexedPropertyInt32OrOtherLoc");
+        return;
+
     case IndexedPropertyInt52Loc:
         out.print("IndexedPropertyInt52Loc");
         return;

Modified: trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGHeapLocation.h	2020-08-17 22:10:14 UTC (rev 265775)
@@ -49,7 +49,9 @@
     HasIndexedPropertyLoc,
     IndexedPropertyDoubleLoc,
     IndexedPropertyDoubleSaneChainLoc,
+    IndexedPropertyDoubleOrOtherSaneChainLoc,
     IndexedPropertyInt32Loc,
+    IndexedPropertyInt32OrOtherLoc,
     IndexedPropertyInt52Loc,
     IndexedPropertyJSLoc,
     IndexedPropertyStorageLoc,

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -2408,7 +2408,7 @@
 
         if (globalObject->stringPrototypeChainIsSane()) {
             // FIXME: This could be captured using a Speculation mode that means "out-of-bounds
-            // loads return a trivial value". Something like SaneChainOutOfBounds. This should
+            // loads return a trivial value". Something like OutOfBoundsSaneChain. This should
             // speculate that we don't take negative out-of-bounds, or better yet, it should rely
             // on a stringPrototypeChainIsSane() guaranteeing that the prototypes have no negative
             // indexed properties either.
@@ -14148,7 +14148,7 @@
         m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
 #endif
 
-        if (mode.isSaneChain()) {
+        if (mode.isInBoundsSaneChain()) {
             m_jit.isNotEmpty(scratchGPR, resultGPR);
             break;
         }
@@ -14177,7 +14177,7 @@
 
         m_jit.loadDouble(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight), scratchFPR);
 
-        if (mode.isSaneChain()) {
+        if (mode.isInBoundsSaneChain()) {
             m_jit.compareDouble(MacroAssembler::DoubleEqualAndOrdered, scratchFPR, scratchFPR, resultGPR);
             break;
         }
@@ -14210,13 +14210,13 @@
         m_jit.load32(MacroAssembler::BaseIndex(storageGPR, indexGPR, MacroAssembler::TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), scratchGPR);
 #endif
 
-        if (mode.isSaneChain()) {
+        if (mode.isInBoundsSaneChain()) {
             m_jit.isNotEmpty(scratchGPR, resultGPR);
             break;
         }
 
         MacroAssembler::Jump isHole = m_jit.branchIfEmpty(scratchGPR);
-        if (!mode.isInBounds() || mode.isSaneChain())
+        if (!mode.isInBounds() || mode.isInBoundsSaneChain())
             slowCases.append(isHole);
         else
             speculationCheck(LoadFromHole, JSValueRegs(), nullptr, isHole);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -2366,7 +2366,7 @@
             
                 GPRTemporary resultPayload(this);
                 if (node->arrayMode().type() == Array::Int32) {
-                    ASSERT(!node->arrayMode().isSaneChain());
+                    ASSERT(!node->arrayMode().isInBoundsSaneChain());
                     
                     speculationCheck(
                         OutOfBounds, JSValueRegs(), 0,
@@ -2392,7 +2392,7 @@
                     MacroAssembler::BaseIndex(
                         storageReg, propertyReg, MacroAssembler::TimesEight, PayloadOffset),
                     resultPayload.gpr());
-                if (node->arrayMode().isSaneChain()) {
+                if (node->arrayMode().isInBoundsSaneChain()) {
                     JITCompiler::Jump notHole = m_jit.branchIfNotEmpty(resultTag.gpr());
                     m_jit.move(TrustedImm32(JSValue::UndefinedTag), resultTag.gpr());
                     m_jit.move(TrustedImm32(0), resultPayload.gpr());
@@ -2453,7 +2453,7 @@
             
                 FPRTemporary result(this);
                 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
-                if (!node->arrayMode().isSaneChain())
+                if (!node->arrayMode().isInBoundsSaneChain())
                     speculationCheck(LoadFromHole, JSValueRegs(), 0, m_jit.branchIfNaN(result.fpr()));
                 doubleResult(result.fpr(), node);
                 break;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -2736,7 +2736,7 @@
                 GPRTemporary result(this);
 
                 m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.gpr());
-                if (node->arrayMode().isSaneChain()) {
+                if (node->arrayMode().isInBoundsSaneChain()) {
                     ASSERT(node->arrayMode().type() == Array::Contiguous);
                     JITCompiler::Jump notHole = m_jit.branchIfNotEmpty(result.gpr());
                     m_jit.move(TrustedImm64(JSValue::encode(jsUndefined())), result.gpr());
@@ -2769,12 +2769,21 @@
             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
 
             m_jit.load64(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
-            slowCases.append(m_jit.branchIfEmpty(resultReg));
+
+            if (node->arrayMode().isOutOfBoundsSaneChain()) {
+                auto done = m_jit.branchIfNotEmpty(resultReg);
+                slowCases.link(&m_jit);
+                speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
+                m_jit.move(CCallHelpers::TrustedImm64(JSValue::encode(jsUndefined())), resultReg);
+                done.link(&m_jit);
+            } else {
+                slowCases.append(m_jit.branchIfEmpty(resultReg));
+                addSlowPathGenerator(
+                    slowPathCall(
+                        slowCases, this, operationGetByValObjectInt,
+                        result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
+            }
             
-            addSlowPathGenerator(
-                slowPathCall(
-                    slowCases, this, operationGetByValObjectInt,
-                    result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
             
             jsValueResult(resultReg, node);
             break;
@@ -2797,12 +2806,14 @@
                 speculationCheck(OutOfBounds, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
 
                 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
-                if (!node->arrayMode().isSaneChain())
+                if (!node->arrayMode().isInBoundsSaneChain())
                     speculationCheck(LoadFromHole, JSValueRegs(), nullptr, m_jit.branchIfNaN(resultReg));
                 doubleResult(resultReg, node);
                 break;
             }
 
+            bool resultIsUnboxed = node->arrayMode().isOutOfBoundsSaneChain() && !(node->flags() & NodeBytecodeUsesAsOther);
+
             SpeculateCellOperand base(this, m_graph.varArgChild(node, 0));
             SpeculateStrictInt32Operand property(this, m_graph.varArgChild(node, 1));
             StorageOperand storage(this, m_graph.varArgChild(node, 2));
@@ -2814,9 +2825,13 @@
             if (!m_compileOkay)
                 return;
             
-            GPRTemporary result(this);
+            Optional<GPRTemporary> result;
+            Optional<GPRReg> resultReg;
+            if (!resultIsUnboxed) {
+                result.emplace(this);
+                resultReg = result->gpr();
+            }
             FPRTemporary temp(this);
-            GPRReg resultReg = result.gpr();
             FPRReg tempReg = temp.fpr();
             
             MacroAssembler::JumpList slowCases;
@@ -2824,15 +2839,35 @@
             slowCases.append(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, Butterfly::offsetOfPublicLength())));
 
             m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), tempReg);
-            slowCases.append(m_jit.branchIfNaN(tempReg));
-            boxDouble(tempReg, resultReg);
-            
-            addSlowPathGenerator(
-                slowPathCall(
-                    slowCases, this, operationGetByValObjectInt,
-                    result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
-            
-            jsValueResult(resultReg, node);
+            if (node->arrayMode().isOutOfBoundsSaneChain()) {
+                if (resultIsUnboxed) {
+                    auto done = m_jit.jump();
+                    slowCases.link(&m_jit);
+                    speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
+                    static const double NaN = PNaN;
+                    m_jit.loadDouble(TrustedImmPtr(&NaN), tempReg);
+                    done.link(&m_jit);
+                    doubleResult(tempReg, node);
+                } else {
+                    slowCases.append(m_jit.branchIfNaN(tempReg));
+                    boxDouble(tempReg, *resultReg);
+                    auto done = m_jit.jump();
+                    slowCases.link(&m_jit);
+                    speculationCheck(NegativeIndex, JSValueRegs(), nullptr, m_jit.branch32(MacroAssembler::LessThan, propertyReg, CCallHelpers::TrustedImm32(0)));
+                    m_jit.move(CCallHelpers::TrustedImm64(JSValue::encode(jsUndefined())), *resultReg);
+                    done.link(&m_jit);
+                    jsValueResult(*resultReg, node);
+                }
+            } else {
+                slowCases.append(m_jit.branchIfNaN(tempReg));
+                boxDouble(tempReg, *resultReg);
+                addSlowPathGenerator(
+                    slowPathCall(
+                        slowCases, this, operationGetByValObjectInt,
+                        *resultReg, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseReg, propertyReg));
+                jsValueResult(*resultReg, node);
+            }
+
             break;
         }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -382,6 +382,20 @@
                 case NewArrayBuffer:
                     VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSImmutableButterfly*>()->length());
                     break;
+                case GetByVal:
+                    switch (node->arrayMode().type()) {
+                    case Array::Int32:
+                    case Array::Double:
+                    case Array::Contiguous:
+                        // We rely on being an original array structure because we are SaneChain, and we need 
+                        // Array.prototype to be our prototype, so we can return undefined when we go OOB.
+                        if (node->arrayMode().isOutOfBoundsSaneChain())
+                            VALIDATE((node), node->arrayMode().isJSArrayWithOriginalStructure());
+                        break;
+                    default:
+                        break;
+                    }
+                    break;
                 default:
                     break;
                 }

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (265774 => 265775)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2020-08-17 21:54:42 UTC (rev 265774)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2020-08-17 22:10:14 UTC (rev 265775)
@@ -4632,7 +4632,7 @@
             if (m_node->arrayMode().isInBounds()) {
                 LValue result = m_out.load64(baseIndex(heap, storage, index, m_graph.varArgChild(m_node, 1)));
                 LValue isHole = m_out.isZero64(result);
-                if (m_node->arrayMode().isSaneChain()) {
+                if (m_node->arrayMode().isInBoundsSaneChain()) {
                     DFG_ASSERT(
                         m_graph, m_node, m_node->arrayMode().type() == Array::Contiguous, m_node->arrayMode().type());
                     result = m_out.select(
@@ -4645,7 +4645,7 @@
                 setJSValue(result);
                 return;
             }
-            
+
             LBasicBlock fastCase = m_out.newBlock();
             LBasicBlock slowCase = m_out.newBlock();
             LBasicBlock continuation = m_out.newBlock();
@@ -4663,7 +4663,12 @@
                 m_out.isZero64(fastResultValue), rarely(slowCase), usually(continuation));
             
             m_out.appendTo(slowCase, continuation);
-            ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, operationGetByValObjectInt, weakPointer(globalObject), base, index));
+            ValueFromBlock slowResult;
+            if (m_node->arrayMode().isOutOfBoundsSaneChain()) {
+                speculate(NegativeIndex, noValue(), nullptr, m_out.lessThan(index, m_out.int32Zero));
+                slowResult = m_out.anchor(m_out.constInt64(JSValue::ValueUndefined));
+            } else
+                slowResult = m_out.anchor(vmCall(Int64, operationGetByValObjectInt, weakPointer(globalObject), base, index));
             m_out.jump(continuation);
             
             m_out.appendTo(continuation, lastNext);
@@ -4685,7 +4690,7 @@
                 LValue result = m_out.loadDouble(
                     baseIndex(heap, storage, index, m_graph.varArgChild(m_node, 1)));
                 
-                if (!m_node->arrayMode().isSaneChain()) {
+                if (!m_node->arrayMode().isInBoundsSaneChain()) {
                     speculate(
                         LoadFromHole, noValue(), nullptr,
                         m_out.doubleNotEqualOrUnordered(result, result));
@@ -4694,6 +4699,8 @@
                 break;
             }
 
+            bool resultIsUnboxed = m_node->arrayMode().isOutOfBoundsSaneChain() && !(m_node->flags() & NodeBytecodeUsesAsOther);
+
             LBasicBlock inBounds = m_out.newBlock();
             LBasicBlock boxPath = m_out.newBlock();
             LBasicBlock slowCase = m_out.newBlock();
@@ -4712,15 +4719,26 @@
                 rarely(slowCase), usually(boxPath));
             
             m_out.appendTo(boxPath, slowCase);
-            ValueFromBlock fastResult = m_out.anchor(boxDouble(doubleValue));
+            ValueFromBlock fastResult = m_out.anchor(resultIsUnboxed ? doubleValue : boxDouble(doubleValue));
             m_out.jump(continuation);
             
             m_out.appendTo(slowCase, continuation);
-            ValueFromBlock slowResult = m_out.anchor(vmCall(Int64, operationGetByValObjectInt, weakPointer(globalObject), base, index));
+            ValueFromBlock slowResult;
+            if (m_node->arrayMode().isOutOfBoundsSaneChain()) {
+                speculate(NegativeIndex, noValue(), nullptr, m_out.lessThan(index, m_out.int32Zero));
+                if (resultIsUnboxed)
+                    slowResult = m_out.anchor(m_out.constDouble(PNaN));
+                else
+                    slowResult = m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined())));
+            } else
+                slowResult = m_out.anchor(vmCall(Int64, operationGetByValObjectInt, weakPointer(globalObject), base, index));
             m_out.jump(continuation);
             
             m_out.appendTo(continuation, lastNext);
-            setJSValue(m_out.phi(Int64, fastResult, slowResult));
+            if (resultIsUnboxed)
+                setDouble(m_out.phi(Double, fastResult, slowResult));
+            else
+                setJSValue(m_out.phi(Int64, fastResult, slowResult));
             return;
         }
 
@@ -8135,7 +8153,7 @@
             if (globalObject->stringPrototypeChainIsSane()) {
                 // FIXME: This could be captured using a Speculation mode that means
                 // "out-of-bounds loads return a trivial value", something like
-                // SaneChainOutOfBounds.
+                // OutOfBoundsSaneChain.
                 // https://bugs.webkit.org/show_bug.cgi?id=144668
                 
                 m_graph.registerAndWatchStructureTransition(stringPrototypeStructure);
@@ -12220,7 +12238,7 @@
             LValue checkHoleResultValue =
                 m_out.notZero64(m_out.load64(baseIndex(heap, storage, index, m_graph.varArgChild(m_node, 1))));
             ValueFromBlock checkHoleResult = m_out.anchor(checkHoleResultValue);
-            if (mode.isSaneChain())
+            if (mode.isInBoundsSaneChain())
                 m_out.jump(continuation);
             else if (!mode.isInBounds())
                 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase));
@@ -12259,7 +12277,7 @@
             LValue doubleValue = m_out.loadDouble(baseIndex(heap, storage, index, m_graph.varArgChild(m_node, 1)));
             LValue checkHoleResultValue = m_out.doubleEqual(doubleValue, doubleValue);
             ValueFromBlock checkHoleResult = m_out.anchor(checkHoleResultValue);
-            if (mode.isSaneChain())
+            if (mode.isInBoundsSaneChain())
                 m_out.jump(continuation);
             else if (!mode.isInBounds())
                 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase));
@@ -12297,7 +12315,7 @@
             LValue checkHoleResultValue =
                 m_out.notZero64(m_out.load64(baseIndex(m_heaps.ArrayStorage_vector, storage, index, m_graph.varArgChild(m_node, 1))));
             ValueFromBlock checkHoleResult = m_out.anchor(checkHoleResultValue);
-            if (mode.isSaneChain())
+            if (mode.isInBoundsSaneChain())
                 m_out.jump(continuation);
             else if (!mode.isInBounds())
                 m_out.branch(checkHoleResultValue, usually(continuation), rarely(slowCase));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to