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