#include "config.h"
#include "DFGGraph.h"
#include "CodeBlock.h"
#if ENABLE(DFG_JIT)
namespace JSC { namespace DFG {
#ifndef NDEBUG
static const char* dfgOpNames[] = {
#define STRINGIZE_DFG_OP_ENUM(opcode, flags) #opcode ,
FOR_EACH_DFG_OP(STRINGIZE_DFG_OP_ENUM)
#undef STRINGIZE_DFG_OP_ENUM
};
const char *Graph::opName(NodeType op)
{
return dfgOpNames[op & NodeIdMask];
}
const char* Graph::nameOfVariableAccessData(VariableAccessData* variableAccessData)
{
unsigned index = std::numeric_limits<unsigned>::max();
for (unsigned i = 0; i < m_variableAccessData.size(); ++i) {
if (&m_variableAccessData[i] == variableAccessData) {
index = i;
break;
}
}
ASSERT(index != std::numeric_limits<unsigned>::max());
if (!index)
return "A";
static char buf[10];
BoundsCheckedPointer<char> ptr(buf, sizeof(buf));
while (index) {
*ptr++ = 'A' + (index % 26);
index /= 26;
}
*ptr++ = 0;
return buf;
}
static void printWhiteSpace(unsigned amount)
{
while (amount-- > 0)
printf(" ");
}
void Graph::dumpCodeOrigin(NodeIndex nodeIndex)
{
if (!nodeIndex)
return;
Node& currentNode = at(nodeIndex);
Node& previousNode = at(nodeIndex - 1);
if (previousNode.codeOrigin.inlineCallFrame == currentNode.codeOrigin.inlineCallFrame)
return;
Vector<CodeOrigin> previousInlineStack = previousNode.codeOrigin.inlineStack();
Vector<CodeOrigin> currentInlineStack = currentNode.codeOrigin.inlineStack();
unsigned commonSize = std::min(previousInlineStack.size(), currentInlineStack.size());
unsigned indexOfDivergence = commonSize;
for (unsigned i = 0; i < commonSize; ++i) {
if (previousInlineStack[i].inlineCallFrame != currentInlineStack[i].inlineCallFrame) {
indexOfDivergence = i;
break;
}
}
for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) {
printWhiteSpace(i * 2);
printf("<-- %p\n", previousInlineStack[i].inlineCallFrame->executable.get());
}
for (unsigned i = indexOfDivergence; i < currentInlineStack.size(); ++i) {
printWhiteSpace(i * 2);
printf("--> %p\n", currentInlineStack[i].inlineCallFrame->executable.get());
}
}
void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock)
{
Node& node = at(nodeIndex);
NodeType op = node.op;
unsigned refCount = node.refCount();
bool skipped = !refCount;
bool mustGenerate = node.mustGenerate();
if (mustGenerate) {
ASSERT(refCount);
--refCount;
}
dumpCodeOrigin(nodeIndex);
printWhiteSpace((node.codeOrigin.inlineDepth() - 1) * 2);
printf("% 4d:%s<%c%u:", (int)nodeIndex, skipped ? " skipped " : " ", mustGenerate ? '!' : ' ', refCount);
if (node.hasResult() && !skipped && node.hasVirtualRegister())
printf("%u", node.virtualRegister());
else
printf("-");
printf(">\t%s(", opName(op));
bool hasPrinted = false;
if (op & NodeHasVarArgs) {
for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++) {
if (hasPrinted)
printf(", ");
else
hasPrinted = true;
printf("@%u", m_varArgChildren[childIdx]);
}
} else {
if (node.child1() != NoNode)
printf("@%u", node.child1());
if (node.child2() != NoNode)
printf(", @%u", node.child2());
if (node.child3() != NoNode)
printf(", @%u", node.child3());
hasPrinted = node.child1() != NoNode;
}
if (node.hasArithNodeFlags()) {
printf("%s%s", hasPrinted ? ", " : "", arithNodeFlagsAsString(node.rawArithNodeFlags()));
hasPrinted = true;
}
if (node.hasVarNumber()) {
printf("%svar%u", hasPrinted ? ", " : "", node.varNumber());
hasPrinted = true;
}
if (node.hasIdentifier()) {
if (codeBlock)
printf("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), codeBlock->identifier(node.identifierNumber()).ustring().utf8().data());
else
printf("%sid%u", hasPrinted ? ", " : "", node.identifierNumber());
hasPrinted = true;
}
if (node.hasStructureSet()) {
for (size_t i = 0; i < node.structureSet().size(); ++i) {
printf("%sstruct(%p)", hasPrinted ? ", " : "", node.structureSet()[i]);
hasPrinted = true;
}
}
if (node.hasStructureTransitionData()) {
printf("%sstruct(%p -> %p)", hasPrinted ? ", " : "", node.structureTransitionData().previousStructure, node.structureTransitionData().newStructure);
hasPrinted = true;
}
if (node.hasStorageAccessData()) {
StorageAccessData& storageAccessData = m_storageAccessData[node.storageAccessDataIndex()];
if (codeBlock)
printf("%sid%u{%s}", hasPrinted ? ", " : "", storageAccessData.identifierNumber, codeBlock->identifier(storageAccessData.identifierNumber).ustring().utf8().data());
else
printf("%sid%u", hasPrinted ? ", " : "", storageAccessData.identifierNumber);
printf(", %lu", static_cast<unsigned long>(storageAccessData.offset));
hasPrinted = true;
}
ASSERT(node.hasVariableAccessData() == node.hasLocal());
if (node.hasVariableAccessData()) {
VariableAccessData* variableAccessData = node.variableAccessData();
int operand = variableAccessData->operand();
if (operandIsArgument(operand))
printf("%sarg%u(%s)", hasPrinted ? ", " : "", operandToArgument(operand), nameOfVariableAccessData(variableAccessData));
else
printf("%sr%u(%s)", hasPrinted ? ", " : "", operand, nameOfVariableAccessData(variableAccessData));
hasPrinted = true;
}
if (node.hasConstantBuffer() && codeBlock) {
if (hasPrinted)
printf(", ");
printf("%u:[", node.startConstant());
for (unsigned i = 0; i < node.numConstants(); ++i) {
if (i)
printf(", ");
printf("%s", codeBlock->constantBuffer(node.startConstant())[i].description());
}
printf("]");
hasPrinted = true;
}
if (op == JSConstant) {
printf("%s$%u", hasPrinted ? ", " : "", node.constantNumber());
if (codeBlock) {
JSValue value = valueOfJSConstant(codeBlock, nodeIndex);
printf(" = %s", value.description());
}
hasPrinted = true;
}
if (op == WeakJSConstant) {
printf("%s%p", hasPrinted ? ", " : "", node.weakConstant());
hasPrinted = true;
}
if (node.isBranch() || node.isJump()) {
printf("%sT:#%u", hasPrinted ? ", " : "", node.takenBlockIndex());
hasPrinted = true;
}
if (node.isBranch()) {
printf("%sF:#%u", hasPrinted ? ", " : "", node.notTakenBlockIndex());
hasPrinted = true;
}
(void)hasPrinted;
printf(")");
if (!skipped) {
if (node.hasVariableAccessData())
printf(" predicting %s", predictionToString(node.variableAccessData()->prediction()));
else if (node.hasVarNumber())
printf(" predicting %s", predictionToString(getGlobalVarPrediction(node.varNumber())));
else if (node.hasHeapPrediction())
printf(" predicting %s", predictionToString(node.getHeapPrediction()));
}
printf("\n");
}
void Graph::dump(CodeBlock* codeBlock)
{
for (size_t b = 0; b < m_blocks.size(); ++b) {
BasicBlock* block = m_blocks[b].get();
printf("Block #%u (bc#%u): %s%s\n", (int)b, block->bytecodeBegin, block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "");
printf(" vars before: ");
if (block->cfaHasVisited)
dumpOperands(block->valuesAtHead, stdout);
else
printf("<empty>");
printf("\n");
printf(" var links: ");
dumpOperands(block->variablesAtHead, stdout);
printf("\n");
for (size_t i = block->begin; i < block->end; ++i)
dump(i, codeBlock);
printf(" vars after: ");
if (block->cfaHasVisited)
dumpOperands(block->valuesAtTail, stdout);
else
printf("<empty>");
printf("\n");
}
printf("Phi Nodes:\n");
for (size_t i = m_blocks.last()->end; i < size(); ++i)
dump(i, codeBlock);
}
#endif
#define DO_TO_CHILDREN(node, thingToDo) do { \
Node& _node = (node); \
if (_node.op & NodeHasVarArgs) { \
for (unsigned _childIdx = _node.firstChild(); \
_childIdx < _node.firstChild() + _node.numChildren(); \
_childIdx++) \
thingToDo(m_varArgChildren[_childIdx]); \
} else { \
if (_node.child1() == NoNode) { \
ASSERT(_node.child2() == NoNode \
&& _node.child3() == NoNode); \
return; \
} \
thingToDo(_node.child1()); \
\
if (_node.child2() == NoNode) { \
ASSERT(_node.child3() == NoNode); \
return; \
} \
thingToDo(_node.child2()); \
\
if (_node.child3() == NoNode) \
return; \
thingToDo(_node.child3()); \
} \
} while (false)
void Graph::refChildren(NodeIndex op)
{
DO_TO_CHILDREN(at(op), ref);
}
void Graph::derefChildren(NodeIndex op)
{
DO_TO_CHILDREN(at(op), deref);
}
void Graph::predictArgumentTypes(CodeBlock* codeBlock)
{
ASSERT(codeBlock);
ASSERT(codeBlock->alternative());
CodeBlock* profiledCodeBlock = codeBlock->alternative();
ASSERT(codeBlock->m_numParameters >= 1);
for (size_t arg = 0; arg < static_cast<size_t>(codeBlock->m_numParameters); ++arg) {
ValueProfile* profile = profiledCodeBlock->valueProfileForArgument(arg);
if (!profile)
continue;
at(m_arguments[arg]).variableAccessData()->predict(profile->computeUpdatedPrediction());
#if DFG_ENABLE(DEBUG_VERBOSE)
printf("Argument [%lu] prediction: %s\n", arg, predictionToString(at(m_arguments[arg]).variableAccessData()->prediction()));
#endif
}
}
} }
#endif