Array type checks and storage accesses should be uniformly represented and available to CSE
https://bugs.webkit.org/show_bug.cgi?id=95013

Reviewed by Oliver Hunt.

This uniformly breaks up all array accesses into up to three parts:
        
1) The type check, using a newly introduced CheckArray node, in addition to possibly
   a CheckStructure node. We were already inserting the CheckStructure prior to this
   patch. The CheckArray node will be automatically eliminated if the thing it was
   checking for had already been checked for, either intentionally (a CheckStructure
   inserted based on the array profile of this access) or accidentally (some checks,
   typically a CheckStructure, inserted for some unrelated operations). The
   CheckArray node may not be inserted if the array type is non-specific (Generic or
   ForceExit).
        
2) The storage load using GetIndexedPropertyStorage. Previously, this only worked for
   GetByVal. Now it works for all array accesses. The storage load may not be
   inserted if the mode of array access does not permit CSE of storage loads (like
   non-specific modes or Arguments).
        
3) The access itself: one of GetByVal, PutByVal, PutByValAlias, ArrayPush, ArrayPop,
   GetArrayLength, StringCharAt, or StringCharCodeAt.
        
This means that the type check can be subjected to CSE even if the CFA isn't smart
enough to reason about it (yet!). It also means that the storage load can always be
subjected to CSE; previously CSE on storage load only worked for array loads and not
other forms of access. Finally, it removes the bizarre behavior that
GetIndexedPropertyStorage previously had: previously, it was responsible for the type
check in some cases, but not others; this made reasoning about the CFA really
confusing.
        
This change also disables late refinement of array mode, since I decided that
supporting that feature is both confusing and likely unprofitable. The array modes are
now locked in in the first fixup run after prediction propagation. Of course,
refinements from Generic to something else would not have been a problem; we could
reenable those if we thought we really needed to.

* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGArgumentsSimplificationPhase.cpp:
(JSC::DFG::ArgumentsSimplificationPhase::run):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::fromStructure):
(DFG):
(JSC::DFG::refineArrayMode):
* dfg/DFGArrayMode.h:
(DFG):
(JSC::DFG::modeIsJSArray):
(JSC::DFG::lengthNeedsStorage):
(JSC::DFG::modeIsSpecific):
(JSC::DFG::modeSupportsLength):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::ByteCodeParser):
(JSC::DFG::ByteCodeParser::getArrayMode):
(ByteCodeParser):
(JSC::DFG::ByteCodeParser::getArrayModeAndEmitChecks):
(JSC::DFG::ByteCodeParser::handleIntrinsic):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::mergeBlocks):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::CSEPhase):
(JSC::DFG::CSEPhase::checkStructureElimination):
(CSEPhase):
(JSC::DFG::CSEPhase::checkArrayElimination):
(JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination):
(JSC::DFG::CSEPhase::performNodeCSE):
(JSC::DFG::performCSE):
* dfg/DFGCSEPhase.h:
(DFG):
* dfg/DFGCommon.h:
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::checkArray):
(FixupPhase):
(JSC::DFG::FixupPhase::blessArrayOperation):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::Graph):
(DFG):
(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::collectGarbage):
* dfg/DFGGraph.h:
(Graph):
(JSC::DFG::Graph::vote):
(JSC::DFG::Graph::substitute):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasArrayMode):
(JSC::DFG::Node::setArrayMode):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
* dfg/DFGPhase.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::mergeDefaultFlags):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::useChildren):
(JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
(JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray):
(JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureCheckHoistingPhase.cpp:
(JSC::DFG::StructureCheckHoistingPhase::run):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@126715 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index dce55ef..b44b32f 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,124 @@
 2012-08-26  Filip Pizlo  <fpizlo@apple.com>
 
+        Array type checks and storage accesses should be uniformly represented and available to CSE
+        https://bugs.webkit.org/show_bug.cgi?id=95013
+
+        Reviewed by Oliver Hunt.
+
+        This uniformly breaks up all array accesses into up to three parts:
+        
+        1) The type check, using a newly introduced CheckArray node, in addition to possibly
+           a CheckStructure node. We were already inserting the CheckStructure prior to this
+           patch. The CheckArray node will be automatically eliminated if the thing it was
+           checking for had already been checked for, either intentionally (a CheckStructure
+           inserted based on the array profile of this access) or accidentally (some checks,
+           typically a CheckStructure, inserted for some unrelated operations). The
+           CheckArray node may not be inserted if the array type is non-specific (Generic or
+           ForceExit).
+        
+        2) The storage load using GetIndexedPropertyStorage. Previously, this only worked for
+           GetByVal. Now it works for all array accesses. The storage load may not be
+           inserted if the mode of array access does not permit CSE of storage loads (like
+           non-specific modes or Arguments).
+        
+        3) The access itself: one of GetByVal, PutByVal, PutByValAlias, ArrayPush, ArrayPop,
+           GetArrayLength, StringCharAt, or StringCharCodeAt.
+        
+        This means that the type check can be subjected to CSE even if the CFA isn't smart
+        enough to reason about it (yet!). It also means that the storage load can always be
+        subjected to CSE; previously CSE on storage load only worked for array loads and not
+        other forms of access. Finally, it removes the bizarre behavior that
+        GetIndexedPropertyStorage previously had: previously, it was responsible for the type
+        check in some cases, but not others; this made reasoning about the CFA really
+        confusing.
+        
+        This change also disables late refinement of array mode, since I decided that
+        supporting that feature is both confusing and likely unprofitable. The array modes are
+        now locked in in the first fixup run after prediction propagation. Of course,
+        refinements from Generic to something else would not have been a problem; we could
+        reenable those if we thought we really needed to.
+
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGArgumentsSimplificationPhase.cpp:
+        (JSC::DFG::ArgumentsSimplificationPhase::run):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::fromStructure):
+        (DFG):
+        (JSC::DFG::refineArrayMode):
+        * dfg/DFGArrayMode.h:
+        (DFG):
+        (JSC::DFG::modeIsJSArray):
+        (JSC::DFG::lengthNeedsStorage):
+        (JSC::DFG::modeIsSpecific):
+        (JSC::DFG::modeSupportsLength):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::ByteCodeParser):
+        (JSC::DFG::ByteCodeParser::getArrayMode):
+        (ByteCodeParser):
+        (JSC::DFG::ByteCodeParser::getArrayModeAndEmitChecks):
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCFGSimplificationPhase.cpp:
+        (JSC::DFG::CFGSimplificationPhase::mergeBlocks):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::CSEPhase):
+        (JSC::DFG::CSEPhase::checkStructureElimination):
+        (CSEPhase):
+        (JSC::DFG::CSEPhase::checkArrayElimination):
+        (JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination):
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        (JSC::DFG::performCSE):
+        * dfg/DFGCSEPhase.h:
+        (DFG):
+        * dfg/DFGCommon.h:
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDriver.cpp:
+        (JSC::DFG::compile):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::checkArray):
+        (FixupPhase):
+        (JSC::DFG::FixupPhase::blessArrayOperation):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::Graph):
+        (DFG):
+        (JSC::DFG::Graph::dump):
+        (JSC::DFG::Graph::collectGarbage):
+        * dfg/DFGGraph.h:
+        (Graph):
+        (JSC::DFG::Graph::vote):
+        (JSC::DFG::Graph::substitute):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasArrayMode):
+        (JSC::DFG::Node::setArrayMode):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGPhase.h:
+        (DFG):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        (JSC::DFG::PredictionPropagationPhase::mergeDefaultFlags):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::checkArray):
+        (JSC::DFG::SpeculativeJIT::useChildren):
+        (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray):
+        (JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray):
+        (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage):
+        (JSC::DFG::SpeculativeJIT::compileGetArrayLength):
+        * dfg/DFGSpeculativeJIT.h:
+        (SpeculativeJIT):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStructureCheckHoistingPhase.cpp:
+        (JSC::DFG::StructureCheckHoistingPhase::run):
+
+2012-08-26  Filip Pizlo  <fpizlo@apple.com>
+
         DFGGraph.h has a bogus comment about the nature of StorageAccessData
         https://bugs.webkit.org/show_bug.cgi?id=95035
 
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 43b5a03..aad9786 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -887,12 +887,10 @@
             forNode(nodeIndex).makeTop();
             break;
         case Array::String:
