KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > classgen > ReflectorGenerator


1 /*
2  $Id: ReflectorGenerator.java,v 1.8 2004/12/14 16:18:14 russel Exp $
3
4  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5
6  Redistribution and use of this software and associated documentation
7  ("Software"), with or without modification, are permitted provided
8  that the following conditions are met:
9
10  1. Redistributions of source code must retain copyright
11     statements and notices. Redistributions must also contain a
12     copy of this document.
13
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus. For written permission,
22     please contact info@codehaus.org.
23
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44
45  */

46 package org.codehaus.groovy.classgen;
47
48 import groovy.lang.MetaMethod;
49
50 import java.util.List JavaDoc;
51
52 import org.objectweb.asm.ClassVisitor;
53 import org.objectweb.asm.CodeVisitor;
54 import org.objectweb.asm.Constants;
55 import org.objectweb.asm.Label;
56
57 /**
58  * Code generates a Reflector
59  *
60  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>
61  * @version $Revision: 1.8 $
62  */

63 public class ReflectorGenerator implements Constants {
64
65     private List JavaDoc methods;
66     private ClassVisitor cw;
67     private CodeVisitor cv;
68     private BytecodeHelper helper = new BytecodeHelper(null);
69     private String JavaDoc classInternalName;
70
71     public ReflectorGenerator(List JavaDoc methods) {
72         this.methods = methods;
73     }
74
75     public void generate(ClassVisitor cw, String JavaDoc className) {
76         this.cw = cw;
77         String JavaDoc fileName = className;
78         int idx = className.lastIndexOf('.');
79         if (idx > 0) {
80             fileName = className.substring(idx + 1);
81         }
82         fileName += ".java";
83
84         classInternalName = BytecodeHelper.getClassInternalName(className);
85         cw.visit(ClassGenerator.asmJDKVersion, ACC_PUBLIC + ACC_SUPER, classInternalName, "org/codehaus/groovy/runtime/Reflector", null, fileName);
86
87         cv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
88         cv.visitVarInsn(ALOAD, 0);
89         cv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/Reflector", "<init>", "()V");
90         cv.visitInsn(RETURN);
91         cv.visitMaxs(1, 1);
92
93         generateInvokeMethod();
94
95         cw.visitEnd();
96     }
97
98     protected void generateInvokeMethod() {
99         int methodCount = methods.size();
100
101         cv =
102             cw.visitMethod(
103                 ACC_PUBLIC,
104                 "invoke",
105                 "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
106                 null,
107                 null);
108         helper = new BytecodeHelper(cv);
109
110         cv.visitVarInsn(ALOAD, 1);
111         cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/MetaMethod", "getMethodIndex", "()I");
112         Label defaultLabel = new Label();
113         Label[] labels = new Label[methodCount];
114         int[] indices = new int[methodCount];
115         for (int i = 0; i < methodCount; i++) {
116             labels[i] = new Label();
117
118             MetaMethod method = (MetaMethod) methods.get(i);
119             method.setMethodIndex(i + 1);
120             indices[i] = method.getMethodIndex();
121
122             //System.out.println("Index: " + method.getMethodIndex() + " for: " + method);
123
}
124
125         cv.visitLookupSwitchInsn(defaultLabel, indices, labels);
126         //cv.visitTableSwitchInsn(minMethodIndex, maxMethodIndex, defaultLabel, labels);
127

128         for (int i = 0; i < methodCount; i++) {
129             cv.visitLabel(labels[i]);
130
131             MetaMethod method = (MetaMethod) methods.get(i);
132             invokeMethod(method);
133             if (method.getReturnType() == void.class) {
134                 cv.visitInsn(ACONST_NULL);
135             }
136             cv.visitInsn(ARETURN);
137         }
138
139         cv.visitLabel(defaultLabel);
140         cv.visitVarInsn(ALOAD, 0);
141         cv.visitVarInsn(ALOAD, 1);
142         cv.visitVarInsn(ALOAD, 2);
143         cv.visitVarInsn(ALOAD, 3);
144         cv.visitMethodInsn(
145             INVOKEVIRTUAL,
146             classInternalName,
147             "noSuchMethod",
148             "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
149         cv.visitInsn(ARETURN);
150         cv.visitMaxs(4, 4);
151     }
152
153     protected void invokeMethod(MetaMethod method) {
154         /** simple
155         cv.visitVarInsn(ALOAD, 2);
156         cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
157         */

158         Class JavaDoc ownerClass = method.getInterfaceClass();
159         boolean useInterface = false;
160         if (ownerClass == null) {
161             ownerClass = method.getDeclaringClass();
162         }
163         else {
164             useInterface = true;
165         }
166         String JavaDoc type = BytecodeHelper.getClassInternalName(ownerClass.getName());
167         String JavaDoc descriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameterTypes());
168
169         // System.out.println("Method: " + method);
170
// System.out.println("Descriptor: " + descriptor);
171

172         if (method.isStatic()) {
173             loadParameters(method, 3);
174             cv.visitMethodInsn(INVOKESTATIC, type, method.getName(), descriptor);
175         }
176         else {
177             cv.visitVarInsn(ALOAD, 2);
178             helper.doCast(ownerClass);
179             loadParameters(method, 3);
180             cv.visitMethodInsn((useInterface) ? INVOKEINTERFACE : INVOKEVIRTUAL, type, method.getName(), descriptor);
181         }
182
183         helper.box(method.getReturnType());
184     }
185
186     /*
187     protected void generateInvokeSuperMethod() {
188         List superMethods = new ArrayList(methods);
189         for (Iterator iter = methods.iterator(); iter.hasNext();) {
190             MetaMethod method = (MetaMethod) iter.next();
191             if (!validSuperMethod(method)) {
192                 superMethods.remove(method);
193             }
194         }
195         int methodCount = superMethods.size();
196         if (methodCount == 0) {
197             return;
198         }
199         cv =
200             cw.visitMethod(
201                 ACC_PUBLIC,
202                 "invokeSuper",
203                 "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
204                 null,
205                 null);
206         helper = new BytecodeHelper(cv);
207
208         cv.visitVarInsn(ALOAD, 1);
209         cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/MetaMethod", "getMethodIndex", "()I");
210         Label defaultLabel = new Label();
211         Label[] labels = new Label[methodCount];
212         int[] indices = new int[methodCount];
213         for (int i = 0; i < methodCount; i++) {
214             labels[i] = new Label();
215
216             MetaMethod method = (MetaMethod) superMethods.get(i);
217             method.setMethodIndex(i + 1);
218             indices[i] = method.getMethodIndex();
219
220             //System.out.println("Index: " + method.getMethodIndex() + " for: " + method);
221         }
222
223         cv.visitLookupSwitchInsn(defaultLabel, indices, labels);
224         //cv.visitTableSwitchInsn(minMethodIndex, maxMethodIndex, defaultLabel, labels);
225
226         for (int i = 0; i < methodCount; i++) {
227             MetaMethod method = (MetaMethod) superMethods.get(i);
228             cv.visitLabel(labels[i]);
229
230             invokeSuperMethod(method);
231             if (method.getReturnType() == void.class) {
232                 cv.visitInsn(ACONST_NULL);
233             }
234             cv.visitInsn(ARETURN);
235         }
236
237         cv.visitLabel(defaultLabel);
238         cv.visitVarInsn(ALOAD, 0);
239         cv.visitVarInsn(ALOAD, 1);
240         cv.visitVarInsn(ALOAD, 2);
241         cv.visitVarInsn(ALOAD, 3);
242         cv.visitMethodInsn(
243             INVOKEVIRTUAL,
244             classInternalName,
245             "noSuchMethod",
246             "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
247         cv.visitInsn(ARETURN);
248         cv.visitMaxs(4, 4);
249     }
250
251     protected boolean validSuperMethod(MetaMethod method) {
252         return !method.isStatic() && (method.getModifiers() & (Modifier.FINAL | Modifier.ABSTRACT)) == 0 && theClass == method.getDeclaringClass();
253     }
254
255     protected void invokeSuperMethod(MetaMethod method) {
256         Class ownerClass = method.getDeclaringClass();
257         String type = helper.getClassInternalName(ownerClass.getName());
258         String descriptor = helper.getMethodDescriptor(method.getReturnType(), method.getParameterTypes());
259
260 // System.out.println("Method: " + method.getName());
261 // System.out.println("Descriptor: " + descriptor);
262
263         cv.visitVarInsn(ALOAD, 2);
264         //helper.doCast(ownerClass);
265         loadParameters(method, 3);
266         cv.visitMethodInsn(INVOKESPECIAL, type, method.getName(), descriptor);
267
268         helper.box(method.getReturnType());
269     }
270 */

271     
272     protected void loadParameters(MetaMethod method, int argumentIndex) {
273         Class JavaDoc[] parameters = method.getParameterTypes();
274         int size = parameters.length;
275         for (int i = 0; i < size; i++) {
276             cv.visitVarInsn(ALOAD, argumentIndex);
277             helper.pushConstant(i);
278             cv.visitInsn(AALOAD);
279
280             // we should cast to something
281
Class JavaDoc type = parameters[i];
282             if (type.isPrimitive()) {
283                 helper.unbox(type);
284             }
285             else {
286                 helper.doCast(type.getName());
287             }
288         }
289     }
290 }
291
Popular Tags