1/* 2 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "DFGGraph.h" 28 29#include "CodeBlock.h" 30 31#if ENABLE(DFG_JIT) 32 33namespace JSC { namespace DFG { 34 35#ifndef NDEBUG 36 37// Creates an array of stringized names. 38static const char* dfgOpNames[] = { 39#define STRINGIZE_DFG_OP_ENUM(opcode, flags) #opcode , 40 FOR_EACH_DFG_OP(STRINGIZE_DFG_OP_ENUM) 41#undef STRINGIZE_DFG_OP_ENUM 42}; 43 44void Graph::dump(NodeIndex nodeIndex, CodeBlock* codeBlock) 45{ 46 Node& node = at(nodeIndex); 47 NodeType op = node.op; 48 49 unsigned refCount = node.refCount; 50 if (!refCount) 51 return; 52 bool mustGenerate = node.mustGenerate(); 53 if (mustGenerate) 54 --refCount; 55 56 // Example/explanation of dataflow dump output 57 // 58 // 14: <!2:7> GetByVal(@3, @13) 59 // ^1 ^2 ^3 ^4 ^5 60 // 61 // (1) The nodeIndex of this operation. 62 // (2) The reference count. The number printed is the 'real' count, 63 // not including the 'mustGenerate' ref. If the node is 64 // 'mustGenerate' then the count it prefixed with '!'. 65 // (3) The virtual register slot assigned to this node. 66 // (4) The name of the operation. 67 // (5) The arguments to the operation. The may be of the form: 68 // @# - a NodeIndex referencing a prior node in the graph. 69 // arg# - an argument number. 70 // $# - the index in the CodeBlock of a constant { for numeric constants the value is displayed | for integers, in both decimal and hex }. 71 // id# - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }. 72 // var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations. 73 printf("% 4d:\t<%c%u:%u>\t%s(", (int)nodeIndex, mustGenerate ? '!' : ' ', refCount, node.virtualRegister, dfgOpNames[op & NodeIdMask]); 74 if (node.child1 != NoNode) 75 printf("@%u", node.child1); 76 if (node.child2 != NoNode) 77 printf(", @%u", node.child2); 78 if (node.child3 != NoNode) 79 printf(", @%u", node.child3); 80 bool hasPrinted = node.child1 != NoNode; 81 82 if (node.hasVarNumber()) { 83 printf("%svar%u", hasPrinted ? ", " : "", node.varNumber()); 84 hasPrinted = true; 85 } 86 if (node.hasIdentifier()) { 87 if (codeBlock) 88 printf("%sid%u{%s}", hasPrinted ? ", " : "", node.identifierNumber(), codeBlock->identifier(node.identifierNumber()).ustring().utf8().data()); 89 else 90 printf("%sid%u", hasPrinted ? ", " : "", node.identifierNumber()); 91 hasPrinted = true; 92 } 93 if (node.hasLocal()) { 94 int local = node.local(); 95 if (local < 0) 96 printf("%sarg%u", hasPrinted ? ", " : "", local - codeBlock->thisRegister()); 97 else 98 printf("%sr%u", hasPrinted ? ", " : "", local); 99 hasPrinted = true; 100 } 101 if (op == Int32Constant) { 102 printf("%s$%u{%d|0x%08x}", hasPrinted ? ", " : "", node.constantNumber(), node.int32Constant(), node.int32Constant()); 103 hasPrinted = true; 104 } 105 if (op == DoubleConstant) { 106 printf("%s$%u{%f})", hasPrinted ? ", " : "", node.constantNumber(), node.numericConstant()); 107 hasPrinted = true; 108 } 109 if (op == JSConstant) { 110 printf("%s$%u", hasPrinted ? ", " : "", node.constantNumber()); 111 hasPrinted = true; 112 } 113 if (node.isBranch() || node.isJump()) { 114 printf("%sT:#%u", hasPrinted ? ", " : "", blockIndexForBytecodeOffset(node.takenBytecodeOffset())); 115 hasPrinted = true; 116 } 117 if (node.isBranch()) { 118 printf("%sF:#%u", hasPrinted ? ", " : "", blockIndexForBytecodeOffset(node.notTakenBytecodeOffset())); 119 hasPrinted = true; 120 } 121 122 printf(")\n"); 123} 124 125void Graph::dump(CodeBlock* codeBlock) 126{ 127 for (size_t b = 0; b < m_blocks.size(); ++b) { 128 printf("Block #%u:\n", (int)b); 129 BasicBlock& block = m_blocks[b]; 130 for (size_t i = block.begin; i < block.end; ++i) 131 dump(i, codeBlock); 132 } 133} 134 135#endif 136 137// FIXME: Convert these methods to be iterative, not recursive. 138void Graph::refChildren(NodeIndex op) 139{ 140 Node& node = at(op); 141 142 if (node.child1 == NoNode) { 143 ASSERT(node.child2 == NoNode && node.child3 == NoNode); 144 return; 145 } 146 ref(node.child1); 147 148 if (node.child2 == NoNode) { 149 ASSERT(node.child3 == NoNode); 150 return; 151 } 152 ref(node.child2); 153 154 if (node.child3 == NoNode) 155 return; 156 ref(node.child3); 157} 158void Graph::derefChildren(NodeIndex op) 159{ 160 Node& node = at(op); 161 162 if (node.child1 == NoNode) { 163 ASSERT(node.child2 == NoNode && node.child3 == NoNode); 164 return; 165 } 166 deref(node.child1); 167 168 if (node.child2 == NoNode) { 169 ASSERT(node.child3 == NoNode); 170 return; 171 } 172 deref(node.child2); 173 174 if (node.child3 == NoNode) 175 return; 176 deref(node.child3); 177} 178 179} } // namespace JSC::DFG 180 181#endif 182