-            forNode(node.child1()).filter(SpecString);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecString);
             break;
         case Array::Arguments:
-            forNode(node.child1()).filter(SpecArguments);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).makeTop();
             break;
@@ -900,42 +898,34 @@
         case Array::JSArrayOutOfBounds:
             // FIXME: We should have more conservative handling of the out-of-bounds
             // case.
-            forNode(node.child1()).filter(SpecCell);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).makeTop();
             break;
         case Array::Int8Array:
-            forNode(node.child1()).filter(SpecInt8Array);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecInt32);
             break;
         case Array::Int16Array:
-            forNode(node.child1()).filter(SpecInt16Array);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecInt32);
             break;
         case Array::Int32Array:
-            forNode(node.child1()).filter(SpecInt32Array);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecInt32);
             break;
         case Array::Uint8Array:
-            forNode(node.child1()).filter(SpecUint8Array);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecInt32);
             break;
         case Array::Uint8ClampedArray:
-            forNode(node.child1()).filter(SpecUint8ClampedArray);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecInt32);
             break;
         case Array::Uint16Array:
-            forNode(node.child1()).filter(SpecUint16Array);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecInt32);
             break;
         case Array::Uint32Array:
-            forNode(node.child1()).filter(SpecUint32Array);
             forNode(node.child2()).filter(SpecInt32);
             if (node.shouldSpeculateInteger())
                 forNode(nodeIndex).set(SpecInt32);
@@ -943,12 +933,10 @@
                 forNode(nodeIndex).set(SpecDouble);
             break;
         case Array::Float32Array:
-            forNode(node.child1()).filter(SpecFloat32Array);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecDouble);
             break;
         case Array::Float64Array:
-            forNode(node.child1()).filter(SpecFloat64Array);
             forNode(node.child2()).filter(SpecInt32);
             forNode(nodeIndex).set(SpecDouble);
             break;
@@ -959,7 +947,6 @@
     case PutByVal:
     case PutByValAlias: {
         node.setCanExit(true);
-        Edge child1 = m_graph.varArgChild(node, 0);
         Edge child2 = m_graph.varArgChild(node, 1);
         Edge child3 = m_graph.varArgChild(node, 2);
         switch (modeForPut(node.arrayMode())) {
@@ -970,20 +957,16 @@
             clobberWorld(node.codeOrigin, indexInBlock);
             break;
         case Array::JSArray:
-            forNode(child1).filter(SpecCell);
             forNode(child2).filter(SpecInt32);
             break;
         case Array::JSArrayOutOfBounds:
-            forNode(child1).filter(SpecCell);
             forNode(child2).filter(SpecInt32);
             clobberWorld(node.codeOrigin, indexInBlock);
             break;
         case Array::Arguments:
-            forNode(child1).filter(SpecArguments);
             forNode(child2).filter(SpecInt32);
             break;
         case Array::Int8Array:
-            forNode(child1).filter(SpecInt8Array);
             forNode(child2).filter(SpecInt32);
             if (m_graph[child3].shouldSpeculateInteger())
                 forNode(child3).filter(SpecInt32);
@@ -991,7 +974,6 @@
                 forNode(child3).filter(SpecNumber);
             break;
         case Array::Int16Array:
-            forNode(child1).filter(SpecInt16Array);
             forNode(child2).filter(SpecInt32);
             if (m_graph[child3].shouldSpeculateInteger())
                 forNode(child3).filter(SpecInt32);
@@ -999,7 +981,6 @@
                 forNode(child3).filter(SpecNumber);
             break;
         case Array::Int32Array:
-            forNode(child1).filter(SpecInt32Array);
             forNode(child2).filter(SpecInt32);
             if (m_graph[child3].shouldSpeculateInteger())
                 forNode(child3).filter(SpecInt32);
@@ -1007,7 +988,6 @@
                 forNode(child3).filter(SpecNumber);
             break;
         case Array::Uint8Array:
-            forNode(child1).filter(SpecUint8Array);
             forNode(child2).filter(SpecInt32);
             if (m_graph[child3].shouldSpeculateInteger())
                 forNode(child3).filter(SpecInt32);
@@ -1015,7 +995,6 @@
                 forNode(child3).filter(SpecNumber);
             break;
         case Array::Uint8ClampedArray:
-            forNode(child1).filter(SpecUint8ClampedArray);
             forNode(child2).filter(SpecInt32);
             if (m_graph[child3].shouldSpeculateInteger())
                 forNode(child3).filter(SpecInt32);
@@ -1023,7 +1002,6 @@
                 forNode(child3).filter(SpecNumber);
             break;
         case Array::Uint16Array:
-            forNode(child1).filter(SpecUint16Array);
             forNode(child2).filter(SpecInt32);
             if (m_graph[child3].shouldSpeculateInteger())
                 forNode(child3).filter(SpecInt32);
@@ -1031,7 +1009,6 @@
                 forNode(child3).filter(SpecNumber);
             break;
         case Array::Uint32Array:
-            forNode(child1).filter(SpecUint32Array);
             forNode(child2).filter(SpecInt32);
             if (m_graph[child3].shouldSpeculateInteger())
                 forNode(child3).filter(SpecInt32);
@@ -1039,12 +1016,10 @@
                 forNode(child3).filter(SpecNumber);
             break;
         case Array::Float32Array:
-            forNode(child1).filter(SpecFloat32Array);
             forNode(child2).filter(SpecInt32);
             forNode(child3).filter(SpecNumber);
             break;
         case Array::Float64Array:
-            forNode(child1).filter(SpecFloat64Array);
             forNode(child2).filter(SpecInt32);
             forNode(child3).filter(SpecNumber);
             break;
@@ -1057,13 +1032,11 @@
             
     case ArrayPush:
         node.setCanExit(true);
-        forNode(node.child1()).filter(SpecCell);
         forNode(nodeIndex).set(SpecNumber);
         break;
             
     case ArrayPop:
         node.setCanExit(true);
-        forNode(node.child1()).filter(SpecCell);
         forNode(nodeIndex).makeTop();
         break;
             
@@ -1347,80 +1320,8 @@
         break;
             
     case GetArrayLength:
-        switch (node.arrayMode()) {
-        case Array::Undecided:
-            ASSERT_NOT_REACHED();
-            break;
-        case Array::ForceExit:
-            m_isValid = false;
-            break;
-        case Array::Generic:
-            ASSERT_NOT_REACHED();
-            break;
-        case Array::String:
-            node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecString);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::JSArray:
-            node.setCanExit(true);
-            forNode(node.child1()).filter(SpecCell);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::JSArrayOutOfBounds:
-            ASSERT_NOT_REACHED();
-            break;
-        case Array::Arguments:
-            node.setCanExit(true);
-            forNode(node.child1()).filter(SpecArguments);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Int8Array:
-            node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecInt8Array);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Int16Array:
-            node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecInt16Array);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Int32Array:
-            node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecInt32Array);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Uint8Array:
-            node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecUint8Array);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Uint8ClampedArray:
-            node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecUint8ClampedArray);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Uint16Array:
-            node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecUint16Array);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Uint32Array:
-            node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecUint32Array);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Float32Array:
-            node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecFloat32Array);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        case Array::Float64Array:
-            node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type));
-            forNode(node.child1()).filter(SpecFloat64Array);
-            forNode(nodeIndex).set(SpecInt32);
-            break;
-        }
+        node.setCanExit(true); // Lies, but it's true for the common case of JSArray, so it's good enough.
+        forNode(nodeIndex).set(SpecInt32);
         break;
 
     case CheckStructure:
