|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
ReflectorGenerator.java | 0% | 0% | 0% | 0% |
|
1 |
/*
|
|
2 |
$Id: ReflectorGenerator.java,v 1.7 2004/03/14 22:20:46 jstrachan 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;
|
|
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.7 $
|
|
62 |
*/
|
|
63 |
public class ReflectorGenerator implements Constants { |
|
64 |
|
|
65 |
private List methods;
|
|
66 |
private ClassVisitor cw;
|
|
67 |
private CodeVisitor cv;
|
|
68 |
private BytecodeHelper helper = new BytecodeHelper(null); |
|
69 |
private String classInternalName;
|
|
70 |
|
|
71 | 0 |
public ReflectorGenerator(List methods) {
|
72 | 0 |
this.methods = methods;
|
73 |
} |
|
74 |
|
|
75 | 0 |
public void generate(ClassVisitor cw, String className) { |
76 | 0 |
this.cw = cw;
|
77 | 0 |
String fileName = className; |
78 | 0 |
int idx = className.lastIndexOf('.');
|
79 | 0 |
if (idx > 0) {
|
80 | 0 |
fileName = className.substring(idx + 1); |
81 |
} |
|
82 | 0 |
fileName += ".java";
|
83 |
|
|
84 | 0 |
classInternalName = BytecodeHelper.getClassInternalName(className); |
85 | 0 |
cw.visit(ACC_PUBLIC + ACC_SUPER, classInternalName, "org/codehaus/groovy/runtime/Reflector", null, fileName); |
86 |
|
|
87 | 0 |
cv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); |
88 | 0 |
cv.visitVarInsn(ALOAD, 0); |
89 | 0 |
cv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/Reflector", "<init>", "()V"); |
90 | 0 |
cv.visitInsn(RETURN); |
91 | 0 |
cv.visitMaxs(1, 1); |
92 |
|
|
93 | 0 |
generateInvokeMethod(); |
94 |
|
|
95 | 0 |
cw.visitEnd(); |
96 |
} |
|
97 |
|
|
98 | 0 |
protected void generateInvokeMethod() { |
99 | 0 |
int methodCount = methods.size();
|
100 |
|
|
101 | 0 |
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 | 0 |
helper = new BytecodeHelper(cv);
|
109 |
|
|
110 | 0 |
cv.visitVarInsn(ALOAD, 1); |
111 | 0 |
cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/MetaMethod", "getMethodIndex", "()I"); |
112 | 0 |
Label defaultLabel = new Label();
|
113 | 0 |
Label[] labels = new Label[methodCount];
|
114 | 0 |
int[] indices = new int[methodCount]; |
115 | 0 |
for (int i = 0; i < methodCount; i++) { |
116 | 0 |
labels[i] = new Label();
|
117 |
|
|
118 | 0 |
MetaMethod method = (MetaMethod) methods.get(i); |
119 | 0 |
method.setMethodIndex(i + 1); |
120 | 0 |
indices[i] = method.getMethodIndex(); |
121 |
|
|
122 |
//System.out.println("Index: " + method.getMethodIndex() + " for: " + method);
|
|
123 |
} |
|
124 |
|
|
125 | 0 |
cv.visitLookupSwitchInsn(defaultLabel, indices, labels); |
126 |
//cv.visitTableSwitchInsn(minMethodIndex, maxMethodIndex, defaultLabel, labels);
|
|
127 |
|
|
128 | 0 |
for (int i = 0; i < methodCount; i++) { |
129 | 0 |
cv.visitLabel(labels[i]); |
130 |
|
|
131 | 0 |
MetaMethod method = (MetaMethod) methods.get(i); |
132 | 0 |
invokeMethod(method); |
133 | 0 |
if (method.getReturnType() == void.class) { |
134 | 0 |
cv.visitInsn(ACONST_NULL); |
135 |
} |
|
136 | 0 |
cv.visitInsn(ARETURN); |
137 |
} |
|
138 |
|
|
139 | 0 |
cv.visitLabel(defaultLabel); |
140 | 0 |
cv.visitVarInsn(ALOAD, 0); |
141 | 0 |
cv.visitVarInsn(ALOAD, 1); |
142 | 0 |
cv.visitVarInsn(ALOAD, 2); |
143 | 0 |
cv.visitVarInsn(ALOAD, 3); |
144 | 0 |
cv.visitMethodInsn( |
145 |
INVOKEVIRTUAL, |
|
146 |
classInternalName, |
|
147 |
"noSuchMethod",
|
|
148 |
"(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
|
|
149 | 0 |
cv.visitInsn(ARETURN); |
150 | 0 |
cv.visitMaxs(4, 4); |
151 |
} |
|
152 |
|
|
153 | 0 |
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 | 0 |
Class ownerClass = method.getInterfaceClass(); |
159 | 0 |
boolean useInterface = false; |
160 | 0 |
if (ownerClass == null) { |
161 | 0 |
ownerClass = method.getDeclaringClass(); |
162 |
} |
|
163 |
else {
|
|
164 | 0 |
useInterface = true;
|
165 |
} |
|
166 | 0 |
String type = BytecodeHelper.getClassInternalName(ownerClass.getName()); |
167 | 0 |
String descriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameterTypes()); |
168 |
|
|
169 |
// System.out.println("Method: " + method);
|
|
170 |
// System.out.println("Descriptor: " + descriptor);
|
|
171 |
|
|
172 | 0 |
if (method.isStatic()) {
|
173 | 0 |
loadParameters(method, 3); |
174 | 0 |
cv.visitMethodInsn(INVOKESTATIC, type, method.getName(), descriptor); |
175 |
} |
|
176 |
else {
|
|
177 | 0 |
cv.visitVarInsn(ALOAD, 2); |
178 | 0 |
helper.doCast(ownerClass); |
179 | 0 |
loadParameters(method, 3); |
180 | 0 |
cv.visitMethodInsn((useInterface) ? INVOKEINTERFACE : INVOKEVIRTUAL, type, method.getName(), descriptor); |
181 |
} |
|
182 |
|
|
183 | 0 |
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 | 0 |
protected void loadParameters(MetaMethod method, int argumentIndex) { |
273 | 0 |
Class[] parameters = method.getParameterTypes(); |
274 | 0 |
int size = parameters.length;
|
275 | 0 |
for (int i = 0; i < size; i++) { |
276 | 0 |
cv.visitVarInsn(ALOAD, argumentIndex); |
277 | 0 |
helper.pushConstant(i); |
278 | 0 |
cv.visitInsn(AALOAD); |
279 |
|
|
280 |
// we should cast to something
|
|
281 | 0 |
Class type = parameters[i]; |
282 | 0 |
if (type.isPrimitive()) {
|
283 | 0 |
helper.unbox(type); |
284 |
} |
|
285 |
else {
|
|
286 | 0 |
helper.doCast(type.getName()); |
287 |
} |
|
288 |
} |
|
289 |
} |
|
290 |
} |
|
291 |
|
|