KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > alt > jiapi > interceptor > InvocationInstrumentor


1 package alt.jiapi.interceptor;
2
3 import java.util.List JavaDoc;
4
5 import java.lang.reflect.InvocationHandler JavaDoc;
6 import java.lang.reflect.Method JavaDoc;
7 import java.lang.reflect.Modifier JavaDoc;
8
9 import alt.jiapi.InstrumentationException;
10
11 import alt.jiapi.event.EventInstrumentor;
12 import alt.jiapi.event.EventRuntime;
13
14 import alt.jiapi.reflect.Instruction;
15 import alt.jiapi.reflect.InstructionFactory;
16 import alt.jiapi.reflect.InstructionList;
17 import alt.jiapi.reflect.JiapiClass;
18 import alt.jiapi.reflect.JiapiField;
19 import alt.jiapi.reflect.JiapiMethod;
20 import alt.jiapi.reflect.Loader;
21 import alt.jiapi.reflect.Signature;
22 import alt.jiapi.reflect.SignatureUtil;
23
24 import alt.jiapi.reflect.FieldExistsException;
25 import alt.jiapi.reflect.MethodExistsException;
26
27 import alt.jiapi.reflect.instruction.Invocation;
28 import alt.jiapi.reflect.instruction.OpcodeGroups;
29 import alt.jiapi.reflect.instruction.Opcodes;
30
31 import alt.jiapi.instrumentor.HotSpot;
32
33 import org.apache.log4j.Category;
34
35 /**
36  * Class InvocationInstrumentor.
37  *
38  * @author Mika Riekkinen
39  */