@@ -1492,8 +1393,13 @@
         forNode(node.child1()).filter(SpecCell);
         forNode(nodeIndex).clear(); // The result is not a JS value.
         break;
-    case GetIndexedPropertyStorage: {
-        node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise.
+    case CheckArray: {
+        if (modeAlreadyChecked(forNode(node.child1()), node.arrayMode())) {
+            m_foundConstants = true;
+            node.setCanExit(false);
+            break;
+        }
+        node.setCanExit(true); // Lies, but this is followed by operations (like GetByVal) that always exit, so there is no point in us trying to be clever here.
         switch (node.arrayMode()) {
         case Array::String:
             forNode(node.child1()).filter(SpecString);
@@ -1504,6 +1410,9 @@
             // CFA tracking of array mode speculations, but we don't have that, yet.
             forNode(node.child1()).filter(SpecCell);
             break;
+        case Array::Arguments:
+            forNode(node.child1()).filter(SpecArguments);
+            break;
         case Array::Int8Array:
             forNode(node.child1()).filter(SpecInt8Array);
             break;
@@ -1535,6 +1444,19 @@
             ASSERT_NOT_REACHED();
             break;
         }
+        break;
+    }
+    case GetIndexedPropertyStorage: {
+        switch (node.arrayMode()) {
+        case Array::String:
+            // Strings are weird - we may spec fail if the string was a rope. That is of course
+            // stupid, and we should fix that, but for now let's at least be honest about it.
+            node.setCanExit(true);
+            break;
+        default:
+            node.setCanExit(false);
+            break;
+        }
         forNode(nodeIndex).clear();
         break; 
     }
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index 2f535ba..640a0a9 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -312,6 +312,7 @@
                 case ForwardCheckStructure:
                 case StructureTransitionWatchpoint:
                 case ForwardStructureTransitionWatchpoint:
+                case CheckArray:
                     // We don't care about these because if we get uses of the relevant
                     // variable then we can safely get rid of these, too. This of course
                     // relies on there not being any information transferred by the CFA
@@ -476,7 +477,8 @@
                 case CheckStructure:
                 case ForwardCheckStructure:
                 case StructureTransitionWatchpoint:
-                case ForwardStructureTransitionWatchpoint: {
+                case ForwardStructureTransitionWatchpoint:
+                case CheckArray: {
                     // We can just get rid of this node, if it references a phantom argument.
                     if (!isOKToOptimize(m_graph[node.child1()]))
                         break;
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
index ec4edc2..cd3944f 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
@@ -51,6 +51,11 @@
     }
 }
 
+Array::Mode fromStructure(Structure* structure, bool makeSafe)
+{
+    return fromObserved(arrayModeFromStructure(structure), makeSafe);
+}
+
 Array::Mode refineArrayMode(Array::Mode arrayMode, SpeculatedType base, SpeculatedType index)
 {
     if (!base || !index) {
@@ -64,17 +69,8 @@
     if (!isInt32Speculation(index) || !isCellSpeculation(base))
         return Array::Generic;
     
-    // Pass through any array modes that would have been decided by the array profile, since
-    // the predictions of the inputs will not tell us anything useful that we didn't already
-    // get from the array profile.
-    switch (arrayMode) {
-    case Array::ForceExit:
-    case Array::JSArray:
-    case Array::JSArrayOutOfBounds:
+    if (arrayMode != Array::Undecided)
         return arrayMode;
-    default:
-        break;
-    }
     
     if (isStringSpeculation(base))
         return Array::String;
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h
index 6ce62ae..36a8637 100644
--- a/Source/JavaScriptCore/dfg/DFGArrayMode.h
+++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h
@@ -63,12 +63,25 @@
 
 Array::Mode fromObserved(ArrayModes modes, bool makeSafe);
 
+Array::Mode fromStructure(Structure*, bool makeSafe);
+
 Array::Mode refineArrayMode(Array::Mode, SpeculatedType base, SpeculatedType index);
 
 bool modeAlreadyChecked(AbstractValue&, Array::Mode);
 
 const char* modeToString(Array::Mode);
 
+inline bool modeIsJSArray(Array::Mode arrayMode)
+{
+    switch (arrayMode) {
+    case Array::JSArray:
+    case Array::JSArrayOutOfBounds:
+        return true;
+    default:
+        return false;
+    }
+}
+
 inline bool canCSEStorage(Array::Mode arrayMode)
 {
     switch (arrayMode) {
@@ -82,6 +95,11 @@
     }
 }
 
+inline bool lengthNeedsStorage(Array::Mode arrayMode)
+{
+    return modeIsJSArray(arrayMode);
+}
+
 inline Array::Mode modeForPut(Array::Mode arrayMode)
 {
     switch (arrayMode) {
@@ -115,7 +133,7 @@
     return false;
 }
 
-inline bool modeSupportsLength(Array::Mode mode)
+inline bool modeIsSpecific(Array::Mode mode)
 {
     switch (mode) {
     case Array::Undecided:
@@ -127,6 +145,11 @@
     }
 }
 
+inline bool modeSupportsLength(Array::Mode mode)
+{
+    return modeIsSpecific(mode);
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index e37ffb3..df19c30 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -71,6 +71,7 @@
         , m_inlineStackTop(0)
         , m_haveBuiltOperandMaps(false)
         , m_emptyJSValueIndex(UINT_MAX)
+        , m_currentInstruction(0)
     {
         ASSERT(m_profiledBlock);
         
@@ -818,9 +819,14 @@
         return getPrediction(m_graph.size(), m_currentProfilingIndex);
     }
     
-    Array::Mode getArrayModeWithoutOSRExit(Instruction* currentInstruction, NodeIndex base)
+    Array::Mode getArrayMode(ArrayProfile* profile)
     {
-        ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
+        profile->computeUpdatedPrediction();
+        return fromObserved(profile->observedArrayModes(), false);
+    }
+    
+    Array::Mode getArrayModeAndEmitChecks(ArrayProfile* profile, NodeIndex base)
+    {
         profile->computeUpdatedPrediction();
         if (profile->hasDefiniteStructure())
             addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
@@ -838,16 +844,6 @@
         return fromObserved(profile->observedArrayModes(), makeSafe);
     }
     
-    Array::Mode getArrayMode(Instruction* currentInstruction, NodeIndex base)
-    {
-        Array::Mode result = getArrayModeWithoutOSRExit(currentInstruction, base);
-        
-        if (result == Array::ForceExit)
-            addToGraph(ForceOSRExit);
-        
-        return result;
-    }
-
     NodeIndex makeSafe(NodeIndex nodeIndex)
     {
         Node& node = m_graph[nodeIndex];
@@ -1150,6 +1146,8 @@
     
     // Cache of code blocks that we've generated bytecode for.
     ByteCodeCache<canInlineFunctionFor> m_codeBlockCache;
+    
+    Instruction* m_currentInstruction;
 };
 
 #define NEXT_OPCODE(name) \
@@ -1553,7 +1551,10 @@
         if (argumentCountIncludingThis != 2)
             return false;
         
-        NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(0), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
+        Array::Mode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile);
+        if (!modeIsJSArray(arrayMode))
+            return false;
+        NodeIndex arrayPush = addToGraph(ArrayPush, OpInfo(arrayMode), OpInfo(prediction), get(registerOffset + argumentToOperand(0)), get(registerOffset + argumentToOperand(1)));
         if (usesResult)
             set(resultOperand, arrayPush);
         
@@ -1564,7 +1565,10 @@
         if (argumentCountIncludingThis != 1)
             return false;
         
-        NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(0), OpInfo(prediction), get(registerOffset + argumentToOperand(0)));
+        Array::Mode arrayMode = getArrayMode(m_currentInstruction[5].u.arrayProfile);
+        if (!modeIsJSArray(arrayMode))
+            return false;
+        NodeIndex arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode), OpInfo(prediction), get(registerOffset + argumentToOperand(0)));
         if (usesResult)
             set(resultOperand, arrayPop);
         return true;
@@ -1792,6 +1796,7 @@
         
         // Switch on the current bytecode opcode.
         Instruction* currentInstruction = instructionsBegin + m_currentIndex;
+        m_currentInstruction = currentInstruction; // Some methods want to use this, and we'd rather not thread it through calls.
         OpcodeID opcodeID = interpreter->getOpcodeID(currentInstruction->u.opcode);
         switch (opcodeID) {
 
@@ -2177,7 +2182,7 @@
             SpeculatedType prediction = getPrediction();
             
             NodeIndex base = get(currentInstruction[2].u.operand);
-            Array::Mode arrayMode = getArrayMode(currentInstruction, base);
+            Array::Mode arrayMode = getArrayModeAndEmitChecks(currentInstruction[4].u.arrayProfile, base);
             NodeIndex property = get(currentInstruction[3].u.operand);
             NodeIndex getByVal = addToGraph(GetByVal, OpInfo(arrayMode), OpInfo(prediction), base, property);
             set(currentInstruction[1].u.operand, getByVal);
@@ -2188,7 +2193,7 @@
         case op_put_by_val: {
             NodeIndex base = get(currentInstruction[1].u.operand);
 
-            Array::Mode arrayMode = getArrayMode(currentInstruction, base);
+            Array::Mode arrayMode = getArrayModeAndEmitChecks(currentInstruction[4].u.arrayProfile, base);
             
             NodeIndex property = get(currentInstruction[2].u.operand);
             NodeIndex value = get(currentInstruction[3].u.operand);
@@ -2196,6 +2201,7 @@
             addVarArgChild(base);
             addVarArgChild(property);
             addVarArgChild(value);
+            addVarArgChild(NoNode); // Leave room for property storage.
             addToGraph(Node::VarArg, PutByVal, OpInfo(arrayMode), OpInfo(0));
 
             NEXT_OPCODE(op_put_by_val);
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index aecce83..e0d9739 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -659,8 +659,10 @@
                 if (node.flags() & NodeHasVarArgs) {
                     for (unsigned childIdx = node.firstChild();
                          childIdx < node.firstChild() + node.numChildren();
-                         ++childIdx)
-                        fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef);
+                         ++childIdx) {
+                        if (!!m_graph.m_varArgChildren[childIdx])
+                            fixPossibleGetLocal(firstBlock, m_graph.m_varArgChildren[childIdx], changeRef);
+                    }
                 } else if (!!node.child1()) {
                     fixPossibleGetLocal(firstBlock, node.children.child1(), changeRef);
                     if (!!node.child2()) {
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index dce57d5..b368197 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -35,9 +35,8 @@
 
 class CSEPhase : public Phase {
 public:
-    CSEPhase(Graph& graph, OptimizationFixpointState fixpointState)
+    CSEPhase(Graph& graph)
         : Phase(graph, "common subexpression elimination")
-        , m_fixpointState(fixpointState)
     {
         // Replacements are used to implement local common subexpression elimination.
         m_replacements.resize(m_graph.size());
@@ -327,7 +326,7 @@
         return false;
     }
 
-    bool checkStructureLoadElimination(const StructureSet& structureSet, NodeIndex child1)
+    bool checkStructureElimination(const StructureSet& structureSet, NodeIndex child1)
     {
         for (unsigned i = m_indexInBlock; i--;) {
             NodeIndex index = m_currentBlock->at(i);
@@ -624,8 +623,37 @@
         }
         return NoNode;
     }
+    
+    bool checkArrayElimination(NodeIndex child1, Array::Mode arrayMode)
+    {
+        for (unsigned i = m_indexInBlock; i--;) {
+            NodeIndex index = m_currentBlock->at(i);
+            if (index == child1) 
+                break;
 
-    NodeIndex getIndexedPropertyStorageLoadElimination(NodeIndex child1, bool hasIntegerIndexPrediction)
+            Node& node = m_graph[index];
+            switch (node.op()) {
+            case PutByOffset:
+            case PutStructure:
+                // Changing the structure or putting to the storage cannot
+                // change the property storage pointer.
+                break;
+                
+            case CheckArray:
+                if (node.child1() == child1 && node.arrayMode() == arrayMode)
+                    return true;
+                break;
+                
+            default:
+                if (m_graph.clobbersWorld(index))
+                    return false;
+                break;
+            }
+        }
+        return false;
+    }
+
+    NodeIndex getIndexedPropertyStorageLoadElimination(NodeIndex child1, Array::Mode arrayMode)
     {
         for (unsigned i = m_indexInBlock; i--;) {
             NodeIndex index = m_currentBlock->at(i);
@@ -635,9 +663,7 @@
             Node& node = m_graph[index];
             switch (node.op()) {
             case GetIndexedPropertyStorage: {
-                SpeculatedType basePrediction = m_graph[node.child2()].prediction();
-                bool nodeHasIntegerIndexPrediction = !(!(basePrediction & SpecInt32) && basePrediction);
-                if (node.child1() == child1 && hasIntegerIndexPrediction == nodeHasIntegerIndexPrediction)
+                if (node.child1() == child1 && node.arrayMode() == arrayMode)
                     return index;
                 break;
             }
@@ -988,7 +1014,7 @@
             ASSERT(replacement.variableAccessData() == variableAccessData);
             // FIXME: We should be able to remove SetLocals that can exit; we just need
             // to replace them with appropriate type checks.
-            if (m_fixpointState == FixpointNotConverged) {
+            if (m_graph.m_fixpointState == FixpointNotConverged) {
                 // Need to be conservative at this time; if the SetLocal has any chance of performing
                 // any speculations then we cannot do anything.
                 if (variableAccessData->isCaptured()) {
@@ -1077,7 +1103,7 @@
             
         case PutGlobalVar:
         case PutGlobalVarCheck:
-            if (m_fixpointState == FixpointNotConverged)
+            if (m_graph.m_fixpointState == FixpointNotConverged)
                 break;
             eliminate(globalVarStoreElimination(node.registerPointer()));
             break;
@@ -1103,7 +1129,7 @@
             
         case CheckStructure:
         case ForwardCheckStructure:
-            if (checkStructureLoadElimination(node.structureSet(), node.child1().index()))
+            if (checkStructureElimination(node.structureSet(), node.child1().index()))
                 eliminate();
             break;
             
@@ -1114,7 +1140,7 @@
             break;
             
         case PutStructure:
-            if (m_fixpointState == FixpointNotConverged)
+            if (m_graph.m_fixpointState == FixpointNotConverged)
                 break;
             eliminate(putStructureStoreElimination(node.child1().index()), PhantomPutStructure);
             break;
@@ -1124,10 +1150,13 @@
                 eliminate();
             break;
                 
+        case CheckArray:
+            if (checkArrayElimination(node.child1().index(), node.arrayMode()))
+                eliminate();
+            break;
+            
         case GetIndexedPropertyStorage: {
-            SpeculatedType basePrediction = m_graph[node.child2()].prediction();
-            bool nodeHasIntegerIndexPrediction = !(!(basePrediction & SpecInt32) && basePrediction);
-            setReplacement(getIndexedPropertyStorageLoadElimination(node.child1().index(), nodeHasIntegerIndexPrediction));
+            setReplacement(getIndexedPropertyStorageLoadElimination(node.child1().index(), node.arrayMode()));
             break;
         }
 
@@ -1140,7 +1169,7 @@
             break;
             
         case PutByOffset:
-            if (m_fixpointState == FixpointNotConverged)
+            if (m_graph.m_fixpointState == FixpointNotConverged)
                 break;
             eliminate(putByOffsetStoreElimination(m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber, node.child1().index()));
             break;
@@ -1178,14 +1207,13 @@
     unsigned m_indexInBlock;
     Vector<NodeIndex, 16> m_replacements;
     FixedArray<unsigned, LastNodeType> m_lastSeen;
-    OptimizationFixpointState m_fixpointState;
     bool m_changed; // Only tracks changes that have a substantive effect on other optimizations.
 };
 
-bool performCSE(Graph& graph, OptimizationFixpointState fixpointState)
+bool performCSE(Graph& graph)
 {
     SamplingRegion samplingRegion("DFG CSE Phase");
-    return runPhase<CSEPhase>(graph, fixpointState);
+    return runPhase<CSEPhase>(graph);
 }
 
 } } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.h b/Source/JavaScriptCore/dfg/DFGCSEPhase.h
index 7e33c22..017bf5a 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.h
@@ -41,7 +41,7 @@
 // a wide range of subexpression similarities. It's known to produce big wins
 // on a few benchmarks, and is relatively cheap to run.
 
-bool performCSE(Graph&, OptimizationFixpointState);
+bool performCSE(Graph&);
 
 } } // namespace JSC::DFG
 
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index 1a64a24..ddbefd2 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -132,7 +132,7 @@
 
 enum NoResultTag { NoResult };
 
-enum OptimizationFixpointState { FixpointConverged, FixpointNotConverged };
+enum OptimizationFixpointState { BeforeFixpoint, FixpointNotConverged, FixpointConverged };
 
 inline bool shouldShowDisassembly()
 {
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index 68d5534..dfb62cb 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -101,7 +101,16 @@
                     node.convertToStructureTransitionWatchpoint(structureValue.singleton());
                 break;
             }
-                    
+                
+            case CheckArray: {
+                if (!modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode()))
+                    break;
+                ASSERT(node.refCount() == 1);
+                node.setOpAndDefaultFlags(Phantom);
+                eliminated = true;
+                break;
+            }
+                
             default:
                 break;
             }
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index a6f06ae..be643ed 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -116,6 +116,7 @@
     performFixup(dfg);
     performStructureCheckHoisting(dfg);
     unsigned cnt = 1;
+    dfg.m_fixpointState = FixpointNotConverged;
     for (;; ++cnt) {
 #if DFG_ENABLE(DEBUG_VERBOSE)
         dataLog("DFG beginning optimization fixpoint iteration #%u.\n", cnt);
@@ -125,13 +126,14 @@
         changed |= performConstantFolding(dfg);
         changed |= performArgumentsSimplification(dfg);
         changed |= performCFGSimplification(dfg);
-        changed |= performCSE(dfg, FixpointNotConverged);
+        changed |= performCSE(dfg);
         if (!changed)
             break;
         dfg.resetExitStates();
         performFixup(dfg);
     }
-    performCSE(dfg, FixpointConverged);
+    dfg.m_fixpointState = FixpointConverged;
+    performCSE(dfg);
 #if DFG_ENABLE(DEBUG_VERBOSE)
     dataLog("DFG optimization fixpoint converged in %u iterations.\n", cnt);
 #endif
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index fe7cae8..7700b4b 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -74,6 +74,9 @@
         
         switch (op) {
         case GetById: {
+            if (m_graph.m_fixpointState > BeforeFixpoint)
+                break;
+            
             Node* nodePtr = &node;
             
             if (!isInt32Speculation(m_graph[m_compileIndex].prediction()))
@@ -90,8 +93,7 @@
                     fromObserved(arrayProfile->observedArrayModes(), false),
                     m_graph[node.child1()].prediction(),
                     m_graph[m_compileIndex].prediction());                    
-                if (modeSupportsLength(arrayMode)
-                    && arrayProfile->hasDefiniteStructure()) {
+                if (modeSupportsLength(arrayMode) && arrayProfile->hasDefiniteStructure()) {
                     m_graph.ref(nodePtr->child1());
                     Node checkStructure(CheckStructure, nodePtr->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), nodePtr->child1().index());
                     checkStructure.ref();
@@ -113,17 +115,16 @@
             nodePtr->clearFlags(NodeMustGenerate);
             m_graph.deref(m_compileIndex);
             nodePtr->setArrayMode(arrayMode);
+            
+            NodeIndex storage = checkArray(arrayMode, nodePtr->codeOrigin, nodePtr->child1().index(), lengthNeedsStorage, nodePtr->shouldGenerate());
+            if (storage == NoNode)
+                break;
+            
+            nodePtr = &m_graph[m_compileIndex];
+            nodePtr->children.child2() = Edge(storage);
             break;
         }
         case GetIndexedPropertyStorage: {
-            node.setArrayMode(
-                refineArrayMode(
-                    node.arrayMode(),
-                    m_graph[node.child1()].prediction(),
-                    m_graph[node.child2()].prediction()));
-            // Predictions should only become more, rather than less, refined. Hence
-            // if we were ever able to CSE the storage pointer for this operation,
-            // then we should always continue to be able to do so.
             ASSERT(canCSEStorage(node.arrayMode()));
             break;
         }
@@ -136,30 +137,19 @@
                     m_graph[node.child1()].prediction(),
                     m_graph[node.child2()].prediction()));
             
-            if (canCSEStorage(node.arrayMode())) {
-                if (node.child3()) {
-                    ASSERT(m_graph[node.child3()].op() == GetIndexedPropertyStorage);
-                    ASSERT(modesCompatibleForStorageLoad(m_graph[node.child3()].arrayMode(), node.arrayMode()));
-                } else {
-                    // Make sure we don't use the node reference after we do the append.
-                    Node getIndexedPropertyStorage(
-                        GetIndexedPropertyStorage, node.codeOrigin, OpInfo(node.arrayMode()),
-                        node.child1().index(), node.child2().index());
-                    NodeIndex getIndexedPropertyStorageIndex = m_graph.size();
-                    node.children.child3() = Edge(getIndexedPropertyStorageIndex);
-                    m_graph.append(getIndexedPropertyStorage);
-                    m_graph.ref(getIndexedPropertyStorageIndex); // Once because it's MustGenerate.
-                    m_graph.ref(getIndexedPropertyStorageIndex); // And again because it's referenced from the GetByVal.
-                    m_insertionSet.append(m_indexInBlock, getIndexedPropertyStorageIndex);
-                }
-            } else {
-                // See above. Continued fixup of the graph should not regress our ability
-                // to speculate.
-                ASSERT(!node.child3());
-            }
+            blessArrayOperation(node.child1(), 2);
             break;
         }
             
+        case ArrayPush: {
+            blessArrayOperation(node.child1(), 2);
+            break;
+        }
+            
+        case ArrayPop: {
+            blessArrayOperation(node.child1(), 1);
+        }
+            
         case ValueToInt32: {
             if (m_graph[node.child1()].shouldSpeculateNumber()
                 && node.mustGenerate()) {
@@ -330,11 +320,18 @@
             Edge child1 = m_graph.varArgChild(node, 0);
             Edge child2 = m_graph.varArgChild(node, 1);
             Edge child3 = m_graph.varArgChild(node, 2);
+
             node.setArrayMode(
                 refineArrayMode(
-                    node.arrayMode(), m_graph[child1].prediction(), m_graph[child2].prediction()));
+                    node.arrayMode(),
+                    m_graph[child1].prediction(),
+                    m_graph[child2].prediction()));
             
-            switch (modeForPut(node.arrayMode())) {
+            blessArrayOperation(child1, 3);
+            
+            Node* nodePtr = &m_graph[m_compileIndex];
+            
+            switch (modeForPut(nodePtr->arrayMode())) {
             case Array::Int8Array:
             case Array::Int16Array:
             case Array::Int32Array:
@@ -368,6 +365,59 @@
 #endif
     }
     
+    NodeIndex checkArray(Array::Mode arrayMode, CodeOrigin codeOrigin, NodeIndex array, bool (*storageCheck)(Array::Mode) = canCSEStorage, bool shouldGenerate = true)
+    {
+        ASSERT(modeIsSpecific(arrayMode));
+        
+        m_graph.ref(array);
+        Node checkArray(CheckArray, codeOrigin, OpInfo(arrayMode), array);
+        checkArray.ref();
+        NodeIndex checkArrayIndex = m_graph.size();
+        m_graph.append(checkArray);
+        m_insertionSet.append(m_indexInBlock, checkArrayIndex);
+
+        if (!storageCheck(arrayMode))
+            return NoNode;
+        
+        if (shouldGenerate)
+            m_graph.ref(array);
+        Node getIndexedPropertyStorage(
+            GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode), array);
+        if (shouldGenerate)
+            getIndexedPropertyStorage.ref();
+        NodeIndex getIndexedPropertyStorageIndex = m_graph.size();
+        m_graph.append(getIndexedPropertyStorage);
+        m_insertionSet.append(m_indexInBlock, getIndexedPropertyStorageIndex);
+        
+        return getIndexedPropertyStorageIndex;
+    }
+    
+    void blessArrayOperation(Edge base, unsigned storageChildIdx)
+    {
+        if (m_graph.m_fixpointState > BeforeFixpoint)
+            return;
+            
+        Node* nodePtr = &m_graph[m_compileIndex];
+        
+        if (nodePtr->arrayMode() == Array::ForceExit) {
+            Node forceExit(ForceOSRExit, nodePtr->codeOrigin);
+            forceExit.ref();
+            NodeIndex forceExitIndex = m_graph.size();
+            m_graph.append(forceExit);
+            m_insertionSet.append(m_indexInBlock, forceExitIndex);
+            return;
+        }
+        
+        if (!modeIsSpecific(nodePtr->arrayMode()))
+            return;
+            
+        NodeIndex storage = checkArray(nodePtr->arrayMode(), nodePtr->codeOrigin, base.index());
+        if (storage == NoNode)
+            return;
+            
+        m_graph.child(m_graph[m_compileIndex], storageChildIdx) = Edge(storage);
+    }
+    
     void fixIntEdge(Edge& edge)
     {
         Node& node = m_graph[edge];
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 8e80ff2..88fe8c8 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -40,6 +40,18 @@
 #undef STRINGIZE_DFG_OP_ENUM
 };
 
+Graph::Graph(JSGlobalData& globalData, CodeBlock* codeBlock, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
+    : m_globalData(globalData)
+    , m_codeBlock(codeBlock)
+    , m_profiledBlock(codeBlock->alternative())
+    , m_hasArguments(false)
+    , m_osrEntryBytecodeIndex(osrEntryBytecodeIndex)
+    , m_mustHandleValues(mustHandleValues)
+    , m_fixpointState(BeforeFixpoint)
+{
+    ASSERT(m_profiledBlock);
+}
+
 const char *Graph::opName(NodeType op)
 {
     return dfgOpNames[op];
@@ -179,6 +191,8 @@
                 dataLog(", ");
             else
                 hasPrinted = true;
+            if (!m_varArgChildren[childIdx])
+                continue;
             dataLog("%s@%u%s",
                     useKindToString(m_varArgChildren[childIdx].useKind()),
                     m_varArgChildren[childIdx].index(),
@@ -392,8 +406,10 @@
         if (_node.flags() & NodeHasVarArgs) {                           \
             for (unsigned _childIdx = _node.firstChild();               \
                  _childIdx < _node.firstChild() + _node.numChildren();  \
-                 _childIdx++)                                           \
-                thingToDo(m_varArgChildren[_childIdx]);                 \
+                 _childIdx++) {                                         \
+                if (!!m_varArgChildren[_childIdx])                      \
+                    thingToDo(m_varArgChildren[_childIdx]);             \
+            }                                                           \
         } else {                                                        \
             if (!_node.child1()) {                                      \
                 ASSERT(!_node.child2()                                  \
@@ -483,6 +499,8 @@
             for (unsigned childIdx = node.firstChild();
                  childIdx < node.firstChild() + node.numChildren();
                  ++childIdx) {
+                if (!m_varArgChildren[childIdx])
+                    continue;
                 NodeIndex childNodeIndex = m_varArgChildren[childIdx].index();
                 if (!at(childNodeIndex).ref())
                     continue;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index 9d65bc0..70cbbaf 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -68,16 +68,7 @@
 // Nodes that are 'dead' remain in the vector with refCount 0.
 class Graph : public Vector<Node, 64> {
 public:
-    Graph(JSGlobalData& globalData, CodeBlock* codeBlock, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
-        : m_globalData(globalData)
-        , m_codeBlock(codeBlock)
-        , m_profiledBlock(codeBlock->alternative())
-        , m_hasArguments(false)
-        , m_osrEntryBytecodeIndex(osrEntryBytecodeIndex)
-        , m_mustHandleValues(mustHandleValues)
-    {
-        ASSERT(m_profiledBlock);
-    }
+    Graph(JSGlobalData&, CodeBlock*, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues);
     
     using Vector<Node, 64>::operator[];
     using Vector<Node, 64>::at;
@@ -577,8 +568,10 @@
         if (node.flags() & NodeHasVarArgs) {
             for (unsigned childIdx = node.firstChild();
                  childIdx < node.firstChild() + node.numChildren();
-                 childIdx++)
-                vote(m_varArgChildren[childIdx], ballot);
+                 childIdx++) {
+                if (!!m_varArgChildren[childIdx])
+                    vote(m_varArgChildren[childIdx], ballot);
+            }
             return;
         }
         
@@ -600,8 +593,10 @@
             NodeIndex nodeIndex = block[indexInBlock];
             Node& node = at(nodeIndex);
             if (node.flags() & NodeHasVarArgs) {
-                for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx)
-                    compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing, node.shouldGenerate());
+                for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); ++childIdx) {
+                    if (!!m_varArgChildren[childIdx])
+                        compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing, node.shouldGenerate());
+                }
                 continue;
             }
             if (!node.child1())
@@ -677,6 +672,8 @@
     unsigned m_parameterSlots;
     unsigned m_osrEntryBytecodeIndex;
     Operands<JSValue> m_mustHandleValues;
+    
+    OptimizationFixpointState m_fixpointState;
 private:
     
     void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 7ca4d8d4..946a5f79 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -743,6 +743,9 @@
         case GetByVal:
         case StringCharAt:
         case StringCharCodeAt:
+        case CheckArray:
+        case ArrayPush:
+        case ArrayPop:
             return true;
         default:
             return false;
@@ -755,10 +758,13 @@
         return static_cast<Array::Mode>(m_opInfo);
     }
     
-    void setArrayMode(Array::Mode arrayMode)
+    bool setArrayMode(Array::Mode arrayMode)
     {
         ASSERT(hasArrayMode());
+        if (this->arrayMode() == arrayMode)
+            return false;
         m_opInfo = arrayMode;
+        return true;
     }
     
     bool hasVirtualRegister()
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index ee5ad90..d86b9b3 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -138,7 +138,8 @@
     macro(AllocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \
     macro(ReallocatePropertyStorage, NodeMustGenerate | NodeDoesNotExit | NodeResultStorage) \
     macro(GetPropertyStorage, NodeResultStorage) \
-    macro(GetIndexedPropertyStorage, NodeMustGenerate | NodeResultStorage) \
+    macro(CheckArray, NodeMustGenerate) \
+    macro(GetIndexedPropertyStorage, NodeResultStorage) \
     macro(GetByOffset, NodeResultJS) \
     macro(PutByOffset, NodeMustGenerate) \
     macro(GetArrayLength, NodeResultInt32) \
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index b5c3b96..1d02005 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -575,6 +575,14 @@
     return JSValue::encode(jsNumber(array->length()));
 }
 
+EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
+{
+    JSGlobalData* globalData = &exec->globalData();
+    NativeCallFrameTracer tracer(globalData, exec);
+    
+    return JSValue::encode(array->pop(exec));
+}
+        
 EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument)
 {
     JSGlobalData& globalData = exec->globalData();
@@ -603,14 +611,6 @@
     return asRegExpObject(base)->test(exec, input);
 }
         
-EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
-{
-    JSGlobalData* globalData = &exec->globalData();
-    NativeCallFrameTracer tracer(globalData, exec);
-    
-    return JSValue::encode(array->pop(exec));
-}
-        
 void DFG_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName)
 {
     JSGlobalData* globalData = &exec->globalData();
diff --git a/Source/JavaScriptCore/dfg/DFGPhase.h b/Source/JavaScriptCore/dfg/DFGPhase.h
index 80fd691..a73d26b 100644
--- a/Source/JavaScriptCore/dfg/DFGPhase.h
+++ b/Source/JavaScriptCore/dfg/DFGPhase.h
@@ -95,13 +95,6 @@
     return runAndLog(phase);
 }
 
