Array type checks and storage accesses should be uniformly represented and available...
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 26 Aug 2012 22:35:26 +0000 (22:35 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 26 Aug 2012 22:35:26 +0000 (22:35 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@126715 268f45cc-cd09-0410-ab3c-d52691b4dbfc

25 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGAbstractState.cpp
Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
Source/JavaScriptCore/dfg/DFGArrayMode.cpp
Source/JavaScriptCore/dfg/DFGArrayMode.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
Source/JavaScriptCore/dfg/DFGCSEPhase.h
Source/JavaScriptCore/dfg/DFGCommon.h
Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
Source/JavaScriptCore/dfg/DFGDriver.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGPhase.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp

index dce55ef..b44b32f 100644 (file)
@@ -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
 
index 43b5a03..aad9786 100644 (file)
@@ -887,12 +887,10 @@ bool AbstractState::execute(unsigned indexInBlock)
             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 @@ bool AbstractState::execute(unsigned indexInBlock)
         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 @@ bool AbstractState::execute(unsigned indexInBlock)
                 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 @@ bool AbstractState::execute(unsigned indexInBlock)
     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 @@ bool AbstractState::execute(unsigned indexInBlock)
             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 @@ bool AbstractState::execute(unsigned indexInBlock)
                 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 @@ bool AbstractState::execute(unsigned indexInBlock)
                 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 @@ bool AbstractState::execute(unsigned indexInBlock)
                 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 @@ bool AbstractState::execute(unsigned indexInBlock)
                 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 @@ bool AbstractState::execute(unsigned indexInBlock)
                 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 @@ bool AbstractState::execute(unsigned indexInBlock)
                 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 @@ bool AbstractState::execute(unsigned indexInBlock)
                 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 @@ bool AbstractState::execute(unsigned indexInBlock)
             
     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 @@ bool AbstractState::execute(unsigned indexInBlock)
         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 @@ bool AbstractState::execute(unsigned indexInBlock)
         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 @@ bool AbstractState::execute(unsigned indexInBlock)
             // 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 @@ bool AbstractState::execute(unsigned indexInBlock)
             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; 
     }
index 2f535ba..640a0a9 100644 (file)
@@ -312,6 +312,7 @@ public:
                 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 @@ public:
                 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;
index ec4edc2..cd3944f 100644 (file)
@@ -51,6 +51,11 @@ Array::Mode fromObserved(ArrayModes modes, bool makeSafe)
     }
 }
 
+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 @@ Array::Mode refineArrayMode(Array::Mode arrayMode, SpeculatedType base, Speculat
     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;
index 6ce62ae..36a8637 100644 (file)
@@ -63,12 +63,25 @@ enum Mode {
 
 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 canCSEStorage(Array::Mode arrayMode)
     }
 }
 
+inline bool lengthNeedsStorage(Array::Mode arrayMode)
+{
+    return modeIsJSArray(arrayMode);
+}
+
 inline Array::Mode modeForPut(Array::Mode arrayMode)
 {
     switch (arrayMode) {
@@ -115,7 +133,7 @@ inline bool modesCompatibleForStorageLoad(Array::Mode left, Array::Mode right)
     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)
     }
 }
 
+inline bool modeSupportsLength(Array::Mode mode)
+{
+    return modeIsSpecific(mode);
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)
index e37ffb3..df19c30 100644 (file)
@@ -71,6 +71,7 @@ public:
         , m_inlineStackTop(0)
         , m_haveBuiltOperandMaps(false)
         , m_emptyJSValueIndex(UINT_MAX)
+        , m_currentInstruction(0)
     {
         ASSERT(m_profiledBlock);
         
@@ -818,9 +819,14 @@ private:
         return getPrediction(m_graph.size(), m_currentProfilingIndex);
     }
     
-    Array::Mode getArrayModeWithoutOSRExit(Instruction* currentInstruction, NodeIndex base)
+    Array::Mode getArrayMode(ArrayProfile* profile)
+    {
+        profile->computeUpdatedPrediction();
+        return fromObserved(profile->observedArrayModes(), false);
+    }
+    
+    Array::Mode getArrayModeAndEmitChecks(ArrayProfile* profile, NodeIndex base)
     {
-        ArrayProfile* profile = currentInstruction[4].u.arrayProfile;
         profile->computeUpdatedPrediction();
         if (profile->hasDefiniteStructure())
             addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base);
