001/* 002 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.printer; 024 025import static com.oracle.graal.compiler.common.GraalOptions.*; 026 027import java.io.*; 028import java.util.*; 029import java.util.Map.Entry; 030 031import jdk.internal.jvmci.meta.*; 032 033import com.oracle.graal.graph.*; 034import com.oracle.graal.java.*; 035import com.oracle.graal.nodeinfo.*; 036import com.oracle.graal.nodes.*; 037import com.oracle.graal.nodes.cfg.*; 038import com.oracle.graal.phases.schedule.*; 039 040/** 041 * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the 042 * <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>. 043 */ 044public class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPrinter { 045 046 private final boolean tryToSchedule; 047 048 /** 049 * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. 050 * 051 * @param tryToSchedule If false, no scheduling is done, which avoids exceptions for 052 * non-schedulable graphs. 053 */ 054 public IdealGraphPrinter(OutputStream stream, boolean tryToSchedule) { 055 super(stream); 056 this.begin(); 057 this.tryToSchedule = tryToSchedule; 058 } 059 060 /** 061 * Starts a new group of graphs with the given name, short name and method byte code index (BCI) 062 * as properties. 063 */ 064 @Override 065 public void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci) { 066 beginGroup(); 067 beginProperties(); 068 printProperty("name", name); 069 endProperties(); 070 beginMethod(name, shortName, bci); 071 if (method != null && method.getCode() != null) { 072 printBytecodes(new BytecodeDisassembler(false).disassemble(method)); 073 } 074 endMethod(); 075 } 076 077 public void print(Graph graph, String title) { 078 print(graph, title, null); 079 } 080 081 /** 082 * Prints an entire {@link Graph} with the specified title, optionally using short names for 083 * nodes. 084 */ 085 @Override 086 public void print(Graph graph, String title, SchedulePhase predefinedSchedule) { 087 beginGraph(title); 088 Set<Node> noBlockNodes = Node.newSet(); 089 SchedulePhase schedule = predefinedSchedule; 090 if (schedule == null && tryToSchedule) { 091 if (PrintIdealGraphSchedule.getValue()) { 092 try { 093 schedule = new SchedulePhase(); 094 schedule.apply((StructuredGraph) graph); 095 } catch (Throwable t) { 096 } 097 } 098 } 099 ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG(); 100 101 beginNodes(); 102 List<Edge> edges = printNodes(graph, cfg == null ? null : cfg.getNodeToBlock(), noBlockNodes); 103 endNodes(); 104 105 beginEdges(); 106 for (Edge edge : edges) { 107 printEdge(edge); 108 } 109 endEdges(); 110 111 if (cfg != null && cfg.getBlocks() != null) { 112 beginControlFlow(); 113 for (Block block : cfg.getBlocks()) { 114 printBlock(graph, block, cfg.getNodeToBlock()); 115 } 116 printNoBlock(noBlockNodes); 117 endControlFlow(); 118 } 119 120 endGraph(); 121 flush(); 122 } 123 124 private List<Edge> printNodes(Graph graph, NodeMap<Block> nodeToBlock, Set<Node> noBlockNodes) { 125 ArrayList<Edge> edges = new ArrayList<>(); 126 127 NodeMap<Set<Entry<String, Integer>>> colors = graph.createNodeMap(); 128 NodeMap<Set<Entry<String, String>>> colorsToString = graph.createNodeMap(); 129 NodeMap<Set<String>> bits = graph.createNodeMap(); 130 131 for (Node node : graph.getNodes()) { 132 133 beginNode(node.toString(Verbosity.Id)); 134 beginProperties(); 135 printProperty("idx", node.toString(Verbosity.Id)); 136 137 Map<Object, Object> props = node.getDebugProperties(); 138 if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) { 139 String name = node.toString(Verbosity.Name); 140 printProperty("name", name); 141 } 142 printProperty("class", node.getClass().getSimpleName()); 143 Block block = nodeToBlock == null ? null : nodeToBlock.get(node); 144 if (block != null) { 145 printProperty("block", Integer.toString(block.getId())); 146 // if (!(node instanceof PhiNode || node instanceof FrameState || node instanceof 147 // ParameterNode) && !block.nodes().contains(node)) { 148 // printProperty("notInOwnBlock", "true"); 149 // } 150 } else { 151 printProperty("block", "noBlock"); 152 noBlockNodes.add(node); 153 } 154 155 Set<Entry<String, Integer>> nodeColors = colors.get(node); 156 if (nodeColors != null) { 157 for (Entry<String, Integer> color : nodeColors) { 158 String name = color.getKey(); 159 Integer value = color.getValue(); 160 printProperty(name, Integer.toString(value)); 161 } 162 } 163 Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node); 164 if (nodeColorStrings != null) { 165 for (Entry<String, String> color : nodeColorStrings) { 166 String name = color.getKey(); 167 String value = color.getValue(); 168 printProperty(name, value); 169 } 170 } 171 Set<String> nodeBits = bits.get(node); 172 if (nodeBits != null) { 173 for (String bit : nodeBits) { 174 printProperty(bit, "true"); 175 } 176 } 177 if (node instanceof BeginNode) { 178 printProperty("shortName", "B"); 179 } else if (node.getClass() == EndNode.class) { 180 printProperty("shortName", "E"); 181 } 182 if (node.predecessor() != null) { 183 printProperty("hasPredecessor", "true"); 184 } 185 186 for (Entry<Object, Object> entry : props.entrySet()) { 187 String key = entry.getKey().toString(); 188 Object value = entry.getValue(); 189 String valueString; 190 if (value == null) { 191 valueString = "null"; 192 } else { 193 Class<?> type = value.getClass(); 194 if (type.isArray()) { 195 if (!type.getComponentType().isPrimitive()) { 196 valueString = Arrays.toString((Object[]) value); 197 } else if (type.getComponentType() == Integer.TYPE) { 198 valueString = Arrays.toString((int[]) value); 199 } else if (type.getComponentType() == Double.TYPE) { 200 valueString = Arrays.toString((double[]) value); 201 } else { 202 valueString = toString(); 203 } 204 } else { 205 valueString = value.toString(); 206 } 207 } 208 printProperty(key, valueString); 209 } 210 211 endProperties(); 212 endNode(); 213 214 // successors 215 int fromIndex = 0; 216 NodePosIterator succIter = node.successors().iterator(); 217 while (succIter.hasNext()) { 218 Position position = succIter.nextPosition(); 219 Node successor = position.get(node); 220 if (successor != null) { 221 edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, position.getName())); 222 } 223 fromIndex++; 224 } 225 226 // inputs 227 int toIndex = 1; 228 NodePosIterator inputIter = node.inputs().iterator(); 229 while (inputIter.hasNext()) { 230 Position position = inputIter.nextPosition(); 231 Node input = position.get(node); 232 if (input != null) { 233 edges.add(new Edge(input.toString(Verbosity.Id), input.successors().count(), node.toString(Verbosity.Id), toIndex, position.getName())); 234 } 235 toIndex++; 236 } 237 } 238 239 return edges; 240 } 241 242 private void printBlock(Graph graph, Block block, NodeMap<Block> nodeToBlock) { 243 beginBlock(Integer.toString(block.getId())); 244 beginSuccessors(); 245 for (Block sux : block.getSuccessors()) { 246 if (sux != null) { 247 printSuccessor(Integer.toString(sux.getId())); 248 } 249 } 250 endSuccessors(); 251 beginBlockNodes(); 252 253 Set<Node> nodes = Node.newSet(); 254 255 if (nodeToBlock != null) { 256 for (Node n : graph.getNodes()) { 257 Block blk = nodeToBlock.get(n); 258 if (blk == block) { 259 nodes.add(n); 260 } 261 } 262 } 263 264 if (nodes.size() > 0) { 265 // if this is the first block: add all locals to this block 266 if (block.getBeginNode() == ((StructuredGraph) graph).start()) { 267 for (Node node : graph.getNodes()) { 268 if (node instanceof ParameterNode) { 269 nodes.add(node); 270 } 271 } 272 } 273 274 Set<Node> snapshot = Node.newSet(nodes); 275 // add all framestates and phis to their blocks 276 for (Node node : snapshot) { 277 if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) { 278 nodes.add(((StateSplit) node).stateAfter()); 279 } 280 if (node instanceof AbstractMergeNode) { 281 for (PhiNode phi : ((AbstractMergeNode) node).phis()) { 282 nodes.add(phi); 283 } 284 } 285 } 286 287 for (Node node : nodes) { 288 printBlockNode(node.toString(Verbosity.Id)); 289 } 290 } 291 endBlockNodes(); 292 endBlock(); 293 } 294 295 private void printNoBlock(Set<Node> noBlockNodes) { 296 if (!noBlockNodes.isEmpty()) { 297 beginBlock("noBlock"); 298 beginBlockNodes(); 299 for (Node node : noBlockNodes) { 300 printBlockNode(node.toString(Verbosity.Id)); 301 } 302 endBlockNodes(); 303 endBlock(); 304 } 305 } 306}