-template<typename PhaseType, typename ArgumentType1>
-bool runPhase(Graph& graph, ArgumentType1 arg1)
-{
-    PhaseType phase(graph, arg1);
-    return runAndLog(phase);
-}
-
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 258d119..af57ab8 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -618,7 +618,8 @@
         case GetMyArgumentsLength:
         case GetMyArgumentByVal:
         case PhantomPutStructure:
-        case PhantomArguments: {
+        case PhantomArguments:
+        case CheckArray: {
             // This node should never be visible at this stage of compilation. It is
             // inserted by fixup(), which follows this phase.
             ASSERT_NOT_REACHED();
@@ -703,8 +704,10 @@
         if (node.flags() & NodeHasVarArgs) {
             for (unsigned childIdx = node.firstChild();
                  childIdx < node.firstChild() + node.numChildren();
-                 childIdx++)
-                changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsValue);
+                 childIdx++) {
+                if (!!m_graph.m_varArgChildren[childIdx])
+                    changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsValue);
+            }
         } else {
             if (!node.child1())
                 return changed;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index d742074..ad4cacd 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -295,20 +295,23 @@
     }
 }
 
-const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode, Edge edge, GPRReg baseReg)
+void SpeculativeJIT::checkArray(Node& node)
 {
-    const TypedArrayDescriptor* result = typedArrayDescriptor(arrayMode);
+    ASSERT(modeIsSpecific(node.arrayMode()));
     
-    if (modeAlreadyChecked(m_state.forNode(edge), arrayMode))
-        return result;
+    SpeculateCellOperand base(this, node.child1());
+    GPRReg baseReg = base.gpr();
+    
+    const TypedArrayDescriptor* result = typedArrayDescriptor(node.arrayMode());
+    
+    if (modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode())) {
+        noResult(m_compileIndex);
+        return;
+    }
     
     const ClassInfo* expectedClassInfo = 0;
     
