diff --git a/jode/jode/bytecode/BinaryInfo.java b/jode/jode/bytecode/BinaryInfo.java index 4cb52c8..258ecd8 100644 --- a/jode/jode/bytecode/BinaryInfo.java +++ b/jode/jode/bytecode/BinaryInfo.java @@ -18,7 +18,12 @@ */ package jode.bytecode; -import java.io.*; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; import jode.util.SimpleMap; ///#ifdef JDK12 diff --git a/jode/jode/bytecode/BytecodeInfo.java b/jode/jode/bytecode/BytecodeInfo.java index 15118f6..d23a296 100644 --- a/jode/jode/bytecode/BytecodeInfo.java +++ b/jode/jode/bytecode/BytecodeInfo.java @@ -27,12 +27,24 @@ import java.io.EOFException; import java.io.IOException; import java.util.Vector; import java.util.Enumeration; +import java.util.NoSuchElementException; + +///#ifdef JDK12 +///import java.util.Collection; +///import java.util.AbstractCollectoin; +///import java.util.Iterator; +///#else +import jode.util.Collection; +import jode.util.AbstractCollection; +import jode.util.Iterator; +///#endif + /** * This class represents the byte code of a method. Each instruction is * stored in an Instruction instance. * - * We canocalize some opcodes: wide opcodes are mapped to short ones, + * 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. */ @@ -44,6 +56,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { int maxStack, maxLocals; int codeLength; Instruction firstInstr = null; + int instructionCount = 0; Handler[] exceptionHandlers; LocalVariableInfo[] lvt; LineNumber[] lnt; @@ -84,20 +97,20 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { int slot = input.readUnsignedShort(); Instruction startInstr, endInstr; for (startInstr = firstInstr; - startInstr.addr < start && startInstr != null; - startInstr = startInstr.nextByAddr) { + startInstr.getAddr() < start && startInstr != null; + startInstr = startInstr.getNextByAddr()) { /* empty */ } endInstr = startInstr; if (startInstr != null) { - while (endInstr.nextByAddr != null - && endInstr.nextByAddr.addr < end) - endInstr = endInstr.nextByAddr; + while (endInstr.getNextByAddr() != null + && endInstr.getNextByAddr().getAddr() < end) + endInstr = endInstr.getNextByAddr(); } if (startInstr == null - || startInstr.addr != start + || startInstr.getAddr() != start || endInstr == null - || endInstr.addr + endInstr.length != end + || endInstr.getAddr() + endInstr.getLength() != end || nameIndex == 0 || typeIndex == 0 || slot >= maxLocals || cp.getTag(nameIndex) != cp.UTF8 @@ -105,8 +118,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { // 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"); + if ((GlobalOptions.debuggingFlags + & GlobalOptions.DEBUG_LVT) != 0) + GlobalOptions.err.println + ("Illegal entry, ignoring LVT"); lvt = null; return; } @@ -135,12 +150,12 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { int start = input.readUnsignedShort(); Instruction startInstr; for (startInstr = firstInstr; - startInstr.addr < start && startInstr != null; - startInstr = startInstr.nextByAddr) { + startInstr.getAddr() < start && startInstr != null; + startInstr = startInstr.getNextByAddr()) { /* empty */ } if (startInstr == null - || startInstr.addr != start) { + || startInstr.getAddr() != start) { GlobalOptions.err.println ("Illegal entry, ignoring LineNumberTable table"); lnt = null; @@ -164,15 +179,14 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { int[] predcounts = new int[codeLength]; { int addr = 0; + firstInstr = new Instruction(this); + instructionCount++; Instruction lastInstr = null; while (addr < codeLength) { - Instruction instr = new Instruction(this); - if (lastInstr != null) { - lastInstr.nextByAddr = instr; - instr.prevByAddr = lastInstr; - } + Instruction instr = lastInstr != null + ? lastInstr.appendInstruction(opc_nop) : firstInstr; + instrs[addr] = instr; - instr.addr = addr; lastInstr = instr; int opcode = input.readUnsignedByte(); @@ -182,60 +196,65 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { & GlobalOptions.DEBUG_BYTECODE) != 0) GlobalOptions.err.print(addr+": "+opcodeString[opcode]); - instr.opcode = opcode; switch (opcode) { case opc_wide: { int wideopcode = input.readUnsignedByte(); - instr.opcode = wideopcode; + instr.replaceInstruction(wideopcode); switch (wideopcode) { case opc_iload: case opc_fload: case opc_aload: - case opc_istore: case opc_fstore: case opc_astore: - instr.localSlot = input.readUnsignedShort(); - if (instr.localSlot >= maxLocals) + case opc_istore: case opc_fstore: case opc_astore: { + int slot = input.readUnsignedShort(); + if (slot >= maxLocals) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.length = 4; + ("Invalid local slot "+slot); + instr.setLocalSlot(slot); + instr.setLength(4); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) - GlobalOptions.err.print(" "+opcodeString[wideopcode] - +" "+instr.localSlot); + GlobalOptions.err.print + (" " + opcodeString[wideopcode] + " " + slot); break; + } case opc_lload: case opc_dload: - case opc_lstore: case opc_dstore: - instr.localSlot = input.readUnsignedShort(); - if (instr.localSlot >= maxLocals-1) + case opc_lstore: case opc_dstore: { + int slot = input.readUnsignedShort(); + if (slot >= maxLocals-1) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.length = 4; + ("Invalid local slot "+slot); + instr.setLocalSlot(slot); + instr.setLength(4); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) GlobalOptions.err.print(" "+opcodeString[wideopcode] - +" "+instr.localSlot); + +" "+slot); break; - case opc_ret: - instr.localSlot = input.readUnsignedShort(); - if (instr.localSlot >= maxLocals) + } + case opc_ret: { + int slot = input.readUnsignedShort(); + if (slot >= maxLocals) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.length = 4; - instr.alwaysJumps = true; + ("Invalid local slot "+slot); + instr.setLocalSlot(slot); + instr.setLength(4); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) - GlobalOptions.err.print(" ret "+instr.localSlot); + GlobalOptions.err.print(" ret "+slot); break; - - case opc_iinc: - instr.localSlot = input.readUnsignedShort(); - if (instr.localSlot >= maxLocals) + } + case opc_iinc: { + int slot = input.readUnsignedShort(); + if (slot >= maxLocals) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.intData = input.readShort(); - instr.length = 6; + ("Invalid local slot "+slot); + instr.setLocalSlot(slot); + instr.setIntData(input.readShort()); + instr.setLength(6); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) - GlobalOptions.err.print(" iinc "+instr.localSlot - +" "+instr.intData); + GlobalOptions.err.print(" iinc "+slot + +" "+instr.getIntData()); break; + } default: throw new ClassFormatError("Invalid wide opcode " +wideopcode); @@ -251,97 +270,114 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { 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: - instr.opcode = opc_iload + (opcode-opc_iload_0)/4; - instr.localSlot = (opcode-opc_iload_0) & 3; - if (instr.localSlot >= maxLocals) + case opc_aload_2: case opc_aload_3: { + int slot = (opcode-opc_iload_0) & 3; + if (slot >= maxLocals) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.length = 1; + ("Invalid local slot "+slot); + instr.replaceInstruction(opc_iload + + (opcode-opc_iload_0)/4); + instr.setLocalSlot(slot); + instr.setLength(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: - instr.opcode = opc_istore + (opcode-opc_istore_0)/4; - instr.localSlot = (opcode-opc_istore_0) & 3; - if (instr.localSlot >= maxLocals) + case opc_astore_2: case opc_astore_3: { + int slot = (opcode-opc_istore_0) & 3; + if (slot >= maxLocals) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.length = 1; + ("Invalid local slot "+slot); + instr.replaceInstruction(opc_istore + + (opcode-opc_istore_0)/4); + instr.setLocalSlot(slot); + instr.setLength(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: - instr.opcode = opc_istore + (opcode-opc_istore_0)/4; - instr.localSlot = (opcode-opc_istore_0) & 3; - if (instr.localSlot >= maxLocals-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 "+instr.localSlot); - instr.length = 1; + ("Invalid local slot "+slot); + instr.replaceInstruction(opc_istore + + (opcode-opc_istore_0)/4); + instr.setLocalSlot(slot); + instr.setLength(1); break; + } case opc_iload: case opc_fload: case opc_aload: - case opc_istore: case opc_fstore: case opc_astore: - instr.localSlot = input.readUnsignedByte(); - if (instr.localSlot >= maxLocals) + case opc_istore: case opc_fstore: case opc_astore: { + int slot = input.readUnsignedByte(); + if (slot >= maxLocals) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.length = 2; + ("Invalid local slot "+slot); + instr.replaceInstruction(opcode); + instr.setLocalSlot(slot); + instr.setLength(2); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) - GlobalOptions.err.print(" "+instr.localSlot); + GlobalOptions.err.print(" "+slot); break; + } case opc_lstore: case opc_dstore: - case opc_lload: case opc_dload: - instr.localSlot = input.readUnsignedByte(); - if (instr.localSlot >= maxLocals - 1) + case opc_lload: case opc_dload: { + int slot = input.readUnsignedByte(); + if (slot >= maxLocals - 1) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.length = 2; + ("Invalid local slot "+slot); + instr.replaceInstruction(opcode); + instr.setLocalSlot(slot); + instr.setLength(2); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) - GlobalOptions.err.print(" "+instr.localSlot); + GlobalOptions.err.print(" "+slot); break; - - case opc_ret: - instr.localSlot = input.readUnsignedByte(); - if (instr.localSlot >= maxLocals) + } + case opc_ret: { + int slot = input.readUnsignedByte(); + if (slot >= maxLocals) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.alwaysJumps = true; - instr.length = 2; + ("Invalid local slot "+slot); + instr.replaceInstruction(opcode); + instr.setLocalSlot(slot); + instr.setLength(2); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) - GlobalOptions.err.print(" "+instr.localSlot); + 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.objData = constants[instr.opcode - opc_aconst_null]; - instr.opcode = opc_ldc; - instr.length = 1; + instr.replaceInstruction(opc_ldc); + instr.setConstant + (constants[opcode - opc_aconst_null]); + instr.setLength(1); break; case opc_lconst_0: case opc_lconst_1: case opc_dconst_0: case opc_dconst_1: - instr.objData = constants[instr.opcode - opc_aconst_null]; - instr.opcode = opc_ldc2_w; - instr.length = 1; + instr.replaceInstruction(opc_ldc2_w); + instr.setConstant + (constants[opcode - opc_aconst_null]); + instr.setLength(1); break; case opc_bipush: - instr.opcode = opc_ldc; - instr.objData = new Integer(input.readByte()); - instr.length = 2; + instr.replaceInstruction(opc_ldc); + instr.setConstant(new Integer(input.readByte())); + instr.setLength(2); break; case opc_sipush: - instr.opcode = opc_ldc; - instr.objData = new Integer(input.readShort()); - instr.length = 3; + instr.replaceInstruction(opc_ldc); + instr.setConstant(new Integer(input.readShort())); + instr.setLength(3); break; case opc_ldc: { int index = input.readUnsignedByte(); @@ -350,8 +386,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { && tag != cp.INTEGER && tag != cp.FLOAT) throw new ClassFormatException ("wrong constant tag: "+tag); - instr.objData = cp.getConstant(index); - instr.length = 2; + instr.replaceInstruction(opcode); + instr.setConstant(cp.getConstant(index)); + instr.setLength(2); break; } case opc_ldc_w: { @@ -361,9 +398,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { && tag != cp.INTEGER && tag != cp.FLOAT) throw new ClassFormatException ("wrong constant tag: "+tag); - instr.opcode = opc_ldc; - instr.objData = cp.getConstant(index); - instr.length = 3; + instr.replaceInstruction(opc_ldc); + instr.setConstant(cp.getConstant(index)); + instr.setLength(3); break; } case opc_ldc2_w: { @@ -372,27 +409,28 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { if (tag != cp.LONG && tag != cp.DOUBLE) throw new ClassFormatException ("wrong constant tag: "+tag); - instr.objData = cp.getConstant(index); - instr.length = 3; + instr.replaceInstruction(opcode); + instr.setConstant(cp.getConstant(index)); + instr.setLength(3); break; } - case opc_iinc: - instr.localSlot = input.readUnsignedByte(); - if (instr.localSlot >= maxLocals) + case opc_iinc: { + int slot = input.readUnsignedByte(); + if (slot >= maxLocals) throw new ClassFormatError - ("Invalid local slot "+instr.localSlot); - instr.intData = input.readByte(); - instr.length = 3; + ("Invalid local slot "+slot); + instr.replaceInstruction(opcode); + instr.setLocalSlot(slot); + instr.setIntData(input.readByte()); + instr.setLength(3); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) - GlobalOptions.err.print(" "+instr.localSlot - +" "+instr.intData); + GlobalOptions.err.print(" "+slot + +" "+instr.getIntData()); break; - + } case opc_goto: case opc_jsr: - instr.alwaysJumps = true; - /* fall through */ case opc_ifeq: case opc_ifne: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: @@ -401,10 +439,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { case opc_if_icmpgt: case opc_if_icmple: case opc_if_acmpeq: case opc_if_acmpne: case opc_ifnull: case opc_ifnonnull: - succAddrs[addr] = new int[1]; - succAddrs[addr][0] = addr+input.readShort(); + instr.replaceInstruction(opcode); + instr.setLength(3); + succAddrs[addr] = new int[] { addr+input.readShort() }; predcounts[succAddrs[addr][0]]++; - instr.length = 3; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) GlobalOptions.err.print(" "+succAddrs[addr][0]); @@ -412,12 +450,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { case opc_goto_w: case opc_jsr_w: - instr.alwaysJumps = true; - instr.opcode -= opc_goto_w - opc_goto; - succAddrs[addr] = new int[1]; - succAddrs[addr][0] = addr+input.readInt(); + instr.replaceInstruction(opcode - (opc_goto_w - opc_goto)); + instr.setLength(5); + succAddrs[addr] = new int[] { addr+input.readInt() }; predcounts[succAddrs[addr][0]]++; - instr.length = 5; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) GlobalOptions.err.print(" "+succAddrs[addr][0]); @@ -429,7 +465,8 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { int def = input.readInt(); int low = input.readInt(); int high = input.readInt(); - instr.intData = low; + instr.replaceInstruction(opcode); + instr.setIntData(low); succAddrs[addr] = new int[high-low+2]; for (int i=0; i+low <= high; i++) { succAddrs[addr][i] = addr + input.readInt(); @@ -437,8 +474,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { } succAddrs[addr][high-low+1] = addr + def; predcounts[addr + def]++; - instr.alwaysJumps = true; - instr.length = length + 13 + 4 * (high-low+1); + instr.setLength(length + 13 + 4 * (high-low+1)); break; } case opc_lookupswitch: { @@ -446,6 +482,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { input.readFully(new byte[length]); int def = input.readInt(); int npairs = input.readInt(); + instr.replaceInstruction(opcode); succAddrs[addr] = new int[npairs + 1]; int[] values = new int[npairs]; for (int i=0; i < npairs; i++) { @@ -455,20 +492,11 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { } succAddrs[addr][npairs] = addr + def; predcounts[addr + def]++; - instr.objData = values; - instr.alwaysJumps = true; - instr.length = length + 9 + 8 * npairs; + instr.setValues(values); + instr.setLength(length + 9 + 8 * npairs); break; } - - case opc_ireturn: case opc_lreturn: - case opc_freturn: case opc_dreturn: case opc_areturn: - case opc_return: - case opc_athrow: - instr.alwaysJumps = true; - instr.length = 1; - break; - + case opc_getstatic: case opc_getfield: case opc_putstatic: @@ -478,7 +506,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { case opc_invokevirtual: { int index = input.readUnsignedShort(); int tag = cp.getTag(index); - if (instr.opcode < opc_invokevirtual) { + if (opcode < opc_invokevirtual) { if (tag != cp.FIELDREF) throw new ClassFormatException ("field tag mismatch: "+tag); @@ -493,11 +521,12 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { || opcode != opc_invokespecial)) throw new ClassFormatException ("Illegal call of special method/field "+ref); + instr.replaceInstruction(opcode); + instr.setReference(ref); + instr.setLength(3); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) GlobalOptions.err.print(" "+ref); - instr.objData = ref; - instr.length = 3; break; } case opc_invokeinterface: { @@ -510,16 +539,21 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { 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.replaceInstruction(opcode); + instr.setReference(ref); + instr.setLength(5); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) GlobalOptions.err.print(" "+ref); - instr.objData = ref; - instr.intData = input.readUnsignedByte(); - if (input.readUnsignedByte() != 0) - throw new ClassFormatException - ("Illegal call of special method "+ref); - - instr.length = 5; break; } @@ -530,68 +564,112 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { if (opcode == opc_new && type.charAt(0) == '[') throw new ClassFormatException ("Can't create array with opc_new"); - instr.objData = type; + instr.replaceInstruction(opcode); + instr.setClazzType(type); + instr.setLength(3); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) - GlobalOptions.err.print(" "+instr.objData); - instr.length = 3; + GlobalOptions.err.print(" "+type); break; } - case opc_multianewarray: - instr.objData = cp.getClassType(input.readUnsignedShort()); - instr.intData = input.readUnsignedByte(); - for (int i=0; i= opc_breakpoint) - throw new ClassFormatError("Invalid opcode "+opcode); - else - instr.length = 1; + throw new ClassFormatError("Invalid opcode "+opcode); } - addr += lastInstr.length; if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0) GlobalOptions.err.println(); + addr += instr.getLength(); } } - firstInstr = instrs[0]; for (Instruction instr = firstInstr; - instr != null; instr = instr.nextByAddr) { - int addr = instr.addr; + instr != null; instr = instr.getNextByAddr()) { + int addr = instr.getAddr(); if (succAddrs[addr] != null) { int length = succAddrs[addr].length; instr.succs = new Instruction[length]; @@ -615,12 +693,12 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { exceptionHandlers[i].start = instrs[input.readUnsignedShort()]; exceptionHandlers[i].end - = instrs[input.readUnsignedShort()].prevByAddr; + = instrs[input.readUnsignedShort()].getPrevByAddr(); exceptionHandlers[i].catcher = instrs[input.readUnsignedShort()]; int index = input.readUnsignedShort(); exceptionHandlers[i].type = (index == 0) ? null - : cp.getClassName(index).replace('/','.'); + : cp.getClassName(index); } } readAttributes(cp, input, FULLINFO); @@ -628,7 +706,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { public void dumpCode(java.io.PrintWriter output) { for (Instruction instr = firstInstr; - instr != null; instr = instr.nextByAddr) { + instr != null; instr = instr.getNextByAddr()) { output.println(instr.getDescription() + " " + Integer.toHexString(hashCode())); if (instr.succs != null) { @@ -655,120 +733,207 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { public void reserveSmallConstants(GrowableConstantPool gcp) { next_instr: for (Instruction instr = firstInstr; - instr != null; instr = instr.nextByAddr) { - if (instr.opcode == opc_ldc) { - if (instr.objData == null) + instr != null; instr = instr.getNextByAddr()) { + if (instr.getOpcode() == opc_ldc) { + Object constant = instr.getConstant(); + if (constant == null) continue next_instr; for (int i=1; i < constants.length; i++) { - if (instr.objData.equals(constants[i])) + if (constant.equals(constants[i])) continue next_instr; } - if (instr.objData instanceof Integer) { - int value = ((Integer) instr.objData).intValue(); + if (constant instanceof Integer) { + int value = ((Integer) constant).intValue(); if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) continue next_instr; } - gcp.reserveConstant(instr.objData); + gcp.reserveConstant(constant); } } } public void prepareWriting(GrowableConstantPool gcp) { - /* Recalculate addr and length */ + /* Recalculate addr, length and add all constants to gcp */ int addr = 0; - next_instr: for (Instruction instr = firstInstr; - instr != null; addr += instr.length, instr = instr.nextByAddr) { - instr.addr = addr; - if (instr.opcode == opc_ldc - || instr.opcode == opc_ldc2_w) { - if (instr.objData == null) { - instr.length = 1; - continue next_instr; + instr != null; instr = instr.getNextByAddr()) { + 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 (instr.objData.equals(constants[i])) { - instr.length = 1; - continue next_instr; + if (constant.equals(constants[i])) { + length = 1; + break switch_opc; } } - if (instr.opcode == opc_ldc2_w) { - gcp.putLongConstant(instr.objData); - instr.length = 3; - continue; + if (opcode == opc_ldc2_w) { + gcp.putLongConstant(constant); + length = 3; + break switch_opc; } - if (instr.objData instanceof Integer) { - int value = ((Integer) instr.objData).intValue(); + if (constant instanceof Integer) { + int value = ((Integer) constant).intValue(); if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { - instr.length = 2; - continue; + length = 2; + break switch_opc; } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { - instr.length = 3; - continue; + length = 3; + break switch_opc; } } - if (gcp.putConstant(instr.objData) < 256) { - instr.length = 2; + if (gcp.putConstant(constant) < 256) { + length = 2; } else { - instr.length = 3; + length = 3; } - } else if (instr.localSlot != -1) { - if (instr.opcode == opc_iinc) { - if (instr.localSlot < 256 - && instr.intData >= Byte.MIN_VALUE - && instr.intData <= Byte.MAX_VALUE) - instr.length = 3; + break; + } + 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: + case opc_ret: + case opc_iinc: { + int slot = instr.getLocalSlot(); + if (opcode == opc_iinc) { + if (slot < 256 + && instr.getIntData() >= Byte.MIN_VALUE + && instr.getIntData() <= Byte.MAX_VALUE) + length = 3; else - instr.length = 6; + length = 6; } else { - if (instr.opcode != opc_ret && instr.localSlot < 4) - instr.length = 1; - else if (instr.localSlot < 256) - instr.length = 2; + if (opcode != opc_ret && slot < 4) + length = 1; + else if (slot < 256) + length = 2; else - instr.length = 4; + length = 4; } - } else if (instr.opcode == opc_tableswitch) { - int length = 3-(addr % 4); - instr.length = length + 9 + 4 * instr.succs.length; - } else if (instr.opcode == opc_lookupswitch) { - int length = 3-(addr % 4); - instr.length = length + 1 + 8 * instr.succs.length; - } else if (instr.opcode == opc_goto - || instr.opcode == opc_jsr) { - int dist = instr.succs[0].addr - instr.addr; + break; + } + case opc_tableswitch: { + length = 3-(addr % 4); + length += 9 + 4 * instr.succs.length; + break; + } + case opc_lookupswitch: { + length = 3-(addr % 4); + length += 1 + 8 * instr.succs.length; + break; + } + case opc_goto: case opc_jsr: { + int dist = instr.succs[0].getAddr() - instr.getAddr(); if (dist < Short.MIN_VALUE || dist > Short.MAX_VALUE) { - instr.length = 5; - } else - instr.length = 3; - } else if (instr.opcode == opc_multianewarray) { - if (instr.intData == 1) { - String clazz = ((String) instr.objData).substring(1); - if (newArrayTypes.indexOf(clazz.charAt(0)) - != -1) { - instr.length = 2; + /* 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.getIntData() == 1) { + String clazz = instr.getClazzType().substring(1); + if (newArrayTypes.indexOf(clazz.charAt(0)) != -1) { + length = 2; } else { gcp.putClassType(clazz); - instr.length = 3; + length = 3; } } else { - gcp.putClassType((String)instr.objData); - instr.length = 4; + gcp.putClassType(instr.getClazzType()); + length = 4; } - } else if (instr.opcode >= opc_getstatic - && instr.opcode <= opc_invokeinterface) { - int tag = (instr.opcode <= opc_putfield ? gcp.FIELDREF - : instr.opcode <= opc_invokestatic ? gcp.METHODREF - : gcp.INTERFACEMETHODREF); - gcp.putRef(tag, (Reference) instr.objData); - } else if (instr.opcode == opc_new - || instr.opcode == opc_checkcast - || instr.opcode == opc_instanceof) { - gcp.putClassType((String) instr.objData); + 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); } + instr.setLength(length); + addr += length; } codeLength = addr; for (int i=0; i< exceptionHandlers.length; i++) @@ -805,9 +970,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { output.writeInt(length); output.writeShort(count); for (int i=0; i < count; i++) { - output.writeShort(lvt[i].start.addr); - output.writeShort(lvt[i].end.addr + lvt[i].end.length - - lvt[i].start.addr); + 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); @@ -820,7 +985,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { output.writeInt(length); output.writeShort(count); for (int i=0; i < count; i++) { - output.writeShort(lnt[i].start.addr); + output.writeShort(lnt[i].start.getAddr()); output.writeShort(lnt[i].linenr); } } @@ -832,100 +997,115 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { output.writeShort(maxLocals); output.writeInt(codeLength); for (Instruction instr = firstInstr; - instr != null; instr = instr.nextByAddr) { + instr != null; instr = instr.getNextByAddr()) { + int opcode = instr.getOpcode(); switch_opc: - switch (instr.opcode) { + 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: - if (instr.length == 1) { - if (instr.opcode < opc_istore) + 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*(instr.opcode-opc_iload) - + instr.localSlot); + + 4*(opcode-opc_iload) + + slot); else output.writeByte(opc_istore_0 - + 4*(instr.opcode-opc_istore) - + instr.localSlot); - } else if (instr.length == 2) { - output.writeByte(instr.opcode); - output.writeByte(instr.localSlot); + + 4*(opcode-opc_istore) + + slot); + } else if (slot < 256) { + output.writeByte(opcode); + output.writeByte(slot); } else { output.writeByte(opc_wide); - output.writeByte(instr.opcode); - output.writeShort(instr.localSlot); + output.writeByte(opcode); + output.writeShort(slot); } break; - - case opc_ret: - if (instr.length == 2) { - output.writeByte(instr.opcode); - output.writeByte(instr.localSlot); + } + case opc_ret: { + int slot = instr.getLocalSlot(); + if (slot < 256) { + output.writeByte(opcode); + output.writeByte(slot); } else { output.writeByte(opc_wide); - output.writeByte(instr.opcode); - output.writeShort(instr.localSlot); + output.writeByte(opcode); + output.writeShort(slot); } break; - + } case opc_ldc: - case opc_ldc2_w: - if (instr.objData == null) { + case opc_ldc2_w: { + Object constant = instr.getConstant(); + if (constant == null) { output.writeByte(opc_aconst_null); - instr.length = 1; break switch_opc; } for (int i=1; i < constants.length; i++) { - if (instr.objData.equals(constants[i])) { + if (constant.equals(constants[i])) { output.writeByte(opc_aconst_null + i); break switch_opc; } } - if (instr.opcode == opc_ldc2_w) { - output.writeByte(instr.opcode); - output.writeShort(gcp.putLongConstant(instr.objData)); + if (opcode == opc_ldc2_w) { + output.writeByte(opcode); + output.writeShort(gcp.putLongConstant(constant)); } else { - if (instr.objData instanceof Integer) { - int value = ((Integer) instr.objData).intValue(); + 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)instr.objData) + 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)instr.objData) + output.writeShort(((Integer)constant) .intValue()); break switch_opc; } } - if (instr.length == 2) { + if (instr.getLength() == 2) { output.writeByte(opc_ldc); - output.writeByte(gcp.putConstant(instr.objData)); + output.writeByte(gcp.putConstant(constant)); } else { output.writeByte(opc_ldc_w); - output.writeShort(gcp.putConstant(instr.objData)); + output.writeShort(gcp.putConstant(constant)); } } break; - case opc_iinc: - if (instr.length == 3) { - output.writeByte(instr.opcode); - output.writeByte(instr.localSlot); - output.writeByte(instr.intData); + } + case opc_iinc: { + int slot = instr.getLocalSlot(); + int incr = instr.getIntData(); + if (instr.getLength() == 3) { + output.writeByte(opcode); + output.writeByte(slot); + output.writeByte(incr); } else { output.writeByte(opc_wide); - output.writeByte(instr.opcode); - output.writeShort(instr.localSlot); - output.writeShort(instr.intData); + 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.succs[0].getAddr() + - instr.getAddr()); + break; + } + /* fall through */ case opc_ifeq: case opc_ifne: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: @@ -934,44 +1114,38 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { case opc_if_icmpgt: case opc_if_icmple: case opc_if_acmpeq: case opc_if_acmpne: case opc_ifnull: case opc_ifnonnull: - case opc_jsr: - if (instr.length == 3) { - output.writeByte(instr.opcode); - output.writeShort(instr.succs[0].addr - instr.addr); - } else { - /* wide goto or jsr */ - output.writeByte(instr.opcode + (opc_goto_w - opc_goto)); - output.writeInt(instr.succs[0].addr - instr.addr); - } + output.writeByte(opcode); + output.writeShort(instr.succs[0].getAddr() + - instr.getAddr()); break; case opc_tableswitch: { - output.writeByte(instr.opcode); - int align = 3-(instr.addr % 4); + output.writeByte(opcode); + int align = 3-(instr.getAddr() % 4); int numcases = instr.succs.length - 1; output.write(new byte[align]); /* def */ - output.writeInt(instr.succs[numcases].addr - instr.addr); + output.writeInt(instr.succs[numcases].getAddr() - instr.getAddr()); /* low */ - output.writeInt(instr.intData); + output.writeInt(instr.getIntData()); /* high */ - output.writeInt(instr.intData + numcases - 1); + output.writeInt(instr.getIntData() + numcases - 1); for (int i=0; i < numcases; i++) - output.writeInt(instr.succs[i].addr - instr.addr); + output.writeInt(instr.succs[i].getAddr() - instr.getAddr()); break; } case opc_lookupswitch: { - output.writeByte(instr.opcode); - int[] values = (int[]) instr.objData; - int align = 3-(instr.addr % 4); + output.writeByte(opcode); + int[] values = instr.getValues(); + int align = 3-(instr.getAddr() % 4); int numcases = values.length; output.write(new byte[align]); /* def */ - output.writeInt(instr.succs[numcases].addr - instr.addr); + output.writeInt(instr.succs[numcases].getAddr() - instr.getAddr()); output.writeInt(numcases); for (int i=0; i < numcases; i++) { output.writeInt(values[i]); - output.writeInt(instr.succs[i].addr - instr.addr); + output.writeInt(instr.succs[i].getAddr() - instr.getAddr()); } break; } @@ -980,34 +1154,35 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { case opc_getfield: case opc_putstatic: case opc_putfield: - output.writeByte(instr.opcode); + output.writeByte(opcode); output.writeShort(gcp.putRef(gcp.FIELDREF, - (Reference) instr.objData)); + instr.getReference())); break; case opc_invokespecial: case opc_invokestatic: case opc_invokeinterface: - case opc_invokevirtual: - output.writeByte(instr.opcode); - if (instr.opcode == opc_invokeinterface) { - output.writeShort(gcp.putRef(gcp.INTERFACEMETHODREF, - (Reference) instr.objData)); - output.writeByte(instr.intData); + 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, - (Reference) instr.objData)); + output.writeShort(gcp.putRef(gcp.METHODREF, ref)); break; + } case opc_new: case opc_checkcast: case opc_instanceof: - output.writeByte(instr.opcode); - output.writeShort(gcp.putClassType((String) instr.objData)); + output.writeByte(opcode); + output.writeShort(gcp.putClassType(instr.getClazzType())); break; case opc_multianewarray: - if (instr.intData == 1) { - String clazz = ((String) instr.objData).substring(1); + if (instr.getIntData() == 1) { + String clazz = instr.getClazzType().substring(1); int index = newArrayTypes.indexOf(clazz.charAt(0)); if (index != -1) { output.writeByte(opc_newarray); @@ -1017,30 +1192,60 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { output.writeShort(gcp.putClassType(clazz)); } } else { - output.writeByte(instr.opcode); - output.writeShort(gcp.putClassType((String)instr.objData)); - output.writeByte(instr.intData); + output.writeByte(opcode); + output.writeShort(gcp.putClassType(instr.getClazzType())); + output.writeByte(instr.getIntData()); } 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: - if (instr.opcode == opc_xxxunusedxxx - || instr.opcode >= opc_breakpoint) - throw new ClassFormatError("Invalid opcode "+instr.opcode); - else if (instr.length != 1) - throw new ClassFormatError("Length differs at " - + instr.addr + " opcode " - + opcodeString[instr.opcode]); - else - output.writeByte(instr.opcode); + throw new ClassFormatError("Invalid opcode "+opcode); } } output.writeShort(exceptionHandlers.length); for (int i=0; i< exceptionHandlers.length; i++) { - output.writeShort(exceptionHandlers[i].start.addr); - output.writeShort(exceptionHandlers[i].end.nextByAddr.addr); - output.writeShort(exceptionHandlers[i].catcher.addr); + 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)); } @@ -1085,6 +1290,36 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes { return methodInfo; } + public Collection getInstructions() { + return new AbstractCollection() { + public int size() { + return instructionCount; + } + + public Iterator iterator() { + return new Iterator() { + Instruction instr = firstInstr; + + public boolean hasNext() { + return instr != null; + } + + public Object next() { + if (instr == null) + throw new NoSuchElementException(); + Instruction result = instr; + instr = instr.getNextByAddr(); + return result; + } + + public void remove() { + instr.getPrevByAddr().removeInstruction(); + } + }; + } + }; + } + public Instruction getFirstInstr() { return firstInstr; } diff --git a/jode/jode/bytecode/ClassInfo.java b/jode/jode/bytecode/ClassInfo.java index e0482cb..1a2489e 100644 --- a/jode/jode/bytecode/ClassInfo.java +++ b/jode/jode/bytecode/ClassInfo.java @@ -19,12 +19,17 @@ package jode.bytecode; import jode.GlobalOptions; -import jode.type.Type; -import java.io.*; -import java.util.*; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Enumeration; ///#ifdef JDK12 +///import java.util.Map; +///import java.util.HashMap; ///import java.lang.ref.WeakReference; ///import java.lang.ref.ReferenceQueue; +///#else +import java.util.Hashtable; ///#endif import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -472,7 +477,7 @@ public class ClassInfo extends BinaryInfo { } fields = new FieldInfo[fs.length]; for (int i = fs.length; --i >= 0; ) { - String type = Type.getSignature(fs[i].getType()); + String type = TypeSignature.getSignature(fs[i].getType()); fields[i] = new FieldInfo (this, fs[i].getName(), type, fs[i].getModifiers()); } @@ -489,7 +494,7 @@ public class ClassInfo extends BinaryInfo { } methods = new MethodInfo[ms.length]; for (int i = ms.length; --i >= 0; ) { - String type = Type.getSignature + String type = TypeSignature.getSignature (ms[i].getParameterTypes(), ms[i].getReturnType()); methods[i] = new MethodInfo (this, ms[i].getName(), type, ms[i].getModifiers()); diff --git a/jode/jode/bytecode/ConstantPool.java b/jode/jode/bytecode/ConstantPool.java index 36e5b17..4aec04c 100644 --- a/jode/jode/bytecode/ConstantPool.java +++ b/jode/jode/bytecode/ConstantPool.java @@ -18,8 +18,8 @@ */ package jode.bytecode; -import java.io.*; -import jode.type.Type; +import java.io.DataInputStream; +import java.io.IOException; /** * This class represent the constant pool. @@ -45,76 +45,6 @@ public class ConstantPool { Object[] constants; - void checkClassName(String clName) throws ClassFormatException { - boolean start = true; - for (int i=0; i< clName.length(); i++) { - char c = clName.charAt(i); - if (c == '/') - start = true; - else if (start && Character.isJavaIdentifierStart(c)) - start = false; - else if ((start && false /*XXX*/) - || !Character.isJavaIdentifierPart(c)) - throw new ClassFormatException("Illegal java class name: " - + clName); - } - } - - void checkTypeSig(String typesig, boolean isMethod) - throws ClassFormatException { - try { - int i = 0; - if (isMethod) { - if (typesig.charAt(i++) != '(') - throw new ClassFormatException - ("Type sig doesn't match tag: "+typesig); - while (typesig.charAt(i) != ')') { - while (typesig.charAt(i) == '[') { - i++; - if (i >= typesig.length()) - throw new ClassFormatException - ("Type sig error: "+typesig); - } - if (typesig.charAt(i) == 'L') { - int end = typesig.indexOf(';', i); - if (end == -1) - throw new ClassFormatException - ("Type sig error: "+typesig); - checkClassName(typesig.substring(i+1, end)); - i = end; - } else { - if ("ZBSCIJFD".indexOf(typesig.charAt(i)) == -1) - throw new ClassFormatException - ("Type sig error: "+typesig); - } - i++; - } - i++; - } - while (typesig.charAt(i) == '[') - i++; - if (typesig.charAt(i) == 'L') { - int end = typesig.indexOf(';', i); - if (i == -1) - throw new ClassFormatException - ("Type sig error: "+typesig); - checkClassName(typesig.substring(i+1, end)); - i = end; - } else { - if ("ZBSCIJFD".indexOf(typesig.charAt(i)) == -1) - if (!isMethod || typesig.charAt(i) != 'V') - throw new ClassFormatException - ("Type sig error: "+typesig); - } - if (i+1 != typesig.length()) - throw new ClassFormatException - ("Type sig error: "+typesig); - } catch (StringIndexOutOfBoundsException ex) { - throw new ClassFormatException - ("Incomplete type sig: "+typesig); - } - } - public ConstantPool () { } @@ -195,7 +125,14 @@ public class ConstantPool { if (tags[nameTypeIndex] != NAMEANDTYPE) throw new ClassFormatException("Tag mismatch"); String type = getUTF8(indices2[nameTypeIndex]); - checkTypeSig(type, tags[i] != FIELDREF); + try { + if (tags[i] == FIELDREF) + TypeSignature.checkTypeSig(type); + else + TypeSignature.checkMethodTypeSig(type); + } catch (IllegalArgumentException ex) { + throw new ClassFormatException(ex.getMessage()); + } String clName = getClassType(classIndex); constants[i] = Reference.getReference (clName, getUTF8(indices1[nameTypeIndex]), type); @@ -224,12 +161,15 @@ public class ConstantPool { if (tags[i] != CLASS) throw new ClassFormatException("Tag mismatch"); String clName = getUTF8(indices1[i]); - if (clName.charAt(0) == '[') - checkTypeSig(clName, false); - else { - checkClassName(clName); + if (clName.charAt(0) != '[') { clName = ("L"+clName+';').intern(); } + try { + TypeSignature.checkTypeSig(clName); + } catch (IllegalArgumentException ex) { + throw new ClassFormatException(ex.getMessage()); + } + return clName; } @@ -239,7 +179,11 @@ public class ConstantPool { if (tags[i] != CLASS) throw new ClassFormatException("Tag mismatch"); String clName = getUTF8(indices1[i]); - checkClassName(clName); + try { + TypeSignature.checkTypeSig("L"+clName+";"); + } catch (IllegalArgumentException ex) { + throw new ClassFormatException(ex.getMessage()); + } return clName.replace('/','.').intern(); } diff --git a/jode/jode/bytecode/FieldInfo.java b/jode/jode/bytecode/FieldInfo.java index d67f409..19ceb9b 100644 --- a/jode/jode/bytecode/FieldInfo.java +++ b/jode/jode/bytecode/FieldInfo.java @@ -18,7 +18,9 @@ */ package jode.bytecode; -import java.io.*; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.lang.reflect.Modifier; public class FieldInfo extends BinaryInfo { diff --git a/jode/jode/bytecode/GrowableConstantPool.java b/jode/jode/bytecode/GrowableConstantPool.java index 88a938a..6d605ff 100644 --- a/jode/jode/bytecode/GrowableConstantPool.java +++ b/jode/jode/bytecode/GrowableConstantPool.java @@ -18,8 +18,8 @@ */ package jode.bytecode; -import java.io.*; -import jode.type.Type; +import java.io.DataOutputStream; +import java.io.IOException; import java.util.Hashtable; /** @@ -60,7 +60,7 @@ public class GrowableConstantPool extends ConstantPool { } } - int putConstant(int tag, Object constant) { + private int putConstant(int tag, Object constant) { String key = "" + (char)tag + constant; Integer index = (Integer) entryToIndex.get(key); if (index != null) @@ -74,7 +74,7 @@ public class GrowableConstantPool extends ConstantPool { return newIndex; } - int putLongConstant(int tag, Object constant) { + private int putLongConstant(int tag, Object constant) { String key = "" + (char)tag + constant; Integer index = (Integer) entryToIndex.get(key); if (index != null) @@ -112,13 +112,17 @@ public class GrowableConstantPool extends ConstantPool { public int putClassName(String name) { name = name.replace('.','/'); + TypeSignature.checkTypeSig("L"+name+";"); return putIndexed(""+(char) CLASS + name, CLASS, putUTF8(name), 0); } public int putClassType(String name) { + TypeSignature.checkTypeSig(name); if (name.charAt(0) == 'L') name = name.substring(1, name.length()-1); + else if (name.charAt(0) != '[') + throw new IllegalArgumentException("wrong class type: "+name); return putIndexed(""+(char) CLASS + name, CLASS, putUTF8(name), 0); } @@ -127,6 +131,11 @@ public class GrowableConstantPool extends ConstantPool { String className = ref.getClazz(); String typeSig = ref.getType(); String nameAndType = ref.getName() + "/" + typeSig; + if (tag == FIELDREF) + TypeSignature.checkTypeSig(typeSig); + else + TypeSignature.checkMethodTypeSig(typeSig); + int classIndex = putClassType(className); int nameIndex = putUTF8(ref.getName()); diff --git a/jode/jode/bytecode/Instruction.java b/jode/jode/bytecode/Instruction.java index 7e99057..f65c9d2 100644 --- a/jode/jode/bytecode/Instruction.java +++ b/jode/jode/bytecode/Instruction.java @@ -20,85 +20,298 @@ package jode.bytecode; import java.util.Vector; import java.util.Enumeration; -import jode.type.Type; -import jode.type.MethodType; /** * This class represents an instruction in the byte code. * - * For simplicity currently most fields are public. You shouldn't change - * many of them, though. */ -public class Instruction implements Opcodes{ - public BytecodeInfo codeinfo; +public final class Instruction implements Opcodes{ + private BytecodeInfo codeinfo; /** * The opcode of the instruction. We map some opcodes, e.g. *
      * iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc.
      * 
