1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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.8 $
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 public ReflectorGenerator(List methods) {
72 this.methods = methods;
73 }
74
75 public void generate(ClassVisitor cw, String className) {
76 this.cw = cw;
77 String 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
123 }
124
125 cv.visitLookupSwitchInsn(defaultLabel, indices, labels);
126
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 ownerClass = method.getInterfaceClass();
159 boolean useInterface = false;
160 if (ownerClass == null) {
161 ownerClass = method.getDeclaringClass();
162 }
163 else {
164 useInterface = true;
165 }
166 String type = BytecodeHelper.getClassInternalName(ownerClass.getName());
167 String descriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameterTypes());
168
169
170
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 protected void loadParameters(MetaMethod method, int argumentIndex) {
273 Class[] 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
281 Class type = parameters[i];
282 if (type.isPrimitive()) {
283 helper.unbox(type);
284 }
285 else {
286 helper.doCast(type.getName());
287 }
288 }
289 }
290 }