KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > julia > asm > MetaCodeGenerator


1 /***
2  * Julia: France Telecom's implementation of the Fractal API
3  * Copyright (C) 2001-2002 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: Eric.Bruneton@rd.francetelecom.com
20  *
21  * Author: Eric Bruneton
22  */

23
24 package org.objectweb.fractal.julia.asm;
25
26 import org.objectweb.fractal.julia.InitializationContext;
27 import org.objectweb.fractal.julia.loader.Initializable;
28 import org.objectweb.fractal.julia.loader.Tree;
29
30 import org.objectweb.asm.ClassVisitor;
31 import org.objectweb.asm.CodeVisitor;
32 import org.objectweb.asm.Constants;
33 import org.objectweb.asm.Label;
34 import org.objectweb.asm.Type;
35 import org.objectweb.asm.Attribute;
36
37 import java.lang.reflect.Method JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.List JavaDoc;
40
41 /**
42  * A {@link CodeGenerator} to generate interception code that
43  * reifies method calls. This abstract code generator can
44  * be used to easily generate interceptors of the following form, without
45  * knowing the Java bytecode instructions and ASM:
46  *
47  * <center>
48  * <img SRC="../../../../../../figures/interceptor.gif" height=313 width=417><p>
49  * <b>Figure 1: an interceptor and an associated controller object (see also
50  * <a HREF="../../../../../overview-summary.html#4">here</a>)</b>
51  * </center>
52  *
53  * <p>where the interceptor calls a <tt>void</tt> <i>handleMethodCall</i>
54  * <tt>(Method m, Object[] args)</tt> method on the controller object at each
55  * intercepted method. This abstract code generator can be configured in many
56  * ways:
57  * <ul>
58  * <li>The name <i>N</i> (see the above figure) can be configured with the
59  * {@link #getControllerInterfaceName getControllerInterfaceName} method.</li>
60  * <li>The name of the <i>handleMethodCall</i> method can be configured
61  * with the {@link #getHandleMethodCallMethodName getHandleMethodCallMethodName}
62  * method. This method must be defined in the <i>C</i> class. It can also be
63  * declared in the <tt>T</tt> interface, but this is not mandatory.</li>
64  * <li>the name of Fractal interface to which the interceptor is associated can
65  * be passed as parameter to the <i>handleMethodCall</i> method. For this you
66  * just need to override the {@link #reifyInterfaceName reifyInterfaceName}
67  * method, so that it returns <tt>true</tt>. The <i>handleMethodCall</i>
68  * method must then have an additional parameter of type <tt>String</tt>:
69  * <tt>Object handleMethodCall (String itf, Method m, Object[] args)</tt>.</li>
70  * <li>the target object of the intercepted method call can be passed as
71  * parameter to the <i>handleMethodCall</i> method. For this you just need to
72  * override the {@link #reifyTargetObject reifyTargetObject} method, so that it
73  * returns <tt>true</tt>. The <i>handleMethodCall</i> method must then have an
74  * additional parameter of type <tt>Object</tt>: <tt>Object handleMethodCall
75  * (Object target, Method m, Object[] args)</tt> (if the previous option is also
76  * enabled, the parameters must be placed in the following order: <tt>Object
77  * handleMethodCall (String itf, Object target, Method m, Object[] args)</tt>).
78  * </li>
79  * <li>the {@link #intercept intercept} method can be overriden to intercept
80  * only some specific methods, while leaving the other unchanged.</li>
81  * </ul>
82  *
83  * <p>The code adapters returned by the {@link #generateInterceptionCode
84  * generateInterceptionCode} method (see {@link CodeGenerator})
85  * transform the original methods into methods of the following form:
86  *
87  * <p><pre>
88  * <i>method-signature</i> {
89  * return (...)delegate.<i>handleMethodCall</i>(
90  * _M<i>id</i>, new Object[] { ... });
91  * }
92  * </pre>
93  *
94  * <p>The <tt>_M</tt><i>id</i> static fields are initialized by a static
95  * initializer whose code is generated by this code generator. This initializer
96  * has the following form:
97  *
98  * <p><pre>
99  * static {
100  * _M0 = Class.forName(...).getMethod(... , new Class[] { ... });
101  * _M1 = Class.forName(...).getMethod(... , new Class[] { ... });
102  * ...
103  * }
104  * </pre>
105  *
106  * <p>The {@link #generateInitCode generateInitCode} method adds a
107  * <tt>delegate</tt> field to the interceptor class, and adds a code fragment of
108  * the following form to the generated {@link #generateInitCode
109  * generateInitCode} method (recall that <i>N</i> can be configured with the
110  * {@link #getControllerInterfaceName getControllerInterfaceName} method):
111  *
112  * <p><pre>
113  * delegate = (...)ic.getFcInterface(<i>N</i>);
114  * </pre>
115  *
116  * Finally this code generator takes into account the Julia
117  * <a HREF="../../../../../overview-summary.html#5.1">optimizations options</a>.
118  * So, for example, if the interceptors and controller objects are merged, the
119  * <tt>delegate</tt> field is not generated, and <tt>this</tt> is used instead.
120  * Moreover, if the content, the controller and the interceptor classes are
121  * merged, then the interception code that is generated takes the following
122  * form:
123  *
124  * <p><pre>
125  * <i>method-signature</i> {
126  * if (!<i>isReflectedCall</i>()) {
127  * return (...)<i>handleMethodCall</i>(
128  * _M<i>id</i>, new Object[] { ... });
129  * } else {
130  * // original method code
131  * }
132  * }
133  * </pre>
134  *
135  * The first time this method is called the <i>isReflectedCall</i> method (which
136  * must be provided by the associated controller object) must return
137  * <tt>false</tt>. The call is therefore reifed and passed to the
138  * <i>handleMethodCall</i> method. This method will then call the method back,
139  * through the Java Reflection API, and this time the <i>isReflectedCall</i>
140  * must return <tt>true</tt>, so that the original method code is executed. The
141  * name of the <i>isReflectedCall</i> method can be configured
142  * with the {@link #getIsReflectedCallMethodName getIsReflectedCallMethodName}
143  * method.
144  */

