Snippets

Michael Eichberg [OPAL - 1.0.0] Compute Control-dependencies based on (Post-)Dominator Trees

You are viewing an old version of this snippet. View the current version.
Revised by Michael Eichberg f2efd69
// In the following, we demonstrate how to get the 
//    - Dominator Tree(DT), 
//    - Post-Dominator Tree and 
//    - Control-Dependence Graph 
// for a given method.
import org.opalj.io.writeAndOpen
import org.opalj.br._ ; 
import org.opalj.br.analyses._; 
import org.opalj.ai._;

implicit val p = Project(new java.io.File("OPAL/bi/target/scala-2.11/resource_managed/test/controlflow.jar"))

// Select a method // HERE, WE DELIBERATELY CHOOSE A METHOD WHICH CONTAINS AN INFINITE LOOP (NOT AN UNBOUNDED ONE...); i.e., 
val cf = p.classFile(ObjectType("controlflow/InfiniteLoops")).get
val methodNames = List(
//  "trivialInfiniteLoop",
//  "trivialNestedInfiniteLoops",
//  "regularLoopInInfiniteLoop",
//  "nestedInfiniteLoops",
//  "complexPathToInfiniteLoop",
//  "infiniteLoopWithComplexPath",
//  "complexPathToInfiniteLoopWithComplexPath",
  "multipleInfiniteLoops"
)
val aiResults = for {methodName <- methodNames} yield {
  println("processing: "+methodName)
  
  val m = cf.findMethod(methodName).head

  // Perform an intra-procedural, very lightweight abstract interpretation of the method
  // using a domain which records the CFG (RecordCFG); the most lightweight domain is
  // the `PrimitiveTACAIDomain`.
  val r = BaseAI(m,new domain.l1.DefaultDomainWithCFG(p,m))

  val bbcfg = r.domain.bbCFG
  writeAndOpen(bbcfg.toDot,"BBCFG-"+methodName,".bbcfg.gv")
  
  val cfg = r.domain.cfgAsGraph
  writeAndOpen(org.opalj.graphs.toDot(List(cfg)),"CFG-"+methodName,".cfg.gv")

  // Domintator Tree
  val dt = r.domain.dominatorTree
  writeAndOpen(dt.toDot(m.body.get.instructions(_) != null),"DT-"+methodName,".dt.gv")

  // (Forward) Dominance Frontiers
  val df = org.opalj.graphs.DominanceFrontiers.apply(dt,r.domain.wasExecuted)
  writeAndOpen(df.toDot(i => i >= m.body.get.codeSize || m.body.get.instructions(i) != null),"DF-"+methodName,".df.gv")

  // Post Dominator Tree
  val pdt = r.domain.postDominatorTree
  writeAndOpen(pdt.toDot(i => i >= m.body.get.codeSize || m.body.get.instructions(i) != null),"PDT-"+methodName,".pdt.gv")
  
  r.domain.infiniteLoopHeaders.foreach(println)
  
  val cdg = r.domain.controlDependencies // Uses backward dominance frontiers
  for (pc <- r.domain.allExecuted){
    var ps : List[Int] = Nil
    cdg.xIsControlDependentOn(pc)(p => ps ::= p)
    println(s"$pc is control dependent on ${ps.mkString("{",",","}")}")
  }
  
  r
}

// Check if some method contains an infinite loop
p.allClassFiles.foreach{cf => 
  cf.methods.filter(_.body.isDefined).foreach{m =>
    val r = BaseAI(m,new domain.l1.DefaultDomainWithCFG(p,m)); 
    val infiniteLoops = r.domain.infiniteLoopHeaders
    print(if(infiniteLoops.nonEmpty) Console.RED else Console.GREEN)
    println(m.toJava("infinite loops="+infiniteLoops.mkString(", "))+Console.RESET)
  }
}
HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.