-    switch (arrayMode) {
-    case Array::ForceExit:
-        ASSERT_NOT_REACHED();
-        terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
-        return result;
+    switch (node.arrayMode()) {
     case Array::String:
         expectedClassInfo = &JSString::s_info;
         break;
@@ -325,7 +328,9 @@
                 MacroAssembler::NotEqual,
                 MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
                 MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
-        return result;
+        
+        noResult(m_compileIndex);
+        return;
     }
     case Array::Arguments:
         expectedClassInfo = &Arguments::s_info;
@@ -356,7 +361,7 @@
             MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
             MacroAssembler::TrustedImmPtr(expectedClassInfo)));
     
-    return result;
+    noResult(m_compileIndex);
 }
 
 GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
@@ -393,8 +398,10 @@
 void SpeculativeJIT::useChildren(Node& node)
 {
     if (node.flags() & NodeHasVarArgs) {
-        for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
-            use(m_jit.graph().m_varArgChildren[childIdx]);
+        for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++) {
+            if (!!m_jit.graph().m_varArgChildren[childIdx])
+                use(m_jit.graph().m_varArgChildren[childIdx]);
+        }
     } else {
         Edge child1 = node.child1();
         if (!child1) {
@@ -2146,6 +2153,9 @@
 
 void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySignedness signedness, TypedArrayRounding rounding)
 {
+    StorageOperand storage(this, m_jit.graph().varArgChild(node, 3));
+    GPRReg storageReg = storage.gpr();
+    
     Edge valueUse = m_jit.graph().varArgChild(node, 2);
     
     GPRTemporary value;
@@ -2213,10 +2223,7 @@
     }
     ASSERT_UNUSED(valueGPR, valueGPR != property);
     ASSERT(valueGPR != base);
-    GPRTemporary storage(this);
-    GPRReg storageReg = storage.gpr();
     ASSERT(valueGPR != storageReg);
-    m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg);
     MacroAssembler::Jump outOfBounds;
     if (node.op() == PutByVal)
         outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset));
