/* * This file is part of JOP, the Java Optimized Processor * see <http://www.jopdesign.com/> * * Copyright (C) 2008, Benedikt Huber (benedikt.huber@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jopdesign.common.graphutils; import org.jgrapht.DirectedGraph; import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.SimpleDirectedGraph; import org.jgrapht.traverse.DepthFirstIterator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * Compute Dominators of a graph, following: * A Simple, Fast Dominance Algorithm * (Cooper, Keith D. and Harvey, Timothy J. and Kennedy, Ken). */ public class Dominators<V, E> { private DirectedGraph<V, E> graph; private List<V> vertexPreOrder; private Map<V, V> idom = null; private Map<V, Integer> preOrderMap; protected int getOrder(V vertex) { return preOrderMap.get(vertex); } protected V getIDom(V vertex) { if (idom == null) computeDominators(); return idom.get(vertex); } /** * Dominators, using default pre-oder traversal * * @param g the graph * @param entry the entry node */ public Dominators(DirectedGraph<V, E> g, V entry) { this(g, dfsPreOrder(g, entry)); } private static <V, E> List<V> dfsPreOrder(DirectedGraph<V, E> g, V exit) { DepthFirstIterator<V, E> iter = new DepthFirstIterator<V, E>(g, exit); iter.setCrossComponentTraversal(false); List<V> trav = new LinkedList<V>(); while (iter.hasNext()) { trav.add(iter.next()); } return trav; } /** * (Immediate) Dominators based on the given pre-order traversal of the graph. * * @param g the graph * @param preOrder a pre-order DFS traversal of the graph. Its first node is the entry point of the graph. */ public Dominators(DirectedGraph<V, E> g, List<V> preOrder) { this.graph = g; this.vertexPreOrder = preOrder; // just making sure we have a non-empty graph, assert vertexPreOrder != null && !vertexPreOrder.isEmpty(); this.preOrderMap = new HashMap<V, Integer>(); for (int i = 0; i < this.vertexPreOrder.size(); i++) { preOrderMap.put(vertexPreOrder.get(i), i); } } protected void computeDominators() { if (this.idom != null) return; this.idom = new HashMap<V, V>(); V firstElement = vertexPreOrder.get(0); idom.put(firstElement, firstElement); if (!graph.incomingEdgesOf(vertexPreOrder.get(0)).isEmpty()) throw new AssertionError("The entry of the flow graph is not allowed to have incoming edges"); boolean changed; do { changed = false; for (V v : vertexPreOrder) { if (v.equals(firstElement)) continue; V oldIdom = getIDom(v); V newIdom = null; for (E edge : graph.incomingEdgesOf(v)) { V pre = graph.getEdgeSource(edge); if (getIDom(pre) == null) /* not yet analyzed */ continue; if (newIdom == null) { /* If we only have one (defined) predecessor pre, IDom(v) = pre */ newIdom = pre; } else { /* compute the intersection of all defined predecessors of v */ newIdom = intersectIDoms(pre, newIdom); } } if (newIdom == null) throw new AssertionError("newIDom == null !, for " + v); if (!newIdom.equals(oldIdom)) { changed = true; this.idom.put(v, newIdom); } } } while (changed); } private V intersectIDoms(V v1, V v2) { while (v1 != v2) { if (getOrder(v1) < getOrder(v2)) { v2 = getIDom(v2); } else { v1 = getIDom(v1); } } return v1; } /** * Get the table of immediate dominators. Note that by convention, the graph's entry * is dominated by itself (so <code>IDOM(n)</code> is a total function).</br> * Note that the set <code>DOM(n)</code> is given by * <ul> * <li/><code>DOM(Entry) = Entry</code> * <li/><code>DOM(n) = n \cup DOM(IDOM(n))</code> * </ul> * * @return */ public Map<V, V> getIDoms() { computeDominators(); return this.idom; } /** * Check wheter a node dominates another one. * * @param dominator * @param dominated * @return true, if <code>dominator</code> dominates <code>dominated</code> w.r.t to the entry node */ public boolean dominates(V dominator, V dominated) { computeDominators(); if (dominator.equals(dominated)) return true; // Domination is reflexive ;) V dom = getIDom(dominated); // as long as dominated >= dominator while (dom != null && getOrder(dom) >= getOrder(dominator) && !dom.equals(dominator)) { dom = getIDom(dom); } return dominator.equals(dom); } public Set<V> getStrictDominators(V n) { computeDominators(); Set<V> strictDoms = new HashSet<V>(); V dominated = n; V iDom = getIDom(n); while (iDom != dominated) { strictDoms.add(iDom); dominated = iDom; iDom = getIDom(dominated); } return strictDoms; } /** * get the dominator tree * * @return a new dominator tree */ public SimpleDirectedGraph<V, DefaultEdge> getDominatorTree() { computeDominators(); SimpleDirectedGraph<V, DefaultEdge> domTree = new SimpleDirectedGraph<V, DefaultEdge>(DefaultEdge.class); for (V node : graph.vertexSet()) { domTree.addVertex(node); V idom = getIDom(node); if (idom != null && !node.equals(idom)) { domTree.addVertex(idom); domTree.addEdge(idom, node); } } return domTree; } }