@@ -838,16 +844,6 @@ private:
         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 @@ private:
     
     // 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 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
         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 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins
         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 @@ bool ByteCodeParser::parseBlock(unsigned limit)
         
         // 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 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             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 @@ bool ByteCodeParser::parseBlock(unsigned limit)
         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 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             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);
index aecce83..e0d9739 100644 (file)
@@ -659,8 +659,10 @@ private:
                 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()) {
index dce57d5..b368197 100644 (file)
@@ -35,9 +35,8 @@ namespace JSC { namespace DFG {
 
 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 @@ private:
         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 @@ private:
         }
         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 @@ private:
             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 @@ private:
             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 @@ private:
             
         case PutGlobalVar:
         case PutGlobalVarCheck:
-            if (m_fixpointState == FixpointNotConverged)
+            if (m_graph.m_fixpointState == FixpointNotConverged)
                 break;
             eliminate(globalVarStoreElimination(node.registerPointer()));
             break;
@@ -1103,7 +1129,7 @@ private:
             
         case CheckStructure:
         case ForwardCheckStructure:
-            if (checkStructureLoadElimination(node.structureSet(), node.child1().index()))
+            if (checkStructureElimination(node.structureSet(), node.child1().index()))
                 eliminate();
             break;
             
@@ -1114,7 +1140,7 @@ private:
             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 @@ private:
                 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 @@ private:
             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 @@ private:
     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
index 7e33c22..017bf5a 100644 (file)
@@ -41,7 +41,7 @@ class Graph;
 // 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
 
index 1a64a24..ddbefd2 100644 (file)
@@ -132,7 +132,7 @@ enum SpillRegistersMode { NeedToSpill, DontSpill };
 
 enum NoResultTag { NoResult };
 
-enum OptimizationFixpointState { FixpointConverged, FixpointNotConverged };
+enum OptimizationFixpointState { BeforeFixpoint, FixpointNotConverged, FixpointConverged };
 
 inline bool shouldShowDisassembly()
 {
index 68d5534..dfb62cb 100644 (file)
@@ -101,7 +101,16 @@ private:
                     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;
             }
index a6f06ae..be643ed 100644 (file)
@@ -116,6 +116,7 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
     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 @@ inline bool compile(CompileMode compileMode, ExecState* exec, CodeBlock* codeBlo
         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
index fe7cae8..7700b4b 100644 (file)
@@ -74,6 +74,9 @@ private:
         
         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 @@ private:
                     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 @@ private:
             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 @@ private:
                     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 @@ private:
             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()));
+            
+            blessArrayOperation(child1, 3);
             
-            switch (modeForPut(node.arrayMode())) {
+            Node* nodePtr = &m_graph[m_compileIndex];
+            
+            switch (modeForPut(nodePtr->arrayMode())) {
             case Array::Int8Array:
             case Array::Int16Array:
             case Array::Int32Array:
@@ -368,6 +365,59 @@ private:
 #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];
index 8e80ff2..88fe8c8 100644 (file)
@@ -40,6 +40,18 @@ static const char* dfgOpNames[] = {
 #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 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex)
                 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 @@ void Graph::dump()
         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 @@ void Graph::collectGarbage()
             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;
index 9d65bc0..70cbbaf 100644 (file)
@@ -68,16 +68,7 @@ struct ResolveGlobalData {
 // 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 @@ public:
         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 @@ public:
             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 @@ public:
     unsigned m_parameterSlots;
     unsigned m_osrEntryBytecodeIndex;
     Operands<JSValue> m_mustHandleValues;
+    
+    OptimizationFixpointState m_fixpointState;
 private:
     
     void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex);
index 7ca4d8d..946a5f7 100644 (file)
@@ -743,6 +743,9 @@ struct Node {
         case GetByVal:
         case StringCharAt:
         case StringCharCodeAt:
+        case CheckArray:
+        case ArrayPush:
+        case ArrayPop:
             return true;
         default:
             return false;
@@ -755,10 +758,13 @@ struct Node {
         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()
index ee5ad90..d86b9b3 100644 (file)
@@ -138,7 +138,8 @@ namespace JSC { namespace DFG {
     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) \
index b5c3b96..1d02005 100644 (file)
@@ -575,6 +575,14 @@ EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue
     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 @@ size_t DFG_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell*
     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();
index 80fd691..a73d26b 100644 (file)
@@ -95,13 +95,6 @@ bool runPhase(Graph& graph)
     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)
index 258d119..af57ab8 100644 (file)
@@ -618,7 +618,8 @@ private:
         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 @@ private:
         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;
index d742074..ad4cacd 100644 (file)
@@ -295,20 +295,23 @@ const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(Array::Mode arr
     }
 }
 
-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 @@ const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode
                 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 @@ const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode
             MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()),
             MacroAssembler::TrustedImmPtr(expectedClassInfo)));
     
-    return result;
+    noResult(m_compileIndex);
 }
 
 GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
@@ -393,8 +398,10 @@ GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
 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::compileGetByValOnIntTypedArray(const TypedArrayDescriptor&
 
 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 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor&
     }
     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::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor
 
 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 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto
     
     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 @@ void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node)
     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::compileGetArgumentsLength(Node& node)
 
 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);
