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 25 years ago
parent ddbf2c969a
commit 996fc49dbd
  1. 58
      jode/jode/bytecode/BinaryInfo.java.in
  2. 610
      jode/jode/bytecode/BytecodeInfo.java.in
  3. 73
      jode/jode/bytecode/ClassInfo.java.in
  4. 471
      jode/jode/bytecode/Instruction.java
  5. 94
      jode/jode/bytecode/Reference.java
  6. 72
      jode/jode/bytecode/Reference.java.in
  7. 73
      jode/jode/bytecode/TypeSignature.java

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

File diff suppressed because it is too large Load Diff

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

@ -18,27 +18,29 @@
*/
package jode.bytecode;
import java.util.Vector;
import java.util.Enumeration;
/**
* This class represents an instruction in the byte code.
*
*/
public final class Instruction implements Opcodes{
private BytecodeInfo codeinfo;
/**
* The opcode of the instruction. We map some opcodes, e.g.
* <pre>
* iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc.
* </pre>
*/
// a byte would be enough, but then we would need an unsigned convert.
private int opcode;
/**
* If this opcode uses a local this gives the slot. This info is
* used when swapping locals.
* If this opcode uses a local this gives the slot. For multianewarray
* 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
* usages of this field:
@ -54,68 +56,50 @@ public final class Instruction implements Opcodes{
* </dl>
*/
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
* (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.
* This must be null or a non empty array.
*/
Instruction[] preds;
private Instruction[] preds;
/**
* The next instruction in code order.
*/
private Instruction nextByAddr;
Instruction nextByAddr;
/**
* The previous instruction in code order, useful when changing
* the order.
*/
private Instruction prevByAddr;
Instruction prevByAddr;
/**
* You can use this field to add some info to each instruction.
* 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;
public Instruction(BytecodeInfo ci) {
this.codeinfo = ci;
public Instruction(int opcode) {
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>
* iload_0 -&gt; iload
* ldc_w -&gt; ldc
* wide iinc -&gt; iinc
* [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 int getOpcode() {
@ -137,6 +121,10 @@ public final class Instruction implements Opcodes{
return addr;
}
public final int getNextAddr() {
return nextByAddr.addr;
}
/**
* Returns the length of this opcode. See getAddr() for some
* 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.
*/
public final int getLength() {
return length;
return getNextAddr() - addr;
}
final void setAddr(int addr) {
this.addr = addr;
}
final void setLength(int length) {
this.length = length;
}
public final int getLocalSlot() {
return localSlot;
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()
/*{ require { hasLocalSlot()
:: "Instruction has no slot" } }*/
{
return shortData;
}
public final void setLocalSlot(int slot) {
localSlot = slot;
public final void setLocalSlot(int 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
|| opcode == opc_tableswitch
:: "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
|| opcode == opc_tableswitch
:: "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()
@ -265,15 +303,44 @@ public final class Instruction implements Opcodes{
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() {
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() {
if (prevByAddr.opcode == opc_xxxunusedxxx)
return null;
return prevByAddr;
}
public final Instruction getNextByAddr() {
if (nextByAddr.opcode == opc_xxxunusedxxx)
return null;
return nextByAddr;
}
@ -285,34 +352,68 @@ public final class Instruction implements Opcodes{
tmpInfo = info;
}
public final void replaceInstruction(int newOpcode) {
replaceInstruction(newOpcode, null);
// INTERNAL FUNCTIONS TO KEEP PREDS AND SUCCS CONSISTENT
final void removeSuccs() {
if (succs == null)
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;
}
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);
/**
* @param to may be null
*/
private final void promoteSuccs(Instruction from, Instruction to) {
if (succs == from)
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;
}
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);
/**
* @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;
((Instruction) newSuccs).addPredecessor(this);
}
}
public void addPredecessor(Instruction pred) {
void addPredecessor(Instruction pred) {
if (preds == null) {
preds = new Instruction[] { pred };
return;
@ -324,7 +425,7 @@ public final class Instruction implements Opcodes{
preds = newPreds;
}
public void removePredecessor(Instruction pred) {
void removePredecessor(Instruction pred) {
/* Hopefully it doesn't matter if this is slow */
int predLength = preds.length;
if (predLength == 1) {
@ -342,108 +443,107 @@ public final class Instruction implements Opcodes{
}
}
public final Instruction insertInstruction(int opc) {
codeinfo.instructionCount++;
Instruction newInstr = new Instruction(codeinfo);
newInstr.opcode = opc;
newInstr.addr = addr;
// ADDING, REMOVING AND REPLACING INSTRUCTIONS
/**
* 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;
newInstr.prevByAddr = prevByAddr;
if (prevByAddr != null)
prevByAddr.nextByAddr = newInstr;
else
codeinfo.firstInstr = newInstr;
newInstr.nextByAddr = this;
prevByAddr = newInstr;
/* promote the predecessors to newInstr */
prevByAddr = null;
nextByAddr = null;
/* promote the successors of the predecessors to newInstr */
if (preds != null) {
for (int j=0; j < preds.length; j++)
for (int i=0; i < preds[j].succs.length; i++)
if (preds[j].succs[i] == this)
preds[j].succs[i] = newInstr;
preds[j].promoteSuccs(this, newInstr);
newInstr.preds = preds;
preds = null;
}
return newInstr;
}
public final Instruction insertInstruction(int opc,
Instruction[] newSuccs) {
Instruction newInstr = insertInstruction(opc);
if (newSuccs != null)
newInstr.setSuccs(newSuccs);
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;
}
/* adjust local variable table and line number table */
LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable();
if (lvt != null) {
for (int i=0; i< lvt.length; i++) {
if (lvt[i].start == this)
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;
}
}
}
public Instruction appendInstruction(int opc) {
codeinfo.instructionCount++;
Instruction newInstr = new Instruction(codeinfo);
newInstr.opcode = opc;
newInstr.addr = addr + length;
newInstr.length = 0;
void appendInstruction(Instruction newInstr) {
newInstr.addr = nextByAddr.addr;
newInstr.nextByAddr = nextByAddr;
if (nextByAddr != null)
nextByAddr.prevByAddr = newInstr;
nextByAddr.prevByAddr = newInstr;
newInstr.prevByAddr = this;
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).
*/
public void removeInstruction() {
codeinfo.instructionCount--;
void removeInstruction(BytecodeInfo codeinfo) {
/* remove from chained list and adjust addr / length */
if (prevByAddr != null) {
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;
prevByAddr.nextByAddr = nextByAddr;
nextByAddr.prevByAddr = prevByAddr;
/* remove predecessors of successors */
if (succs != null) {
for (int i=0; i < succs.length; i++)
succs[i].removePredecessor(this);
succs = null;
}
removeSuccs();
Instruction alternative = nextByAddr != null ? nextByAddr : prevByAddr;
/* remove the predecessors to alternative */
/* promote the predecessors to next instruction */
if (preds != null) {
for (int j=0; j < preds.length; j++)
for (int i=0; i < preds[j].succs.length; i++)
if (preds[j].succs[i] == this)
preds[j].succs[i] = alternative;
if (alternative.preds == null)
alternative.preds = preds;
preds[j].promoteSuccs(this, nextByAddr);
if (nextByAddr.preds == null)
nextByAddr.preds = preds;
else {
Instruction[] newPreds
= new Instruction[alternative.preds.length + preds.length];
System.arraycopy(preds, 0, newPreds, 0, preds.length);
System.arraycopy(alternative.preds, 0, newPreds, preds.length,
alternative.preds.length);
alternative.preds = newPreds;
Instruction[] newPreds = new Instruction
[nextByAddr.preds.length + preds.length];
System.arraycopy(nextByAddr.preds, 0, newPreds, 0,
nextByAddr.preds.length);
System.arraycopy(preds, 0, newPreds, nextByAddr.preds.length,
preds.length);
nextByAddr.preds = newPreds;
}
preds = null;
}
@ -499,7 +599,7 @@ public final class Instruction implements Opcodes{
if (lnt != null) {
for (int i=0; i< lnt.length; i++) {
if (lnt[i].start == this) {
if (nextByAddr == null
if (nextByAddr.opcode == opc_xxxunusedxxx
|| (i+1 < lnt.length
&& lnt[i+1].start == nextByAddr)) {
/* 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_invokestatic:
case opc_invokeinterface: {
Reference ref = (Reference) objData;
Reference ref = getReference();
String typeSig = ref.getType();
poppush[0] = opcode != opc_invokestatic ? 1 : 0;
poppush[0] += TypeSignature.getArgumentSize(typeSig);
@ -551,7 +667,7 @@ public final class Instruction implements Opcodes{
case opc_putfield:
case opc_putstatic: {
Reference ref = (Reference) objData;
Reference ref = getReference();
poppush[1] = 0;
poppush[0] = TypeSignature.getTypeSize(ref.getType());
if (opcode == opc_putfield)
@ -560,7 +676,7 @@ public final class Instruction implements Opcodes{
}
case opc_getstatic:
case opc_getfield: {
Reference ref = (Reference) objData;
Reference ref = getReference();
poppush[1] = TypeSignature.getTypeSize(ref.getType());
poppush[0] = opcode == opc_getfield ? 1 : 0;
break;
@ -568,7 +684,7 @@ public final class Instruction implements Opcodes{
case opc_multianewarray: {
poppush[1] = 1;
poppush[0] = prevByAddr.intData;
poppush[0] = getDimensions();
break;
}
default:
@ -620,27 +736,24 @@ public final class Instruction implements Opcodes{
StringBuffer result = new StringBuffer(String.valueOf(addr))
.append('_').append(Integer.toHexString(hashCode()))
.append(": ").append(opcodeString[opcode]);
if (localSlot != -1)
result.append(" ").append(localSlot);
if (succs != null && succs.length == 1)
result.append(" ").append(succs[0].addr);
switch (opcode) {
case opc_iinc:
result.append(" ").append(intData);
break;
case opc_ldc: case opc_ldc2_w:
case opc_getstatic: case opc_getfield:
case opc_putstatic: case opc_putfield:
case opc_invokespecial: case opc_invokestatic: case opc_invokevirtual:
case opc_new:
case opc_checkcast:
case opc_instanceof:
result.append(" ").append(objData);
break;
case opc_multianewarray:
case opc_invokeinterface:
result.append(" ").append(objData).append(" ").append(intData);
break;
if (opcode != opc_lookupswitch) {
if (hasLocalSlot())
result.append(' ').append(getLocalSlot());
if (succs != null)
result.append(' ').append(((Instruction) succs).addr);
if (objData != null)
result.append(' ').append(objData);
if (opcode == opc_multianewarray)
result.append(' ').append(getDimensions());
} else {
int[] values = getValues();
Instruction[] succs = getSuccs();
for (int i=0; i < values.length; i++) {
result.append(' ').append(values[i]).append("->")
.append(((Instruction) succs[i]).addr);
}
result.append(' ').append("default: ")
.append(((Instruction) succs[values.length]).addr);
}
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;
}
}

@ -80,6 +80,28 @@ public class TypeSignature {
public static int getTypeSize(String typeSig) {
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
@ -89,18 +111,14 @@ public class TypeSignature {
int nargs = 0;
int i = 1;
for (;;) {
char c = methodTypeSig.charAt(i++);
char c = methodTypeSig.charAt(i);
if (c == ')')
return nargs;
i = skipType(methodTypeSig, i);
if (usingTwoSlots(c))
nargs += 2;
else {
while (c == '[')
c = methodTypeSig.charAt(i++);
if (c == 'L')
i = methodTypeSig.indexOf(';', i) + 1;
else
nargs++;
}
}
}
@ -109,9 +127,44 @@ public class TypeSignature {
* signature takes.
*/
public static int getReturnSize(String methodTypeSig) {
char returnType = methodTypeSig.charAt(methodTypeSig.indexOf(')')+1);
return returnType == 'V' ? 0
: usingTwoSlots(returnType) ? 2 : 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
: 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)

Loading…
Cancel
Save