jdk/src/share/classes/sun/reflect/MethodAccessorGenerator.java
changeset 2 90ce3da70b43
child 51 6fe31bc95bbc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/reflect/MethodAccessorGenerator.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,781 @@
+/*
+ * Copyright 2001 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.reflect;
+
+import java.lang.reflect.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.misc.Unsafe;
+
+/** 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 (MagicAccessorImpl)
+            AccessController.doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        try {
+                            return ClassDefiner.defineClass
+                                (generatedName,
+                                 bytes,
+                                 0,
+                                 bytes.length,
+                                 declaringClass.getClassLoader()).newInstance();
+                        } catch (InstantiationException e) {
+                            throw (InternalError)
+                                new InternalError().initCause(e);
+                        } catch (IllegalAccessException e) {
+                            throw (InternalError)
+                                new InternalError().initCause(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()) {
+                    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;
+        }
+    }
+}