FileDocCategorySizeDatePackage
MethodInfo.javaAPI DocJ2ME CLDC 1.132846Wed Feb 05 15:56:02 GMT 2003components

MethodInfo

public class MethodInfo extends ClassMemberInfo implements vm.Const

Fields Summary
public int
argsSize
public int
stack
public int
locals
public int
methodTableIndex
public byte[]
code
private Attribute[]
methodAttributes
public CodeAttribute
codeAttribute
public Attribute[]
codeAttributes
public ExceptionEntry[]
exceptionTable
public ClassConstant[]
exceptionsThrown
private boolean
checkedDebugTables
private LineNumberTableEntry[]
lineNumberTable
private LocalVariableTableEntry[]
localVariableTable
public StackMapFrame[]
stackMapTable
public vm.VMMethodInfo
vmMethodInfo
public MethodInfo[]
targetMethods
public int[]
ldcInstructions
The following are arrays of indexes into the code array of references to the constant pool: ldcInstructions lists the instructions with a one-byte index. wideConstantRefInstructions lists the instructions with a two-byte index. In each case, the index is that of the opcode: the actual reference begins with the following byte. Entries of value -1 are ignored.
public int[]
wideConstantRefInstructions
private String
nativeName
private static Hashtable
methodAttributeTypes
Constructors Summary
public MethodInfo(int name, int sig, int access, ClassInfo p)


               
    super( name, sig, access, p );
    
Methods Summary
private static final intat(byte[] codeBytes, int index)
Return the byte stored at a given index from the offset within code bytes

        return codeBytes[index] & 0xFF;
    
public voidcountConstantReferences(ConstantObject[] table, boolean isRelocatable)

    super.countConstantReferences();
    Attribute.countConstantReferences( methodAttributes, isRelocatable );
    Attribute.countConstantReferences( codeAttributes, isRelocatable );
    if ( code == null ) return; // no code, no relocation
    if ( ldcInstructions != null ){
        int list[] = ldcInstructions;
        int n = list.length;
        for (int i = 0; i < n; i++){
        int loc = list[i];
        if ( loc==-1 ) continue;
        table[ (int)code[loc+1]&0xff ].incReference();
        }
    }
    if ( wideConstantRefInstructions != null ){
        int list[] = wideConstantRefInstructions;
        int n = list.length;
        for (int i = 0; i < n; i++){
        int loc = list[i];
        if ( loc==-1 ) continue;
        table[ getUnsignedShort(loc+1) ].incReference();
        }
    }
    
public voiddisassemble()

 
        System.out.println(disassemble(code, 0, code.length));
    
public java.lang.Stringdisassemble(int start, int end)

 
    return disassemble(code, start, end);
    
