Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/jode/decompiler/CodeAnalyzer.java

1016 lines
40 KiB

package jode;
import sun.tools.java.*;
import java.lang.reflect.Modifier;
import java.util.*;
import java.io.*;
public class CodeAnalyzer implements Analyzer, Constants, Opcodes {
MethodAnalyzer method;
JodeEnvironment env;
BinaryCode bincode;
Instruction[] instr;
int[] references;
Hashtable tryAddrs = new Hashtable();
Hashtable catchAddrs = new Hashtable();
Hashtable labels = new Hashtable();
public void readOpcodes(DataInputStream stream)
throws IOException, ClassFormatError
{
int addr = 0;
try {
while (true) {
int opcode;
try {
opcode = stream.readUnsignedByte();
} catch (EOFException eof) {
break;
}
switch (opcode) {
case NOP_OP:
instr[addr] = new NopOperator(addr, 1);
break;
case ACONST_NULL_OP:
instr[addr] = new ConstOperator(addr, 1, OBJECT_TYPE, "null");
break;
case ICONST_M1_OP:
case ICONST_0_OP: case ICONST_1_OP: case ICONST_2_OP:
case ICONST_3_OP: case ICONST_4_OP: case ICONST_5_OP:
instr[addr] =
new ConstOperator(addr, 1, ALL_INT_TYPE,
Integer.toString(opcode - ICONST_0_OP));
break;
case LCONST_0_OP: case LCONST_1_OP:
instr[addr] =
new ConstOperator(addr, 1, LONG_TYPE,
Integer.toString(opcode - LCONST_0_OP)+
"L");
break;
case FCONST_0_OP: case FCONST_1_OP: case FCONST_2_OP:
instr[addr] =
new ConstOperator(addr, 1, FLOAT_TYPE,
Integer.toString(opcode - FCONST_0_OP)+
".0F");
break;
case DCONST_0_OP: case DCONST_1_OP:
instr[addr] =
new ConstOperator(addr, 1, DOUBLE_TYPE,
Integer.toString(opcode - DCONST_0_OP)+
".0");
break;
case BIPUSH_OP:
instr[addr] =
new ConstOperator(addr, 2, ALL_INT_TYPE,
Integer.toString(stream.readByte()));
break;
case SIPUSH_OP:
instr[addr] =
new ConstOperator(addr, 3, ALL_INT_TYPE,
Integer.toString(stream.readShort()));
break;
case LDC_OP: {
int index = stream.readUnsignedByte();
instr[addr] =
new ConstOperator(addr, 2, env.getConstantType(index),
env.getConstant(index).toString());
break;
}
case LDC_W_OP:
case LDC2_W_OP: {
int index = stream.readUnsignedShort();
instr[addr] =
new ConstOperator(addr, 3, env.getConstantType(index),
env.getConstant(index).toString());
break;
}
case ILOAD_OP: case LLOAD_OP:
case FLOAD_OP: case DLOAD_OP: case ALOAD_OP:
instr[addr] =
new LoadOperator(addr, 2, types[0][opcode-ILOAD_OP],
method.getLocal(stream.readUnsignedByte()));
break;
case ILOAD_0_OP: case ILOAD_1_OP: case ILOAD_2_OP: case ILOAD_3_OP:
case LLOAD_0_OP: case LLOAD_1_OP: case LLOAD_2_OP: case LLOAD_3_OP:
case FLOAD_0_OP: case FLOAD_1_OP: case FLOAD_2_OP: case FLOAD_3_OP:
case DLOAD_0_OP: case DLOAD_1_OP: case DLOAD_2_OP: case DLOAD_3_OP:
case ALOAD_0_OP: case ALOAD_1_OP: case ALOAD_2_OP: case ALOAD_3_OP:
instr[addr] =
new LoadOperator(addr, 1, types[0][(opcode-ILOAD_0_OP)/4],
method.getLocal((opcode-ILOAD_0_OP) & 3));
break;
case IALOAD_OP: case LALOAD_OP:
case FALOAD_OP: case DALOAD_OP: case AALOAD_OP:
case BALOAD_OP: case CALOAD_OP: case SALOAD_OP:
instr[addr] =
new ArrayLoadOperator(addr, 1, types[1][opcode - IALOAD_OP]);
break;
case ISTORE_OP: case LSTORE_OP:
case FSTORE_OP: case DSTORE_OP: case ASTORE_OP:
instr[addr] =
new StoreOperator(addr, 2, types[0][opcode-ISTORE_OP],
method.getLocal(stream.readUnsignedByte()),
Operator.ASSIGN_OP);
break;
case ISTORE_0_OP: case ISTORE_1_OP:
case ISTORE_2_OP: case ISTORE_3_OP:
case LSTORE_0_OP: case LSTORE_1_OP:
case LSTORE_2_OP: case LSTORE_3_OP:
case FSTORE_0_OP: case FSTORE_1_OP:
case FSTORE_2_OP: case FSTORE_3_OP:
case DSTORE_0_OP: case DSTORE_1_OP:
case DSTORE_2_OP: case DSTORE_3_OP:
case ASTORE_0_OP: case ASTORE_1_OP:
case ASTORE_2_OP: case ASTORE_3_OP:
instr[addr] =
new StoreOperator(addr, 1, types[0][(opcode-ISTORE_0_OP)/4],
method.getLocal((opcode-ISTORE_0_OP) & 3),
Operator.ASSIGN_OP);
break;
case IASTORE_OP: case LASTORE_OP:
case FASTORE_OP: case DASTORE_OP: case AASTORE_OP:
case BASTORE_OP: case CASTORE_OP: case SASTORE_OP:
instr[addr] =
new ArrayStoreOperator(addr, 1,
types[1][opcode - IASTORE_OP]);
break;
case POP_OP: case POP2_OP:
instr[addr] =
new PopOperator(addr, 1, opcode - POP_OP + 1);
break;
case DUP_OP: case DUP_X1_OP: case DUP_X2_OP:
case DUP2_OP: case DUP2_X1_OP: case DUP2_X2_OP:
instr[addr] =
new DupOperator(addr, 1,
(opcode - DUP_OP)%3,
(opcode - DUP_OP)/3+1);
break;
case SWAP_OP:
instr[addr] = new SwapOperator(addr, 1);
break;
case IADD_OP: case LADD_OP: case FADD_OP: case DADD_OP:
case ISUB_OP: case LSUB_OP: case FSUB_OP: case DSUB_OP:
case IMUL_OP: case LMUL_OP: case FMUL_OP: case DMUL_OP:
case IDIV_OP: case LDIV_OP: case FDIV_OP: case DDIV_OP:
case IREM_OP: case LREM_OP: case FREM_OP: case DREM_OP:
instr[addr] =
new BinaryOperator(addr, 1, types[0][(opcode - IADD_OP)%4],
(opcode - IADD_OP)/4+Operator.ADD_OP);
break;
case INEG_OP: case LNEG_OP: case FNEG_OP: case DNEG_OP:
instr[addr] =
new UnaryOperator(addr, 1, types[0][opcode - INEG_OP],
Operator.NEG_OP);
break;
case ISHL_OP: case LSHL_OP:
case ISHR_OP: case LSHR_OP:
case IUSHR_OP: case LUSHR_OP:
instr[addr] = new ShiftOperator(addr, 1,
types[0][(opcode - ISHL_OP)%2],
(opcode - ISHL_OP)/2 +
Operator.SHIFT_OP);
break;
case IAND_OP: case LAND_OP:
case IOR_OP : case LOR_OP :
case IXOR_OP: case LXOR_OP:
instr[addr] = new BinaryOperator(addr, 1,
types[0][(opcode - ISHL_OP)%2],
(opcode - ISHL_OP)/2 +
Operator.SHIFT_OP);
break;
case IINC_OP: {
int local = stream.readUnsignedByte();
int value = stream.readUnsignedByte();
int operation = Operator.ADD_OP;
if (value < 0) {
value = -value;
operation = Operator.NEG_OP;
}
instr[addr] = new ConstOperator(addr, 1, ALL_INT_TYPE,
Integer.toString(value));
instr[addr+1] =
new StoreOperator(addr+1, 2, ALL_INT_TYPE,
method.getLocal(local),
operation + Operator.OPASSIGN_OP);
addr++;
}
break;
case I2L_OP: case I2F_OP: case I2D_OP:
case L2I_OP: case L2F_OP: case L2D_OP:
case F2I_OP: case F2L_OP: case F2D_OP:
case D2I_OP: case D2L_OP: case D2F_OP: {
int from = (opcode-I2L_OP)/3;
int to = (opcode-I2L_OP)%3;
if (to >= from)
to++;
instr[addr] = new ConvertOperator(addr, 1, types[0][from],
types[1][to]);
break;
}
case I2B_OP: case I2C_OP: case I2S_OP:
instr[addr] = new ConvertOperator(addr, 1, ALL_INT_TYPE,
types[1][(opcode-I2B_OP)+5]);
break;
case LCMP_OP:
case FCMPL_OP: case FCMPG_OP:
case DCMPL_OP: case DCMPG_OP:
instr[addr] = new CompareToIntOperator
(addr, 1, types[0][(opcode-LCMP_OP+3)/2],
(opcode-LCMP_OP+3)%2);
break;
case IFEQ_OP: case IFNE_OP:
case IFLT_OP: case IFGE_OP: case IFGT_OP: case IFLE_OP: {
instr[addr] = new CompareUnaryOperator
(addr, 1, ALL_INT_TYPE,
opcode - IFEQ_OP+Operator.COMPARE_OP);
instr[addr+1] = new IfGotoOperator(addr+1, 2,
addr+stream.readShort());
addr++;
break;
}
case IF_ICMPEQ_OP: case IF_ICMPNE_OP: case IF_ICMPLT_OP:
case IF_ICMPGE_OP: case IF_ICMPGT_OP: case IF_ICMPLE_OP:
instr[addr] = new CompareBinaryOperator
(addr, 1, ALL_INT_TYPE,
opcode - IF_ICMPEQ_OP+Operator.COMPARE_OP);
instr[addr+1] = new IfGotoOperator(addr+1, 2,
addr+stream.readShort());
addr++;
break;
case IF_ACMPEQ_OP: case IF_ACMPNE_OP:
instr[addr] = new CompareBinaryOperator
(addr, 1, OBJECT_TYPE,
opcode - IF_ACMPEQ_OP+Operator.COMPARE_OP);
instr[addr+1] = new IfGotoOperator(addr+1, 2,
addr+stream.readShort());
addr++;
break;
case GOTO_OP:
instr[addr] = new GotoOperator(addr, 3, addr+stream.readShort());
break;
case JSR_OP:
instr[addr] = new JsrOperator(addr, 3, addr+stream.readShort());
break;
case RET_OP:
instr[addr] = new RetOperator(addr, 3, stream.readUnsignedByte());
break;
case TABLESWITCH_OP: {
int length = 3-(addr % 4);
stream.skip(length);
int def = addr + stream.readInt();
int low = stream.readInt();
int high = stream.readInt();
int[] cases = new int[high-low+1];
int[] dests = new int[high-low+2];
for (int i=0; i+low <= high; i++) {
cases[i] = i+low;
dests[i] = addr + stream.readInt();
}
dests[cases.length] = def;
length += 13 + 4 * cases.length;
instr[addr] = new SwitchOperator(addr, length, cases, dests);
break;
}
case LOOKUPSWITCH_OP: {
int length = 3-(addr % 4);
stream.skip(length);
int def = addr + stream.readInt();
int npairs = stream.readInt();
int[] cases = new int[npairs];
int[] dests = new int[npairs+1];
for (int i=0; i < npairs; i++) {
cases[i] = stream.readInt();
dests[i] = addr + stream.readInt();
}
dests[npairs] = def;
length += 9 + 8 * npairs;
instr[addr] = new SwitchOperator(addr, length, cases, dests);
break;
}
case IRETURN_OP: case LRETURN_OP:
case FRETURN_OP: case DRETURN_OP: case ARETURN_OP: {
Type retType = UnknownType.commonType
(method.mdef.getType().getReturnType(),
types[0][opcode-IRETURN_OP]);
instr[addr] =
new ReturnOperator(addr, 1, retType);
break;
}
case RETURN_OP:
instr[addr] = new ReturnOperator(addr, 1, Type.tVoid);
break;
case GETSTATIC_OP:
instr[addr] =
new GetFieldOperator(addr, 3, true,
(FieldDefinition)env.getConstant
(stream.readUnsignedShort()));
break;
case PUTSTATIC_OP:
instr[addr] =
new PutFieldOperator(addr, 3, true,
(FieldDefinition)env.getConstant
(stream.readUnsignedShort()));
break;
case GETFIELD_OP:
instr[addr] = new GetFieldOperator(addr, 3, false,
(FieldDefinition)env.getConstant
(stream.readUnsignedShort()));
break;
case PUTFIELD_OP:
instr[addr] =
new PutFieldOperator(addr, 3, false,
(FieldDefinition)env.getConstant
(stream.readUnsignedShort()));
break;
case INVOKEVIRTUAL_OP:
case INVOKESPECIAL_OP:
case INVOKESTATIC_OP :
instr[addr] = new InvokeOperator(addr, 3,
opcode == INVOKESTATIC_OP,
opcode == INVOKESPECIAL_OP,
(FieldDefinition)env.getConstant
(stream.readUnsignedShort()));
break;
case INVOKEINTERFACE_OP: {
instr[addr] = new InvokeOperator(addr, 5,
false, false,
(FieldDefinition)env.getConstant
(stream.readUnsignedShort()));
int reserved = stream.readUnsignedShort();
break;
}
case NEW_OP: {
ClassDeclaration cldec = (ClassDeclaration)
env.getConstant(stream.readUnsignedShort());
instr[addr] = new NewOperator(addr, 3,
Type.tClass(cldec.getName()));
break;
}
case NEWARRAY_OP: {
Type type;
switch (stream.readUnsignedByte()) {
case 4: type = Type.tBoolean; break;
case 5: type = Type.tChar ; break;
case 6: type = Type.tFloat ; break;
case 7: type = Type.tDouble ; break;
case 8: type = Type.tByte ; break;
case 9: type = Type.tShort ; break;
case 10: type = Type.tInt ; break;
case 11: type = Type.tLong ; break;
default:
throw new ClassFormatError("Invalid newarray operand");
}
instr[addr] = new NewArrayOperator(addr, 2, type);
break;
}
case ANEWARRAY_OP: {
ClassDeclaration cldec = (ClassDeclaration) env.getConstant
(stream.readUnsignedShort());
instr[addr] = new NewArrayOperator
(addr, 3, Type.tClass(cldec.getName()));
break;
}
case ARRAYLENGTH_OP:
instr[addr] = new ArrayLengthOperator(addr, 1);
break;
case ATHROW_OP:
instr[addr] = new ThrowOperator(addr, 1);
break;
case CHECKCAST_OP: {
ClassDeclaration cldec = (ClassDeclaration) env.getConstant
(stream.readUnsignedShort());
instr[addr] = new CheckCastOperator
(addr, 3, Type.tClass(cldec.getName()));
break;
}
case INSTANCEOF_OP: {
ClassDeclaration cldec = (ClassDeclaration) env.getConstant
(stream.readUnsignedShort());
instr[addr] = new InstanceOfOperator
(addr, 3, Type.tClass(cldec.getName()));
break;
}
case MONITORENTER_OP:
instr[addr] = new MonitorEnterOperator(addr, 1);
break;
case MONITOREXIT_OP:
instr[addr] = new MonitorExitOperator(addr, 1);
break;
case WIDE_OP: {
switch (opcode=stream.readUnsignedByte()) {
case ILOAD_OP: case LLOAD_OP:
case FLOAD_OP: case DLOAD_OP: case ALOAD_OP:
instr[addr] = new LoadOperator(addr, 3,
types[0][opcode-ILOAD_OP],
method.getLocal
(stream.readUnsignedShort()));
break;
case ISTORE_OP: case LSTORE_OP:
case FSTORE_OP: case DSTORE_OP: case ASTORE_OP:
instr[addr] = new StoreOperator(addr, 3,
types[0][opcode-ISTORE_OP],
method.getLocal
(stream.readUnsignedShort()),
Operator.ASSIGN_OP);
break;
case IINC_OP: {
int local = stream.readUnsignedShort();
int value = stream.readUnsignedShort();
int operation = Operator.ADD_OP;
if (value < 0) {
value = -value;
operation = Operator.NEG_OP;
}
instr[addr] = new ConstOperator(addr, 1, ALL_INT_TYPE,
Integer.toString(value));
instr[addr+1] =
new StoreOperator(addr+1, 4, ALL_INT_TYPE,
method.getLocal(local),
operation + Operator.OPASSIGN_OP);
addr++;
break;
}
case RET_OP:
instr[addr] =
new RetOperator(addr, 3, stream.readUnsignedShort());
break;
default:
throw new ClassFormatError("Invalid wide opcode "+opcode);
}
break;
}
case MULTIANEWARRAY_OP: {
ClassDeclaration cldec = (ClassDeclaration) env.getConstant
(stream.readUnsignedShort());
int dimension = stream.readUnsignedByte();
instr[addr] = new NewArrayOperator
(addr, 3, Type.tClass(cldec.getName()), dimension);
break;
}
case IFNULL_OP: case IFNONNULL_OP:
instr[addr] = new CompareUnaryOperator
(addr, 1, OBJECT_TYPE,
opcode - IFNULL_OP + Operator.COMPARE_OP);
instr[addr+1] = new IfGotoOperator(addr+1, 2,
addr+stream.readShort());
addr++;
break;
case GOTO_W_OP:
instr[addr] = new GotoOperator(addr, 5, addr + stream.readInt());
break;
case JSR_W_OP:
instr[addr] = new JsrOperator(addr, 5, addr + stream.readInt());
break;
default:
throw new ClassFormatError("Invalid opcode "+opcode);
}
addr += instr[addr].getLength();
if (stream.available() != instr.length-addr) {
throw new RuntimeException("invalid op size: "+opcode);
}
}
} catch (ClassCastException ex) {
ex.printStackTrace();
throw new ClassFormatError("Constant has wrong type");
}
}
void readCode(byte[] code)
throws ClassFormatError
{
instr = new Instruction[code.length];
references = new int[code.length];
try {
DataInputStream stream =
new DataInputStream(new ByteArrayInputStream(code));
readOpcodes(stream);
} catch (IOException ex) {
throw new ClassFormatError(ex.toString());
}
references[0]++;
for (int addr = 0; addr < code.length;
addr += instr[addr].getLength()) {
int[] successors = instr[addr].getSuccessors();
for (int i=0; i < successors.length; i++) {
references[successors[i]]++;
}
}
}
void setExceptionHandler(BinaryExceptionHandler handler) {
tryAddrs.put(new Integer(handler.startPC), handler);
references[handler.startPC]++;
catchAddrs.put(new Integer(handler.handlerPC), handler);
references[handler.handlerPC]++;
}
Instruction getInstruction(int addr) {
return instr[addr];
}
void setInstruction(int addr, Instruction i) {
instr[addr] = i;
}
void removeInstruction(int addr) {
instr[addr] = null;
}
static int WRONG = -3;
static int SPECIAL = -2;
static int FIRST = -1;
int getPreviousAddr(int addr) {
int i;
for (i = addr-1; i >= 0 && instr[i] == null; i--) {}
return i;
}
int getNextAddr(int addr) {
return addr + instr[addr].getLength();
}
int getPredecessor(int addr) {
if (references[addr] != 1)
return WRONG;
if (addr == 0)
return FIRST;
if (catchAddrs.get(new Integer(addr)) != null)
return SPECIAL;
int i = getPreviousAddr(addr);
if (instr[i].getLength() != addr-i)
throw new RuntimeException("length mismatch");
int[] successors = instr[i].getSuccessors();
for (int j=0; j< successors.length; j++) {
if (successors[j] == addr)
return i;
}
return WRONG;
}
public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException
{
int[] successors = { 0};
for (int addr = 0; addr < instr.length;) {
if (writer.verbosity > 5) {
writer.println("<"+addr + " - "+
(addr+instr[addr].getLength()-1)+
"> ["+references[addr]+"] : "+
instr[addr].getClass().getName());
writer.tab();
}
int i;
for (i=0; i< successors.length && successors[i] != addr; i++)
{}
if (references[addr] != 1 || i == successors.length)
writer.print("addr_"+addr+": ");
instr[addr].dumpSource(writer, this);
if (writer.verbosity > 5)
writer.untab();
successors = instr[addr].getSuccessors();
for (i = instr[addr++].getLength()-1; i>0; i--)
if (instr[addr++] != null)
throw new AssertError ("dubious instr at addr "+addr);
}
}
public CodeAnalyzer(MethodAnalyzer ma, BinaryCode bc, JodeEnvironment e)
throws ClassFormatError
{
method = ma;
env = e;
readCode(bincode.getCode());
BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers();
for (int i=0; i<handlers.length; i++) {
setExceptionHandler(handlers[i]);
}
}
public int createExpression(int addr) {
try {
Operator op = (Operator) instr[addr];
int length = instr[addr].getLength();
int params = op.getOperandCount();
Expression exprs[] = new Expression[params];
int addrs[] = new int[params+1];
addrs[params] = addr;
for (int i = params-1; i>=0; i--) {
addrs[i] = getPredecessor(addrs[i+1]);
if (addrs[i] < 0)
return -1;
exprs[i] = (Expression) instr[addrs[i]];
if (exprs[i].isVoid())
return -1;
}
length += addrs[params]-addrs[0];
for (int i = 1; i <= params; i++) {
instr[addrs[i]] = null;
}
addr = addrs[0];
instr[addr] = new Expression(addr, length, op, exprs);
return addr;
} catch (ClassCastException ex) {
return -1;
}
}
public int combineExpressions(int addr) {
int count = 0;
int start = addr;
if (!(instr[addr] instanceof Expression) ||
!((Expression)instr[addr]).isVoid())
return -1;
do {
addr = getNextAddr(addr);
count++;
} while (addr < instr.length &&
references[addr] == 1 &&
instr[addr] instanceof Expression &&
((Expression)instr[addr]).isVoid());
Expression[] expr = new Expression[count];
addr = start;
for (int i=0; i < count; i++) {
expr[i] = (Expression)instr[addr];
int next = getNextAddr(addr);
instr[addr] = null;
addr = next;
}
instr[start] = new Block(start, addr-start, expr);
return start;
}
public int createAssignExpression(int addr) {
try {
StoreInstruction store = (StoreInstruction) instr[addr];
int dupAddr = getPreviousAddr(addr);
if (dupAddr < 0 || references[dupAddr] != 1)
return -1;
DupOperator dup = (DupOperator) instr[dupAddr];
if (dup.getDepth() != store.getLValueOperandCount() &&
dup.getLength() != store.getLValueType().stackSize())
return -1;
int end = getNextAddr(addr);
instr[dupAddr] = new AssignOperator(dupAddr, end-dupAddr,
Operator.ASSIGN_OP, store);
instr[addr] = null;
return dupAddr;
} catch (ClassCastException ex) {
return -1;
}
}
public int createPostIncExpression(int addr) {
try {
int op;
Expression storeExpr = (Expression) instr[addr];
StoreOperator store = (StoreOperator) storeExpr.getOperator();
if (store.getOperator() == store.ADD_OP+store.OPASSIGN_OP)
op = Operator.INC_OP;
else if (store.getOperator() == store.NEG_OP+store.OPASSIGN_OP)
op = Operator.INC_OP+1;
else
return -1;
Expression expr = storeExpr.getSubExpressions()[0];
ConstOperator constOp = (ConstOperator) expr.getOperator();
if (!constOp.getValue().equals("1"))
return -1;
int loadAddr = getPreviousAddr(addr);
if (loadAddr < 0 || references[loadAddr] != 1)
return -1;
Expression loadExpr = (Expression) instr[loadAddr];
LoadOperator load = (LoadOperator) loadExpr.getOperator();
if (load.getSlot() != store.getSlot())
return -1;
int end = getNextAddr(addr);
Operator postop =
new PostFixOperator(loadAddr, end-loadAddr,
loadExpr.getType(), op);
Expression [] exprs = { loadExpr };
instr[loadAddr] = new Expression
(loadAddr, end-loadAddr, postop, exprs);
instr[addr] = null;
return loadAddr;
} catch (ClassCastException ex) {
return -1;
}
}
public int createArrayOpAssign(int addr) {
try {
StoreInstruction store = (StoreInstruction) instr[addr];
int binOpAddr = getPreviousAddr(addr);
if (binOpAddr < 0 || references[binOpAddr] != 1)
return -1;
BinaryOperator binop = (BinaryOperator) instr[binOpAddr];
if (binop.getOperator() < binop.ADD_OP ||
binop.getOperator() >= binop.ASSIGN_OP)
return -1;
int exprAddr = getPreviousAddr(binOpAddr);
if (exprAddr < 0 || references[exprAddr] != 1)
return -1;
Expression expr = (Expression) instr[exprAddr];
int loadAddr = getPreviousAddr(exprAddr);
if (loadAddr < 0 || references[loadAddr] != 1)
return -1;
Operator load =
(Operator) instr[loadAddr];
if (load.getType() != store.getLValueType())
return -1;
if (!store.matches(load))
return -1;
int dupAddr = getPreviousAddr(loadAddr);
if (dupAddr < 0)
return -1;
DupOperator dup = (DupOperator) instr[dupAddr];
if (dup.getDepth() != 0 &&
dup.getLength() != store.getLValueOperandCount())
return -1;
int end = getNextAddr(addr);
instr[dupAddr] = new Expression
(dupAddr, binOpAddr-dupAddr,
expr.getOperator(), expr.getSubExpressions());
instr[binOpAddr] = store;
store.setAddr(binOpAddr);
store.setLength(end-binOpAddr);
store.setOperator(store.OPASSIGN_OP+binop.getOperator());
store.setLValueType
(UnknownType.commonType(binop.getType(),
store.getLValueType()));
instr[loadAddr] = instr[exprAddr] =
instr[addr] = null;
return dupAddr;
} catch (ClassCastException ex) {
return -1;
}
}
public int combineNewConstructor(int addr) {
try {
InvokeOperator constrCall = (InvokeOperator) instr[addr];
if (!constrCall.isConstructor())
return -1;
int length = instr[addr].getLength();
int params = constrCall.getOperandCount();
Expression exprs[] = new Expression[params];
int addrs[] = new int[params+1];
addrs[params] = addr;
for (int i = params-1; i>0; i--) {
addrs[i] = getPredecessor(addrs[i+1]);
if (addrs[i] < 0)
return -1;
exprs[i] = (Expression) instr[addrs[i]];
if (exprs[i].isVoid())
return -1;
}
addrs[0] = getPredecessor(addrs[1]);
DupOperator dup = (DupOperator) instr[addrs[0]];
if (dup.getCount() != 1 && dup.getDepth() != 0)
return -1;
addr = getPredecessor(addrs[0]);
exprs[0] = (Expression) instr[addr];
if (exprs[0].isVoid())
return -1;
NewOperator op = (NewOperator) exprs[0].getOperator();
if (constrCall.getClassType() != op.getType())
return -1;
length += addrs[params]-addr;
for (int i = 0; i <= params; i++) {
instr[addrs[i]] = null;
}
ConstructorOperator conOp =
new ConstructorOperator(addr, length,
constrCall.getClassType(),
constrCall.getField());
instr[addr] = new Expression(addr, length, conOp, exprs);
return addr;
} catch (ClassCastException ex) {
return -1;
}
}
// public int createIfGotoStatement(int addr) {
// if (references[addr] != 1)
// return -1;
// Expression e;
// int condAddr, dest;
// try {
// IfGotoOperator igo = (IfGotoOperator) instr[addr];
// condAddr = getPreviousAddr(addr);
// if (condAddr < 0)
// return -1;
// e = (Expression) instr[condAddr];
// if (e.isVoid())
// return -1;
// dest = igo.getDestination();
// } catch (ClassCastException ex) {
// return -1;
// }
// int end = getNextAddr(addr);
// instr[condAddr] = new IfGotoStatement(condAddr, end-condAddr, dest, e);
// instr[addr] = null;
// return condAddr;
// }
public int combineIfGotoExpressions(int addr) {
Expression e[];
int if1Addr;
int end = getNextAddr(addr);
int operator;
IfGotoOperator igo2;
try {
igo2 = (IfGotoOperator)
((Expression)instr[addr]).getOperator();
int dest = igo2.getDestination();
if1Addr = getPreviousAddr(addr);
if (if1Addr < 0 || references[if1Addr] != 1)
return -1;
IfGotoOperator igo1 = (IfGotoOperator)
((Expression)instr[if1Addr]).getOperator();
if (igo1.getDestination() == end) {
e = new Expression[2];
operator = Operator.LOG_AND_OP;
e[1] = ((Expression)instr[addr]).getSubExpressions()[0];
e[0] = ((Expression)instr[if1Addr]).
getSubExpressions()[0].negate();
references[end]--;
} else if (igo1.getDestination() == dest) {
e = new Expression[2];
operator = Operator.LOG_OR_OP;
e[1] = ((Expression)instr[addr]).getSubExpressions()[0];
e[0] = ((Expression)instr[if1Addr]).getSubExpressions()[0];
references[dest]--;
} else
return -1;
} catch (ClassCastException ex) {
return -1;
}
Expression[] cond =
{ new Expression(if1Addr, end-if1Addr,
new BinaryOperator(if1Addr, end-if1Addr,
Type.tBoolean, operator), e) };
instr[if1Addr] = new Expression(if1Addr, end-if1Addr, igo2, cond);
instr[addr] = null;
return if1Addr;
}
public int combineConditionalExpr(int addr) {
if (references[addr] != 1)
return -1;
Expression e[] = new Expression[3];
int ifAddr, gotoAddr, e1Addr;
int end = getNextAddr(addr);
try {
e[2] = (Expression) instr[addr];
if (e[2].isVoid())
return -1;
gotoAddr = getPreviousAddr(addr);
if (gotoAddr < 0 || references[gotoAddr] != 1)
return -1;
if (((GotoOperator)
((Expression)instr[gotoAddr]).getOperator())
.getDestination() != end)
return -1;
e1Addr = getPreviousAddr(gotoAddr);
if (e1Addr <0 || references[e1Addr] != 1)
return -1;
e[1] = (Expression) instr[e1Addr];
if (e[1].isVoid())
return -1;
ifAddr = getPreviousAddr(e1Addr);
if (ifAddr < 0)
return -1;
e[0] = (Expression)instr[ifAddr];
IfGotoOperator igo = (IfGotoOperator) e[0].getOperator();
if (igo.getDestination() != addr)
return -1;
e[0] = e[0].getSubExpressions()[0].negate();
} catch (ClassCastException ex) {
return -1;
}
IfThenElseOperator iteo = new IfThenElseOperator
(ifAddr, end-ifAddr,
UnknownType.commonType(e[1].getType(),e[2].getType()));
instr[ifAddr] = new Expression(ifAddr, end-ifAddr, iteo, e);
instr[e1Addr] = instr[gotoAddr] = instr[addr] = null;
references[end]--;
return ifAddr;
}
public void analyzeLocals()
{
for (int slot=0; slot< bincode.maxLocals(); slot++) {
LocalVariable localVar = method.getLocal(slot);
int storeAddr[] = new int[instr.size];
for (int i=0; i< instr.size; i++) {
storeAddr[i] = -1;
Stack addrStack = new Stack();
addrStack.push(new Integer(0));
storeAddr[0] = 0;
while (!addrStack.isEmpty()) {
int[] successors;
int addr = ((Integer)addrStack.pop()).intValue();
int store = infos[addr];
if (instr[addr] instanceof StoreOperator) {
store = addr;
} else if (instr[addr] instanceof LoadOperator) {
localVar.combine(store, addr);
}
successors = instr[addr].getSuccessors();
addr = (successors.length==1)?successor[0];
/* XXX try - catch blocks */
LocalInfo nextInfo = localVar.getInfo(store);
for (int i=0; i< successors.length; i++) {
if (info[successors[i]] != -1) {
if (nextInfo == localVar.getInfo(info[successors[i]]))
continue;
localVar.combine(info[successors[i]], store);
} else
info[successors[i]] = store;
addrStack.push(successors[i]);
}
}
}
}
public void analyze()
{
for (int addr = 0; addr < instr.length; ) {
int nextAddr;
nextAddr = createExpression(addr);
if (nextAddr >= 0) {
addr = nextAddr;
continue;
}
nextAddr = createAssignExpression(addr);
if (nextAddr >= 0) {
addr = nextAddr;
continue;
}
nextAddr = createArrayOpAssign(addr);
if (nextAddr >= 0) {
addr = nextAddr;
continue;
}
nextAddr = createPostIncExpression(addr);
if (nextAddr >= 0) {
addr = nextAddr;
continue;
}
nextAddr = combineNewConstructor(addr);
if (nextAddr >= 0) {
addr = nextAddr;
continue;
}
// nextAddr = createIfGotoStatement(addr);
// if (nextAddr >= 0) {
// addr = nextAddr;
// continue;
// }
nextAddr = combineIfGotoExpressions(addr);
if (nextAddr >= 0) {
addr = nextAddr;
continue;
}
nextAddr = combineConditionalExpr(addr);
if (nextAddr >= 0) {
addr = nextAddr;
continue;
}
addr += instr[addr].getLength();
}
for (int addr = 0; addr < instr.length; ) {
int nextAddr;
nextAddr = combineExpressions(addr);
if (nextAddr >= 0) {
addr = nextAddr;
continue;
}
addr += instr[addr].getLength();
}
}
public String getLocalName(int i, int addr) {
return method.getLocalName(i, addr).toString();
}
public String getTypeString(Type type) {
return type.toString();
}
public ClassDefinition getClassDefinition() {
return env.getClassDefinition();
}
}