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