public static java.lang.Stringdisassemble(byte[] codeBytes, int start, int end)

 
    // Output goes into a string
    StringWriter sw = new StringWriter();
    PrintWriter output = new PrintWriter(sw);
    
    for (int offset = start; offset < end; ) {
        int opcode = at(codeBytes, offset);

        if (offset > start) 
            output.print("; ");
            
            output.print(opcodeName(opcode));

        switch (opcode) {
        case opc_aload: case opc_astore:
        case opc_fload: case opc_fstore:
        case opc_iload: case opc_istore:
        case opc_lload: case opc_lstore:
        case opc_dload: case opc_dstore:
        case opc_ret:
        output.print(" " + at(codeBytes, offset+1));
        offset += 2;
        break;
            
        case opc_iinc:
        output.print(" " + at(codeBytes, offset+1)  + " " + 
                 (byte) at(codeBytes, offset +2));
        offset += 3;
        break;

        case opc_newarray:
        switch (at(codeBytes, offset+1)) {
        case T_INT:    output.print(" int");    break;
        case T_LONG:   output.print(" long");   break;
        case T_FLOAT:  output.print(" float");  break;
        case T_DOUBLE: output.print(" double"); break;
        case T_CHAR:   output.print(" char");   break;
        case T_SHORT:  output.print(" short");  break;
        case T_BYTE:   output.print(" byte");   break;
        case T_BOOLEAN:output.print(" boolean");   break;
        default:             output.print(" BOGUS"); break;
        }
        offset += 2;
        break;

        case opc_anewarray_fast:
        case opc_anewarray: {
        int index =  shortAt(codeBytes, offset+1);
        output.print(" class #" + index + " ");
        offset += 3;
        break;
        }
              
        case opc_sipush:
        output.print(" " + (short) shortAt(codeBytes, offset+1));
        offset += 3;
        break;

        case opc_bipush:
        output.print(" " + (byte) at(codeBytes, offset+1));
        offset += 2;
        break;

        case opc_ldc: {
        int index = at(codeBytes, offset+1);
        output.print(" #" + index + " ");
        offset += 2;
        break;
        }

            case opc_getstatic_fast:
            case opc_getstaticp_fast:
            case opc_getstatic2_fast:
            case opc_putstatic_fast:
            case opc_putstatic2_fast:
            case opc_unused_d5:
            case opc_invokevirtual_fast:
            case opc_invokespecial_fast:
            case opc_invokestatic_fast:
            case opc_invokeinterface_fast:
            case opc_new_fast:
            case opc_multianewarray_fast:
            case opc_checkcast_fast:
            case opc_instanceof_fast:
        case opc_ldc_w: case opc_ldc2_w:
        case opc_instanceof: case opc_checkcast:
        case opc_new:
        case opc_putstatic: case opc_getstatic:
        case opc_putfield: case opc_getfield:
        case opc_invokevirtual:
        case opc_invokespecial:
        case opc_invokestatic: {
        int index = shortAt(codeBytes, offset+1);
        output.print(" #" + index + " ");
        offset += 3;
        break;
        }

            case opc_getfield_fast:
            case opc_getfieldp_fast:
            case opc_getfield2_fast:
            case opc_putfield_fast:
            case opc_putfield2_fast: { 
        int index = at(codeBytes, offset+1);
        output.print(" [" + index + "] ");
        offset += 3;
        break;
        }

        case opc_jsr: case opc_goto:
        case opc_ifeq: case opc_ifge: case opc_ifgt:
        case opc_ifle: case opc_iflt: case opc_ifne:
        case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
        case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
        case opc_if_acmpeq: case opc_if_acmpne:
        case opc_ifnull: case opc_ifnonnull: {
        int target = offset + (short) shortAt(codeBytes,offset+1);
        output.print(" " + target);
        offset += 3;
        break;
        }

        default:
        offset += opcodeLength(codeBytes, offset);
        break;
        }
    }
        
    output.close();
    return sw.toString();
    
public voidexternalize(ConstantPool p)

    super.externalize( p );
    Attribute.externalizeAttributes( methodAttributes, p );
    Attribute.externalizeAttributes( codeAttributes, p );
    
