Unreviewed, rolling out r156474.
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGValidate.cpp
index 8e182dd..88bfdd4 100644 (file)
@@ -34,8 +34,6 @@
 
 namespace JSC { namespace DFG {
 
-#if DFG_ENABLE(VALIDATION)
-
 class Validate {
 public:
     Validate(Graph& graph, GraphDumpMode graphDumpMode)
@@ -60,9 +58,9 @@ public:
             dataLogF("\n\n\nAt "); \
             reportValidationContext context; \
             dataLogF(": validation (%s = ", #left); \
-            dumpData(left); \
+            dataLog(left); \
             dataLogF(") == (%s = ", #right); \
-            dumpData(right); \
+            dataLog(right); \
             dataLogF(") (%s:%d) failed.\n", __FILE__, __LINE__); \
             dumpGraphIfAppropriate(); \
             WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #left " == " #right); \
@@ -76,99 +74,194 @@ public:
     {
         // NB. This code is not written for performance, since it is not intended to run
         // in release builds.
-        
+
         // Validate that all local variables at the head of the root block are dead.
-        BasicBlock* root = m_graph.m_blocks[0].get();
+        BasicBlock* root = m_graph.block(0);
         for (unsigned i = 0; i < root->variablesAtHead.numberOfLocals(); ++i)
-            V_EQUAL((static_cast<VirtualRegister>(i), 0), NoNode, root->variablesAtHead.local(i));
+            V_EQUAL((static_cast<VirtualRegister>(localToOperand(i)), 0), static_cast<Node*>(0), root->variablesAtHead.local(i));
         
         // Validate ref counts and uses.
-        Vector<unsigned> myRefCounts;
-        myRefCounts.fill(0, m_graph.size());
-        BitVector acceptableNodeIndices;
-        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
-            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+            BasicBlock* block = m_graph.block(blockIndex);
             if (!block)
                 continue;
-            if (!block->isReachable)
+            VALIDATE((block), block->isReachable);
+            for (size_t i = 0; i < block->numNodes(); ++i)
+                m_myRefCounts.add(block->node(i), 0);
+        }
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            if (!block)
                 continue;
             for (size_t i = 0; i < block->numNodes(); ++i) {
-                NodeIndex nodeIndex = block->nodeIndex(i);
-                acceptableNodeIndices.set(nodeIndex);
-                Node& node = m_graph[nodeIndex];
-                if (!node.shouldGenerate())
+                Node* node = block->node(i);
+                m_acceptableNodes.add(node);
+                if (!node->shouldGenerate())
                     continue;
+                if (node->op() == Upsilon) {
+                    VALIDATE((node), m_graph.m_form == SSA);
+                    if (node->phi()->shouldGenerate())
+                        m_myRefCounts.find(node)->value++;
+                }
                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
+                    // Phi children in LoadStore form are invalid.
+                    if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
+                        continue;
+                    
                     Edge edge = m_graph.child(node, j);
                     if (!edge)
                         continue;
                     
-                    myRefCounts[edge.index()]++;
+                    m_myRefCounts.find(edge.node())->value++;
+                    
+                    if (m_graph.m_form == SSA) {
+                        // In SSA, all edges must hasResult().
+                        VALIDATE((node, edge), edge->hasResult());
+                        continue;
+                    }
                     
                     // Unless I'm a Flush, Phantom, GetLocal, or Phi, my children should hasResult().
-                    switch (node.op()) {
+                    switch (node->op()) {
                     case Flush:
-                    case Phantom:
                     case GetLocal:
+                        VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
+                        VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
+                        break;
+                    case PhantomLocal:
+                        VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
+                        VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
+                        VALIDATE((node, edge), edge->op() != SetLocal);
+                        break;
                     case Phi:
+                        VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
+                        if (m_graph.m_unificationState == LocallyUnified)
+                            break;
+                        VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
+                        break;
+                    case Phantom:
+                        switch (m_graph.m_form) {
+                        case LoadStore:
+                            if (j) {
+                                VALIDATE((node, edge), edge->hasResult());
+                                break;
+                            }
+                            switch (edge->op()) {
+                            case Phi:
+                            case SetArgument:
+                            case SetLocal:
+                                break;
+                            default:
+                                VALIDATE((node, edge), edge->hasResult());
+                                break;
+                            }
+                            break;
+                        case ThreadedCPS:
+                            VALIDATE((node, edge), edge->hasResult());
+                            break;
+                        case SSA:
+                            RELEASE_ASSERT_NOT_REACHED();
+                            break;
+                        }
                         break;
                     default:
-                        VALIDATE((nodeIndex, edge), m_graph[edge].hasResult());
+                        VALIDATE((node, edge), edge->hasResult());
                         break;
                     }
                 }
             }
         }
-        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
-            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+        
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+            BasicBlock* block = m_graph.block(blockIndex);
             if (!block)
                 continue;
-            if (!block->isReachable)
+            for (size_t i = 0; i < block->numNodes(); ++i) {
+                Node* node = block->node(i);
+                if (m_graph.m_refCountState == ExactRefCount)
+                    V_EQUAL((node), m_myRefCounts.get(node), node->adjustedRefCount());
+                else
+                    V_EQUAL((node), node->refCount(), 1);
+            }
+        }
+        
+        switch (m_graph.m_form) {
+        case LoadStore:
+        case ThreadedCPS:
+            validateCPS();
+            break;
+            
+        case SSA:
+            // FIXME: Implement SSA verification.
+            break;
+        }
+    }
+    
+private:
+    Graph& m_graph;
+    GraphDumpMode m_graphDumpMode;
+    
+    HashMap<Node*, unsigned> m_myRefCounts;
+    HashSet<Node*> m_acceptableNodes;
+    
+    void validateCPS()
+    {
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            if (!block)
                 continue;
             
-            BitVector phisInThisBlock;
-            BitVector nodesInThisBlock;
+            HashSet<Node*> phisInThisBlock;
+            HashSet<Node*> nodesInThisBlock;
             
             for (size_t i = 0; i < block->numNodes(); ++i) {
-                NodeIndex nodeIndex = block->nodeIndex(i);
-                Node& node = m_graph[nodeIndex];
-                nodesInThisBlock.set(nodeIndex);
+                Node* node = block->node(i);
+                nodesInThisBlock.add(node);
                 if (block->isPhiIndex(i))
-                    phisInThisBlock.set(nodeIndex);
-                V_EQUAL((nodeIndex), myRefCounts[nodeIndex], node.adjustedRefCount());
+                    phisInThisBlock.add(node);
                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
                     Edge edge = m_graph.child(node, j);
                     if (!edge)
                         continue;
-                    VALIDATE((nodeIndex, edge), acceptableNodeIndices.get(edge.index()));
+                    VALIDATE((node, edge), m_acceptableNodes.contains(edge.node()));
                 }
             }
             
             for (size_t i = 0; i < block->phis.size(); ++i) {
-                NodeIndex nodeIndex = block->phis[i];
-                Node& node = m_graph[nodeIndex];
-                ASSERT(phisInThisBlock.get(nodeIndex));
-                VALIDATE((nodeIndex), node.op() == Phi);
-                VirtualRegister local = node.local();
+                Node* node = block->phis[i];
+                ASSERT(phisInThisBlock.contains(node));
+                VALIDATE((node), node->op() == Phi);
+                VirtualRegister local = node->local();
                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
+                    // Phi children in LoadStore form are invalid.
+                    if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
+                        continue;
+                    
                     Edge edge = m_graph.child(node, j);
                     if (!edge)
                         continue;
                     
-                    VALIDATE((nodeIndex, edge),
-                             m_graph[edge].op() == SetLocal
-                             || m_graph[edge].op() == SetArgument
-                             || m_graph[edge].op() == Flush
-                             || m_graph[edge].op() == Phi);
+                    VALIDATE(
+                        (node, edge),
+                        edge->op() == SetLocal
+                        || edge->op() == SetArgument
+                        || edge->op() == Flush
+                        || edge->op() == Phi
+                        || edge->op() == ZombieHint
+                        || edge->op() == MovHint
+                        || edge->op() == MovHintAndCheck);
                     
-                    if (phisInThisBlock.get(edge.index()))
+                    if (phisInThisBlock.contains(edge.node()))
                         continue;
                     
-                    if (nodesInThisBlock.get(edge.index())) {
-                        VALIDATE((nodeIndex, edge),
-                                 m_graph[edge].op() == SetLocal
-                                 || m_graph[edge].op() == SetArgument
-                                 || m_graph[edge].op() == Flush);
+                    if (nodesInThisBlock.contains(edge.node())) {
+                        VALIDATE(
+                            (node, edge),
+                            edge->op() == SetLocal
+                            || edge->op() == ZombieHint
+                            || edge->op() == MovHint
+                            || edge->op() == MovHintAndCheck
+                            || edge->op() == SetArgument
+                            || edge->op() == Flush);
                         
                         continue;
                     }
@@ -176,37 +269,43 @@ public:
                     // There must exist a predecessor block that has this node index in
                     // its tail variables.
                     bool found = false;
-                    for (unsigned k = 0; k < block->m_predecessors.size(); ++k) {
-                        BasicBlock* prevBlock = m_graph.m_blocks[block->m_predecessors[k]].get();
-                        VALIDATE((Block, block->m_predecessors[k]), prevBlock);
-                        VALIDATE((Block, block->m_predecessors[k]), prevBlock->isReachable);
-                        NodeIndex prevNodeIndex = prevBlock->variablesAtTail.operand(local);
+                    for (unsigned k = 0; k < block->predecessors.size(); ++k) {
+                        BasicBlock* prevBlock = block->predecessors[k];
+                        VALIDATE((block->predecessors[k]), prevBlock);
+                        Node* prevNode = prevBlock->variablesAtTail.operand(local);
                         // If we have a Phi that is not referring to *this* block then all predecessors
                         // must have that local available.
-                        VALIDATE((local, blockIndex, Block, block->m_predecessors[k]), prevNodeIndex != NoNode);
-                        Node* prevNode = &m_graph[prevNodeIndex];
-                        if (prevNode->op() == GetLocal) {
-                            prevNodeIndex = prevNode->child1().index();
-                            prevNode = &m_graph[prevNodeIndex];
+                        VALIDATE((local, block, block->predecessors[k]), prevNode);
+                        switch (prevNode->op()) {
+                        case GetLocal:
+                        case Flush:
+                        case PhantomLocal:
+                            prevNode = prevNode->child1().node();
+                            break;
+                        default:
+                            break;
                         }
-                        if (node.shouldGenerate()) {
-                            VALIDATE((local, block->m_predecessors[k], prevNodeIndex),
+                        if (node->shouldGenerate()) {
+                            VALIDATE((local, block->predecessors[k], prevNode),
                                      prevNode->shouldGenerate());
                         }
-                        VALIDATE((local, block->m_predecessors[k], prevNodeIndex),
-                                 prevNode->op() == SetLocal
-                                 || prevNode->op() == SetArgument
-                                 || prevNode->op() == Flush
-                                 || prevNode->op() == Phi);
-                        if (prevNodeIndex == edge.index()) {
+                        VALIDATE(
+                            (local, block->predecessors[k], prevNode),
+                            prevNode->op() == SetLocal
+                            || prevNode->op() == MovHint
+                            || prevNode->op() == MovHintAndCheck
+                            || prevNode->op() == ZombieHint
+                            || prevNode->op() == SetArgument
+                            || prevNode->op() == Phi);
+                        if (prevNode == edge.node()) {
                             found = true;
                             break;
                         }
                         // At this point it cannot refer into this block.
-                        VALIDATE((local, block->m_predecessors[k], prevNodeIndex), !prevBlock->isInBlock(edge.index()));
+                        VALIDATE((local, block->predecessors[k], prevNode), !prevBlock->isInBlock(edge.node()));
                     }
                     
-                    VALIDATE((nodeIndex, edge), found);
+                    VALIDATE((node, edge), found);
                 }
             }
             
@@ -218,66 +317,89 @@ public:
                 block->variablesAtHead.numberOfLocals());
             
             for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
+                VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), block), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->hasVariableAccessData(m_graph));
+                if (m_graph.m_form == ThreadedCPS)
+                    VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), block), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->hasVariableAccessData(m_graph));
+                
                 getLocalPositions.argument(i) = notSet;
                 setLocalPositions.argument(i) = notSet;
             }
             for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
