langtools/src/share/classes/com/sun/tools/javac/util/GraphUtils.java
author mcimadamore
Tue, 12 Feb 2013 19:25:09 +0000
changeset 15717 ab55670d2e62
child 19914 d86271bd430a
permissions -rw-r--r--
8007464: Add graph inference support Summary: Add support for more aggressive type-inference scheme Reviewed-by: jjg
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15717
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     1
/*
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     2
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     4
 *
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    10
 *
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    15
 * accompanied this code).
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    16
 *
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    20
 *
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    23
 * questions.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    24
 */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    25
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    26
package com.sun.tools.javac.util;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    27
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    28
/** <p><b>This is NOT part of any supported API.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    29
 *  If you write code that depends on this, you do so at your own risk.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    30
 *  This code and its internal interfaces are subject to change or
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    31
 *  deletion without notice.</b>
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    32
 */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    33
public class GraphUtils {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    34
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    35
    /**
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    36
     * This class is a basic abstract class for representing a node.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    37
     * A node is associated with a given data.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    38
     */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    39
    public static abstract class Node<D> {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    40
        public final D data;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    41
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    42
        public Node(D data) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    43
            this.data = data;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    44
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    45
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    46
        public abstract Iterable<? extends Node<D>> getDependencies();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    47
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    48
        public abstract String printDependency(Node<D> to);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    49
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    50
        @Override
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    51
        public String toString() {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    52
            return data.toString();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    53
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    54
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    55
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    56
    /**
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    57
     * This class specialized Node, by adding elements that are required in order
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    58
     * to perform Tarjan computation of strongly connected components.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    59
     */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    60
    public static abstract class TarjanNode<D> extends Node<D> implements Comparable<TarjanNode<D>> {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    61
        int index = -1;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    62
        int lowlink;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    63
        boolean active;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    64
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    65
        public TarjanNode(D data) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    66
            super(data);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    67
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    68
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    69
        public abstract Iterable<? extends TarjanNode<D>> getDependencies();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    70
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    71
        public int compareTo(TarjanNode<D> o) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    72
            return (index < o.index) ? -1 : (index == o.index) ? 0 : 1;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    73
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    74
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    75
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    76
    /**
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    77
     * Tarjan's algorithm to determine strongly connected components of a
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    78
     * directed graph in linear time. Works on TarjanNode.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    79
     */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    80
    public static <D, N extends TarjanNode<D>> List<? extends List<? extends N>> tarjan(Iterable<? extends N> nodes) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    81
        ListBuffer<List<N>> cycles = ListBuffer.lb();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    82
        ListBuffer<N> stack = ListBuffer.lb();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    83
        int index = 0;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    84
        for (N node: nodes) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    85
            if (node.index == -1) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    86
                index += tarjan(node, index, stack, cycles);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    87
            }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    88
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    89
        return cycles.toList();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    90
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    91
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    92
    private static <D, N extends TarjanNode<D>> int tarjan(N v, int index, ListBuffer<N> stack, ListBuffer<List<N>> cycles) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    93
        v.index = index;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    94
        v.lowlink = index;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    95
        index++;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    96
        stack.prepend(v);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    97
        v.active = true;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    98
        for (TarjanNode<D> nd: v.getDependencies()) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
    99
            @SuppressWarnings("unchecked")
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   100
            N n = (N)nd;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   101
            if (n.index == -1) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   102
                tarjan(n, index, stack, cycles);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   103
                v.lowlink = Math.min(v.lowlink, n.lowlink);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   104
            } else if (stack.contains(n)) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   105
                v.lowlink = Math.min(v.lowlink, n.index);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   106
            }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   107
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   108
        if (v.lowlink == v.index) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   109
            N n;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   110
            ListBuffer<N> cycle = ListBuffer.lb();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   111
            do {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   112
                n = stack.remove();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   113
                n.active = false;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   114
                cycle.add(n);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   115
            } while (n != v);
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   116
            cycles.add(cycle.toList());
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   117
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   118
        return index;
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   119
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   120
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   121
    /**
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   122
     * Debugging: dot representation of a set of connected nodes. The resulting
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   123
     * dot representation will use {@code Node.toString} to display node labels
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   124
     * and {@code Node.printDependency} to display edge labels. The resulting
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   125
     * representation is also customizable with a graph name and a header.
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   126
     */
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   127
    public static <D> String toDot(Iterable<? extends TarjanNode<D>> nodes, String name, String header) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   128
        StringBuilder buf = new StringBuilder();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   129
        buf.append(String.format("digraph %s {\n", name));
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   130
        buf.append(String.format("label = \"%s\";\n", header));
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   131
        //dump nodes
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   132
        for (TarjanNode<D> n : nodes) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   133
            buf.append(String.format("%s [label = \"%s\"];\n", n.hashCode(), n.toString()));
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   134
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   135
        //dump arcs
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   136
        for (TarjanNode<D> from : nodes) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   137
            for (TarjanNode<D> to : from.getDependencies()) {
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   138
                buf.append(String.format("%s -> %s [label = \" %s \"];\n",
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   139
                        from.hashCode(), to.hashCode(), from.printDependency(to)));
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   140
            }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   141
        }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   142
        buf.append("}\n");
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   143
        return buf.toString();
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   144
    }
ab55670d2e62 8007464: Add graph inference support
mcimadamore
parents:
diff changeset
   145
}