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 NodeMap<Block> nodeToBlocks = info.nodeToBlocks; 233 234 if (nodeToBlocks != null) { 235 Block block = getBlockForNode(node, nodeToBlocks); 236 if (block != null) { 237 props.put("relativeFrequency", block.getRelativeFrequency()); 238 props.put("nodeToBlock", block); 239 } 240 } 241 242 props.put("nodeCostSize", node.estimatedNodeSize()); 243 props.put("nodeCostCycles", node.estimatedNodeCycles()); 244 245 if (nodeToBlocks != null) { 246 Object block = getBlockForNode(node, nodeToBlocks); 247 if (block != null) { 248 props.put("nodeToBlock", block); 249 } 250 } 251 252 if (node instanceof ControlSinkNode) { 253 props.put("category", "controlSink"); 254 } else if (node instanceof ControlSplitNode) { 255 props.put("category", "controlSplit"); 256 } else if (node instanceof AbstractMergeNode) { 257 props.put("category", "merge"); 258 } else if (node instanceof AbstractBeginNode) { 259 props.put("category", "begin"); 260 } else if (node instanceof AbstractEndNode) { 261 props.put("category", "end"); 262 } else if (node instanceof FixedNode) { 263 props.put("category", "fixed"); 264 } else if (node instanceof VirtualState) { 265 props.put("category", "state"); 266 } else if (node instanceof PhiNode) { 267 props.put("category", "phi"); 268 } else if (node instanceof ProxyNode) { 269 props.put("category", "proxy"); 270 } else { 271 if (node instanceof ConstantNode) { 272 ConstantNode cn = (ConstantNode) node; 273 updateStringPropertiesForConstant((Map) props, cn); 274 } 275 props.put("category", "floating"); 276 } 277 if (getSnippetReflectionProvider() != null) { 278 for (Map.Entry<String, Object> prop : props.entrySet()) { 279 if (prop.getValue() instanceof JavaConstantFormattable) { 280 props.put(prop.getKey(), ((JavaConstantFormattable) prop.getValue()).format(this)); 281 } 282 } 283 } 284 } 285 286 private Block getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) { 287 if (nodeToBlocks.isNew(node)) { 288 return null; 289 } else { 290 Block block = nodeToBlocks.get(node); 291 if (block != null) { 292 return block; 293 } else if (node instanceof PhiNode) { 294 return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks); 295 } 296 } 297 return null; 298 } 299 300 private static void findExtraNodes(Node node, Collection<? super Node> extraNodes) { 301 if (node instanceof AbstractMergeNode) { 302 AbstractMergeNode merge = (AbstractMergeNode) node; 303 for (PhiNode phi : merge.phis()) { 304 extraNodes.add(phi); 305 } 306 } 307 } 308 309 @Override 310 public boolean nodeHasPredecessor(Node node) { 311 return node.predecessor() != null; 312 } 313 314 @Override 315 public List<Block> blocks(GraphInfo graph) { 316 return graph.blocks; 317 } 318 319 @Override 320 public void print(DebugContext debug, Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException { 321 output.print(new GraphInfo(debug, graph), properties, id, format, args); 322 } 323 324 @Override 325 public int portSize(Edges port) { 326 return port.getCount(); 327 } 328 329 @Override 330 public boolean edgeDirect(Edges port, int index) { 331 return index < port.getDirectCount(); 332 } 333 334 @Override 335 public String edgeName(Edges port, int index) { 336 return port.getName(index); 337 } 338 339 @Override 340 public Object edgeType(Edges port, int index) { 341 return ((InputEdges) port).getInputType(index); 342 } 343 344 @Override 345 public Collection<? extends Node> edgeNodes(GraphInfo graph, Node node, Edges port, int i) { 346 if (i < port.getDirectCount()) { 347 Node single = Edges.getNode(node, port.getOffsets(), i); 348 return Collections.singletonList(single); 349 } else { 350 return Edges.getNodeList(node, port.getOffsets(), i); 351 } 352 } 353 354 @Override 355 public Object enumClass(Object enumValue) { 356 if (enumValue instanceof Enum) { 357 return enumValue.getClass(); 358 } 359 return null; 360 } 361 362 @Override 363 public int enumOrdinal(Object obj) { 364 if (obj instanceof Enum<?>) { 365 return ((Enum<?>) obj).ordinal(); 366 } 367 return -1; 368 } 369 370 @SuppressWarnings("unchecked") 371 @Override 372 public String[] enumTypeValues(Object clazz) { 373 if (clazz instanceof Class<?>) { 374 Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) clazz; 375 Enum<?>[] constants = enumClass.getEnumConstants(); 376 if (constants != null) { 377 String[] names = new String[constants.length]; 378 for (int i = 0; i < constants.length; i++) { 379 names[i] = constants[i].name(); 380 } 381 return names; 382 } 383 } 384 return null; 385 } 386 387 @Override 388 public String typeName(Object obj) { 389 if (obj instanceof Class<?>) { 390 return ((Class<?>) obj).getName(); 391 } 392 if (obj instanceof JavaType) { 393 return ((JavaType) obj).toJavaName(); 394 } 395 return null; 396 } 397 398 @Override 399 public byte[] methodCode(ResolvedJavaMethod method) { 400 return method.getCode(); 401 } 402 403 @Override 404 public int methodModifiers(ResolvedJavaMethod method) { 405 return method.getModifiers(); 406 } 407 408 @Override 409 public Signature methodSignature(ResolvedJavaMethod method) { 410 return method.getSignature(); 411 } 412 413 @Override 414 public String methodName(ResolvedJavaMethod method) { 415 return method.getName(); 416 } 417 418 @Override 419 public Object methodDeclaringClass(ResolvedJavaMethod method) { 420 return method.getDeclaringClass(); 421 } 422 423 @Override 424 public int fieldModifiers(ResolvedJavaField field) { 425 return field.getModifiers(); 426 } 427 428 @Override 429 public String fieldTypeName(ResolvedJavaField field) { 430 return field.getType().toJavaName(); 431 } 432 433 @Override 434 public String fieldName(ResolvedJavaField field) { 435 return field.getName(); 436 } 437 438 @Override 439 public Object fieldDeclaringClass(ResolvedJavaField field) { 440 return field.getDeclaringClass(); 441 } 442 443 @Override 444 public ResolvedJavaField field(Object object) { 445 if (object instanceof ResolvedJavaField) { 446 return (ResolvedJavaField) object; 447 } 448 return null; 449 } 450 451 @Override 452 public Signature signature(Object object) { 453 if (object instanceof Signature) { 454 return (Signature) object; 455 } 456 return null; 457 } 458 459 @Override 460 public int signatureParameterCount(Signature signature) { 461 return signature.getParameterCount(false); 462 } 463 464 @Override 465 public String signatureParameterTypeName(Signature signature, int index) { 466 return signature.getParameterType(index, null).getName(); 467 } 468 469 @Override 470 public String signatureReturnTypeName(Signature signature) { 471 return signature.getReturnType(null).getName(); 472 } 473 474 @Override 475 public NodeSourcePosition nodeSourcePosition(Object object) { 476 if (object instanceof NodeSourcePosition) { 477 return (NodeSourcePosition) object; 478 } 479 return null; 480 } 481 482 @Override 483 public ResolvedJavaMethod nodeSourcePositionMethod(NodeSourcePosition pos) { 484 return pos.getMethod(); 485 } 486 487 @Override 488 public NodeSourcePosition nodeSourcePositionCaller(NodeSourcePosition pos) { 489 return pos.getCaller(); 490 } 491 492 @Override 493 public int nodeSourcePositionBCI(NodeSourcePosition pos) { 494 return pos.getBCI(); 495 } 496 497 @Override 498 public StackTraceElement methodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { 499 return method.asStackTraceElement(bci); 500 } 501 502 @Override 503 public Iterable<SourceLanguagePosition> methodLocation(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) { 504 StackTraceElement e = methodStackTraceElement(method, bci, pos); 505 class JavaSourcePosition implements SourceLanguagePosition { 506 507 @Override 508 public String toShortString() { 509 return e.toString(); 510 } 511 512 @Override 513 public int getOffsetEnd() { 514 return -1; 515 } 516 517 @Override 518 public int getOffsetStart() { 519 return -1; 520 } 521 522 @Override 523 public int getLineNumber() { 524 return e.getLineNumber(); 525 } 526 527 @Override 528 public URI getURI() { 529 String path = e.getFileName(); 530 try { 531 return path == null ? null : new URI(null, null, path, null); 532 } catch (URISyntaxException ex) { 533 throw new IllegalArgumentException(ex); 534 } 535 } 536 537 @Override 538 public String getLanguage() { 539 return "Java"; 540 } 541 } 542 543 List<SourceLanguagePosition> arr = new ArrayList<>(); 544 arr.add(new JavaSourcePosition()); 545 NodeSourcePosition at = pos; 546 while (at != null) { 547 SourceLanguagePosition cur = at.getSourceLanguage(); 548 if (cur != null) { 549 arr.add(cur); 550 } 551 at = at.getCaller(); 552 } 553 return arr; 554 } 555 556 @Override 557 public String locationLanguage(SourceLanguagePosition location) { 558 return location.getLanguage(); 559 } 560 561 @Override 562 public URI locationURI(SourceLanguagePosition location) { 563 return location.getURI(); 564 } 565 566 @Override 567 public int locationLineNumber(SourceLanguagePosition location) { 568 return location.getLineNumber(); 569 } 570 571 @Override 572 public int locationOffsetStart(SourceLanguagePosition location) { 573 return location.getOffsetStart(); 574 } 575 576 @Override 577 public int locationOffsetEnd(SourceLanguagePosition location) { 578 return location.getOffsetEnd(); 579 } 580 581 static final class GraphInfo { 582 final DebugContext debug; 583 final Graph graph; 584 final ControlFlowGraph cfg; 585 final BlockMap<List<Node>> blockToNodes; 586 final NodeMap<Block> nodeToBlocks; 587 final List<Block> blocks; 588 589 private GraphInfo(DebugContext debug, Graph graph) { 590 this.debug = debug; 591 this.graph = graph; 592 StructuredGraph.ScheduleResult scheduleResult = null; 593 if (graph instanceof StructuredGraph) { 594 595 StructuredGraph structuredGraph = (StructuredGraph) graph; 596 scheduleResult = structuredGraph.getLastSchedule(); 597 if (scheduleResult == null) { 598 599 // Also provide a schedule when an error occurs 600 if (DebugOptions.PrintGraphWithSchedule.getValue(graph.getOptions()) || debug.contextLookup(Throwable.class) != null) { 601 try { 602 SchedulePhase schedule = new SchedulePhase(graph.getOptions()); 603 schedule.apply(structuredGraph); 604 scheduleResult = structuredGraph.getLastSchedule(); 605 } catch (Throwable t) { 606 } 607 } 608 609 } 610 } 611 cfg = scheduleResult == null ? debug.contextLookup(ControlFlowGraph.class) : scheduleResult.getCFG(); 612 blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap(); 613 nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap(); 614 blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks()); 615 } 616 } 617 618 }