+                VALIDATE((static_cast<VirtualRegister>(localToOperand(i)), block), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->hasVariableAccessData(m_graph));
+                if (m_graph.m_form == ThreadedCPS)
+                    VALIDATE((static_cast<VirtualRegister>(localToOperand(i)), block), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->hasVariableAccessData(m_graph));
+
                 getLocalPositions.local(i) = notSet;
                 setLocalPositions.local(i) = notSet;
             }
             
             for (size_t i = 0; i < block->size(); ++i) {
-                NodeIndex nodeIndex = block->at(i);
-                Node& node = m_graph[nodeIndex];
-                ASSERT(nodesInThisBlock.get(nodeIndex));
-                VALIDATE((nodeIndex), node.op() != Phi);
+                Node* node = block->at(i);
+                ASSERT(nodesInThisBlock.contains(node));
+                VALIDATE((node), node->op() != Phi);
                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
                     Edge edge = m_graph.child(node, j);
                     if (!edge)
                         continue;
-                    VALIDATE((nodeIndex, edge), nodesInThisBlock.get(nodeIndex));
+                    VALIDATE((node, edge), nodesInThisBlock.contains(edge.node()));
+                    switch (node->op()) {
+                    case PhantomLocal:
+                    case GetLocal:
+                    case Flush:
+                        break;
+                    case Phantom:
+                        if (m_graph.m_form == LoadStore && !j)
+                            break;
+                    default:
+                        VALIDATE((node, edge), !phisInThisBlock.contains(edge.node()));
+                        break;
+                    }
                 }
                 
