KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > InvokeStaticInstrumenter


1 /*
2  * InvokeStaticInstrumenter inserts count instructions before
3  * INVOKESTATIC bytecode in a program. The instrumented program will
4  * report how many static invocations happen in a run.
5  *
6  * Goal:
7  * Insert counter instruction before static invocation instruction.
8  * Report counters before program's normal exit point.
9  *
10  * Approach:
11  * 1. Create a counter class which has a counter field, and
12  * a reporting method.
13  * 2. Take each method body, go through each instruction, and
14  * insert count instructions before INVOKESTATIC.
15  * 3. Make a call of reporting method of the counter class.
16  *
17  * Things to learn from this example:
18  * 1. How to use Soot to examine a Java class.
19  * 2. How to insert profiling instructions in a class.
20  */

21
22 /* InvokeStaticInstrumenter extends the abstract class BodyTransformer,
23  * and implements <pre>internalTransform</pre> method.
24  */

25 import soot.*;
26 import soot.jimple.*;
27 import soot.util.*;
28 import java.util.*;
29
30 public class InvokeStaticInstrumenter extends BodyTransformer{
31
32   /* some internal fields */
33   static SootClass counterClass;
34   static SootMethod increaseCounter, reportCounter;
35
36   static {
37     counterClass = Scene.v().loadClassAndSupport("MyCounter");
38     increaseCounter = counterClass.getMethod("void increase(int)");
39     reportCounter = counterClass.getMethod("void report()");
40   }
41
42   /* internalTransform goes through a method body and inserts
43    * counter instructions before an INVOKESTATIC instruction
44    */

45   protected void internalTransform(Body body, String JavaDoc phase, Map options) {
46     // body's method
47
SootMethod method = body.getMethod();
48
49     // debugging
50
System.out.println("instrumenting method : " + method.getSignature());
51
52     // get body's unit as a chain
53
Chain units = body.getUnits();
54
55     // get a snapshot iterator of the unit since we are going to
56
// mutate the chain when iterating over it.
57
//
58
Iterator stmtIt = units.snapshotIterator();
59     
60     // typical while loop for iterating over each statement
61
while (stmtIt.hasNext()) {
62       
63       // cast back to a statement.
64
Stmt stmt = (Stmt)stmtIt.next();
65
66       // there are many kinds of statements, here we are only
67
// interested in statements containing InvokeStatic
68
// NOTE: there are two kinds of statements may contain
69
// invoke expression: InvokeStmt, and AssignStmt
70
if (!stmt.containsInvokeExpr()) {
71     continue;
72       }
73
74       // take out the invoke expression
75
InvokeExpr expr = (InvokeExpr)stmt.getInvokeExpr();
76       
77       // now skip non-static invocations
78
if (! (expr instanceof StaticInvokeExpr)) {
79     continue;
80       }
81
82       // now we reach the real instruction
83
// call Chain.insertBefore() to insert instructions
84
//
85
// 1. first, make a new invoke expression
86
InvokeExpr incExpr= Jimple.v().newStaticInvokeExpr(increaseCounter.makeRef(),
87                           IntConstant.v(1));
88       // 2. then, make a invoke statement
89
Stmt incStmt = Jimple.v().newInvokeStmt(incExpr);
90
91       // 3. insert new statement into the chain
92
// (we are mutating the unit chain).
93
units.insertBefore(incStmt, stmt);
94     }
95
96     
97     // Do not forget to insert instructions to report the counter
98
// this only happens before the exit points of main method.
99

100     // 1. check if this is the main method by checking signature
101
String JavaDoc signature = method.getSubSignature();
102     boolean isMain = signature.equals("void main(java.lang.String[])");
103
104     // re-iterate the body to look for return statement
105
if (isMain) {
106       stmtIt = units.snapshotIterator();
107
108       while (stmtIt.hasNext()) {
109     Stmt stmt = (Stmt)stmtIt.next();
110
111     // check if the instruction is a return with/without value
112
if ((stmt instanceof ReturnStmt)
113         ||(stmt instanceof ReturnVoidStmt)) {
114       // 1. make invoke expression of MyCounter.report()
115
InvokeExpr reportExpr= Jimple.v().newStaticInvokeExpr(reportCounter.makeRef());
116
117       // 2. then, make a invoke statement
118
Stmt reportStmt = Jimple.v().newInvokeStmt(reportExpr);
119
120       // 3. insert new statement into the chain
121
// (we are mutating the unit chain).
122
units.insertBefore(reportStmt, stmt);
123     }
124       }
125     }
126   }
127 }
128
Popular Tags