collection interface for instructions.

made instructions smaller
canonicalized switch opcodes
use UnifyHash
More methods for TypeSignature


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1095 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 26 years ago
parent ddbf2c969a
commit 996fc49dbd
  1. 30
      jode/jode/bytecode/BinaryInfo.java.in
  2. 584
      jode/jode/bytecode/BytecodeInfo.java.in
  3. 67
      jode/jode/bytecode/ClassInfo.java.in
  4. 457
      jode/jode/bytecode/Instruction.java
  5. 94
      jode/jode/bytecode/Reference.java
  6. 72
      jode/jode/bytecode/Reference.java.in
  7. 69
      jode/jode/bytecode/TypeSignature.java

@ -27,6 +27,7 @@ import java.io.InputStream;
import jode.util.SimpleMap; import jode.util.SimpleMap;
import @COLLECTIONS@.Map; import @COLLECTIONS@.Map;
import @COLLECTIONS@.Collections;
import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Iterator;
@ -44,7 +45,7 @@ public class BinaryInfo {
public static final int OUTERCLASSES = 0x40; public static final int OUTERCLASSES = 0x40;
public static final int FULLINFO = 0xff; public static final int FULLINFO = 0xff;
private Map unknownAttributes = new SimpleMap(); private Map unknownAttributes = null;
protected void skipAttributes(DataInputStream input) throws IOException { protected void skipAttributes(DataInputStream input) throws IOException {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
@ -70,9 +71,12 @@ public class BinaryInfo {
int howMuch) throws IOException { int howMuch) throws IOException {
byte[] data = new byte[length]; byte[] data = new byte[length];
input.readFully(data); input.readFully(data);
if ((howMuch & ALL_ATTRIBUTES) != 0) if ((howMuch & ALL_ATTRIBUTES) != 0) {
if (unknownAttributes == null)
unknownAttributes = new SimpleMap();
unknownAttributes.put(name, data); unknownAttributes.put(name, data);
} }
}
static class ConstrainedInputStream extends FilterInputStream { static class ConstrainedInputStream extends FilterInputStream {
int length; int length;
@ -129,7 +133,7 @@ public class BinaryInfo {
DataInputStream input, DataInputStream input,
int howMuch) throws IOException { int howMuch) throws IOException {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
unknownAttributes.clear(); unknownAttributes = null;
for (int i=0; i< count; i++) { for (int i=0; i< count; i++) {
String attrName = String attrName =
constantPool.getUTF8(input.readUnsignedShort()); constantPool.getUTF8(input.readUnsignedShort());
@ -144,6 +148,8 @@ public class BinaryInfo {
} }
protected void prepareAttributes(GrowableConstantPool gcp) { protected void prepareAttributes(GrowableConstantPool gcp) {
if (unknownAttributes == null)
return;
Iterator i = unknownAttributes.keySet().iterator(); Iterator i = unknownAttributes.keySet().iterator();
while (i.hasNext()) while (i.hasNext())
gcp.putUTF8((String) i.next()); gcp.putUTF8((String) i.next());
@ -157,9 +163,12 @@ public class BinaryInfo {
protected void writeAttributes protected void writeAttributes
(GrowableConstantPool constantPool, (GrowableConstantPool constantPool,
DataOutputStream output) throws IOException { DataOutputStream output) throws IOException {
int count = unknownAttributes.size() + getKnownAttributeCount(); int count = getKnownAttributeCount();
if (unknownAttributes != null)
count += unknownAttributes.size();
output.writeShort(count); output.writeShort(count);
writeKnownAttributes(constantPool, output); writeKnownAttributes(constantPool, output);
if (unknownAttributes != null) {
Iterator i = unknownAttributes.entrySet().iterator(); Iterator i = unknownAttributes.entrySet().iterator();
while (i.hasNext()) { while (i.hasNext()) {
Map.Entry e = (Map.Entry) i.next(); Map.Entry e = (Map.Entry) i.next();
@ -170,32 +179,43 @@ public class BinaryInfo {
output.write(data); output.write(data);
} }
} }
}
public int getAttributeSize() { public int getAttributeSize() {
int size = 2; /* attribute count */ int size = 2; /* attribute count */
if (unknownAttributes != null) {
Iterator i = unknownAttributes.values().iterator(); Iterator i = unknownAttributes.values().iterator();
while (i.hasNext()) while (i.hasNext())
size += 2 + 4 + ((byte[]) i.next()).length; size += 2 + 4 + ((byte[]) i.next()).length;
}
return size; return size;
} }
public byte[] findAttribute(String name) { public byte[] findAttribute(String name) {
if (unknownAttributes != null)
return (byte[]) unknownAttributes.get(name); return (byte[]) unknownAttributes.get(name);
return null;
} }
public Iterator getAttributes() { public Iterator getAttributes() {
if (unknownAttributes != null)
return unknownAttributes.values().iterator(); return unknownAttributes.values().iterator();
return Collections.EMPTY_SET.iterator();
} }
public void setAttribute(String name, byte[] content) { public void setAttribute(String name, byte[] content) {
if (unknownAttributes == null)
unknownAttributes = new SimpleMap();
unknownAttributes.put(name, content); unknownAttributes.put(name, content);
} }
public byte[] removeAttribute(String name) { public byte[] removeAttribute(String name) {
if (unknownAttributes != null)
return (byte[]) unknownAttributes.remove(name); return (byte[]) unknownAttributes.remove(name);
return null;
} }
public void removeAllAttributes() { public void removeAllAttributes() {
unknownAttributes.clear(); unknownAttributes = null;
} }
} }

@ -29,9 +29,10 @@ import java.util.Vector;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import @COLLECTIONS@.Collection; import @COLLECTIONS@.List;
import @COLLECTIONS@.AbstractCollection; import @COLLECTIONS@.AbstractSequentialList;
import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
/** /**
@ -44,16 +45,136 @@ import @COLLECTIONS@.Iterator;
*/ */
public class BytecodeInfo extends BinaryInfo implements Opcodes { public class BytecodeInfo extends BinaryInfo implements Opcodes {
MethodInfo methodInfo; private MethodInfo methodInfo;
private int maxStack, maxLocals;
private Handler[] exceptionHandlers;
private LocalVariableInfo[] lvt;
private LineNumber[] lnt;
ConstantPool cp; private InstructionList instructions;
int maxStack, maxLocals;
int codeLength; private class InstructionList extends AbstractSequentialList {
Instruction firstInstr = null; Instruction borderInstr;
int instructionCount = 0; int instructionCount = 0;
Handler[] exceptionHandlers;
LocalVariableInfo[] lvt; InstructionList() {
LineNumber[] lnt; borderInstr = new Instruction(opc_xxxunusedxxx);
borderInstr.nextByAddr = borderInstr.prevByAddr = borderInstr;
}
public int size() {
return instructionCount;
}
private 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 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);
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) { public BytecodeInfo(MethodInfo mi) {
methodInfo = mi; methodInfo = mi;
@ -74,7 +195,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if ((howMuch & ALL_ATTRIBUTES) != 0 if ((howMuch & ALL_ATTRIBUTES) != 0
&& name.equals("LocalVariableTable")) { && name.equals("LocalVariableTable")) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
GlobalOptions.err.println("LocalVariableTable of "+methodInfo.clazzInfo.getName() + "." + methodInfo.getName()); GlobalOptions.err.println("LocalVariableTable of "+methodInfo);
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
if (length != 2 + count * 10) { if (length != 2 + count * 10) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
@ -89,22 +210,21 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
int nameIndex = input.readUnsignedShort(); int nameIndex = input.readUnsignedShort();
int typeIndex = input.readUnsignedShort(); int typeIndex = input.readUnsignedShort();
int slot = input.readUnsignedShort(); int slot = input.readUnsignedShort();
Instruction startInstr, endInstr; Instruction startInstr = null;
for (startInstr = firstInstr; Instruction endInstr = null;
startInstr.getAddr() < start && startInstr != null;
startInstr = startInstr.getNextByAddr()) { for (Iterator iter = instructions.iterator();
/* empty */ iter.hasNext(); ) {
} Instruction instr = (Instruction) iter.next();
endInstr = startInstr; if (instr.getAddr() == start)
if (startInstr != null) { startInstr = instr;
while (endInstr.getNextByAddr() != null if (instr.getNextAddr() == end)
&& endInstr.getNextByAddr().getAddr() < end) endInstr = instr;
endInstr = endInstr.getNextByAddr(); if (instr.getAddr() >= end)
break;
} }
if (startInstr == null if (startInstr == null
|| startInstr.getAddr() != start
|| endInstr == null || endInstr == null
|| endInstr.getAddr() + endInstr.getLength() != end
|| nameIndex == 0 || typeIndex == 0 || nameIndex == 0 || typeIndex == 0
|| slot >= maxLocals || slot >= maxLocals
|| cp.getTag(nameIndex) != cp.UTF8 || cp.getTag(nameIndex) != cp.UTF8
@ -142,14 +262,15 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
lnt[i] = new LineNumber(); lnt[i] = new LineNumber();
int start = input.readUnsignedShort(); int start = input.readUnsignedShort();
Instruction startInstr; Instruction startInstr = null;
for (startInstr = firstInstr; for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
startInstr.getAddr() < start && startInstr != null; Instruction instr = (Instruction) iter.next();
startInstr = startInstr.getNextByAddr()) { if (instr.getAddr() == start)
/* empty */ startInstr = instr;
if (instr.getAddr() >= start)
break;
} }
if (startInstr == null if (startInstr == null) {
|| startInstr.getAddr() != start) {
GlobalOptions.err.println GlobalOptions.err.println
("Illegal entry, ignoring LineNumberTable table"); ("Illegal entry, ignoring LineNumberTable table");
lnt = null; lnt = null;
@ -164,25 +285,17 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
public void read(ConstantPool cp, public void read(ConstantPool cp,
DataInputStream input) throws IOException { DataInputStream input) throws IOException {
this.cp = cp;
maxStack = input.readUnsignedShort(); maxStack = input.readUnsignedShort();
maxLocals = input.readUnsignedShort(); maxLocals = input.readUnsignedShort();
codeLength = input.readInt(); instructions = new InstructionList();
int codeLength = input.readInt();
Instruction[] instrs = new Instruction[codeLength]; Instruction[] instrs = new Instruction[codeLength];
int[][] succAddrs = new int[codeLength][]; int[][] succAddrs = new int[codeLength][];
int[] predcounts = new int[codeLength];
{ {
int addr = 0; int addr = 0;
firstInstr = new Instruction(this);
instructionCount++;
Instruction lastInstr = null;
while (addr < codeLength) { while (addr < codeLength) {
Instruction instr = lastInstr != null Instruction instr;
? lastInstr.appendInstruction(opc_nop) : firstInstr; int length;
instrs[addr] = instr;
lastInstr = instr;
int opcode = input.readUnsignedByte(); int opcode = input.readUnsignedByte();
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
@ -193,7 +306,6 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
switch (opcode) { switch (opcode) {
case opc_wide: { case opc_wide: {
int wideopcode = input.readUnsignedByte(); int wideopcode = input.readUnsignedByte();
instr.replaceInstruction(wideopcode);
switch (wideopcode) { switch (wideopcode) {
case opc_iload: case opc_fload: case opc_aload: case opc_iload: case opc_fload: case opc_aload:
case opc_istore: case opc_fstore: case opc_astore: { case opc_istore: case opc_fstore: case opc_astore: {
@ -201,8 +313,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new Instruction(wideopcode);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(4); length = 4;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print GlobalOptions.err.print
@ -215,12 +328,13 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals-1) if (slot >= maxLocals-1)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new Instruction(wideopcode);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(4); length = 4;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+opcodeString[wideopcode] GlobalOptions.err.print
+" "+slot); (" " + opcodeString[wideopcode] + " " + slot);
break; break;
} }
case opc_ret: { case opc_ret: {
@ -228,8 +342,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new Instruction(wideopcode);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(4); length = 4;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" ret "+slot); GlobalOptions.err.print(" ret "+slot);
@ -240,13 +355,14 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr = new Instruction(wideopcode);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setIntData(input.readShort()); instr.setIncrement(input.readShort());
instr.setLength(6); length = 6;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" iinc "+slot GlobalOptions.err.print
+" "+instr.getIntData()); (" iinc " + slot + " " + instr.getIncrement());
break; break;
} }
default: default:
@ -269,10 +385,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr.replaceInstruction(opc_iload + instr = new Instruction(opc_iload +
(opcode-opc_iload_0)/4); (opcode-opc_iload_0)/4);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(1); length = 1;
break; break;
} }
case opc_istore_0: case opc_istore_1: case opc_istore_0: case opc_istore_1:
@ -285,10 +401,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr.replaceInstruction(opc_istore + instr = new Instruction(opc_istore +
(opcode-opc_istore_0)/4); (opcode-opc_istore_0)/4);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(1); length = 1;
break; break;
} }
case opc_lstore_0: case opc_lstore_1: case opc_lstore_0: case opc_lstore_1:
@ -299,10 +415,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals-1) if (slot >= maxLocals-1)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr.replaceInstruction(opc_istore instr = new Instruction(opc_istore
+ (opcode-opc_istore_0)/4); + (opcode-opc_istore_0)/4);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(1); length = 1;
break; break;
} }
case opc_iload: case opc_fload: case opc_aload: case opc_iload: case opc_fload: case opc_aload:
@ -311,9 +427,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(2); length = 2;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+slot); GlobalOptions.err.print(" "+slot);
@ -325,9 +441,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals - 1) if (slot >= maxLocals - 1)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(2); length = 2;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+slot); GlobalOptions.err.print(" "+slot);
@ -338,9 +454,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setLength(2); length = 2;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+slot); GlobalOptions.err.print(" "+slot);
@ -351,27 +467,27 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2: 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_iconst_3: case opc_iconst_4: case opc_iconst_5:
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
instr.replaceInstruction(opc_ldc); instr = new Instruction(opc_ldc);
instr.setConstant instr.setConstant
(constants[opcode - opc_aconst_null]); (constants[opcode - opc_aconst_null]);
instr.setLength(1); length = 1;
break; break;
case opc_lconst_0: case opc_lconst_1: case opc_lconst_0: case opc_lconst_1:
case opc_dconst_0: case opc_dconst_1: case opc_dconst_0: case opc_dconst_1:
instr.replaceInstruction(opc_ldc2_w); instr = new Instruction(opc_ldc2_w);
instr.setConstant instr.setConstant
(constants[opcode - opc_aconst_null]); (constants[opcode - opc_aconst_null]);
instr.setLength(1); length = 1;
break; break;
case opc_bipush: case opc_bipush:
instr.replaceInstruction(opc_ldc); instr = new Instruction(opc_ldc);
instr.setConstant(new Integer(input.readByte())); instr.setConstant(new Integer(input.readByte()));
instr.setLength(2); length = 2;
break; break;
case opc_sipush: case opc_sipush:
instr.replaceInstruction(opc_ldc); instr = new Instruction(opc_ldc);
instr.setConstant(new Integer(input.readShort())); instr.setConstant(new Integer(input.readShort()));
instr.setLength(3); length = 3;
break; break;
case opc_ldc: { case opc_ldc: {
int index = input.readUnsignedByte(); int index = input.readUnsignedByte();
@ -380,9 +496,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
&& tag != cp.INTEGER && tag != cp.FLOAT) && tag != cp.INTEGER && tag != cp.FLOAT)
throw new ClassFormatException throw new ClassFormatException
("wrong constant tag: "+tag); ("wrong constant tag: "+tag);
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setConstant(cp.getConstant(index)); instr.setConstant(cp.getConstant(index));
instr.setLength(2); length = 2;
break; break;
} }
case opc_ldc_w: { case opc_ldc_w: {
@ -392,9 +508,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
&& tag != cp.INTEGER && tag != cp.FLOAT) && tag != cp.INTEGER && tag != cp.FLOAT)
throw new ClassFormatException throw new ClassFormatException
("wrong constant tag: "+tag); ("wrong constant tag: "+tag);
instr.replaceInstruction(opc_ldc); instr = new Instruction(opc_ldc);
instr.setConstant(cp.getConstant(index)); instr.setConstant(cp.getConstant(index));
instr.setLength(3); length = 3;
break; break;
} }
case opc_ldc2_w: { case opc_ldc2_w: {
@ -403,9 +519,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (tag != cp.LONG && tag != cp.DOUBLE) if (tag != cp.LONG && tag != cp.DOUBLE)
throw new ClassFormatException throw new ClassFormatException
("wrong constant tag: "+tag); ("wrong constant tag: "+tag);
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setConstant(cp.getConstant(index)); instr.setConstant(cp.getConstant(index));
instr.setLength(3); length = 3;
break; break;
} }
case opc_iinc: { case opc_iinc: {
@ -413,14 +529,14 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (slot >= maxLocals) if (slot >= maxLocals)
throw new ClassFormatError throw new ClassFormatError
("Invalid local slot "+slot); ("Invalid local slot "+slot);
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setLocalSlot(slot); instr.setLocalSlot(slot);
instr.setIntData(input.readByte()); instr.setIncrement(input.readByte());
instr.setLength(3); length = 3;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+slot GlobalOptions.err.print
+" "+instr.getIntData()); (" " + slot + " " + instr.getIncrement());
break; break;
} }
case opc_goto: case opc_goto:
@ -433,10 +549,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne: case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull: case opc_ifnull: case opc_ifnonnull:
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setLength(3); length = 3;
succAddrs[addr] = new int[] { addr+input.readShort() }; succAddrs[addr] = new int[] { addr+input.readShort() };
predcounts[succAddrs[addr][0]]++;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+succAddrs[addr][0]); GlobalOptions.err.print(" "+succAddrs[addr][0]);
@ -444,50 +559,61 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
case opc_goto_w: case opc_goto_w:
case opc_jsr_w: case opc_jsr_w:
instr.replaceInstruction(opcode - (opc_goto_w - opc_goto)); instr = new Instruction(opcode - (opc_goto_w - opc_goto));
instr.setLength(5); length = 5;
succAddrs[addr] = new int[] { addr+input.readInt() }; succAddrs[addr] = new int[] { addr+input.readInt() };
predcounts[succAddrs[addr][0]]++;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+succAddrs[addr][0]); GlobalOptions.err.print(" "+succAddrs[addr][0]);
break; break;
case opc_tableswitch: { case opc_tableswitch: {
int length = 3-(addr % 4); length = 3 - (addr % 4);
input.readFully(new byte[length]); input.readFully(new byte[length]);
int def = input.readInt(); int def = input.readInt();
int low = input.readInt(); int low = input.readInt();
int high = input.readInt(); int high = input.readInt();
instr.replaceInstruction(opcode); int[] dests = new int[high-low+1];
instr.setIntData(low); int npairs = 0;
succAddrs[addr] = new int[high-low+2]; for (int i=0; i < dests.length; i++) {
for (int i=0; i+low <= high; i++) { dests[i] = input.readInt();
succAddrs[addr][i] = addr + input.readInt(); if (dests[i] != def)
predcounts[succAddrs[addr][i]]++; 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][high-low+1] = addr + def; succAddrs[addr][npairs] = addr + def;
predcounts[addr + def]++; instr.setValues(values);
instr.setLength(length + 13 + 4 * (high-low+1)); length += 13 + 4 * (high-low+1);
break; break;
} }
case opc_lookupswitch: { case opc_lookupswitch: {
int length = 3-(addr % 4); length = 3 - (addr % 4);
input.readFully(new byte[length]); input.readFully(new byte[length]);
int def = input.readInt(); int def = input.readInt();
int npairs = input.readInt(); int npairs = input.readInt();
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
succAddrs[addr] = new int[npairs + 1]; succAddrs[addr] = new int[npairs + 1];
int[] values = new int[npairs]; int[] values = new int[npairs];
for (int i=0; i < npairs; i++) { for (int i=0; i < npairs; i++) {
values[i] = input.readInt(); 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][i] = addr + input.readInt();
predcounts[succAddrs[addr][i]]++;
} }
succAddrs[addr][npairs] = addr + def; succAddrs[addr][npairs] = addr + def;
predcounts[addr + def]++;
instr.setValues(values); instr.setValues(values);
instr.setLength(length + 9 + 8 * npairs); length += 9 + 8 * npairs;
break; break;
} }
@ -515,9 +641,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
|| opcode != opc_invokespecial)) || opcode != opc_invokespecial))
throw new ClassFormatException throw new ClassFormatException
("Illegal call of special method/field "+ref); ("Illegal call of special method/field "+ref);
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setReference(ref); instr.setReference(ref);
instr.setLength(3); length = 3;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+ref); GlobalOptions.err.print(" "+ref);
@ -542,9 +668,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
throw new ClassFormatException throw new ClassFormatException
("Interface reserved param not zero"); ("Interface reserved param not zero");
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setReference(ref); instr.setReference(ref);
instr.setLength(5); length = 5;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+ref); GlobalOptions.err.print(" "+ref);
@ -558,9 +684,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (opcode == opc_new && type.charAt(0) == '[') if (opcode == opc_new && type.charAt(0) == '[')
throw new ClassFormatException throw new ClassFormatException
("Can't create array with opc_new"); ("Can't create array with opc_new");
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setClazzType(type); instr.setClazzType(type);
instr.setLength(3); length = 3;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+type); GlobalOptions.err.print(" "+type);
@ -569,7 +695,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
case opc_multianewarray: { case opc_multianewarray: {
String type = cp.getClassType(input.readUnsignedShort()); String type = cp.getClassType(input.readUnsignedShort());
int dims = input.readUnsignedByte(); int dims = input.readUnsignedByte();
for (int i=0; i < dims; i++) 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 /* Note that since type is a valid type
* signature, there must be a non bracket * signature, there must be a non bracket
* character, before the string is over. * character, before the string is over.
@ -577,12 +706,12 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
*/ */
if (type.charAt(i) != '[') if (type.charAt(i) != '[')
throw new ClassFormatException throw new ClassFormatException
("multianewarray called for non array:" ("multianewarray called for non array:"+ type);
+ instr.getDescription()); }
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setClazzType(type); instr.setClazzType(type);
instr.setIntData(dims); instr.setDimensions(dims);
instr.setLength(4); length = 4;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" " + type + " " + dims); GlobalOptions.err.print(" " + type + " " + dims);
@ -590,10 +719,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
} }
case opc_anewarray: { case opc_anewarray: {
String type = cp.getClassType(input.readUnsignedShort()); String type = cp.getClassType(input.readUnsignedShort());
instr.replaceInstruction(opc_multianewarray); instr = new Instruction(opc_multianewarray);
instr.setClazzType(("["+type).intern()); instr.setClazzType(("["+type).intern());
instr.setIntData(1); instr.setDimensions(1);
instr.setLength(3); length = 3;
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+type); GlobalOptions.err.print(" "+type);
@ -606,10 +735,10 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.print(" "+type); GlobalOptions.err.print(" "+type);
instr.replaceInstruction(opc_multianewarray); instr = new Instruction(opc_multianewarray);
instr.setClazzType(type); instr.setClazzType(type);
instr.setIntData(1); instr.setDimensions(1);
instr.setLength(2); length = 2;
break; break;
} }
@ -649,8 +778,8 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
case opc_athrow: case opc_athrow:
case opc_arraylength: case opc_arraylength:
case opc_monitorenter: case opc_monitorexit: case opc_monitorenter: case opc_monitorexit:
instr.replaceInstruction(opcode); instr = new Instruction(opcode);
instr.setLength(1); length = 1;
break; break;
default: default:
throw new ClassFormatError("Invalid opcode "+opcode); throw new ClassFormatError("Invalid opcode "+opcode);
@ -658,23 +787,32 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_BYTECODE) != 0) & GlobalOptions.DEBUG_BYTECODE) != 0)
GlobalOptions.err.println(); GlobalOptions.err.println();
addr += instr.getLength();
instrs[addr] = instr;
instructions.add(instr);
addr += length;
instructions.setLastAddr(addr);
} }
if (addr != codeLength)
throw new ClassFormatError("last instruction too long");
} }
for (Instruction instr = firstInstr; for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
instr != null; instr = instr.getNextByAddr()) { Instruction instr = (Instruction) iter.next();
int addr = instr.getAddr(); int addr = instr.getAddr();
if (succAddrs[addr] != null) { if (succAddrs[addr] != null) {
int length = succAddrs[addr].length; int length = succAddrs[addr].length;
instr.succs = new Instruction[length]; Instruction[] succs = new Instruction[length];
for (int i=0; i < length; i++) { for (int i=0; i < length; i++) {
int succAddr = succAddrs[addr][i]; int succAddr = succAddrs[addr][i];
instr.succs[i] = instrs[succAddr]; if (succAddr < 0 || succAddr > codeLength
if (instr.succs[i].preds == null) || instrs[succAddr] == null)
instr.succs[i].preds throw new ClassFormatException
= new Instruction[predcounts[succAddr]]; ("Illegal jump target at "
instr.succs[i].preds[--predcounts[succAddr]] = instr; +this+"@"+addr);
succs[i] = instrs[succAddr];
} }
instr.setSuccs(succs);
} }
} }
succAddrs = null; succAddrs = null;
@ -699,20 +837,21 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
} }
public void dumpCode(java.io.PrintWriter output) { public void dumpCode(java.io.PrintWriter output) {
for (Instruction instr = firstInstr; for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
instr != null; instr = instr.getNextByAddr()) { Instruction instr = (Instruction) iter.next();
output.println(instr.getDescription() + " " output.println(instr.getDescription() + " "
+ Integer.toHexString(hashCode())); + Integer.toHexString(hashCode()));
if (instr.succs != null) { Instruction[] succs = instr.getSuccs();
output.print("\tsuccs: "+instr.succs[0]); if (succs != null) {
for (int i = 1; i < instr.succs.length; i++) output.print("\tsuccs: "+succs[0]);
output.print(", "+instr.succs[i]); for (int i = 1; i < succs.length; i++)
output.print(", "+succs[i]);
output.println(); output.println();
} }
if (instr.preds != null) { if (instr.getPreds() != null) {
output.print("\tpreds: " + instr.preds[0]); output.print("\tpreds: " + instr.getPreds()[0]);
for (int i=1; i < instr.preds.length; i++) for (int i=1; i < instr.getPreds().length; i++)
output.print(", " + instr.preds[i]); output.print(", " + instr.getPreds()[i]);
output.println(); output.println();
} }
} }
@ -726,8 +865,8 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
public void reserveSmallConstants(GrowableConstantPool gcp) { public void reserveSmallConstants(GrowableConstantPool gcp) {
next_instr: next_instr:
for (Instruction instr = firstInstr; for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
instr != null; instr = instr.getNextByAddr()) { Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_ldc) { if (instr.getOpcode() == opc_ldc) {
Object constant = instr.getConstant(); Object constant = instr.getConstant();
if (constant == null) if (constant == null)
@ -750,8 +889,8 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
public void prepareWriting(GrowableConstantPool gcp) { public void prepareWriting(GrowableConstantPool gcp) {
/* Recalculate addr, length and add all constants to gcp */ /* Recalculate addr, length and add all constants to gcp */
int addr = 0; int addr = 0;
for (Instruction instr = firstInstr; for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
instr != null; instr = instr.getNextByAddr()) { Instruction instr = (Instruction) iter.next();
int opcode = instr.getOpcode(); int opcode = instr.getOpcode();
instr.setAddr(addr); instr.setAddr(addr);
int length; int length;
@ -794,42 +933,51 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
} }
break; 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: { case opc_iinc: {
int slot = instr.getLocalSlot(); int slot = instr.getLocalSlot();
if (opcode == opc_iinc) { int increment = instr.getIncrement();
if (slot < 256 if (slot < 256
&& instr.getIntData() >= Byte.MIN_VALUE && increment >= Byte.MIN_VALUE
&& instr.getIntData() <= Byte.MAX_VALUE) && increment <= Byte.MAX_VALUE)
length = 3; length = 3;
else else
length = 6; length = 6;
} else { break;
if (opcode != opc_ret && slot < 4) }
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.getLocalSlot() < 4) {
length = 1; length = 1;
else if (slot < 256) break;
}
/* fall through */
case opc_ret: {
if (instr.getLocalSlot() < 256)
length = 2; length = 2;
else else
length = 4; length = 4;
}
break; break;
} }
case opc_tableswitch: { case opc_lookupswitch: {
length = 3-(addr % 4); length = 3-(addr % 4);
length += 9 + 4 * instr.succs.length; 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; break;
} }
case opc_lookupswitch: { }
length = 3-(addr % 4); // Use a lookup switch
length += 1 + 8 * instr.succs.length; length += 9 + 8 * npairs;
break; break;
} }
case opc_goto: case opc_jsr: { case opc_goto: case opc_jsr: {
int dist = instr.succs[0].getAddr() - instr.getAddr(); int dist = instr.getSingleSucc().getAddr() - instr.getAddr();
if (dist < Short.MIN_VALUE || dist > Short.MAX_VALUE) { if (dist < Short.MIN_VALUE || dist > Short.MAX_VALUE) {
/* wide goto / jsr */ /* wide goto / jsr */
length = 5; length = 5;
@ -848,7 +996,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
length = 3; length = 3;
break; break;
case opc_multianewarray: { case opc_multianewarray: {
if (instr.getIntData() == 1) { if (instr.getDimensions() == 1) {
String clazz = instr.getClazzType().substring(1); String clazz = instr.getClazzType().substring(1);
if (newArrayTypes.indexOf(clazz.charAt(0)) != -1) { if (newArrayTypes.indexOf(clazz.charAt(0)) != -1) {
length = 2; length = 2;
@ -926,10 +1074,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
default: default:
throw new ClassFormatError("Invalid opcode "+opcode); throw new ClassFormatError("Invalid opcode "+opcode);
} }
instr.setLength(length);
addr += length; addr += length;
} }
codeLength = addr; instructions.setLastAddr(addr);
for (int i=0; i< exceptionHandlers.length; i++) for (int i=0; i< exceptionHandlers.length; i++)
if (exceptionHandlers[i].type != null) if (exceptionHandlers[i].type != null)
gcp.putClassName(exceptionHandlers[i].type); gcp.putClassName(exceptionHandlers[i].type);
@ -989,9 +1136,9 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
DataOutputStream output) throws IOException { DataOutputStream output) throws IOException {
output.writeShort(maxStack); output.writeShort(maxStack);
output.writeShort(maxLocals); output.writeShort(maxLocals);
output.writeInt(codeLength); output.writeInt(instructions.getCodeLength());
for (Instruction instr = firstInstr; for (Iterator iter = instructions.iterator(); iter.hasNext(); ) {
instr != null; instr = instr.getNextByAddr()) { Instruction instr = (Instruction) iter.next();
int opcode = instr.getOpcode(); int opcode = instr.getOpcode();
switch_opc: switch_opc:
switch (opcode) { switch (opcode) {
@ -1077,7 +1224,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
} }
case opc_iinc: { case opc_iinc: {
int slot = instr.getLocalSlot(); int slot = instr.getLocalSlot();
int incr = instr.getIntData(); int incr = instr.getIncrement();
if (instr.getLength() == 3) { if (instr.getLength() == 3) {
output.writeByte(opcode); output.writeByte(opcode);
output.writeByte(slot); output.writeByte(slot);
@ -1095,7 +1242,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
if (instr.getLength() == 5) { if (instr.getLength() == 5) {
/* wide goto or jsr */ /* wide goto or jsr */
output.writeByte(opcode + (opc_goto_w - opc_goto)); output.writeByte(opcode + (opc_goto_w - opc_goto));
output.writeInt(instr.succs[0].getAddr() output.writeInt(instr.getSingleSucc().getAddr()
- instr.getAddr()); - instr.getAddr());
break; break;
} }
@ -1109,37 +1256,49 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
case opc_if_acmpeq: case opc_if_acmpne: case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull: case opc_ifnull: case opc_ifnonnull:
output.writeByte(opcode); output.writeByte(opcode);
output.writeShort(instr.succs[0].getAddr() output.writeShort(instr.getSingleSucc().getAddr()
- instr.getAddr()); - instr.getAddr());
break; break;
case opc_tableswitch: { case opc_lookupswitch: {
output.writeByte(opcode);
int align = 3-(instr.getAddr() % 4); int align = 3-(instr.getAddr() % 4);
int numcases = instr.succs.length - 1; 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]); output.write(new byte[align]);
/* def */ /* def */
output.writeInt(instr.succs[numcases].getAddr() - instr.getAddr()); output.writeInt(defAddr);
/* low */ /* low */
output.writeInt(instr.getIntData()); output.writeInt(values[0]);
/* high */ /* high */
output.writeInt(instr.getIntData() + numcases - 1); output.writeInt(values[npairs-1]);
for (int i=0; i < numcases; i++) int pos = values[0];
output.writeInt(instr.succs[i].getAddr() - instr.getAddr()); for (int i = 0; i < npairs; i++) {
while (pos++ < values[i])
output.writeInt(defAddr);
output.writeInt(instr.getSuccs()[i].getAddr()
- instr.getAddr());
}
break; break;
} }
case opc_lookupswitch: { }
output.writeByte(opcode); // Use a lookup switch
int[] values = instr.getValues(); output.writeByte(opc_lookupswitch);
int align = 3-(instr.getAddr() % 4);
int numcases = values.length;
output.write(new byte[align]); output.write(new byte[align]);
/* def */ /* def */
output.writeInt(instr.succs[numcases].getAddr() - instr.getAddr()); output.writeInt(defAddr);
output.writeInt(numcases); output.writeInt(npairs);
for (int i=0; i < numcases; i++) { for (int i=0; i < npairs; i++) {
output.writeInt(values[i]); output.writeInt(values[i]);
output.writeInt(instr.succs[i].getAddr() - instr.getAddr()); output.writeInt(instr.getSuccs()[i].getAddr()
-instr.getAddr());
} }
break; break;
} }
@ -1175,7 +1334,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
output.writeShort(gcp.putClassType(instr.getClazzType())); output.writeShort(gcp.putClassType(instr.getClazzType()));
break; break;
case opc_multianewarray: case opc_multianewarray:
if (instr.getIntData() == 1) { if (instr.getDimensions() == 1) {
String clazz = instr.getClazzType().substring(1); String clazz = instr.getClazzType().substring(1);
int index = newArrayTypes.indexOf(clazz.charAt(0)); int index = newArrayTypes.indexOf(clazz.charAt(0));
if (index != -1) { if (index != -1) {
@ -1188,7 +1347,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
} else { } else {
output.writeByte(opcode); output.writeByte(opcode);
output.writeShort(gcp.putClassType(instr.getClazzType())); output.writeShort(gcp.putClassType(instr.getClazzType()));
output.writeByte(instr.getIntData()); output.writeByte(instr.getDimensions());
} }
break; break;
@ -1268,7 +1427,8 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
size += 8 + lvt.length * 10; size += 8 + lvt.length * 10;
if (lnt != null) if (lnt != null)
size += 8 + lnt.length * 4; size += 8 + lnt.length * 4;
return 10 + codeLength + exceptionHandlers.length * 8 return 10 + instructions.getCodeLength()
+ exceptionHandlers.length * 8
+ getAttributeSize() + size; + getAttributeSize() + size;
} }
@ -1284,38 +1444,8 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
return methodInfo; return methodInfo;
} }
public Collection getInstructions() { public List getInstructions() {
return new AbstractCollection() { return instructions;
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;
} }
public Handler[] getExceptionHandlers() { public Handler[] getExceptionHandlers() {

@ -19,16 +19,13 @@
package jode.bytecode; package jode.bytecode;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.util.UnifyHash;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.BufferedInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Enumeration; import java.util.Enumeration;
///#ifdef JDK12
///import java.lang.ref.WeakReference;
///import java.lang.ref.ReferenceQueue;
///#endif
import @COLLECTIONS@.Map;
import @COLLECTIONS@.HashMap;
import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Iterator;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -49,10 +46,12 @@ import java.lang.reflect.Modifier;
public class ClassInfo extends BinaryInfo { public class ClassInfo extends BinaryInfo {
private static SearchPath classpath; private static SearchPath classpath;
private static final Map classes = new HashMap();
///#ifdef JDK12 private static final UnifyHash classes = new UnifyHash();
/// private static final ReferenceQueue queue = new ReferenceQueue(); // private static final Map classes = new HashMap();
///#endif // ///#ifdef JDK12
// /// private static final ReferenceQueue queue = new ReferenceQueue();
// ///#endif
private int status = 0; private int status = 0;
@ -73,23 +72,9 @@ public class ClassInfo extends BinaryInfo {
public static void setClassPath(String path) { public static void setClassPath(String path) {
classpath = new SearchPath(path); classpath = new SearchPath(path);
///#ifdef JDK12 Iterator i = classes.iterator();
/// java.lang.ref.Reference died;
/// while ((died = queue.poll()) != null) {
/// classes.values().remove(died);
/// }
/// Iterator i = classes.values().iterator();
/// while (i.hasNext()) {
/// ClassInfo ci = (ClassInfo) ((WeakReference)i.next()).get();
/// if (ci == null) {
/// i.remove();
/// continue;
/// }
///#else
Iterator i = classes.values().iterator();
while (i.hasNext()) { while (i.hasNext()) {
ClassInfo ci = (ClassInfo) i.next(); ClassInfo ci = (ClassInfo) i.next();
///#endif
ci.status = 0; ci.status = 0;
ci.superclass = null; ci.superclass = null;
ci.fields = null; ci.fields = null;
@ -132,24 +117,15 @@ public class ClassInfo extends BinaryInfo {
|| name.indexOf('/') != -1) || name.indexOf('/') != -1)
throw new IllegalArgumentException("Illegal class name: "+name); throw new IllegalArgumentException("Illegal class name: "+name);
///#ifdef JDK12 int hash = name.hashCode();
/// java.lang.ref.Reference died; Iterator iter = classes.iterateHashCode(hash);
/// while ((died = queue.poll()) != null) { while (iter.hasNext()) {
/// classes.values().remove(died); ClassInfo clazz = (ClassInfo) iter.next();
/// } if (clazz.name.equals(name))
/// WeakReference ref = (WeakReference) classes.get(name); return clazz;
/// ClassInfo clazz = (ref == null) ? null : (ClassInfo) ref.get();
///#else
ClassInfo clazz = (ClassInfo) classes.get(name);
///#endif
if (clazz == null) {
clazz = new ClassInfo(name);
///#ifdef JDK12
/// classes.put(name, new WeakReference(clazz, queue));
///#else
classes.put(name, clazz);
///#endif
} }
ClassInfo clazz = new ClassInfo(name);
classes.put(hash, clazz);
return clazz; return clazz;
} }
@ -565,9 +541,9 @@ public class ClassInfo extends BinaryInfo {
return; return;
} }
try { try {
DataInputStream input = DataInputStream input = new DataInputStream
new DataInputStream(classpath.getFile(name.replace('.', '/') (new BufferedInputStream
+ ".class")); (classpath.getFile(name.replace('.', '/') + ".class")));
read(input, howMuch); read(input, howMuch);
} catch (IOException ex) { } catch (IOException ex) {
@ -602,6 +578,7 @@ public class ClassInfo extends BinaryInfo {
("Can't read class " + name + ", types may be incorrect. (" ("Can't read class " + name + ", types may be incorrect. ("
+ ex.getClass().getName() + ex.getClass().getName()
+ (message != null ? ": " + message : "") + ")"); + (message != null ? ": " + message : "") + ")");
ex.printStackTrace(GlobalOptions.err);
if ((howMuch & HIERARCHY) != 0) { if ((howMuch & HIERARCHY) != 0) {
modifiers = Modifier.PUBLIC; modifiers = Modifier.PUBLIC;

@ -18,27 +18,29 @@
*/ */
package jode.bytecode; package jode.bytecode;
import java.util.Vector;
import java.util.Enumeration;
/** /**
* This class represents an instruction in the byte code. * This class represents an instruction in the byte code.
* *
*/ */
public final class Instruction implements Opcodes{ public final class Instruction implements Opcodes{
private BytecodeInfo codeinfo;
/** /**
* The opcode of the instruction. We map some opcodes, e.g. * The opcode of the instruction. We map some opcodes, e.g.
* <pre> * <pre>
* iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc. * iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc.
* </pre> * </pre>
*/ */
// a byte would be enough, but then we would need an unsigned convert.
private int opcode; private int opcode;
/** /**
* If this opcode uses a local this gives the slot. This info is * If this opcode uses a local this gives the slot. For multianewarray
* used when swapping locals. * this gives the dimension.
*/ */
private int localSlot = -1; private int shortData;
/**
* The address of this opcode.
*/
private int addr;
/** /**
* Optional object data for this opcode. There are four different * Optional object data for this opcode. There are four different
* usages of this field: * usages of this field:
@ -54,68 +56,50 @@ public final class Instruction implements Opcodes{
* </dl> * </dl>
*/ */
private Object objData; private Object objData;
/**
* Optional integer data for this opcode. There are various uses
* for this:
* <dl>
* <dt>opc_iinc</dt>
* <dd>The value by which the constant is increased/decreased. (short)</dd>
* <dt>opc_tableswitch</dt>
* <dd>The start value of the table</dd>
* <dt>opc_multianewarray</dt>
* <dd>The number of dimensions (1..255)</dd>
* <dt>opc_lookupswitch</dt>
* <dd>The array of values of type int[]</dd>
* </dl>
*/
private int intData;
/**
* The address of this opcode.
*/
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)
*/
private int length;
/** /**
* The successors of this opcodes, where flow may lead to * The successors of this opcodes, where flow may lead to
* (except that nextByAddr is implicit if !alwaysJump). The * (except that nextByAddr is implicit if !alwaysJump). The
* value null is equivalent to an empty array. * value null means no successor, if there is one succesor, this
* is of type Instruction, otherwise, this is an array of Instruction.
*/ */
Instruction[] succs; private Object succs;
/** /**
* The predecessors of this opcode, orthogonal to the succs array. * The predecessors of this opcode, orthogonal to the succs array.
* This must be null or a non empty array. * This must be null or a non empty array.
*/ */
Instruction[] preds; private Instruction[] preds;
/** /**
* The next instruction in code order. * The next instruction in code order.
*/ */
private Instruction nextByAddr; Instruction nextByAddr;
/** /**
* The previous instruction in code order, useful when changing * The previous instruction in code order, useful when changing
* the order. * the order.
*/ */
private Instruction prevByAddr; Instruction prevByAddr;
/** /**
* You can use this field to add some info to each instruction. * You can use this field to add some info to each instruction.
* After using, you must set it to null again. * After using, you must set it to null again.
* @XXX Do we really need this. Every field here can quickly take
* half a megabyte!
*/ */
private Object tmpInfo; private Object tmpInfo;
public Instruction(BytecodeInfo ci) { public Instruction(int opcode) {
this.codeinfo = ci; this.opcode = opcode;
} }
/** /**
* Returns the opcode of the instruction. We map some opcodes, e.g. * Returns the opcode of the instruction. We map some opcodes:
* <pre> * <pre>
* iload_0 -&gt; iload * [iflda]load_x -&gt; [iflda]load
* ldc_w -&gt; ldc * [iflda]store_x -&gt; [iflda]store
* wide iinc -&gt; iinc * [ifa]const_xx, ldc_w -&gt; ldc
* [dl]const_xx -&gt; ldc2_w
* wide opcode -&gt; opcode
* tableswitch -&gt; lookupswitch
* [a]newarray -&gt; multianewarray
* </pre> * </pre>
*/ */
public final int getOpcode() { public final int getOpcode() {
@ -137,6 +121,10 @@ public final class Instruction implements Opcodes{
return addr; return addr;
} }
public final int getNextAddr() {
return nextByAddr.addr;
}
/** /**
* Returns the length of this opcode. See getAddr() for some * Returns the length of this opcode. See getAddr() for some
* notes. Note that the length doesn't necessarily reflect the * notes. Note that the length doesn't necessarily reflect the
@ -145,38 +133,88 @@ public final class Instruction implements Opcodes{
* in constant pool, and the order they are allocated. * in constant pool, and the order they are allocated.
*/ */
public final int getLength() { public final int getLength() {
return length; return getNextAddr() - addr;
} }
final void setAddr(int addr) { final void setAddr(int addr) {
this.addr = addr; this.addr = addr;
} }
final void setLength(int length) {
this.length = length; public final boolean hasLocalSlot() {
return opcode == opc_iinc || opcode == opc_ret
|| opcode >= opc_iload && opcode <= opc_aload
|| opcode >= opc_istore && opcode <= opc_astore;
} }
public final int getLocalSlot() { public final int getLocalSlot()
return localSlot; /*{ require { hasLocalSlot()
:: "Instruction has no slot" } }*/
{
return shortData;
} }
public final void setLocalSlot(int slot) { public final void setLocalSlot(int slot)
localSlot = slot; /*{ require { hasLocalSlot()
:: "Instruction has no slot" } }*/
{
shortData = slot;
} }
public final int getIntData() /**
* Optional integer data for this opcode. There are various uses
* for this:
* <dl>
* <dt>opc_iinc</dt>
* <dd>The value by which the constant is increased/decreased. (short)</dd>
* <dt>opc_multianewarray</dt>
* <dd>The number of dimensions (1..255)</dd>
* </dl>
*/
public final int getIncrement()
/*{ require { opcode == opc_iinc || opcode == opc_multianewarray /*{ require { opcode == opc_iinc || opcode == opc_multianewarray
|| opcode == opc_tableswitch || opcode == opc_tableswitch
:: "Instruction has no int data" } }*/ :: "Instruction has no int data" } }*/
{ {
return intData; /* shortData already used for local slot */
return ((Short) objData).shortValue();
} }
public final void setIntData(int data) /**
* Optional integer data for this opcode. There are various uses
* for this:
* <dl>
* <dt>opc_iinc</dt>
* <dd>The value by which the constant is increased/decreased. (short)</dd>
* <dt>opc_multianewarray</dt>
* <dd>The number of dimensions (1..255)</dd>
* </dl>
*/
public final void setIncrement(int incr)
/*{ require { opcode == opc_iinc || opcode == opc_multianewarray /*{ require { opcode == opc_iinc || opcode == opc_multianewarray
|| opcode == opc_tableswitch
:: "Instruction has no int data" } }*/ :: "Instruction has no int data" } }*/
{ {
this.intData = data; /* shortData already used for local slot */
objData = new Short((short) incr);
}
/**
*
*/
public final int getDimensions()
/*{ require { opcode == opc_multianewarray
:: "Instruction has no dimensions" } }*/
{
return shortData;
}
/**
*
*/
public final void setDimensions(int dims)
/*{ require { opcode == opc_multianewarray
:: "Instruction has no dimensions" } }*/
{
shortData = dims;
} }
public final Object getConstant() public final Object getConstant()
@ -265,15 +303,44 @@ public final class Instruction implements Opcodes{
return preds; return preds;
} }
/**
* Returns true if this opcode has successors, other than the implicit
* getNextByAddr().
*/
public boolean hasSuccs() {
return succs != null;
}
/**
* Returns the successors of this opcodes, where flow may lead to
* (except that nextByAddr is implicit if !alwaysJump). The
* value null means that there is no successor.
*/
public final Instruction[] getSuccs() { public final Instruction[] getSuccs() {
return succs; if (succs instanceof Instruction)
return new Instruction[] { (Instruction) succs };
return (Instruction[]) succs;
}
/**
* Returns the single successor of this opcodes. This gives the
* target of a goto, jsr, or if opcode.
* @return null if there is no successor, otherwise the successor.
* @exception ClassCastException if this has more than one succ.
*/
public final Instruction getSingleSucc() {
return (Instruction) succs;
} }
public final Instruction getPrevByAddr() { public final Instruction getPrevByAddr() {
if (prevByAddr.opcode == opc_xxxunusedxxx)
return null;
return prevByAddr; return prevByAddr;
} }
public final Instruction getNextByAddr() { public final Instruction getNextByAddr() {
if (nextByAddr.opcode == opc_xxxunusedxxx)
return null;
return nextByAddr; return nextByAddr;
} }
@ -285,34 +352,68 @@ public final class Instruction implements Opcodes{
tmpInfo = info; tmpInfo = info;
} }
public final void replaceInstruction(int newOpcode) {
replaceInstruction(newOpcode, null);
}
public final void replaceInstruction(int newOpcode, // INTERNAL FUNCTIONS TO KEEP PREDS AND SUCCS CONSISTENT
Instruction[] newSuccs) {
if (succs != null && succs != newSuccs) { final void removeSuccs() {
for (int i = 0; i< succs.length; i++) if (succs == null)
succs[i].removePredecessor(this); return;
if (succs instanceof Instruction[]) {
Instruction[] ss = (Instruction[]) succs;
for (int i = 0; i < ss.length; i++)
if (ss[i] != null)
ss[i].removePredecessor(this);
} else
((Instruction) succs).removePredecessor(this);
succs = null;
} }
opcode = newOpcode; /**
localSlot = -1; * @param to may be null
objData = null; */
intData = 0; private final void promoteSuccs(Instruction from, Instruction to) {
if (succs != newSuccs) if (succs == from)
setSuccs(newSuccs); succs = to;
else if (succs instanceof Instruction[]) {
Instruction[] ss = (Instruction[]) succs;
for (int i = 0; i < ss.length; i++)
if (ss[i] == from)
ss[i] = to;
}
} }
private final void setSuccs(Instruction[] newSuccs) { /**
* @exception ClassCastException if newSuccs is neither an Instruction
* nor an array of instructions.
*/
public final void setSuccs(Object newSuccs) {
if (succs == newSuccs)
return;
removeSuccs();
if (newSuccs == null)
return;
if (newSuccs instanceof Instruction[]) {
Instruction[] ns = (Instruction[]) newSuccs;
switch (ns.length) {
case 0:
break;
case 1:
succs = ns[0];
ns[0].addPredecessor(this);
break;
default:
succs = ns;
for (int i = 0; i < ns.length; i++)
ns[i].addPredecessor(this);
break;
}
} else {
succs = newSuccs; succs = newSuccs;
if (succs != null) { ((Instruction) newSuccs).addPredecessor(this);
for (int i = 0; i< succs.length; i++)
succs[i].addPredecessor(this);
} }
} }
public void addPredecessor(Instruction pred) { void addPredecessor(Instruction pred) {
if (preds == null) { if (preds == null) {
preds = new Instruction[] { pred }; preds = new Instruction[] { pred };
return; return;
@ -324,7 +425,7 @@ public final class Instruction implements Opcodes{
preds = newPreds; preds = newPreds;
} }
public void removePredecessor(Instruction pred) { void removePredecessor(Instruction pred) {
/* Hopefully it doesn't matter if this is slow */ /* Hopefully it doesn't matter if this is slow */
int predLength = preds.length; int predLength = preds.length;
if (predLength == 1) { if (predLength == 1) {
@ -342,108 +443,107 @@ public final class Instruction implements Opcodes{
} }
} }
public final Instruction insertInstruction(int opc) { // ADDING, REMOVING AND REPLACING INSTRUCTIONS
codeinfo.instructionCount++;
Instruction newInstr = new Instruction(codeinfo);
newInstr.opcode = opc;
newInstr.addr = addr;
newInstr.prevByAddr = prevByAddr; /**
if (prevByAddr != null) * Replaces the opcode of this instruction. You should only use the
* mapped opcodes:
* <pre>
* [iflda]load_x -&gt; [iflda]load
* [iflda]store_x -&gt; [iflda]store
* [ifa]const_xx, ldc_w -&gt; ldc
* [dl]const_xx -&gt; ldc2_w
* wide opcode -&gt; opcode
* tableswitch -&gt; lookupswitch
* [a]newarray -&gt; multianewarray
* </pre>
*/
public final void replaceInstruction(Instruction newInstr,
BytecodeInfo codeinfo) {
/* remove predecessors of successors */
removeSuccs();
newInstr.addr = addr;
nextByAddr.prevByAddr = newInstr;
newInstr.nextByAddr = nextByAddr;
prevByAddr.nextByAddr = newInstr; prevByAddr.nextByAddr = newInstr;
else newInstr.prevByAddr = prevByAddr;
codeinfo.firstInstr = newInstr; prevByAddr = null;
newInstr.nextByAddr = this; nextByAddr = null;
prevByAddr = newInstr;
/* promote the predecessors to newInstr */ /* promote the successors of the predecessors to newInstr */
if (preds != null) { if (preds != null) {
for (int j=0; j < preds.length; j++) for (int j=0; j < preds.length; j++)
for (int i=0; i < preds[j].succs.length; i++) preds[j].promoteSuccs(this, newInstr);
if (preds[j].succs[i] == this)
preds[j].succs[i] = newInstr;
newInstr.preds = preds; newInstr.preds = preds;
preds = null; preds = null;
} }
return newInstr;
/* adjust exception handlers */
Handler[] handlers = codeinfo.getExceptionHandlers();
for (int i=0; i< handlers.length; i++) {
if (handlers[i].start == this)
handlers[i].start = newInstr;
if (handlers[i].end == this)
handlers[i].end = newInstr;
if (handlers[i].catcher == this)
handlers[i].catcher = newInstr;
} }
public final Instruction insertInstruction(int opc, /* adjust local variable table and line number table */
Instruction[] newSuccs) { LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable();
Instruction newInstr = insertInstruction(opc); if (lvt != null) {
if (newSuccs != null) for (int i=0; i< lvt.length; i++) {
newInstr.setSuccs(newSuccs); if (lvt[i].start == this)
return newInstr; lvt[i].start = newInstr;
if (lvt[i].end == this)
lvt[i].end = newInstr;
}
} }
LineNumber[] lnt = codeinfo.getLineNumberTable();
if (lnt != null) {
for (int i=0; i< lnt.length; i++) {
if (lnt[i].start == this)
lnt[i].start = newInstr;
}
}
}
void appendInstruction(Instruction newInstr) {
newInstr.addr = nextByAddr.addr;
public Instruction appendInstruction(int opc) {
codeinfo.instructionCount++;
Instruction newInstr = new Instruction(codeinfo);
newInstr.opcode = opc;
newInstr.addr = addr + length;
newInstr.length = 0;
newInstr.nextByAddr = nextByAddr; newInstr.nextByAddr = nextByAddr;
if (nextByAddr != null)
nextByAddr.prevByAddr = newInstr; nextByAddr.prevByAddr = newInstr;
newInstr.prevByAddr = this; newInstr.prevByAddr = this;
nextByAddr = newInstr; nextByAddr = newInstr;
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). * Removes this instruction (as if it would be replaced by a nop).
*/ */
public void removeInstruction() { void removeInstruction(BytecodeInfo codeinfo) {
codeinfo.instructionCount--;
/* remove from chained list and adjust addr / length */ /* remove from chained list and adjust addr / length */
if (prevByAddr != null) {
prevByAddr.nextByAddr = nextByAddr; prevByAddr.nextByAddr = nextByAddr;
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; nextByAddr.prevByAddr = prevByAddr;
/* remove predecessors of successors */ /* remove predecessors of successors */
if (succs != null) { removeSuccs();
for (int i=0; i < succs.length; i++)
succs[i].removePredecessor(this);
succs = null;
}
Instruction alternative = nextByAddr != null ? nextByAddr : prevByAddr; /* promote the predecessors to next instruction */
/* remove the predecessors to alternative */
if (preds != null) { if (preds != null) {
for (int j=0; j < preds.length; j++) for (int j=0; j < preds.length; j++)
for (int i=0; i < preds[j].succs.length; i++) preds[j].promoteSuccs(this, nextByAddr);
if (preds[j].succs[i] == this) if (nextByAddr.preds == null)
preds[j].succs[i] = alternative; nextByAddr.preds = preds;
if (alternative.preds == null)
alternative.preds = preds;
else { else {
Instruction[] newPreds Instruction[] newPreds = new Instruction
= new Instruction[alternative.preds.length + preds.length]; [nextByAddr.preds.length + preds.length];
System.arraycopy(preds, 0, newPreds, 0, preds.length); System.arraycopy(nextByAddr.preds, 0, newPreds, 0,
System.arraycopy(alternative.preds, 0, newPreds, preds.length, nextByAddr.preds.length);
alternative.preds.length); System.arraycopy(preds, 0, newPreds, nextByAddr.preds.length,
alternative.preds = newPreds; preds.length);
nextByAddr.preds = newPreds;
} }
preds = null; preds = null;
} }
@ -499,7 +599,7 @@ public final class Instruction implements Opcodes{
if (lnt != null) { if (lnt != null) {
for (int i=0; i< lnt.length; i++) { for (int i=0; i< lnt.length; i++) {
if (lnt[i].start == this) { if (lnt[i].start == this) {
if (nextByAddr == null if (nextByAddr.opcode == opc_xxxunusedxxx
|| (i+1 < lnt.length || (i+1 < lnt.length
&& lnt[i+1].start == nextByAddr)) { && lnt[i+1].start == nextByAddr)) {
/* Remove the line number. /* Remove the line number.
@ -517,6 +617,22 @@ public final class Instruction implements Opcodes{
} }
} }
} }
prevByAddr = null;
nextByAddr = null;
}
public int compareTo(Instruction instr) {
if (addr != instr.addr)
return addr - instr.addr;
if (this == instr)
return 0;
do {
instr = instr.nextByAddr;
if (instr.addr > addr)
return -1;
} while (instr != this);
return 1;
} }
/** /**
@ -541,7 +657,7 @@ public final class Instruction implements Opcodes{
case opc_invokespecial: case opc_invokespecial:
case opc_invokestatic: case opc_invokestatic:
case opc_invokeinterface: { case opc_invokeinterface: {
Reference ref = (Reference) objData; Reference ref = getReference();
String typeSig = ref.getType(); String typeSig = ref.getType();
poppush[0] = opcode != opc_invokestatic ? 1 : 0; poppush[0] = opcode != opc_invokestatic ? 1 : 0;
poppush[0] += TypeSignature.getArgumentSize(typeSig); poppush[0] += TypeSignature.getArgumentSize(typeSig);
@ -551,7 +667,7 @@ public final class Instruction implements Opcodes{
case opc_putfield: case opc_putfield:
case opc_putstatic: { case opc_putstatic: {
Reference ref = (Reference) objData; Reference ref = getReference();
poppush[1] = 0; poppush[1] = 0;
poppush[0] = TypeSignature.getTypeSize(ref.getType()); poppush[0] = TypeSignature.getTypeSize(ref.getType());
if (opcode == opc_putfield) if (opcode == opc_putfield)
@ -560,7 +676,7 @@ public final class Instruction implements Opcodes{
} }
case opc_getstatic: case opc_getstatic:
case opc_getfield: { case opc_getfield: {
Reference ref = (Reference) objData; Reference ref = getReference();
poppush[1] = TypeSignature.getTypeSize(ref.getType()); poppush[1] = TypeSignature.getTypeSize(ref.getType());
poppush[0] = opcode == opc_getfield ? 1 : 0; poppush[0] = opcode == opc_getfield ? 1 : 0;
break; break;
@ -568,7 +684,7 @@ public final class Instruction implements Opcodes{
case opc_multianewarray: { case opc_multianewarray: {
poppush[1] = 1; poppush[1] = 1;
poppush[0] = prevByAddr.intData; poppush[0] = getDimensions();
break; break;
} }
default: default:
@ -620,27 +736,24 @@ public final class Instruction implements Opcodes{
StringBuffer result = new StringBuffer(String.valueOf(addr)) StringBuffer result = new StringBuffer(String.valueOf(addr))
.append('_').append(Integer.toHexString(hashCode())) .append('_').append(Integer.toHexString(hashCode()))
.append(": ").append(opcodeString[opcode]); .append(": ").append(opcodeString[opcode]);
if (localSlot != -1) if (opcode != opc_lookupswitch) {
result.append(" ").append(localSlot); if (hasLocalSlot())
if (succs != null && succs.length == 1) result.append(' ').append(getLocalSlot());
result.append(" ").append(succs[0].addr); if (succs != null)
switch (opcode) { result.append(' ').append(((Instruction) succs).addr);
case opc_iinc: if (objData != null)
result.append(" ").append(intData); result.append(' ').append(objData);
break; if (opcode == opc_multianewarray)
case opc_ldc: case opc_ldc2_w: result.append(' ').append(getDimensions());
case opc_getstatic: case opc_getfield: } else {
case opc_putstatic: case opc_putfield: int[] values = getValues();
case opc_invokespecial: case opc_invokestatic: case opc_invokevirtual: Instruction[] succs = getSuccs();
case opc_new: for (int i=0; i < values.length; i++) {
case opc_checkcast: result.append(' ').append(values[i]).append("->")
case opc_instanceof: .append(((Instruction) succs[i]).addr);
result.append(" ").append(objData); }
break; result.append(' ').append("default: ")
case opc_multianewarray: .append(((Instruction) succs[values.length]).addr);
case opc_invokeinterface:
result.append(" ").append(objData).append(" ").append(intData);
break;
} }
return result.toString(); return result.toString();
} }

@ -1,94 +0,0 @@
/* Reference Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
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
/**
* This class represents a field or method reference.
*/
public class Reference {
/**
* The reference string. This is the class name, the member name and
* the member type, all separated by a space.
*/
private final String sig;
/**
* The position of the first and second space in the reference
* string.
*/
private final int firstSpace, secondSpace;
///#ifdef JDK12
/// private static final Map references = new HashMap();
///#else
private static final Hashtable references = new Hashtable();
///#endif
public static Reference getReference(String className,
String name, String type) {
String sig = className+" "+name+" "+type;
///#ifdef JDK12
/// WeakReference ref = (WeakReference) references.get(sig);
/// Reference reference = (ref == null) ? null : (Reference) ref.get();
///#else
Reference reference = (Reference) references.get(sig);
///#endif
if (reference == null) {
sig = sig.intern();
int firstSpace = className.length();
int secondSpace = firstSpace + name.length() + 1;
reference = new Reference(sig, firstSpace, secondSpace);
///#ifdef JDK12
/// references.put(sig, new WeakReference(reference));
///#else
references.put(sig, reference);
///#endif
}
return reference;
}
private Reference(String sig, int first, int second) {
this.sig = sig;
this.firstSpace = first;
this.secondSpace = second;
}
public String getClazz() {
return sig.substring(0, firstSpace);
}
public String getName() {
return sig.substring(firstSpace + 1, secondSpace);
}
public String getType() {
return sig.substring(secondSpace + 1);
}
public String toString() {
return sig;
}
}

@ -0,0 +1,72 @@
/* Reference Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.bytecode;
import jode.util.UnifyHash;
import @COLLECTIONS@.Iterator;
/**
* This class represents a field or method reference.
*/
public class Reference {
/**
* A reference consists of a class name, a member name and a type.
*/
private final String clazz, name, type;
private static final UnifyHash unifier = new UnifyHash();
public static Reference getReference(String className,
String name, String type) {
int hash = className.hashCode() ^ name.hashCode() ^ type.hashCode();
Iterator iter = unifier.iterateHashCode(hash);
while (iter.hasNext()) {
Reference ref = (Reference) iter.next();
if (ref.clazz.equals(className)
&& ref.name.equals(name)
&& ref.type.equals(type))
return ref;
}
Reference ref = new Reference(className, name, type);
unifier.put(hash, ref);
return ref;
}
private Reference(String clazz, String name, String type) {
this.clazz = clazz;
this.name = name;
this.type = type;
}
public String getClazz() {
return clazz;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public String toString() {
return clazz + " " + name + " " + type;
}
}

@ -81,6 +81,28 @@ public class TypeSignature {
return usingTwoSlots(typeSig.charAt(0)) ? 2 : 1; return usingTwoSlots(typeSig.charAt(0)) ? 2 : 1;
} }
public static String getElementType(String typeSig) {
if (typeSig.charAt(0) != '[')
throw new IllegalArgumentException();
return typeSig.substring(1);
}
public static ClassInfo getClassInfo(String typeSig) {
if (typeSig.charAt(0) != 'L')
throw new IllegalArgumentException();
return ClassInfo.forName
(typeSig.substring(1, typeSig.length()-1).replace('/', '.'));
}
public static int skipType(String methodTypeSig, int position) {
char c = methodTypeSig.charAt(position++);
while (c == '[')
c = methodTypeSig.charAt(position++);
if (c == 'L')
return methodTypeSig.indexOf(';', position) + 1;
return position;
}
/** /**
* Returns the number of words, the arguments for the given method * Returns the number of words, the arguments for the given method
* type signature takes. * type signature takes.
@ -89,29 +111,60 @@ public class TypeSignature {
int nargs = 0; int nargs = 0;
int i = 1; int i = 1;
for (;;) { for (;;) {
char c = methodTypeSig.charAt(i++); char c = methodTypeSig.charAt(i);
if (c == ')') if (c == ')')
return nargs; return nargs;
i = skipType(methodTypeSig, i);
if (usingTwoSlots(c)) if (usingTwoSlots(c))
nargs += 2; nargs += 2;
else { else
while (c == '[')
c = methodTypeSig.charAt(i++);
if (c == 'L')
i = methodTypeSig.indexOf(';', i) + 1;
nargs++; nargs++;
} }
} }
}
/** /**
* Returns the number of words, an object of the given simple type * Returns the number of words, an object of the given simple type
* signature takes. * signature takes.
*/ */
public static int getReturnSize(String methodTypeSig) { public static int getReturnSize(String methodTypeSig) {
char returnType = methodTypeSig.charAt(methodTypeSig.indexOf(')')+1); int length = methodTypeSig.length();
if (methodTypeSig.charAt(length - 2) == ')') {
// This is a single character return type.
char returnType = methodTypeSig.charAt(length - 1);
return returnType == 'V' ? 0 return returnType == 'V' ? 0
: usingTwoSlots(returnType) ? 2 : 1; : usingTwoSlots(returnType) ? 2 : 1;
} else
// All multi character return types take one parameter
return 1;
}
/**
* Returns the number of words, an object of the given simple type
* signature takes.
*/
public static String[] getParameterTypes(String methodTypeSig) {
int pos = 1;
int count = 0;
while (methodTypeSig.charAt(pos) != ')') {
pos = skipType(methodTypeSig, pos);
count++;
}
String[] params = new String[count];
pos = 1;
for (int i = 0; i < count; i++) {
int start = pos;
pos = skipType(methodTypeSig, pos);
params[i] = methodTypeSig.substring(start, pos);
}
return params;
}
/**
* Returns the number of words, an object of the given simple type
* signature takes.
*/
public static String getReturnType(String methodTypeSig) {
return methodTypeSig.substring(methodTypeSig.lastIndexOf(')')+1);
} }
private static void checkClassName(String clName) private static void checkClassName(String clName)

Loading…
Cancel
Save