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 24 25 package org.graalvm.compiler.printer; 26 27 import static org.graalvm.compiler.graph.Edges.Type.Inputs; 28 import static org.graalvm.compiler.graph.Edges.Type.Successors; 29 30 import java.io.IOException; 31 import java.net.URI; 32 import java.net.URISyntaxException; 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.Collection; 36 import java.util.Collections; 37 import java.util.LinkedList; 38 import java.util.List; 39 import java.util.Map; 40 41 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 42 import org.graalvm.compiler.bytecode.Bytecode; 43 import org.graalvm.compiler.core.common.cfg.BlockMap; 44 import org.graalvm.compiler.debug.DebugContext; 45 import org.graalvm.compiler.debug.DebugOptions; 46 import org.graalvm.compiler.graph.CachedGraph; 47 import org.graalvm.compiler.graph.Edges; 48 import org.graalvm.compiler.graph.Graph; 49 import org.graalvm.compiler.graph.InputEdges; 50 import org.graalvm.compiler.graph.Node; 51 import org.graalvm.compiler.graph.NodeClass; 52 import org.graalvm.compiler.graph.NodeMap; 53 import org.graalvm.compiler.graph.NodeSourcePosition; 54 import org.graalvm.compiler.graph.SourceLanguagePosition; 55 import org.graalvm.compiler.nodes.AbstractBeginNode; 56 import org.graalvm.compiler.nodes.AbstractEndNode; 57 import org.graalvm.compiler.nodes.AbstractMergeNode; 58 import org.graalvm.compiler.nodes.ConstantNode; 59 import org.graalvm.compiler.nodes.ControlSinkNode; 60 import org.graalvm.compiler.nodes.ControlSplitNode; 61 import org.graalvm.compiler.nodes.FixedNode; 62 import org.graalvm.compiler.nodes.PhiNode; 63 import org.graalvm.compiler.nodes.ProxyNode; 64 import org.graalvm.compiler.nodes.StructuredGraph; 65 import org.graalvm.compiler.nodes.VirtualState; 66 import org.graalvm.compiler.nodes.cfg.Block; 67 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 68 import org.graalvm.compiler.nodes.util.JavaConstantFormattable; 69 import org.graalvm.compiler.phases.schedule.SchedulePhase; 70 import org.graalvm.graphio.GraphBlocks; 71 import org.graalvm.graphio.GraphElements; 72 import org.graalvm.graphio.GraphOutput; 73 import org.graalvm.graphio.GraphStructure; 74 import org.graalvm.graphio.GraphTypes; 75 76 import jdk.vm.ci.meta.JavaType; 77 import jdk.vm.ci.meta.ResolvedJavaField; 78 import jdk.vm.ci.meta.ResolvedJavaMethod; 79 import jdk.vm.ci.meta.Signature; 80 import org.graalvm.graphio.GraphLocations; 81 82 public class BinaryGraphPrinter implements 83 GraphStructure<BinaryGraphPrinter.GraphInfo, Node, NodeClass<?>, Edges>, 84 GraphBlocks<BinaryGraphPrinter.GraphInfo, Block, Node>, 85 GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition>, 86 GraphLocations<ResolvedJavaMethod, NodeSourcePosition, SourceLanguagePosition>, 87 GraphTypes, GraphPrinter { 88 private final SnippetReflectionProvider snippetReflection; 89 private final GraphOutput<BinaryGraphPrinter.GraphInfo, ResolvedJavaMethod> output; 90 91 public BinaryGraphPrinter(DebugContext ctx, SnippetReflectionProvider snippetReflection) throws IOException { 92 // @formatter:off 93 this.output = ctx.buildOutput(GraphOutput.newBuilder(this). 94 protocolVersion(6, 0). 95 blocks(this). 96 elementsAndLocations(this, this). 97 types(this) 98 ); 99 // @formatter:on 100 this.snippetReflection = snippetReflection; 101 } 102 103 @Override 104 public SnippetReflectionProvider getSnippetReflectionProvider() { 105 return snippetReflection; 106 } 107 108 @Override 109 public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException { 110 output.beginGroup(new GraphInfo(debug, null), name, shortName, method, bci, DebugContext.addVersionProperties(properties)); 111 } 112 113 @Override 114 public void endGroup() throws IOException { 115 output.endGroup(); 116 } 117 118 @Override 119 public void close() { 120 output.close(); 121 } 122 123 @Override 124 public ResolvedJavaMethod method(Object object) { 125 if (object instanceof Bytecode) { 126 return ((Bytecode) object).getMethod(); 127 } else if (object instanceof ResolvedJavaMethod) { 128 return ((ResolvedJavaMethod) object); 129 } else { 130 return null; 131 } 132 } 133 134 @Override 135 public Node node(Object obj) { 136 return obj instanceof Node ? (Node) obj : null; 137 } 138 139 @Override 140 public NodeClass<?> nodeClass(Object obj) { 141 if (obj instanceof NodeClass<?>) { 142 return (NodeClass<?>) obj; 143 } 144 return null; 145 } 146 147 @Override 148 public NodeClass<?> classForNode(Node node) { 149 return node.getNodeClass(); 150 } 151 152 @Override 153 public Object nodeClassType(NodeClass<?> node) { 154 return node.getJavaClass(); 155 } 156 157 @Override 158 public String nameTemplate(NodeClass<?> nodeClass) { 159 return nodeClass.getNameTemplate(); 160 } 161 162 @Override 163 public final GraphInfo graph(GraphInfo currrent, Object obj) { 164 if (obj instanceof Graph) { 165 return new GraphInfo(currrent.debug, (Graph) obj); 166 } else if (obj instanceof CachedGraph) { 167 return new GraphInfo(currrent.debug, ((CachedGraph<?>) obj).getReadonlyCopy()); 168 } else { 169 return null; 170 } 171 } 172 173 @Override 174 public int nodeId(Node n) { 175 return getNodeId(n); 176 } 177 178 @Override 179 public Edges portInputs(NodeClass<?> nodeClass) { 180 return nodeClass.getEdges(Inputs); 181 } 182 183 @Override 184 public Edges portOutputs(NodeClass<?> nodeClass) { 185 return nodeClass.getEdges(Successors); 186 } 187 188 @SuppressWarnings("deprecation") 189 private static int getNodeId(Node node) { 190 return node == null ? -1 : node.getId(); 191 } 192 193 @Override 194 public List<Node> blockNodes(GraphInfo info, Block block) { 195 List<Node> nodes = info.blockToNodes.get(block); 196 if (nodes == null) { 197 return null; 198 } 199 List<Node> extraNodes = new LinkedList<>(); 200 for (Node node : nodes) { 201 findExtraNodes(node, extraNodes); 202 } 203 extraNodes.removeAll(nodes); 204 extraNodes.addAll(0, nodes); 205 return extraNodes; 206 } 207 208 @Override 209 public int blockId(Block sux) { 210 return sux.getId(); 211 } 212 213 @Override 214 public List<Block> blockSuccessors(Block block) { 215 return Arrays.asList(block.getSuccessors()); 216 } 217 218 @Override 219 public Iterable<Node> nodes(GraphInfo info) { 220 return info.graph.getNodes(); 221 } 222 223 @Override 224 public int nodesCount(GraphInfo info) { 225 return info.graph.getNodeCount(); 226 } 227 228 @Override 229 @SuppressWarnings({"unchecked", "rawtypes"}) 230 public void nodeProperties(GraphInfo info, Node node, Map<String, Object> props) { 231 node.getDebugProperties((Map) props); 232 Graph graph = info.graph; 233 ControlFlowGraph cfg = info.cfg; 234 NodeMap<Block> nodeToBlocks = info.nodeToBlocks; 235 if (cfg != null && DebugOptions.PrintGraphProbabilities.getValue(graph.getOptions()) && node instanceof FixedNode) { 236 try { 237 props.put("probability", cfg.blockFor(node).probability()); 238 } catch (Throwable t) { 239 props.put("probability", 0.0); 240 props.put("probability-exception", t); 241 } 242 } 243 244 try { 245 props.put("NodeCost-Size", node.estimatedNodeSize()); 246 props.put("NodeCost-Cycles", node.estimatedNodeCycles()); 247 } catch (Throwable t) { 248 props.put("node-cost-exception", t.getMessage()); 249 } 250 251 if (nodeToBlocks != null) { 252 Object block = getBlockForNode(node, nodeToBlocks); 253 if (block != null) { 254 props.put("node-to-block", block); 255 } 256 } 257 258 if (node instanceof ControlSinkNode) { 259 props.put("category", "controlSink"); 260 } else if (node instanceof ControlSplitNode) { 261 props.put("category", "controlSplit"); 262 } else if (node instanceof AbstractMergeNode) { 263 props.put("category", "merge"); 264 } else if (node instanceof AbstractBeginNode) { 265 props.put("category", "begin"); 266 } else if (node instanceof AbstractEndNode) { 267 props.put("category", "end"); 268 } else if (node instanceof FixedNode) { 269 props.put("category", "fixed"); 270 } else if (node instanceof VirtualState) { 271 props.put("category", "state"); 272 } else if (node instanceof PhiNode) { 273 props.put("category", "phi"); 274 } else if (node instanceof ProxyNode) { 275 props.put("category", "proxy"); 276 } else { 277 if (node instanceof ConstantNode) { 278 ConstantNode cn = (ConstantNode) node; 279 updateStringPropertiesForConstant((Map) props, cn); 280 } 281 props.put("category", "floating"); 282 } 283 if (getSnippetReflectionProvider() != null) { 284 for (Map.Entry<String, Object> prop : props.entrySet()) { 285 if (prop.getValue() instanceof JavaConstantFormattable) { 286 props.put(prop.getKey(), ((JavaConstantFormattable) prop.getValue()).format(this)); 287 } 288 } 289 } 290 } 291 292 private Object getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) { 293 if (nodeToBlocks.isNew(node)) { 294 return "NEW (not in schedule)"; 295 } else { 296 Block block = nodeToBlocks.get(node); 297 if (block != null) { 298 return block.getId(); 299 } else if (node instanceof PhiNode) { 300 return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks); 301 } 302 } 303 return null; 304 } 305 306 private static void findExtraNodes(Node node, Collection<? super Node> extraNodes) { 307 if (node instanceof AbstractMergeNode) { 308 AbstractMergeNode merge = (AbstractMergeNode) node; 309 for (PhiNode phi : merge.phis()) { 310 extraNodes.add(phi); 311 } 312 } 313 } 314 315 @Override 316 public boolean nodeHasPredecessor(Node node) { 317 return node.predecessor() != null; 318 } 319 320 @Override 321 public List<Block> blocks(GraphInfo graph) { 322 return graph.blocks; 323 } 324 325 @Override 326 public void print(DebugContext debug, Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException { 327 output.print(new GraphInfo(debug, graph), properties, id, format, args); 328 } 329 330 @Override 331 public int portSize(Edges port) { 332 return port.getCount(); 333 } 334 335 @Override 336 public boolean edgeDirect(Edges port, int index) { 337 return index < port.getDirectCount(); 338 } 339 340 @Override 341 public String edgeName(Edges port, int index) { 342 return port.getName(index); 343 } 344 345 @Override 346 public Object edgeType(Edges port, int index) { 347 return ((InputEdges) port).getInputType(index); 348 } 349 350 @Override 351 public Collection<? extends Node> edgeNodes(GraphInfo graph, Node node, Edges port, int i) { 352 if (i < port.getDirectCount()) { 353 Node single = Edges.getNode(node, port.getOffsets(), i); 354 return Collections.singletonList(single); 355 } else { 356 return Edges.getNodeList(node, port.getOffsets(), i); 357 } 358 } 359 360 @Override 361 public Object enumClass(Object enumValue) { 362 if (enumValue instanceof Enum) { 363 return enumValue.getClass(); 364 } 365 return null; 366 } 367 368 @Override 369 public int enumOrdinal(Object obj) { 370 if (obj instanceof Enum<?>) { 371 return ((Enum<?>) obj).ordinal(); 372 } 373 return -1; 374 } 375 376 @SuppressWarnings("unchecked") 377 @Override 378 public String[] enumTypeValues(Object clazz) { 379 if (clazz instanceof Class<?>) { 380 Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) clazz; 381 Enum<?>[] constants = enumClass.getEnumConstants(); 382 if (constants != null) { 383 String[] names = new String[constants.length]; 384 for (int i = 0; i < constants.length; i++) { 385 names[i] = constants[i].name(); 386 } 387 return names; 388 } 389 } 390 return null; 391 } 392 393 @Override 394 public String typeName(Object obj) { 395 if (obj instanceof Class<?>) { 396 return ((Class<?>) obj).getName(); 397 } 398 if (obj instanceof JavaType) { 399 return ((JavaType) obj).toJavaName(); 400 } 401 return null; 402 } 403 404 @Override 405 public byte[] methodCode(ResolvedJavaMethod method) { 406 return method.getCode(); 407 } 408 409 @Override 410 public int methodModifiers(ResolvedJavaMethod method) { 411 return method.getModifiers(); 412 } 413 414 @Override 415 public Signature methodSignature(ResolvedJavaMethod method) { 416 return method.getSignature(); 417 } 418 419 @Override 420 public String methodName(ResolvedJavaMethod method) { 421 return method.getName(); 422 } 423 424 @Override 425 public Object methodDeclaringClass(ResolvedJavaMethod method) { 426 return method.getDeclaringClass(); 427 } 428 429 @Override 430 public int fieldModifiers(ResolvedJavaField field) { 431 return field.getModifiers(); 432 } 433 434 @Override 435 public String fieldTypeName(ResolvedJavaField field) { 436 return field.getType().toJavaName(); 437 } 438 439 @Override 440 public String fieldName(ResolvedJavaField field) { 441 return field.getName(); 442 } 443 444 @Override 445 public Object fieldDeclaringClass(ResolvedJavaField field) { 446 return field.getDeclaringClass(); 447 } 448 449 @Override 450 public ResolvedJavaField field(Object object) { 451 if (object instanceof ResolvedJavaField) { 452 return (ResolvedJavaField) object; 453 } 454 return null; 455 } 456 457 @Override 458 public Signature signature(Object object) { 459 if (object instanceof Signature) { 460 return (Signature) object; 461 } 462 return null; 463 } 464 465 @Override 466 public int signatureParameterCount(Signature signature) { 467 return signature.getParameterCount(false); 468 } 469 470 @Override 471 public String signatureParameterTypeName(Signature signature, int index) { 472 return signature.getParameterType(index, null).getName(); 473 } 474 475 @Override 476 public String signatureReturnTypeName(Signature signature) { 477 return signature.getReturnType(null).getName(); 478 } 479 480 @Override 481 public NodeSourcePosition nodeSourcePosition(Object object) { 482 if (object instanceof NodeSourcePosition) { 483 return (NodeSourcePosition) object; 484 } 485 return null; 486 } 487 488 @Override 489 public ResolvedJavaMethod nodeSourcePositionMethod(NodeSourcePosition pos) { 490 return pos.getMethod(); 491 } 492 493 @Override 494 public NodeSourcePosition nodeSourcePositionCaller(NodeSourcePosition pos) { 495 return pos.getCaller(); 496 } 497 498 @Override 499 public int nodeSourcePositionBCI(NodeSourcePosition pos) { 500 return pos.getBCI(); 501 } 502 503 @Override 504 public StackTraceElement methodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { 505 return method.asStackTraceElement(bci); 506 } 507 508 @Override 509 public Iterable<SourceLanguagePosition> methodLocation(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { 510 StackTraceElement e = methodStackTraceElement(method, bci, pos); 511 class JavaSourcePosition implements SourceLanguagePosition { 512 513 @Override 514 public String toShortString() { 515 return e.toString(); 516 } 517 518 @Override 519 public int getOffsetEnd() { 520 return -1; 521 } 522 523 @Override 524 public int getOffsetStart() { 525 return -1; 526 } 527 528 @Override 529 public int getLineNumber() { 530 return e.getLineNumber(); 531 } 532 533 @Override 534 public URI getURI() { 535 String path = e.getFileName(); 536 try { 537 return path == null ? null : new URI(null, null, path, null); 538 } catch (URISyntaxException ex) { 539 throw new IllegalArgumentException(ex); 540 } 541 } 542 543 @Override 544 public String getLanguage() { 545 return "Java"; 546 } 547 } 548 549 List<SourceLanguagePosition> arr = new ArrayList<>(); 550 arr.add(new JavaSourcePosition()); 551 NodeSourcePosition at = pos; 552 while (at != null) { 553 SourceLanguagePosition cur = at.getSourceLanguage(); 554 if (cur != null) { 555 arr.add(cur); 556 } 557 at = at.getCaller(); 558 } 559 return arr; 560 } 561 562 @Override 563 public String locationLanguage(SourceLanguagePosition location) { 564 return location.getLanguage(); 565 } 566 567 @Override 568 public URI locationURI(SourceLanguagePosition location) { 569 return location.getURI(); 570 } 571 572 @Override 573 public int locationLineNumber(SourceLanguagePosition location) { 574 return location.getLineNumber(); 575 } 576 577 @Override 578 public int locationOffsetStart(SourceLanguagePosition location) { 579 return location.getOffsetStart(); 580 } 581 582 @Override 583 public int locationOffsetEnd(SourceLanguagePosition location) { 584 return location.getOffsetEnd(); 585 } 586 587 static final class GraphInfo { 588 final DebugContext debug; 589 final Graph graph; 590 final ControlFlowGraph cfg; 591 final BlockMap<List<Node>> blockToNodes; 592 final NodeMap<Block> nodeToBlocks; 593 final List<Block> blocks; 594 595 private GraphInfo(DebugContext debug, Graph graph) { 596 this.debug = debug; 597 this.graph = graph; 598 StructuredGraph.ScheduleResult scheduleResult = null; 599 if (graph instanceof StructuredGraph) { 600 601 StructuredGraph structuredGraph = (StructuredGraph) graph; 602 scheduleResult = structuredGraph.getLastSchedule(); 603 if (scheduleResult == null) { 604 605 // Also provide a schedule when an error occurs 606 if (DebugOptions.PrintGraphWithSchedule.getValue(graph.getOptions()) || debug.contextLookup(Throwable.class) != null) { 607 try { 608 SchedulePhase schedule = new SchedulePhase(graph.getOptions()); 609 schedule.apply(structuredGraph); 610 scheduleResult = structuredGraph.getLastSchedule(); 611 } catch (Throwable t) { 612 } 613 } 614 615 } 616 } 617 cfg = scheduleResult == null ? debug.contextLookup(ControlFlowGraph.class) : scheduleResult.getCFG(); 618 blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap(); 619 nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap(); 620 blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks()); 621 } 622 } 623 624 }