BytecodeInfo.java :  » Development » jode » jode » bytecode » Java Open Source

Java Open Source » Development » jode 
jode » jode » bytecode » BytecodeInfo.java
/* BytecodeInfo Copyright (C) 1999-2002 Jochen Hoenicke.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; see the file COPYING.LESSER.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: BytecodeInfo.java.in,v 4.9.2.8 2002/06/11 08:40:31 hoenicke Exp $
 */

package jode.bytecode;
import jode.GlobalOptions;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.BitSet;
import java.util.Stack;
import java.util.Vector;
import java.util.Enumeration;
import java.util.NoSuchElementException;

import java.util.List;
import java.util.AbstractSequentialList;
import java.util.Iterator;
import java.util.ListIterator;


/**
 * This class represents the byte code of a method.  Each instruction is
 * stored in an Instruction instance.
 *
 * We canonicalize some opcodes:  wide opcodes are mapped to short ones,
 * opcodes that load a constant are mapped to opc_ldc or opc_ldc2_w, and
 * opc_xload_x / opc_xstore_x opcodes are mapped to opc_xload / opc_xstore.
 */
public class BytecodeInfo extends BinaryInfo implements Opcodes {

    private MethodInfo methodInfo;
    private int maxStack, maxLocals;
    private Handler[] exceptionHandlers;
    private LocalVariableInfo[] lvt;
    private LineNumber[] lnt;
    
    /**
     * A array of instructions, indexed by address.  This array is only
     * valid while reading the code.
     */
    private Instruction[] instrs;

    private InstructionList instructions;

    private class InstructionList extends AbstractSequentialList {
  Instruction borderInstr;
  int instructionCount = 0;

  InstructionList() {
      // opc_impdep1 is used as border instruction, it may not
      // occur in bytecode.
      borderInstr = new Instruction(opc_impdep1);
      borderInstr.nextByAddr = borderInstr.prevByAddr = borderInstr;
  }

  public int size() {
      return instructionCount;
  }

  Instruction get0(int index) {
      Instruction instr = borderInstr;
      if (index < instructionCount / 2) {
    for (int i=0; i <= index; i++)
        instr = instr.nextByAddr;
      } else {
    for (int i=instructionCount; i > index; i--)
        instr = instr.prevByAddr;
      }
      return instr;
  }

  public Object get(int index) {
      if (index < 0 || index >= instructionCount)
    throw new IllegalArgumentException();
      return get0(index);
  }

  public boolean add(Object o) {
      /* optimize add, since it is called many times by read() */
      instructionCount++;
      borderInstr.prevByAddr.appendInstruction((Instruction) o,
                 BytecodeInfo.this);
      return true;
  }

  public ListIterator listIterator(final int startIndex) {
      if (startIndex < 0 || startIndex > instructionCount)
    throw new IllegalArgumentException();
      return new ListIterator() {
    Instruction instr = get0(startIndex);
    Instruction toRemove = null;
    int index = startIndex;
    
    public boolean hasNext() {
        return index < instructionCount;
    }

    public boolean hasPrevious() {
        return index > 0;
    }
    
    public Object next() {
        if (index >= instructionCount)
      throw new NoSuchElementException();
        index++;
        toRemove = instr;
        instr = instr.nextByAddr;
//          System.err.println("next: "+toRemove.getDescription());
        return toRemove;
    }

    public Object previous() {
        if (index == 0)
      throw new NoSuchElementException();
        index--;
        instr = instr.prevByAddr;
        toRemove = instr;
//          System.err.println("prev: "+toRemove.getDescription());
        return toRemove;
    }

    public int nextIndex() {
        return index;
    }

    public int previousIndex() {
        return index - 1;
    }
    
    public void remove() {
        if (toRemove == null)
      throw new IllegalStateException();
//          System.err.println("remove: "+toRemove.getDescription());
        instructionCount--;
        if (instr == toRemove)
      instr = instr.nextByAddr;
        else
      index--;
        toRemove.removeInstruction(BytecodeInfo.this);
        toRemove = null;
    }

    public void add(Object o) {
        instructionCount++;
        index++;
//          System.err.println("add: "
//                 +((Instruction)o).getDescription()
//                 +" after "+instr.prevByAddr
//                 .getDescription());
        instr.prevByAddr.appendInstruction((Instruction) o,
                   BytecodeInfo.this);
        toRemove = null;
    }

    public void set(Object o) {
        if (toRemove == null)
      throw new IllegalStateException();
//          System.err.println("replace "+toRemove.getDescription()
//                 +" with "
//                 +((Instruction)o).getDescription());
        toRemove.replaceInstruction((Instruction) o, 
            BytecodeInfo.this);
        if (instr == toRemove)
      instr = (Instruction) o;
        toRemove = (Instruction) o;
    }
      };
  }

  void setLastAddr(int addr) {
      borderInstr.setAddr(addr);
  }

  int getCodeLength() {
      return borderInstr.getAddr();
  }
    }

    public BytecodeInfo(MethodInfo mi) {
  methodInfo = mi;
    }

    private final static Object[] constants = {
  null, 
  new Integer(-1), new Integer(0), new Integer(1), 
  new Integer(2), new Integer(3), new Integer(4), new Integer(5),
  new Long(0), new Long(1), 
  new Float(0), new Float(1), new Float(2),
  new Double(0), new Double(1)
    };

