/**
  * Create a method for reflectively invoking this method
  *
  * @param reflectionClass the class this method will belong to
  * @param constantPool for the class
  * @param memRef the member reference corresponding to this method
  * @return the created method
  */
 RVMMethod createReflectionMethod(
     TypeReference reflectionClass, int[] constantPool, MethodReference memRef) {
   TypeReference[] parameters = getParameterTypes();
   int numParams = parameters.length;
   byte[] bytecodes;
   boolean interfaceCall = false;
   int curBC = 0;
   if (!isStatic()) {
     if (!getDeclaringClass().isInterface()) {
       // virtual call
       bytecodes = new byte[8 * numParams + 8];
     } else {
       // interface call
       bytecodes = new byte[8 * numParams + 10];
       interfaceCall = true;
     }
     bytecodes[curBC] = JBC_aload_1;
     curBC++;
   } else {
     // static call
     bytecodes = new byte[8 * numParams + 7];
   }
   for (int i = 0; i < numParams; i++) {
     if (parameters[i].isVoidType()) {
       bytecodes[curBC] =
           bytecodes[curBC + 1] =
               bytecodes[curBC + 2] =
                   bytecodes[curBC + 3] =
                       bytecodes[curBC + 4] =
                           bytecodes[curBC + 5] =
                               bytecodes[curBC + 6] = bytecodes[curBC + 7] = (byte) JBC_nop;
       continue;
     }
     bytecodes[curBC] = (byte) JBC_aload_2;
     bytecodes[curBC + 1] = (byte) JBC_sipush;
     bytecodes[curBC + 2] = (byte) (i >>> 8);
     bytecodes[curBC + 3] = (byte) i;
     bytecodes[curBC + 4] = (byte) JBC_aaload;
     if (!parameters[i].isPrimitiveType()) {
       bytecodes[curBC + 5] = (byte) JBC_checkcast;
       if (VM.VerifyAssertions) VM._assert(parameters[i].getId() != 0);
       constantPool[i + 1] = ClassFileReader.packCPEntry(CP_CLASS, parameters[i].getId());
       bytecodes[curBC + 6] = (byte) ((i + 1) >>> 8);
       bytecodes[curBC + 7] = (byte) (i + 1);
     } else if (parameters[i].isWordLikeType()) {
       bytecodes[curBC + 5] = bytecodes[curBC + 6] = bytecodes[curBC + 7] = (byte) JBC_nop;
     } else {
       bytecodes[curBC + 5] = (byte) JBC_invokestatic;
       MemberReference unboxMethod;
       if (parameters[i].isBooleanType()) {
         unboxMethod =
             MethodReference.findOrCreate(
                 baseReflectionClass,
                 Atom.findOrCreateUnicodeAtom("unboxAsBoolean"),
                 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)Z"));
       } else if (parameters[i].isByteType()) {
         unboxMethod =
             MethodReference.findOrCreate(
                 baseReflectionClass,
                 Atom.findOrCreateUnicodeAtom("unboxAsByte"),
                 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)B"));
       } else if (parameters[i].isShortType()) {
         unboxMethod =
             MethodReference.findOrCreate(
                 baseReflectionClass,
                 Atom.findOrCreateUnicodeAtom("unboxAsShort"),
                 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)S"));
       } else if (parameters[i].isCharType()) {
         unboxMethod =
             MethodReference.findOrCreate(
                 baseReflectionClass,
                 Atom.findOrCreateUnicodeAtom("unboxAsChar"),
                 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)C"));
       } else if (parameters[i].isIntType()) {
         unboxMethod =
             MethodReference.findOrCreate(
                 baseReflectionClass,
                 Atom.findOrCreateUnicodeAtom("unboxAsInt"),
                 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)I"));
       } else if (parameters[i].isLongType()) {
         unboxMethod =
             MethodReference.findOrCreate(
                 baseReflectionClass,
                 Atom.findOrCreateUnicodeAtom("unboxAsLong"),
                 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)J"));
       } else if (parameters[i].isFloatType()) {
         unboxMethod =
             MethodReference.findOrCreate(
                 baseReflectionClass,
                 Atom.findOrCreateUnicodeAtom("unboxAsFloat"),
                 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)F"));
       } else {
         if (VM.VerifyAssertions) VM._assert(parameters[i].isDoubleType());
         unboxMethod =
             MethodReference.findOrCreate(
                 baseReflectionClass,
                 Atom.findOrCreateUnicodeAtom("unboxAsDouble"),
                 Atom.findOrCreateUnicodeAtom("(Ljava/lang/Object;)D"));
       }
       constantPool[i + 1] = ClassFileReader.packCPEntry(CP_MEMBER, unboxMethod.getId());
       bytecodes[curBC + 6] = (byte) ((i + 1) >>> 8);
       bytecodes[curBC + 7] = (byte) (i + 1);
     }
     curBC += 8;
   }
   if (isStatic()) {
     bytecodes[curBC] = (byte) JBC_invokestatic;
   } else if (isObjectInitializer() || isPrivate()) {
     bytecodes[curBC] = (byte) JBC_invokespecial;
   } else if (interfaceCall) {
     bytecodes[curBC] = (byte) JBC_invokeinterface;
   } else {
     bytecodes[curBC] = (byte) JBC_invokevirtual;
   }
   constantPool[numParams + 1] = ClassFileReader.packCPEntry(CP_MEMBER, getId());
   bytecodes[curBC + 1] = (byte) ((numParams + 1) >>> 8);
   bytecodes[curBC + 2] = (byte) (numParams + 1);
   if (interfaceCall) {
     // invokeinterface bytecodes are historically longer than others
     curBC += 2;
   }
   TypeReference returnType = getReturnType();
   if (!returnType.isPrimitiveType() || returnType.isWordLikeType()) {
     bytecodes[curBC + 3] = (byte) JBC_nop;
     bytecodes[curBC + 4] = (byte) JBC_nop;
     bytecodes[curBC + 5] = (byte) JBC_nop;
   } else if (returnType.isVoidType()) {
     bytecodes[curBC + 3] = (byte) JBC_aconst_null;
     bytecodes[curBC + 4] = (byte) JBC_nop;
     bytecodes[curBC + 5] = (byte) JBC_nop;
   } else {
     MemberReference boxMethod;
     if (returnType.isBooleanType()) {
       boxMethod =
           MethodReference.findOrCreate(
               baseReflectionClass,
               Atom.findOrCreateUnicodeAtom("boxAsBoolean"),
               Atom.findOrCreateUnicodeAtom("(Z)Ljava/lang/Object;"));
     } else if (returnType.isByteType()) {
       boxMethod =
           MethodReference.findOrCreate(
               baseReflectionClass,
               Atom.findOrCreateUnicodeAtom("boxAsByte"),
               Atom.findOrCreateUnicodeAtom("(B)Ljava/lang/Object;"));
     } else if (returnType.isShortType()) {
       boxMethod =
           MethodReference.findOrCreate(
               baseReflectionClass,
               Atom.findOrCreateUnicodeAtom("boxAsShort"),
               Atom.findOrCreateUnicodeAtom("(S)Ljava/lang/Object;"));
     } else if (returnType.isCharType()) {
       boxMethod =
           MethodReference.findOrCreate(
               baseReflectionClass,
               Atom.findOrCreateUnicodeAtom("boxAsChar"),
               Atom.findOrCreateUnicodeAtom("(C)Ljava/lang/Object;"));
     } else if (returnType.isIntType()) {
       boxMethod =
           MethodReference.findOrCreate(
               baseReflectionClass,
               Atom.findOrCreateUnicodeAtom("boxAsInt"),
               Atom.findOrCreateUnicodeAtom("(I)Ljava/lang/Object;"));
     } else if (returnType.isLongType()) {
       boxMethod =
           MethodReference.findOrCreate(
               baseReflectionClass,
               Atom.findOrCreateUnicodeAtom("boxAsLong"),
               Atom.findOrCreateUnicodeAtom("(J)Ljava/lang/Object;"));
     } else if (returnType.isFloatType()) {
       boxMethod =
           MethodReference.findOrCreate(
               baseReflectionClass,
               Atom.findOrCreateUnicodeAtom("boxAsFloat"),
               Atom.findOrCreateUnicodeAtom("(F)Ljava/lang/Object;"));
     } else {
       if (VM.VerifyAssertions) VM._assert(returnType.isDoubleType());
       boxMethod =
           MethodReference.findOrCreate(
               baseReflectionClass,
               Atom.findOrCreateUnicodeAtom("boxAsDouble"),
               Atom.findOrCreateUnicodeAtom("(D)Ljava/lang/Object;"));
     }
     constantPool[numParams + 2] = ClassFileReader.packCPEntry(CP_MEMBER, boxMethod.getId());
     bytecodes[curBC + 3] = (byte) JBC_invokestatic;
     bytecodes[curBC + 4] = (byte) ((numParams + 2) >>> 8);
     bytecodes[curBC + 5] = (byte) (numParams + 2);
   }
   bytecodes[curBC + 6] = (byte) JBC_areturn;
   return new NormalMethod(
       reflectionClass,
       memRef,
       (short) (ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC),
       null,
       (short) 3,
       (short) (getParameterWords() + 2),
       bytecodes,
       null,
       null,
       null,
       constantPool,
       null,
       null,
       null,
       null);
 }