diff options
Diffstat (limited to 'src/Java/sun/repackage/MethodAccessorGenerator.java')
-rw-r--r-- | src/Java/sun/repackage/MethodAccessorGenerator.java | 780 |
1 files changed, 780 insertions, 0 deletions
diff --git a/src/Java/sun/repackage/MethodAccessorGenerator.java b/src/Java/sun/repackage/MethodAccessorGenerator.java new file mode 100644 index 0000000000..21eae8174f --- /dev/null +++ b/src/Java/sun/repackage/MethodAccessorGenerator.java @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.repackage; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** Generator for sun.reflect.MethodAccessor and + sun.reflect.ConstructorAccessor objects using bytecodes to + implement reflection. A java.lang.reflect.Method or + java.lang.reflect.Constructor object can delegate its invoke or + newInstance method to an accessor using native code or to one + generated by this class. (Methods and Constructors were merged + together in this class to ensure maximum code sharing.) */ + +class MethodAccessorGenerator extends AccessorGenerator { + + private static final short NUM_BASE_CPOOL_ENTRIES = (short) 12; + // One for invoke() plus one for constructor + private static final short NUM_METHODS = (short) 2; + // Only used if forSerialization is true + private static final short NUM_SERIALIZATION_CPOOL_ENTRIES = (short) 2; + + private static volatile int methodSymnum = 0; + private static volatile int constructorSymnum = 0; + private static volatile int serializationConstructorSymnum = 0; + + private Class<?> declaringClass; + private Class<?>[] parameterTypes; + private Class<?> returnType; + private boolean isConstructor; + private boolean forSerialization; + + private short targetMethodRef; + private short invokeIdx; + private short invokeDescriptorIdx; + // Constant pool index of CONSTANT_Class_info for first + // non-primitive parameter type. Should be incremented by 2. + private short nonPrimitiveParametersBaseIdx; + + MethodAccessorGenerator() { + } + + /** This routine is not thread-safe */ + public MethodAccessor generateMethod(Class<?> declaringClass, + String name, + Class<?>[] parameterTypes, + Class<?> returnType, + Class<?>[] checkedExceptions, + int modifiers) + { + return (MethodAccessor) generate(declaringClass, + name, + parameterTypes, + returnType, + checkedExceptions, + modifiers, + false, + false, + null); + } + + /** This routine is not thread-safe */ + public ConstructorAccessor generateConstructor(Class<?> declaringClass, + Class<?>[] parameterTypes, + Class<?>[] checkedExceptions, + int modifiers) + { + return (ConstructorAccessor) generate(declaringClass, + "<init>", + parameterTypes, + Void.TYPE, + checkedExceptions, + modifiers, + true, + false, + null); + } + + /** This routine is not thread-safe */ + public SerializationConstructorAccessorImpl + generateSerializationConstructor(Class<?> declaringClass, + Class<?>[] parameterTypes, + Class<?>[] checkedExceptions, + int modifiers, + Class<?> targetConstructorClass) + { + return (SerializationConstructorAccessorImpl) + generate(declaringClass, + "<init>", + parameterTypes, + Void.TYPE, + checkedExceptions, + modifiers, + true, + true, + targetConstructorClass); + } + + /** This routine is not thread-safe */ + private MagicAccessorImpl generate(final Class<?> declaringClass, + String name, + Class<?>[] parameterTypes, + Class<?> returnType, + Class<?>[] checkedExceptions, + int modifiers, + boolean isConstructor, + boolean forSerialization, + Class<?> serializationTargetClass) + { + ByteVector vec = ByteVectorFactory.create(); + asm = new ClassFileAssembler(vec); + this.declaringClass = declaringClass; + this.parameterTypes = parameterTypes; + this.returnType = returnType; + this.modifiers = modifiers; + this.isConstructor = isConstructor; + this.forSerialization = forSerialization; + + asm.emitMagicAndVersion(); + + // Constant pool entries: + // ( * = Boxing information: optional) + // (+ = Shared entries provided by AccessorGenerator) + // (^ = Only present if generating SerializationConstructorAccessor) + // [UTF-8] [This class's name] + // [CONSTANT_Class_info] for above + // [UTF-8] "sun/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" + // [CONSTANT_Class_info] for above + // [UTF-8] [Target class's name] + // [CONSTANT_Class_info] for above + // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] + // ^ [CONSTANT_Class_info] for above + // [UTF-8] target method or constructor name + // [UTF-8] target method or constructor signature + // [CONSTANT_NameAndType_info] for above + // [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method + // [UTF-8] "invoke" or "newInstance" + // [UTF-8] invoke or newInstance descriptor + // [UTF-8] descriptor for type of non-primitive parameter 1 + // [CONSTANT_Class_info] for type of non-primitive parameter 1 + // ... + // [UTF-8] descriptor for type of non-primitive parameter n + // [CONSTANT_Class_info] for type of non-primitive parameter n + // + [UTF-8] "java/lang/Exception" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "java/lang/ClassCastException" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "java/lang/NullPointerException" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "java/lang/IllegalArgumentException" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "java/lang/InvocationTargetException" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "<init>" + // + [UTF-8] "()V" + // + [CONSTANT_NameAndType_info] for above + // + [CONSTANT_Methodref_info] for NullPointerException's constructor + // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor + // + [UTF-8] "(Ljava/lang/String;)V" + // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V" + // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String + // + [UTF-8] "(Ljava/lang/Throwable;)V" + // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V" + // + [CONSTANT_Methodref_info] for InvocationTargetException's constructor + // + [CONSTANT_Methodref_info] for "super()" + // + [UTF-8] "java/lang/Object" + // + [CONSTANT_Class_info] for above + // + [UTF-8] "toString" + // + [UTF-8] "()Ljava/lang/String;" + // + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;" + // + [CONSTANT_Methodref_info] for Object's toString method + // + [UTF-8] "Code" + // + [UTF-8] "Exceptions" + // * [UTF-8] "java/lang/Boolean" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(Z)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "booleanValue" + // * [UTF-8] "()Z" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Byte" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(B)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "byteValue" + // * [UTF-8] "()B" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Character" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(C)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "charValue" + // * [UTF-8] "()C" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Double" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(D)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "doubleValue" + // * [UTF-8] "()D" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Float" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(F)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "floatValue" + // * [UTF-8] "()F" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Integer" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(I)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "intValue" + // * [UTF-8] "()I" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Long" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(J)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "longValue" + // * [UTF-8] "()J" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "java/lang/Short" + // * [CONSTANT_Class_info] for above + // * [UTF-8] "(S)V" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + // * [UTF-8] "shortValue" + // * [UTF-8] "()S" + // * [CONSTANT_NameAndType_info] for above + // * [CONSTANT_Methodref_info] for above + + short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES; + boolean usesPrimitives = usesPrimitiveTypes(); + if (usesPrimitives) { + numCPEntries += NUM_BOXING_CPOOL_ENTRIES; + } + if (forSerialization) { + numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES; + } + + // Add in variable-length number of entries to be able to describe + // non-primitive parameter types and checked exceptions. + numCPEntries += (short) (2 * numNonPrimitiveParameterTypes()); + + asm.emitShort(add(numCPEntries, S1)); + + final String generatedName = generateName(isConstructor, forSerialization); + asm.emitConstantPoolUTF8(generatedName); + asm.emitConstantPoolClass(asm.cpi()); + thisClass = asm.cpi(); + if (isConstructor) { + if (forSerialization) { + asm.emitConstantPoolUTF8 + ("sun/reflect/SerializationConstructorAccessorImpl"); + } else { + asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl"); + } + } else { + asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl"); + } + asm.emitConstantPoolClass(asm.cpi()); + superClass = asm.cpi(); + asm.emitConstantPoolUTF8(getClassName(declaringClass, false)); + asm.emitConstantPoolClass(asm.cpi()); + targetClass = asm.cpi(); + short serializationTargetClassIdx = (short) 0; + if (forSerialization) { + asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false)); + asm.emitConstantPoolClass(asm.cpi()); + serializationTargetClassIdx = asm.cpi(); + } + asm.emitConstantPoolUTF8(name); + asm.emitConstantPoolUTF8(buildInternalSignature()); + asm.emitConstantPoolNameAndType(sub(asm.cpi(), S1), asm.cpi()); + if (isInterface()) { + asm.emitConstantPoolInterfaceMethodref(targetClass, asm.cpi()); + } else { + if (forSerialization) { + asm.emitConstantPoolMethodref(serializationTargetClassIdx, asm.cpi()); + } else { + asm.emitConstantPoolMethodref(targetClass, asm.cpi()); + } + } + targetMethodRef = asm.cpi(); + if (isConstructor) { + asm.emitConstantPoolUTF8("newInstance"); + } else { + asm.emitConstantPoolUTF8("invoke"); + } + invokeIdx = asm.cpi(); + if (isConstructor) { + asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;"); + } else { + asm.emitConstantPoolUTF8 + ("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"); + } + invokeDescriptorIdx = asm.cpi(); + + // Output class information for non-primitive parameter types + nonPrimitiveParametersBaseIdx = add(asm.cpi(), S2); + for (int i = 0; i < parameterTypes.length; i++) { + Class<?> c = parameterTypes[i]; + if (!isPrimitive(c)) { + asm.emitConstantPoolUTF8(getClassName(c, false)); + asm.emitConstantPoolClass(asm.cpi()); + } + } + + // Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor + emitCommonConstantPoolEntries(); + + // Boxing entries + if (usesPrimitives) { + emitBoxingContantPoolEntries(); + } + + if (asm.cpi() != numCPEntries) { + throw new InternalError("Adjust this code (cpi = " + asm.cpi() + + ", numCPEntries = " + numCPEntries + ")"); + } + + // Access flags + asm.emitShort(ACC_PUBLIC); + + // This class + asm.emitShort(thisClass); + + // Superclass + asm.emitShort(superClass); + + // Interfaces count and interfaces + asm.emitShort(S0); + + // Fields count and fields + asm.emitShort(S0); + + // Methods count and methods + asm.emitShort(NUM_METHODS); + + emitConstructor(); + emitInvoke(); + + // Additional attributes (none) + asm.emitShort(S0); + + // Load class + vec.trim(); + final byte[] bytes = vec.getData(); + // Note: the class loader is the only thing that really matters + // here -- it's important to get the generated code into the + // same namespace as the target class. Since the generated code + // is privileged anyway, the protection domain probably doesn't + // matter. + return AccessController.doPrivileged( + new PrivilegedAction<MagicAccessorImpl>() { + public MagicAccessorImpl run() { + try { + return (MagicAccessorImpl) + ClassDefiner.defineClass + (generatedName, + bytes, + 0, + bytes.length, + declaringClass.getClassLoader()).newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new InternalError(e); + } + } + }); + } + + /** This emits the code for either invoke() or newInstance() */ + private void emitInvoke() { + // NOTE that this code will only handle 65535 parameters since we + // use the sipush instruction to get the array index on the + // operand stack. + if (parameterTypes.length > 65535) { + throw new InternalError("Can't handle more than 65535 parameters"); + } + + // Generate code into fresh code buffer + ClassFileAssembler cb = new ClassFileAssembler(); + if (isConstructor) { + // 1 incoming argument + cb.setMaxLocals(2); + } else { + // 2 incoming arguments + cb.setMaxLocals(3); + } + + short illegalArgStartPC = 0; + + if (isConstructor) { + // Instantiate target class before continuing + // new <target class type> + // dup + cb.opc_new(targetClass); + cb.opc_dup(); + } else { + // Setup before iterating down argument list + if (isPrimitive(returnType)) { + // new <boxing type for primitive type> + // dup + // ... (see below:) + // invokespecial <constructor for boxing type for primitive type> + // areturn + cb.opc_new(indexForPrimitiveType(returnType)); + cb.opc_dup(); + } + + // Get target object on operand stack if necessary. + + // We need to do an explicit null check here; we won't see + // NullPointerExceptions from the invoke bytecode, since it's + // covered by an exception handler. + if (!isStatic()) { + // aload_1 + // ifnonnull <checkcast label> + // new <NullPointerException> + // dup + // invokespecial <NullPointerException ctor> + // athrow + // <checkcast label:> + // aload_1 + // checkcast <target class's type> + cb.opc_aload_1(); + Label l = new Label(); + cb.opc_ifnonnull(l); + cb.opc_new(nullPointerClass); + cb.opc_dup(); + cb.opc_invokespecial(nullPointerCtorIdx, 0, 0); + cb.opc_athrow(); + l.bind(); + illegalArgStartPC = cb.getLength(); + cb.opc_aload_1(); + cb.opc_checkcast(targetClass); + } + } + + // Have to check length of incoming array and throw + // IllegalArgumentException if not correct. A concession to the + // JCK (isn't clearly specified in the spec): we allow null in the + // case where the argument list is zero length. + // if no-arg: + // aload_2 | aload_1 (Method | Constructor) + // ifnull <success label> + // aload_2 | aload_1 + // arraylength + // sipush <num parameter types> + // if_icmpeq <success label> + // new <IllegalArgumentException> + // dup + // invokespecial <IllegalArgumentException ctor> + // athrow + // <success label:> + Label successLabel = new Label(); + if (parameterTypes.length == 0) { + if (isConstructor) { + cb.opc_aload_1(); + } else { + cb.opc_aload_2(); + } + cb.opc_ifnull(successLabel); + } + if (isConstructor) { + cb.opc_aload_1(); + } else { + cb.opc_aload_2(); + } + cb.opc_arraylength(); + cb.opc_sipush((short) parameterTypes.length); + cb.opc_if_icmpeq(successLabel); + cb.opc_new(illegalArgumentClass); + cb.opc_dup(); + cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); + cb.opc_athrow(); + successLabel.bind(); + + // Iterate through incoming actual parameters, ensuring that each + // is compatible with the formal parameter type, and pushing the + // actual on the operand stack (unboxing and widening if necessary). + + short paramTypeCPIdx = nonPrimitiveParametersBaseIdx; + Label nextParamLabel = null; + byte count = 1; // both invokeinterface opcode's "count" as well as + // num args of other invoke bytecodes + for (int i = 0; i < parameterTypes.length; i++) { + Class<?> paramType = parameterTypes[i]; + count += (byte) typeSizeInStackSlots(paramType); + if (nextParamLabel != null) { + nextParamLabel.bind(); + nextParamLabel = null; + } + // aload_2 | aload_1 + // sipush <index> + // aaload + if (isConstructor) { + cb.opc_aload_1(); + } else { + cb.opc_aload_2(); + } + cb.opc_sipush((short) i); + cb.opc_aaload(); + if (isPrimitive(paramType)) { + // Unboxing code. + // Put parameter into temporary local variable + // astore_3 | astore_2 + if (isConstructor) { + cb.opc_astore_2(); + } else { + cb.opc_astore_3(); + } + + // repeat for all possible widening conversions: + // aload_3 | aload_2 + // instanceof <primitive boxing type> + // ifeq <next unboxing label> + // aload_3 | aload_2 + // checkcast <primitive boxing type> // Note: this is "redundant", + // // but necessary for the verifier + // invokevirtual <unboxing method> + // <widening conversion bytecode, if necessary> + // goto <next parameter label> + // <next unboxing label:> ... + // last unboxing label: + // new <IllegalArgumentException> + // dup + // invokespecial <IllegalArgumentException ctor> + // athrow + + Label l = null; // unboxing label + nextParamLabel = new Label(); + + for (int j = 0; j < primitiveTypes.length; j++) { + Class<?> c = primitiveTypes[j]; + if (canWidenTo(c, paramType)) { + if (l != null) { + l.bind(); + } + // Emit checking and unboxing code for this type + if (isConstructor) { + cb.opc_aload_2(); + } else { + cb.opc_aload_3(); + } + cb.opc_instanceof(indexForPrimitiveType(c)); + l = new Label(); + cb.opc_ifeq(l); + if (isConstructor) { + cb.opc_aload_2(); + } else { + cb.opc_aload_3(); + } + cb.opc_checkcast(indexForPrimitiveType(c)); + cb.opc_invokevirtual(unboxingMethodForPrimitiveType(c), + 0, + typeSizeInStackSlots(c)); + emitWideningBytecodeForPrimitiveConversion(cb, + c, + paramType); + cb.opc_goto(nextParamLabel); + } + } + + if (l == null) { + throw new InternalError + ("Must have found at least identity conversion"); + } + + // Fell through; given object is null or invalid. According to + // the spec, we can throw IllegalArgumentException for both of + // these cases. + + l.bind(); + cb.opc_new(illegalArgumentClass); + cb.opc_dup(); + cb.opc_invokespecial(illegalArgumentCtorIdx, 0, 0); + cb.opc_athrow(); + } else { + // Emit appropriate checkcast + cb.opc_checkcast(paramTypeCPIdx); + paramTypeCPIdx = add(paramTypeCPIdx, S2); + // Fall through to next argument + } + } + // Bind last goto if present + if (nextParamLabel != null) { + nextParamLabel.bind(); + } + + short invokeStartPC = cb.getLength(); + + // OK, ready to perform the invocation. + if (isConstructor) { + cb.opc_invokespecial(targetMethodRef, count, 0); + } else { + if (isStatic()) { + cb.opc_invokestatic(targetMethodRef, + count, + typeSizeInStackSlots(returnType)); + } else { + if (isInterface()) { + if (isPrivate()) { + cb.opc_invokespecial(targetMethodRef, count, 0); + } else { + cb.opc_invokeinterface(targetMethodRef, + count, + count, + typeSizeInStackSlots(returnType)); + } + } else { + cb.opc_invokevirtual(targetMethodRef, + count, + typeSizeInStackSlots(returnType)); + } + } + } + + short invokeEndPC = cb.getLength(); + + if (!isConstructor) { + // Box return value if necessary + if (isPrimitive(returnType)) { + cb.opc_invokespecial(ctorIndexForPrimitiveType(returnType), + typeSizeInStackSlots(returnType), + 0); + } else if (returnType == Void.TYPE) { + cb.opc_aconst_null(); + } + } + cb.opc_areturn(); + + // We generate two exception handlers; one which is responsible + // for catching ClassCastException and NullPointerException and + // throwing IllegalArgumentException, and the other which catches + // all java/lang/Throwable objects thrown from the target method + // and wraps them in InvocationTargetExceptions. + + short classCastHandler = cb.getLength(); + + // ClassCast, etc. exception handler + cb.setStack(1); + cb.opc_invokespecial(toStringIdx, 0, 1); + cb.opc_new(illegalArgumentClass); + cb.opc_dup_x1(); + cb.opc_swap(); + cb.opc_invokespecial(illegalArgumentStringCtorIdx, 1, 0); + cb.opc_athrow(); + + short invocationTargetHandler = cb.getLength(); + + // InvocationTargetException exception handler + cb.setStack(1); + cb.opc_new(invocationTargetClass); + cb.opc_dup_x1(); + cb.opc_swap(); + cb.opc_invokespecial(invocationTargetCtorIdx, 1, 0); + cb.opc_athrow(); + + // Generate exception table. We cover the entire code sequence + // with an exception handler which catches ClassCastException and + // converts it into an IllegalArgumentException. + + ClassFileAssembler exc = new ClassFileAssembler(); + + exc.emitShort(illegalArgStartPC); // start PC + exc.emitShort(invokeStartPC); // end PC + exc.emitShort(classCastHandler); // handler PC + exc.emitShort(classCastClass); // catch type + + exc.emitShort(illegalArgStartPC); // start PC + exc.emitShort(invokeStartPC); // end PC + exc.emitShort(classCastHandler); // handler PC + exc.emitShort(nullPointerClass); // catch type + + exc.emitShort(invokeStartPC); // start PC + exc.emitShort(invokeEndPC); // end PC + exc.emitShort(invocationTargetHandler); // handler PC + exc.emitShort(throwableClass); // catch type + + emitMethod(invokeIdx, cb.getMaxLocals(), cb, exc, + new short[] { invocationTargetClass }); + } + + private boolean usesPrimitiveTypes() { + // We need to emit boxing/unboxing constant pool information if + // the method takes a primitive type for any of its parameters or + // returns a primitive value (except void) + if (returnType.isPrimitive()) { + return true; + } + for (int i = 0; i < parameterTypes.length; i++) { + if (parameterTypes[i].isPrimitive()) { + return true; + } + } + return false; + } + + private int numNonPrimitiveParameterTypes() { + int num = 0; + for (int i = 0; i < parameterTypes.length; i++) { + if (!parameterTypes[i].isPrimitive()) { + ++num; + } + } + return num; + } + + private boolean isInterface() { + return declaringClass.isInterface(); + } + + private String buildInternalSignature() { + StringBuffer buf = new StringBuffer(); + buf.append("("); + for (int i = 0; i < parameterTypes.length; i++) { + buf.append(getClassName(parameterTypes[i], true)); + } + buf.append(")"); + buf.append(getClassName(returnType, true)); + return buf.toString(); + } + + private static synchronized String generateName(boolean isConstructor, + boolean forSerialization) + { + if (isConstructor) { + if (forSerialization) { + int num = ++serializationConstructorSymnum; + return "sun/reflect/GeneratedSerializationConstructorAccessor" + num; + } else { + int num = ++constructorSymnum; + return "sun/reflect/GeneratedConstructorAccessor" + num; + } + } else { + int num = ++methodSymnum; + return "sun/reflect/GeneratedMethodAccessor" + num; + } + } +} |