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