Created
April 13, 2013 14:34
-
-
Save pxpc2/5378639 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package us.brtm.cfg; | |
import org.objectweb.asm.tree.AbstractInsnNode; | |
import org.objectweb.asm.tree.LabelNode; | |
import org.objectweb.asm.tree.MethodNode; | |
import org.objectweb.asm.tree.analysis.*; | |
import us.brtm.cfg.generic.Node; | |
/** | |
* Class that represents a Control Flow Graph constructed for a specified method. | |
* Useful for static analysis of applications and/or compiler optimizations. | |
* | |
* @author Pedro Daia Cardoso | |
*/ | |
public final class Graph { | |
/** | |
* The representation of the analyzed method. | |
*/ | |
private MethodNode method; | |
/** | |
* The analyzer instance of an analyzed method :P | |
*/ | |
private Analyzer analyzer; | |
/** | |
* All frames -- representing a block -- in the method. | |
*/ | |
private Frame[] frames; | |
/** | |
* The first or opening frame or node in the graph. | |
*/ | |
private Frame entryBlock; | |
/** | |
* @param owner the internal name of the class to which the method belongs. | |
* @param method the method to be analyzed. | |
* @param debug debug flag | |
* @throws AnalyzerException if a problem occurs during the analysis. | |
*/ | |
public Graph(String owner, MethodNode method, boolean debug) throws AnalyzerException { | |
if (debug) { | |
System.out.println("Starting to build graph for " + owner + "." + method.name + "()"); | |
} | |
this.method = method; | |
this.analyzer = new Analyzer<BasicValue>(new BasicInterpreter()) { | |
protected Frame<BasicValue> newFrame(int nLocals, int nStack) { | |
return new Node(nLocals, nStack); | |
} | |
protected void newControlFlowEdge(int src, int dst) { | |
Node s = (Node) getFrames()[src]; | |
s.getSuccessors().add((Node) getFrames()[dst]); | |
} | |
}; | |
analyzer.analyze(owner, method); | |
int totalInsns = method.instructions.size(); | |
Frame entryBlock = locateEntryBlock(); | |
if (entryBlock == null && debug) { | |
System.out.println("Entry block for the graph's null. Fail."); | |
} | |
this.entryBlock = entryBlock; | |
optimizeMethod(); | |
if (debug) { | |
System.out.println("Built graph for " + owner + "." + method.name + "()."); | |
System.out.println("Cyclomatic complexity: " + getCyclomaticComplexity()); | |
System.out.println("Optimized " + (totalInsns - method.instructions.size()) + " instructions."); | |
} | |
} | |
public Frame locateEntryBlock() { | |
for (Frame frame : frames) { | |
if (((Node) frame).getSuccessors().size() > 0) { | |
continue; | |
} | |
return frame; | |
} | |
return null; | |
} | |
/** | |
* Optimizes the method by removing useless things and/or | |
* simplifying the code. | |
*/ | |
public void optimizeMethod() { | |
AbstractInsnNode[] instructions = method.instructions.toArray(); | |
for (int i = 0; i < frames.length; i++) { | |
AbstractInsnNode instruction = instructions[i]; | |
if (frames[i] == null && !(instruction instanceof LabelNode)) { | |
method.instructions.remove(instructions[i]); | |
} | |
} | |
} | |
/** | |
* A simple method to calculate the cyclomatic complexity of a method. This metric is defined | |
* as the number of edges in the control flow graph, minus the number of nodes, plus two. | |
* The metric gives a good indication if the complexity of a method, which have a | |
* relation with the average amount of bugs in the method. | |
* | |
* @return the cyclomatic complexity of this graph's method. | |
*/ | |
public int getCyclomaticComplexity() { | |
int edges = 0; | |
int nodes = 0; | |
for (Frame frame : frames) { | |
if (frame != null) { | |
edges += ((Node) frame).getSuccessors().size(); | |
nodes += 1; | |
} | |
} | |
return edges - nodes + 2; | |
} | |
/** | |
* @return returns the analyzer instance | |
*/ | |
public Analyzer getAnalyzer() { | |
return analyzer; | |
} | |
public Frame getEntryBlock() { | |
return entryBlock; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sir, could you please share the code for the package used: " us.brtm.cfg.generic.Node"?