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;
class BasicIdealGraphPrinter {
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;
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);
}
}
protected void flush() {
stream.flush();
}
protected void begin() {
stream.println("<graphDocument>");
}
protected void beginGroup() {
stream.println("<group>");
}
protected void beginMethod(String name, String shortName, int bci) {
stream.printf(" <method name='%s' shortName='%s' bci='%d'>%n", escape(name), escape(shortName), bci);
}
protected void beginBytecodes() {
stream.println(" <bytecodes>\n<![CDATA[");
}
protected void printBytecode(int bci, String mnemonic, int[] extra) {
stream.print(bci);
stream.print(' ');
stream.print(mnemonic);
if (extra != null) {
for (int b : extra) {
stream.print(' ');
stream.print(b);
}
}
stream.println();
}
protected void endBytecodes() {
stream.println(" ]]></bytecodes>");
}
protected void printBytecodes(String disassembly) {
beginBytecodes();
stream.println(disassembly);
endBytecodes();
}
protected void endMethod() {
stream.println(" </method>");
}
protected void beginGraph(String title) {
stream.printf(" <graph name='%s'>%n", escape(title));
}
protected void beginProperties() {
stream.print("<properties>");
}
protected void printProperty(String name, String value) {
stream.printf("<p name='%s'>%s</p>", escape(name), escape(value));
}
protected void endProperties() {
stream.print("</properties>");
}
protected void printProperties(Map<String, String> properties) {
beginProperties();
for (Entry<String, String> entry : properties.entrySet()) {
printProperty(entry.getKey(), entry.getValue());
}
endProperties();
}
protected void beginNodes() {
stream.println(" <nodes>");
}
protected void beginNode(String id) {
stream.printf(" <node id='%s'>", escape(id));
}
protected void endNode() {
stream.println(" </node>");
}
protected void printNode(String id, Map<String, String> properties) {
beginNode(id);
if (properties != null) {
printProperties(properties);
}
endNode();
}
protected void endNodes() {
stream.println(" </nodes>");
}
protected void beginEdges() {
stream.println(" <edges>");
}
protected void printEdge(Edge edge) {
stream.printf(" <edge from='%s' fromIndex='%d' to='%s' toIndex='%d' label='%s' />%n", escape(edge.from), edge.fromIndex, escape(edge.to), edge.toIndex, escape(edge.label));
}
protected void endEdges() {
stream.println(" </edges>");
}
protected void beginControlFlow() {
stream.println(" <controlFlow>");
}
protected void beginBlock(String name) {
stream.printf(" <block name='%s'>%n", escape(name));
}
protected void beginSuccessors() {
stream.println(" <successors>");
}
protected void printSuccessor(String name) {
stream.printf(" <successor name='%s'/>%n", escape(name));
}
protected void endSuccessors() {
stream.println(" </successors>");
}
protected void beginBlockNodes() {
stream.println(" <nodes>");
}
protected void printBlockNode(String nodeId) {
stream.printf(" <node id='%s'/>%n", escape(nodeId));
}
protected void endBlockNodes() {
stream.println(" </nodes>");
}
protected void endBlock() {
stream.println(" </block>");
}
protected void endControlFlow() {
stream.println(" </controlFlow>");
}
protected void endGraph() {
stream.println(" </graph>");
}
public void endGroup() {
stream.println("</group>");
}
protected void end() {
stream.println("</graphDocument>");
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();
}
}
}