-                if (!node.shouldGenerate())
+                if (!node->shouldGenerate())
                     continue;
-                switch (node.op()) {
+                switch (node->op()) {
                 case GetLocal:
-                    if (node.variableAccessData()->isCaptured())
+                    if (node->variableAccessData()->isCaptured())
                         break;
-                    VALIDATE((nodeIndex, blockIndex), getLocalPositions.operand(node.local()) == notSet);
-                    getLocalPositions.operand(node.local()) = i;
+                    // Ignore GetLocal's that we know to be dead, but that the graph
+                    // doesn't yet know to be dead.
+                    if (!m_myRefCounts.get(node))
+                        break;
+                    if (m_graph.m_form == ThreadedCPS)
+                        VALIDATE((node, block), getLocalPositions.operand(node->local()) == notSet);
+                    getLocalPositions.operand(node->local()) = i;
                     break;
                 case SetLocal:
-                    if (node.variableAccessData()->isCaptured())
+                    if (node->variableAccessData()->isCaptured())
                         break;
                     // Only record the first SetLocal. There may be multiple SetLocals
                     // because of flushing.
-                    if (setLocalPositions.operand(node.local()) != notSet)
+                    if (setLocalPositions.operand(node->local()) != notSet)
                         break;
-                    setLocalPositions.operand(node.local()) = i;
+                    setLocalPositions.operand(node->local()) = i;
                     break;
                 default:
                     break;
                 }
             }
             
