summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGGraph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGGraph.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGGraph.cpp363
1 files changed, 363 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
new file mode 100644
index 000000000..487b69206
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DFGGraph.h"
+
+#include "CodeBlock.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+#ifndef NDEBUG
+
+// Creates an array of stringized names.
+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)
+{
+ // Variables are already numbered. For readability of IR dumps, this returns
+ // an alphabetic name for the variable access data, so that you don't have to
+ // reason about two numbers (variable number and live range number), but instead
+ // a number and a letter.
+
+ 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;
+ }
+ }
+
+ // Print the pops.
+ for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) {
+ printWhiteSpace(i * 2);
+ printf("<-- %p\n", previousInlineStack[i].inlineCallFrame->executable.get());
+ }
+
+ // Print the pushes.
+ 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);
+
+ // 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]);
+ }
+ } 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, double ratio %lf%s", predictionToString(node.variableAccessData()->prediction()), node.variableAccessData()->doubleVoteRatio(), node.variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : "");
+ 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
+
+// FIXME: Convert this to be iterative, not recursive.
+#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); \
+ break; \
+ } \
+ thingToDo(_node.child1()); \
+ \
+ if (_node.child2() == NoNode) { \
+ ASSERT(_node.child3() == NoNode); \
+ break; \
+ } \
+ thingToDo(_node.child2()); \
+ \
+ if (_node.child3() == NoNode) \
+ break; \
+ 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
+ }
+}
+
+} } // namespace JSC::DFG
+
+#endif