*/ - public int opcode; + private int opcode; /** * If this opcode uses a local this gives the slot. This info is * used when swapping locals. */ - public int localSlot = -1; + private int localSlot = -1; /** - * Optional object data for this opcode. This is mostly used for - * method/field/class references, but also for a value array - * in a lookupswitch. + * Optional object data for this opcode. There are four different + * usages of this field: + *
+ *
opc_ldc / opc_ldc2_w
+ *
The constant of type Integer/Long/Float/Double/String.
+ *
opc_invokexxx / opc_xxxfield / opc_xxxstatic
+ *
The field/method Reference
+ *
opc_new / opc_checkcast / opc_instanceof / opc_multianewarray
+ *
The typesignature of the class/array
+ *
opc_lookupswitch
+ *
The array of values of type int[]
+ *
*/ - public Object objData; + private Object objData; /** * Optional integer data for this opcode. There are various uses - * for this. + * for this: + *
+ *
opc_iinc
+ *
The value by which the constant is increased/decreased. (short)
+ *
opc_tableswitch
+ *
The start value of the table
+ *
opc_multianewarray
+ *
The number of dimensions (1..255)
+ *
opc_lookupswitch
+ *
The array of values of type int[]
+ *
*/ - public int intData; + private int intData; /** * The address of this opcode. */ - public int addr; + private int addr; /** * The length of this opcode. You shouldn't touch it, nor rely on * it, since the length of some opcodes may change automagically * (e.g. when changing localSlot iload_0 <-> iload 5) */ - public int length; - /** - * If this is true, the instruction will never flow into the nextByAddr. - */ - public boolean alwaysJumps = false; + private int length; /** * The successors of this opcodes, where flow may lead to * (except that nextByAddr is implicit if !alwaysJump). The * value null is equivalent to an empty array. */ - public Instruction[] succs; + Instruction[] succs; /** * The predecessors of this opcode, orthogonal to the succs array. * This must be null or a non empty array. */ - public Instruction[] preds; + Instruction[] preds; /** * The next instruction in code order. */ - public Instruction nextByAddr; + private Instruction nextByAddr; /** * The previous instruction in code order, useful when changing * the order. */ - public Instruction prevByAddr; + private Instruction prevByAddr; /** * You can use this field to add some info to each instruction. * After using, you must set it to null again. */ - public Object tmpInfo; + private Object tmpInfo; public Instruction(BytecodeInfo ci) { this.codeinfo = ci; } + /** + * Returns the opcode of the instruction. We map some opcodes, e.g. + *
+     * iload_0   -> iload
+     * ldc_w     -> ldc
+     * wide iinc -> iinc
+     * 
+ */ + public final int getOpcode() { + return opcode; + } + + /** + * Returns the address of this opcode. As long as you don't remove + * or insert instructions, you can be sure, that the addresses of the + * opcodes are unique, and that + *
+     * instr.getAddr() + instr.getLength() == instr.getNextByAddr().getAddr()
+     * 
+     *
+     * If you insert/remove Instructions, you should be aware that the
+     * above property is not guaranteed anymore.
+     */
+    public final int getAddr() {
+	return addr;
+    }
+
+    /**
+     * Returns the length of this opcode.  See getAddr() for some
+     * notes.  Note that the length doesn't necessarily reflect the
+     * real length, when this bytecode is written again, since the
+     * length of an ldc instruction depends on the number of entries
+     * in constant pool, and the order they are allocated.  
+     */
+    public final int getLength() {
+	return length;
+    }
+
+    final void setAddr(int addr) {
+	this.addr = addr;
+    }
+    final void setLength(int length) {
+	this.length = length;
+    }
+
+    public final int getLocalSlot() {
+	return localSlot;
+    }
+
+    public final void setLocalSlot(int slot) {
+	localSlot = slot;
+    }
+
+    public final int getIntData()
+    /*{ require { opcode == opc_iinc || opcode == opc_multianewarray
+                  || opcode == opc_tableswitch
+                  :: "Instruction has no int data" } }*/
+    {
+	return intData;
+    }
+
+    public final void setIntData(int data)
+    /*{ require { opcode == opc_iinc || opcode == opc_multianewarray
+                  || opcode == opc_tableswitch
+                  :: "Instruction has no int data" } }*/
+    {
+	this.intData = data;
+    }
+
+    public final Object getConstant() 
+    /*{ require { opcode == opc_ldc || opcode == opc_ldc2_w
+                  :: "Instruction has no constant" } }*/
+    {
+	return objData;
+    }
+
+    public final void setConstant(Object constant) 
+    /*{ require { opcode == opc_ldc || opcode == opc_ldc2_w
+                  :: "Instruction has no constant" } }*/
+    {
+	objData = constant;
+    }
+
+    public final Reference getReference()
+    /*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface
+                  :: "Instruction has no reference" } }*/
+    {
+	return (Reference) objData;
+    }
+
+    public final void setReference(Reference ref)
+    /*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface
+                  :: "Instruction has no reference" } }*/
+    {
+	objData = ref;
+    }
+
+    public final String getClazzType() 
+    /*{ require { opcode == opc_new 
+                  || opcode == opc_checkcast
+                  || opcode == opc_instanceof
+                  || opcode == opc_multianewarray
+		  :: "Instruction has no typesig" } }*/
+    {
+	return (String) objData;
+    }
+
+    public final void setClazzType(String type)
+    /*{ require { opcode == opc_new 
+                  || opcode == opc_checkcast
+                  || opcode == opc_instanceof
+                  || opcode == opc_multianewarray
+		  :: "Instruction has no typesig" } }*/
+    {
+	objData = type;
+    }
+
+    public final int[] getValues()
+    /*{ require { opcode == opc_lookupswitch
+                  :: "Instruction has no values" } }*/
+    {
+	return (int[]) objData;
+    }
+
+    public final void setValues(int[] values) 
+    /*{ require { opcode == opc_lookupswitch
+                  :: "Instruction has no values" } }*/
+    {
+	objData = values;
+    }
+
+    public final boolean doesAlwaysJump() {
+	switch (opcode) {
+	case opc_ret:
+	case opc_goto:
+	case opc_jsr:
+	case opc_tableswitch:
+	case opc_lookupswitch:
+	case opc_ireturn: 
+	case opc_lreturn: 
+	case opc_freturn: 
+	case opc_dreturn: 
+	case opc_areturn:
+	case opc_return: 
+	case opc_athrow:
+	    return true;
+	default:
+	    return false;
+	}
+    }
+
+    public final Instruction[] getPreds() {
+	return preds;
+    }
+
+    public final Instruction[] getSuccs() {
+	return succs;
+    }
+
+    public final Instruction getPrevByAddr() {
+	return prevByAddr;
+    }
+
+    public final Instruction getNextByAddr() {
+	return nextByAddr;
+    }
+
+    public final Object getTmpInfo() {
+	return tmpInfo;
+    }
+
+    public final void setTmpInfo(Object info) {
+	tmpInfo = info;
+    }
+
+    public final void replaceInstruction(int newOpcode) {
+	replaceInstruction(newOpcode, null);
+    }
+
+    public final void replaceInstruction(int newOpcode, 
+					 Instruction[] newSuccs) {
+	if (succs != null && succs != newSuccs) {
+	    for (int i = 0; i< succs.length; i++)
+		succs[i].removePredecessor(this);
+	}
+
+	opcode = newOpcode;
+	localSlot = -1;
+	objData = null;
+	intData = 0;
+	if (succs != newSuccs)
+	    setSuccs(newSuccs);
+    }
+
+    private final void setSuccs(Instruction[] newSuccs) {
+	succs = newSuccs;
+	if (succs != null) {
+	    for (int i = 0; i< succs.length; i++)
+		succs[i].addPredecessor(this);
+	}
+    }
+
     public void addPredecessor(Instruction pred) {
 	if (preds == null) {
 	    preds = new Instruction[] { pred };
@@ -129,8 +342,10 @@ public class Instruction implements Opcodes{
 	}
     }
 
-    public Instruction insertInstruction() {
+    public final Instruction insertInstruction(int opc) {
+	codeinfo.instructionCount++;
 	Instruction newInstr = new Instruction(codeinfo);
+	newInstr.opcode = opc;
 	newInstr.addr = addr;
 
 	newInstr.prevByAddr = prevByAddr;
@@ -153,9 +368,20 @@ public class Instruction implements Opcodes{
 	return newInstr;
     }
 
-    public Instruction appendInstruction() {
+    public final Instruction insertInstruction(int opc, 
+					       Instruction[] newSuccs) {
+	Instruction newInstr = insertInstruction(opc);
+	if (newSuccs != null)
+	    newInstr.setSuccs(newSuccs);
+	return newInstr;
+    }
+
+    public Instruction appendInstruction(int opc) {
+	codeinfo.instructionCount++;
 	Instruction newInstr = new Instruction(codeinfo);
-	newInstr.addr = addr;
+	newInstr.opcode = opc;
+	newInstr.addr = addr + length;
+	newInstr.length = 0;
 	newInstr.nextByAddr = nextByAddr;
 	if (nextByAddr != null)
 	    nextByAddr.prevByAddr = newInstr;
@@ -165,15 +391,32 @@ public class Instruction implements Opcodes{
 	return newInstr;
     }
 
+    public Instruction appendInstruction(int opc, Instruction[] newSuccs) {
+	Instruction newInstr = appendInstruction(opc);
+	if (newSuccs != null)
+	    newInstr.setSuccs(newSuccs);
+	return newInstr;
+    }
+
     /**
      * Removes this instruction (as if it would be replaced by a nop).
      */
     public void removeInstruction() {
-	/* remove from chained list */
-	if (prevByAddr != null)
+	codeinfo.instructionCount--;
+
+	/* remove from chained list and adjust addr / length */
+	if (prevByAddr != null) {
 	    prevByAddr.nextByAddr = nextByAddr;
-	else
+	    prevByAddr.length += length;
+	} else {
+	    if (nextByAddr == null)
+		/* Mustn't happen, each method must include a return */
+		throw new IllegalArgumentException
+		    ("Removing the last instruction of a method!");
 	    codeinfo.firstInstr = nextByAddr;
+	    nextByAddr.addr = 0;
+	    nextByAddr.length += length;
+	}
 
 	if (nextByAddr != null)
 	    nextByAddr.prevByAddr = prevByAddr;
@@ -208,16 +451,7 @@ public class Instruction implements Opcodes{
 	/* adjust exception handlers */
 	Handler[] handlers = codeinfo.getExceptionHandlers();
 	for (int i=0; i< handlers.length; i++) {
-	    if (handlers[i].start == this)
-		handlers[i].start = nextByAddr;
-	    if (handlers[i].end == this)
-		handlers[i].end = prevByAddr;
-	    if (handlers[i].catcher == this)
-		handlers[i].catcher = nextByAddr;
-
-	    if (handlers[i].start == null
-		|| handlers[i].end == null
-		|| handlers[i].end.nextByAddr == handlers[i].start) {
+	    if (handlers[i].start == this && handlers[i].end == this) {
 		/* Remove the handler.
 		 * This is very seldom, so we can make it slow */
 		Handler[] newHandlers = new Handler[handlers.length - 1];
@@ -227,6 +461,13 @@ public class Instruction implements Opcodes{
 		handlers = newHandlers;
 		codeinfo.setExceptionHandlers(newHandlers);
 		i--;
+	    } else {
+		if (handlers[i].start == this)
+		    handlers[i].start = nextByAddr;
+		if (handlers[i].end == this)
+		    handlers[i].end = prevByAddr;
+		if (handlers[i].catcher == this)
+		    handlers[i].catcher = nextByAddr;
 	    }
 	}
 
@@ -234,15 +475,10 @@ public class Instruction implements Opcodes{
 	LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable();
 	if (lvt != null) {
 	    for (int i=0; i< lvt.length; i++) {
-		if (lvt[i].start == this)
-		    lvt[i].start = nextByAddr;
-		if (lvt[i].end == this)
-		    lvt[i].end = prevByAddr;
-		if (lvt[i].start == null
-		    || lvt[i].end == null
-		    || lvt[i].end.nextByAddr == lvt[i].start) {
+		if (lvt[i].start == this && lvt[i].end == this) {
 		    /* Remove the local variable info.
-		     * This is very seldom, so we can make it slow */
+		     * This is very seldom, so we can make it slow
+		     */
 		    LocalVariableInfo[] newLVT = 
 			new LocalVariableInfo[lvt.length - 1];
 		    System.arraycopy(lvt, 0, newLVT, 0, i);
@@ -251,26 +487,33 @@ public class Instruction implements Opcodes{
 		    lvt = newLVT;
 		    codeinfo.setLocalVariableTable(newLVT);
 		    i--;
+		} else {
+		    if (lvt[i].start == this)
+			lvt[i].start = nextByAddr;
+		    if (lvt[i].end == this)
+			lvt[i].end = prevByAddr;
 		}
 	    }
 	}
 	LineNumber[] lnt = codeinfo.getLineNumberTable();
 	if (lnt != null) {
 	    for (int i=0; i< lnt.length; i++) {
-		if (lnt[i].start == this)
-		    lnt[i].start = nextByAddr;
-		if (lnt[i].start == null
-		    || (i+1 < lnt.length && lnt[i].start == lnt[i+1].start)) {
-		    /* Remove the line number.
-		     * This is very seldom, so we can make it slow */
-		    LineNumber[] newLNT = 
-			new LineNumber[lnt.length - 1];
-		    System.arraycopy(lnt, 0, newLNT, 0, i);
-		    System.arraycopy(lnt, i+1, newLNT, i, 
-				     newLNT.length - i);
-		    lnt = newLNT;
-		    codeinfo.setLineNumberTable(newLNT);
-		    i--;
+		if (lnt[i].start == this) {
+		    if (nextByAddr == null
+			|| (i+1 < lnt.length 
+			    && lnt[i+1].start == nextByAddr)) {
+			/* Remove the line number.
+			 * This is very seldom, so we can make it slow */
+			LineNumber[] newLNT = 
+			    new LineNumber[lnt.length - 1];
+			System.arraycopy(lnt, 0, newLNT, 0, i);
+			System.arraycopy(lnt, i+1, newLNT, i, 
+					 newLNT.length - i);
+			lnt = newLNT;
+			codeinfo.setLineNumberTable(newLNT);
+			i--;
+		    } else
+			lnt[i].start = nextByAddr;
 		}
 	    }
 	}
@@ -285,10 +528,10 @@ public class Instruction implements Opcodes{
      * get the number of pops, the second the number of pushes.  
      */
     public void getStackPopPush(int[] poppush)
-        /*{ require { poppush != null && poppush.length == 2
-	  :: "poppush must be an array of two ints" } } */
+    /*{ require { poppush != null && poppush.length == 2
+        :: "poppush must be an array of two ints" } } */
     {
-	byte delta = stackDelta[opcode];
+	byte delta = (byte) stackDelta.charAt(opcode);
 	if (delta < 0x40) {
 	    poppush[0] = delta & 7;
 	    poppush[1] = delta >> 3;
@@ -299,12 +542,10 @@ public class Instruction implements Opcodes{
 	    case opc_invokestatic:
 	    case opc_invokeinterface: {
 		Reference ref = (Reference) objData;
-		MethodType mt = (MethodType) Type.tType(ref.getType());
-		poppush[1] = mt.getReturnType().stackSize();
-		
+		String typeSig = ref.getType();
 		poppush[0] = opcode != opc_invokestatic ? 1 : 0;
-		for (int i = mt.getParameterTypes().length-1; i >= 0; i--)
-		    poppush[0] += mt.getParameterTypes()[i].stackSize();
+		poppush[0] += TypeSignature.getArgumentSize(typeSig);
+		poppush[1] = TypeSignature.getReturnSize(typeSig);
 		break;
 	    }
 	    
@@ -312,7 +553,7 @@ public class Instruction implements Opcodes{
 	    case opc_putstatic: {
 		Reference ref = (Reference) objData;
 		poppush[1] = 0;
-		poppush[0] = Type.tType(ref.getType()).stackSize();
+		poppush[0] = TypeSignature.getTypeSize(ref.getType());
 		if (opcode == opc_putfield)
 		    poppush[0]++;
 		break;
@@ -320,7 +561,7 @@ public class Instruction implements Opcodes{
 	    case opc_getstatic:
 	    case opc_getfield: {
 		Reference ref = (Reference) objData;
-		poppush[1] = Type.tType(ref.getType()).stackSize();
+		poppush[1] = TypeSignature.getTypeSize(ref.getType());
 		poppush[0] = opcode == opc_getfield ? 1 : 0;
 		break;
 	    }
@@ -343,7 +584,7 @@ public class Instruction implements Opcodes{
 	int count = poppush[1];
 	Instruction instr = this;
 	while (true) {
-	    if (instr.succs != null || instr.alwaysJumps)
+	    if (instr.succs != null || instr.doesAlwaysJump())
 		return null;
 	    instr = instr.nextByAddr;
 	    if (instr.preds != null)
@@ -364,7 +605,7 @@ public class Instruction implements Opcodes{
 	    if (instr.preds != null)
 		return null;
 	    instr = instr.prevByAddr;
-	    if (instr == null || instr.succs != null || instr.alwaysJumps)
+	    if (instr == null || instr.succs != null || instr.doesAlwaysJump())
 		return null;
 
 	    instr.getStackPopPush(poppush);
@@ -379,16 +620,13 @@ public class Instruction implements Opcodes{
 	StringBuffer result = new StringBuffer(String.valueOf(addr))
 	    .append('_').append(Integer.toHexString(hashCode()))
 	    .append(": ").append(opcodeString[opcode]);
-	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:
-	case opc_ret:
+	if (localSlot != -1)
 	    result.append(" ").append(localSlot);
-	    break;
+	if (succs != null && succs.length == 1)
+	    result.append(" ").append(succs[0].addr);
+	switch (opcode) {
 	case opc_iinc:
-	    result.append(" ").append(localSlot).append(" ").append(intData);
+	    result.append(" ").append(intData);
 	    break;
 	case opc_ldc: case opc_ldc2_w:    
 	case opc_getstatic: case opc_getfield:
@@ -399,42 +637,20 @@ public class Instruction implements Opcodes{
 	case opc_instanceof:
 	    result.append(" ").append(objData);
 	    break;
-	case opc_anewarray: 
-	case opc_newarray:
-	    result.append(" ").append(((String)objData).substring(1));
-	    break;
 	case opc_multianewarray:
 	case opc_invokeinterface:
 	    result.append(" ").append(objData).append(" ").append(intData);
 	    break;
-	case opc_ifeq: case opc_ifne: 
-	case opc_iflt: case opc_ifge: 
-	case opc_ifgt: case opc_ifle:
-	case opc_if_icmpeq: case opc_if_icmpne:
-	case opc_if_icmplt: case opc_if_icmpge: 
-	case opc_if_icmpgt: case opc_if_icmple: 
-	case opc_if_acmpeq: case opc_if_acmpne:
-	case opc_ifnull: case opc_ifnonnull:
-	case opc_goto:
-	case opc_jsr:
-	    result.append(" ").append(succs[0].addr);
-	    break;
 	}
 	return result.toString();
     }
 
     public String toString() {
-	return ""+addr+"_"+Integer.toHexString(hashCode());
+        return "" + addr + "_" + Integer.toHexString(hashCode());
     }
 
-    public final static byte[] stackDelta;
-
-    static { 
-	stackDelta = new byte[202];
-	for (int i=0; i < 202; i++) {
-	    stackDelta[i] = (byte) "\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\010\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\010".charAt(i);
-	}
-    }
+    private final static String stackDelta = 
+	"\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\010\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\010";
 
     /* stackDelta contains \100 if stack count of opcode is variable
      * \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise
diff --git a/jode/jode/bytecode/MethodInfo.java b/jode/jode/bytecode/MethodInfo.java
index 37d2dfe..cbcc98f 100644
--- a/jode/jode/bytecode/MethodInfo.java
+++ b/jode/jode/bytecode/MethodInfo.java
@@ -18,7 +18,9 @@
  */
 
 package jode.bytecode;
-import java.io.*;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
 import java.lang.reflect.Modifier;
 
 public class MethodInfo extends BinaryInfo {
diff --git a/jode/jode/bytecode/Reference.java b/jode/jode/bytecode/Reference.java
index 981b1f5..97d2685 100644
--- a/jode/jode/bytecode/Reference.java
+++ b/jode/jode/bytecode/Reference.java
@@ -21,8 +21,10 @@ package jode.bytecode;
 ///#ifdef JDK12
 ///import java.lang.ref.WeakReference;
 ///import java.lang.ref.ReferenceQueue;
+///import java.lang.ref.HashMap;
+///#else
+import java.util.Hashtable;
 ///#endif
-import java.util.*;
 
 /**
  * This class represents a field or method reference.
diff --git a/jode/jode/bytecode/SearchPath.java b/jode/jode/bytecode/SearchPath.java
index 6087c55..b5e4849 100644
--- a/jode/jode/bytecode/SearchPath.java
+++ b/jode/jode/bytecode/SearchPath.java
@@ -18,10 +18,23 @@
  */
 
 package jode.bytecode;
-import java.io.*;
-import java.net.*;
-import java.util.zip.*;
-import java.util.*;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
 import jode.GlobalOptions;
 
 /**
diff --git a/jode/jode/bytecode/TypeSignature.java b/jode/jode/bytecode/TypeSignature.java
new file mode 100644
index 0000000..136b7c9
--- /dev/null
+++ b/jode/jode/bytecode/TypeSignature.java
@@ -0,0 +1,196 @@
+package jode.bytecode;
+import jode.AssertError;
+
+/**
+ * This class contains some static methods to handle type signatures.
+ */
+public class TypeSignature {
+    /**
+     * This is a private method for generating the signature of a
+     * given type.  
+     */
+    private static final StringBuffer appendSignature(StringBuffer sb,
+						      Class javaType) {
+	if (javaType.isPrimitive()) {
+	    if (javaType == Boolean.TYPE)
+		return sb.append('Z');
+	    else if (javaType == Byte.TYPE)
+		return sb.append('B');
+	    else if (javaType == Character.TYPE)
+		return sb.append('C');
+	    else if (javaType == Short.TYPE)
+		return sb.append('S');
+	    else if (javaType == Integer.TYPE)
+		return sb.append('I');
+	    else if (javaType == Long.TYPE)
+		return sb.append('J');
+	    else if (javaType == Float.TYPE)
+		return sb.append('F');
+	    else if (javaType == Double.TYPE)
+		return sb.append('D');
+	    else if (javaType == Void.TYPE)
+		return sb.append('V');
+	    else
+		throw new AssertError("Unknown primitive type: "+javaType);
+	} else if (javaType.isArray()) {
+	    return appendSignature(sb.append('['), 
+				   javaType.getComponentType());
+	} else {
+	    return sb.append('L')
+		.append(javaType.getName().replace('.','/')).append(';');
+	}
+    }
+
+    /**
+     * Generate the signature for the given Class.
+     * @param clazz a java.lang.Class, this may also be a primitive or
+     * array type.
+     * @return the type signature (see section 4.3.2 Field Descriptors
+     * of the JVM specification)
+     */
+    public static String getSignature(Class clazz) {
+	return appendSignature(new StringBuffer(), clazz).toString();
+    }
+ 
+    /**
+     * Generate a method signature.
+     * @param paramT the java.lang.Class of the parameter types of the method.
+     * @param returnT the java.lang.Class of the return type of the method.
+     * @return the method signature (see section 4.3.3 Method Descriptors
+     * of the JVM specification)
+     */
+    public static String getSignature(Class paramT[], Class returnT) {
+	StringBuffer sig = new StringBuffer("(");
+	for (int i=0; i< paramT.length; i++)
+	    appendSignature(sig, paramT[i]);
+	return appendSignature(sig.append(')'), returnT).toString();
+    }
+
+    /**
+     * Check if the given type is a two slot type.
+     */
+    private static boolean usingTwoSlots(char type) {
+	return "JD".indexOf(type) >= 0;
+    }
+
+    /**
+     * Returns the number of words, an object of the given simple type
+     * signature takes.  
+     */
+    public static int getTypeSize(String typeSig) {
+	return usingTwoSlots(typeSig.charAt(0)) ? 2 : 1;
+    }
+    
+    /**
+     * Returns the number of words, the arguments for the given method
+     * type signature takes.  
+     */
+    public static int getArgumentSize(String methodTypeSig) {
+	int nargs = 0;
+	int i = 1;
+	for (;;) {
+	    char c = methodTypeSig.charAt(i++);
+	    if (c == ')')
+		return nargs;
+	    if (usingTwoSlots(c))
+		nargs += 2;
+	    else {
+		while (c == '[')
+		    c = methodTypeSig.charAt(i++);
+		if (c == 'L')
+		    i = methodTypeSig.indexOf(';', i) + 1;
+		nargs++;
+	    }
+	}
+    }
+
+    /**
+     * Returns the number of words, an object of the given simple type
+     * signature takes.  
+     */
+    public static int getReturnSize(String methodTypeSig) {
+	char returnType = methodTypeSig.charAt(methodTypeSig.indexOf(')')+1);
+	return returnType == 'V' ? 0 
+	    : usingTwoSlots(returnType) ? 2 : 1;
+    }
+
+    private static void checkClassName(String clName) 
+	throws IllegalArgumentException 
+    {
+	boolean start = true;
+	for (int i=0; i< clName.length(); i++) {
+	    char c = clName.charAt(i);
+	    if (c == '/')
+		start = true;
+	    else if (start && Character.isJavaIdentifierStart(c)) 
+		start = false;
+	    else if ((start && false /*XXX*/)
+		     || !Character.isJavaIdentifierPart(c))
+		throw new IllegalArgumentException("Illegal java class name: "
+						   + clName);
+	}
+    }
+
+    /**
+     * Check if there is a valid simple type signature starting at index
+     * in string typesig.
+     * @return the index at which the type signature ends.
+     * @exception IllegalArgumentException if there was an illegal character.
+     * @exception StringIndexOutOfBoundsException if the typesig ended early.
+     */
+    private static int checkTypeSig(String typesig, int index) {
+	char c = typesig.charAt(index++);
+	while (c == '[')
+	    c = typesig.charAt(index++);
+	if (c == 'L') {
+	    int end = typesig.indexOf(';', index);
+	    // next instruction throws StringIndexOutOfBounds, if no ; exists.
+	    checkClassName(typesig.substring(index+1, end));
+	    index = end + 1;
+	} else {
+	    if ("ZBSCIJFD".indexOf(c) == -1)
+		throw new IllegalArgumentException("Type sig error: "+typesig);
+	}
+	return index;
+    }
+
+    public static void checkTypeSig(String typesig) 
+	throws IllegalArgumentException
+    {
+	try {
+	    if (checkTypeSig(typesig, 0) != typesig.length())
+		throw new IllegalArgumentException
+		    ("Type sig too long: "+typesig);
+	} catch (StringIndexOutOfBoundsException ex) {
+	    throw new IllegalArgumentException
+		("Incomplete type sig: "+typesig);
+	}
+    }
+
+    public static void checkMethodTypeSig(String typesig) 
+	throws IllegalArgumentException
+    {
+	try {
+	    if (typesig.charAt(0) != '(')
+		throw new IllegalArgumentException
+		    ("No method signature: "+typesig);
+	    int i = 1;
+	    while (typesig.charAt(i) != ')')
+		i = checkTypeSig(typesig, i);
+	    // skip closing parenthesis.
+	    i++;
+	    if (typesig.charAt(i) == 'V')
+		// accept void return type.
+		i++;
+	    else
+		i = checkTypeSig(typesig, i);
+	    if (i != typesig.length())
+		throw new IllegalArgumentException
+		    ("Type sig too long: "+typesig);
+	} catch (StringIndexOutOfBoundsException ex) {
+	    throw new IllegalArgumentException
+		("Incomplete type sig: "+typesig);
+	}
+    }
+}
+