@@ -2278,6 +2285,9 @@
 
 void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize)
 {
+    StorageOperand storage(this, m_jit.graph().varArgChild(node, 3));
+    GPRReg storageReg = storage.gpr();
+    
     Edge baseUse = m_jit.graph().varArgChild(node, 0);
     Edge valueUse = m_jit.graph().varArgChild(node, 2);
     
@@ -2287,10 +2297,6 @@
     
     GPRTemporary result(this);
     
-    GPRTemporary storage(this);
-    GPRReg storageReg = storage.gpr();
-    
-    m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg);
     MacroAssembler::Jump outOfBounds;
     if (node.op() == PutByVal)
         outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset));
@@ -3109,8 +3115,7 @@
     GPRTemporary storage(this);
     GPRReg storageReg = storage.gpr();
     
-    const TypedArrayDescriptor* descriptor =
-        speculateArray(node.arrayMode(), node.child1(), baseReg);
+    const TypedArrayDescriptor* descriptor = typedArrayDescriptor(node.arrayMode());
     
     switch (node.arrayMode()) {
     case Array::String:
@@ -3252,33 +3257,40 @@
 
 void SpeculativeJIT::compileGetArrayLength(Node& node)
 {
-    SpeculateCellOperand base(this, node.child1());
-    GPRTemporary result(this);
-        
-    GPRReg baseGPR = base.gpr();
-    GPRReg resultGPR = result.gpr();
-        
-    const TypedArrayDescriptor* descriptor =
-        speculateArray(node.arrayMode(), node.child1(), baseGPR);
+    const TypedArrayDescriptor* descriptor = typedArrayDescriptor(node.arrayMode());
 
     switch (node.arrayMode()) {
     case Array::JSArray:
-    case Array::JSArrayOutOfBounds:
-        m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);
-        m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR);
+    case Array::JSArrayOutOfBounds: {
+        StorageOperand storage(this, node.child2());
+        GPRTemporary result(this, storage);
+        GPRReg storageReg = storage.gpr();
+        GPRReg resultReg = result.gpr();
+        m_jit.load32(MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultReg);
             
-        speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0)));
+        speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultReg, MacroAssembler::TrustedImm32(0)));
             