    protected void readAttribute(String name, int length, ConstantPool cp,
         DataInputStream input, 
         int howMuch) throws IOException {
  if ((howMuch & KNOWNATTRIBS) != 0 
      && name.equals("LocalVariableTable")) {
      if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) 
    GlobalOptions.err.println("LocalVariableTable of "+methodInfo);
            int count = input.readUnsignedShort();
      if (length != 2 + count * 10) {
    if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) 
        GlobalOptions.err.println("Illegal LVT length, ignoring it");
    return;
      }
      lvt = new LocalVariableInfo[count];
            for (int i=0; i < count; i++) {
    lvt[i] = new LocalVariableInfo();
                int start  = input.readUnsignedShort();
                int end    = start + input.readUnsignedShort();
    int nameIndex = input.readUnsignedShort();
    int typeIndex = input.readUnsignedShort();
    int slot = input.readUnsignedShort();
    Instruction startInstr = 
        start >= 0 && start < instrs.length ? instrs[start] : null;
    Instruction endInstr;
    if (end >=0 && end < instrs.length)
        endInstr = instrs[end] == null ? null
      : instrs[end].getPrevByAddr();
    else {
        endInstr = null;
        for (int nr = instrs.length - 1; nr >= 0; nr--) {
      if (instrs[nr] != null) {
          if (instrs[nr].getNextAddr() == end)
        endInstr = instrs[nr];
          break;
      }
        }
    }

    if (startInstr == null
        || endInstr == null
        || nameIndex == 0 || typeIndex == 0
        || slot >= maxLocals
        || cp.getTag(nameIndex) != cp.UTF8
        || cp.getTag(typeIndex) != cp.UTF8) {

        // This is probably an evil lvt as created by HashJava
        // simply ignore it.
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_LVT) != 0) 
      GlobalOptions.err.println
          ("Illegal entry, ignoring LVT");
        lvt = null;
        return;
    }
    lvt[i].start = startInstr;
    lvt[i].end = endInstr;
    lvt[i].name = cp.getUTF8(nameIndex);
                lvt[i].type = cp.getUTF8(typeIndex);
                lvt[i].slot = slot;
                if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
                    GlobalOptions.err.println("\t" + lvt[i].name + ": "
             + lvt[i].type
             +" range "+start+" - "+end
             +" slot "+slot);
            }
  } else if ((howMuch & KNOWNATTRIBS) != 0 
       && name.equals("LineNumberTable")) {
      int count = input.readUnsignedShort();
      if (length != 2 + count * 4) {
    GlobalOptions.err.println
        ("Illegal LineNumberTable, ignoring it");
    return;
      }
      lnt = new LineNumber[count];
      for (int i = 0; i < count; i++) {
    lnt[i] = new LineNumber();
    int start = input.readUnsignedShort();
    Instruction startInstr = instrs[start];
    if (startInstr == null) {
        GlobalOptions.err.println
      ("Illegal entry, ignoring LineNumberTable table");
        lnt = null;
        return;
    }
    lnt[i].start = startInstr;
    lnt[i].linenr = input.readUnsignedShort();
      }
  } else
      super.readAttribute(name, length, cp, input, howMuch);
    }

    public void read(ConstantPool cp, 
         DataInputStream input) throws IOException {
        maxStack = input.readUnsignedShort();
        maxLocals = input.readUnsignedShort();
  instructions = new InstructionList();
        int codeLength = input.readInt();
  instrs = new Instruction[codeLength];
  int[][] succAddrs = new int[codeLength][];
  {
      int addr = 0;
      while (addr < codeLength) {
    Instruction instr;
    int length;
    int opcode = input.readUnsignedByte();
    if ((GlobalOptions.debuggingFlags
         & GlobalOptions.DEBUG_BYTECODE) != 0) 
    if ((GlobalOptions.debuggingFlags
         & GlobalOptions.DEBUG_BYTECODE) != 0) 
        GlobalOptions.err.print(addr+": "+opcodeString[opcode]);

    switch (opcode) {
    case opc_wide: {
        int wideopcode = input.readUnsignedByte();
        switch (wideopcode) {
        case opc_iload: case opc_fload: case opc_aload:
        case opc_istore: case opc_fstore: case opc_astore: {
      int slot = input.readUnsignedShort();
      if (slot >= maxLocals)
          throw new ClassFormatError
        ("Invalid local slot "+slot);
      instr = new Instruction(wideopcode);
      instr.setLocalSlot(slot);
      length = 4;
      if ((GlobalOptions.debuggingFlags
           & GlobalOptions.DEBUG_BYTECODE) != 0) 
          GlobalOptions.err.print
        (" " + opcodeString[wideopcode] + " " + slot);
      break;
        }
        case opc_lload: case opc_dload:
        case opc_lstore: case opc_dstore: {
      int slot = input.readUnsignedShort();
      if (slot >= maxLocals-1)
          throw new ClassFormatError
        ("Invalid local slot "+slot);
      instr = new Instruction(wideopcode);
      instr.setLocalSlot(slot);
      length = 4;
      if ((GlobalOptions.debuggingFlags
           & GlobalOptions.DEBUG_BYTECODE) != 0) 
          GlobalOptions.err.print
        (" " + opcodeString[wideopcode] + " " + slot);
      break;
        }
        case opc_ret: {
      int slot = input.readUnsignedShort();
      if (slot >= maxLocals)
          throw new ClassFormatError
        ("Invalid local slot "+slot);
      instr = new Instruction(wideopcode);
      instr.setLocalSlot(slot);
      length = 4;
      if ((GlobalOptions.debuggingFlags
           & GlobalOptions.DEBUG_BYTECODE) != 0) 
          GlobalOptions.err.print(" ret "+slot);
      break;
        }
        case opc_iinc: {
      int slot = input.readUnsignedShort();
      if (slot >= maxLocals)
          throw new ClassFormatError
        ("Invalid local slot "+slot);
      instr = new Instruction(wideopcode);
      instr.setLocalSlot(slot);
      instr.setIncrement(input.readShort());
      length = 6;
      if ((GlobalOptions.debuggingFlags
           & GlobalOptions.DEBUG_BYTECODE) != 0) 
          GlobalOptions.err.print
        (" iinc " + slot + " " + instr.getIncrement());
      break;
        }
        default:
      throw new ClassFormatError("Invalid wide opcode "
               +wideopcode);
        }
        break;
    }
    case opc_iload_0: case opc_iload_1:
    case opc_iload_2: case opc_iload_3:
    case opc_lload_0: case opc_lload_1:
    case opc_lload_2: case opc_lload_3:
    case opc_fload_0: case opc_fload_1:
    case opc_fload_2: case opc_fload_3:
    case opc_dload_0: case opc_dload_1:
    case opc_dload_2: case opc_dload_3:
    case opc_aload_0: case opc_aload_1:
    case opc_aload_2: case opc_aload_3: {
        int slot = (opcode-opc_iload_0) & 3;
        if (slot >= maxLocals)
      throw new ClassFormatError
          ("Invalid local slot "+slot);
        instr = new Instruction(opc_iload + 
              (opcode-opc_iload_0)/4);
        instr.setLocalSlot(slot);
        length = 1;
        break;
    }
    case opc_istore_0: case opc_istore_1: 
    case opc_istore_2: case opc_istore_3:
    case opc_fstore_0: case opc_fstore_1:
    case opc_fstore_2: case opc_fstore_3:
    case opc_astore_0: case opc_astore_1:
    case opc_astore_2: case opc_astore_3: {
        int slot = (opcode-opc_istore_0) & 3;
        if (slot >= maxLocals)
      throw new ClassFormatError
          ("Invalid local slot "+slot);
        instr = new Instruction(opc_istore + 
               (opcode-opc_istore_0)/4);
        instr.setLocalSlot(slot);
        length = 1;
        break;
    }
    case opc_lstore_0: case opc_lstore_1: 
    case opc_lstore_2: case opc_lstore_3:
    case opc_dstore_0: case opc_dstore_1:
    case opc_dstore_2: case opc_dstore_3: {
        int slot = (opcode-opc_istore_0) & 3;
        if (slot >= maxLocals-1)
      throw new ClassFormatError
          ("Invalid local slot "+slot);
        instr = new Instruction(opc_istore
               + (opcode-opc_istore_0)/4);
        instr.setLocalSlot(slot);
        length = 1;
        break;
    }
    case opc_iload: case opc_fload: case opc_aload:
    case opc_istore: case opc_fstore: case opc_astore: {
        int slot = input.readUnsignedByte();
        if (slot >= maxLocals)
      throw new ClassFormatError
          ("Invalid local slot "+slot);
        instr = new Instruction(opcode);
        instr.setLocalSlot(slot);
        length = 2;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+slot);
        break;
    }
    case opc_lstore: case opc_dstore:
    case opc_lload: case opc_dload: {
        int slot = input.readUnsignedByte();
        if (slot >= maxLocals - 1)
      throw new ClassFormatError
          ("Invalid local slot "+slot);
        instr = new Instruction(opcode);
        instr.setLocalSlot(slot);
        length = 2;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+slot);
        break;
    }
    case opc_ret: {
        int slot = input.readUnsignedByte();
        if (slot >= maxLocals)
      throw new ClassFormatError
          ("Invalid local slot "+slot);
        instr = new Instruction(opcode);
        instr.setLocalSlot(slot);
        length = 2;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+slot);
        break;
    }
    case opc_aconst_null:
    case opc_iconst_m1: 
    case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
    case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
    case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
        instr = new Instruction(opc_ldc);
        instr.setConstant
      (constants[opcode - opc_aconst_null]);
        length = 1;
        break;
    case opc_lconst_0: case opc_lconst_1:
    case opc_dconst_0: case opc_dconst_1:
        instr = new Instruction(opc_ldc2_w);
        instr.setConstant
      (constants[opcode - opc_aconst_null]);
        length = 1;
        break;
    case opc_bipush:
        instr = new Instruction(opc_ldc);
        instr.setConstant(new Integer(input.readByte()));
        length = 2;
        break;
    case opc_sipush:
        instr = new Instruction(opc_ldc);
        instr.setConstant(new Integer(input.readShort()));
        length = 3;
        break;
    case opc_ldc: {
        int index = input.readUnsignedByte();
        int tag = cp.getTag(index);
        if (tag != cp.STRING
       && tag != cp.INTEGER && tag != cp.FLOAT)
      throw new ClassFormatException
          ("wrong constant tag: "+tag);
        instr = new Instruction(opcode);
        instr.setConstant(cp.getConstant(index));
        length = 2;
        break;
    }
    case opc_ldc_w: {
        int index = input.readUnsignedShort();
        int tag = cp.getTag(index);
        if (tag != cp.STRING
       && tag != cp.INTEGER && tag != cp.FLOAT)
      throw new ClassFormatException
          ("wrong constant tag: "+tag);
        instr = new Instruction(opc_ldc);
        instr.setConstant(cp.getConstant(index));
        length = 3;
        break;
    }
    case opc_ldc2_w: {
        int index = input.readUnsignedShort();
        int tag = cp.getTag(index);
        if (tag != cp.LONG && tag != cp.DOUBLE)
      throw new ClassFormatException
          ("wrong constant tag: "+tag);
        instr = new Instruction(opcode);
        instr.setConstant(cp.getConstant(index));
        length = 3;
        break;
    }
    case opc_iinc: {
        int slot = input.readUnsignedByte();
        if (slot >= maxLocals)
      throw new ClassFormatError
          ("Invalid local slot "+slot);
        instr = new Instruction(opcode);
        instr.setLocalSlot(slot);
        instr.setIncrement(input.readByte());
        length = 3;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print
          (" " + slot + " " + instr.getIncrement());
        break;
    }
    case opc_goto:
    case opc_jsr:
    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:
        instr = new Instruction(opcode);
        length = 3;
        succAddrs[addr] = new int[] { addr+input.readShort() };
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+succAddrs[addr][0]);
        break;

    case opc_goto_w:
    case opc_jsr_w:
        instr = new Instruction(opcode - (opc_goto_w - opc_goto));
        length = 5;
        succAddrs[addr] = new int[] { addr+input.readInt() };
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+succAddrs[addr][0]);
        break;

    case opc_tableswitch: {
        length = 3 - (addr % 4);
        input.readFully(new byte[length]);
        int def  = input.readInt();
        int low  = input.readInt();
        int high = input.readInt();
        int[] dests = new int[high-low+1];
        int npairs = 0;
        for (int i=0; i < dests.length; i++) {
      dests[i] = input.readInt();
      if (dests[i] != def)
          npairs++;
        }
        instr = new Instruction(opc_lookupswitch);
        succAddrs[addr] = new int[npairs + 1];
        int[] values = new int[npairs];
        int pos = 0;
        for (int i=0; i < dests.length; i++) {
      if (dests[i] != def) {
          values[pos] = i+low;
          succAddrs[addr][pos] = addr + dests[i];
          pos++;
      }
        }
        succAddrs[addr][npairs] = addr + def;
        instr.setValues(values);
        length += 13 + 4 * (high-low+1);
        break;
    }
    case opc_lookupswitch: {
        length = 3 - (addr % 4);
        input.readFully(new byte[length]);
        int def = input.readInt();
        int npairs = input.readInt();
        instr = new Instruction(opcode);
        succAddrs[addr] = new int[npairs + 1];
        int[] values = new int[npairs];
        for (int i=0; i < npairs; i++) {
      values[i] = input.readInt();
      if (i > 0 && values[i-1] >= values[i])
          throw new ClassFormatException
        ("lookupswitch not sorted");
      succAddrs[addr][i] = addr + input.readInt();
        }
        succAddrs[addr][npairs] = addr + def;
        instr.setValues(values);
        length += 9 + 8 * npairs;
        break;
    }
          
    case opc_getstatic:
    case opc_getfield:
    case opc_putstatic:
    case opc_putfield:
    case opc_invokespecial:
    case opc_invokestatic:
    case opc_invokevirtual: {
        int index = input.readUnsignedShort();
        int tag = cp.getTag(index);
        if (opcode < opc_invokevirtual) {
      if (tag != cp.FIELDREF)
          throw new ClassFormatException
        ("field tag mismatch: "+tag);
        } else {
      if (tag != cp.METHODREF)
          throw new ClassFormatException
        ("method tag mismatch: "+tag);
        }
        Reference ref = cp.getRef(index);
        if (ref.getName().charAt(0) == '<'
      && (!ref.getName().equals("<init>")
          || opcode != opc_invokespecial))
      throw new ClassFormatException
          ("Illegal call of special method/field "+ref);
        instr = new Instruction(opcode);
        instr.setReference(ref);
        length = 3;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+ref);
        break;
    }
    case opc_invokeinterface: {
        int index = input.readUnsignedShort();
        int tag = cp.getTag(index);
        if (tag != cp.INTERFACEMETHODREF)
      throw new ClassFormatException
          ("interface tag mismatch: "+tag);
        Reference ref = cp.getRef(index);
        if (ref.getName().charAt(0) == '<')
      throw new ClassFormatException
          ("Illegal call of special method "+ref);
        int nargs = input.readUnsignedByte();
        if (TypeSignature.getArgumentSize(ref.getType())
      != nargs - 1)
      throw new ClassFormatException
          ("Interface nargs mismatch: "+ref+" vs. "+nargs);
        if (input.readUnsignedByte() != 0)
      throw new ClassFormatException
          ("Interface reserved param not zero");

        instr = new Instruction(opcode);
        instr.setReference(ref);
        length = 5;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+ref);
        break;
    }

    case opc_new:
    case opc_checkcast:
    case opc_instanceof: {
        String type = cp.getClassType(input.readUnsignedShort());
        if (opcode == opc_new && type.charAt(0) == '[')
      throw new ClassFormatException
          ("Can't create array with opc_new");
        instr = new Instruction(opcode);
        instr.setClazzType(type);
        length = 3;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+type);
        break;
    }
    case opc_multianewarray: {
        String type = cp.getClassType(input.readUnsignedShort());
        int dims = input.readUnsignedByte();
        if (dims == 0)
      throw new ClassFormatException
          ("multianewarray dimension is 0.");
        for (int i=0; i < dims; i++) {
      /* Note that since type is a valid type
       * signature, there must be a non bracket
       * character, before the string is over.  
       * So there is no StringIndexOutOfBoundsException.
       */
      if (type.charAt(i) != '[')
          throw new ClassFormatException
        ("multianewarray called for non array:"+ type);
        }
        instr = new Instruction(opcode);
        instr.setClazzType(type);
        instr.setDimensions(dims);
        length = 4;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" " + type + " " + dims);
        break;
    }
    case opc_anewarray: {
        String type = cp.getClassType(input.readUnsignedShort());
        instr = new Instruction(opc_multianewarray);
        instr.setClazzType(("["+type).intern());
        instr.setDimensions(1);
        length = 3;
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+type);
        break;
    }
    case opc_newarray: {
        char sig = newArrayTypes.charAt
      (input.readUnsignedByte()-4);
        String type = new String (new char[] { '[', sig });
        if ((GlobalOptions.debuggingFlags
       & GlobalOptions.DEBUG_BYTECODE) != 0) 
      GlobalOptions.err.print(" "+type);
        instr = new Instruction(opc_multianewarray);
        instr.setClazzType(type);
        instr.setDimensions(1);
        length = 2;
        break;
    }
    
    case opc_nop:
    case opc_iaload: case opc_laload: case opc_faload:
    case opc_daload: case opc_aaload:
    case opc_baload: case opc_caload: case opc_saload:
    case opc_iastore: case opc_lastore: case opc_fastore:
    case opc_dastore: case opc_aastore:
    case opc_bastore: case opc_castore: case opc_sastore:
    case opc_pop: case opc_pop2:
    case opc_dup: case opc_dup_x1: case opc_dup_x2:
    case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
    case opc_swap:
    case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
    case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
    case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
    case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
    case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
    case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
    case opc_ishl: case opc_lshl:
    case opc_ishr: case opc_lshr:
    case opc_iushr: case opc_lushr: 
    case opc_iand: case opc_land:
    case opc_ior: case opc_lor: 
    case opc_ixor: case opc_lxor:
    case opc_i2l: case opc_i2f: case opc_i2d:
    case opc_l2i: case opc_l2f: case opc_l2d:
    case opc_f2i: case opc_f2l: case opc_f2d:
    case opc_d2i: case opc_d2l: case opc_d2f:
    case opc_i2b: case opc_i2c: case opc_i2s:
    case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
    case opc_dcmpl: case opc_dcmpg:
    case opc_ireturn: case opc_lreturn: 
    case opc_freturn: case opc_dreturn: case opc_areturn:
    case opc_return: 
    case opc_athrow:
    case opc_arraylength:
    case opc_monitorenter: case opc_monitorexit:
        instr = new Instruction(opcode);
        length = 1;
        break;
    default:
        throw new ClassFormatError("Invalid opcode "+opcode);
    }
    if ((GlobalOptions.debuggingFlags
         & GlobalOptions.DEBUG_BYTECODE) != 0) 
        GlobalOptions.err.println();

    instrs[addr] = instr;
    instructions.add(instr);

    addr += length;
    instructions.setLastAddr(addr);
      }
      if (addr != codeLength)
    throw new ClassFormatError("last instruction too long");
  }
  for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
      Instruction instr = (Instruction) iter.next();
      int addr = instr.getAddr();
      if (succAddrs[addr] != null) {
    int length = succAddrs[addr].length;
    Instruction[] succs = new Instruction[length];
    for (int i=0; i < length; i++) {
        int succAddr = succAddrs[addr][i];
        if (succAddr < 0 || succAddr > codeLength
      || instrs[succAddr] == null)
      throw new ClassFormatException
          ("Illegal jump target at "
           +this+"@"+addr);
        succs[i] = instrs[succAddr];
    }
    instr.setSuccs(succs);
      }
  }
  succAddrs = null;

  {
      int handlersLength = input.readUnsignedShort();
      exceptionHandlers = new Handler[handlersLength];
      for (int i=0; i< handlersLength; i ++) {
    exceptionHandlers[i] = new Handler();
    exceptionHandlers[i].start
        = instrs[input.readUnsignedShort()];
    exceptionHandlers[i].end
        = instrs[input.readUnsignedShort()].getPrevByAddr();
    exceptionHandlers[i].catcher
        = instrs[input.readUnsignedShort()];
    int index = input.readUnsignedShort();
    exceptionHandlers[i].type = (index == 0) ? null
        : cp.getClassName(index);

    if (exceptionHandlers[i].catcher.getOpcode() == opc_athrow) {
        /* There is an obfuscator, which inserts bogus
         * exception entries jumping directly to a throw
         * instruction.  Remove those handlers.
         */
        handlersLength--;
        i--;
        continue;
    }

    if (exceptionHandlers[i].start.getAddr()
           <= exceptionHandlers[i].catcher.getAddr()
        && exceptionHandlers[i].end.getAddr()
           >= exceptionHandlers[i].catcher.getAddr())
    {
        /* Javac 1.4 is a bit paranoid with finally and
         * synchronize blocks and even breaks the JLS.
         * We fix it here.  Hopefully this won't produce
         * any other problems.
         */
        if (exceptionHandlers[i].start
      == exceptionHandlers[i].catcher) {
      handlersLength--;
      i--;
        } else {
      exceptionHandlers[i].end = 
          exceptionHandlers[i].catcher.getPrevByAddr();
        }
    }
      }
      if (handlersLength < exceptionHandlers.length) {
    Handler[] newHandlers = new Handler[handlersLength];
    System.arraycopy(exceptionHandlers, 0, newHandlers, 0,
         handlersLength);
    exceptionHandlers = newHandlers;
      }
  }
  readAttributes(cp, input, FULLINFO);
  instrs = null;
    }

    public void dumpCode(java.io.PrintWriter output) {
  for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
      Instruction instr = (Instruction) iter.next();
      output.println(instr.getDescription() + " "
         + Integer.toHexString(hashCode()));
      Instruction[] succs = instr.getSuccs();
      if (succs != null) {
    output.print("\tsuccs: "+succs[0]);
    for (int i = 1; i < succs.length; i++)
        output.print(", "+succs[i]);
    output.println();
      }
      if (instr.getPreds() != null) {
    output.print("\tpreds: " + instr.getPreds()[0]);
    for (int i=1; i < instr.getPreds().length; i++)
        output.print(", " + instr.getPreds()[i]);
    output.println();
      }
  }
  for (int i=0; i< exceptionHandlers.length; i++) {
      output.println("catch " + exceptionHandlers[i].type 
         + " from " + exceptionHandlers[i].start 
         + " to " + exceptionHandlers[i].end
         + " catcher " + exceptionHandlers[i].catcher);
  }
    }

    public void reserveSmallConstants(GrowableConstantPool gcp) {
    next_instr:
  for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
      Instruction instr = (Instruction) iter.next();
      if (instr.getOpcode() == opc_ldc) {
    Object constant = instr.getConstant();
    if (constant == null)
        continue next_instr;
    for (int i=1; i < constants.length; i++) {
        if (constant.equals(constants[i]))
      continue next_instr;
    }
    if (constant instanceof Integer) {
        int value = ((Integer) constant).intValue();
        if (value >= Short.MIN_VALUE
      && value <= Short.MAX_VALUE)
      continue next_instr;
    }
    gcp.reserveConstant(constant);
      }
  }
    }

    private void calculateMaxStack() {
  maxStack = 0;
  int[] stackHeights = new int[instructions.getCodeLength()];
  int[] poppush = new int[2];
  Stack todo = new Stack();

  for (int i=0; i < stackHeights.length; i++)
      stackHeights[i] = -1;

  stackHeights[0] = 0;
  todo.push(instructions.get(0));
  while (!todo.isEmpty()) {
      Instruction instr = (Instruction) todo.pop();
      Instruction next = instr.getNextByAddr();
      Instruction[] succs = instr.getSuccs();
      int addr = instr.getAddr();
      instr.getStackPopPush(poppush);
      int sh = stackHeights[addr] - poppush[0] + poppush[1];
//       System.err.println("Instr: "+instr.getDescription()+
//              "; before: "+stackHeights[addr]+" after: "+sh);
      if (maxStack < sh)
    maxStack = sh;
      if (instr.getOpcode() == opc_jsr) {
    if (stackHeights[next.getAddr()] == -1) {
        stackHeights[next.getAddr()] = sh - 1;
        todo.push(next);
    }
    if (stackHeights[succs[0].getAddr()] == -1) {
        stackHeights[succs[0].getAddr()] = sh;
        todo.push(succs[0]);
    }
      } else {
    if (succs != null) {
        for (int i=0; i < succs.length; i++) {
      if (stackHeights[succs[i].getAddr()] == -1) {
          stackHeights[succs[i].getAddr()] = sh;
          todo.push(succs[i]);
      }
        }
    }
    if (!instr.doesAlwaysJump()
        && stackHeights[next.getAddr()] == -1) {
        stackHeights[next.getAddr()] = sh;
        todo.push(next);
    }
      }
      for (int i=0; i< exceptionHandlers.length; i++) {
    if (exceptionHandlers[i].start.compareTo(instr) <= 0
        && exceptionHandlers[i].end.compareTo(instr) >= 0) {
        int catcher = exceptionHandlers[i].catcher.getAddr();
        if (stackHeights[catcher] == -1) {
      stackHeights[catcher] = 1;
      todo.push(exceptionHandlers[i].catcher);
        }
    }
      }
  }
//   System.err.println("New maxStack: "+maxStack+" Locals: "+maxLocals);
    }

    public void prepareWriting(GrowableConstantPool gcp) {
  /* Recalculate addr, length, maxStack, maxLocals and add all
   * constants to gcp */
  int addr = 0;
  maxLocals = (methodInfo.isStatic() ? 0 : 1) + 
      TypeSignature.getArgumentSize(methodInfo.getType());
  
  for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
      Instruction instr = (Instruction) iter.next();
      int opcode = instr.getOpcode();
      instr.setAddr(addr);
      int length;
  switch_opc:
      switch (opcode) {
      case opc_ldc:
      case opc_ldc2_w: {
    Object constant = instr.getConstant();
    if (constant == null) {
        length = 1;
        break switch_opc;
    }
    for (int i=1; i < constants.length; i++) {
        if (constant.equals(constants[i])) {
      length = 1;
      break switch_opc;
        }
    }
    if (opcode == opc_ldc2_w) {
        gcp.putLongConstant(constant);
        length = 3;
        break switch_opc;
    }
    if (constant instanceof Integer) {
        int value = ((Integer) constant).intValue();
        if (value >= Byte.MIN_VALUE
      && value <= Byte.MAX_VALUE) {
      length = 2;
      break switch_opc;
        } else if (value >= Short.MIN_VALUE
             && value <= Short.MAX_VALUE) {
      length = 3;
      break switch_opc;
        }
    }
    if (gcp.putConstant(constant) < 256) {
        length = 2;
    } else {
        length = 3;
    }
    break;
      } 
      case opc_iinc: {
    int slot = instr.getLocalSlot();
    int increment = instr.getIncrement();
    if (slot < 256 
        && increment >= Byte.MIN_VALUE 
        && increment <= Byte.MAX_VALUE)
        length = 3;
    else
        length = 6;
    if (slot >= maxLocals)
        maxLocals = slot + 1;
    break;
      }
      case opc_iload: case opc_fload: case opc_aload:
      case opc_istore: case opc_fstore: case opc_astore: {
    int slot = instr.getLocalSlot();
    if (slot < 4)
        length = 1;
    else if (slot < 256)
        length = 2;
    else 
        length = 4;
    if (slot >= maxLocals)
        maxLocals = slot + 1;
    break;
      }
      case opc_lload: case opc_dload:
      case opc_lstore: case opc_dstore: {
    int slot = instr.getLocalSlot();
    if (slot < 4)
        length = 1;
    else if (slot < 256)
        length = 2;
    else 
        length = 4;
    if (slot+1 >= maxLocals)
        maxLocals = slot + 2;
    break;
      }
      case opc_ret: {
    int slot = instr.getLocalSlot();
    if (slot < 256)
        length = 2;
    else 
        length = 4;
    if (slot >= maxLocals)
        maxLocals = slot + 1;
    break;
      } 
      case opc_lookupswitch: {
    length = 3-(addr % 4);
    int[] values = instr.getValues();
    int   npairs = values.length;
    if (npairs > 0) {
        int tablesize = values[npairs-1] - values[0] + 1;
        if (4 + tablesize * 4 < 8 * npairs) {
      // Use a table switch
      length += 13 + 4 * tablesize;
      break;
        }
    }
    // Use a lookup switch
    length += 9 + 8 * npairs;
    break;
      }
      case opc_goto: case opc_jsr: {
    int dist = instr.getSingleSucc().getAddr() - instr.getAddr();
    if (dist < Short.MIN_VALUE || dist > Short.MAX_VALUE) {
        /* wide goto / jsr */
        length = 5;
        break;
    } 
    /* fall through */
      }
      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:
    length = 3;
    break;
      case opc_multianewarray: {
    if (instr.getDimensions() == 1) {
        String clazz = instr.getClazzType().substring(1);
        if (newArrayTypes.indexOf(clazz.charAt(0)) != -1) {
      length = 2;
        } else {
      gcp.putClassType(clazz);
      length = 3;
        }
    } else {
        gcp.putClassType(instr.getClazzType());
        length = 4;
    }
    break;
      }
      case opc_getstatic:
      case opc_getfield:
      case opc_putstatic:
      case opc_putfield:
    gcp.putRef(gcp.FIELDREF, instr.getReference());
    length = 3;
    break;
      case opc_invokespecial:
      case opc_invokestatic:
      case opc_invokevirtual:
    gcp.putRef(gcp.METHODREF, instr.getReference());
    length = 3;
    break;
      case opc_invokeinterface:
    gcp.putRef(gcp.INTERFACEMETHODREF, instr.getReference());
    length = 5;
    break;
      case opc_new:
      case opc_checkcast:
      case opc_instanceof:
    gcp.putClassType(instr.getClazzType());
    length = 3;
    break;
      case opc_nop:
      case opc_iaload: case opc_laload: case opc_faload:
      case opc_daload: case opc_aaload:
      case opc_baload: case opc_caload: case opc_saload:
      case opc_iastore: case opc_lastore: case opc_fastore:
      case opc_dastore: case opc_aastore:
      case opc_bastore: case opc_castore: case opc_sastore:
      case opc_pop: case opc_pop2:
      case opc_dup: case opc_dup_x1: case opc_dup_x2:
      case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
      case opc_swap:
      case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
      case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
      case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
      case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
      case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
      case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
      case opc_ishl: case opc_lshl:
      case opc_ishr: case opc_lshr:
      case opc_iushr: case opc_lushr: 
      case opc_iand: case opc_land:
      case opc_ior: case opc_lor: 
      case opc_ixor: case opc_lxor:
      case opc_i2l: case opc_i2f: case opc_i2d:
      case opc_l2i: case opc_l2f: case opc_l2d:
      case opc_f2i: case opc_f2l: case opc_f2d:
      case opc_d2i: case opc_d2l: case opc_d2f:
      case opc_i2b: case opc_i2c: case opc_i2s:
      case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
      case opc_dcmpl: case opc_dcmpg:
      case opc_ireturn: case opc_lreturn: 
      case opc_freturn: case opc_dreturn: case opc_areturn:
      case opc_return: 
      case opc_athrow:
      case opc_arraylength:
      case opc_monitorenter: case opc_monitorexit:
    length = 1;
    break;
      default:
    throw new ClassFormatError("Invalid opcode "+opcode);
      }
      addr += length;
  }
  instructions.setLastAddr(addr);
  try {
      calculateMaxStack();
  } catch (RuntimeException ex) {
      ex.printStackTrace();
      dumpCode(GlobalOptions.err);
  }
  for (int i=0; i< exceptionHandlers.length; i++)
      if (exceptionHandlers[i].type != null)
    gcp.putClassName(exceptionHandlers[i].type);
  if (lvt != null) {
      gcp.putUTF8("LocalVariableTable");
            for (int i=0; i < lvt.length; i++) {
    gcp.putUTF8(lvt[i].name);
    gcp.putUTF8(lvt[i].type);
            }
  }
  if (lnt != null)
      gcp.putUTF8("LineNumberTable");
  prepareAttributes(gcp);
    }

    protected int getKnownAttributeCount() {
  int count = 0;
  if (lvt != null)
      count++;
  if (lnt != null)
      count++;
  return count;
    }

    public void writeKnownAttributes(GrowableConstantPool gcp,
             DataOutputStream output) 
  throws IOException {
  if (lvt != null) {
      output.writeShort(gcp.putUTF8("LocalVariableTable"));
            int count = lvt.length;
      int length = 2 + 10 * count;
      output.writeInt(length);
      output.writeShort(count);
            for (int i=0; i < count; i++) {
    output.writeShort(lvt[i].start.getAddr());
    output.writeShort(lvt[i].end.getAddr() + lvt[i].end.getLength()
          - lvt[i].start.getAddr());
    output.writeShort(gcp.putUTF8(lvt[i].name));
    output.writeShort(gcp.putUTF8(lvt[i].type));
    output.writeShort(lvt[i].slot);
            }
  }
  if (lnt != null) {
      output.writeShort(gcp.putUTF8("LineNumberTable"));
            int count = lnt.length;
      int length = 2 + 4 * count;
      output.writeInt(length);
      output.writeShort(count);
            for (int i=0; i < count; i++) {
    output.writeShort(lnt[i].start.getAddr());
    output.writeShort(lnt[i].linenr);
            }
  }
    }

    public void write(GrowableConstantPool gcp, 
          DataOutputStream output) throws IOException {
  output.writeShort(maxStack);
  output.writeShort(maxLocals);
  output.writeInt(instructions.getCodeLength());
  for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
      Instruction instr = (Instruction) iter.next();
      int opcode = instr.getOpcode();
        switch_opc:
      switch (opcode) {
      case opc_iload: case opc_lload: 
      case opc_fload: case opc_dload: case opc_aload:
      case opc_istore: case opc_lstore: 
      case opc_fstore: case opc_dstore: case opc_astore: {
    int slot = instr.getLocalSlot();
    if (slot < 4) {
        if (opcode < opc_istore)
      output.writeByte(opc_iload_0
           + 4*(opcode-opc_iload)
           + slot);
        else
      output.writeByte(opc_istore_0
           + 4*(opcode-opc_istore)
           + slot);
    } else if (slot < 256) {
        output.writeByte(opcode);
        output.writeByte(slot);
    } else {
        output.writeByte(opc_wide);
        output.writeByte(opcode);
        output.writeShort(slot);
    }
    break;
      }    
      case opc_ret: {
    int slot = instr.getLocalSlot();
    if (slot < 256) {
        output.writeByte(opcode);
        output.writeByte(slot);
    } else {
        output.writeByte(opc_wide);
        output.writeByte(opcode);
        output.writeShort(slot);
    }
    break;
      }
      case opc_ldc:
      case opc_ldc2_w: {
    Object constant = instr.getConstant();
    if (constant == null) {
        output.writeByte(opc_aconst_null);
        break switch_opc;
    }
    for (int i=1; i < constants.length; i++) {
        if (constant.equals(constants[i])) {
      output.writeByte(opc_aconst_null + i);
      break switch_opc;
        }
    }
    if (opcode == opc_ldc2_w) {
        output.writeByte(opcode);
        output.writeShort(gcp.putLongConstant(constant));
    } else {
        if (constant instanceof Integer) {
      int value = ((Integer) constant).intValue();
      if (value >= Byte.MIN_VALUE
          && value <= Byte.MAX_VALUE) {
          
          output.writeByte(opc_bipush);
          output.writeByte(((Integer)constant)
               .intValue());
          break switch_opc;
      } else if (value >= Short.MIN_VALUE
           && value <= Short.MAX_VALUE) {
          output.writeByte(opc_sipush);
          output.writeShort(((Integer)constant)
                .intValue());
          break switch_opc;
      }
        }
        if (instr.getLength() == 2) {
      output.writeByte(opc_ldc);
      output.writeByte(gcp.putConstant(constant));
        } else {
      output.writeByte(opc_ldc_w);
      output.writeShort(gcp.putConstant(constant));
        }
    }
    break;
      }
      case opc_iinc: {
    int slot = instr.getLocalSlot();
    int incr = instr.getIncrement();
    if (instr.getLength() == 3) {
        output.writeByte(opcode);
        output.writeByte(slot);
        output.writeByte(incr);
    } else {
        output.writeByte(opc_wide);
        output.writeByte(opcode);
        output.writeShort(slot);
        output.writeShort(incr);
    }
    break;
      }
      case opc_goto:
      case opc_jsr:
    if (instr.getLength() == 5) {
        /* wide goto or jsr */
        output.writeByte(opcode + (opc_goto_w - opc_goto));
        output.writeInt(instr.getSingleSucc().getAddr()
            - instr.getAddr());
        break;
    }
    /* fall through */
      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:
    output.writeByte(opcode);
    output.writeShort(instr.getSingleSucc().getAddr() 
          - instr.getAddr());
    break;

      case opc_lookupswitch: {
    int align = 3-(instr.getAddr() % 4);
    int[] values = instr.getValues();
    int npairs = values.length;
    int defAddr = instr.getSuccs()[npairs].getAddr()
        - instr.getAddr();

    if (npairs > 0) {
        int tablesize = values[npairs-1] - values[0] + 1;
        if (4 + tablesize * 4 < 8 * npairs) {
      // Use a table switch
      output.writeByte(opc_tableswitch);
      output.write(new byte[align]);
      /* def */
      output.writeInt(defAddr);
      /* low */
      output.writeInt(values[0]); 
      /* high */
      output.writeInt(values[npairs-1]);
      int pos = values[0];
      for (int i = 0; i < npairs; i++) {
          while (pos++ < values[i])
        output.writeInt(defAddr);
          output.writeInt(instr.getSuccs()[i].getAddr()
              - instr.getAddr());
      }
      break;
        }
    }
    // Use a lookup switch
    output.writeByte(opc_lookupswitch);
    output.write(new byte[align]);
    /* def */
    output.writeInt(defAddr);
    output.writeInt(npairs);
    for (int i=0; i < npairs; i++) {
        output.writeInt(values[i]);
        output.writeInt(instr.getSuccs()[i].getAddr()
            -instr.getAddr());
    }
    break;
      }

      case opc_getstatic:
      case opc_getfield:
      case opc_putstatic:
      case opc_putfield:
    output.writeByte(opcode);
    output.writeShort(gcp.putRef(gcp.FIELDREF, 
               instr.getReference()));
    break;

      case opc_invokespecial:
      case opc_invokestatic:
      case opc_invokeinterface:
      case opc_invokevirtual: {
    Reference ref = instr.getReference();
    output.writeByte(opcode);
    if (opcode == opc_invokeinterface) {
        output.writeShort(gcp.putRef(gcp.INTERFACEMETHODREF, ref));
        output.writeByte
      (TypeSignature.getArgumentSize(ref.getType()) + 1);
        output.writeByte(0);
    } else 
        output.writeShort(gcp.putRef(gcp.METHODREF, ref));
    break;
      }
      case opc_new:
      case opc_checkcast:
      case opc_instanceof:
    output.writeByte(opcode);
    output.writeShort(gcp.putClassType(instr.getClazzType()));
    break;
      case opc_multianewarray:
    if (instr.getDimensions() == 1) {
        String clazz = instr.getClazzType().substring(1);
        int index = newArrayTypes.indexOf(clazz.charAt(0));
        if (index != -1) {
      output.writeByte(opc_newarray);
      output.writeByte(index + 4);
        } else {
      output.writeByte(opc_anewarray);
      output.writeShort(gcp.putClassType(clazz));
        }
    } else {
        output.writeByte(opcode);
        output.writeShort(gcp.putClassType(instr.getClazzType()));
        output.writeByte(instr.getDimensions());
    }
    break;

      case opc_nop:
      case opc_iaload: case opc_laload: case opc_faload:
      case opc_daload: case opc_aaload:
      case opc_baload: case opc_caload: case opc_saload:
      case opc_iastore: case opc_lastore: case opc_fastore:
      case opc_dastore: case opc_aastore:
      case opc_bastore: case opc_castore: case opc_sastore:
      case opc_pop: case opc_pop2:
      case opc_dup: case opc_dup_x1: case opc_dup_x2:
      case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
      case opc_swap:
      case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
      case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
      case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
      case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
      case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
      case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
      case opc_ishl: case opc_lshl:
      case opc_ishr: case opc_lshr:
      case opc_iushr: case opc_lushr: 
      case opc_iand: case opc_land:
      case opc_ior: case opc_lor: 
      case opc_ixor: case opc_lxor:
      case opc_i2l: case opc_i2f: case opc_i2d:
      case opc_l2i: case opc_l2f: case opc_l2d:
      case opc_f2i: case opc_f2l: case opc_f2d:
      case opc_d2i: case opc_d2l: case opc_d2f:
      case opc_i2b: case opc_i2c: case opc_i2s:
      case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
      case opc_dcmpl: case opc_dcmpg:
      case opc_ireturn: case opc_lreturn: 
      case opc_freturn: case opc_dreturn: case opc_areturn:
      case opc_return: 
      case opc_athrow:
      case opc_arraylength:
      case opc_monitorenter: case opc_monitorexit:
    output.writeByte(opcode);
    break;
      default:
    throw new ClassFormatError("Invalid opcode "+opcode);
      }
  }

  output.writeShort(exceptionHandlers.length);
  for (int i=0; i< exceptionHandlers.length; i++) {
      output.writeShort(exceptionHandlers[i].start.getAddr());
      output.writeShort(exceptionHandlers[i].end.getNextByAddr().getAddr());
      output.writeShort(exceptionHandlers[i].catcher.getAddr());
      output.writeShort((exceptionHandlers[i].type == null) ? 0
            : gcp.putClassName(exceptionHandlers[i].type));
  }
  writeAttributes(gcp, output);
    }

    public void dropInfo(int howMuch) {
  if ((howMuch & KNOWNATTRIBS) != 0) {
      lvt = null;
      lnt = null;
  }
  super.dropInfo(howMuch);
    }

    public int getSize() {
  /* maxStack:    2
   * maxLocals:   2
   * code:        4 + codeLength
   * exc count:   2
   * exceptions:  n * 8
   * attributes:
   *  lvt_name:    2
   *  lvt_length:  4
   *  lvt_count:   2
   *  lvt_entries: n * 10
   * attributes:
   *  lnt_name:    2
   *  lnt_length:  4
   *  lnt_count:   2
   *  lnt_entries: n * 4
   */
  int size = 0;
  if (lvt != null)
      size += 8 + lvt.length * 10;
  if (lnt != null)
      size += 8 + lnt.length * 4;
  return 10 + instructions.getCodeLength()
      + exceptionHandlers.length * 8
      + getAttributeSize() + size;
    }

    public int getMaxStack() {
        return maxStack;
    }

    public int getMaxLocals() {
        return maxLocals;
    }

    public MethodInfo getMethodInfo() {
  return methodInfo;
    }

    public List getInstructions() {
  return instructions;
    }

    public Handler[] getExceptionHandlers() {
  return exceptionHandlers;
    }

    public LocalVariableInfo[] getLocalVariableTable() {
  return lvt;
    }

    public LineNumber[] getLineNumberTable() {
  return lnt;
    }

    public void setExceptionHandlers(Handler[] handlers) {
        exceptionHandlers = handlers;
    }

    public void setLocalVariableTable(LocalVariableInfo[] newLvt) {
  lvt = newLvt;
    }

    public void setLineNumberTable(LineNumber[] newLnt) {
  lnt = newLnt;
    }

    public String toString() {
        return "Bytecode "+methodInfo;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.