1 /* |
|
2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package sun.reflect; |
|
27 |
|
28 import java.security.AccessController; |
|
29 import java.security.PrivilegedAction; |
|
30 |
|
31 /** Generator for sun.reflect.MethodAccessor and |
|
32 sun.reflect.ConstructorAccessor objects using bytecodes to |
|
33 implement reflection. A java.lang.reflect.Method or |
|
34 java.lang.reflect.Constructor object can delegate its invoke or |
|
35 newInstance method to an accessor using native code or to one |
|
36 generated by this class. (Methods and Constructors were merged |
|
37 together in this class to ensure maximum code sharing.) */ |
|
38 |
|
39 class MethodAccessorGenerator extends AccessorGenerator { |
|
40 |
|
41 private static final short NUM_BASE_CPOOL_ENTRIES = (short) 12; |
|
42 // One for invoke() plus one for constructor |
|
43 private static final short NUM_METHODS = (short) 2; |
|
44 // Only used if forSerialization is true |
|
45 private static final short NUM_SERIALIZATION_CPOOL_ENTRIES = (short) 2; |
|
46 |
|
47 private static volatile int methodSymnum; |
|
48 private static volatile int constructorSymnum; |
|
49 private static volatile int serializationConstructorSymnum; |
|
50 |
|
51 private Class<?> declaringClass; |
|
52 private Class<?>[] parameterTypes; |
|
53 private Class<?> returnType; |
|
54 private boolean isConstructor; |
|
55 private boolean forSerialization; |
|
56 |
|
57 private short targetMethodRef; |
|
58 private short invokeIdx; |
|
59 private short invokeDescriptorIdx; |
|
60 // Constant pool index of CONSTANT_Class_info for first |
|
61 // non-primitive parameter type. Should be incremented by 2. |
|
62 private short nonPrimitiveParametersBaseIdx; |
|
63 |
|
64 MethodAccessorGenerator() { |
|
65 } |
|
66 |
|
67 /** This routine is not thread-safe */ |
|
68 public MethodAccessor generateMethod(Class<?> declaringClass, |
|
69 String name, |
|
70 Class<?>[] parameterTypes, |
|
71 Class<?> returnType, |
|
72 Class<?>[] checkedExceptions, |
|
73 int modifiers) |
|
74 { |
|
75 return (MethodAccessor) generate(declaringClass, |
|
76 name, |
|
77 parameterTypes, |
|
78 returnType, |
|
79 checkedExceptions, |
|
80 modifiers, |
|
81 false, |
|
82 false, |
|
83 null); |
|
84 } |
|
85 |
|
86 /** This routine is not thread-safe */ |
|
87 public ConstructorAccessor generateConstructor(Class<?> declaringClass, |
|
88 Class<?>[] parameterTypes, |
|
89 Class<?>[] checkedExceptions, |
|
90 int modifiers) |
|
91 { |
|
92 return (ConstructorAccessor) generate(declaringClass, |
|
93 "<init>", |
|
94 parameterTypes, |
|
95 Void.TYPE, |
|
96 checkedExceptions, |
|
97 modifiers, |
|
98 true, |
|
99 false, |
|
100 null); |
|
101 } |
|
102 |
|
103 /** This routine is not thread-safe */ |
|
104 public SerializationConstructorAccessorImpl |
|
105 generateSerializationConstructor(Class<?> declaringClass, |
|
106 Class<?>[] parameterTypes, |
|
107 Class<?>[] checkedExceptions, |
|
108 int modifiers, |
|
109 Class<?> targetConstructorClass) |
|
110 { |
|
111 return (SerializationConstructorAccessorImpl) |
|
112 generate(declaringClass, |
|
113 "<init>", |
|
114 parameterTypes, |
|
115 Void.TYPE, |
|
116 checkedExceptions, |
|
117 modifiers, |
|
118 true, |
|
119 true, |
|
120 targetConstructorClass); |
|
121 } |
|
122 |
|
123 /** This routine is not thread-safe */ |
|
124 private MagicAccessorImpl generate(final Class<?> declaringClass, |
|
125 String name, |
|
126 Class<?>[] parameterTypes, |
|
127 Class<?> returnType, |
|
128 Class<?>[] checkedExceptions, |
|
129 int modifiers, |
|
130 boolean isConstructor, |
|
131 boolean forSerialization, |
|
132 Class<?> serializationTargetClass) |
|
133 { |
|
134 ByteVector vec = ByteVectorFactory.create(); |
|
135 asm = new ClassFileAssembler(vec); |
|
136 this.declaringClass = declaringClass; |
|
137 this.parameterTypes = parameterTypes; |
|
138 this.returnType = returnType; |
|
139 this.modifiers = modifiers; |
|
140 this.isConstructor = isConstructor; |
|
141 this.forSerialization = forSerialization; |
|
142 |
|
143 asm.emitMagicAndVersion(); |
|
144 |
|
145 // Constant pool entries: |
|
146 // ( * = Boxing information: optional) |
|
147 // (+ = Shared entries provided by AccessorGenerator) |
|
148 // (^ = Only present if generating SerializationConstructorAccessor) |
|
149 // [UTF-8] [This class's name] |
|
150 // [CONSTANT_Class_info] for above |
|
151 // [UTF-8] "sun/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" |
|
152 // [CONSTANT_Class_info] for above |
|
153 // [UTF-8] [Target class's name] |
|
154 // [CONSTANT_Class_info] for above |
|
155 // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] |
|
156 // ^ [CONSTANT_Class_info] for above |
|
157 // [UTF-8] target method or constructor name |
|
158 // [UTF-8] target method or constructor signature |
|
159 // [CONSTANT_NameAndType_info] for above |
|
160 // [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method |
|
161 // [UTF-8] "invoke" or "newInstance" |
|
162 // [UTF-8] invoke or newInstance descriptor |
|
163 // [UTF-8] descriptor for type of non-primitive parameter 1 |
|
164 // [CONSTANT_Class_info] for type of non-primitive parameter 1 |
|
165 // ... |
|
166 // [UTF-8] descriptor for type of non-primitive parameter n |
|
167 // [CONSTANT_Class_info] for type of non-primitive parameter n |
|
168 // + [UTF-8] "java/lang/Exception" |
|
169 // + [CONSTANT_Class_info] for above |
|
170 // + [UTF-8] "java/lang/ClassCastException" |
|
171 // + [CONSTANT_Class_info] for above |
|
172 // + [UTF-8] "java/lang/NullPointerException" |
|
173 // + [CONSTANT_Class_info] for above |
|
174 // + [UTF-8] "java/lang/IllegalArgumentException" |
|
175 // + [CONSTANT_Class_info] for above |
|
176 // + [UTF-8] "java/lang/InvocationTargetException" |
|
177 // + [CONSTANT_Class_info] for above |
|
178 // + [UTF-8] "<init>" |
|
179 // + [UTF-8] "()V" |
|
180 // + [CONSTANT_NameAndType_info] for above |
|
181 // + [CONSTANT_Methodref_info] for NullPointerException's constructor |
|
182 // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor |
|
183 // + [UTF-8] "(Ljava/lang/String;)V" |
|
184 // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V" |
|
185 // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String |
|
186 // + [UTF-8] "(Ljava/lang/Throwable;)V" |
|
187 // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V" |
|
188 // + [CONSTANT_Methodref_info] for InvocationTargetException's constructor |
|
189 // + [CONSTANT_Methodref_info] for "super()" |
|
190 // + [UTF-8] "java/lang/Object" |
|
191 // + [CONSTANT_Class_info] for above |
|
192 // + [UTF-8] "toString" |
|
193 // + [UTF-8] "()Ljava/lang/String;" |
|
194 // + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;" |
|
195 // + [CONSTANT_Methodref_info] for Object's toString method |
|
196 // + [UTF-8] "Code" |
|
197 // + [UTF-8] "Exceptions" |
|
198 // * [UTF-8] "java/lang/Boolean" |
|
199 // * [CONSTANT_Class_info] for above |
|
200 // * [UTF-8] "(Z)V" |
|
201 // * [CONSTANT_NameAndType_info] for above |
|
202 // * [CONSTANT_Methodref_info] for above |
|
203 // * [UTF-8] "booleanValue" |
|
204 // * [UTF-8] "()Z" |
|
205 // * [CONSTANT_NameAndType_info] for above |
|
206 // * [CONSTANT_Methodref_info] for above |
|
207 // * [UTF-8] "java/lang/Byte" |
|
208 // * [CONSTANT_Class_info] for above |
|
209 // * [UTF-8] "(B)V" |
|
210 // * [CONSTANT_NameAndType_info] for above |
|
211 // * [CONSTANT_Methodref_info] for above |
|
212 // * [UTF-8] "byteValue" |
|
213 // * [UTF-8] "()B" |
|
214 // * [CONSTANT_NameAndType_info] for above |
|
215 // * [CONSTANT_Methodref_info] for above |
|
216 // * [UTF-8] "java/lang/Character" |
|
217 // * [CONSTANT_Class_info] for above |
|
218 // * [UTF-8] "(C)V" |
|
219 // * [CONSTANT_NameAndType_info] for above |
|
220 // * [CONSTANT_Methodref_info] for above |
|
221 // * [UTF-8] "charValue" |
|
222 // * [UTF-8] "()C" |
|
223 // * [CONSTANT_NameAndType_info] for above |
|
224 // * [CONSTANT_Methodref_info] for above |
|
225 // * [UTF-8] "java/lang/Double" |
|
226 // * [CONSTANT_Class_info] for above |
|
227 // * [UTF-8] "(D)V" |
|
228 // * [CONSTANT_NameAndType_info] for above |
|
229 // * [CONSTANT_Methodref_info] for above |
|
230 // * [UTF-8] "doubleValue" |
|
231 // * [UTF-8] "()D" |
|
232 // * [CONSTANT_NameAndType_info] for above |
|
233 // * [CONSTANT_Methodref_info] for above |
|
234 // * [UTF-8] "java/lang/Float" |
|
235 // * [CONSTANT_Class_info] for above |
|
236 // * [UTF-8] "(F)V" |
|
237 // * [CONSTANT_NameAndType_info] for above |
|
238 // * [CONSTANT_Methodref_info] for above |
|
239 // * [UTF-8] "floatValue" |
|
240 // * [UTF-8] "()F" |
|
241 // * [CONSTANT_NameAndType_info] for above |
|
242 // * [CONSTANT_Methodref_info] for above |
|
243 // * [UTF-8] "java/lang/Integer" |
|
244 // * [CONSTANT_Class_info] for above |
|
245 // * [UTF-8] "(I)V" |
|
246 // * [CONSTANT_NameAndType_info] for above |
|
247 // * [CONSTANT_Methodref_info] for above |
|
248 // * [UTF-8] "intValue" |
|
249 // * [UTF-8] "()I" |
|
250 // * [CONSTANT_NameAndType_info] for above |
|
251 // * [CONSTANT_Methodref_info] for above |
|
252 // * [UTF-8] "java/lang/Long" |
|
253 // * [CONSTANT_Class_info] for above |
|
254 // * [UTF-8] "(J)V" |
|
255 // * [CONSTANT_NameAndType_info] for above |
|
256 // * [CONSTANT_Methodref_info] for above |
|
257 // * [UTF-8] "longValue" |
|
258 // * [UTF-8] "()J" |
|
259 // * [CONSTANT_NameAndType_info] for above |
|
260 // * [CONSTANT_Methodref_info] for above |
|
261 // * [UTF-8] "java/lang/Short" |
|
262 // * [CONSTANT_Class_info] for above |
|
263 // * [UTF-8] "(S)V" |
|
264 // * [CONSTANT_NameAndType_info] for above |
|
265 // * [CONSTANT_Methodref_info] for above |
|
266 // * [UTF-8] "shortValue" |
|
267 // * [UTF-8] "()S" |
|
268 // * [CONSTANT_NameAndType_info] for above |
|
269 // * [CONSTANT_Methodref_info] for above |
|
270 |
|
271 short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES; |
|
272 boolean usesPrimitives = usesPrimitiveTypes(); |
|
273 if (usesPrimitives) { |
|
274 numCPEntries += NUM_BOXING_CPOOL_ENTRIES; |
|
275 } |
|
276 if (forSerialization) { |
|
277 numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES; |
|
278 } |
|
279 |
|
280 // Add in variable-length number of entries to be able to describe |
|
281 // non-primitive parameter types and checked exceptions. |
|
282 numCPEntries += (short) (2 * numNonPrimitiveParameterTypes()); |
|
283 |
|
284 asm.emitShort(add(numCPEntries, S1)); |
|
285 |
|
286 final String generatedName = generateName(isConstructor, forSerialization); |
|
287 asm.emitConstantPoolUTF8(generatedName); |
|
288 asm.emitConstantPoolClass(asm.cpi()); |
|
289 thisClass = asm.cpi(); |
|
290 if (isConstructor) { |
|
291 if (forSerialization) { |
|
292 asm.emitConstantPoolUTF8 |
|
293 ("sun/reflect/SerializationConstructorAccessorImpl"); |
|
294 } else { |
|
295 asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl"); |
|
296 } |
|
297 } else { |
|
298 asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl"); |
|
299 } |
|
300 asm.emitConstantPoolClass(asm.cpi()); |
|
301 superClass = asm.cpi(); |
|
302 asm.emitConstantPoolUTF8(getClassName(declaringClass, false)); |
|
303 asm.emitConstantPoolClass(asm.cpi()); |
|
304 targetClass = asm.cpi(); |
|
305 short serializationTargetClassIdx = (short) 0; |
|
306 if (forSerialization) { |
|
307 asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false)); |
|
308 asm.emitConstantPoolClass(asm.cpi()); |
|
309 serializationTargetClassIdx = asm.cpi(); |
|
310 } |
|
311 asm.emitConstantPoolUTF8(name); |
|
312 asm.emitConstantPoolUTF8(buildInternalSignature()); |
|
313 asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); |
|
314 if (isInterface()) { |
|
315 asm.emitConstantPoolInterfaceMethodref(targetClass, asm.cpi()); |
|
316 } else { |
|
317 if (forSerialization) { |
|
318 asm.emitConstantPoolMethodref(serializationTargetClassIdx, asm.cpi()); |
|
319 } else { |
|
320 asm.emitConstantPoolMethodref(targetClass, asm.cpi()); |
|
321 } |
|
322 } |
|
323 targetMethodRef = asm.cpi(); |
|
324 if (isConstructor) { |
|
325 asm.emitConstantPoolUTF8("newInstance"); |
|
326 } else { |
|
327 asm.emitConstantPoolUTF8("invoke"); |
|
328 } |
|
329 invokeIdx = asm.cpi(); |
|
330 if (isConstructor) { |
|
331 asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;"); |
|
332 } else { |
|
333 asm.emitConstantPoolUTF8 |
|
334 ("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); |
|
335 } |
|
336 invokeDescriptorIdx = asm.cpi(); |
|
337 |
|
338 // Output class information for non-primitive parameter types |
|
339 nonPrimitiveParametersBaseIdx = add(asm.cpi(), S2); |
|
340 for (int i = 0; i < parameterTypes.length; i++) { |
|
341 Class<?> c = parameterTypes[i]; |
|
342 if (!isPrimitive(c)) { |
|
343 asm.emitConstantPoolUTF8(getClassName(c, false)); |
|
344 asm.emitConstantPoolClass(asm.cpi()); |
|
345 } |
|
346 } |
|
347 |
|
348 // Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor |
|
349 emitCommonConstantPoolEntries(); |
|
350 |
|
351 // Boxing entries |
|
352 if (usesPrimitives) { |
|
353 emitBoxingContantPoolEntries(); |
|
354 } |
|
355 |
|
356 if (asm.cpi() != numCPEntries) { |
|
357 throw new InternalError("Adjust this code (cpi = " + asm.cpi() + |
|
358 ", numCPEntries = " + numCPEntries + ")"); |
|
359 } |
|
360 |
|
361 // Access flags |
|
362 asm.emitShort(ACC_PUBLIC); |
|
363 |
|
364 // This class |
|
365 asm.emitShort(thisClass); |
|
366 |
|
367 // Superclass |
|
368 asm.emitShort(superClass); |
|
369 |
|
370 // Interfaces count and interfaces |
|
371 asm.emitShort(S0); |
|
372 |
|
373 // Fields count and fields |
|
374 asm.emitShort(S0); |
|
375 |
|
376 // Methods count and methods |
|
377 asm.emitShort(NUM_METHODS); |
|
378 |
|
379 emitConstructor(); |
|
380 emitInvoke(); |
|
381 |
|
382 // Additional attributes (none) |
|
383 asm.emitShort(S0); |
|
384 |
|
385 // Load class |
|
386 vec.trim(); |
|
387 final byte[] bytes = vec.getData(); |
|
388 // Note: the class loader is the only thing that really matters |
|
389 // here -- it's important to get the generated code into the |
|
390 // same namespace as the target class. Since the generated code |
|
391 // is privileged anyway, the protection domain probably doesn't |
|
392 // matter. |
|
393 return AccessController.doPrivileged( |
|
394 new PrivilegedAction<MagicAccessorImpl>() { |
|
395 public MagicAccessorImpl run() { |
|
396 try { |
|
397 return (MagicAccessorImpl) |
|
398 ClassDefiner.defineClass |
|
399 (generatedName, |
|
400 bytes, |
|
401 0, |
|
402 bytes.length, |
|
403 declaringClass.getClassLoader()).newInstance(); |
|
404 } catch (InstantiationException | IllegalAccessException e) { |
|
405 throw new InternalError(e); |
|
406 } |
|
407 } |
|
408 }); |
|
409 } |
|
410 |
|
411 /** This emits the code for either invoke() or newInstance() */ |
|
412 private void emitInvoke() { |
|
413 // NOTE that this code will only handle 65535 parameters since we |
|
414 // use the sipush instruction to get the array index on the |
|
415 // operand stack. |
|
416 if (parameterTypes.length > 65535) { |
|
417 throw new InternalError("Can't handle more than 65535 parameters"); |
|
418 } |
|
419 |
|
420 // Generate code into fresh code buffer |
|
421 ClassFileAssembler cb = new ClassFileAssembler(); |
|
422 if (isConstructor) { |
|
423 // 1 incoming argument |
|
424 cb.setMaxLocals(2); |
|
425 } else { |
|
426 // 2 incoming arguments |
|
427 cb.setMaxLocals(3); |
|
428 } |
|
429 |
|
430 short illegalArgStartPC = 0; |
|
431 |
|
432 if (isConstructor) { |
|
433 // Instantiate target class before continuing |
|
434 // new <target class type> |
|
435 // dup |
|
436 cb.opc_new(targetClass); |
|
437 cb.opc_dup(); |
|
438 } else { |
|
439 // Setup before iterating down argument list |
|
440 if (isPrimitive(returnType)) { |
|
441 // new <boxing type for primitive type> |
|
442 // dup |
|
443 // ... (see below:) |
|
444 // invokespecial <constructor for boxing type for primitive type> |
|
445 // areturn |
|
446 cb.opc_new(indexForPrimitiveType(returnType)); |
|
447 cb.opc_dup(); |
|
448 } |
|
449 |
|
450 // Get target object on operand stack if necessary. |
|
451 |
|
452 // We need to do an explicit null check here; we won't see |
|
453 // NullPointerExceptions from the invoke bytecode, since it's |
|
454 // covered by an exception handler. |
|
455 if (!isStatic()) { |
|
456 // aload_1 |
|
457 // ifnonnull <checkcast label> |
|
458 // new <NullPointerException> |
|
459 // dup |
|
460 // invokespecial <NullPointerException ctor> |
|
461 // athrow |
|
462 // <checkcast label:> |
|
463 // aload_1 |
|
464 // checkcast <target class's type> |
|
465 cb.opc_aload_1(); |
|
466 Label l = new Label(); |
|
467 cb.opc_ifnonnull(l); |
|
468 cb.opc_new(nullPointerClass); |
|
469 cb.opc_dup(); |
|
470 cb.opc_invokespecial(nullPointerCtorIdx, 0, 0); |
|
471 cb.opc_athrow(); |
|
472 l.bind(); |
|
473 illegalArgStartPC = cb.getLength(); |
|
474 cb.opc_aload_1(); |
|
475 cb.opc_checkcast(targetClass); |
|
476 } |
|
477 } |
|
478 |
|
479 // Have to check length of incoming array and throw |
|
480 // IllegalArgumentException if not correct. A concession to the |
|
481 // JCK (isn't clearly specified in the spec): we allow null in the |
|
482 // case where the argument list is zero length. |
|
483 // if no-arg: |
|
484 // aload_2 | aload_1 (Method | Constructor) |
|
485 // ifnull <success label> |
|
486 // aload_2 | aload_1 |
|
487 // arraylength |
|
488 // sipush <num parameter types> |
|
489 // if_icmpeq <success label> |
|
490 // new <IllegalArgumentException> |
|
491 // dup |
|
492 // invokespecial <IllegalArgumentException ctor> |
|
493 // athrow |
|
494 // <success label:> |
|
495 Label successLabel = new Label(); |
|
496 if (parameterTypes.length == 0) { |
|
497 if (isConstructor) { |
|
498 cb.opc_aload_1(); |
|
499 } else { |
|
500 cb.opc_aload_2(); |
|
501 } |
|
502 cb.opc_ifnull(successLabel); |
|
503 } |
|
504 if (isConstructor) { |
|
505 cb.opc_aload_1(); |
|
506 } else { |
|
507 cb.opc_aload_2(); |
|
508 } |
|
509 cb.opc_arraylength(); |
|
510 cb.opc_sipush((short) parameterTypes.length); |
|
511 cb.opc_if_icmpeq(successLabel); |
|
512 cb.opc_new(illegalArgumentClass); |
|
513 cb.opc_dup(); |
|
514 cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); |
|
515 cb.opc_athrow(); |
|
516 successLabel.bind(); |
|
517 |
|
518 // Iterate through incoming actual parameters, ensuring that each |
|
519 // is compatible with the formal parameter type, and pushing the |
|
520 // actual on the operand stack (unboxing and widening if necessary). |
|
521 |
|
522 short paramTypeCPIdx = nonPrimitiveParametersBaseIdx; |
|
523 Label nextParamLabel = null; |
|
524 byte count = 1; // both invokeinterface opcode's "count" as well as |
|
525 // num args of other invoke bytecodes |
|
526 for (int i = 0; i < parameterTypes.length; i++) { |
|
527 Class<?> paramType = parameterTypes[i]; |
|
528 count += (byte) typeSizeInStackSlots(paramType); |
|
529 if (nextParamLabel != null) { |
|
530 nextParamLabel.bind(); |
|
531 nextParamLabel = null; |
|
532 } |
|
533 // aload_2 | aload_1 |
|
534 // sipush <index> |
|
535 // aaload |
|
536 if (isConstructor) { |
|
537 cb.opc_aload_1(); |
|
538 } else { |
|
539 cb.opc_aload_2(); |
|
540 } |
|
541 cb.opc_sipush((short) i); |
|
542 cb.opc_aaload(); |
|
543 if (isPrimitive(paramType)) { |
|
544 // Unboxing code. |
|
545 // Put parameter into temporary local variable |
|
546 // astore_3 | astore_2 |
|
547 if (isConstructor) { |
|
548 cb.opc_astore_2(); |
|
549 } else { |
|
550 cb.opc_astore_3(); |
|
551 } |
|
552 |
|
553 // repeat for all possible widening conversions: |
|
554 // aload_3 | aload_2 |
|
555 // instanceof <primitive boxing type> |
|
556 // ifeq <next unboxing label> |
|
557 // aload_3 | aload_2 |
|
558 // checkcast <primitive boxing type> // Note: this is "redundant", |
|
559 // // but necessary for the verifier |
|
560 // invokevirtual <unboxing method> |
|
561 // <widening conversion bytecode, if necessary> |
|
562 // goto <next parameter label> |
|
563 // <next unboxing label:> ... |
|
564 // last unboxing label: |
|
565 // new <IllegalArgumentException> |
|
566 // dup |
|
567 // invokespecial <IllegalArgumentException ctor> |
|
568 // athrow |
|
569 |
|
570 Label l = null; // unboxing label |
|
571 nextParamLabel = new Label(); |
|
572 |
|
573 for (int j = 0; j < primitiveTypes.length; j++) { |
|
574 Class<?> c = primitiveTypes[j]; |
|
575 if (canWidenTo(c, paramType)) { |
|
576 if (l != null) { |
|
577 l.bind(); |
|
578 } |
|
579 // Emit checking and unboxing code for this type |
|
580 if (isConstructor) { |
|
581 cb.opc_aload_2(); |
|
582 } else { |
|
583 cb.opc_aload_3(); |
|
584 } |
|
585 cb.opc_instanceof(indexForPrimitiveType(c)); |
|
586 l = new Label(); |
|
587 cb.opc_ifeq(l); |
|
588 if (isConstructor) { |
|
589 cb.opc_aload_2(); |
|
590 } else { |
|
591 cb.opc_aload_3(); |
|
592 } |
|
593 cb.opc_checkcast(indexForPrimitiveType(c)); |
|
594 cb.opc_invokevirtual(unboxingMethodForPrimitiveType(c), |
|
595 0, |
|
596 typeSizeInStackSlots(c)); |
|
597 emitWideningBytecodeForPrimitiveConversion(cb, |
|
598 c, |
|
599 paramType); |
|
600 cb.opc_goto(nextParamLabel); |
|
601 } |
|
602 } |
|
603 |
|
604 if (l == null) { |
|
605 throw new InternalError |
|
606 ("Must have found at least identity conversion"); |
|
607 } |
|
608 |
|
609 // Fell through; given object is null or invalid. According to |
|
610 // the spec, we can throw IllegalArgumentException for both of |
|
611 // these cases. |
|
612 |
|
613 l.bind(); |
|
614 cb.opc_new(illegalArgumentClass); |
|
615 cb.opc_dup(); |
|
616 cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); |
|
617 cb.opc_athrow(); |
|
618 } else { |
|
619 // Emit appropriate checkcast |
|
620 cb.opc_checkcast(paramTypeCPIdx); |
|
621 paramTypeCPIdx = add(paramTypeCPIdx, S2); |
|
622 // Fall through to next argument |
|
623 } |
|
624 } |
|
625 // Bind last goto if present |
|
626 if (nextParamLabel != null) { |
|
627 nextParamLabel.bind(); |
|
628 } |
|
629 |
|
630 short invokeStartPC = cb.getLength(); |
|
631 |
|
632 // OK, ready to perform the invocation. |
|
633 if (isConstructor) { |
|
634 cb.opc_invokespecial(targetMethodRef, count, 0); |
|
635 } else { |
|
636 if (isStatic()) { |
|
637 cb.opc_invokestatic(targetMethodRef, |
|
638 count, |
|
639 typeSizeInStackSlots(returnType)); |
|
640 } else { |
|
641 if (isInterface()) { |
|
642 if (isPrivate()) { |
|
643 cb.opc_invokespecial(targetMethodRef, count, 0); |
|
644 } else { |
|
645 cb.opc_invokeinterface(targetMethodRef, |
|
646 count, |
|
647 count, |
|
648 typeSizeInStackSlots(returnType)); |
|
649 } |
|
650 } else { |
|
651 cb.opc_invokevirtual(targetMethodRef, |
|
652 count, |
|
653 typeSizeInStackSlots(returnType)); |
|
654 } |
|
655 } |
|
656 } |
|
657 |
|
658 short invokeEndPC = cb.getLength(); |
|
659 |
|
660 if (!isConstructor) { |
|
661 // Box return value if necessary |
|
662 if (isPrimitive(returnType)) { |
|
663 cb.opc_invokestatic(boxingMethodForPrimitiveType(returnType), |
|
664 typeSizeInStackSlots(returnType), |
|
665 0); |
|
666 } else if (returnType == Void.TYPE) { |
|
667 cb.opc_aconst_null(); |
|
668 } |
|
669 } |
|
670 cb.opc_areturn(); |
|
671 |
|
672 // We generate two exception handlers; one which is responsible |
|
673 // for catching ClassCastException and NullPointerException and |
|
674 // throwing IllegalArgumentException, and the other which catches |
|
675 // all java/lang/Throwable objects thrown from the target method |
|
676 // and wraps them in InvocationTargetExceptions. |
|
677 |
|
678 short classCastHandler = cb.getLength(); |
|
679 |
|
680 // ClassCast, etc. exception handler |
|
681 cb.setStack(1); |
|
682 cb.opc_invokespecial(toStringIdx, 0, 1); |
|
683 cb.opc_new(illegalArgumentClass); |
|
684 cb.opc_dup_x1(); |
|
685 cb.opc_swap(); |
|
686 cb.opc_invokespecial(illegalArgumentStringCtorIdx, 1, 0); |
|
687 cb.opc_athrow(); |
|
688 |
|
689 short invocationTargetHandler = cb.getLength(); |
|
690 |
|
691 // InvocationTargetException exception handler |
|
692 cb.setStack(1); |
|
693 cb.opc_new(invocationTargetClass); |
|
694 cb.opc_dup_x1(); |
|
695 cb.opc_swap(); |
|
696 cb.opc_invokespecial(invocationTargetCtorIdx, 1, 0); |
|
697 cb.opc_athrow(); |
|
698 |
|
699 // Generate exception table. We cover the entire code sequence |
|
700 // with an exception handler which catches ClassCastException and |
|
701 // converts it into an IllegalArgumentException. |
|
702 |
|
703 ClassFileAssembler exc = new ClassFileAssembler(); |
|
704 |
|
705 exc.emitShort(illegalArgStartPC); // start PC |
|
706 exc.emitShort(invokeStartPC); // end PC |
|
707 exc.emitShort(classCastHandler); // handler PC |
|
708 exc.emitShort(classCastClass); // catch type |
|
709 |
|
710 exc.emitShort(illegalArgStartPC); // start PC |
|
711 exc.emitShort(invokeStartPC); // end PC |
|
712 exc.emitShort(classCastHandler); // handler PC |
|
713 exc.emitShort(nullPointerClass); // catch type |
|
714 |
|
715 exc.emitShort(invokeStartPC); // start PC |
|
716 exc.emitShort(invokeEndPC); // end PC |
|
717 exc.emitShort(invocationTargetHandler); // handler PC |
|
718 exc.emitShort(throwableClass); // catch type |
|
719 |
|
720 emitMethod(invokeIdx, cb.getMaxLocals(), cb, exc, |
|
721 new short[] { invocationTargetClass }); |
|
722 } |
|
723 |
|
724 private boolean usesPrimitiveTypes() { |
|
725 // We need to emit boxing/unboxing constant pool information if |
|
726 // the method takes a primitive type for any of its parameters or |
|
727 // returns a primitive value (except void) |
|
728 if (returnType.isPrimitive()) { |
|
729 return true; |
|
730 } |
|
731 for (int i = 0; i < parameterTypes.length; i++) { |
|
732 if (parameterTypes[i].isPrimitive()) { |
|
733 return true; |
|
734 } |
|
735 } |
|
736 return false; |
|
737 } |
|
738 |
|
739 private int numNonPrimitiveParameterTypes() { |
|
740 int num = 0; |
|
741 for (int i = 0; i < parameterTypes.length; i++) { |
|
742 if (!parameterTypes[i].isPrimitive()) { |
|
743 ++num; |
|
744 } |
|
745 } |
|
746 return num; |
|
747 } |
|
748 |
|
749 private boolean isInterface() { |
|
750 return declaringClass.isInterface(); |
|
751 } |
|
752 |
|
753 private String buildInternalSignature() { |
|
754 StringBuilder sb = new StringBuilder(); |
|
755 sb.append("("); |
|
756 for (int i = 0; i < parameterTypes.length; i++) { |
|
757 sb.append(getClassName(parameterTypes[i], true)); |
|
758 } |
|
759 sb.append(")"); |
|
760 sb.append(getClassName(returnType, true)); |
|
761 return sb.toString(); |
|
762 } |
|
763 |
|
764 private static synchronized String generateName(boolean isConstructor, |
|
765 boolean forSerialization) |
|
766 { |
|
767 if (isConstructor) { |
|
768 if (forSerialization) { |
|
769 int num = ++serializationConstructorSymnum; |
|
770 return "sun/reflect/GeneratedSerializationConstructorAccessor" + num; |
|
771 } else { |
|
772 int num = ++constructorSymnum; |
|
773 return "sun/reflect/GeneratedConstructorAccessor" + num; |
|
774 } |
|
775 } else { |
|
776 int num = ++methodSymnum; |
|
777 return "sun/reflect/GeneratedMethodAccessor" + num; |
|
778 } |
|
779 } |
|
780 } |
|