+            if (m_graph.m_form == LoadStore)
+                continue;
+            
             for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
                 checkOperand(
-                    blockIndex, getLocalPositions, setLocalPositions, argumentToOperand(i));
+                    block, getLocalPositions, setLocalPositions, argumentToOperand(i));
             }
             for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
                 checkOperand(
-                    blockIndex, getLocalPositions, setLocalPositions, i);
+                    block, getLocalPositions, setLocalPositions, localToOperand(i));
             }
         }
     }
     
-private:
-    Graph& m_graph;
-    GraphDumpMode m_graphDumpMode;
-    
     void checkOperand(
-        BlockIndex blockIndex, Operands<size_t>& getLocalPositions,
+        BasicBlock* block, Operands<size_t>& getLocalPositions,
         Operands<size_t>& setLocalPositions, int operand)
     {
         if (getLocalPositions.operand(operand) == notSet)
@@ -285,76 +407,71 @@ private:
         if (setLocalPositions.operand(operand) == notSet)
             return;
         
-        BasicBlock* block = m_graph.m_blocks[blockIndex].get();
-        
         VALIDATE(
             (block->at(getLocalPositions.operand(operand)),
              block->at(setLocalPositions.operand(operand)),
-             blockIndex),
+             block),
             getLocalPositions.operand(operand) < setLocalPositions.operand(operand));
     }
     
