/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#if ENABLE(DFG_JIT)
#include "CodeBlockWithJITType.h"
+#include "JSCInlines.h"
#include <wtf/Assertions.h>
#include <wtf/BitVector.h>
#define VALIDATE(context, assertion) do { \
if (!(assertion)) { \
+ startCrashing(); \
dataLogF("\n\n\nAt "); \
reportValidationContext context; \
dataLogF(": validation %s (%s:%d) failed.\n", #assertion, __FILE__, __LINE__); \
#define V_EQUAL(context, left, right) do { \
if (left != right) { \
+ startCrashing(); \
dataLogF("\n\n\nAt "); \
reportValidationContext context; \
dataLogF(": validation (%s = ", #left); \
{
// 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), static_cast<Node*>(0), root->variablesAtHead.local(i));
+ V_EQUAL((virtualRegisterForLocal(i), root), static_cast<Node*>(0), root->variablesAtHead.local(i));
// Validate ref counts and uses.
- HashMap<Node*, unsigned> myRefCounts;
- for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
- BasicBlock* block = m_graph.m_blocks[blockIndex].get();
- if (!block || !block->isReachable)
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
continue;
+ VALIDATE((block), block->isReachable);
for (size_t i = 0; i < block->numNodes(); ++i)
- myRefCounts.add(block->node(i), 0);
+ m_myRefCounts.add(block->node(i), 0);
}
- HashSet<Node*> acceptableNodes;
- for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
- BasicBlock* block = m_graph.m_blocks[blockIndex].get();
- if (!block || !block->isReachable)
+ 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) {
Node* node = block->node(i);
- acceptableNodes.add(node);
+ 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))
if (!edge)
continue;
- myRefCounts.find(edge.node())->value++;
+ m_myRefCounts.find(edge.node())->value++;
+
+ VALIDATE((node, edge), edge->hasDoubleResult() == (edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse));
+ VALIDATE((node, edge), edge->hasInt52Result() == (edge.useKind() == Int52RepUse));
+
+ 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()) {
case Flush:
case GetLocal:
- VALIDATE((node, edge), edge->hasVariableAccessData());
+ VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
break;
case PhantomLocal:
- VALIDATE((node, edge), edge->hasVariableAccessData());
+ 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());
+ VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
if (m_graph.m_unificationState == LocallyUnified)
break;
VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
case ThreadedCPS:
VALIDATE((node, edge), edge->hasResult());
break;
+ case SSA:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
}
break;
default:
}
}
}
- for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
- BasicBlock* block = m_graph.m_blocks[blockIndex].get();
- if (!block || !block->isReachable)
+
+ 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) {
+ 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);
+ }
+
+ for (size_t i = 0 ; i < block->size() - 1; ++i) {
+ Node* node = block->at(i);
+ VALIDATE((node), !node->isTerminal());
+ }
+
+ for (size_t i = 0; i < block->size(); ++i) {
+ Node* node = block->at(i);
+
+ if (node->hasStructure())
+ VALIDATE((node), !!node->structure());
+
+ switch (node->op()) {
+ case Identity:
+ VALIDATE((node), canonicalResultRepresentation(node->result()) == canonicalResultRepresentation(node->child1()->result()));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ switch (m_graph.m_form) {
+ case LoadStore:
+ case ThreadedCPS:
+ validateCPS();
+ break;
+
+ case SSA:
+ validateSSA();
+ 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;
HashSet<Node*> phisInThisBlock;
nodesInThisBlock.add(node);
if (block->isPhiIndex(i))
phisInThisBlock.add(node);
- if (m_graph.m_refCountState == ExactRefCount)
- V_EQUAL((node), myRefCounts.get(node), node->adjustedRefCount());
- else
- V_EQUAL((node), node->refCount(), 1);
for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
Edge edge = m_graph.child(node, j);
if (!edge)
continue;
- VALIDATE((node, edge), acceptableNodes.contains(edge.node()));
+ VALIDATE((node, edge), m_acceptableNodes.contains(edge.node()));
}
}
edge->op() == SetLocal
|| edge->op() == SetArgument
|| edge->op() == Flush
- || edge->op() == Phi
- || edge->op() == ZombieHint
- || edge->op() == MovHint
- || edge->op() == MovHintAndCheck);
+ || edge->op() == Phi);
if (phisInThisBlock.contains(edge.node()))
continue;
VALIDATE(
(node, edge),
edge->op() == SetLocal
- || edge->op() == ZombieHint
- || edge->op() == MovHint
- || edge->op() == MovHintAndCheck
|| edge->op() == SetArgument
|| edge->op() == Flush);
// 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);
+ 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]), prevNode);
+ VALIDATE((local, block, block->predecessors[k]), prevNode);
switch (prevNode->op()) {
case GetLocal:
case Flush:
break;
}
if (node->shouldGenerate()) {
- VALIDATE((local, block->m_predecessors[k], prevNode),
+ VALIDATE((local, block->predecessors[k], prevNode),
prevNode->shouldGenerate());
}
VALIDATE(
- (local, block->m_predecessors[k], prevNode),
+ (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()) {
break;
}
// At this point it cannot refer into this block.
- VALIDATE((local, block->m_predecessors[k], prevNode), !prevBlock->isInBlock(edge.node()));
+ VALIDATE((local, block->predecessors[k], prevNode), !prevBlock->isInBlock(edge.node()));
}
VALIDATE((node, edge), found);
block->variablesAtHead.numberOfLocals());
for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
- VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), blockIndex), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->hasVariableAccessData());
+ VALIDATE((virtualRegisterForArgument(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)), blockIndex), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->hasVariableAccessData());
+ VALIDATE((virtualRegisterForArgument(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>(i), blockIndex), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->hasVariableAccessData());
+ VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->hasVariableAccessData(m_graph));
if (m_graph.m_form == ThreadedCPS)
- VALIDATE((static_cast<VirtualRegister>(i), blockIndex), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->hasVariableAccessData());
+ VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->hasVariableAccessData(m_graph));
getLocalPositions.local(i) = notSet;
setLocalPositions.local(i) = notSet;
case Phantom:
if (m_graph.m_form == LoadStore && !j)
break;
+ FALLTHROUGH;
default:
VALIDATE((node, edge), !phisInThisBlock.contains(edge.node()));
break;
break;
// Ignore GetLocal's that we know to be dead, but that the graph
// doesn't yet know to be dead.
- if (!myRefCounts.get(node))
+ if (!m_myRefCounts.get(node))
break;
if (m_graph.m_form == ThreadedCPS)
- VALIDATE((node, blockIndex), getLocalPositions.operand(node->local()) == notSet);
+ VALIDATE((node, block), getLocalPositions.operand(node->local()) == notSet);
getLocalPositions.operand(node->local()) = i;
break;
case SetLocal:
for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
checkOperand(
- blockIndex, getLocalPositions, setLocalPositions, argumentToOperand(i));
+ block, getLocalPositions, setLocalPositions, virtualRegisterForArgument(i));
}
for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
checkOperand(
- blockIndex, getLocalPositions, setLocalPositions, i);
+ block, getLocalPositions, setLocalPositions, virtualRegisterForLocal(i));
}
}
}
-private:
- Graph& m_graph;
- GraphDumpMode m_graphDumpMode;
+ void validateSSA()
+ {
+ // FIXME: Add more things here.
+ // https://bugs.webkit.org/show_bug.cgi?id=123471
+
+ for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+ BasicBlock* block = m_graph.block(blockIndex);
+ if (!block)
+ continue;
+
+ unsigned nodeIndex = 0;
+ for (; nodeIndex < block->size() && !block->at(nodeIndex)->origin.isSet(); nodeIndex++) { }
+
+ VALIDATE((block), nodeIndex < block->size());
+
+ for (; nodeIndex < block->size(); nodeIndex++)
+ VALIDATE((block->at(nodeIndex)), block->at(nodeIndex)->origin.isSet());
+
+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
+ Node* node = block->at(nodeIndex);
+ switch (node->op()) {
+ case Phi:
+ VALIDATE((node), !node->origin.isSet());
+ break;
+
+ default:
+ // FIXME: Add more things here.
+ // https://bugs.webkit.org/show_bug.cgi?id=123471
+ break;
+ }
+ }
+ }
+ }
void checkOperand(
- BlockIndex blockIndex, Operands<size_t>& getLocalPositions,
- Operands<size_t>& setLocalPositions, int operand)
+ BasicBlock* block, Operands<size_t>& getLocalPositions,
+ Operands<size_t>& setLocalPositions, VirtualRegister operand)
{
if (getLocalPositions.operand(operand) == notSet)
return;
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));
}
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(Node* node, Edge edge)
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", local, " in null Block ");
+ return;
+ }
+
+ dataLog("r", 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", local, " in Block ", *sourceBlock, " -> ", *destinationBlock);
}
void reportValidationContext(
- VirtualRegister local, BlockIndex sourceBlockIndex, Node* prevNode)
+ VirtualRegister local, BasicBlock* sourceBlock, Node* prevNode)
{
- dataLogF("@%u for r%d in Block #%u", prevNode->index(), local, sourceBlockIndex);
+ dataLog(prevNode, " for r", local, " in Block ", *sourceBlock);
}
- void reportValidationContext(
- Node* node, BlockIndex blockIndex)
+ void reportValidationContext(Node* node, BasicBlock* block)
{
- dataLogF("@%u in Block #%u", node->index(), blockIndex);
+ dataLog(node, " in Block ", *block);
}
- void reportValidationContext(
- Node* node, Node* node2, BlockIndex blockIndex)
+ void reportValidationContext(Node* node, Node* node2, BasicBlock* block)
{
- dataLogF("@%u and @%u in Block #%u", node->index(), node2->index(), blockIndex);
+ dataLog(node, " and ", node2, " in Block ", *block);
}
void reportValidationContext(
- Node* node, BlockIndex blockIndex, Node* expectedNode, Edge incomingEdge)
+ Node* node, BasicBlock* block, Node* expectedNode, Edge incomingEdge)
{
- dataLog(node, " in Block #", blockIndex, ", searching for ", expectedNode, " from ", incomingEdge);
+ dataLog(node, " in Block ", *block, ", searching for ", expectedNode, " from ", incomingEdge);
}
void dumpGraphIfAppropriate()