KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > proactive > core > mop > ASMBytecodeStubBuilder


1 /*
2 * ################################################################
3 *
4 * ProActive: The Java(TM) library for Parallel, Distributed,
5 * Concurrent computing with Security and Mobility
6 *
7 * Copyright (C) 1997-2002 INRIA/University of Nice-Sophia Antipolis
8 * Contact: proactive-support@inria.fr
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
25 * Initial developer(s): The ProActive Team
26 * http://www.inria.fr/oasis/ProActive/contacts.html
27 *
28 * Contributor(s): Eric Bruneton
29 *
30 * ################################################################
31 */

32 package org.objectweb.proactive.core.mop;
33
34 import java.lang.reflect.Method JavaDoc;
35 import java.lang.reflect.Modifier JavaDoc;
36 import java.util.Vector JavaDoc;
37
38 import org.apache.log4j.Logger;
39 import org.objectweb.asm.ClassWriter;
40 import org.objectweb.asm.CodeVisitor;
41 import org.objectweb.asm.Constants;
42 import org.objectweb.asm.Label;
43 import org.objectweb.asm.Type;
44
45 public class ASMBytecodeStubBuilder implements Constants {
46     
47     protected static Logger logger = Logger.getLogger(ASMBytecodeStubBuilder.class.getName());
48     
49     // Those fields contain information about the class
50
// for which we are building a wrapper
51
protected Class JavaDoc cl;
52     protected String JavaDoc className;
53     protected String JavaDoc packageName;
54     protected Method JavaDoc[] methods;
55
56     // The following fields have to do with
57
// the actual genration of the stub
58
protected String JavaDoc stubClassSimpleName;
59     protected String JavaDoc stubClassFullName;
60     protected ClassWriter classGenerator;
61
62     // A few constants that come in handy when using ASM in our case
63
protected static final String JavaDoc METHODCALL_TYPE = "Lorg/objectweb/proactive/core/mop/MethodCall;";
64     protected static final String JavaDoc OBJECT_TYPE = "Ljava/lang/Object;";
65     protected static final String JavaDoc OBJECT_ARRAY_TYPE = "[Ljava/lang/Object;";
66     protected static final String JavaDoc METHOD_TYPE = "Ljava/lang/reflect/Method;";
67     protected static final String JavaDoc METHOD_ARRAY_TYPE = "[Ljava/lang/reflect/Method;";
68     protected static final String JavaDoc PROXY_TYPE = "Lorg/objectweb/proactive/core/mop/Proxy;";
69     protected static final String JavaDoc STUB_INTERFACE_NAME = "org/objectweb/proactive/core/mop/StubObject";
70     protected static final String JavaDoc PROXY_FIELD_NAME = "myProxy";
71
72     public ASMBytecodeStubBuilder(String JavaDoc classname) throws ClassNotFoundException JavaDoc {
73         // Obtains the object that represents the type we want to create
74
// a wrapper class for. This call may fail with a ClassNotFoundException
75
// if the class corresponding to this type cannot be found.
76
logger.debug("ASMBytecodeStubBuilder.init<> classname " + classname);
77         try {
78         this.cl = Class.forName(classname);
79         } catch (ClassNotFoundException JavaDoc e) {
80             e.printStackTrace();
81             throw e;
82         }
83         logger.debug("ASMBytecodeStubBuilder.init<> 1");
84         // Keep this info at hand for performance purpose
85
this.className = classname;
86         logger.debug("ASMBytecodeStubBuilder.init<> 2");
87         // Fills in all the infos about this class
88
this.setInfos();
89     }
90 ////Modif FAb
91
// public ASMBytecodeStubBuilder(String classname, ClassLoader classLoader) throws ClassNotFoundException {
92
// // Obtains the object that represents the type we want to create
93
// // a wrapper class for. This call may fail with a ClassNotFoundException
94
// // if the class corresponding to this type cannot be found.
95
// if (classLoader != null) {
96
//
97
//
98
// this.cl = classLoader.loadClass(classname);
99
// } else {
100
// this.cl = Class.forName(classname);
101
//
102
// }
103
// // Keep this info at hand for performance purpose
104
// this.className = classname;
105
//
106
// // Fills in all the infos about this class
107
// this.setInfos();
108
// }
109

110     protected ClassWriter createClassGenerator() {
111         String JavaDoc superclassName;
112         String JavaDoc[] interfaces;
113
114         // If we generate a stub for an interface type, we have to explicitely declare
115
// that we implement the interface. Also, the name of the superclass is not the reified
116
// type, but java.lang.Object
117
if (this.cl.isInterface()) {
118             superclassName = "java.lang.Object";
119             interfaces = new String JavaDoc[3];
120             interfaces[0] = "java/io/Serializable";
121             interfaces[1] = STUB_INTERFACE_NAME;
122             interfaces[2] = this.cl.getName().replace('.', '/');
123         } else {
124             superclassName = this.className;
125             interfaces = new String JavaDoc[2];
126             interfaces[0] = "java/io/Serializable";
127             interfaces[1] = STUB_INTERFACE_NAME;
128         }
129
130         ClassWriter cw = new ClassWriter(true);
131         cw.visit(Constants.ACC_PUBLIC | Constants.ACC_SUPER, // Same access modifiers as superclass or public ???
132
this.stubClassFullName.replace('.', '/'), // Fully-qualified class name
133
superclassName.replace('.', '/'), // Superclass
134
interfaces, // declared interfaces
135
"<generated>");
136         return cw;
137     }
138
139     public byte[] create() {
140         // Creates the class generator
141
this.classGenerator = this.createClassGenerator();
142
143         // Add a public no-arg constructor
144
this.createConstructor();
145
146         // Creates all the methods in the class
147
for (int i = 0; i < this.methods.length; i++) {
148             CodeVisitor mg = this.createMethod(i, this.methods[i]);
149         }
150
151         // Creates the two methods getProxy and setProxy
152
// declared in interface StubObject
153
this.createGetAndSetProxyMethods();
154
155         // Creates the fields of the class
156
this.createFields();
157
158         // Create the static fields
159
this.createStaticVariables();
160
161         // Creates the static initializer
162
this.createStaticInitializer();
163
164         // Next few lines for debugging only
165
// try {
166
// java.io.File file = new java.io.File ("generated/" , "ASM_" + stubClassSimpleName + ".class");
167
// System.out.println("writing down the generated stub : " + file.getAbsolutePath());
168
// java.io.FileOutputStream fos = new java.io.FileOutputStream(file);
169
// fos.write(this.classGenerator.toByteArray());
170
// fos.close();
171
// } catch (Exception e) {
172
// e.printStackTrace();
173
// }
174

175         return this.classGenerator.toByteArray();
176     }
177
178     protected CodeVisitor createMethodGenerator(Method JavaDoc m) {
179         // Extracts modifiers
180
int flags = convertJavaModifierToASM(m.getModifiers());
181
182         // Modifies the modifiers in order to remove 'native' and 'abstract'
183
flags = removeNativeAndAbstractModifiers(flags);
184
185         // Extracts return and arguments types
186
String JavaDoc mDesc = Type.getMethodDescriptor(m);
187     
188         // Actually creates the method generator
189
CodeVisitor cv = this.classGenerator.visitMethod(flags, // access flags
190
m.getName(), // Method name
191
mDesc, // return and argument types
192
null, // exceptions
193
null); // Attributes
194
return cv;
195     }
196
197     protected static int removeNativeAndAbstractModifiers(int modifiers) {
198         // In order to set to 0 the bit that represents 'native', we first
199
// compute the mask that contains 1s everywhere and a 0 where the bit
200
// is, and then apply this mask with an 'and', bitwise.
201
int result = modifiers & (~Modifier.NATIVE);
202         result = result & (~Modifier.ABSTRACT);
203         return result;
204     }
205
206     protected static int convertJavaModifierToASM(int javaModifier) {
207         int result = 0;
208
209         if (Modifier.isAbstract(javaModifier)) {
210             result = result | Constants.ACC_ABSTRACT;
211         }
212         if (Modifier.isFinal(javaModifier)) {
213             result = result | Constants.ACC_FINAL;
214         }
215         if (Modifier.isInterface(javaModifier)) {
216             result = result | Constants.ACC_INTERFACE;
217         }
218         if (Modifier.isNative(javaModifier)) {
219             result = result | Constants.ACC_NATIVE;
220         }
221         if (Modifier.isPrivate(javaModifier)) {
222             result = result | Constants.ACC_PRIVATE;
223         }
224         if (Modifier.isProtected(javaModifier)) {
225             result = result | Constants.ACC_PROTECTED;
226         }
227         if (Modifier.isPublic(javaModifier)) {
228             result = result | Constants.ACC_PUBLIC;
229         }
230         if (Modifier.isStatic(javaModifier)) {
231             result = result | Constants.ACC_STATIC;
232         }
233         if (Modifier.isSynchronized(javaModifier)) {
234             result = result | Constants.ACC_SYNCHRONIZED;
235         }
236         if (Modifier.isTransient(javaModifier)) {
237             result = result | Constants.ACC_TRANSIENT;
238         }
239         if (Modifier.isVolatile(javaModifier)) {
240             result = result | Constants.ACC_VOLATILE;
241         }
242
243         return result;
244     }
245
246     protected CodeVisitor createMethod(int methodIndex, Method JavaDoc m) {
247         CodeVisitor cv = createMethodGenerator(m);
248         //InstructionFactory factory = new InstructionFactory(classGenerator);
249
Label inConstructorHandle = new Label();
250
251         if (this.cl.isInterface() == false) {
252             // First, check if the method is called from within the constructor
253
// Load 'this' onto the stack
254
cv.visitVarInsn(ALOAD, 0);
255
256             // Gets the value of the field 'outsideConstructor'
257
cv.visitFieldInsn(GETFIELD, this.stubClassFullName.replace('.', '/'), "outsideConstructor", "Z");
258
259             // The following line is for inserting the conditional branch instruction
260
// at the beginning of the method. If the condition is satisfied, the
261
// control flows move to the previous instruction
262
cv.visitJumpInsn(IFEQ, inConstructorHandle);
263         }
264
265         // Now we create the code for the case where we are outside of
266
// the constructor, i.e. we want the call to be reified
267

268         // Pushes on the stack the reference to the proxy object
269
cv.visitVarInsn(ALOAD, 0);
270         cv.visitFieldInsn(GETFIELD, this.stubClassFullName.replace('.', '/'), PROXY_FIELD_NAME, PROXY_TYPE);
271
272         // Pushes on the stack the Method object that represents the current method
273
cv.visitFieldInsn(GETSTATIC, this.stubClassFullName.replace('.', '/'), "methods", METHOD_ARRAY_TYPE);
274         pushInt(cv, methodIndex);
275         cv.visitInsn(AALOAD);
276
277         Class JavaDoc[] paramTypes = m.getParameterTypes();
278         // Create an array of type Object[] for holding all the parameters
279
// Push on the stack the size of the array
280
pushInt(cv, paramTypes.length);
281         // Creates an array of class objects of that size
282
cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
283
284         // Fill in the array with the parameters
285
int indexInParameterArray = 1; // Necessary because sometimes we need to jump 2 slots ahead
286
for (int i = 0; i < paramTypes.length; i++) {
287             // First, duplicate the reference to the array of type Object[]
288
// That currently sits on top of the stack
289
cv.visitInsn(DUP);
290
291             // Load the array index for storing the result
292
pushInt(cv, i);
293
294             //Type theType = convertClassToType(paramTypes[i]);
295
Class JavaDoc param = paramTypes[i];
296
297             // If it is a primitive type, we need to create the wrapper here
298
if (param.isPrimitive()) {
299                 int opcode = ILOAD;
300                 String JavaDoc type;
301                 String JavaDoc desc;
302                 if (param == Byte.TYPE) {
303                     type = "java/lang/Byte";
304                     desc = "B";
305                 } else if (param == Integer.TYPE) {
306                     type = "java/lang/Integer";
307                     desc = "I";
308                 } else if (param == Boolean.TYPE) {
309                     type = "java/lang/Boolean";
310                     desc = "Z";
311                 } else if (param == Double.TYPE) {
312                     opcode = DLOAD;
313                     type = "java/lang/Double";
314                     desc = "D";
315                 } else if (param == Float.TYPE) {
316                     opcode = FLOAD;
317                     type = "java/lang/Float";
318                     desc = "F";
319                 } else if (param == Long.TYPE) {
320                     opcode = LLOAD;
321                     type = "java/lang/Long";
322                     desc = "J";
323                 } else if (param == Character.TYPE) {
324                     type = "java/lang/Character";
325                     desc = "C";
326                 } else /*if (param == Short.TYPE)*/ {
327                     type = "java/lang/Short";
328                     desc = "S";
329                 }
330                 cv.visitTypeInsn(NEW, type);
331                 cv.visitInsn(DUP);
332                 cv.visitVarInsn(opcode, indexInParameterArray);
333                 cv.visitMethodInsn(INVOKESPECIAL, type, "<init>", "(" + desc + ")V");
334             } else {
335                 cv.visitVarInsn(ALOAD, indexInParameterArray);
336             }
337             indexInParameterArray += (param == Double.TYPE || param == Long.TYPE ? 2 : 1);
338
339             // Stores the object in the array
340
cv.visitInsn(AASTORE);
341         }
342
343         // So now we have the Method object and the array of objects on the stack,
344
// Let's call the static method MethodCall.getMethodCall.
345
cv.visitMethodInsn(
346             INVOKESTATIC,
347             "org/objectweb/proactive/core/mop/MethodCall",
348             "getMethodCall",
349             "(" + METHOD_TYPE + OBJECT_ARRAY_TYPE + ")" + METHODCALL_TYPE);
350
351         // Now, call 'reify' on the proxy object
352
cv.visitMethodInsn(
353             //INVOKEVIRTUAL,
354
// BUGFIX: use INVOKEINTERFACE because Proxy is an interface
355
INVOKEINTERFACE,
356             "org/objectweb/proactive/core/mop/Proxy",
357             "reify",
358             "(" + METHODCALL_TYPE + ")" + OBJECT_TYPE);
359
360         // If the return type of the method is a primitive type,
361
// we want to unwrap it first
362
if (m.getReturnType().isPrimitive()) {
363             this.createUnwrappingCode(cv, m.getReturnType());
364         } else {
365             // If the return type is a reference type,
366
// we need to insert a type check
367
cv.visitTypeInsn(CHECKCAST, Type.getInternalName(m.getReturnType()));
368         }
369
370         // Writes the code for inside constructor
371
// What follows is a quick (but not dirty, simply non-optimized) fix to the problem
372
// of stubs built for interfaces, not classes. We simply do not perform the call
373
if (this.cl.isInterface() == false) {
374             // The following lines are for inserting the conditional branch instruction
375
// at the beginning of the method. If the condition is satisfied, the
376
// control flows move to the previous instruction
377
Label returnHandle = new Label();
378             cv.visitJumpInsn(GOTO, returnHandle);
379
380             // Now we need to perform the call to super.blablabla if need be
381
// Let's stack up the arguments
382
cv.visitLabel(inConstructorHandle);
383             cv.visitVarInsn(ALOAD, 0);
384
385
386             // This is for browsing the parameter array, not forgetting that some parameters
387
// require two slots (longs and doubles)
388
indexInParameterArray = 1;
389             for (int i = 0; i < paramTypes.length; ++i) {
390                 cv.visitVarInsn(ILOAD + getOpcodeOffset(paramTypes[i]), indexInParameterArray);
391                 indexInParameterArray += getSize(paramTypes[i]);
392             }
393
394             // And perform the call
395
String JavaDoc declaringClassName = this.methods[methodIndex].getDeclaringClass().getName();
396             cv.visitMethodInsn(
397                 INVOKESPECIAL,
398                 declaringClassName.replace('.', '/'),
399                 m.getName(),
400                 Type.getMethodDescriptor(m));
401
402             // Returns the result to the caller
403
cv.visitLabel(returnHandle);
404             createReturnCode(cv, m.getReturnType());
405
406         } else {
407             // If we are an interface, we need to remove from the top of the stack
408
// the value of boolean field that tells whether we are inside a constructor
409
// or not
410
createReturnCode(cv, m.getReturnType());
411         }
412         cv.visitMaxs(0, 0); // max stack and max locals automatically computed
413

414         return cv;
415     }
416
417     protected void createUnwrappingCode(CodeVisitor cv, Class JavaDoc c) {
418         // Depending on the type of the wrapper, the code differs
419
// The parameter 'c' represents the primitive type, not the type of the
420
// wrapper
421

422         if (c == Void.TYPE) {
423             cv.visitInsn(POP);
424         } else if (c.isPrimitive()) {
425             String JavaDoc type;
426             String JavaDoc meth;
427             String JavaDoc desc;
428             if (c == Byte.TYPE) {
429                 type = "java/lang/Byte";
430                 meth = "byteValue";
431                 desc = "B";
432             } else if (c == Integer.TYPE) {
433                 type = "java/lang/Integer";
434                 meth = "intValue";
435                 desc = "I";
436             } else if (c == Boolean.TYPE) {
437                 type = "java/lang/Boolean";
438                 meth = "booleanValue";
439                 desc = "Z";
440             } else if (c == Double.TYPE) {
441                 type = "java/lang/Double";
442                 meth = "doubleValue";
443                 desc = "D";
444             } else if (c == Float.TYPE) {
445                 type = "java/lang/Float";
446                 meth = "floatValue";
447                 desc = "F";
448             } else if (c == Long.TYPE) {
449                 type = "java/lang/Long";
450                 meth = "longValue";
451                 desc = "J";
452             } else if (c == Character.TYPE) {
453                 type = "java/lang/Character";
454                 meth = "charValue";
455                 desc = "C";
456             } else /*if (result == Short.TYPE)*/ {
457                 type = "java/lang/Short";
458                 meth = "shortValue";
459                 desc = "S";
460             }
461             cv.visitTypeInsn(CHECKCAST, type);
462             cv.visitMethodInsn(INVOKEVIRTUAL, type, meth, "()" + desc);
463         } else {
464             cv.visitTypeInsn(CHECKCAST, Type.getInternalName(c));
465         }
466
467         return;
468     }
469
470     protected void createReturnCode(CodeVisitor cv, Class JavaDoc c) {
471         if (c == Void.TYPE) {
472             cv.visitInsn(RETURN);
473         } else if (c.isPrimitive()) {
474             int opcode;
475             if (c == Double.TYPE) {
476                 opcode = DRETURN;
477             } else if (c == Float.TYPE) {
478                 opcode = FRETURN;
479             } else if (c == Long.TYPE) {
480                 opcode = LRETURN;
481             } else {
482                 opcode = IRETURN;
483             }
484             cv.visitInsn(opcode);
485         } else {
486             cv.visitInsn(ARETURN);
487         }
488     }
489
490     protected void createFields() {
491         // Creates the boolean field that indicates whether or not
492
// we are currently inside the constructor of the stub
493
// This is only necessary if we are generating a stub for
494
// a type that is not an interface
495
if (!this.cl.isInterface()) {
496             this.classGenerator.visitField(ACC_PROTECTED, "outsideConstructor", "Z", null, null);
497         }
498         // Creates the field that points to the handler inside the MOP
499
this.classGenerator.visitField(ACC_PROTECTED, PROXY_FIELD_NAME, PROXY_TYPE, null, null);
500     }
501
502     protected void createConstructor() {
503         // Actually creates the method generator (ASM : uses the visitor)
504
CodeVisitor cv = this.classGenerator.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
505
506         if (!this.cl.isInterface()) {
507             // Calls the constructor of the super class
508
cv.visitVarInsn(ALOAD, 0);
509             cv.visitMethodInsn(INVOKESPECIAL, this.className.replace('.', '/'), "<init>", "()V");
510
511             // Sets the value of 'outsideConstructor' to true
512
cv.visitVarInsn(ALOAD, 0);
513             cv.visitInsn(ICONST_1);
514             cv.visitFieldInsn(PUTFIELD, this.stubClassFullName.replace('.', '/'), "outsideConstructor", "Z");
515         } else {
516             // Calls the constructor of the super class
517
cv.visitVarInsn(ALOAD, 0);
518             cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
519         }
520
521         // And returns from the constructor
522
cv.visitInsn(RETURN);
523
524         // Needed stack size
525
// Needed locals
526
cv.visitMaxs(0, 0);
527
528
529         return;
530     }
531
532     protected void createStaticVariables() {
533         // Creates fields that contains the array of Method objects
534
// that represent the reified methods of this class
535
this.classGenerator.visitField(ACC_PROTECTED | ACC_STATIC, "methods", METHOD_ARRAY_TYPE, null, null);
536         return;
537     }
538
539     protected void createStaticInitializer() {
540         // Creates the class initializer method itself
541
CodeVisitor cv = this.classGenerator.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
542
543         // Creates an array of Method objects that we will store into the static
544
// variable 'methods' of type 'Method[]'
545
// Pushes the size of the array on to the stack
546
pushInt(cv, this.methods.length);
547         // Creates an array of Method objects of that size
548
cv.visitTypeInsn(ANEWARRAY, "java/lang/reflect/Method");
549
550         // Stores the reference to this newly-created array into the static variable 'methods'
551
cv.visitFieldInsn(PUTSTATIC, this.stubClassFullName.replace('.', '/'), "methods", METHOD_ARRAY_TYPE);
552
553         // Creates an array of Class objects that represent all the superclasses of
554
// the stub class.
555
Vector JavaDoc vectorOfSuperClasses = new Vector JavaDoc();
556         Class JavaDoc currentClass = cl;
557         while (currentClass != null) {
558             vectorOfSuperClasses.addElement(currentClass);
559             currentClass = currentClass.getSuperclass();
560         }
561
562         // Pushes on the stack the size of the array
563
pushInt(cv, vectorOfSuperClasses.size());
564         // Creates an array of class objects of that size
565
cv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
566         // Stores the reference to this newly-created array as the local variable with index '1'
567
cv.visitVarInsn(ASTORE, 1);
568
569         // Make as many calls to Class.forName as is needed to fill in the array
570
for (int i = 0; i < vectorOfSuperClasses.size(); i++) {
571             // Load onto the stack a pointer to the array
572
cv.visitVarInsn(ALOAD, 1);
573             // Load the index in the array where we want to store the result
574
pushInt(cv, i);
575             // Loads the name of the class onto the stack
576
String JavaDoc s = ((Class JavaDoc) vectorOfSuperClasses.elementAt(i)).getName();
577             cv.visitLdcInsn(s);
578             // Performs the call to Class.forName
579
cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
580
581             // Stores the result of the invocation of forName into the array
582
// The index into which to store as well as the reference to the array
583
// are already on the stack
584
cv.visitInsn(AASTORE);
585         }
586
587         // Now, lookup each of the Method objects and store it into the 'method' array
588
for (int i = 0; i < this.methods.length; i++) {
589             // Stacks up the reference to the array of methods and the index in the array
590
cv.visitFieldInsn(GETSTATIC, this.stubClassFullName.replace('.', '/'), "methods", METHOD_ARRAY_TYPE);
591             pushInt(cv, i);
592
593             // Now, we load onto the stack a pointer to the class that contains the method
594
int indexInClassArray = vectorOfSuperClasses.indexOf(this.methods[i].getDeclaringClass());
595             if (indexInClassArray == -1) {
596             }
597             // Load a pointer to the Class array (local variable number 1)
598
cv.visitVarInsn(ALOAD, 1);
599             // Access element number 'indexInClassArray'
600
pushInt(cv, indexInClassArray);
601             cv.visitInsn(AALOAD);
602             // Now, perform a call to 'getDeclaredMethod'
603
// First, stack up the simple name of the method to solve
604
cv.visitLdcInsn(this.methods[i].getName());
605             // Now, we want to create an array of type Class[] for representing
606
// the parameters to this method. We choose to store this array into the
607
// slot number 2
608
// Pushes the size of the array
609
pushInt(cv, this.methods[i].getParameterTypes().length);
610             // Creates an array of class objects of that size
611
cv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
612             // Stores the reference to this newly-created array as the local variable with index '2'
613
cv.visitVarInsn(ASTORE, 2);
614
615             // Stack up the class objects that represent the types of all the arguments to this method
616
for (int j = 0; j < this.methods[i].getParameterTypes().length; j++) {
617                 Class JavaDoc currentParameter = this.methods[i].getParameterTypes()[j];
618
619                 // Load onto the stack a pointer to the array of Class objects (for parameters)
620
cv.visitVarInsn(ALOAD, 2);
621                 // Load the index in the array where we want to store the result
622
pushInt(cv, j);
623
624                 // If the type of the parameter is a primitive one, we use the predefined
625
// constants (like java.lang.Integer.TYPE) instead of calling Class.forName
626
if (currentParameter.isPrimitive()) {
627                     // Loads that static variable
628
cv.visitFieldInsn(
629                         GETSTATIC,
630                         Type.getInternalName(Utils.getWrapperClass(currentParameter)),
631                         "TYPE",
632                         "Ljava/lang/Class;");
633                 } else {
634                     // Load the name of the parameter class onto the stack
635
cv.visitLdcInsn(currentParameter.getName());
636                     // Performs a call to Class.forName
637
cv.visitMethodInsn(
638                         INVOKESTATIC,
639                         "java/lang/Class",
640                         "forName",
641                         "(Ljava/lang/String;)Ljava/lang/Class;");
642                 }
643
644                 // Stores the result in the array
645
cv.visitInsn(AASTORE);
646             }
647
648             // Loads the array
649
cv.visitVarInsn(ALOAD, 2);
650
651             // Perform the actual call to 'getDeclaredMethod'
652
cv.visitMethodInsn(
653                 INVOKEVIRTUAL,
654                 "java/lang/Class",
655                 "getDeclaredMethod",
656                 "(Ljava/lang/String;[Ljava/lang/Class;)" + METHOD_TYPE);
657             // Now that we have the result, let's store it into the array
658
cv.visitInsn(AASTORE);
659         }
660
661         // And returns
662
cv.visitInsn(RETURN);
663
664         // Needed stack size
665
// Needed locals
666
cv.visitMaxs(0, 0);
667
668         return;
669     }
670
671     protected void createGetAndSetProxyMethods() {
672         // Do the getProxy method first
673
CodeVisitor cv = this.classGenerator.visitMethod(ACC_PUBLIC, "getProxy", "()" + PROXY_TYPE, null, null);
674
675         // Now, fills in the instruction list
676
cv.visitVarInsn(ALOAD, 0);
677         cv.visitFieldInsn(GETFIELD, this.stubClassFullName.replace('.', '/'), PROXY_FIELD_NAME, PROXY_TYPE);
678         cv.visitInsn(ARETURN);
679
680         // Needed stack size
681
// Needed locals
682
cv.visitMaxs(0, 0);
683
684         // Now, do the setProxy method
685
cv = this.classGenerator.visitMethod(ACC_PUBLIC, "setProxy", "(" + PROXY_TYPE + ")V", null, null);
686
687         // Now, fills in the instruction list
688
cv.visitVarInsn(ALOAD, 0);
689         cv.visitVarInsn(ALOAD, 1);
690         cv.visitFieldInsn(PUTFIELD, this.stubClassFullName.replace('.', '/'), PROXY_FIELD_NAME, PROXY_TYPE);
691         cv.visitInsn(RETURN);
692
693         // Needed stack size
694
// Needed locals
695
cv.visitMaxs(0, 0);
696
697         return;
698     }
699
700
701     protected static int lengthOfType(Class JavaDoc cl) {
702         int result;
703         if (cl.isPrimitive()) {
704             if ((cl.equals(Long.TYPE)) || (cl.equals(Double.TYPE))) {
705                 result = 2;
706             } else {
707                 result = 1;
708             }
709         } else {
710             result = 1;
711         }
712         return result;
713     }
714
715     /**
716      * This method is called by the constructor
717      */

718
719     protected void setInfos() {
720         logger.debug("ASMByteCodeStubBuilder.setInfos()");
721         // This hashtable is used for keeping track of the method signatures
722
// we have already met while going up the inheritance branch
723
java.util.Hashtable JavaDoc temp = new java.util.Hashtable JavaDoc();
724
725         // Recursively calls getDeclaredMethods () on the target type
726
// and each of its superclasses, all the way up to java.lang.Object
727
// We have to be careful and only take into account overriden methods once
728
Class JavaDoc currentClass = this.cl;
729
730         // This Vector keeps track of all the methods accessible from this class
731
Vector JavaDoc tempVector = new Vector JavaDoc();
732         Class JavaDoc[] params;
733         Object JavaDoc exists;
734
735         // If the target type is an interface, the only thing we have to do is to
736
// get the list of all its public methods.
737
logger.debug("ASMByteCodeStubBuilder.setInfos() 1");
738         if (this.cl.isInterface()) {
739             Method JavaDoc[] allPublicMethods = this.cl.getMethods();
740             for (int i = 0; i < allPublicMethods.length; i++) {
741                 tempVector.addElement(allPublicMethods[i]);
742             }
743         } else // If the target type is an actual class, we climb up the tree
744
{
745             do // Loops from the current class up to java.lang.Object
746
{
747                 // The declared methods for the current class
748
logger.debug("ASMByteCodeStubBuilder.setInfos() 2");
749                 Method JavaDoc[] declaredMethods = currentClass.getDeclaredMethods();
750
751                 // For each method declared in this class
752
for (int i = 0; i < declaredMethods.length; i++) {
753                     Method JavaDoc currentMethod = declaredMethods[i];
754                     // Build a key with the simple name of the method
755
// and the names of its parameters in the right order
756
String JavaDoc key = "";
757                     key = key + currentMethod.getName();
758                     params = currentMethod.getParameterTypes();
759                     for (int k = 0; k < params.length; k++) {
760                         key = key + params[k].getName();
761                     }
762                     logger.debug("ASMByteCodeStubBuilder.setInfos() 3");
763                     // Tests if we already have met this method in a subclass
764
exists = temp.get(key);
765                     if (exists == null) {
766                         // The only method we ABSOLUTELY want to be called directly
767
// on the stub (and thus not reified) is
768
// the protected void finalize () throws Throwable
769
if ((key.equals("finalize")) && (params.length == 0)) {
770                             // Do nothing, simply avoid adding this method to the list
771
} else {
772                             // If not, adds this method to the Vector that
773
// holds all the methods for this class
774
tempVector.addElement(currentMethod);
775                             temp.put(key, currentMethod);
776                         }
777                     } else {
778                         // We already know this method because it is overriden
779
// in a subclass. Then do nothing
780
}
781                 }
782                 currentClass = currentClass.getSuperclass();
783             } while (currentClass != null); // Continue until we ask for the superclass of java.lang.Object
784
}
785
786         // Turns the vector into an array of type Method[]
787
this.methods = new Method JavaDoc[tempVector.size()];
788         tempVector.copyInto(this.methods);
789
790         // Determines which methods are valid for reification
791
// It is the responsibility of method checkMethod in class Utils
792
// to decide if a method is valid for reification or not
793

794         Vector JavaDoc v = new Vector JavaDoc();
795         int initialNumberOfMethods = this.methods.length;
796
797         for (int i = 0; i < initialNumberOfMethods; i++) {
798             if (Utils.checkMethod(this.methods[i])) {
799                 v.addElement(this.methods[i]);
800             }
801         }
802         Method JavaDoc[] validMethods = new Method JavaDoc[v.size()];
803         v.copyInto(validMethods);
804
805         // Installs the list of valid methods as an instance variable of this object
806
this.methods = validMethods;
807
808         this.packageName = Utils.getPackageName(this.className);
809         this.stubClassFullName = Utils.convertClassNameToStubClassName(this.className);
810         this.stubClassSimpleName = Utils.getSimpleName(this.stubClassFullName);
811
812         return;
813     }
814
815     public String JavaDoc getStubClassFullName() {
816         return this.stubClassFullName;
817     }
818
819     // ASM : added utility methods
820

821     static void pushInt(CodeVisitor cv, int i) {
822         if (i >= -128 && i < 128) {
823             cv.visitIntInsn(BIPUSH, i);
824         } else if (i >= -32768 && i < 32768) {
825             cv.visitIntInsn(SIPUSH, i);
826         } else {
827             cv.visitLdcInsn(new Integer JavaDoc(i));
828         }
829     }
830
831     /**
832      * Returns the offset which must be added to some opcodes to get an opcode of
833      * the given type. More precisely, returns the offset which must be added to
834      * an opc_iXXXX opcode to get the opc_YXXXX opcode corresponding to the given
835      * type. For example, if the given type is double the result is 3, which
836      * means that opc_dload, opc_dstore, opc_dreturn... opcodes are equal to
837      * opc_iload+3, opc_istore+3, opc_ireturn+3...
838      *
839      * @param type a Java class representing a Java type (primitive or not).
840      * @return the opcode offset of the corresponding to the given type.
841      */

842
843     protected int getOpcodeOffset(final Class JavaDoc type) {
844         if (type == Double.TYPE) {
845             return 3;
846         } else if (type == Float.TYPE) {
847             return 2;
848         } else if (type == Long.TYPE) {
849             return 1;
850         } else if (type.isPrimitive()) {
851             return 0;
852         }
853         return 4;
854     }
855
856     /**
857      * Return the size of the given type. This size is 2 for the double and long
858      * types, and 1 for the other types.
859      *
860      * @param type a Java class representing a Java type (primitive or not).
861      * @return the size of the given type.
862      */

863
864     protected int getSize(final Class JavaDoc type) {
865         return (type == Double.TYPE || type == Long.TYPE ? 2 : 1);
866     }
867 }
868
Popular Tags