/**
     * Gets the correct return instruction for a proxy method
     *
     * @param pool
     * @param methodDescriptor
     */
    public static void addReturnProxyMethod(String methodDescriptor, Bytecode b) {
      String ret = DescriptorUtils.getReturnType(methodDescriptor);
      // if the return type is larger than one then it is not a primitive
      // so just do an ARETURN
      if (ret.length() != 1) {
        b.addCheckcast(DescriptorUtils.getReturnTypeInJvmFormat(methodDescriptor));
        b.add(Opcode.ARETURN);
        return;
      }
      // void methods are special
      if (ret.equals("V")) {
        b.add(Opcode.RETURN);
        return;
      } else {
        // unbox the primitive type

        char tp = ret.charAt(0);
        Boxing.unbox(b, tp);
        if (tp == 'F') {
          b.add(Opcode.FRETURN);
        } else if (tp == 'D') {
          b.add(Opcode.DRETURN);
        } else if (tp == 'J') {
          b.add(Opcode.LRETURN);
        } else {
          b.add(Opcode.IRETURN);
        }
        return;
      }
    }
  /** Add a method to a class that simply delegates to the parent implementation of the method */
  public static void addDelegatingMethod(ClassFile file, MethodData mData)
      throws BadBytecode, DuplicateMemberException {
    MethodInfo m =
        new MethodInfo(file.getConstPool(), mData.getMethodName(), mData.getDescriptor());
    m.setAccessFlags(mData.getAccessFlags());
    Bytecode code = new Bytecode(file.getConstPool());

    String[] params = DescriptorUtils.descriptorStringToParameterArray(mData.getDescriptor());
    code.add(Opcode.ALOAD_0); // push this
    int count = 1; // zero is the this pointer
    int maxLocals = 1;
    for (String p : params) {
      // int char short boolean byte
      if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) {
        // push integer 0
        code.addIload(count);
        maxLocals++;
      }
      // long
      else if (p.equals("J")) {
        code.addLload(count);
        maxLocals += 2;
        count++;
      }
      // double
      else if (p.equals("D")) {
        code.addDload(count);
        maxLocals += 2;
        count++;
      }
      // float
      else if (p.equals("F")) {
        code.addFload(count);
        maxLocals++;
      }
      // arrays and reference types
      else {
        code.addAload(count);
        maxLocals++;
      }
      count++;
    }
    code.addInvokespecial(file.getSuperclass(), mData.getMethodName(), mData.getDescriptor());
    String p = DescriptorUtils.getReturnTypeInJvmFormat(mData.getDescriptor());
    // int char short boolean byte
    if (p.equals("I") || p.equals("C") || p.equals("S") || p.equals("Z") || p.equals("B")) {
      code.add(Opcode.IRETURN);
    }
    // long
    else if (p.equals("J")) {
      code.add(Opcode.LRETURN);
    }
    // double
    else if (p.equals("D")) {
      code.add(Opcode.DRETURN);
    }
    // float
    else if (p.equals("F")) {
      code.add(Opcode.FRETURN);
    }
    // void
    else if (p.equals("V")) {
      code.add(Opcode.RETURN);
    }
    // arrays and reference types
    else {
      code.add(Opcode.ARETURN);
    }
    CodeAttribute ca = code.toCodeAttribute();
    ca.computeMaxStack();
    ca.setMaxLocals(maxLocals);
    m.setCodeAttribute(ca);
    file.addMethod(m);
  }