40 class InvocationInstrumentor extends EventInstrumentor {
41     private static Category log = Category.getInstance(InvocationInstrumentor.class);
42
43     private InvocationHandler JavaDoc handler;
44
45     InvocationInstrumentor(InvocationInterceptor ii, InvocationHandler JavaDoc handler) {
46         super(ii);
47         this.handler = handler;
48     }
49
50     public void instrument(JiapiMethod jm) {
51         InstructionList il = jm.getInstructionList();
52
53         if ("<clinit>".equals(jm.getName())) {
54             return;
55         }
56
57         InstructionFactory factory = il.getInstructionFactory();
58         JiapiClass ii = getEventProducer();
59         JiapiMethod invokeMethod = null;
60
61         try {
62             invokeMethod =
63                 ii.getDeclaredMethod("invokeMethod",
64                                      new String JavaDoc[] { "java.lang.Object",
65                                                     "java.lang.String",
66                                                     "java.lang.Object[]",
67                                                     "java.lang.String"});
68         }
69         catch(Exception JavaDoc e) {
70             e.printStackTrace();
71         }
72
73
74         int idx = -1;
75         while ((idx = il.indexOf(OpcodeGroups.INVOKE_INSTRUCTIONS, idx+1)) != -1) {
76             Invocation ins = (Invocation)il.get(idx);
77             if (!match(ins.getClassName() + "." + ins.getMethodName())) {
78                 continue;
79             }
80
81
82 // if (System.getProperty("no-lfix") == null) {
83
// // --- bug workaround for long/doubles in method params
84
// boolean bailOutForLongDoubleSyndrome = false;
85
// String[] i_params = ins.getParameterTypes();
86
// for (int i = 0; i < i_params.length; i++) {
87
// if ("double".equals(i_params[i]) ||
88
// "long".equals(i_params[i])) {
89
// bailOutForLongDoubleSyndrome = true;
90
// break;
91
// }
92
// }
93
// if (bailOutForLongDoubleSyndrome) {
94
// log.warn("Will not instrument invocations to methods with long or double as parameter: In " + jm.getDeclaringClass().getName() + "#" + jm +
95
// ", a call to " + ins + ". This is a workaround for bug in jiapi.");
96
// continue;
97
// }
98
// // --- bug workaround for long/doubles in method params
99
// }
100

101             // We support only these methods at the moment.
102
if (ins.getOpcode() != Opcodes.INVOKESTATIC &&
103                 ins.getOpcode() != Opcodes.INVOKEVIRTUAL) {
104                 continue;
105             }
106
107             JiapiField interceptor = getEventProducerField();
108         
109 // InstructionList nList = il.createEmptyList();
110
InstructionList nList = new InstructionList();
111
112
113             // each entry in pList holds creation of one argument
114
// to method invocation
115
// InstructionList[] pLists = createArgumentLists(il, idx);
116
ArgumentList al = createArgumentLists(il, idx);
117             InstructionList[] pLists = al.arguments;
118             int paramIdx = al.paramIndex;
119
120             short opCode = ins.getOpcode();
121             if (opCode == Opcodes.INVOKEVIRTUAL ||
122                 opCode == Opcodes.INVOKESPECIAL) {
123                 paramIdx--; // Include object ref
124
}
125
126             // Generate code, that replaces invocation with a new
127
// invocation to InvokeHandler
128
switch(opCode) {
129             case Opcodes.INVOKEVIRTUAL:
130             case Opcodes.INVOKESTATIC:
131
132                 nList.add(factory.getField(interceptor)); // Interceptor
133
if (opCode == Opcodes.INVOKESTATIC) {
134 // addClassForNameInstructions(jm.getDeclaringClass().getName(), nList);
135
addClassForNameInstructions(ins.getClassName(), nList);
136                     
137                 }
138                 else {
139                     nList.add(il.get(paramIdx)); // objref
140
}
141
142                 String JavaDoc mName = ins.getMethodName();
143                 //nList.add(factory.getField(rField));
144
nList.add(factory.pushConstant(mName));
145                 nList.add(factory.newArray("java.lang.Object",
146                                            ins.getParameterTypes().length));
147
148                 String JavaDoc[] i_params = ins.getParameterTypes();
149                 // Populate Object array with call parameters
150
for (int i = 0; i < pLists.length; i++) {
151                     if ("long".equals(i_params[i])) {
152                         nList.add(factory.dup());
153                     }
154                     else if ("double".equals(i_params[i])) {
155                         nList.add(factory.dup());
156                     }
157                     else {
158                         nList.add(factory.dup());
159                     }
160                     nList.add(factory.pushConstant(i));
161                     nList.add(pLists[i]);
162                     nList.add(factory.aastore());
163                 }
164
165                 // Add Methods signature
166
// nList.add(factory.pushConstant(ins.getDescriptor()));
167
// Add cache-key
168
nList.add(factory.pushConstant(ins.getClassName() + ins.getMethodName() + ins.getDescriptor()));
169
170                 // call Interceptor
171
nList.add(factory.invoke(invokeMethod));
172
173                 handleReturnValue(nList, ins);
174
175
176                 // Replace invocation and its parameters with new
177
// instruction list
178
il.replace(paramIdx, idx + 1, nList);
179
180                 break;
181             }
182
183             // Next index. Skip Instructions created above.
184
//idx += nList.size() - (idx - paramIdx) - 1;
185
idx = paramIdx + nList.size() - 1;
186         }
187     }
188
189
190
191
192     /**
193      * Create an array of InstructionLists. Each element in array
194      * represents one argument of a method invocation.
195      */

196     private ArgumentList createArgumentLists(InstructionList il, int invocationIndex) {
197         Invocation ins = (Invocation)il.get(invocationIndex);
198
199 // System.out.println("Creating arg list for " + ins);
200

201         String JavaDoc[] paramTypes = ins.getParameterTypes();
202         InstructionList[] argList =
203             new InstructionList[paramTypes.length];
204
205         // First pIdx points to Instruction just before Invocation
206
int pIdx = invocationIndex - 1;
207
208 // for (int i = 0; i < argList.length; i++) {
209
for (int i = argList.length - 1; i >= 0; i--) {
210             int stackUsage = ins.stackConsumption();
211             InstructionList pList = il.createEmptyList();
212
213             boolean primitive = SignatureUtil.isPrimitive(paramTypes[i]);
214             Instruction pr_ins = null;
215
216             if (primitive) {
217                 pr_ins = handlePrimitiveType(paramTypes[i], pList);
218             }
219
220             int insertIdx = pList.size();
221             // When stack usage is 1, we have reached an argument in stack
222
// while (stackUsage != 1) {
223
while ((stackUsage > 0 && ins.getOpcode() == Opcodes.INVOKESTATIC)||
224                     (stackUsage > 1 && ins.getOpcode() == Opcodes.INVOKEVIRTUAL)) {
225                 Instruction pIns = il.get(pIdx);
226 // System.out.println(">> pIdx: " + pIdx + ": " + pIns +
227
// ", stackusage: " + stackUsage);
228
stackUsage -= pIns.stackUsage();
229
230                 // Insert pIns allways to same index. We are scanning
231
// Instructions backwards!
232
// System.out.println("Adding " + pIns + " to plist");
233
pList.insert(insertIdx, pIns);
234                 pIdx--;
235             }
236
237             if (primitive) {
238                 pList.add(pr_ins); // Call constructor of primitive wrapper
239
}
240
241             argList[i] = pList;
242          }
243          
244          // pIdx + 1 points to first instruction, that counts
245
// as an argument to method call.
246
return new ArgumentList(argList, pIdx+1);
247     }
248
249
250     /**
251      * @return an Invocation to constructor of primitive wrapper
252      */

253     private Instruction handlePrimitiveType(String JavaDoc type, InstructionList il) {
254         InstructionFactory f = il.getInstructionFactory();
255         String JavaDoc cName = null;
256         Signature s = new Signature("void", new String JavaDoc[]{ type });
257
258         if ("int".equals(type)) {
259             cName = "java.lang.Integer";
260         }
261         else if ("long".equals(type)) {
262             cName = "java.lang.Long";
263         }
264         else if ("char".equals(type)) {
265             cName = "java.lang.Character";
266         }
267         else if ("boolean".equals(type)) {
268             cName = "java.lang.Boolean";
269         }
270         else if ("byte".equals(type)) {
271             cName = "java.lang.Byte";
272         }
273         else if ("float".equals(type)) {
274             cName = "java.lang.Float";
275         }
276         else if ("double".equals(type)) {
277             cName = "java.lang.Double";
278         }
279
280          il.add(f.newClass(cName));
281          il.add(f.dup());
282          Instruction ins = f.invoke(Modifier.PUBLIC, cName, "<init>", s);
283          return ins;
284     }
285
286
287     private void handleReturnValue(InstructionList il, Invocation ins) {
288         // Convert return value if needed.
289
InstructionFactory factory = il.getInstructionFactory();
290         String JavaDoc rType = ins.getReturnType();
291
292         if ("int".equals(rType)) {
293             try {
294                 JiapiClass jc = new Loader().loadClass("java.lang.Integer");
295                 JiapiMethod jm =
296                     jc.getDeclaredMethod("intValue", new String JavaDoc[0]);
297
298                 il.add(factory.cast("java.lang.Integer"));
299                 il.add(factory.invoke(jm));
300             }
301             catch(Exception JavaDoc e) {
302                 e.printStackTrace();
303             }
304         }
305         else if ("long".equals(rType)) {
306             try {
307                 JiapiClass jc = new Loader().loadClass("java.lang.Long");
308                 JiapiMethod jm =
309                     jc.getDeclaredMethod("longValue", new String JavaDoc[0]);
310
311                 il.add(factory.cast("java.lang.Long"));
312                 il.add(factory.invoke(jm));
313             }
314             catch(Exception JavaDoc e) {
315                 e.printStackTrace();
316             }
317         }
318         else if ("char".equals(rType)) {
319             try {
320                 JiapiClass jc = new Loader().loadClass("java.lang.Character");
321                 JiapiMethod jm =
322                     jc.getDeclaredMethod("charValue", new String JavaDoc[0]);
323
324                 il.add(factory.cast("java.lang.Character"));
325                 il.add(factory.invoke(jm));
326             }
327             catch(Exception JavaDoc e) {
328                 e.printStackTrace();
329             }
330         }
331         else if ("boolean".equals(rType)) {
332             try {
333                 JiapiClass jc = new Loader().loadClass("java.lang.Boolean");
334                 JiapiMethod jm =
335                     jc.getDeclaredMethod("booleanValue", new String JavaDoc[0]);
336
337                 il.add(factory.cast("java.lang.Boolean"));
338                 il.add(factory.invoke(jm));
339             }
340             catch(Exception JavaDoc e) {
341                 e.printStackTrace();
342             }
343         }
344         else if ("byte".equals(rType)) {
345             try {
346                 JiapiClass jc = new Loader().loadClass("java.lang.Byte");
347                 JiapiMethod jm =
348                     jc.getDeclaredMethod("byteValue", new String JavaDoc[0]);
349
350                 il.add(factory.cast("java.lang.Byte"));
351                 il.add(factory.invoke(jm));
352             }
353             catch(Exception JavaDoc e) {
354                 e.printStackTrace();
355             }
356         }
357         else if ("float".equals(rType)) {
358             try {
359                 JiapiClass jc = new Loader().loadClass("java.lang.Float");
360                 JiapiMethod jm =
361                     jc.getDeclaredMethod("floatValue", new String JavaDoc[0]);
362
363                 il.add(factory.cast("java.lang.Float"));
364                 il.add(factory.invoke(jm));
365             }
366             catch(Exception JavaDoc e) {
367                 e.printStackTrace();
368             }
369         }
370         else if ("double".equals(rType)) {
371             try {
372                 JiapiClass jc = new Loader().loadClass("java.lang.Double");
373                 JiapiMethod jm =
374                     jc.getDeclaredMethod("doubleValue", new String JavaDoc[0]);
375
376                 il.add(factory.cast("java.lang.Double"));
377                 il.add(factory.invoke(jm));
378             }
379             catch(Exception JavaDoc e) {
380                 e.printStackTrace();
381             }
382         }
383         else if ("void".equals(rType)){
384             // Pop out the return value(probably null) of
385
// the invocation handler if it was a 'void' method
386
il.add(new Instruction(new byte[]{Opcodes.POP}));
387         }
388         else { // Cast to correct Object
389
il.add(factory.cast(ins.getReturnType()));
390         }
391     }
392
393
394     private void addClassForNameInstructions(String JavaDoc name, InstructionList il) {
395         InstructionFactory f = il.getInstructionFactory();
396
397         InstructionList nl = il.createEmptyList();
398         
399         // NOTE: We do not create exception handlers for
400
// Class.forName(...) invocation.
401
// However, we use this to get Class of the running object,
402
// so its Class is allways found.
403
try {
404             nl.add(f.pushConstant(name));
405             nl.add(f.invoke(Modifier.STATIC, "java.lang.Class",
406                             "forName", new Signature("java.lang.Class",
407                                                      new String JavaDoc[] {"java.lang.String"})));
408         }
409         catch(Exception JavaDoc e) {
410             e.printStackTrace();
411             il.add(f.pushNull());
412         }
413
414         il.add(nl);
415     }
416
417
418     private class ArgumentList {
419         public InstructionList[] arguments;
420         public int paramIndex;
421
422         public ArgumentList(InstructionList[] args, int paramIndex) {
423             this.arguments = args;
424             this.paramIndex = paramIndex;
425         }
426     }
427 }
428
Popular Tags