view graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BasicIdealGraphPrinter.java @ 7530:5e3d1a68664e

applied mx eclipseformat to all Java files
author Doug Simon <doug.simon@oracle.com>
date Wed, 23 Jan 2013 16:34:57 +0100
parents 8fd81d0e3acf
children b6b930315135
line wrap: on
line source

/*
 * 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 com.oracle.graal.printer;

import java.io.*;
import java.util.*;
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, "US-ASCII");
        } 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("<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>");
    }

    /**
     * Ends the current group.
     */
    public void endGroup() {
        stream.println("</group>");
    }

    /**
     * Finishes the graph document and flushes the output stream.
     */
    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("&amp;");
                            break;
                        case '<':
                            str.append("&lt;");
                            break;
                        case '>':
                            str.append("&gt;");
                            break;
                        case '"':
                            str.append("&quot;");
                            break;
                        case '\'':
                            str.append("&apos;");
                            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();
        }
    }
}