Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/jode/bytecode/BytecodeInfo.java.in

1635 lines
48 KiB

/* 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$
*/
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 @COLLECTIONS@.List;
import @COLLECTIONS@.AbstractSequentialList;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.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 (name.equals("LocalVariableTable")) {
if ((howMuch & KNOWNATTRIBS) != 0){
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
input.readFully(new byte[length]);
} else if (name.equals("LineNumberTable")) {
if ((howMuch & KNOWNATTRIBS) != 0) {
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
input.readFully(new byte[length]);
} 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;
}
}