public voidfindConstantReferences()

    if ( code == null ) return; // no code, no references.
    int     ldc[]  = new int[ code.length / 2 ];
    int     wide[] = new int[ code.length / 3 ];
    int    nldc   = 0;
    int    nwide  = 0;
    int    ncode  = code.length;
    int    opcode;
    for( int i = 0; i < ncode; /*nothing*/){
        switch (opcode = (int)code[i]&0xff) {
        case opc_tableswitch:
        i = (i + 4) & ~3;
        int low = getInt( i+4);
        int high = getInt( i+8);
        i += (high - low + 1) * 4 + 12;
        break;

        case opc_lookupswitch:
        i = (i + 4) & ~3;
        int pairs = getInt(i+4);
        i += pairs * 8 + 8;
        break;

        case opc_wide:
        switch ((int)code[i+1]&0xff) {
        case opc_aload:
        case opc_iload:
        case opc_fload:
        case opc_lload:
        case opc_dload:
        case opc_istore:
        case opc_astore:
        case opc_fstore:
        case opc_lstore:
        case opc_dstore:
        case opc_ret:
            i += 4;
            break;

        case opc_iinc:
            i += 6;
            break;

        default:
            throw new DataFormatException( parent.className + "." +
            name.string + ": unknown wide " +
            "instruction: " + code[i+1] );
        }
        break;
        case opc_ldc:
        ldc[nldc++] = i;
        i += opcLengths[opcode];
        break;
        case opc_ldc_w:
        case opc_ldc2_w:
        case opc_getstatic:
        case opc_putstatic:
        case opc_getfield:
        case opc_putfield:
        case opc_invokevirtual:
        case opc_invokespecial:
        case opc_invokestatic:
        case opc_invokeinterface:
        case opc_new:
        case opc_anewarray:
        case opc_checkcast:
        case opc_instanceof:
        case opc_multianewarray:

            case opc_getstatic_fast:
            case opc_getstaticp_fast:
            case opc_getstatic2_fast:
            case opc_putstatic_fast:
            case opc_putstatic2_fast:
            case opc_invokevirtual_fast:
            case opc_invokespecial_fast:
            case opc_invokestatic_fast:
            case opc_invokeinterface_fast:
            case opc_new_fast:
            case opc_anewarray_fast:
            case opc_multianewarray_fast:
            case opc_checkcast_fast:
            case opc_instanceof_fast:
        wide[nwide++] = i;
        i += opcLengths[opcode];
        break;
        default: 
        i +=  opcLengths[opcode];
        break;
        }
    }
    // not knowing any better, we allocated excess capacity.
    // allocate and fill appropriately-sized arrays.
    ldcInstructions = new int[ nldc ];
    System.arraycopy( ldc, 0, ldcInstructions, 0, nldc );
    ldc = null;
    wideConstantRefInstructions = new int[ nwide ];
    System.arraycopy( wide, 0, wideConstantRefInstructions, 0, nwide );
    wide = null;
    
public ClassConstant[]getExceptionsThrown()

    return exceptionsThrown;
    
private static intgetInt(byte[] code, int w)

 
    return    (  (int)code[w]   << 24 ) |
        (( (int)code[w+1] &0xff ) << 16 ) |
        (( (int)code[w+2] &0xff ) << 8 ) |
         ( (int)code[w+3] &0xff );
    
public intgetInt(int w)

    return    getInt(code, w);
    
private java.lang.StringgetJNIName()

 
        ClassInfo ci = parent;
        String classname = ci.className;
    String methodname = this.name.string;
    int nmethods = ci.methods.length;
    String typeName = null;    // by default, don't need type
    for (int j = 0; j < nmethods; j ++ ){
        MethodInfo m = ci.methods[j];
        if ((m != this) && ( (m.access&Const.ACC_NATIVE) != 0 )) {
            if (m.name.equals(this.name)) {
            // Two native methods with the same name.  Need type name
            typeName = this.type.string;
            break;
        }
        }
    } 
    return Util.convertToJNIName(classname, methodname, typeName);
    
public java.util.BitSetgetLabelTargets()

 
        java.util.BitSet result = new java.util.BitSet();
    int ncode  = code.length;
    int nextpc;

    for(int pc = 0; pc < ncode; pc = nextpc) {
        nextpc = pc + opcodeLength(pc);
        int opcode = (int)code[pc]&0xff;
        switch (opcode) {
          
        case opc_tableswitch: 
        case opc_lookupswitch: 
            int i = (pc + 4) & ~3;
        int delta = (opcode == opc_tableswitch) ? 4 : 8;
        result.set(pc + getInt(i)); // default
        for (i = i + 12; i < nextpc; i += delta)
            result.set(pc + getInt(i));
        break;

        case opc_jsr: 
            result.set(pc + 3);
        case opc_goto:
        case opc_ifeq: case opc_ifge: case opc_ifgt:
        case opc_ifle: case opc_iflt: case opc_ifne:
        case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge: 
        case opc_if_icmplt: case opc_if_icmpgt: case opc_if_icmple: 
        case opc_if_acmpeq: case opc_if_acmpne:
        case opc_ifnull: case opc_ifnonnull:
            result.set(pc + getShort(pc + 1)); 
        break;

        case opc_jsr_w:
            result.set(pc + 5);
        case opc_goto_w:
            result.set(pc + getInt(pc + 1)); 
        break;
        }
    }
    return result;
    
