KickJava   Java API By Example, From Geeks To Geeks.

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


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.asm.CodeVisitor;
27 import org.objectweb.asm.Constants;
28 import org.objectweb.asm.Label;
29
30 import java.lang.reflect.Method JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.ArrayList JavaDoc;
33
34 /**
35  * An abstract {@link CodeGenerator} to add interception code
36  * "around" methods. More precisely, depending on the result of the {@link
37  * #getInterceptionType getInterceptionType} method, the code adapters returned
38  * by the {@link #generateInterceptionCode generateInterceptionCode} method
39  * (see {@link CodeGenerator}) transform the original methods into
40  * methods of the following form:
41  *
42  * <p><pre>
43  * <i>method-signature</i> {
44  * // pre code block generated by 'generateInterceptionCodeBlock'
45  * // original method code
46  * }
47  * </pre>
48  *
49  * if {@link #getInterceptionType getInterceptionType} returns
50  * {@link InterceptorCodeAdapter#EMPTY EMPTY},
51  *
52  * <p><pre>
53  * <i>method-signature</i> {
54  * <i>return-type</i> result;
55  * // pre code block generated by 'generateInterceptionCodeBlock'
56  * // original method code, where returns are replaced with gotos
57  * // post code block generated by 'generateInterceptionCodeBlock'
58  * return result;
59  * }
60  * </pre>
61  *
62  * if {@link #getInterceptionType getInterceptionType} returns
63  * {@link InterceptorCodeAdapter#NORMAL NORMAL},
64  *
65  * <p><pre>
66  * <i>method-signature</i> {
67  * // pre code block generated by 'generateInterceptionCodeBlock'
68  * try {
69  * // original method code
70  * } finally {
71  * // post code block generated by 'generateInterceptionCodeBlock'
72  * }
73  * }
74  * </pre>
75  *
76  * if {@link #getInterceptionType getInterceptionType} returns
77  * {@link InterceptorCodeAdapter#FINALLY FINALLY}.
78  */

