KickJava   Java API By Example, From Geeks To Geeks.

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


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.loader.Generated;
27 import org.objectweb.fractal.julia.loader.Loader;
28 import org.objectweb.fractal.julia.loader.Tree;
29
30 import org.objectweb.asm.ClassWriter;
31 import org.objectweb.asm.CodeVisitor;
32 import org.objectweb.asm.Constants;
33 import org.objectweb.asm.Type;
34
35 import java.lang.reflect.Method JavaDoc;
36 import java.util.ArrayList JavaDoc;
37 import java.util.Arrays JavaDoc;
38 import java.util.List JavaDoc;
39
40 /**
41  * An abstract class generator based on the {@link org.objectweb.asm} package.
42  * This class generator takes as parameter the name of a super class and a list
43  * of interface names, and generates a sub class of the given super class that
44  * implements all the given interfaces.
45  * <p>
46  * <b>Note</b>: since this class stores information about the class that is
47  * currently being generated in its fields, it should not be used by multiple
48  * threads simultaneously.
49  */

50
51 public abstract class AbstractClassGenerator implements
52   ClassGenerator,
53   Constants
54 {
55
56   /**
57    * The class that is being generated.
58    */

59
60   public ClassWriter cw;
61
62   /**
63    * The internal name of the class that is being generated.
64    */

65
66   public String JavaDoc name;
67
68   /**
69    * The internal name of the super class of the class that is being generated.
70    */

71
72   public String JavaDoc superClass;
73
74   /**
75    * The interfaces to be implemented by the class that is being generated.
76    * More precisely, this list of String is the list of the internal names of
77    * these interfaces.
78    */

79
80   public List JavaDoc interfaces;
81
82   /**
83    * The parameters used to generate the class that is being generated.
84    */

85
86   public String JavaDoc parameters;
87
88   /**
89    * The loader to be used to load or generate auxiliary classes, if needed.
90    */

91
92   public Loader loader;
93
94   /**
95    * The class loader to be used to load auxiliary classes, if needed.
96    */

97   
98   public ClassLoader JavaDoc classLoader;
99   
100   /**
101    * Generates a sub class of the given class that implements the given
102    * interfaces. This method initializes the fields of this class, and then
103    * calls {@link #parseArgs parseArgs}, {@link #generateHeader generateHeader},
104    * {@link #generateConstructor generateConstructor}, {@link
105    * #generateDefaultMethods generateDefaultMethods} and {@link
106    * #generateInterfaceMethods generateInterfaceMethods}, in this order, in
107    * order to generate the specified class.
108    *
109    * @param name the name of the class that must be generated.
110    * @param args the parameters that described how the class must be generated.
111    * @param loader the loader to be used to load auxiliary classes.
112    * @param classLoader the class loader to be used to load auxiliary classes.
113    * @return the generated class, as a byte array.
114    * @throws ClassGenerationException if the class cannot be generated.
115    */

116
117   public byte[] generateClass (
118     final String JavaDoc name,
119     final Tree args,
120     final Loader loader,
121     final ClassLoader JavaDoc classLoader) throws ClassGenerationException
122   {
123     this.name = name.replace('.', '/');
124     this.parameters = args.toString();
125     this.loader = loader;
126     this.classLoader = classLoader;
127     this.cw = new ClassWriter(computeMaxs());
128     parseArgs(args);
129     generateHeader();
130     generateConstructor();
131     generateDefaultMethods();
132     generateInterfaceMethods();
133     return cw.toByteArray();
134   }
135
136   /**
137    * Initializes this class generator with the given arguments. The default
138    * implementation of this method requires arguments of the form
139    * "(objectDescriptor superClassName (itfName1 ... itfNameN) ...)", where
140    * superClassName is the name of the super class of the class to be generated,
141    * and itfName1 ... itfNameN the names of the interfaces it must implement.
142    *
143    * @param args the descriptor of the class to be generated.
144    */

145
146   protected void parseArgs (final Tree args) {
147     superClass = args.getSubTree(1).toString().replace('.', '/');
148     interfaces = new ArrayList JavaDoc(Arrays.asList(args.getSubTree(2).getSubTrees()));
149     for (int i = 0; i < interfaces.size(); ++i) {
150       interfaces.set(i, interfaces.get(i).toString().replace('.', '/'));
151     }
152   }
153
154   /**
155    * Returns <tt>true</tt> if maxStack and maxLocals must be automatically
156    * computed. This method returns <tt>false</tt> by default.
157    *
158    * @return <tt>true</tt> if the maximum stack size and the maximum number of
159    * local variables of the methods generated by this class generator must
160    * be automatically computed (see {@link ClassWriter#ClassWriter
161    * ClassWriter}).
162    */

163
164   protected boolean computeMaxs () {
165     return false;
166   }
167
168   /**
169    * Generates the header of the class to be generated.
170    *
171    * @throws ClassGenerationException if a problem occurs.
172    */

173
174   protected void generateHeader () throws ClassGenerationException {
175     int access = ACC_PUBLIC;
176     List JavaDoc itfList = getImplementedInterfaces();
177     String JavaDoc[] itfs = (String JavaDoc[])itfList.toArray(new String JavaDoc[itfList.size()]);
178     cw.visit(V1_1, access, name, superClass, itfs, getSource());
179   }
180
181   /**
182    * Returns the source of the class to be generated. The default implementation
183    * of this method returns "GENERATED".
184    *
185    * @return the source of the class to be generated.
186    */

187
188   protected String JavaDoc getSource () {
189     return "GENERATED";
190   }
191
192   /**
193    * Returns all the interfaces implemented by the class to be generated. This
194    * list contains the {@link #interfaces interfaces} interfaces, and some
195    * default interfaces such as {@link
196    * org.objectweb.fractal.julia.loader.Generated}. This method is used by
197    * {@link #generateHeader generateHeader}.
198    *
199    * @return the names of all the interfaces implemented by the generated class.
200    * @throws ClassGenerationException if a problem occurs.
201    */

202
203   protected List JavaDoc getImplementedInterfaces () throws ClassGenerationException {
204     List JavaDoc itfs = new ArrayList JavaDoc(interfaces);
205     itfs.add(Type.getInternalName(Generated.class));
206     return itfs;
207   }
208
209   /**
210    * Generates the constructor of the class to be generated. The default
211    * implementation of this method generates an empty public constructor without
212    * arguments. The super class should also have such a constructor.
213    *
214    * @throws ClassGenerationException if a problem occurs.
215    */

216
217   protected void generateConstructor () throws ClassGenerationException {
218     CodeVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
219     // generates the bytecode corresponding to 'super(...);'
220
mv.visitVarInsn(ALOAD, 0);
221     mv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>", "()V");
222     mv.visitInsn(RETURN);
223     mv.visitMaxs(1, 1);
224   }
225
226   /**
227    * Generates the default methods of the class to be generated. The default
228    * implementation of this method generates the {@link
229    * org.objectweb.fractal.julia.loader.Generated#getFcGeneratorParameters
230    * getFcGeneratorParameters} method.
231    *
232    * @throws ClassGenerationException if a problem occurs.
233    */

234
235   protected void generateDefaultMethods () throws ClassGenerationException {
236     String JavaDoc name = "getFcGeneratorParameters";
237     String JavaDoc desc = "()Ljava/lang/String;";
238     CodeVisitor mv = cw.visitMethod(ACC_PUBLIC, name, desc, null, null);
239     mv.visitLdcInsn(parameters);
240     mv.visitInsn(ARETURN);
241     mv.visitMaxs(1, 1);
242   }
243
244   /**
245    * Generates the methods of the interfaces to be implemented by the class to
246    * be generated. This method calls {@link #generateMethod generateMethod} for
247    * each method of each interface to be implemented ({@link #generateMethod
248    * generateMethod} is called only once per method, even for those that are
249    * specified in several interfaces).
250    *
251    * @throws ClassGenerationException if a problem occurs.
252    */

253
254   protected void generateInterfaceMethods () throws ClassGenerationException {
255     List JavaDoc generated = new ArrayList JavaDoc();
256     for (int i = 0; i < interfaces.size(); ++i) {
257       String JavaDoc s = ((String JavaDoc)interfaces.get(i)).replace('/', '.');
258       Class JavaDoc itf;
259       try {
260         itf = loader.loadClass(s, classLoader);
261       } catch (ClassNotFoundException JavaDoc e) {
262         throw new ClassGenerationException(
263           e, parameters, "Cannot load the '" + s + "' interface");
264       }
265       Method JavaDoc[] meths = itf.getMethods();
266       for (int j = 0; j < meths.length; ++j) {
267         Method JavaDoc meth = meths[j];
268         String JavaDoc desc = meth.getName() + Type.getMethodDescriptor(meth);
269         if (!generated.contains(desc)) {
270           generateMethod(meth);
271           generated.add(desc);
272         }
273       }
274     }
275   }
276
277   /**
278    * Generates a method of an interface to be implemented by the class to be
279    * generated.
280    *
281    * @param m the method to be generated.
282    * @throws ClassGenerationException if a problem occurs.
283    */

284
285   protected abstract void generateMethod (Method JavaDoc m)
286     throws ClassGenerationException;
287
288   /**
289    * Returns the offset which must be added to some opcodes to get an opcode of
290    * the given type. More precisely, returns the offset which must be added to
291    * an opc_iXXXX opcode to get the opc_YXXXX opcode corresponding to the given
292    * type. For example, if the given type is double the result is 3, which
293    * means that opc_dload, opc_dstore, opc_dreturn... opcodes are equal to
294    * opc_iload+3, opc_istore+3, opc_ireturn+3...
295    *
296    * @param type a Java class representing a Java type (primitive or not).
297    * @return the opcode offset of the corresponding to the given type.
298    */

299
300   public static int getOpcodeOffset (final Class JavaDoc type) {
301     if (type == Double.TYPE) {
302       return 3;
303     } else if (type == Float.TYPE) {
304       return 2;
305     } else if (type == Long.TYPE) {
306       return 1;
307     } else if (type.isPrimitive()) {
308       return 0;
309     }
310     return 4;
311   }
312
313   /**
314    * Returns the size of the given type. This size is 2 for the double and long
315    * types, and 1 for the other types.
316    *
317    * @param type a Java class representing a Java type (primitive or not).
318    * @return the size of the given type.
319    */

320
321   public static int getSize (final Class JavaDoc type) {
322     return (type == Double.TYPE || type == Long.TYPE ? 2 : 1);
323   }
324 }
325
Popular Tags