Cleaned up the bytecode module:

-  no references to jode.type anymore
  -  all fields in Instruction are private now
  -  instructions are inserted with length 0, so that addr's are correct
  -  instruction length increases, when a neighbour gets removed
  -  all lenghts are recalculated on write
  -  more checks


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1062 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent 75df7ec7f2
commit 56464880ac
  1. 7
      jode/jode/bytecode/BinaryInfo.java
  2. 951
      jode/jode/bytecode/BytecodeInfo.java
  3. 15
      jode/jode/bytecode/ClassInfo.java
  4. 100
      jode/jode/bytecode/ConstantPool.java
  5. 4
      jode/jode/bytecode/FieldInfo.java
  6. 17
      jode/jode/bytecode/GrowableConstantPool.java
  7. 432
      jode/jode/bytecode/Instruction.java
  8. 4
      jode/jode/bytecode/MethodInfo.java
  9. 4
      jode/jode/bytecode/Reference.java
  10. 21
      jode/jode/bytecode/SearchPath.java
  11. 196
      jode/jode/bytecode/TypeSignature.java

@ -18,7 +18,12 @@
*/
package jode.bytecode;
import java.io.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import jode.util.SimpleMap;
///#ifdef JDK12

File diff suppressed because it is too large Load Diff

@ -19,12 +19,17 @@
package jode.bytecode;
import jode.GlobalOptions;
import jode.type.Type;
import java.io.*;
import java.util.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Enumeration;
///#ifdef JDK12
///import java.util.Map;
///import java.util.HashMap;
///import java.lang.ref.WeakReference;
///import java.lang.ref.ReferenceQueue;
///#else
import java.util.Hashtable;
///#endif
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@ -472,7 +477,7 @@ public class ClassInfo extends BinaryInfo {
}
fields = new FieldInfo[fs.length];
for (int i = fs.length; --i >= 0; ) {
String type = Type.getSignature(fs[i].getType());
String type = TypeSignature.getSignature(fs[i].getType());
fields[i] = new FieldInfo
(this, fs[i].getName(), type, fs[i].getModifiers());
}
@ -489,7 +494,7 @@ public class ClassInfo extends BinaryInfo {
}
methods = new MethodInfo[ms.length];
for (int i = ms.length; --i >= 0; ) {
String type = Type.getSignature
String type = TypeSignature.getSignature
(ms[i].getParameterTypes(), ms[i].getReturnType());
methods[i] = new MethodInfo
(this, ms[i].getName(), type, ms[i].getModifiers());

@ -18,8 +18,8 @@
*/
package jode.bytecode;
import java.io.*;
import jode.type.Type;
import java.io.DataInputStream;
import java.io.IOException;
/**
* This class represent the constant pool.
@ -45,76 +45,6 @@ public class ConstantPool {
Object[] constants;
void checkClassName(String clName) throws ClassFormatException {
boolean start = true;
for (int i=0; i< clName.length(); i++) {
char c = clName.charAt(i);
if (c == '/')
start = true;
else if (start && Character.isJavaIdentifierStart(c))
start = false;
else if ((start && false /*XXX*/)
|| !Character.isJavaIdentifierPart(c))
throw new ClassFormatException("Illegal java class name: "
+ clName);
}
}
void checkTypeSig(String typesig, boolean isMethod)
throws ClassFormatException {
try {
int i = 0;
if (isMethod) {
if (typesig.charAt(i++) != '(')
throw new ClassFormatException
("Type sig doesn't match tag: "+typesig);
while (typesig.charAt(i) != ')') {
while (typesig.charAt(i) == '[') {
i++;
if (i >= typesig.length())
throw new ClassFormatException
("Type sig error: "+typesig);
}
if (typesig.charAt(i) == 'L') {
int end = typesig.indexOf(';', i);
if (end == -1)
throw new ClassFormatException
("Type sig error: "+typesig);
checkClassName(typesig.substring(i+1, end));
i = end;
} else {
if ("ZBSCIJFD".indexOf(typesig.charAt(i)) == -1)
throw new ClassFormatException
("Type sig error: "+typesig);
}
i++;
}
i++;
}
while (typesig.charAt(i) == '[')
i++;
if (typesig.charAt(i) == 'L') {
int end = typesig.indexOf(';', i);
if (i == -1)
throw new ClassFormatException
("Type sig error: "+typesig);
checkClassName(typesig.substring(i+1, end));
i = end;
} else {
if ("ZBSCIJFD".indexOf(typesig.charAt(i)) == -1)
if (!isMethod || typesig.charAt(i) != 'V')
throw new ClassFormatException
("Type sig error: "+typesig);
}
if (i+1 != typesig.length())
throw new ClassFormatException
("Type sig error: "+typesig);
} catch (StringIndexOutOfBoundsException ex) {
throw new ClassFormatException
("Incomplete type sig: "+typesig);
}
}
public ConstantPool () {
}
@ -195,7 +125,14 @@ public class ConstantPool {
if (tags[nameTypeIndex] != NAMEANDTYPE)
throw new ClassFormatException("Tag mismatch");
String type = getUTF8(indices2[nameTypeIndex]);
checkTypeSig(type, tags[i] != FIELDREF);
try {
if (tags[i] == FIELDREF)
TypeSignature.checkTypeSig(type);
else
TypeSignature.checkMethodTypeSig(type);
} catch (IllegalArgumentException ex) {
throw new ClassFormatException(ex.getMessage());
}
String clName = getClassType(classIndex);
constants[i] = Reference.getReference
(clName, getUTF8(indices1[nameTypeIndex]), type);
@ -224,12 +161,15 @@ public class ConstantPool {
if (tags[i] != CLASS)
throw new ClassFormatException("Tag mismatch");
String clName = getUTF8(indices1[i]);
if (clName.charAt(0) == '[')
checkTypeSig(clName, false);
else {
checkClassName(clName);
if (clName.charAt(0) != '[') {
clName = ("L"+clName+';').intern();
}
try {
TypeSignature.checkTypeSig(clName);
} catch (IllegalArgumentException ex) {
throw new ClassFormatException(ex.getMessage());
}
return clName;
}
@ -239,7 +179,11 @@ public class ConstantPool {
if (tags[i] != CLASS)
throw new ClassFormatException("Tag mismatch");
String clName = getUTF8(indices1[i]);
checkClassName(clName);
try {
TypeSignature.checkTypeSig("L"+clName+";");
} catch (IllegalArgumentException ex) {
throw new ClassFormatException(ex.getMessage());
}
return clName.replace('/','.').intern();
}

@ -18,7 +18,9 @@
*/
package jode.bytecode;
import java.io.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
public class FieldInfo extends BinaryInfo {

@ -18,8 +18,8 @@
*/
package jode.bytecode;
import java.io.*;
import jode.type.Type;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Hashtable;
/**
@ -60,7 +60,7 @@ public class GrowableConstantPool extends ConstantPool {
}
}
int putConstant(int tag, Object constant) {
private int putConstant(int tag, Object constant) {
String key = "" + (char)tag + constant;
Integer index = (Integer) entryToIndex.get(key);
if (index != null)
@ -74,7 +74,7 @@ public class GrowableConstantPool extends ConstantPool {
return newIndex;
}
int putLongConstant(int tag, Object constant) {
private int putLongConstant(int tag, Object constant) {
String key = "" + (char)tag + constant;
Integer index = (Integer) entryToIndex.get(key);
if (index != null)
@ -112,13 +112,17 @@ public class GrowableConstantPool extends ConstantPool {
public int putClassName(String name) {
name = name.replace('.','/');
TypeSignature.checkTypeSig("L"+name+";");
return putIndexed(""+(char) CLASS + name,
CLASS, putUTF8(name), 0);
}
public int putClassType(String name) {
TypeSignature.checkTypeSig(name);
if (name.charAt(0) == 'L')
name = name.substring(1, name.length()-1);
else if (name.charAt(0) != '[')
throw new IllegalArgumentException("wrong class type: "+name);
return putIndexed(""+(char) CLASS + name,
CLASS, putUTF8(name), 0);
}
@ -127,6 +131,11 @@ public class GrowableConstantPool extends ConstantPool {
String className = ref.getClazz();
String typeSig = ref.getType();
String nameAndType = ref.getName() + "/" + typeSig;
if (tag == FIELDREF)
TypeSignature.checkTypeSig(typeSig);
else
TypeSignature.checkMethodTypeSig(typeSig);
int classIndex = putClassType(className);
int nameIndex = putUTF8(ref.getName());

@ -20,85 +20,298 @@
package jode.bytecode;
import java.util.Vector;
import java.util.Enumeration;
import jode.type.Type;
import jode.type.MethodType;
/**
* This class represents an instruction in the byte code.
*
* For simplicity currently most fields are public. You shouldn't change
* many of them, though.
*/
public class Instruction implements Opcodes{
public BytecodeInfo codeinfo;
public final class Instruction implements Opcodes{
private BytecodeInfo codeinfo;
/**
* The opcode of the instruction. We map some opcodes, e.g.
* <pre>
* iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc.
* </pre>
*/
public int opcode;
private int opcode;
/**
* If this opcode uses a local this gives the slot. This info is
* used when swapping locals.
*/
public int localSlot = -1;
private int localSlot = -1;
/**
* Optional object data for this opcode. This is mostly used for
* method/field/class references, but also for a value array
* in a lookupswitch.
* Optional object data for this opcode. There are four different
* usages of this field:
* <dl>
* <dt>opc_ldc / opc_ldc2_w</dt>
* <dd>The constant of type Integer/Long/Float/Double/String. </dd>
* <dt>opc_invokexxx / opc_xxxfield / opc_xxxstatic</dt>
* <dd>The field/method Reference</dd>
* <dt>opc_new / opc_checkcast / opc_instanceof / opc_multianewarray</dt>
* <dd>The typesignature of the class/array</dd>
* <dt>opc_lookupswitch</dt>
* <dd>The array of values of type int[]</dd>
* </dl>
*/
public Object objData;
private Object objData;
/**
* Optional integer data for this opcode. There are various uses
* for this.
* 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>
*/
public int intData;
private int intData;
/**
* The address of this opcode.
*/
public int addr;
private int addr;
/**
* The length of this opcode. You shouldn't touch it, nor rely on
* it, since the length of some opcodes may change automagically
* (e.g. when changing localSlot iload_0 <-> iload 5)
*/
public int length;
/**
* If this is true, the instruction will never flow into the nextByAddr.
*/
public boolean alwaysJumps = false;
private int length;
/**
* The successors of this opcodes, where flow may lead to
* (except that nextByAddr is implicit if !alwaysJump). The
* value null is equivalent to an empty array.
*/
public Instruction[] succs;
Instruction[] succs;
/**
* The predecessors of this opcode, orthogonal to the succs array.
* This must be null or a non empty array.
*/
public Instruction[] preds;
Instruction[] preds;
/**
* The next instruction in code order.
*/
public Instruction nextByAddr;
private Instruction nextByAddr;
/**
* The previous instruction in code order, useful when changing
* the order.
*/
public Instruction prevByAddr;
private Instruction prevByAddr;
/**
* You can use this field to add some info to each instruction.
* After using, you must set it to null again.
*/
public Object tmpInfo;
private Object tmpInfo;
public Instruction(BytecodeInfo ci) {
this.codeinfo = ci;
}
/**
* Returns the opcode of the instruction. We map some opcodes, e.g.
* <pre>
* iload_0 -&gt; iload
* ldc_w -&gt; ldc
* wide iinc -&gt; iinc
* </pre>
*/
public final int getOpcode() {
return opcode;
}
/**
* Returns the address of this opcode. As long as you don't remove
* or insert instructions, you can be sure, that the addresses of the
* opcodes are unique, and that
* <pre>
* instr.getAddr() + instr.getLength() == instr.getNextByAddr().getAddr()
* <pre>
*
* If you insert/remove Instructions, you should be aware that the
* above property is not guaranteed anymore.
*/
public final int getAddr() {
return addr;
}
/**
* Returns the length of this opcode. See getAddr() for some
* notes. Note that the length doesn't necessarily reflect the
* real length, when this bytecode is written again, since the
* length of an ldc instruction depends on the number of entries
* in constant pool, and the order they are allocated.
*/
public final int getLength() {
return length;
}
final void setAddr(int addr) {
this.addr = addr;
}
final void setLength(int length) {
this.length = length;
}
public final int getLocalSlot() {
return localSlot;
}
public final void setLocalSlot(int slot) {
localSlot = slot;
}
public final int getIntData()
/*{ require { opcode == opc_iinc || opcode == opc_multianewarray
|| opcode == opc_tableswitch
:: "Instruction has no int data" } }*/
{
return intData;
}
public final void setIntData(int data)
/*{ require { opcode == opc_iinc || opcode == opc_multianewarray
|| opcode == opc_tableswitch
:: "Instruction has no int data" } }*/
{
this.intData = data;
}
public final Object getConstant()
/*{ require { opcode == opc_ldc || opcode == opc_ldc2_w
:: "Instruction has no constant" } }*/
{
return objData;
}
public final void setConstant(Object constant)
/*{ require { opcode == opc_ldc || opcode == opc_ldc2_w
:: "Instruction has no constant" } }*/
{
objData = constant;
}
public final Reference getReference()
/*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface
:: "Instruction has no reference" } }*/
{
return (Reference) objData;
}
public final void setReference(Reference ref)
/*{ require { opcode >= opc_getstatic && opcode <= opc_invokeinterface
:: "Instruction has no reference" } }*/
{
objData = ref;
}
public final String getClazzType()
/*{ require { opcode == opc_new
|| opcode == opc_checkcast
|| opcode == opc_instanceof
|| opcode == opc_multianewarray
:: "Instruction has no typesig" } }*/
{
return (String) objData;
}
public final void setClazzType(String type)
/*{ require { opcode == opc_new
|| opcode == opc_checkcast
|| opcode == opc_instanceof
|| opcode == opc_multianewarray
:: "Instruction has no typesig" } }*/
{
objData = type;
}
public final int[] getValues()
/*{ require { opcode == opc_lookupswitch
:: "Instruction has no values" } }*/
{
return (int[]) objData;
}
public final void setValues(int[] values)
/*{ require { opcode == opc_lookupswitch
:: "Instruction has no values" } }*/
{
objData = values;
}
public final boolean doesAlwaysJump() {
switch (opcode) {
case opc_ret:
case opc_goto:
case opc_jsr:
case opc_tableswitch:
case opc_lookupswitch:
case opc_ireturn:
case opc_lreturn:
case opc_freturn:
case opc_dreturn:
case opc_areturn:
case opc_return:
case opc_athrow:
return true;
default:
return false;
}
}
public final Instruction[] getPreds() {
return preds;
}
public final Instruction[] getSuccs() {
return succs;
}
public final Instruction getPrevByAddr() {
return prevByAddr;
}
public final Instruction getNextByAddr() {
return nextByAddr;
}
public final Object getTmpInfo() {
return tmpInfo;
}
public final void setTmpInfo(Object info) {
tmpInfo = info;
}
public final void replaceInstruction(int newOpcode) {
replaceInstruction(newOpcode, null);
}
public final void replaceInstruction(int newOpcode,
Instruction[] newSuccs) {
if (succs != null && succs != newSuccs) {
for (int i = 0; i< succs.length; i++)
succs[i].removePredecessor(this);
}
opcode = newOpcode;
localSlot = -1;
objData = null;
intData = 0;
if (succs != newSuccs)
setSuccs(newSuccs);
}
private final void setSuccs(Instruction[] newSuccs) {
succs = newSuccs;
if (succs != null) {
for (int i = 0; i< succs.length; i++)
succs[i].addPredecessor(this);
}
}
public void addPredecessor(Instruction pred) {
if (preds == null) {
preds = new Instruction[] { pred };
@ -129,8 +342,10 @@ public class Instruction implements Opcodes{
}
}
public Instruction insertInstruction() {
public final Instruction insertInstruction(int opc) {
codeinfo.instructionCount++;
Instruction newInstr = new Instruction(codeinfo);
newInstr.opcode = opc;
newInstr.addr = addr;
newInstr.prevByAddr = prevByAddr;
@ -153,9 +368,20 @@ public class Instruction implements Opcodes{
return newInstr;
}
public Instruction appendInstruction() {
public final Instruction insertInstruction(int opc,
Instruction[] newSuccs) {
Instruction newInstr = insertInstruction(opc);
if (newSuccs != null)
newInstr.setSuccs(newSuccs);
return newInstr;
}
public Instruction appendInstruction(int opc) {
codeinfo.instructionCount++;
Instruction newInstr = new Instruction(codeinfo);
newInstr.addr = addr;
newInstr.opcode = opc;
newInstr.addr = addr + length;
newInstr.length = 0;
newInstr.nextByAddr = nextByAddr;
if (nextByAddr != null)
nextByAddr.prevByAddr = newInstr;
@ -165,15 +391,32 @@ public class Instruction implements Opcodes{
return newInstr;
}
public Instruction appendInstruction(int opc, Instruction[] newSuccs) {
Instruction newInstr = appendInstruction(opc);
if (newSuccs != null)
newInstr.setSuccs(newSuccs);
return newInstr;
}
/**
* Removes this instruction (as if it would be replaced by a nop).
*/
public void removeInstruction() {
/* remove from chained list */
if (prevByAddr != null)
codeinfo.instructionCount--;
/* remove from chained list and adjust addr / length */
if (prevByAddr != null) {
prevByAddr.nextByAddr = nextByAddr;
else
prevByAddr.length += length;
} else {
if (nextByAddr == null)
/* Mustn't happen, each method must include a return */
throw new IllegalArgumentException
("Removing the last instruction of a method!");
codeinfo.firstInstr = nextByAddr;
nextByAddr.addr = 0;
nextByAddr.length += length;
}
if (nextByAddr != null)
nextByAddr.prevByAddr = prevByAddr;
@ -208,16 +451,7 @@ public class Instruction implements Opcodes{
/* adjust exception handlers */
Handler[] handlers = codeinfo.getExceptionHandlers();
for (int i=0; i< handlers.length; i++) {
if (handlers[i].start == this)
handlers[i].start = nextByAddr;
if (handlers[i].end == this)
handlers[i].end = prevByAddr;
if (handlers[i].catcher == this)
handlers[i].catcher = nextByAddr;
if (handlers[i].start == null
|| handlers[i].end == null
|| handlers[i].end.nextByAddr == handlers[i].start) {
if (handlers[i].start == this && handlers[i].end == this) {
/* Remove the handler.
* This is very seldom, so we can make it slow */
Handler[] newHandlers = new Handler[handlers.length - 1];
@ -227,6 +461,13 @@ public class Instruction implements Opcodes{
handlers = newHandlers;
codeinfo.setExceptionHandlers(newHandlers);
i--;
} else {
if (handlers[i].start == this)
handlers[i].start = nextByAddr;
if (handlers[i].end == this)
handlers[i].end = prevByAddr;
if (handlers[i].catcher == this)
handlers[i].catcher = nextByAddr;
}
}
@ -234,15 +475,10 @@ public class Instruction implements Opcodes{
LocalVariableInfo[] lvt = codeinfo.getLocalVariableTable();
if (lvt != null) {
for (int i=0; i< lvt.length; i++) {
if (lvt[i].start == this)
lvt[i].start = nextByAddr;
if (lvt[i].end == this)
lvt[i].end = prevByAddr;
if (lvt[i].start == null
|| lvt[i].end == null
|| lvt[i].end.nextByAddr == lvt[i].start) {
if (lvt[i].start == this && lvt[i].end == this) {
/* Remove the local variable info.
* This is very seldom, so we can make it slow */
* This is very seldom, so we can make it slow
*/
LocalVariableInfo[] newLVT =
new LocalVariableInfo[lvt.length - 1];
System.arraycopy(lvt, 0, newLVT, 0, i);
@ -251,26 +487,33 @@ public class Instruction implements Opcodes{
lvt = newLVT;
codeinfo.setLocalVariableTable(newLVT);
i--;
} else {
if (lvt[i].start == this)
lvt[i].start = nextByAddr;
if (lvt[i].end == this)
lvt[i].end = prevByAddr;
}
}
}
LineNumber[] lnt = codeinfo.getLineNumberTable();
if (lnt != null) {
for (int i=0; i< lnt.length; i++) {
if (lnt[i].start == this)
lnt[i].start = nextByAddr;
if (lnt[i].start == null
|| (i+1 < lnt.length && lnt[i].start == lnt[i+1].start)) {
/* Remove the line number.
* This is very seldom, so we can make it slow */
LineNumber[] newLNT =
new LineNumber[lnt.length - 1];
System.arraycopy(lnt, 0, newLNT, 0, i);
System.arraycopy(lnt, i+1, newLNT, i,
newLNT.length - i);
lnt = newLNT;
codeinfo.setLineNumberTable(newLNT);
i--;
if (lnt[i].start == this) {
if (nextByAddr == null
|| (i+1 < lnt.length
&& lnt[i+1].start == nextByAddr)) {
/* Remove the line number.
* This is very seldom, so we can make it slow */
LineNumber[] newLNT =
new LineNumber[lnt.length - 1];
System.arraycopy(lnt, 0, newLNT, 0, i);
System.arraycopy(lnt, i+1, newLNT, i,
newLNT.length - i);
lnt = newLNT;
codeinfo.setLineNumberTable(newLNT);
i--;
} else
lnt[i].start = nextByAddr;
}
}
}
@ -285,10 +528,10 @@ public class Instruction implements Opcodes{
* get the number of pops, the second the number of pushes.
*/
public void getStackPopPush(int[] poppush)
/*{ require { poppush != null && poppush.length == 2
:: "poppush must be an array of two ints" } } */
/*{ require { poppush != null && poppush.length == 2
:: "poppush must be an array of two ints" } } */
{
byte delta = stackDelta[opcode];
byte delta = (byte) stackDelta.charAt(opcode);
if (delta < 0x40) {
poppush[0] = delta & 7;
poppush[1] = delta >> 3;
@ -299,12 +542,10 @@ public class Instruction implements Opcodes{
case opc_invokestatic:
case opc_invokeinterface: {
Reference ref = (Reference) objData;
MethodType mt = (MethodType) Type.tType(ref.getType());
poppush[1] = mt.getReturnType().stackSize();
String typeSig = ref.getType();
poppush[0] = opcode != opc_invokestatic ? 1 : 0;
for (int i = mt.getParameterTypes().length-1; i >= 0; i--)
poppush[0] += mt.getParameterTypes()[i].stackSize();
poppush[0] += TypeSignature.getArgumentSize(typeSig);
poppush[1] = TypeSignature.getReturnSize(typeSig);
break;
}
@ -312,7 +553,7 @@ public class Instruction implements Opcodes{
case opc_putstatic: {
Reference ref = (Reference) objData;
poppush[1] = 0;
poppush[0] = Type.tType(ref.getType()).stackSize();
poppush[0] = TypeSignature.getTypeSize(ref.getType());
if (opcode == opc_putfield)
poppush[0]++;
break;
@ -320,7 +561,7 @@ public class Instruction implements Opcodes{
case opc_getstatic:
case opc_getfield: {
Reference ref = (Reference) objData;
poppush[1] = Type.tType(ref.getType()).stackSize();
poppush[1] = TypeSignature.getTypeSize(ref.getType());
poppush[0] = opcode == opc_getfield ? 1 : 0;
break;
}
@ -343,7 +584,7 @@ public class Instruction implements Opcodes{
int count = poppush[1];
Instruction instr = this;
while (true) {
if (instr.succs != null || instr.alwaysJumps)
if (instr.succs != null || instr.doesAlwaysJump())
return null;
instr = instr.nextByAddr;
if (instr.preds != null)
@ -364,7 +605,7 @@ public class Instruction implements Opcodes{
if (instr.preds != null)
return null;
instr = instr.prevByAddr;
if (instr == null || instr.succs != null || instr.alwaysJumps)
if (instr == null || instr.succs != null || instr.doesAlwaysJump())
return null;
instr.getStackPopPush(poppush);
@ -379,16 +620,13 @@ public class Instruction implements Opcodes{
StringBuffer result = new StringBuffer(String.valueOf(addr))
.append('_').append(Integer.toHexString(hashCode()))
.append(": ").append(opcodeString[opcode]);
switch (opcode) {
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
case opc_ret:
if (localSlot != -1)
result.append(" ").append(localSlot);
break;
if (succs != null && succs.length == 1)
result.append(" ").append(succs[0].addr);
switch (opcode) {
case opc_iinc:
result.append(" ").append(localSlot).append(" ").append(intData);
result.append(" ").append(intData);
break;
case opc_ldc: case opc_ldc2_w:
case opc_getstatic: case opc_getfield:
@ -399,42 +637,20 @@ public class Instruction implements Opcodes{
case opc_instanceof:
result.append(" ").append(objData);
break;
case opc_anewarray:
case opc_newarray:
result.append(" ").append(((String)objData).substring(1));
break;
case opc_multianewarray:
case opc_invokeinterface:
result.append(" ").append(objData).append(" ").append(intData);
break;
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull:
case opc_goto:
case opc_jsr:
result.append(" ").append(succs[0].addr);
break;
}
return result.toString();
}
public String toString() {
return ""+addr+"_"+Integer.toHexString(hashCode());
return "" + addr + "_" + Integer.toHexString(hashCode());
}
public final static byte[] stackDelta;
static {
stackDelta = new byte[202];
for (int i=0; i < 202; i++) {
stackDelta[i] = (byte) "\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\010\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\010".charAt(i);
}
}
private final static String stackDelta =
"\000\010\010\010\010\010\010\010\010\020\020\010\010\010\020\020\010\010\010\010\020\010\020\010\020\010\010\010\010\010\020\020\020\020\010\010\010\010\020\020\020\020\010\010\010\010\012\022\012\022\012\012\012\012\001\002\001\002\001\001\001\001\001\002\002\002\002\001\001\001\001\002\002\002\002\001\001\001\001\003\004\003\004\003\003\003\003\001\002\021\032\043\042\053\064\022\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\012\024\011\022\011\022\012\023\012\023\012\023\012\024\012\024\012\024\000\021\011\021\012\012\022\011\021\021\012\022\012\011\011\011\014\012\012\014\014\001\001\001\001\001\001\002\002\002\002\002\002\002\002\000\010\000\001\001\001\002\001\002\001\000\100\100\100\100\100\100\100\100\177\010\011\011\011\001\011\011\001\001\177\100\001\001\000\010";
/* stackDelta contains \100 if stack count of opcode is variable
* \177 if opcode is illegal, or 8*stack_push + stack_pop otherwise

@ -18,7 +18,9 @@
*/
package jode.bytecode;
import java.io.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
public class MethodInfo extends BinaryInfo {

@ -21,8 +21,10 @@ package jode.bytecode;
///#ifdef JDK12
///import java.lang.ref.WeakReference;
///import java.lang.ref.ReferenceQueue;
///import java.lang.ref.HashMap;
///#else
import java.util.Hashtable;
///#endif
import java.util.*;
/**
* This class represents a field or method reference.

@ -18,10 +18,23 @@
*/
package jode.bytecode;
import java.io.*;
import java.net.*;
import java.util.zip.*;
import java.util.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import jode.GlobalOptions;
/**

@ -0,0 +1,196 @@
package jode.bytecode;
import jode.AssertError;
/**
* This class contains some static methods to handle type signatures.
*/
public class TypeSignature {
/**
* This is a private method for generating the signature of a
* given type.
*/
private static final StringBuffer appendSignature(StringBuffer sb,
Class javaType) {
if (javaType.isPrimitive()) {
if (javaType == Boolean.TYPE)
return sb.append('Z');
else if (javaType == Byte.TYPE)
return sb.append('B');
else if (javaType == Character.TYPE)
return sb.append('C');
else if (javaType == Short.TYPE)
return sb.append('S');
else if (javaType == Integer.TYPE)
return sb.append('I');
else if (javaType == Long.TYPE)
return sb.append('J');
else if (javaType == Float.TYPE)
return sb.append('F');
else if (javaType == Double.TYPE)
return sb.append('D');
else if (javaType == Void.TYPE)
return sb.append('V');
else
throw new AssertError("Unknown primitive type: "+javaType);
} else if (javaType.isArray()) {
return appendSignature(sb.append('['),
javaType.getComponentType());
} else {
return sb.append('L')
.append(javaType.getName().replace('.','/')).append(';');
}
}
/**
* Generate the signature for the given Class.
* @param clazz a java.lang.Class, this may also be a primitive or
* array type.
* @return the type signature (see section 4.3.2 Field Descriptors
* of the JVM specification)
*/
public static String getSignature(Class clazz) {
return appendSignature(new StringBuffer(), clazz).toString();
}
/**
* Generate a method signature.
* @param paramT the java.lang.Class of the parameter types of the method.
* @param returnT the java.lang.Class of the return type of the method.
* @return the method signature (see section 4.3.3 Method Descriptors
* of the JVM specification)
*/
public static String getSignature(Class paramT[], Class returnT) {
StringBuffer sig = new StringBuffer("(");
for (int i=0; i< paramT.length; i++)
appendSignature(sig, paramT[i]);
return appendSignature(sig.append(')'), returnT).toString();
}
/**
* Check if the given type is a two slot type.
*/
private static boolean usingTwoSlots(char type) {
return "JD".indexOf(type) >= 0;
}
/**
* Returns the number of words, an object of the given simple type
* signature takes.
*/
public static int getTypeSize(String typeSig) {
return usingTwoSlots(typeSig.charAt(0)) ? 2 : 1;
}
/**
* Returns the number of words, the arguments for the given method
* type signature takes.
*/
public static int getArgumentSize(String methodTypeSig) {
int nargs = 0;
int i = 1;
for (;;) {
char c = methodTypeSig.charAt(i++);
if (c == ')')
return nargs;
if (usingTwoSlots(c))
nargs += 2;
else {
while (c == '[')
c = methodTypeSig.charAt(i++);
if (c == 'L')
i = methodTypeSig.indexOf(';', i) + 1;
nargs++;
}
}
}
/**
* Returns the number of words, an object of the given simple type
* signature takes.
*/
public static int getReturnSize(String methodTypeSig) {
char returnType = methodTypeSig.charAt(methodTypeSig.indexOf(')')+1);
return returnType == 'V' ? 0
: usingTwoSlots(returnType) ? 2 : 1;
}
private static void checkClassName(String clName)
throws IllegalArgumentException
{
boolean start = true;
for (int i=0; i< clName.length(); i++) {
char c = clName.charAt(i);
if (c == '/')
start = true;
else if (start && Character.isJavaIdentifierStart(c))
start = false;
else if ((start && false /*XXX*/)
|| !Character.isJavaIdentifierPart(c))
throw new IllegalArgumentException("Illegal java class name: "
+ clName);
}
}
/**
* Check if there is a valid simple type signature starting at index
* in string typesig.
* @return the index at which the type signature ends.
* @exception IllegalArgumentException if there was an illegal character.
* @exception StringIndexOutOfBoundsException if the typesig ended early.
*/
private static int checkTypeSig(String typesig, int index) {
char c = typesig.charAt(index++);
while (c == '[')
c = typesig.charAt(index++);
if (c == 'L') {
int end = typesig.indexOf(';', index);
// next instruction throws StringIndexOutOfBounds, if no ; exists.
checkClassName(typesig.substring(index+1, end));
index = end + 1;
} else {
if ("ZBSCIJFD".indexOf(c) == -1)
throw new IllegalArgumentException("Type sig error: "+typesig);
}
return index;
}
public static void checkTypeSig(String typesig)
throws IllegalArgumentException
{
try {
if (checkTypeSig(typesig, 0) != typesig.length())
throw new IllegalArgumentException
("Type sig too long: "+typesig);
} catch (StringIndexOutOfBoundsException ex) {
throw new IllegalArgumentException
("Incomplete type sig: "+typesig);
}
}
public static void checkMethodTypeSig(String typesig)
throws IllegalArgumentException
{
try {
if (typesig.charAt(0) != '(')
throw new IllegalArgumentException
("No method signature: "+typesig);
int i = 1;
while (typesig.charAt(i) != ')')
i = checkTypeSig(typesig, i);
// skip closing parenthesis.
i++;
if (typesig.charAt(i) == 'V')
// accept void return type.
i++;
else
i = checkTypeSig(typesig, i);
if (i != typesig.length())
throw new IllegalArgumentException
("Type sig too long: "+typesig);
} catch (StringIndexOutOfBoundsException ex) {
throw new IllegalArgumentException
("Incomplete type sig: "+typesig);
}
}
}
Loading…
Cancel
Save