void Graph::dumpCodeOrigin(const char* prefix, NodeIndex prevNodeIndex, NodeIndex nodeIndex) { if (prevNodeIndex == NoNode) return; Node& currentNode = at(nodeIndex); Node& previousNode = at(prevNodeIndex); 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; } } // Print the pops. for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) { dataLog("%s", prefix); printWhiteSpace(i * 2); dataLog("<-- %p\n", previousInlineStack[i].inlineCallFrame->executable.get()); } // Print the pushes. for (unsigned i = indexOfDivergence; i < currentInlineStack.size(); ++i) { dataLog("%s", prefix); printWhiteSpace(i * 2); dataLog("--> %p\n", currentInlineStack[i].inlineCallFrame->executable.get()); } }
void print_int_array(FILE* out, const int* tab, unsigned count) { unsigned int max_width = ints_width(tab, count); // unsigned int leadingIndex = 0; unsigned int numOfIntsInTheRow; unsigned int indexWidth = int_width(count - 1); for (unsigned int i = 0; i < count;) { numOfIntsInTheRow = (MtabX_COLUMN - int_width(count - 1) - 2) / (max_width + 1); printWhiteSpace(out, indexWidth - int_width(i)); fprintf(out, "["); fprintf(out, "%d", i); fprintf(out, "]"); for (unsigned int j = i; j < i + numOfIntsInTheRow && j < count; ++j) { fprintf(out, " "); printOneInt(out, tab[j], int_width(tab[j]), max_width); } fprintf(out, "\n"); i += numOfIntsInTheRow; } }
void Graph::printNodeWhiteSpace(Node& node) { printWhiteSpace(amountOfNodeWhiteSpace(node)); }
void printOneInt(FILE*out, const int num, const unsigned int int_width, const unsigned int max_width) { printWhiteSpace(out, max_width - int_width); fprintf(out, "%d", num); }
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); // Example/explanation of dataflow dump output // // 14: <!2:7> GetByVal(@3, @13) // ^1 ^2 ^3 ^4 ^5 // // (1) The nodeIndex of this operation. // (2) The reference count. The number printed is the 'real' count, // not including the 'mustGenerate' ref. If the node is // 'mustGenerate' then the count it prefixed with '!'. // (3) The virtual register slot assigned to this node. // (4) The name of the operation. // (5) The arguments to the operation. The may be of the form: // @# - a NodeIndex referencing a prior node in the graph. // arg# - an argument number. // $# - the index in the CodeBlock of a constant { for numeric constants the value is displayed | for integers, in both decimal and hex }. // id# - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }. // var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations. 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].index()); } } else { if (!!node.child1()) printf("@%u", node.child1().index()); if (!!node.child2()) printf(", @%u", node.child2().index()); if (!!node.child3()) printf(", @%u", node.child3().index()); hasPrinted = !!node.child1(); } 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, double ratio %lf%s", predictionToString(node.variableAccessData()->prediction()), node.variableAccessData()->doubleVoteRatio(), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : ""); else if (node.hasHeapPrediction()) printf(" predicting %s", predictionToString(node.getHeapPrediction())); else if (node.hasVarNumber()) printf(" predicting %s", predictionToString(getGlobalVarPrediction(node.varNumber()))); } printf("\n"); }