-    void reportValidationContext(NodeIndex nodeIndex)
+    void reportValidationContext(Node* node)
     {
-        dataLogF("@%u", nodeIndex);
+        dataLogF("@%u", node->index());
     }
     
-    enum BlockTag { Block };
-    void reportValidationContext(BlockTag, BlockIndex blockIndex)
+    void reportValidationContext(BasicBlock* block)
     {
-        dataLogF("Block #%u", blockIndex);
+        dataLog("Block ", *block);
     }
     
-    void reportValidationContext(NodeIndex nodeIndex, Edge edge)
+    void reportValidationContext(Node* node, Edge edge)
     {
-        dataLogF("@%u -> %s@%u", nodeIndex, useKindToString(edge.useKind()), edge.index());
+        dataLog(node, " -> ", edge);
     }
     
-    void reportValidationContext(VirtualRegister local, BlockIndex blockIndex)
+    void reportValidationContext(VirtualRegister local, BasicBlock* block)
     {
-        dataLogF("r%d in Block #%u", local, blockIndex);
+        if (!block) {
+            dataLog("r", static_cast<int>(local), " in null Block ");
+            return;
+        }
+
+        dataLog("r", static_cast<int>(local), " in Block ", *block);
     }
     
     void reportValidationContext(
-        VirtualRegister local, BlockIndex sourceBlockIndex, BlockTag, BlockIndex destinationBlockIndex)
+        VirtualRegister local, BasicBlock* sourceBlock, BasicBlock* destinationBlock)
     {
-        dataLogF("r%d in Block #%u -> #%u", local, sourceBlockIndex, destinationBlockIndex);
+        dataLog("r", static_cast<int>(local), " in Block ", *sourceBlock, " -> ", *destinationBlock);
     }
     
     void reportValidationContext(
-        VirtualRegister local, BlockIndex sourceBlockIndex, NodeIndex prevNodeIndex)
+        VirtualRegister local, BasicBlock* sourceBlock, Node* prevNode)
     {
-        dataLogF("@%u for r%d in Block #%u", prevNodeIndex, local, sourceBlockIndex);
+        dataLog(prevNode, " for r", static_cast<int>(local), " in Block ", *sourceBlock);
     }
     
-    void reportValidationContext(
-        NodeIndex nodeIndex, BlockIndex blockIndex)
+    void reportValidationContext(Node* node, BasicBlock* block)
     {
-        dataLogF("@%u in Block #%u", nodeIndex, blockIndex);
+        dataLog(node, " in Block ", *block);
     }
     
-    void reportValidationContext(
-        NodeIndex nodeIndex, NodeIndex nodeIndex2, BlockIndex blockIndex)
+    void reportValidationContext(Node* node, Node* node2, BasicBlock* block)
     {
-        dataLogF("@%u and @%u in Block #%u", nodeIndex, nodeIndex2, blockIndex);
+        dataLog(node, " and ", node2, " in Block ", *block);
     }
     
     void reportValidationContext(
-        NodeIndex nodeIndex, BlockIndex blockIndex, NodeIndex expectedNodeIndex, Edge incomingEdge)
+        Node* node, BasicBlock* block, Node* expectedNode, Edge incomingEdge)
     {
-        dataLogF("@%u in Block #%u, searching for @%u from @%u", nodeIndex, blockIndex, expectedNodeIndex, incomingEdge.index());
-    }
-    
-    void dumpData(unsigned value)
-    {
-        dataLogF("%u", value);
+        dataLog(node, " in Block ", *block, ", searching for ", expectedNode, " from ", incomingEdge);
     }
     
     void dumpGraphIfAppropriate()
     {
         if (m_graphDumpMode == DontDumpGraph)
             return;
-        dataLog("Graph of ", CodeBlockWithJITType(m_graph.m_codeBlock, JITCode::DFGJIT), " at time of failure:\n");
+        dataLog("At time of failure:\n");
         m_graph.dump();
     }
 };
@@ -365,8 +482,6 @@ void validate(Graph& graph, GraphDumpMode graphDumpMode)
     validationObject.validate();
 }
 
-#endif // DFG_ENABLE(VALIDATION)
-
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)