--- /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/BasicIdealGraphPrinter.java 2017-02-15 17:08:37.163821431 -0800 @@ -0,0 +1,366 @@ +/* + * 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.BufferedOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Elementary, generic generator of Ideal Graph Visualizer input for use in printers for specific + * data structures. + */ +class BasicIdealGraphPrinter { + + /** + * Edge between two nodes. + */ + protected static class Edge { + + final String from; + final int fromIndex; + final String to; + final int toIndex; + final String label; + + public Edge(String from, int fromIndex, String to, int toIndex, String label) { + assert (from != null && to != null); + this.from = from; + this.fromIndex = fromIndex; + this.to = to; + this.toIndex = toIndex; + this.label = label; + } + + @Override + public int hashCode() { + int h = from.hashCode() ^ to.hashCode(); + h = 3 * h + fromIndex; + h = 5 * h + toIndex; + if (label != null) { + h ^= label.hashCode(); + } + return h; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Edge) { + Edge other = (Edge) obj; + return from.equals(other.from) && fromIndex == other.fromIndex && to.equals(other.to) && toIndex == other.toIndex && + (label == other.label || (label != null && label.equals(other.label))); + } + return false; + } + } + + private final PrintStream stream; + + /** + * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream. + */ + protected BasicIdealGraphPrinter(OutputStream stream) { + try { + OutputStream buffered; + if (stream instanceof BufferedOutputStream) { + buffered = stream; + } else { + buffered = new BufferedOutputStream(stream, 256 * 1024); + } + this.stream = new PrintStream(buffered, false, Charset.defaultCharset().name()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + /** + * Flushes any buffered output. + */ + protected void flush() { + stream.flush(); + } + + /** + * Starts a new graph document. + */ + protected void begin() { + stream.println(""); + } + + protected void beginGroup() { + stream.println(""); + } + + protected void beginMethod(String name, String shortName, int bci) { + stream.printf(" %n", escape(name), escape(shortName), bci); + } + + protected void beginBytecodes() { + stream.println(" \n"); + } + + protected void printBytecodes(String disassembly) { + beginBytecodes(); + stream.println(disassembly); + endBytecodes(); + } + + protected void endMethod() { + stream.println(" "); + } + + protected void beginGraph(String title) { + stream.printf(" %n", escape(title)); + } + + protected void beginProperties() { + stream.print(""); + } + + protected void printProperty(String name, String value) { + stream.printf("

%s

", escape(name), escape(value)); + } + + protected void endProperties() { + stream.print("
"); + } + + protected void printProperties(Map properties) { + beginProperties(); + for (Entry entry : properties.entrySet()) { + printProperty(entry.getKey(), entry.getValue()); + } + endProperties(); + } + + protected void beginNodes() { + stream.println(" "); + } + + protected void beginNode(String id) { + stream.printf(" ", escape(id)); + } + + protected void endNode() { + stream.println(" "); + } + + protected void printNode(String id, Map properties) { + beginNode(id); + if (properties != null) { + printProperties(properties); + } + endNode(); + } + + protected void endNodes() { + stream.println(" "); + } + + protected void beginEdges() { + stream.println(" "); + } + + protected void printEdge(Edge edge) { + stream.printf(" %n", escape(edge.from), edge.fromIndex, escape(edge.to), edge.toIndex, escape(edge.label)); + } + + protected void endEdges() { + stream.println(" "); + } + + protected void beginControlFlow() { + stream.println(" "); + } + + protected void beginBlock(String name) { + stream.printf(" %n", escape(name)); + } + + protected void beginSuccessors() { + stream.println(" "); + } + + protected void printSuccessor(String name) { + stream.printf(" %n", escape(name)); + } + + protected void endSuccessors() { + stream.println(" "); + } + + protected void beginBlockNodes() { + stream.println(" "); + } + + protected void printBlockNode(String nodeId) { + stream.printf(" %n", escape(nodeId)); + } + + protected void endBlockNodes() { + stream.println(" "); + } + + protected void endBlock() { + stream.println(" "); + } + + protected void endControlFlow() { + stream.println(" "); + } + + protected void endGraph() { + stream.println("
"); + } + + /** + * Ends the current group. + */ + public void endGroup() { + stream.println("
"); + } + + /** + * Finishes the graph document and flushes the output stream. + */ + protected void end() { + stream.println("
"); + flush(); + } + + public void close() { + end(); + stream.close(); + } + + public boolean isValid() { + return !stream.checkError(); + } + + private static String escape(String s) { + StringBuilder str = null; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '&': + case '<': + case '>': + case '"': + case '\'': + if (str == null) { + str = new StringBuilder(); + str.append(s, 0, i); + } + switch (c) { + case '&': + str.append("&"); + break; + case '<': + str.append("<"); + break; + case '>': + str.append(">"); + break; + case '"': + str.append("""); + break; + case '\'': + str.append("'"); + break; + default: + assert false; + } + break; + case '\u0000': + case '\u0001': + case '\u0002': + case '\u0003': + case '\u0004': + case '\u0005': + case '\u0006': + case '\u0007': + case '\u0008': + case '\u000b': + case '\u000c': + case '\u000e': + case '\u000f': + case '\u0010': + case '\u0011': + case '\u0012': + case '\u0013': + case '\u0014': + case '\u0015': + case '\u0016': + case '\u0017': + case '\u0018': + case '\u0019': + case '\u001a': + case '\u001b': + case '\u001c': + case '\u001d': + case '\u001e': + case '\u001f': + if (str == null) { + str = new StringBuilder(); + str.append(s, 0, i); + } + str.append("'0x").append(Integer.toHexString(c)); + break; + default: + if (str != null) { + str.append(c); + } + break; + } + } + if (str == null) { + return s; + } else { + return str.toString(); + } + } +}