public LineNumberTableEntry[]getLineNumberTable()

    if ( !checkedDebugTables ){
        initializeClassDebugTables();
        checkedDebugTables = true;
    }
    return lineNumberTable;
    
public LocalVariableTableEntry[]getLocalVariableTable()

    if ( !checkedDebugTables ){
        initializeClassDebugTables();
        checkedDebugTables = true;
    }
    return localVariableTable;
    
public java.lang.StringgetNativeName(boolean isJNI)

 
        if (nativeName == null) { 
        nativeName = isJNI ? getJNIName() : getOldNativeName();
    }
    return nativeName;
    
private java.lang.StringgetOldNativeName()

 
        ClassInfo ci = parent;
    String methodname = this.name.string;
    StringBuffer sbuf = new StringBuffer(/*NOI18N*/"Java_")
                              .append(ci.getGenericNativeName())
                              .append('_");
    if (methodname.indexOf('_") == -1) {
        // optimization.  Most methods don't have an _ in them
        sbuf.append(methodname);
    } else { 
        for (int i = 0; i < methodname.length(); i++) { 
          if (methodname.charAt(i) == '_") {
          sbuf.append(/*NOI18N*/"_0005f");
          } else {
          sbuf.append(methodname.charAt(i));
          }
        }
    }
    sbuf.append("_stub");
    return sbuf.toString();
    
public intgetShort(int w)

    return    (( (int)code[w]) << 8 ) | ( (int)code[w+1] &0xff );
    
public intgetUnsignedShort(int w)

    return    (( (int)code[w] &0xff ) << 8 ) | ( (int)code[w+1] &0xff );
    
public booleanhasLineNumberTable()

    if ( !checkedDebugTables ){
        initializeClassDebugTables();
        checkedDebugTables = true;
    }
    return (lineNumberTable != null) && (lineNumberTable.length != 0);
    
public booleanhasLocalVariableTable()

    if ( !checkedDebugTables ){
        initializeClassDebugTables();
        checkedDebugTables = true;
    }
    return (localVariableTable != null) && (localVariableTable.length != 0);
    
public voidinitializeClassDebugTables()

    int nattr = (codeAttributes == null) ? 0 : codeAttributes.length;
    // parse code attributes
    for (int i = 0; i < nattr; i++) {
        Attribute a = codeAttributes[i];
        if (a.name.string.equals("LineNumberTable")) {
        lineNumberTable = ((LineNumberTableAttribute)a).data;
        }
        if (a.name.string.equals("LocalVariableTable")) {
        localVariableTable = ((LocalVariableTableAttribute)a).data;
        }
        if (a.name.string.equals("StackMap")) {
        stackMapTable = ((StackMapAttribute)a).data;
        }

    }
    
public intnExceptionsThrown()

    return ( exceptionsThrown == null ) ? 0 : exceptionsThrown.length;
    
private static intopcodeLength(byte[] code, int pc)

        int old_pc;
    int opcode = (int)code[pc]&0xff;
        switch (opcode) {

    case opc_tableswitch: 
        old_pc = pc;
          pc = (pc + 4) & ~3;
        int low = getInt(code, pc + 4);
        int high = getInt(code, pc + 8);
        pc += (high - low + 1) * 4 + 12;
        return pc - old_pc;

    case opc_lookupswitch:
        old_pc = pc;
        pc = (pc + 4) & ~3;
        int pairs = getInt(code, pc + 4);
        pc += pairs * 8 + 8;
        return pc - old_pc;

    case opc_wide:
        if (((int)code[pc + 1]&0xff) == opc_iinc) 
            return 6;
        return 4;

    default:
        return opcLengths[opcode];
    }
    
public intopcodeLength(int pc)

 
        return opcodeLength(code, pc);
    
public static java.lang.StringopcodeName(int opcode)

 
    return opcNames[opcode];
    
private voidputInt(byte[] array, int offset, int val)

        array[offset] =   (byte) ((val >> 24) & 0xFF);
        array[offset+1] = (byte) ((val >> 16) & 0xFF);
        array[offset+2] = (byte) ((val >> 8) & 0xFF);
        array[offset+3] = (byte) (val & 0xFF);
    
private voidputShort(int w, short v)

    code[w]   = (byte)(v>>>8);
    code[w+1] = (byte)v;
    
voidreadAttributes(java.io.DataInput in, ConstantObject[] locals, ConstantObject[] globals, boolean readCode)


     
    methodAttributeTypes.put( "Code", CodeAttributeFactory.instance );
    methodAttributeTypes.put( "Exceptions", ExceptionsAttributeFactory.instance );
    

    methodAttributes = Attribute.readAttributes( in, locals, globals, methodAttributeTypes, false );

    // oops, we read the code.
    // we'll fix this someday.

    //
    // parse special attributes
    //
    if ( methodAttributes != null ){
        for ( int i = 0; i < methodAttributes.length; i ++ ){
        Attribute a = methodAttributes[i];
        if (a.name.string.equals("Code") ) {
            CodeAttribute ca = (CodeAttribute)a;
            this.locals = ca.locals;
            this.stack  = ca.stack;
            this.code   = ca.code;
            this.exceptionTable = ca.exceptionTable;
            this.codeAttributes = ca.codeAttributes;
            this.codeAttribute = ca;
        } else if (a.name.string.equals("Exceptions") ) {
            this.exceptionsThrown = ((ExceptionsAttribute)a).data;
        }
        }
    }

    
public static components.MethodInforeadMethod(java.io.DataInput in, ClassInfo p, boolean readCode)

    int access = in.readUnsignedShort();
    int name   = in.readUnsignedShort();
    int sig    = in.readUnsignedShort();
    MethodInfo m = new MethodInfo( name, sig, access, p );
    // the bad thing is, we really cannot go far
    // without resolving. So we resolve here.
    m.resolve( p.symbols );

    m.argsSize = Util.argsSize(m.type.string);
    if ((m.access & ACC_STATIC) == 0) {
        m.argsSize++;
    }

    m.readAttributes( in, p.constants, p.symbols, readCode );
    return m;
    
public voidrelocateAndPackCode(ConstantObject[] co)


        if (code == null)
            return;

        int opcode, adjustment = 0;
        int newOffsets[] = new int[code.length];
        int indexByPC[] = new int[code.length];

        // First figure out where we'll have to insert extra bytes in
        // order to fit opc_ldc_w instead of opc_ldc instructions.
        for (int pc = 0, pcindex = 0; pc < code.length;
         pc = pc + opcodeLength(pc), pcindex++) {
            opcode = (int) code[pc]&0xFF;
            newOffsets[pcindex] = pc + adjustment;
            indexByPC[pc] = pcindex;

          /*******
           * switch (opcode) {
           *    case opc_ldc: {
           *        // a conversion table which maps pcValue to new index.
           *        int oldindex = (int)(code[pc+1] & 0xFF);
           *        int index = co[oldindex].index;
           *
           *        if (index >= 0x100)
           *            adjustment++;
           *        break;
           *    }
           *
           *
       *  case opc_ldc_w: {
       *      // a conversion table which maps pcValue to new index.
           *      int oldindex = (int)(((code[pc+1]&0xFF) << 8)
       *             | (code[pc+2]&0xFF));
       *      int index = co[oldindex].index;
           *
           *      if (index < 0x100)
           *          adjustment--;
           *      break;
           *  }
           *
           *
           *
           *  case opc_goto: {
           *      // Calculate the displacement, sign extend high byte
           *      int displ = (code[pc+1] << 8) | (code[pc+2] & 0xFF);
           *
       *      if (displ == 3) {
       *          adjustment -= 3; // remove no-use goto's.
       *      }
       *      break;
       *  }
           *
       *  case opc_nop: {
       *      adjustment--; // remove
       *      break;
       *  }
           *
           *
       *  case opc_tableswitch:
       *  case opc_lookupswitch: {
       *      int oldExtraPC = (( pc + 4 ) & ~3);
       *      int newExtraPC = (( pc + adjustment + 4) & ~3);
       *      adjustment = newExtraPC - oldExtraPC;
       *      break;
       *  }
           * }
           *******/
        }

        // Now copy the code to the new location. At the same
        // time, we adjust all branch targets.
        byte newCode[] = new byte[code.length + adjustment];

        for (int pc = 0, pcindex = 0; pc < code.length;
         pc = pc + opcodeLength(pc), pcindex++) {
            int outPos = newOffsets[pcindex];
        int inPos = pc;

        opcode = (int) code[pc]&0xFF;

            for (int i = 0; i < opcodeLength(pc); i++) {
                newCode[outPos + i] = code[pc + i];
            }

            switch (opcode) {
          case opc_ldc: {
          int oldindex = (int)(code[pc+1] & 0xFF);
                  int index = co[oldindex].index;
                  if (index >= 0x100) {
                      new RuntimeException("load constant overflow");
                  }
                  newCode[outPos +1] = (byte) index ;
                  break;
              }

         /****
      *   // Remapping branches
      *   case opc_ifeq:
          *   case opc_ifne:
          *   case opc_iflt:
          *   case opc_ifge:
          *   case opc_ifgt:
          *   case opc_ifle:
          *   case opc_if_icmpeq:
          *   case opc_if_icmpne:
          *   case opc_if_icmplt:
          *   case opc_if_icmpge:
          *   case opc_if_icmpgt:
          *   case opc_if_icmple:
          *   case opc_if_acmpeq:
          *   case opc_if_acmpne:
          *   case opc_ifnull:
          *   case opc_ifnonnull:
          *   case opc_goto:
          *   case opc_jsr: {
          *       // Calculate the displacement, sign extend high byte
          *       int displ = (code[pc+1] << 8) | (code[pc+2] & 0xFF);
          *
          *      *  if (displ == 3 && opcode == opc_goto) {
      *      *     break;
      *      * }
          *

          *       int branchDest = pc + displ;
          *
      *       if ((code[branchDest] & 0xFF) == opc_goto) {
          *           // We're branching to a goto.  We can just branch to
      *           // where the goto was going.
      *           branchDest +=
      *         (code[branchDest+1] << 8) | (code[branchDest+2] & 0xFF);
      *       }
          *       int newDest = newOffsets[indexByPC[branchDest]] - outPos;
          *       newCode[outPos+1] = (byte) ((newDest >> 8) & 0xFF);
          *       newCode[outPos+2] = (byte) (newDest & 0xFF);
          *       break;
          *   }
          *
      *   case opc_tableswitch: {
      *       newCode[outPos] = code[pc];
      *       outPos = (outPos + 4) & ~3;
      *       inPos = (inPos + 4) & ~3;
          *
      *       // Update the default destination
      *       int oldDest = getInt(inPos) + pc;
      *       int newDest = newOffsets[indexByPC[oldDest]]
      *             - newOffsets[pcindex];
      *       putInt(newCode, outPos, newDest);
          *
      *       // Update each of the destinations in the table
      *       int low = getInt(inPos+4);
      *       int high = getInt(inPos+8);
      *       putInt(newCode, outPos+4, low);
      *       putInt(newCode, outPos+8, high);
      *       for (int j = 0; j <= high-low; j++) {
          *           int offset = j * 4 + 12;
          *           oldDest = getInt(inPos + offset) + pc;
          *           newDest = newOffsets[indexByPC[oldDest]]
      *             - newOffsets[pcindex];
      *           putInt(newCode, outPos + offset, newDest);
          *       }
      *       break;
          *   }
          *
      *   case opc_lookupswitch: {
      *       newCode[outPos] = code[pc];
      *       // 0-3 byte pads
      *       outPos = (outPos + 4) & ~3;
      *       inPos = (inPos + 4) & ~3;
          *
      *       // Update the default destination
          *       int oldDest = getInt(inPos) + pc;
          *       int newDest = newOffsets[indexByPC[oldDest]]
      *                 - newOffsets[pcindex];
          *       putInt(newCode, outPos, newDest);
          *
          *       // Update each of the pairs of destinations in the list
          *       int pairs = getInt(inPos+4);
          *       putInt(newCode, outPos+4, pairs);
          *       for (int j = 0; j < pairs; j++) {
          *           int offset = (j + 1) * 8;
          *
          *           // First copy the value
          *           putInt(newCode, outPos + offset,
          *                  getInt(inPos + offset));
          *           offset += 4;
          *
          *           // Now adjust the destination
          *           oldDest = getInt(inPos + offset) + pc;
          *           newDest = newOffsets[indexByPC[oldDest]]
      *             - newOffsets[pcindex];
          *           putInt(newCode, outPos + offset, newDest);
          *       }
      *       break;
      *   }
          ********/

          // Byte-codes with constant pool access. Remap to new indices
          case opc_getfield:
          case opc_checkcast:
          case opc_getstatic:
          case opc_instanceof:
          case opc_ldc2_w:
          case opc_new:
          case opc_putfield:
          case opc_putstatic:
          case opc_invokevirtual:
          case opc_invokestatic:
          case opc_invokespecial:
              case opc_getstatic_fast:
              case opc_getstaticp_fast:
              case opc_getstatic2_fast:
              case opc_putstatic_fast:
              case opc_putstatic2_fast:
              case opc_invokevirtual_fast:
              case opc_invokespecial_fast:
              case opc_invokestatic_fast:
              case opc_anewarray_fast:
              case opc_checkcast_fast:
              case opc_instanceof_fast:
          case opc_multianewarray:
          case opc_multianewarray_fast:
          case opc_invokeinterface:
           case opc_invokeinterface_fast:
              case opc_ldc_w: {
          int oldindex = (int)(((code[pc+1]&0xFF) << 8)
                                   | (code[pc+2]&0xFF));
                  int index = co[oldindex].index;
          newCode[outPos] = (byte) opcode;
          newCode[outPos+1] = (byte) ((index >> 8) & 0xFF);
                  newCode[outPos+2] = (byte) (index & 0xFF);
                  break;
          }
            }
        }

        // Update the exception table
        for (int i = 0; i < exceptionTable.length; i++) {
            ExceptionEntry e = exceptionTable[i];
            e.startPC = newOffsets[indexByPC[e.startPC]];
            e.endPC = newOffsets[indexByPC[e.endPC]];
            e.handlerPC = newOffsets[indexByPC[e.handlerPC]];
        }

        // Update the line number table
    LineNumberTableEntry[] lntab = getLineNumberTable();
        if (lntab != null) {
            for (int i = 0; i < lntab.length; i++) {
                LineNumberTableEntry e = lntab[i];
                e.startPC = newOffsets[indexByPC[e.startPC]];
            }
        }

        // Update the line number table
    LocalVariableTableEntry[] locvartab = getLocalVariableTable();
        if (locvartab != null) {
            for (int i = 0; i < locvartab.length; i++) {
                LocalVariableTableEntry e = locvartab[i];
                e.pc0 = newOffsets[indexByPC[e.pc0]];
            }
        }

    // Update the stack maps
    if (stackMapTable != null) {
        for (int i = 0; i < stackMapTable.length; i++) {
        StackMapFrame frame = stackMapTable[i];
        frame.offset = newOffsets[indexByPC[frame.offset]];
        }
    }
        // make the changes permanent
    code = newCode;
    
public voidrelocateConstantReferences(ConstantObject[] table)

    if ( code == null ) return; // no code, no relocation
    if ( ldcInstructions != null ){
        int list[] = ldcInstructions;
        int n = list.length;
        for (int i = 0; i < n; i++){
        int j = list[i]+1;
        if ( j <= 0 ) continue;
        ConstantObject c = table[ (int)code[j]&0xff ];
        if ( c.shared )
            throw new DataFormatException("code reference to shared constant");
        int v = c.index;
        if ( v < 0 )
            throw new DataFormatException("code reference to deleted constant at "+qualifiedName()+"+"+Integer.toHexString(j));
        if ( v > 255 )
            throw new DataFormatException("ldc subscript out of range at "+qualifiedName()+"+"+Integer.toHexString(j));
        code[j] = (byte)v;
        }
    }
    if ( wideConstantRefInstructions != null ){
        int list[] = wideConstantRefInstructions;
        int n = list.length;
        for (int i = 0; i < n; i++){
        int j = list[i]+1;
        if ( j <= 0 ) continue;
        ConstantObject c = table[ getUnsignedShort(j) ];
        if ( c.shared )
            throw new DataFormatException("code reference to shared constant at "+qualifiedName()+"+"+Integer.toHexString(j));
        int v = c.index;
        if ( v < 0 )
            throw new DataFormatException("code reference to deleted constant at "+qualifiedName()+"+"+Integer.toHexString(j));
        putShort( j, (short)v );
        }
    }
    
public voidreplaceCode(int start, int end)

 
    replaceCode(start, end, new byte[0]);
    
public voidreplaceCode(int start, int end, int op1)

 
    byte code[] = { (byte)op1 };
    replaceCode(start, end, code);
    
public voidreplaceCode(int start, int end, int op1, int op2)

 
    byte code[] = { (byte)op1, (byte)op2 };
    replaceCode(start, end, code);
    
public voidreplaceCode(int start, int end, int op1, int op2, int op3)

 
    byte code[] = { (byte)op1, (byte)op2, (byte)op3 };
    replaceCode(start, end, code);
    
public voidreplaceCode(int start, int end, byte[] replaceCode)

 
        if (end - start < replaceCode.length) { 
        // System.out.println("  Cannot yet do expansion!!");
        return;
    }
        if (exceptionTable != null && exceptionTable.length > 0) {   
        for (int i = 0; i < exceptionTable.length; i++) { 
           int startPC = exceptionTable[i].startPC;
           int endPC = exceptionTable[i].endPC;
           if (startPC >= start && startPC < end) 
           return;
           if (endPC >= start && endPC < end) 
           return;
        }
    }
    int startExtra = start + replaceCode.length;
    int extra = end - startExtra;
    
    System.arraycopy(replaceCode, 0, code, start, replaceCode.length);

    for (int i = startExtra; i < end; i++) 
        code[i] = (byte)opc_nop;
    
private static final intshortAt(byte[] codeBytes, int index)
Return the short stored at a given index from the offset within code bytes

        return ((codeBytes[index] & 0xFF) << 8) 
            | (codeBytes[index+1] & 0xFF);
    
public booleanthrowsExceptions()

    return exceptionsThrown != null;
    
public java.lang.StringtoString()

    String r = "Method: "+super.toString();
    if ( code != null ){
        r += " {"+code.length+" bytes of code}";
    }
    return r;
    
public voidwrite(java.io.DataOutput o)

    o.writeShort( access );
    o.writeShort( name.index );
    o.writeShort( type.index );
    Attribute.writeAttributes( methodAttributes, o, false );