/* * 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 }; void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock) { Node& node = at(nodeIndex); NodeType op = node.op; unsigned refCount = node.refCount; if (!refCount) return; bool mustGenerate = node.mustGenerate(); if (mustGenerate) --refCount; // Example/explanation of dataflow dump output // // 14: 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:\t<%c%u:%u>\t%s(", (int)nodeIndex, mustGenerate ? '!' : ' ', refCount, node.virtualRegister, dfgOpNames[op & NodeIdMask]); if (node.child1 != NoNode) printf("@%u", node.child1); if (node.child2 != NoNode) printf(", @%u", node.child2); if (node.child3 != NoNode) printf(", @%u", node.child3); bool hasPrinted = node.child1 != NoNode; 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.hasLocal()) { int local = node.local(); if (local < 0) printf("%sarg%u", hasPrinted ? ", " : "", local - codeBlock->thisRegister()); else printf("%sr%u", hasPrinted ? ", " : "", local); hasPrinted = true; } if (op == Int32Constant) { printf("%s$%u{%d|0x%08x}", hasPrinted ? ", " : "", node.constantNumber(), node.int32Constant(), node.int32Constant()); hasPrinted = true; } if (op == DoubleConstant) { printf("%s$%u{%f})", hasPrinted ? ", " : "", node.constantNumber(), node.numericConstant()); hasPrinted = true; } if (op == JSConstant) { printf("%s$%u", hasPrinted ? ", " : "", node.constantNumber()); hasPrinted = true; } if (node.isBranch() || node.isJump()) { printf("%sT:#%u", hasPrinted ? ", " : "", blockIndexForBytecodeOffset(node.takenBytecodeOffset())); hasPrinted = true; } if (node.isBranch()) { printf("%sF:#%u", hasPrinted ? ", " : "", blockIndexForBytecodeOffset(node.notTakenBytecodeOffset())); hasPrinted = true; } printf(")\n"); } void Graph::dump(CodeBlock* codeBlock) { for (size_t b = 0; b < m_blocks.size(); ++b) { printf("Block #%u:\n", (int)b); BasicBlock& block = m_blocks[b]; for (size_t i = block.begin; i < block.end; ++i) dump(i, codeBlock); } } #endif // FIXME: Convert these methods to be iterative, not recursive. void Graph::refChildren(NodeIndex op) { Node& node = at(op); if (node.child1 == NoNode) { ASSERT(node.child2 == NoNode && node.child3 == NoNode); return; } ref(node.child1); if (node.child2 == NoNode) { ASSERT(node.child3 == NoNode); return; } ref(node.child2); if (node.child3 == NoNode) return; ref(node.child3); } void Graph::derefChildren(NodeIndex op) { Node& node = at(op); if (node.child1 == NoNode) { ASSERT(node.child2 == NoNode && node.child3 == NoNode); return; } deref(node.child1); if (node.child2 == NoNode) { ASSERT(node.child3 == NoNode); return; } deref(node.child2); if (node.child3 == NoNode) return; deref(node.child3); } } } // namespace JSC::DFG #endif