-        integerResult(resultGPR, m_compileIndex);
+        integerResult(resultReg, m_compileIndex);
         break;
-    case Array::String:
+    }
+    case Array::String: {
+        SpeculateCellOperand base(this, node.child1());
+        GPRTemporary result(this, base);
+        GPRReg baseGPR = base.gpr();
+        GPRReg resultGPR = result.gpr();
         m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR);
         integerResult(resultGPR, m_compileIndex);
         break;
-    case Array::Arguments:
+    }
+    case Array::Arguments: {
         compileGetArgumentsLength(node);
         break;
+    }
     default:
+        SpeculateCellOperand base(this, node.child1());
+        GPRTemporary result(this, base);
+        GPRReg baseGPR = base.gpr();
+        GPRReg resultGPR = result.gpr();
         ASSERT(descriptor);
         m_jit.load32(MacroAssembler::Address(baseGPR, descriptor->m_lengthOffset), resultGPR);
         integerResult(resultGPR, m_compileIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 69a30a9..92a3bb9 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2197,7 +2197,7 @@
     
     const TypedArrayDescriptor* typedArrayDescriptor(Array::Mode);
     
-    const TypedArrayDescriptor* speculateArray(Array::Mode, Edge baseEdge, GPRReg baseReg);
+    void checkArray(Node&);
     
     template<bool strict>
     GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 82d86a4..23623e1 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2373,6 +2373,11 @@
         compileGetByValOnString(node);
         break;
     }
