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 }