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.MethodVisitor;
54 import org.objectweb.asm.Opcodes;
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.12 $
62 */
63 public class ReflectorGenerator implements Opcodes {
64
65 private List methods;
66 private ClassVisitor cw;
67 private MethodVisitor 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
78 classInternalName = BytecodeHelper.getClassInternalName(className);
79 cw.visit(ClassGenerator.asmJDKVersion, ACC_PUBLIC + ACC_SUPER, classInternalName, (String)null, "org/codehaus/groovy/runtime/Reflector", null);
80
81 cv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
82 cv.visitVarInsn(ALOAD, 0);
83 cv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/Reflector", "<init>", "()V");
84 cv.visitInsn(RETURN);
85 cv.visitMaxs(1, 1);
86
87 generateInvokeMethod();
88
89 cw.visitEnd();
90 }
91
92 protected void generateInvokeMethod() {
93 int methodCount = methods.size();
94
95 cv =
96 cw.visitMethod(
97 ACC_PUBLIC,
98 "invoke",
99 "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
100 null,
101 null);
102 helper = new BytecodeHelper(cv);
103
104 cv.visitVarInsn(ALOAD, 1);
105 cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/MetaMethod", "getMethodIndex", "()I");
106 Label defaultLabel = new Label();
107 Label[] labels = new Label[methodCount];
108 int[] indices = new int[methodCount];
109 for (int i = 0; i < methodCount; i++) {
110 labels[i] = new Label();
111
112 MetaMethod method = (MetaMethod) methods.get(i);
113 method.setMethodIndex(i + 1);
114 indices[i] = method.getMethodIndex();
115
116
117 }
118
119 cv.visitLookupSwitchInsn(defaultLabel, indices, labels);
120
121
122 for (int i = 0; i < methodCount; i++) {
123 cv.visitLabel(labels[i]);
124
125 MetaMethod method = (MetaMethod) methods.get(i);
126 invokeMethod(method);
127 if (method.getReturnType() == void.class) {
128 cv.visitInsn(ACONST_NULL);
129 }
130 cv.visitInsn(ARETURN);
131 }
132
133 cv.visitLabel(defaultLabel);
134 cv.visitVarInsn(ALOAD, 0);
135 cv.visitVarInsn(ALOAD, 1);
136 cv.visitVarInsn(ALOAD, 2);
137 cv.visitVarInsn(ALOAD, 3);
138 cv.visitMethodInsn(
139 INVOKEVIRTUAL,
140 classInternalName,
141 "noSuchMethod",
142 "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
143 cv.visitInsn(ARETURN);
144 cv.visitMaxs(4, 4);
145 }
146
147 protected void invokeMethod(MetaMethod method) {
148 /*** simple
149 cv.visitVarInsn(ALOAD, 2);
150 cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
151 */
152 Class ownerClass = method.getInterfaceClass();
153 boolean useInterface = false;
154 if (ownerClass == null) {
155 ownerClass = method.getDeclaringClass();
156 }
157 else {
158 useInterface = true;
159 }
160 String type = BytecodeHelper.getClassInternalName(ownerClass.getName());
161 String descriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameterTypes());
162
163
164
165
166 if (method.isStatic()) {
167 loadParameters(method, 3);
168 cv.visitMethodInsn(INVOKESTATIC, type, method.getName(), descriptor);
169 }
170 else {
171 cv.visitVarInsn(ALOAD, 2);
172 helper.doCast(ownerClass);
173 loadParameters(method, 3);
174 cv.visitMethodInsn((useInterface) ? INVOKEINTERFACE : INVOKEVIRTUAL, type, method.getName(), descriptor);
175 }
176
177 helper.box(method.getReturnType());
178 }
179
180
181
182
183
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 protected void loadParameters(MetaMethod method, int argumentIndex) {
267 Class[] parameters = method.getParameterTypes();
268 int size = parameters.length;
269 for (int i = 0; i < size; i++) {
270 cv.visitVarInsn(ALOAD, argumentIndex);
271 helper.pushConstant(i);
272 cv.visitInsn(AALOAD);
273
274
275 Class type = parameters[i];
276 if (type.isPrimitive()) {
277 helper.unbox(type);
278 }
279 else {
280 helper.doCast(type);
281 }
282 }
283 }
284 }