/**
   * Called from {@link ClassFileReader#readClass(TypeReference,DataInputStream)} to create an
   * instance of a RVMMethod by reading the relevant data from the argument bytecode stream.
   *
   * @param declaringClass the TypeReference of the class being loaded
   * @param constantPool the constantPool of the RVMClass object that's being constructed
   * @param memRef the canonical memberReference for this member.
   * @param modifiers modifiers associated with this member.
   * @param input the DataInputStream to read the method's attributes from
   */
  static RVMMethod readMethod(
      TypeReference declaringClass,
      int[] constantPool,
      MemberReference memRef,
      short modifiers,
      DataInputStream input)
      throws IOException {
    short tmp_localWords = 0;
    short tmp_operandWords = 0;
    byte[] tmp_bytecodes = null;
    ExceptionHandlerMap tmp_exceptionHandlerMap = null;
    TypeReference[] tmp_exceptionTypes = null;
    int[] tmp_lineNumberMap = null;
    LocalVariableTable tmp_localVariableTable = null;
    Atom tmp_signature = null;
    RVMAnnotation[] annotations = null;
    RVMAnnotation[][] parameterAnnotations = null;
    Object tmp_annotationDefault = null;

    // Read the attributes
    for (int i = 0, n = input.readUnsignedShort(); i < n; i++) {
      Atom attName = ClassFileReader.getUtf(constantPool, input.readUnsignedShort());
      int attLength = input.readInt();

      // Only bother to interpret non-boring Method attributes
      if (attName == RVMClassLoader.codeAttributeName) {
        tmp_operandWords = input.readShort();
        tmp_localWords = input.readShort();
        tmp_bytecodes = new byte[input.readInt()];
        input.readFully(tmp_bytecodes);
        tmp_exceptionHandlerMap = ExceptionHandlerMap.readExceptionHandlerMap(input, constantPool);

        // Read the attributes portion of the code attribute
        for (int j = 0, n2 = input.readUnsignedShort(); j < n2; j++) {
          attName = ClassFileReader.getUtf(constantPool, input.readUnsignedShort());
          attLength = input.readInt();

          if (attName == RVMClassLoader.lineNumberTableAttributeName) {
            int cnt = input.readUnsignedShort();
            if (cnt != 0) {
              tmp_lineNumberMap = new int[cnt];
              for (int k = 0; k < cnt; k++) {
                int startPC = input.readUnsignedShort();
                int lineNumber = input.readUnsignedShort();
                tmp_lineNumberMap[k] = (lineNumber << BITS_IN_SHORT) | startPC;
              }
            }
          } else if (attName == RVMClassLoader.localVariableTableAttributeName) {
            tmp_localVariableTable = LocalVariableTable.readLocalVariableTable(input, constantPool);
          } else {
            // All other entries in the attribute portion of the code attribute are boring.
            int skippedAmount = input.skipBytes(attLength);
            if (skippedAmount != attLength) {
              throw new IOException("Unexpected short skip");
            }
          }
        }
      } else if (attName == RVMClassLoader.exceptionsAttributeName) {
        int cnt = input.readUnsignedShort();
        if (cnt != 0) {
          tmp_exceptionTypes = new TypeReference[cnt];
          for (int j = 0, m = tmp_exceptionTypes.length; j < m; ++j) {
            tmp_exceptionTypes[j] =
                ClassFileReader.getTypeRef(constantPool, input.readUnsignedShort());
          }
        }
      } else if (attName == RVMClassLoader.syntheticAttributeName) {
        modifiers |= ACC_SYNTHETIC;
      } else if (attName == RVMClassLoader.signatureAttributeName) {
        tmp_signature = ClassFileReader.getUtf(constantPool, input.readUnsignedShort());
      } else if (attName == RVMClassLoader.runtimeVisibleAnnotationsAttributeName) {
        annotations =
            AnnotatedElement.readAnnotations(constantPool, input, declaringClass.getClassLoader());
      } else if (attName == RVMClassLoader.runtimeVisibleParameterAnnotationsAttributeName) {
        int numParameters = input.readByte() & 0xFF;
        parameterAnnotations = new RVMAnnotation[numParameters][];
        for (int a = 0; a < numParameters; ++a) {
          parameterAnnotations[a] =
              AnnotatedElement.readAnnotations(
                  constantPool, input, declaringClass.getClassLoader());
        }
      } else if (attName == RVMClassLoader.annotationDefaultAttributeName) {
        try {
          tmp_annotationDefault =
              RVMAnnotation.readValue(
                  memRef.asMethodReference().getReturnType(),
                  constantPool,
                  input,
                  declaringClass.getClassLoader());
        } catch (ClassNotFoundException e) {
          throw new Error(e);
        }
      } else {
        // all other method attributes are boring
        int skippedAmount = input.skipBytes(attLength);
        if (skippedAmount != attLength) {
          throw new IOException("Unexpected short skip");
        }
      }
    }
    RVMMethod method;
    if ((modifiers & ACC_NATIVE) != 0) {
      method =
          new NativeMethod(
              declaringClass,
              memRef,
              modifiers,
              tmp_exceptionTypes,
              tmp_signature,
              annotations,
              parameterAnnotations,
              tmp_annotationDefault);
    } else if ((modifiers & ACC_ABSTRACT) != 0) {
      method =
          new AbstractMethod(
              declaringClass,
              memRef,
              modifiers,
              tmp_exceptionTypes,
              tmp_signature,
              annotations,
              parameterAnnotations,
              tmp_annotationDefault);

    } else {
      method =
          new NormalMethod(
              declaringClass,
              memRef,
              modifiers,
              tmp_exceptionTypes,
              tmp_localWords,
              tmp_operandWords,
              tmp_bytecodes,
              tmp_exceptionHandlerMap,
              tmp_lineNumberMap,
              tmp_localVariableTable,
              constantPool,
              tmp_signature,
              annotations,
              parameterAnnotations,
              tmp_annotationDefault);
    }
    return method;
  }