KickJava   Java API By Example, From Geeks To Geeks.

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


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.CodeAdapter;
27 import org.objectweb.asm.CodeVisitor;
28 import org.objectweb.asm.Constants;
29 import org.objectweb.asm.Label;
30
31 import java.lang.reflect.Method JavaDoc;
32
33 /**
34  * An abstract code adapter to ease the implementation of {@link CodeGenerator}.
35  * This code adapter can replace the return instructions it
36  * visits with goto or jsr instructions, in order to add a post code block after
37  * the original code of a method. This code adapter can also insert new local
38  * variables before the original local variables (which are therefore shifted),
39  * but after the actual parameters. This can be useful to use private local
40  * variables in the interception code.
41  */

42
43 public abstract class InterceptorCodeAdapter
44   extends CodeAdapter
45   implements Constants
46 {
47
48   /**
49    * Describes an empty post block.
50    */

51
52   public final static int EMPTY = 0;
53
54   /**
55    * Describes a normal post code block. A normal post code block is not
56    * executed if the original code throws an exception.
57    */

58
59   public final static int NORMAL = 1;
60
61   /**
62    * Describes a finally post block. A finally post code block is always
63    * executed, even if the original code throws an exception.
64    */

65
66   public final static int FINALLY = 2;
67
68   /**
69    * The method for which this code adapter is used.
70    */

71
72   protected Method JavaDoc m;
73
74   /**
75    * Size of the formal parameters of the method for which this code adapter is
76    * used. This size is also the index of the first inserted local variable.
77    */

78
79   protected int nbFormals;
80
81   /**
82    * The inserted local variable used to store the result value.
83    */

84
85   protected int returnLocal;
86
87   /**
88    * Total size of the inserted local variables. This total includes the local
89    * variable used to store the result value.
90    */

91
92   private int newLocals;
93
94   /**
95    * Type of the post code block that will be added after the original code.
96    */

97
98   private int postBlockType;
99
100   /**
101    * Beginning of the post code block added to the original code.
102    */

103
104   protected Label postBlockLabel;
105
106   // -------------------------------------------------------------------------
107
// Constructor
108
// -------------------------------------------------------------------------
109

110   /**
111    * Constructs a new {@link InterceptorCodeAdapter}.
112    *
113    * @param cv the code visitor to which this adapter must delegate calls.
114    * @param m the method for which this code adapter is used.
115    * @param newLocals the number of new local variables that must be inserted
116    * in the original method code. This number does not include the local
117    * variable used to store the result value, which is automatically
118    * inserted. The inserted local variables are those between the {@link
119    * #nbFormals nbFormals} index, inclusive, and the {@link #nbFormals
120    * nbFormals} + <tt>newLocals</tt> index, exclusive.
121    * @param postBlockType the type of the post code block that will be added
122    * after the original code, i.e., either {@link #EMPTY EMPTY}, {@link
123    * #NORMAL NORMAL} or {@link #FINALLY FINALLY}.
124    */

125
126   public InterceptorCodeAdapter (
127     final CodeVisitor cv,
128     final Method JavaDoc m,
129     final int newLocals,
130     final int postBlockType)
131   {
132     super(cv);
133     // computes the size of the formal parameters
134
int parameterSize = 1;
135     Class JavaDoc[] formals = m.getParameterTypes();
136     for (int i = 0; i < formals.length; ++i) {
137       if (formals[i] == Long.TYPE || formals[i] == Double.TYPE) {
138         parameterSize += 2;
139       } else {
140         parameterSize += 1;
141       }
142     }
143     // computes the size of the return type
144
int returnSize;
145     Class JavaDoc result = m.getReturnType();
146     if (result == Long.TYPE || result == Double.TYPE) {
147       returnSize = 2;
148     } else if (result != Void.TYPE) {
149       returnSize = 1;
150     } else {
151       returnSize = 0;
152     }
153     // initializes fields
154
this.m = m;
155     this.nbFormals = parameterSize;
156     this.returnLocal = parameterSize + newLocals;
157     this.newLocals = newLocals + returnSize;
158     this.postBlockType = postBlockType;
159     this.postBlockLabel = new Label();
160   }
161
162   // -------------------------------------------------------------------------
163
// Overriden CodeAdapter methods
164
// -------------------------------------------------------------------------
165

166   /**
167    * Replaces returns with instructions to jump to the beginning of the post
168    * code block. More precisely, if the post code bock is empty, the returns
169    * are not replaced. If the post code block is normal they are replaced by
170    * sequences of the following form:
171    * <pre>
172    * xSTORE returnLocal
173    * GOTO postCodeLabel
174    * </pre>
175    * If the post code block is a finally block, they are replaced by sequences
176    * of the following form:
177    * <pre>
178    * xSTORE returnLocal
179    * JSR postCodeLabel
180    * xLOAD returnLocal
181    * xRETURN
182    * </pre>
183    *
184    * @param opcode the opcode of the visited instruction.
185    */

186
187   public void visitInsn (final int opcode) {
188     if (postBlockType == EMPTY) {
189       cv.visitInsn(opcode);
190       return;
191     }
192     switch (opcode) {
193       case IRETURN:
194       case LRETURN:
195       case FRETURN:
196       case DRETURN:
197       case ARETURN:
198         int opcOffset = opcode - IRETURN;
199         cv.visitVarInsn(ISTORE + opcOffset, returnLocal);
200         if (postBlockType == NORMAL) {
201           cv.visitJumpInsn(GOTO, postBlockLabel);
202         } else {
203           cv.visitJumpInsn(JSR, postBlockLabel);
204           cv.visitVarInsn(ILOAD + opcOffset, returnLocal);
205           cv.visitInsn(opcode);
206         }
207         break;
208       case RETURN:
209         if (postBlockType == NORMAL) {
210           cv.visitJumpInsn(GOTO, postBlockLabel);
211         } else {
212           cv.visitJumpInsn(JSR, postBlockLabel);
213           cv.visitInsn(RETURN);
214         }
215         break;
216       default:
217         cv.visitInsn(opcode);
218     }
219   }
220
221   /**
222    * Shifts the original local variables to make room for the inserted ones.
223    *
224    * @param opcode the opcode of the visited instruction.
225    * @param var a local variable index.
226    */

227
228   public void visitVarInsn (final int opcode, final int var) {
229     cv.visitVarInsn(opcode, var >= nbFormals ? var + newLocals : var);
230   }
231
232   /**
233    * Shifts the original local variables to make room for the inserted ones.
234    *
235    * @param var a local variable index.
236    * @param increment an increment value.
237    */

238
239   public void visitIincInsn (final int var, final int increment) {
240     cv.visitIincInsn(var >= nbFormals ? var + newLocals : var, increment);
241   }
242
243   // -------------------------------------------------------------------------
244
// Utility methods
245
// -------------------------------------------------------------------------
246

247   /**
248    * Generates the code to return the result value stored in the {@link
249    * #returnLocal returnLocal} local variable. More precisely, generates
250    * a sequence of the following form:
251    * <pre>
252    * xLOAD returnLocal
253    * xRETURN
254    * </pre>
255    */

256
257   protected void generateReturnCode () {
258     Class JavaDoc c = m.getReturnType();
259     if (c.isPrimitive()) {
260       if (c == Void.TYPE) {
261         cv.visitInsn(RETURN);
262       } else if (c == Long.TYPE) {
263         cv.visitVarInsn(LLOAD, returnLocal);
264         cv.visitInsn(LRETURN);
265       } else if (c == Float.TYPE) {
266         cv.visitVarInsn(FLOAD, returnLocal);
267         cv.visitInsn(FRETURN);
268       } else if (c == Double.TYPE) {
269         cv.visitVarInsn(DLOAD, returnLocal);
270         cv.visitInsn(DRETURN);
271       } else {
272         cv.visitVarInsn(ILOAD, returnLocal);
273         cv.visitInsn(IRETURN);
274       }
275     } else {
276       cv.visitVarInsn(ALOAD, returnLocal);
277       cv.visitInsn(ARETURN);
278     }
279   }
280 }
281
Popular Tags