79
80 public abstract class AbstractCodeGenerator implements Constants, CodeGenerator {
81
82   // -------------------------------------------------------------------------
83
// Implementation of the CodeGenerator interface
84
// -------------------------------------------------------------------------
85

86   public int init (final InterceptorClassGenerator icg) {
87     return IN;
88   }
89
90   public void generateInitCode (final CodeVisitor cv)
91     throws ClassGenerationException
92   {
93     // does nothing
94
}
95
96   public CodeVisitor generateInterceptionCode (
97     final Method JavaDoc m,
98     final CodeVisitor cv) throws ClassGenerationException
99   {
100     if (intercept(m)) {
101       return new SimpleInterceptorCodeAdapter(cv, m);
102     } else {
103       return cv;
104     }
105   }
106
107   public void generateCloneCode (final CodeVisitor cv)
108     throws ClassGenerationException
109   {
110     // does nothing
111
}
112
113   public void close () {
114     // does nothing
115
}
116
117   // -------------------------------------------------------------------------
118
// Utility methods
119
// -------------------------------------------------------------------------
120

121   /**
122    * Returns <tt>true</tt> if this code generator must generate interception
123    * code for the given method. The default implementation of this method
124    * returns <tt>true</tt> for all methods.
125    *
126    * @param m a method object.
127    * @return <tt>true</tt> if this code generator must generate interception
128    * code for the given method, or <tt>false</tt> if the given method must
129    * be left unchanged.
130    */

131
132   protected boolean intercept (final Method JavaDoc m) {
133     return true;
134   }
135
136   /**
137    * Returns the type of the interception code to be generated for the given
138    * method. The default implementation of this method returns {@link
139    * InterceptorCodeAdapter#NORMAL NORMAL} for all methods.
140    *
141    * @param m a method object.
142    * @return {@link InterceptorCodeAdapter#EMPTY EMPTY} to generate only a pre
143    * code block at the beginning of the method, {@link
144    * InterceptorCodeAdapter#NORMAL NORMAL} to generate both a pre code
145    * block and a post code block, or {@link InterceptorCodeAdapter#FINALLY
146    * FINALLY} to generate a pre code block, and a post code block inside a
147    * finally block (to be sure that the post code block will always be
148    * executed).
149    */

150
151   protected int getInterceptionType (final Method JavaDoc m) {
152     return InterceptorCodeAdapter.NORMAL;
153   }
154
155   /**
156    * Returns the number of local variables that are used by the generated
157    * interception code. The default implementation of this method returns 0
158    * for all methods.
159    *
160    * @param m a method object.
161    * @return the number of local variables that are used by the generated
162    * interception code.
163    */

164
165   protected int getInterceptionCodeFormals (final Method JavaDoc m) {
166     return 0;
167   }
168
169   /**
170    * Generates an interception code block for the given method.
171    *
172    * @param m the method for which the interception code must be generated.
173    * @param pre <tt>true</tt> to generate a pre code block, or <tt>false</tt> to
174    * generate a post code block.
175    * @param cv the method visitor to be used to generate the interception code.
176    * @param formals the index of the first local variable reserved for the code
177    * block. The generated code can use the local variables between indexes
178    * <tt>formals</tt>, inclusive, and <tt>formals +
179    * getInterceptionCodeFormals(m)</tt>, exclusive.
180    */

181
182   protected abstract void generateInterceptionCodeBlock (
183     final Method JavaDoc m,
184     final boolean pre,
185     final CodeVisitor cv,
186     final int formals);
187
188  /**
189   * Returns the list of interfaces to be added to be implemented by the generated interceptor.<p>
190   *
191   * This method provides an empty implementation, returning an empty List.<p>
192   *
193   * Subclasses which need to add interfaces to be implemented by the generated
194   * interceptor should override this method.
195   *
196   * @see org.objectweb.fractal.julia.asm.CodeGenerator#getImplementedInterfaces()
197   */

198   public List JavaDoc getImplementedInterfaces() throws ClassGenerationException {
199         return new ArrayList JavaDoc();
200   }
201
202   // -------------------------------------------------------------------------
203
// Utility class
204
// -------------------------------------------------------------------------
205

206   /**
207    * A code adapter to insert pre and post code blocks around visited methods.
208    */

209
210   class SimpleInterceptorCodeAdapter extends InterceptorCodeAdapter {
211
212     /**
213      * The type of "around" code to be inserted. See getInterceptionType.
214      */

215
216     private int interceptionType;
217
218     /**
219      * Beginning of the original method code.
220      */

221
222     private Label tryLabel;
223
224     /**
225      * Beginning of the exception handler block for the finally block.
226      */

227
228     private Label catchLabel;
229
230     /**
231      * Constructs a new {@link SimpleInterceptorCodeAdapter}.
232      *
233      * @param cv the code visitor to which this adapter must delegate calls.
234      * @param m the method for which this code adapter is used.
235      */

236
237     public SimpleInterceptorCodeAdapter (final CodeVisitor cv, final Method JavaDoc m) {
238       // local variables that are inserted:
239
// local var at index nbFormals = return address for RET
240
// local var at index nbFormals + 1 = catched exception
241
// local var at index nbFormals + 2, 3, ... = user defined variables
242
super(
243         cv,
244         m,
245         getInterceptionCodeFormals(m) +
246           (getInterceptionType(m) == FINALLY ? 2 : 0),
247         getInterceptionType(m));
248       // generates the pre code block
249
interceptionType = getInterceptionType(m);
250       if (interceptionType == FINALLY) {
251         tryLabel = new Label();
252         catchLabel = new Label();
253         generateInterceptionCodeBlock(m, true, cv, nbFormals + 2);
254         cv.visitLabel(tryLabel);
255       } else {
256         generateInterceptionCodeBlock(m, true, cv, nbFormals);
257       }
258     }
259
260     public void visitMaxs (final int maxStack, final int maxLocals) {
261       if (interceptionType == NORMAL) {
262         visitLabel(postBlockLabel);
263         // generates the post code block
264
generateInterceptionCodeBlock(m, false, cv, nbFormals);
265         // generates the appropriate xRETURN opcode
266
generateReturnCode();
267       } else if (interceptionType == FINALLY) {
268         // generates the bytecode corresponding to: finally {
269
cv.visitLabel(catchLabel);
270         cv.visitVarInsn(ASTORE, nbFormals + 1);
271         cv.visitJumpInsn(JSR, postBlockLabel);
272         cv.visitVarInsn(ALOAD, nbFormals + 1);
273         cv.visitInsn(ATHROW);
274         cv.visitLabel(postBlockLabel);
275         cv.visitVarInsn(ASTORE, nbFormals);
276         // generates the content of the finally block
277
generateInterceptionCodeBlock(m, false, cv, nbFormals + 2);
278         // generates the end of the finally block
279
cv.visitVarInsn(RET, nbFormals);
280         // generates the exception table
281
cv.visitTryCatchBlock(tryLabel, catchLabel, catchLabel, null);
282       }
283       // visits the max stack and max locals attributes
284
cv.visitMaxs(maxStack, maxLocals);
285     }
286   }
287 }
288
Popular Tags