145
146 public abstract class MetaCodeGenerator implements
147   Initializable,
148   CodeGenerator,
149   Constants
150 {
151
152   /**
153    * The arguments used to initialize this object. These arguments are the list
154    * of interface names, corresponding to the list of interface types in
155    * icg.interfaces. May be <tt>null</tt>.
156    */

157
158   private Tree args;
159
160   /**
161    * The interceptor class generator to which this code generator belongs.
162    */

163
164   private InterceptorClassGenerator icg;
165
166   /**
167    * The name of the 'delegate' field.
168    */

169
170   private String JavaDoc delegateFieldName;
171
172   /**
173    * The descriptor of the 'delegate' field.
174    */

175
176   private String JavaDoc delegateFieldDesc;
177
178   /**
179    * The name of the owner class of the 'delegate' field.
180    */

181
182   private String JavaDoc owner;
183
184   /**
185    * The code visitor used to generate the static initializer.
186    */

187
188   private CodeVisitor clinit;
189
190   /**
191    * Counter used to generate names for the static fields containing the Method
192    * objects.
193    */

194
195   private int counter;
196
197   // -------------------------------------------------------------------------
198
// Implementation of the Init interface
199
// -------------------------------------------------------------------------
200

201   public void initialize (Tree args) {
202     this.args = args.getSubTree(0);
203   }
204
205   // -------------------------------------------------------------------------
206
// Implementation of the CodeGenerator interface
207
// -------------------------------------------------------------------------
208

209   public int init (final InterceptorClassGenerator icg) {
210     this.icg = icg;
211     return IN;
212   }
213
214   public void generateInitCode (final CodeVisitor cv)
215     throws ClassGenerationException
216   {
217     // computes the internal name of the controller class
218
// that contains the needed 'handleMethodCall' method
219
String JavaDoc owner = null;
220     for (int i = 0; i < icg.controllerClasses.length; ++i) {
221       Class JavaDoc c = icg.controllerClasses[i];
222       List JavaDoc params = new ArrayList JavaDoc();
223       if (reifyInterfaceName()) {
224         params.add(String JavaDoc.class);
225       }
226       if (reifyTargetObject()) {
227         params.add(Object JavaDoc.class);
228       }
229       params.add(Method JavaDoc.class);
230       params.add(Object JavaDoc[].class);
231       Class JavaDoc[] paramClasses = (Class JavaDoc[])params.toArray(new Class JavaDoc[params.size()]);
232       try {
233         c.getMethod(getHandleMethodCallMethodName(), paramClasses);
234         owner = c.getName();
235         break;
236       } catch (Exception JavaDoc e) {
237       }
238     }
239     if (owner == null) {
240       throw new ClassGenerationException(
241         null,
242         icg.args.toString(),
243         "Cannot find a controller class providing a '" +
244         getHandleMethodCallMethodName() + "' method with the good arguments");
245     }
246     owner = owner.replace('.', '/');
247
248     int hashcode = getControllerInterfaceName().hashCode();
249     delegateFieldName = "d" + Integer.toHexString(hashcode);
250     delegateFieldDesc = "L" + owner + ";";
251
252     icg.cw.visitField(
253       ACC_PRIVATE, delegateFieldName, delegateFieldDesc, null, null);
254
255     cv.visitVarInsn(ALOAD, 0);
256     cv.visitVarInsn(ALOAD, 1);
257     cv.visitLdcInsn(getControllerInterfaceName());
258     cv.visitMethodInsn(
259       INVOKEVIRTUAL,
260       Type.getInternalName(InitializationContext.class),
261       "getInterface",
262       "(" + Type.getDescriptor(String JavaDoc.class) + ")" +
263         Type.getDescriptor(Object JavaDoc.class));
264     cv.visitTypeInsn(CHECKCAST, owner);
265     cv.visitFieldInsn(PUTFIELD, icg.name, delegateFieldName, delegateFieldDesc);
266   }
267
268   public CodeVisitor generateInterceptionCode (
269     final Method JavaDoc m,
270     final CodeVisitor cv)
271   {
272     if (intercept(m)) {
273       return new MetaCodeAdapter(cv, m);
274     } else {
275       return cv;
276     }
277   }
278
279   public void generateCloneCode (final CodeVisitor cv) {
280     cv.visitVarInsn(ALOAD, 1);
281     cv.visitVarInsn(ALOAD, 0);
282     cv.visitFieldInsn(GETFIELD, icg.name, delegateFieldName, delegateFieldDesc);
283     cv.visitFieldInsn(PUTFIELD, icg.name, delegateFieldName, delegateFieldDesc);
284   }
285
286   public void close () {
287     if (clinit != null) {
288       clinit.visitInsn(RETURN);
289       clinit.visitMaxs(0, 0);
290     }
291   }
292
293   // -------------------------------------------------------------------------
294
// Utility methods
295
// -------------------------------------------------------------------------
296

297   /**
298    * Returns the name of the interface provided by the controller object to be
299    * associated to the interceptor.
300    *
301    * @return the name of the interface provided by the controller object to be
302    * associated to the interceptor (called <i>N</i> in the above figure).
303    */

304
305   protected abstract String JavaDoc getControllerInterfaceName ();
306
307   /**
308    * Returns <tt>true</tt> if this code generator must generate interception
309    * code for the given method. The default implementation of this method
310    * returns <tt>true</tt> for all methods.
311    *
312    * @param m a method object.
313    * @return <tt>true</tt> if this code generator must generate interception
314    * code for the given method, or <tt>false</tt> if the given method must
315    * be left unchanged.
316    */

317
318   protected boolean intercept (final Method JavaDoc m) {
319     return true;
320   }
321
322   /**
323    * Returns the name of the method to be called on the associated controller
324    * object, for each intercepted call.
325    *
326    * @return the name of the method to be called on the associated controller
327    * object, for each intercepted call (called <i>handleMethodCall</i>
328    * above).
329    */

330
331   protected abstract String JavaDoc getHandleMethodCallMethodName ();
332
333   /**
334    * Returns <tt>true</tt> if the target interface name must be passed as
335    * argument to the <i>handleMethodCall</i> method. The default implementation
336    * of this method returns <tt>false</tt>.
337    *
338    * @return <tt>true</tt> if the name of the fractal interface associated to
339    * the generated interceptor must be passed as argument to the
340    * <i>handleMethodCall</i> method.
341    */

342
343   protected boolean reifyInterfaceName () {
344     return false;
345   }
346
347   /**
348    * Returns the name of the fractal interface in which the given method is
349    * defined.
350    *
351    * @param m a method.
352    * @return the name of the fractal interface in which the given method is
353    * defined.
354    */

355
356   private String JavaDoc getInterfaceName (Method JavaDoc m) {
357     if (args != null) {
358       String JavaDoc desc = m.getName()+Type.getMethodDescriptor(m);
359       List JavaDoc itfs = icg.interfaces;
360       for (int i = 0; i < itfs.size(); ++i) {
361         String JavaDoc itf = ((String JavaDoc)itfs.get(i)).replace('/', '.');
362         Class JavaDoc c;
363         try {
364           c = icg.loader.loadClass(itf, icg.classLoader);
365         } catch (ClassNotFoundException JavaDoc e) {
366           continue;
367         }
368         Method JavaDoc[] meths = c.getMethods();
369         for (int j = 0; j < meths.length; ++j) {
370           Method JavaDoc meth = meths[j];
371           if (desc.equals(meth.getName()+Type.getMethodDescriptor(meth))) {
372             return args.getSubTree(i).toString();
373           }
374         }
375       }
376     }
377     return null;
378   }
379
380   /**
381    * Returns <tt>true</tt> if the target object must be passed as argument
382    * to the <i>handleMethodCall</i> method. The default implementation of this
383    * method returns <tt>false</tt>.
384    *
385    * @return <tt>true</tt> if the target object of intercepted method calls must
386    * be passed as argument to the <i>handleMethodCall</i> method.
387    */

388
389   protected boolean reifyTargetObject () {
390     return false;
391   }
392
393   /**
394    * Returns the name of the method to be called on the associated controller
395    * object to identify reflected calls.
396    *
397    * @return the name of the method to be called on the associated controller
398    * object to identify reflected calls. (called <i>isReflectedCall</i>
399    * above).
400    */

401
402   protected abstract String JavaDoc getIsReflectedCallMethodName ();
403
404   /**
405    * Generates code to initialize a static field containing the Method object.
406    *
407    * @param m the static field's value.
408    * @param owner the internal name of the owner class of the static field.
409    * @param field the static field's name.
410    * @param cv the class visitor to be used to generate the static field.
411    * @param mv the code visitor to be used to generate the static field's
412    * initialization code.
413    */

414
415   public static void generateMethodInitializerCode (
416     final Method JavaDoc m,
417     final String JavaDoc owner,
418     final String JavaDoc field,
419     final ClassVisitor cv,
420     final CodeVisitor mv)
421   {
422     // adds the static field to the class that is being generated
423
cv.visitField(
424       ACC_PRIVATE + ACC_STATIC,
425       field,
426       "Ljava/lang/reflect/Method;",
427       null,
428       null);
429
430     // generates "Class c = Class.forName(...);"
431
mv.visitLdcInsn(m.getDeclaringClass().getName());
432     mv.visitMethodInsn(
433       INVOKESTATIC,
434       "java/lang/Class",
435       "forName",
436       "(Ljava/lang/String;)Ljava/lang/Class;");
437     // generates code to push the method's name
438
mv.visitLdcInsn(m.getName());
439     // generates code to push the method's argument types
440
Class JavaDoc[] formals = m.getParameterTypes();
441     mv.visitIntInsn(SIPUSH, formals.length);
442     mv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
443     for (int i = 0; i < formals.length; ++i) {
444       mv.visitInsn(DUP);
445       mv.visitIntInsn(SIPUSH, i);
446       Class JavaDoc c = formals[i];
447       if (c.isPrimitive()) {
448         String JavaDoc type;
449         if (c == Byte.TYPE) {
450           type = "java/lang/Byte";
451         } else if (c == Integer.TYPE) {
452           type = "java/lang/Integer";
453         } else if (c == Boolean.TYPE) {
454           type = "java/lang/Boolean";
455         } else if (c == Double.TYPE) {
456           type = "java/lang/Double";
457         } else if (c == Float.TYPE) {
458           type = "java/lang/Float";
459         } else if (c == Long.TYPE) {
460           type = "java/lang/Long";
461         } else if (c == Character.TYPE) {
462           type = "java/lang/Character";
463         } else /*if (c == Short.TYPE)*/ {
464           type = "java/lang/Short";
465         }
466         mv.visitFieldInsn(
467           GETSTATIC, type, "TYPE", "Ljava/lang/Class;");
468       } else {
469         String JavaDoc name;
470         if (c.isArray()) {
471           name = Type.getDescriptor(c).replace('/', '.');
472         } else {
473           name = c.getName();
474         }
475         mv.visitLdcInsn(name);
476         mv.visitMethodInsn(
477           INVOKESTATIC,
478           "java/lang/Class",
479           "forName",
480           "(Ljava/lang/String;)Ljava/lang/Class;");
481       }
482       mv.visitInsn(AASTORE);
483     }
484     // generates "_Mi = c.getMethod(name, formals);"
485
mv.visitMethodInsn(
486       INVOKEVIRTUAL,
487       "java/lang/Class",
488       "getMethod",
489       "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
490     mv.visitFieldInsn(
491       PUTSTATIC,
492       owner,
493       field,
494       "Ljava/lang/reflect/Method;");
495   }
496
497   /**
498    * Generates the code to reify the arguments of the given method.
499    * For a method "int m (int i, String s)", this code is the bytecode
500    * corresponding to the "new Object[] { new Integer(i), s}" expression.
501    *
502    * @param m a method object.
503    * @param cv the code visitor to be used to generate the bytecode.
504    */

505
506   public static void generateParameterReifierCode (
507     final Method JavaDoc m,
508     final CodeVisitor cv)
509   {
510     Class JavaDoc[] params = m.getParameterTypes();
511     cv.visitIntInsn(SIPUSH, params.length);
512     cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
513     int localVarIndex = 1;
514     for (int i = 0; i < params.length; ++i) {
515       Class JavaDoc param = params[i];
516       cv.visitInsn(DUP);
517       cv.visitIntInsn(SIPUSH, i);
518       if (param.isPrimitive()) {
519         int opcode = ILOAD;
520         String JavaDoc type;
521         String JavaDoc desc;
522         if (param == Byte.TYPE) {
523           type = "java/lang/Byte";
524           desc = "B";
525         } else if (param == Integer.TYPE) {
526           type = "java/lang/Integer";
527           desc = "I";
528         } else if (param == Boolean.TYPE) {
529           type = "java/lang/Boolean";
530           desc = "Z";
531         } else if (param == Double.TYPE) {
532           opcode = DLOAD;
533           type = "java/lang/Double";
534           desc = "D";
535         } else if (param == Float.TYPE) {
536           opcode = FLOAD;
537           type = "java/lang/Float";
538           desc = "F";
539         } else if (param == Long.TYPE) {
540           opcode = LLOAD;
541           type = "java/lang/Long";
542           desc = "J";
543         } else if (param == Character.TYPE) {
544           type = "java/lang/Character";
545           desc = "C";
546         } else /*if (param == Short.TYPE)*/ {
547           type = "java/lang/Short";
548           desc = "S";
549         }
550         cv.visitTypeInsn(NEW, type);
551         cv.visitInsn(DUP);
552         cv.visitVarInsn(opcode, localVarIndex);
553         cv.visitMethodInsn(
554           INVOKESPECIAL, type, "<init>", "(" + desc + ")V");
555       } else {
556         cv.visitVarInsn(ALOAD, localVarIndex);
557       }
558       cv.visitInsn(AASTORE);
559       localVarIndex += (param == Double.TYPE || param == Long.TYPE ? 2 : 1);
560     }
561   }
562
563   /**
564    * Generates the code to unreify the result of the given method.
565    * For a method "int m (int i, String s)", this code is the bytecode
566    * corresponding to the "((Integer)...).intValue()" expression.
567    *
568    * @param m a method object.
569    * @param cv the code visitor to be used to generate the bytecode.
570    */

571
572   public static void generateReturnCode (final Method JavaDoc m, final CodeVisitor cv) {
573     Class JavaDoc result = m.getReturnType();
574     if (result == Void.TYPE) {
575       cv.visitInsn(POP);
576       cv.visitInsn(RETURN);
577     } else if (result.isPrimitive()) {
578       int opcode = IRETURN;
579       String JavaDoc type;
580       String JavaDoc meth;
581       String JavaDoc desc;
582       if (result == Byte.TYPE) {
583         type = "java/lang/Byte";
584         meth = "byteValue";
585         desc = "B";
586       } else if (result == Integer.TYPE) {
587         type = "java/lang/Integer";
588         meth = "intValue";
589         desc = "I";
590       } else if (result == Boolean.TYPE) {
591         type = "java/lang/Boolean";
592         meth = "booleanValue";
593         desc = "Z";
594       } else if (result == Double.TYPE) {
595         opcode = DRETURN;
596         type = "java/lang/Double";
597         meth = "doubleValue";
598         desc = "D";
599       } else if (result == Float.TYPE) {
600         opcode = FRETURN;
601         type = "java/lang/Float";
602         meth = "floatValue";
603         desc = "F";
604       } else if (result == Long.TYPE) {
605         opcode = LRETURN;
606         type = "java/lang/Long";
607         meth = "longValue";
608         desc = "J";
609       } else if (result == Character.TYPE) {
610         type = "java/lang/Character";
611         meth = "charValue";
612         desc = "C";
613       } else /*if (result == Short.TYPE)*/ {
614         type = "java/lang/Short";
615         meth = "shortValue";
616         desc = "S";
617       }
618       cv.visitTypeInsn(CHECKCAST, type);
619       cv.visitMethodInsn(INVOKEVIRTUAL, type, meth, "()" + desc);
620       cv.visitInsn(opcode);
621     } else {
622       cv.visitTypeInsn(CHECKCAST, Type.getInternalName(result));
623       cv.visitInsn(ARETURN);
624     }
625   }
626  
627   /**
628    * Returns the list of interfaces to be added to be implemented by the generated interceptor.<p>
629    *
630    * This method provides an empty implementation, returning an empty List.<p>
631    *
632    * Subclasses which need to add interfaces to be implemented by the generated
633    * interceptor should override this method.
634    *
635    * @see org.objectweb.fractal.julia.asm.CodeGenerator#getImplementedInterfaces()
636    */

637    public List JavaDoc getImplementedInterfaces() throws ClassGenerationException {
638         return new ArrayList JavaDoc();
639    }
640
641   // -------------------------------------------------------------------------
642
// Utility class
643
// -------------------------------------------------------------------------
644

645   /**
646    * A code adapter to insert a meta object related interception code block to
647    * the code of a method.
648    */

649
650   class MetaCodeAdapter implements CodeVisitor {
651
652     /**
653      * The code visitor to which this code adapter delegates calls.
654      */

655
656     private final CodeVisitor cv;
657
658     /**
659      * Indicates if the controller, interceptor and content classes are merged.
660      */

661
662     private final boolean mergeAll;
663
664     /**
665      * Constructs a new {@link MetaCodeAdapter}.
666      *
667      * @param cv the code visitor to which this adapter must delegate calls.
668      * @param m the method for which this code adapter is used.
669      */

670
671     public MetaCodeAdapter (
672       final CodeVisitor cv,
673       final Method JavaDoc m)
674     {
675       this.cv = cv;
676       this.mergeAll = icg.mergeAll;
677
678       // computes the name of the owner class of the 'delegate' field.
679
if (owner == null) {
680         if (delegateFieldDesc == null) {
681           owner = icg.name;
682         } else {
683           owner = delegateFieldDesc.substring(1, delegateFieldDesc.length() - 1);
684         }
685       }
686
687       Label endLabel = null;
688
689       if (mergeAll) {
690         // generates code to test if the current call is a reflected call
691
cv.visitVarInsn(ALOAD, 0);
692         cv.visitMethodInsn(
693           INVOKEVIRTUAL,
694           owner,
695           getIsReflectedCallMethodName(),
696           "()Z");
697         endLabel = new Label();
698         cv.visitJumpInsn(IFNE, endLabel);
699       }
700
701       // pushes the reference of the controller object associated to the
702
// interceptor. This reference is stored in the 'delegate' field, unless
703
// the controller and interceptor classes are merged (in this case the
704
// reference of the controller object is the reference of the interceptor,
705
// i.e., 'this')
706
cv.visitVarInsn(ALOAD, 0);
707       // if controller and interceptor classes are merged, the generateInitCode
708
// method is not called, and the delegateFieldName is therefore null. In
709
// this case we do not load the value of the 'delegate' field, which does
710
// not exist.
711
if (delegateFieldName != null) {
712         cv.visitFieldInsn(
713           GETFIELD, icg.name, delegateFieldName, delegateFieldDesc);
714       }
715
716       // adds code to the static initializer to initialize the static field
717
// containing the Method object
718
// adds code to the static initializer to initialize this field
719
if (clinit == null) {
720         // creates the static initializer first, if does not exist yet
721
clinit = icg.cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
722       }
723       generateMethodInitializerCode(m, icg.name, "_M"+counter, icg.cw, clinit);
724
725       if (reifyInterfaceName()) {
726         String JavaDoc name = getInterfaceName(m);
727         if (name == null) {
728           cv.visitInsn(ACONST_NULL);
729         } else {
730           cv.visitLdcInsn(name);
731         }
732       }
733
734       if (reifyTargetObject()) {
735         // generates code to push the reference of the target object
736
cv.visitVarInsn(ALOAD, 0);
737         cv.visitFieldInsn(
738           GETFIELD, icg.name, icg.implFieldName, icg.implFieldDesc);
739       }
740
741       // generates code to push the value of the static
742
// field containing the Method object
743
cv.visitFieldInsn(
744         GETSTATIC, icg.name, "_M" + counter, "Ljava/lang/reflect/Method;");
745
746       // generates code to push the reified method arguments
747
generateParameterReifierCode(m, cv);
748
749       // generates code to call the 'handleMethodCall' method
750
String JavaDoc desc =
751         "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;";
752       if (reifyTargetObject()) {
753         desc = "Ljava/lang/Object;" + desc;
754       }
755       if (reifyInterfaceName()) {
756         desc = "Ljava/lang/String;" + desc;
757       }
758       cv.visitMethodInsn(
759         INVOKEVIRTUAL,
760         owner,
761         getHandleMethodCallMethodName(),
762         "(" + desc);
763
764       // generates code to return result
765
generateReturnCode(m, cv);
766
767       if (mergeAll) {
768         cv.visitLabel(endLabel);
769       } else {
770         cv.visitMaxs(0, 0);
771       }
772
773       ++counter;
774     }
775
776     // -------------------------------------------------------------------------
777
// Implementation of the CodeVisitor interface
778
// -------------------------------------------------------------------------
779

780     public void visitInsn (final int opcode) {
781       if (mergeAll) {
782         cv.visitInsn(opcode);
783       }
784     }
785
786     public void visitIntInsn (final int opcode, final int operand) {
787       if (mergeAll) {
788         cv.visitIntInsn(opcode, operand);
789       }
790     }
791
792     public void visitVarInsn (final int opcode, final int var) {
793       if (mergeAll) {
794         cv.visitVarInsn(opcode, var);
795       }
796     }
797
798     public void visitTypeInsn (final int opcode, final String JavaDoc desc) {
799       if (mergeAll) {
800         cv.visitTypeInsn(opcode, desc);
801       }
802     }
803
804     public void visitFieldInsn (
805       final int opcode,
806       final String JavaDoc owner,
807       final String JavaDoc name,
808       final String JavaDoc desc)
809     {
810       if (mergeAll) {
811         cv.visitFieldInsn(opcode, owner, name, desc);
812       }
813     }
814
815     public void visitMethodInsn (
816       final int opcode,
817       final String JavaDoc owner,
818       final String JavaDoc name,
819       final String JavaDoc desc)
820     {
821       if (mergeAll) {
822         cv.visitMethodInsn(opcode, owner, name, desc);
823       }
824     }
825
826     public void visitJumpInsn (final int opcode, final Label label) {
827       if (mergeAll) {
828         cv.visitJumpInsn(opcode, label);
829       }
830     }
831
832     public void visitLabel (final Label label) {
833       if (mergeAll) {
834         cv.visitLabel(label);
835       }
836     }
837
838     public void visitLdcInsn (final Object JavaDoc cst) {
839       if (mergeAll) {
840         cv.visitLdcInsn(cst);
841       }
842     }
843
844     public void visitIincInsn (final int var, final int increment) {
845       if (mergeAll) {
846         cv.visitIincInsn(var, increment);
847       }
848     }
849
850     public void visitTableSwitchInsn (
851       final int min,
852       final int max,
853       final Label dflt,
854       final Label labels[])
855     {
856       if (mergeAll) {
857         cv.visitTableSwitchInsn(min, max, dflt, labels);
858       }
859     }
860
861     public void visitLookupSwitchInsn (
862       final Label dflt,
863       final int keys[],
864       final Label labels[])
865     {
866       if (mergeAll) {
867         cv.visitLookupSwitchInsn(dflt, keys, labels);
868       }
869     }
870
871     public void visitMultiANewArrayInsn (final String JavaDoc desc, final int dims) {
872       if (mergeAll) {
873         cv.visitMultiANewArrayInsn(desc, dims);
874       }
875     }
876
877     public void visitTryCatchBlock (
878       final Label start,
879       final Label end,
880       final Label handler,
881       final String JavaDoc type)
882     {
883       if (mergeAll) {
884         cv.visitTryCatchBlock(start, end, handler, type);
885       }
886     }
887
888     public void visitMaxs (final int maxStack, final int maxLocals) {
889       if (mergeAll) {
890         cv.visitMaxs(maxStack, maxLocals);
891       }
892     }
893
894     public void visitAttribute (final Attribute attribute) {
895       cv.visitAttribute(attribute);
896     }
897
898     public void visitLocalVariable (
899       final String JavaDoc name,
900       final String JavaDoc desc,
901       final Label start,
902       final Label end,
903       final int index)
904     {
905       if (mergeAll) {
906         cv.visitLocalVariable(name, desc, start, end, index);
907       }
908     }
909
910     public void visitLineNumber (final int line, final Label start) {
911       if (mergeAll) {
912         cv.visitLineNumber(line, start);
913       }
914     }
915   }
916 }
917
Popular Tags