index 69a30a9..92a3bb9 100644 (file)
@@ -2197,7 +2197,7 @@ public:
     
     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);
index 82d86a4..23623e1 100644 (file)
@@ -2373,6 +2373,11 @@ void SpeculativeJIT::compile(Node& node)
         compileGetByValOnString(node);
         break;
     }
+        
+    case CheckArray: {
+        checkArray(node);
+        break;
+    }
 
     case GetByVal: {
         switch (node.arrayMode()) {
@@ -2470,6 +2475,7 @@ void SpeculativeJIT::compile(Node& node)
         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 @@ void SpeculativeJIT::compile(Node& node)
         GPRReg baseReg = base.gpr();
         GPRReg propertyReg = property.gpr();
 
-        speculateArray(arrayMode, child1, baseReg);
-
         switch (arrayMode) {
         case Array::JSArray:
         case Array::JSArrayOutOfBounds: {
@@ -2531,13 +2535,11 @@ void SpeculativeJIT::compile(Node& node)
                 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 @@ void SpeculativeJIT::compile(Node& node)
             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 @@ void SpeculativeJIT::compile(Node& node)
     }
         
     case ArrayPush: {
+        ASSERT(modeIsJSArray(node.arrayMode()));
+        
         SpeculateCellOperand base(this, node.child1());
         JSValueOperand value(this, node.child2());
         GPRTemporary storageLength(this);
@@ -2697,17 +2697,14 @@ void SpeculativeJIT::compile(Node& node)
         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 @@ void SpeculativeJIT::compile(Node& node)
     }
         
     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 @@ void SpeculativeJIT::compile(Node& node)
         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;
index ab3e184..88b9a47 100644 (file)
@@ -2406,6 +2406,11 @@ void SpeculativeJIT::compile(Node& node)
         compileGetByValOnString(node);
         break;
     }
+        
+    case CheckArray: {
+        checkArray(node);
+        break;
+    }
 
     case GetByVal: {
         switch (node.arrayMode()) {
@@ -2497,6 +2502,7 @@ void SpeculativeJIT::compile(Node& node)
         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 @@ void SpeculativeJIT::compile(Node& node)
         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 @@ void SpeculativeJIT::compile(Node& node)
             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 @@ void SpeculativeJIT::compile(Node& node)
     }
         
     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 @@ void SpeculativeJIT::compile(Node& node)
     }
         
     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;
index eb04a67..ee7dd0a 100644 (file)
@@ -99,6 +99,8 @@ public:
                 case PutByVal:
                 case PutByValAlias:
                 case GetArrayLength:
+                case CheckArray:
+                case GetIndexedPropertyStorage:
                 case Phantom:
                     // Don't count these uses.
                     break;