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. 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 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,8 +71,11 @@ 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 {
@ -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,45 +163,59 @@ 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);
Iterator i = unknownAttributes.entrySet().iterator(); if (unknownAttributes != null) {
while (i.hasNext()) { Iterator i = unknownAttributes.entrySet().iterator();
Map.Entry e = (Map.Entry) i.next(); while (i.hasNext()) {
String name = (String) e.getKey(); Map.Entry e = (Map.Entry) i.next();
byte[] data = (byte[]) e.getValue(); String name = (String) e.getKey();
output.writeShort(constantPool.putUTF8(name)); byte[] data = (byte[]) e.getValue();
output.writeInt(data.length); output.writeShort(constantPool.putUTF8(name));
output.write(data); output.writeInt(data.length);
output.write(data);
}
} }
} }
public int getAttributeSize() { public int getAttributeSize() {
int size = 2; /* attribute count */ int size = 2; /* attribute count */
Iterator i = unknownAttributes.values().iterator(); if (unknownAttributes != null) {
while (i.hasNext()) Iterator i = unknownAttributes.values().iterator();
size += 2 + 4 + ((byte[]) i.next()).length; while (i.hasNext())
size += 2 + 4 + ((byte[]) i.next()).length;
}
return size; return size;
} }
public byte[] findAttribute(String name) { public byte[] findAttribute(String name) {
return (byte[]) unknownAttributes.get(name); if (unknownAttributes != null)
return (byte[]) unknownAttributes.get(name);
return null;
} }
public Iterator getAttributes() { 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) { 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) {
return (byte[]) unknownAttributes.remove(name); if (unknownAttributes != null)
return (byte[]) unknownAttributes.remove(name);
return null;
} }
public void removeAllAttributes() { public void removeAllAttributes() {
unknownAttributes.clear(); unknownAttributes = null;
} }
} }

File diff suppressed because it is too large Load Diff

@ -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;
@ -70,26 +69,12 @@ public class ClassInfo extends BinaryInfo {
private String sourceFile; private String sourceFile;
public final static ClassInfo javaLangObject = forName("java.lang.Object"); public final static ClassInfo javaLangObject = forName("java.lang.Object");
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;
@ -124,7 +109,7 @@ public class ClassInfo extends BinaryInfo {
} }
}; };
} }
public static ClassInfo forName(String name) { public static ClassInfo forName(String name) {
if (name == null if (name == null
|| name.indexOf(';') != -1 || name.indexOf(';') != -1
@ -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 = new ClassInfo(name);
ClassInfo clazz = (ClassInfo) classes.get(name); classes.put(hash, clazz);
///#endif
if (clazz == null) {
clazz = new ClassInfo(name);
///#ifdef JDK12
/// classes.put(name, new WeakReference(clazz, queue));
///#else
classes.put(name, clazz);
///#endif
}
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 int getLocalSlot() { public final boolean hasLocalSlot() {
return localSlot; 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) { 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); // 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) { * @param to may be null
if (succs != null && succs != newSuccs) { */
for (int i = 0; i< succs.length; i++) private final void promoteSuccs(Instruction from, Instruction to) {
succs[i].removePredecessor(this); 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; * @exception ClassCastException if newSuccs is neither an Instruction
if (succs != null) { * nor an array of instructions.
for (int i = 0; i< succs.length; i++) */
succs[i].addPredecessor(this); 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) { 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; * Replaces the opcode of this instruction. You should only use the
newInstr.addr = addr; * 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; newInstr.prevByAddr = prevByAddr;
if (prevByAddr != null) prevByAddr = null;
prevByAddr.nextByAddr = newInstr; nextByAddr = null;
else
codeinfo.firstInstr = newInstr; /* promote the successors of the predecessors to newInstr */
newInstr.nextByAddr = this;
prevByAddr = newInstr;
/* promote 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;
}
public final Instruction insertInstruction(int opc, /* adjust exception handlers */
Instruction[] newSuccs) { Handler[] handlers = codeinfo.getExceptionHandlers();
Instruction newInstr = insertInstruction(opc); for (int i=0; i< handlers.length; i++) {
if (newSuccs != null) if (handlers[i].start == this)
newInstr.setSuccs(newSuccs); handlers[i].start = newInstr;
return 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) { void appendInstruction(Instruction newInstr) {
codeinfo.instructionCount++; newInstr.addr = nextByAddr.addr;
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; nextByAddr.prevByAddr = prevByAddr;
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;
/* 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;
}
}

@ -80,6 +80,28 @@ public class TypeSignature {
public static int getTypeSize(String typeSig) { public static int getTypeSize(String typeSig) {
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
@ -89,18 +111,14 @@ 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++;
}
} }
} }
@ -109,9 +127,44 @@ public class TypeSignature {
* 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();
return returnType == 'V' ? 0 if (methodTypeSig.charAt(length - 2) == ')') {
: usingTwoSlots(returnType) ? 2 : 1; // 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) private static void checkClassName(String clName)

Loading…
Cancel
Save