+        
+    case CheckArray: {
+        checkArray(node);
+        break;
+    }
 
     case GetByVal: {
         switch (node.arrayMode()) {
@@ -2470,6 +2475,7 @@
         Edge child1 = m_jit.graph().varArgChild(node, 0);
         Edge child2 = m_jit.graph().varArgChild(node, 1);
         Edge child3 = m_jit.graph().varArgChild(node, 2);
+        Edge child4 = m_jit.graph().varArgChild(node, 3);
         
         Array::Mode arrayMode = modeForPut(node.arrayMode());
         bool alreadyHandled = false;
@@ -2513,8 +2519,6 @@
         GPRReg baseReg = base.gpr();
         GPRReg propertyReg = property.gpr();
 
-        speculateArray(arrayMode, child1, baseReg);
-
         switch (arrayMode) {
         case Array::JSArray:
         case Array::JSArrayOutOfBounds: {
@@ -2531,13 +2535,11 @@
                 GPRReg scratchReg = scratch.gpr();
                 writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg);
             }
+            
+            StorageOperand storage(this, child4);
+            GPRReg storageReg = storage.gpr();
 
             if (node.op() == PutByValAlias) {
-                // Get the array storage.
-                GPRTemporary storage(this);
-                GPRReg storageReg = storage.gpr();
-                m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-                
                 // Store the value to the array.
                 GPRReg propertyReg = property.gpr();
                 m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
@@ -2554,12 +2556,8 @@
             base.use();
             property.use();
             value.use();
+            storage.use();
             
-            // Get the array storage.
-            GPRTemporary storage(this);
-            GPRReg storageReg = storage.gpr();
-            m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-
             // Check if we're writing to a hole; if so increment m_numValuesInVector.
             MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
             m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
@@ -2688,6 +2686,8 @@
     }
         
     case ArrayPush: {
+        ASSERT(modeIsJSArray(node.arrayMode()));
+        
         SpeculateCellOperand base(this, node.child1());
         JSValueOperand value(this, node.child2());
         GPRTemporary storageLength(this);
@@ -2697,17 +2697,14 @@
         GPRReg valuePayloadGPR = value.payloadGPR();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        {
+        if (Heap::isWriteBarrierEnabled()) {
             GPRTemporary scratch(this);
             writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
         }
 
-        speculateArray(Array::JSArray, node.child1(), baseGPR);
-        
-        GPRTemporary storage(this);
+        StorageOperand storage(this, node.child3());
         GPRReg storageGPR = storage.gpr();
 
-        m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
         m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
         
         // Refuse to handle bizarre lengths.
@@ -2730,10 +2727,12 @@
     }
         
     case ArrayPop: {
+        ASSERT(modeIsJSArray(node.arrayMode()));
+        
         SpeculateCellOperand base(this, node.child1());
+        StorageOperand storage(this, node.child2());
         GPRTemporary valueTag(this);
         GPRTemporary valuePayload(this);
-        GPRTemporary storage(this);
         GPRTemporary storageLength(this);
         
         GPRReg baseGPR = base.gpr();
@@ -2742,9 +2741,6 @@
         GPRReg storageGPR = storage.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        speculateArray(Array::JSArray, node.child1(), baseGPR);
-        
-        m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
         m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
         
         JITCompiler::JumpList setUndefinedCases;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index ab3e184..88b9a47 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2406,6 +2406,11 @@
         compileGetByValOnString(node);
         break;
     }
+        
+    case CheckArray: {
+        checkArray(node);
+        break;
+    }
 
     case GetByVal: {
         switch (node.arrayMode()) {
@@ -2497,6 +2502,7 @@
         Edge child1 = m_jit.graph().varArgChild(node, 0);
         Edge child2 = m_jit.graph().varArgChild(node, 1);
         Edge child3 = m_jit.graph().varArgChild(node, 2);
+        Edge child4 = m_jit.graph().varArgChild(node, 3);
         
         Array::Mode arrayMode = modeForPut(node.arrayMode());
         bool alreadyHandled = false;
@@ -2538,27 +2544,26 @@
         GPRReg baseReg = base.gpr();
         GPRReg propertyReg = property.gpr();
 
-        speculateArray(arrayMode, child1, baseReg);
-
         switch (arrayMode) {
         case Array::JSArray:
         case Array::JSArrayOutOfBounds: {
             JSValueOperand value(this, child3);
-            GPRTemporary scratch(this);
 
             // Map base, property & value into registers, allocate a scratch register.
             GPRReg valueReg = value.gpr();
-            GPRReg scratchReg = scratch.gpr();
         
             if (!m_compileOkay)
                 return;
         
-            writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg);
+            if (Heap::isWriteBarrierEnabled()) {
+                GPRTemporary scratch(this);
+                writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratch.gpr());
+            }
+
+            StorageOperand storage(this, child4);
+            GPRReg storageReg = storage.gpr();
 
             if (node.op() == PutByValAlias) {
-                GPRReg storageReg = scratchReg;
-                m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-                
                 // Store the value to the array.
                 GPRReg propertyReg = property.gpr();
                 GPRReg valueReg = value.gpr();
@@ -2575,11 +2580,8 @@
             base.use();
             property.use();
             value.use();
+            storage.use();
         
-            // Get the array storage.
-            GPRReg storageReg = scratchReg;
-            m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
-
             // Check if we're writing to a hole; if so increment m_numValuesInVector.
             MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
             m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
@@ -2747,21 +2749,24 @@
     }
         
     case ArrayPush: {
+        ASSERT(modeIsJSArray(node.arrayMode()));
+        
         SpeculateCellOperand base(this, node.child1());
         JSValueOperand value(this, node.child2());
-        GPRTemporary storage(this);
         GPRTemporary storageLength(this);
         
         GPRReg baseGPR = base.gpr();
         GPRReg valueGPR = value.gpr();
-        GPRReg storageGPR = storage.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR);
+        if (Heap::isWriteBarrierEnabled()) {
+            GPRTemporary scratch(this);
+            writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR);
+        }
 
-        speculateArray(Array::JSArray, node.child1(), baseGPR);
+        StorageOperand storage(this, node.child3());
+        GPRReg storageGPR = storage.gpr();
 
-        m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
         m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
         
         // Refuse to handle bizarre lengths.
@@ -2786,19 +2791,18 @@
     }
         
     case ArrayPop: {
+        ASSERT(modeIsJSArray(node.arrayMode()));
+
         SpeculateCellOperand base(this, node.child1());
+        StorageOperand storage(this, node.child2());
         GPRTemporary value(this);
-        GPRTemporary storage(this);
         GPRTemporary storageLength(this);
         
         GPRReg baseGPR = base.gpr();
-        GPRReg valueGPR = value.gpr();
         GPRReg storageGPR = storage.gpr();
+        GPRReg valueGPR = value.gpr();
         GPRReg storageLengthGPR = storageLength.gpr();
         
-        speculateArray(Array::JSArray, node.child1(), baseGPR);
-
-        m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR);
         m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR);
         
         JITCompiler::JumpList setUndefinedCases;
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index eb04a67..ee7dd0a 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -99,6 +99,8 @@
                 case PutByVal:
                 case PutByValAlias:
                 case GetArrayLength:
+                case CheckArray:
+                case GetIndexedPropertyStorage:
                 case Phantom:
                     // Don't count these uses.
                     break;