All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opalj.graphs.DominatorTree.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package graphs

import org.opalj.collection.mutable.IntArrayStack
import org.opalj.collection.immutable.IntTrieSet
import org.opalj.collection.immutable.IntTrieSet1

/**
 * A (standard) dominator tree.
 *
 * @note `Int ⇒ ((Int ⇒ Unit) ⇒ Unit)` is basically an `IntFunction[Consumer[IntConsumer]]`.
 *
 * @param  startNode The unique start node of the (augmented) dominator tree.
 * @param  hasVirtualStartNode `true` if the underlying cfg's startNode has a predecessor.
 *         If the start nodes had predecessors, a virtual start node was created; in this case
 *         the startNode will have an id larger than any id used by the graph and is identified by
 *         `startNode`.
 */
final class DominatorTree private (
        val startNode:            Int,
        val hasVirtualStartNode:  Boolean,
        val foreachSuccessorOf:   Int ⇒ ((Int ⇒ Unit) ⇒ Unit),
        private[graphs] val idom: Array[Int]
) extends AbstractDominatorTree {

    def isAugmented: Boolean = hasVirtualStartNode

}

/**
 * Factory to compute [[DominatorTree]]s.
 *
 * @author Stephan Neumann
 * @author Michael Eichberg
 */
object DominatorTree {

    // def fornone(g: Int ⇒ Unit): Unit = { /*nothing to do*/ }
    final val fornone: (Int ⇒ Unit) ⇒ Unit = (_: Int ⇒ Unit) ⇒ {}

    /**
     * Convenience factory method for dominator trees; see
     * [[org.opalj.graphs.DominatorTree$.apply[D<:org\.opalj\.graphs\.AbstractDominatorTree]*]]
     * for details.
     */
    def apply(
        startNode:                Int,
        startNodeHasPredecessors: Boolean,
        foreachSuccessorOf:       Int ⇒ ((Int ⇒ Unit) ⇒ Unit),
        foreachPredecessorOf:     Int ⇒ ((Int ⇒ Unit) ⇒ Unit),
        maxNode:                  Int
    ): DominatorTree = {
        this(
            startNode,
            startNodeHasPredecessors,
            foreachSuccessorOf,
            foreachPredecessorOf,
            maxNode,
            (
                startNode: Int,
                hasVirtualStartNode: Boolean,
                foreachSuccessorOf: Int ⇒ ((Int ⇒ Unit) ⇒ Unit),
                idom: Array[Int]
            ) ⇒ {
                new DominatorTree(startNode, hasVirtualStartNode, foreachSuccessorOf, idom)
            }
        )
    }

