--- /dev/null 2017-01-22 10:16:57.869617664 -0800 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java 2017-02-15 17:08:40.066948535 -0800 @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.printer; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.bytecode.BytecodeDisassembler; +import org.graalvm.compiler.debug.GraalDebugConfig.Options; +import org.graalvm.compiler.graph.Graph; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.graph.Position; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.BeginNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.PhiNode; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; +import org.graalvm.compiler.nodes.cfg.Block; +import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; +import org.graalvm.compiler.phases.schedule.SchedulePhase; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the + * Ideal Graph Visualizer. + */ +public class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPrinter { + + private final boolean tryToSchedule; + private final SnippetReflectionProvider snippetReflection; + + /** + * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. + * + * @param tryToSchedule If false, no scheduling is done, which avoids exceptions for + * non-schedulable graphs. + */ + public IdealGraphPrinter(OutputStream stream, boolean tryToSchedule, SnippetReflectionProvider snippetReflection) { + super(stream); + this.begin(); + this.tryToSchedule = tryToSchedule; + this.snippetReflection = snippetReflection; + } + + @Override + public SnippetReflectionProvider getSnippetReflectionProvider() { + return snippetReflection; + } + + /** + * Starts a new group of graphs with the given name, short name and method byte code index (BCI) + * as properties. + */ + @Override + public void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci, Map properties) { + beginGroup(); + beginProperties(); + printProperty("name", name); + if (properties != null) { + for (Entry entry : properties.entrySet()) { + printProperty(entry.getKey().toString(), entry.getValue().toString()); + } + } + endProperties(); + beginMethod(name, shortName, bci); + if (method != null && method.getCode() != null) { + printBytecodes(new BytecodeDisassembler(false).disassemble(method)); + } + endMethod(); + } + + /** + * Prints an entire {@link Graph} with the specified title, optionally using short names for + * nodes. + */ + @Override + public void print(Graph graph, String title, Map properties) { + beginGraph(title); + Set noBlockNodes = Node.newSet(); + ScheduleResult schedule = null; + if (graph instanceof StructuredGraph) { + StructuredGraph structuredGraph = (StructuredGraph) graph; + schedule = structuredGraph.getLastSchedule(); + if (schedule == null && tryToSchedule) { + if (Options.PrintIdealGraphSchedule.getValue()) { + try { + SchedulePhase schedulePhase = new SchedulePhase(); + schedulePhase.apply(structuredGraph); + schedule = structuredGraph.getLastSchedule(); + } catch (Throwable t) { + } + } + } + } + ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG(); + + if (properties != null) { + beginProperties(); + for (Entry entry : properties.entrySet()) { + printProperty(entry.getKey().toString(), entry.getValue().toString()); + } + endProperties(); + } + + beginNodes(); + List edges = printNodes(graph, cfg == null ? null : cfg.getNodeToBlock(), noBlockNodes); + endNodes(); + + beginEdges(); + for (Edge edge : edges) { + printEdge(edge); + } + endEdges(); + + if (cfg != null && cfg.getBlocks() != null) { + beginControlFlow(); + for (Block block : cfg.getBlocks()) { + printBlock(graph, block, cfg.getNodeToBlock()); + } + printNoBlock(noBlockNodes); + endControlFlow(); + } + + endGraph(); + flush(); + } + + private List printNodes(Graph graph, NodeMap nodeToBlock, Set noBlockNodes) { + ArrayList edges = new ArrayList<>(); + + NodeMap>> colors = graph.createNodeMap(); + NodeMap>> colorsToString = graph.createNodeMap(); + NodeMap> bits = graph.createNodeMap(); + + for (Node node : graph.getNodes()) { + + beginNode(node.toString(Verbosity.Id)); + beginProperties(); + printProperty("idx", node.toString(Verbosity.Id)); + + Map props = node.getDebugProperties(); + if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) { + String name = node.toString(Verbosity.Name); + printProperty("name", name); + } + printProperty("class", node.getClass().getSimpleName()); + + Block block = nodeToBlock == null || nodeToBlock.isNew(node) ? null : nodeToBlock.get(node); + if (block != null) { + printProperty("block", Integer.toString(block.getId())); + // if (!(node instanceof PhiNode || node instanceof FrameState || node instanceof + // ParameterNode) && !block.nodes().contains(node)) { + // printProperty("notInOwnBlock", "true"); + // } + } else { + printProperty("block", "noBlock"); + noBlockNodes.add(node); + } + + Set> nodeColors = colors.get(node); + if (nodeColors != null) { + for (Entry color : nodeColors) { + String name = color.getKey(); + Integer value = color.getValue(); + printProperty(name, Integer.toString(value)); + } + } + Set> nodeColorStrings = colorsToString.get(node); + if (nodeColorStrings != null) { + for (Entry color : nodeColorStrings) { + String name = color.getKey(); + String value = color.getValue(); + printProperty(name, value); + } + } + Set nodeBits = bits.get(node); + if (nodeBits != null) { + for (String bit : nodeBits) { + printProperty(bit, "true"); + } + } + if (node instanceof BeginNode) { + printProperty("shortName", "B"); + } else if (node.getClass() == EndNode.class) { + printProperty("shortName", "E"); + } else if (node instanceof ConstantNode) { + ConstantNode cn = (ConstantNode) node; + updateStringPropertiesForConstant(props, cn); + } + if (node.predecessor() != null) { + printProperty("hasPredecessor", "true"); + } + + for (Entry entry : props.entrySet()) { + String key = entry.getKey().toString(); + Object value = entry.getValue(); + String valueString; + if (value == null) { + valueString = "null"; + } else { + Class type = value.getClass(); + if (type.isArray()) { + if (!type.getComponentType().isPrimitive()) { + valueString = Arrays.toString((Object[]) value); + } else if (type.getComponentType() == Integer.TYPE) { + valueString = Arrays.toString((int[]) value); + } else if (type.getComponentType() == Double.TYPE) { + valueString = Arrays.toString((double[]) value); + } else { + valueString = toString(); + } + } else { + valueString = value.toString(); + } + } + printProperty(key, valueString); + } + + endProperties(); + endNode(); + + // successors + int fromIndex = 0; + for (Position position : node.successorPositions()) { + Node successor = position.get(node); + if (successor != null) { + edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, position.getName())); + } + fromIndex++; + } + + // inputs + int toIndex = 1; + for (Position position : node.inputPositions()) { + Node input = position.get(node); + if (input != null) { + edges.add(new Edge(input.toString(Verbosity.Id), input.successors().count(), node.toString(Verbosity.Id), toIndex, position.getName())); + } + toIndex++; + } + } + + return edges; + } + + private void printBlock(Graph graph, Block block, NodeMap nodeToBlock) { + beginBlock(Integer.toString(block.getId())); + beginSuccessors(); + for (Block sux : block.getSuccessors()) { + if (sux != null) { + printSuccessor(Integer.toString(sux.getId())); + } + } + endSuccessors(); + beginBlockNodes(); + + Set nodes = Node.newSet(); + + if (nodeToBlock != null) { + for (Node n : graph.getNodes()) { + Block blk = nodeToBlock.isNew(n) ? null : nodeToBlock.get(n); + if (blk == block) { + nodes.add(n); + } + } + } + + if (nodes.size() > 0) { + // if this is the first block: add all locals to this block + if (block.getBeginNode() == ((StructuredGraph) graph).start()) { + for (Node node : graph.getNodes()) { + if (node instanceof ParameterNode) { + nodes.add(node); + } + } + } + + Set snapshot = Node.newSet(nodes); + // add all framestates and phis to their blocks + for (Node node : snapshot) { + if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) { + nodes.add(((StateSplit) node).stateAfter()); + } + if (node instanceof AbstractMergeNode) { + for (PhiNode phi : ((AbstractMergeNode) node).phis()) { + nodes.add(phi); + } + } + } + + for (Node node : nodes) { + printBlockNode(node.toString(Verbosity.Id)); + } + } + endBlockNodes(); + endBlock(); + } + + private void printNoBlock(Set noBlockNodes) { + if (!noBlockNodes.isEmpty()) { + beginBlock("noBlock"); + beginBlockNodes(); + for (Node node : noBlockNodes) { + printBlockNode(node.toString(Verbosity.Id)); + } + endBlockNodes(); + endBlock(); + } + } +}