1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.printer; 24 25 import static org.graalvm.compiler.graph.Edges.Type.Inputs; 26 import static org.graalvm.compiler.graph.Edges.Type.Successors; 27 28 import java.io.IOException; 29 import java.util.Arrays; 30 import java.util.Collection; 31 import java.util.Collections; 32 import java.util.LinkedList; 33 import java.util.List; 34 import java.util.Map; 35 36 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 37 import org.graalvm.compiler.bytecode.Bytecode; 38 import org.graalvm.compiler.core.common.cfg.BlockMap; 39 import org.graalvm.compiler.debug.DebugContext; 40 import org.graalvm.compiler.debug.DebugOptions; 41 import org.graalvm.compiler.graph.CachedGraph; 42 import org.graalvm.compiler.graph.Edges; 43 import org.graalvm.compiler.graph.Graph; 44 import org.graalvm.compiler.graph.InputEdges; 45 import org.graalvm.compiler.graph.Node; 46 import org.graalvm.compiler.graph.NodeClass; 47 import org.graalvm.compiler.graph.NodeMap; 48 import org.graalvm.compiler.graph.NodeSourcePosition; 49 import org.graalvm.compiler.nodes.AbstractBeginNode; 50 import org.graalvm.compiler.nodes.AbstractEndNode; 51 import org.graalvm.compiler.nodes.AbstractMergeNode; 52 import org.graalvm.compiler.nodes.ConstantNode; 53 import org.graalvm.compiler.nodes.ControlSinkNode; 54 import org.graalvm.compiler.nodes.ControlSplitNode; 55 import org.graalvm.compiler.nodes.FixedNode; 56 import org.graalvm.compiler.nodes.PhiNode; 57 import org.graalvm.compiler.nodes.ProxyNode; 58 import org.graalvm.compiler.nodes.StructuredGraph; 59 import org.graalvm.compiler.nodes.VirtualState; 60 import org.graalvm.compiler.nodes.cfg.Block; 61 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 62 import org.graalvm.compiler.nodes.util.JavaConstantFormattable; 63 import org.graalvm.compiler.phases.schedule.SchedulePhase; 64 import org.graalvm.graphio.GraphBlocks; 65 import org.graalvm.graphio.GraphElements; 66 import org.graalvm.graphio.GraphOutput; 67 import org.graalvm.graphio.GraphStructure; 68 import org.graalvm.graphio.GraphTypes; 69 70 import jdk.vm.ci.meta.ResolvedJavaField; 71 import jdk.vm.ci.meta.ResolvedJavaMethod; 72 import jdk.vm.ci.meta.ResolvedJavaType; 73 import jdk.vm.ci.meta.Signature; 74 75 public class BinaryGraphPrinter implements 76 GraphStructure<BinaryGraphPrinter.GraphInfo, Node, NodeClass<?>, Edges>, 77 GraphBlocks<BinaryGraphPrinter.GraphInfo, Block, Node>, 78 GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition>, 79 GraphTypes, GraphPrinter { 80 private final SnippetReflectionProvider snippetReflection; 81 private final GraphOutput<BinaryGraphPrinter.GraphInfo, ResolvedJavaMethod> output; 82 83 public BinaryGraphPrinter(DebugContext ctx, SnippetReflectionProvider snippetReflection) throws IOException { 84 this.output = ctx.buildOutput(GraphOutput.newBuilder(this).protocolVersion(5, 0).blocks(this).elements(this).types(this)); 85 this.snippetReflection = snippetReflection; 86 } 87 88 @Override 89 public SnippetReflectionProvider getSnippetReflectionProvider() { 90 return snippetReflection; 91 } 92 93 @Override 94 public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException { 95 output.beginGroup(new GraphInfo(debug, null), name, shortName, method, bci, properties); 96 } 97 98 @Override 99 public void endGroup() throws IOException { 100 output.endGroup(); 101 } 102 103 @Override 104 public void close() { 105 output.close(); 106 } 107 108 @Override 109 public ResolvedJavaMethod method(Object object) { 110 if (object instanceof Bytecode) { 111 return ((Bytecode) object).getMethod(); 112 } else if (object instanceof ResolvedJavaMethod) { 113 return ((ResolvedJavaMethod) object); 114 } else { 115 return null; 116 } 117 } 118 119 @Override 120 public Node node(Object obj) { 121 return obj instanceof Node ? (Node) obj : null; 122 } 123 124 @Override 125 public NodeClass<?> nodeClass(Object obj) { 126 if (obj instanceof NodeClass<?>) { 127 return (NodeClass<?>) obj; 128 } 129 return null; 130 } 131 132 @Override 133 public NodeClass<?> classForNode(Node node) { 134 return node.getNodeClass(); 135 } 136 137 @Override 138 public Object nodeClassType(NodeClass<?> node) { 139 return node.getJavaClass(); 140 } 141 142 @Override 143 public String nameTemplate(NodeClass<?> nodeClass) { 144 return nodeClass.getNameTemplate(); 145 } 146 147 @Override 148 public final GraphInfo graph(GraphInfo currrent, Object obj) { 149 if (obj instanceof Graph) { 150 return new GraphInfo(currrent.debug, (Graph) obj); 151 } else if (obj instanceof CachedGraph) { 152 return new GraphInfo(currrent.debug, ((CachedGraph<?>) obj).getReadonlyCopy()); 153 } else { 154 return null; 155 } 156 } 157 158 @Override 159 public int nodeId(Node n) { 160 return getNodeId(n); 161 } 162 163 @Override 164 public Edges portInputs(NodeClass<?> nodeClass) { 165 return nodeClass.getEdges(Inputs); 166 } 167 168 @Override 169 public Edges portOutputs(NodeClass<?> nodeClass) { 170 return nodeClass.getEdges(Successors); 171 } 172 173 @SuppressWarnings("deprecation") 174 private static int getNodeId(Node node) { 175 return node == null ? -1 : node.getId(); 176 } 177 178 @Override 179 public List<Node> blockNodes(GraphInfo info, Block block) { 180 List<Node> nodes = info.blockToNodes.get(block); 181 if (nodes == null) { 182 return null; 183 } 184 List<Node> extraNodes = new LinkedList<>(); 185 for (Node node : nodes) { 186 findExtraNodes(node, extraNodes); 187 } 188 extraNodes.removeAll(nodes); 189 extraNodes.addAll(0, nodes); 190 return extraNodes; 191 } 192 193 @Override 194 public int blockId(Block sux) { 195 return sux.getId(); 196 } 197 198 @Override 199 public List<Block> blockSuccessors(Block block) { 200 return Arrays.asList(block.getSuccessors()); 201 } 202 203 @Override 204 public Iterable<Node> nodes(GraphInfo info) { 205 return info.graph.getNodes(); 206 } 207 208 @Override 209 public int nodesCount(GraphInfo info) { 210 return info.graph.getNodeCount(); 211 } 212 213 @Override 214 @SuppressWarnings({"unchecked", "rawtypes"}) 215 public void nodeProperties(GraphInfo info, Node node, Map<String, Object> props) { 216 node.getDebugProperties((Map) props); 217 Graph graph = info.graph; 218 ControlFlowGraph cfg = info.cfg; 219 NodeMap<Block> nodeToBlocks = info.nodeToBlocks; 220 if (cfg != null && DebugOptions.PrintGraphProbabilities.getValue(graph.getOptions()) && node instanceof FixedNode) { 221 try { 222 props.put("probability", cfg.blockFor(node).probability()); 223 } catch (Throwable t) { 224 props.put("probability", 0.0); 225 props.put("probability-exception", t); 226 } 227 } 228 229 try { 230 props.put("NodeCost-Size", node.estimatedNodeSize()); 231 props.put("NodeCost-Cycles", node.estimatedNodeCycles()); 232 } catch (Throwable t) { 233 props.put("node-cost-exception", t.getMessage()); 234 } 235 236 if (nodeToBlocks != null) { 237 Object block = getBlockForNode(node, nodeToBlocks); 238 if (block != null) { 239 props.put("node-to-block", block); 240 } 241 } 242 243 if (node instanceof ControlSinkNode) { 244 props.put("category", "controlSink"); 245 } else if (node instanceof ControlSplitNode) { 246 props.put("category", "controlSplit"); 247 } else if (node instanceof AbstractMergeNode) { 248 props.put("category", "merge"); 249 } else if (node instanceof AbstractBeginNode) { 250 props.put("category", "begin"); 251 } else if (node instanceof AbstractEndNode) { 252 props.put("category", "end"); 253 } else if (node instanceof FixedNode) { 254 props.put("category", "fixed"); 255 } else if (node instanceof VirtualState) { 256 props.put("category", "state"); 257 } else if (node instanceof PhiNode) { 258 props.put("category", "phi"); 259 } else if (node instanceof ProxyNode) { 260 props.put("category", "proxy"); 261 } else { 262 if (node instanceof ConstantNode) { 263 ConstantNode cn = (ConstantNode) node; 264 updateStringPropertiesForConstant((Map) props, cn); 265 } 266 props.put("category", "floating"); 267 } 268 if (getSnippetReflectionProvider() != null) { 269 for (Map.Entry<String, Object> prop : props.entrySet()) { 270 if (prop.getValue() instanceof JavaConstantFormattable) { 271 props.put(prop.getKey(), ((JavaConstantFormattable) prop.getValue()).format(this)); 272 } 273 } 274 } 275 } 276 277 private Object getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) { 278 if (nodeToBlocks.isNew(node)) { 279 return "NEW (not in schedule)"; 280 } else { 281 Block block = nodeToBlocks.get(node); 282 if (block != null) { 283 return block.getId(); 284 } else if (node instanceof PhiNode) { 285 return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks); 286 } 287 } 288 return null; 289 } 290 291 private static void findExtraNodes(Node node, Collection<? super Node> extraNodes) { 292 if (node instanceof AbstractMergeNode) { 293 AbstractMergeNode merge = (AbstractMergeNode) node; 294 for (PhiNode phi : merge.phis()) { 295 extraNodes.add(phi); 296 } 297 } 298 } 299 300 @Override 301 public boolean nodeHasPredecessor(Node node) { 302 return node.predecessor() != null; 303 } 304 305 @Override 306 public List<Block> blocks(GraphInfo graph) { 307 return graph.blocks; 308 } 309 310 @Override 311 public void print(DebugContext debug, Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException { 312 output.print(new GraphInfo(debug, graph), properties, id, format, args); 313 } 314 315 @Override 316 public int portSize(Edges port) { 317 return port.getCount(); 318 } 319 320 @Override 321 public boolean edgeDirect(Edges port, int index) { 322 return index < port.getDirectCount(); 323 } 324 325 @Override 326 public String edgeName(Edges port, int index) { 327 return port.getName(index); 328 } 329 330 @Override 331 public Object edgeType(Edges port, int index) { 332 return ((InputEdges) port).getInputType(index); 333 } 334 335 @Override 336 public Collection<? extends Node> edgeNodes(GraphInfo graph, Node node, Edges port, int i) { 337 if (i < port.getDirectCount()) { 338 Node single = Edges.getNode(node, port.getOffsets(), i); 339 return Collections.singletonList(single); 340 } else { 341 return Edges.getNodeList(node, port.getOffsets(), i); 342 } 343 } 344 345 @Override 346 public Object enumClass(Object enumValue) { 347 if (enumValue instanceof Enum) { 348 return enumValue.getClass(); 349 } 350 return null; 351 } 352 353 @Override 354 public int enumOrdinal(Object obj) { 355 if (obj instanceof Enum<?>) { 356 return ((Enum<?>) obj).ordinal(); 357 } 358 return -1; 359 } 360 361 @SuppressWarnings("unchecked") 362 @Override 363 public String[] enumTypeValues(Object clazz) { 364 if (clazz instanceof Class<?>) { 365 Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) clazz; 366 Enum<?>[] constants = enumClass.getEnumConstants(); 367 if (constants != null) { 368 String[] names = new String[constants.length]; 369 for (int i = 0; i < constants.length; i++) { 370 names[i] = constants[i].name(); 371 } 372 return names; 373 } 374 } 375 return null; 376 } 377 378 @Override 379 public String typeName(Object obj) { 380 if (obj instanceof Class<?>) { 381 return ((Class<?>) obj).getName(); 382 } 383 if (obj instanceof ResolvedJavaType) { 384 return ((ResolvedJavaType) obj).toJavaName(); 385 } 386 return null; 387 } 388 389 @Override 390 public byte[] methodCode(ResolvedJavaMethod method) { 391 return method.getCode(); 392 } 393 394 @Override 395 public int methodModifiers(ResolvedJavaMethod method) { 396 return method.getModifiers(); 397 } 398 399 @Override 400 public Signature methodSignature(ResolvedJavaMethod method) { 401 return method.getSignature(); 402 } 403 404 @Override 405 public String methodName(ResolvedJavaMethod method) { 406 return method.getName(); 407 } 408 409 @Override 410 public Object methodDeclaringClass(ResolvedJavaMethod method) { 411 return method.getDeclaringClass(); 412 } 413 414 @Override 415 public int fieldModifiers(ResolvedJavaField field) { 416 return field.getModifiers(); 417 } 418 419 @Override 420 public String fieldTypeName(ResolvedJavaField field) { 421 return field.getType().toJavaName(); 422 } 423 424 @Override 425 public String fieldName(ResolvedJavaField field) { 426 return field.getName(); 427 } 428 429 @Override 430 public Object fieldDeclaringClass(ResolvedJavaField field) { 431 return field.getDeclaringClass(); 432 } 433 434 @Override 435 public ResolvedJavaField field(Object object) { 436 if (object instanceof ResolvedJavaField) { 437 return (ResolvedJavaField) object; 438 } 439 return null; 440 } 441 442 @Override 443 public Signature signature(Object object) { 444 if (object instanceof Signature) { 445 return (Signature) object; 446 } 447 return null; 448 } 449 450 @Override 451 public int signatureParameterCount(Signature signature) { 452 return signature.getParameterCount(false); 453 } 454 455 @Override 456 public String signatureParameterTypeName(Signature signature, int index) { 457 return signature.getParameterType(index, null).getName(); 458 } 459 460 @Override 461 public String signatureReturnTypeName(Signature signature) { 462 return signature.getReturnType(null).getName(); 463 } 464 465 @Override 466 public NodeSourcePosition nodeSourcePosition(Object object) { 467 if (object instanceof NodeSourcePosition) { 468 return (NodeSourcePosition) object; 469 } 470 return null; 471 } 472 473 @Override 474 public ResolvedJavaMethod nodeSourcePositionMethod(NodeSourcePosition pos) { 475 return pos.getMethod(); 476 } 477 478 @Override 479 public NodeSourcePosition nodeSourcePositionCaller(NodeSourcePosition pos) { 480 return pos.getCaller(); 481 } 482 483 @Override 484 public int nodeSourcePositionBCI(NodeSourcePosition pos) { 485 return pos.getBCI(); 486 } 487 488 @Override 489 public StackTraceElement methodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { 490 return method.asStackTraceElement(bci); 491 } 492 493 static final class GraphInfo { 494 final DebugContext debug; 495 final Graph graph; 496 final ControlFlowGraph cfg; 497 final BlockMap<List<Node>> blockToNodes; 498 final NodeMap<Block> nodeToBlocks; 499 final List<Block> blocks; 500 501 private GraphInfo(DebugContext debug, Graph graph) { 502 this.debug = debug; 503 this.graph = graph; 504 StructuredGraph.ScheduleResult scheduleResult = null; 505 if (graph instanceof StructuredGraph) { 506 507 StructuredGraph structuredGraph = (StructuredGraph) graph; 508 scheduleResult = structuredGraph.getLastSchedule(); 509 if (scheduleResult == null) { 510 511 // Also provide a schedule when an error occurs 512 if (DebugOptions.PrintGraphWithSchedule.getValue(graph.getOptions()) || debug.contextLookup(Throwable.class) != null) { 513 try { 514 SchedulePhase schedule = new SchedulePhase(graph.getOptions()); 515 schedule.apply(structuredGraph); 516 scheduleResult = structuredGraph.getLastSchedule(); 517 } catch (Throwable t) { 518 } 519 } 520 521 } 522 } 523 cfg = scheduleResult == null ? debug.contextLookup(ControlFlowGraph.class) : scheduleResult.getCFG(); 524 blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap(); 525 nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap(); 526 blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks()); 527 } 528 } 529 530 }