    /**
     * Computes the immediate dominators for each node of a given graph. Each node of the graph
     * is identified using a unique int value (e.g. the pc of an instruction) in the range
     * [0..maxNode], although not all ids need to be used.
     *
     * @param   startNode The id of the root node of the graph. (Often pc="0" for the CFG
     *          computed for some method; sometimes the id of an artificial start node
     *          that was created when computing the dominator tree).
     * @param   startNodeHasPredecessors If `true` an artificial start node with the id `maxNode+1`
     *          will be created and added to the graph.
     * @param   foreachSuccessorOf A function that given a node subsequently executes the given
     *          function for each direct successor of the given node.
     * @param   foreachPredecessorOf A function that - given a node - executes the given function
     *          for each direct predecessor. The signature of a function that can directly be passed
     *          as a parameter is:
     *          {{{
     *          def foreachPredecessorOf(pc: PC)(f: PC ⇒ Unit): Unit
     *          }}}
     * @param   maxNode The largest unique int id that identifies a node. (E.g., in case of
     *          the analysis of some code it is typically equivalent to the length of the code-1.)
     *
     * @return  The computed dominator tree.
     *
     * @note    This is an implementation of the "fast dominators" algorithm presented by
     *          
     *          T. Lengauaer and R. Tarjan in
     *          A Fast Algorithm for Finding Dominators in a Flowgraph
     *          ACM Transactions on Programming Languages and Systems (TOPLAS) 1.1 (1979): 121-141
     *          
* * '''This implementation does not use non-tailrecursive methods and hence * also handles very large degenerated graphs (e.g., a graph which consists of a * a very, very long single path.).''' */ def apply[D <: AbstractDominatorTree]( startNode: Int, startNodeHasPredecessors: Boolean, foreachSuccessorOf: Int ⇒ ((Int ⇒ Unit) ⇒ Unit), foreachPredecessorOf: Int ⇒ ((Int ⇒ Unit) ⇒ Unit), maxNode: Int, dominatorTreeFactory: ( /*startNode*/ Int, /*hasVirtualStartNode*/ Boolean, /*foreachSuccessorOf*/ Int ⇒ ((Int ⇒ Unit) ⇒ Unit), Array[Int]) ⇒ D ): D = { if (startNodeHasPredecessors) { val newStartNode = maxNode + 1 create( newStartNode, true, /* newForeachSuccessorOf */ (n: Int) ⇒ { if (n == newStartNode) (f: Int ⇒ Unit) ⇒ { f(startNode) } else foreachSuccessorOf(n) }, /* newForeachPredecessorOf */ (n: Int) ⇒ { if (n == newStartNode) (f: Int ⇒ Unit) ⇒ {} else if (n == startNode) (f: Int ⇒ Unit) ⇒ { f(newStartNode) } else foreachPredecessorOf(n) }, newStartNode, dominatorTreeFactory ); } else { create( startNode, false, foreachSuccessorOf, foreachPredecessorOf, maxNode, dominatorTreeFactory ) } } private[graphs] def create[D <: AbstractDominatorTree]( startNode: Int, hasVirtualStartNode: Boolean, foreachSuccessorOf: Int ⇒ ((Int ⇒ Unit) ⇒ Unit), foreachPredecessorOf: Int ⇒ ((Int ⇒ Unit) ⇒ Unit), maxNode: Int, dominatorTreeFactory: ( /*startNode*/ Int, /*hasVirtualStartNode*/ Boolean, /*foreachSuccessorOf*/ Int ⇒ ((Int ⇒ Unit) ⇒ Unit), Array[Int]) ⇒ D ): D = { val max = maxNode + 1 var n = 0; val dom = new Array[Int](max) val parent = new Array[Int](max) val ancestor = new Array[Int](max) val vertex = new Array[Int](max + 1) val label = new Array[Int](max) val semi = new Array[Int](max) val bucket = new Array[IntTrieSet](max) // helper data-structure to resolve recursive methods val vertexStack = new IntArrayStack(initialSize = Math.max(2, max / 4)) // Step 1 (assign dfsnum) vertexStack.push(startNode) while (vertexStack.nonEmpty) { val v = vertexStack.pop() // The following "if" is necessary, because the recursive DFS impl. in the paper // performs an eager decent. This may already initialize a node that is also pushed // on the stack and, hence, must not be visited again. if (semi(v) == 0) { n = n + 1 semi(v) = n label(v) = v vertex(n) = v dom(v) = v foreachSuccessorOf(v) { w ⇒ if (semi(w) == 0) { parent(w) = v vertexStack.push(w) } } } } // Steps 2 & 3 def eval(v: Int): Int = { if (ancestor(v) == 0) { v } else { compress(v) label(v) } } // // PAPER VERSION USING RECURSION // def compress(v: Int): Unit = { // var theAncestor = ancestor(v) // if (ancestor(theAncestor) != 0) { // compress(theAncestor) // theAncestor = ancestor(v) // val ancestorLabel = label(theAncestor) // if (semi(ancestorLabel) < semi(label(v))) { // label(v) = ancestorLabel // } // ancestor(v) = ancestor(theAncestor) // } // } def compress(v: Int): Unit = { // 1. walk the path { var w = v while (ancestor(ancestor(w)) != 0) { vertexStack.push(w) w = ancestor(w) } } // 2. compress while (vertexStack.nonEmpty) { val w = vertexStack.pop() val theAncestor = ancestor(w) val ancestorLabel = label(theAncestor) if (semi(ancestorLabel) < semi(label(w))) { label(w) = ancestorLabel } ancestor(w) = ancestor(theAncestor) } } var i = n while (i >= 2) { val w = vertex(i) // Step 2 foreachPredecessorOf(w) { v: Int ⇒ val u = eval(v) val uSemi = semi(u) if (uSemi < semi(w)) { semi(w) = uSemi } } val v = vertex(semi(w)) val b = bucket(v) bucket(v) = if (b ne null) { b + w } else { IntTrieSet1(w) } ancestor(w) = parent(w) // Step 3 val wParent = parent(w) val wParentBucket = bucket(wParent) if (wParentBucket != null) { for (v ← wParentBucket) { val u = eval(v) dom(v) = if (semi(u) < semi(v)) u else wParent } bucket(wParent) = null } i = i - 1 } // Step 4 var j = 2; while (j <= n) { val w = vertex(j) val domW = dom(w) if (domW != vertex(semi(w))) { dom(w) = dom(domW) } j = j + 1 } dominatorTreeFactory(startNode, hasVirtualStartNode, foreachSuccessorOf, dom) } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy