diff --git a/jode/CombineCatchLocal.java b/jode/CombineCatchLocal.java new file mode 100644 index 0000000..b20c2d7 --- /dev/null +++ b/jode/CombineCatchLocal.java @@ -0,0 +1,37 @@ +package jode; +import java.util.Vector; +import sun.tools.java.Identifier; + +public class CombineCatchLocal implements Transformation{ + + static Identifier idException = Identifier.lookup("exception"); + + public InstructionHeader transform(InstructionHeader ih) { + CatchInstructionHeader catchIH; + LocalInfo local; + try { + catchIH = (CatchInstructionHeader)ih; + ih = ih.nextInstruction; + if (ih.getPredecessors().size() != 1) + return null; + Instruction instr = ih.getInstruction(); + if (instr instanceof PopOperator) { + local = new LocalInfo(99); + local.setName(idException); + } else if (instr instanceof LocalStoreOperator) { + local = ((LocalStoreOperator) instr).getLocalInfo(); + local.setName(idException); + } else + return null; + } catch (ClassCastException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + if (!catchIH.combineWithLocal(local)) + return null; + if(Decompiler.isVerbose) + System.err.print("c"); + return catchIH; + } +} diff --git a/jode/CreateConstantArray.java b/jode/CreateConstantArray.java new file mode 100644 index 0000000..b113c30 --- /dev/null +++ b/jode/CreateConstantArray.java @@ -0,0 +1,86 @@ +package jode; +import sun.tools.java.Type; + +public class CreateConstantArray implements Transformation { + + public InstructionHeader transform(InstructionHeader ih) { + Expression[] consts; + int count; + Type type; + try { + if (ih.getInstruction() instanceof DupOperator) + /* this is not the end of the array assign */ + return null; + ih = ih.getSimpleUniquePredecessor(); + ArrayStoreOperator store = + (ArrayStoreOperator) ih.getInstruction(); + ih = ih.getSimpleUniquePredecessor(); + Expression lastconst = (Expression) ih.getInstruction(); + ih = ih.getSimpleUniquePredecessor(); + Expression lastindexexpr = (Expression) ih.getInstruction(); + ConstOperator lastindexop = + (ConstOperator) lastindexexpr.getOperator(); + if (!MyType.isOfType(lastindexop.getType(), MyType.tInt)) + return null; + int lastindex = Integer.parseInt(lastindexop.getValue()); + ih = ih.getSimpleUniquePredecessor(); + DupOperator dup = (DupOperator) ih.getInstruction(); + if (dup.getDepth() != 0 || + dup.getCount() != store.getLValueType().stackSize()) + return null; + consts = new Expression[lastindex+1]; + consts[lastindex] = lastconst; + count = 1; + while (lastindex-- > 0) { + ih = ih.getSimpleUniquePredecessor(); + ArrayStoreOperator store2 = + (ArrayStoreOperator) ih.getInstruction(); + ih = ih.getSimpleUniquePredecessor(); + lastconst = (Expression) ih.getInstruction(); + ih = ih.getSimpleUniquePredecessor(); + Expression indexexpr = (Expression) ih.getInstruction(); + ConstOperator indexop = + (ConstOperator) indexexpr.getOperator(); + if (!MyType.isOfType(indexop.getType(), MyType.tUInt)) + return null; + int index = Integer.parseInt(indexop.getValue()); + if (index > lastindex) + return null; + while (index < lastindex) { + consts[lastindex] = new Expression + (new ConstOperator(MyType.tUnknown, ""), + new Expression[0]); + lastindex--; + } + consts[lastindex] = lastconst; + ih = ih.getSimpleUniquePredecessor(); + dup = (DupOperator) ih.getInstruction(); + if (dup.getDepth() != 0 || + dup.getCount() != store.getLValueType().stackSize()) + return null; + count++; + } + ih = ih.getSimpleUniquePredecessor(); + Expression newArrayExpr = (Expression) ih.getInstruction(); + NewArrayOperator newArrayOp = + (NewArrayOperator) newArrayExpr.getOperator(); + type = newArrayOp.getType(); + if (newArrayOp.getOperandCount() != 1) + return null; + Expression countexpr = + (Expression) newArrayExpr.getSubExpressions()[0]; + ConstOperator countop = + (ConstOperator) countexpr.getOperator(); + if (!MyType.isOfType(countop.getType(), MyType.tUInt)) + return null; + if (Integer.parseInt(countop.getValue()) != consts.length) + return null; + } catch (NullPointerException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + Operator op = new ConstantArrayOperator(type, consts.length); + return ih.combine(4*count+1, new Expression(op, consts)); + } +} diff --git a/jode/CreateIfStatements.java b/jode/CreateIfStatements.java new file mode 100644 index 0000000..18a5917 --- /dev/null +++ b/jode/CreateIfStatements.java @@ -0,0 +1,58 @@ +package jode; + +public class CreateIfStatements implements Transformation { + + public InstructionHeader transform(InstructionHeader ifgoto) { + if (ifgoto.getFlowType() != ifgoto.IFGOTO || + ifgoto.nextInstruction == null || + ifgoto.getSuccessors()[1].getAddress() <= + ifgoto.getSuccessors()[0].getAddress()) + return null; + + InstructionHeader next = ifgoto.getSuccessors()[1]; + InstructionHeader endBlock = next; + if (ifgoto.outer != next.outer) { + if (ifgoto.outer.endBlock != next) + return null; + next = null; + } + + InstructionHeader thenStart = ifgoto.nextInstruction; + InstructionHeader thenEnd; + for (thenEnd = thenStart; + thenEnd != null && thenEnd.nextInstruction != next; + thenEnd = thenEnd.nextInstruction) { + } + if (thenEnd == null) + return null; + + InstructionHeader elseStart = null; + InstructionHeader elseEnd = null; + if (next != null && + thenEnd.getFlowType() == thenEnd.GOTO && + thenEnd.successors[0].getAddress() > next.getAddress()) { + elseStart = next; + endBlock = next = thenEnd.successors[0]; + if (ifgoto.outer != next.outer) { + if (ifgoto.outer.endBlock != next) + return null; + next = null; + } + for (elseEnd = elseStart; + elseEnd != null && elseEnd.nextInstruction != next; + elseEnd = elseEnd.nextInstruction) { + } + /* XXX return error or create if-then? + */ + if (elseEnd == null) + return null; + } + if(Decompiler.isVerbose) + System.err.print("i"); + return new IfInstructionHeader + (ifgoto, elseStart != null, thenEnd, elseEnd, endBlock); + } +} + + + diff --git a/jode/CreateNewConstructor.java b/jode/CreateNewConstructor.java new file mode 100644 index 0000000..5ce95aa --- /dev/null +++ b/jode/CreateNewConstructor.java @@ -0,0 +1,42 @@ +package jode; + +public class CreateNewConstructor implements Transformation{ + + public InstructionHeader transform(InstructionHeader ih) { + InvokeOperator constrCall; + Expression exprs[]; + try { + constrCall = (InvokeOperator) ih.getInstruction(); + if (!constrCall.isConstructor()) + return null; + int params = constrCall.getOperandCount(); + exprs = new Expression[params]; + for (int i = params-1; i>0; i--) { + ih = ih.getSimpleUniquePredecessor(); + exprs[i] = (Expression) ih.getInstruction(); + if (exprs[i].isVoid()) + return null; /* XXX */ + } + ih = ih.getSimpleUniquePredecessor(); + DupOperator dup = (DupOperator) ih.getInstruction(); + if (dup.getCount() != 1 && dup.getDepth() != 0) + return null; + ih = ih.getSimpleUniquePredecessor(); + exprs[0] = (Expression) ih.getInstruction(); + if (exprs[0].isVoid()) + return null; + NewOperator op = (NewOperator) exprs[0].getOperator(); + if (constrCall.getClassType() != op.getType()) + return null; + } catch (ClassCastException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + ConstructorOperator conOp = + new ConstructorOperator(constrCall.getClassType(), + constrCall.getField()); + + return ih.combine(exprs.length+2, new Expression(conOp, exprs)); + } +} diff --git a/jode/CreateTryCatchStatements.java b/jode/CreateTryCatchStatements.java new file mode 100644 index 0000000..d24be9f --- /dev/null +++ b/jode/CreateTryCatchStatements.java @@ -0,0 +1,67 @@ +package jode; + +public class CreateTryCatchStatements implements Transformation { + + public InstructionHeader transform(InstructionHeader tryIH) { + if (tryIH.getFlowType() != tryIH.TRY || + tryIH.successors.length == 1 || + tryIH.nextInstruction == null) + return null; + + /* find handler with largest end address + * and count the catches. + */ + InstructionHeader endIH = tryIH; + int index = 0, count = 0; + for (int i=1; i < tryIH.successors.length; i+=2) { + if (tryIH.successors[i] == endIH) + count++; + else if (tryIH.successors[i].addr > endIH.addr) { + endIH = tryIH.successors[i]; + count = 1; + } + } + if (count == 0 || endIH.outer != tryIH.outer) + return null; + + /* now find all corresponding catches */ + InstructionHeader[] catchIH = new InstructionHeader[count+1]; + InstructionHeader[] remaining = + new InstructionHeader[tryIH.successors.length-2*count]; + int index1 = 0, index2=0; + remaining[index2++] = tryIH.successors[0]; + catchIH[index1++] = tryIH; + for (int i=1; i < tryIH.successors.length; i+=2) { + if (tryIH.successors[i] == endIH) { + /* assume that the catches are already sorted */ + if (tryIH.successors[i+1].outer != tryIH.outer || + tryIH.successors[i+1].flowType != InstructionHeader.CATCH) + return null; + catchIH[index1] = tryIH.successors[i+1]; + index1++; + } else { + remaining[index2++] = tryIH.successors[i]; + remaining[index2++] = tryIH.successors[i+1]; + } + } + InstructionHeader endBlock = tryIH.outer.endBlock; + if (endIH != catchIH[1]) { + if ((endIH.flowType != endIH.RETURN || + endIH.getInstruction().getType() != MyType.tVoid) && + endIH.flowType != endIH.GOTO) + return null; + + if (endIH.successors[0].outer == tryIH.outer) + endBlock = endIH.successors[0]; + else if (endIH.successors[0] != endBlock) + return null; + } + if (Decompiler.isVerbose) + System.err.print("t"); + return new TryCatchInstructionHeader + (catchIH, endIH, remaining, endBlock); + } +} + + + diff --git a/jode/CreateWhileStatements.java b/jode/CreateWhileStatements.java new file mode 100644 index 0000000..003b11b --- /dev/null +++ b/jode/CreateWhileStatements.java @@ -0,0 +1,26 @@ +package jode; + +public class CreateWhileStatements implements Transformation { + + public InstructionHeader transform(InstructionHeader gotoIH) { + + if (gotoIH.flowType != gotoIH.GOTO || gotoIH.nextInstruction == null || + gotoIH.successors[0].addr < gotoIH.nextInstruction.addr) + return null; + + InstructionHeader block = gotoIH.nextInstruction; + if (block == null) + block = gotoIH.outer.endBlock; + + InstructionHeader ifgoto = gotoIH.successors[0]; + + if (ifgoto.getFlowType() != ifgoto.IFGOTO || + ifgoto.successors[1] != block || + ifgoto.outer != block.outer) + return null; + + if(Decompiler.isVerbose) + System.err.print("w"); + return new WhileInstructionHeader(gotoIH, ifgoto, block); + } +} diff --git a/jode/RemoveNop.java b/jode/RemoveNop.java new file mode 100644 index 0000000..499e714 --- /dev/null +++ b/jode/RemoveNop.java @@ -0,0 +1,19 @@ +package jode; + +public class RemoveNop implements Transformation { + public InstructionHeader transform (InstructionHeader ih) { + Instruction pred; + try { + NopOperator op = (NopOperator) ih.getInstruction(); + ih = ih.getSimpleUniquePredecessor(); + pred = ih.getInstruction(); + if (pred == null) + return null; + } catch (NullPointerException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + return ih.combine(2, pred); + } +} diff --git a/jode/Transformation.java b/jode/Transformation.java new file mode 100644 index 0000000..ee82a9e --- /dev/null +++ b/jode/Transformation.java @@ -0,0 +1,5 @@ +package jode; + +public interface Transformation { + public InstructionHeader transform(InstructionHeader ih); +} diff --git a/jode/jode/Decompiler.java b/jode/jode/Decompiler.java index 412d70c..4d73fc2 100644 --- a/jode/jode/Decompiler.java +++ b/jode/jode/Decompiler.java @@ -3,13 +3,16 @@ import sun.tools.java.*; import java.lang.reflect.Modifier; public class Decompiler { + public static boolean isVerbose = false; + public static boolean isDebugging = false; + public static void main(String[] params) { JodeEnvironment env = new JodeEnvironment(); for (int i=0; i= from) to++; - return new InstructionHeader + return InstructionHeader.createNormal (addr, 1, new ConvertOperator(types[0][from], types[0][to])); } case opc_i2b: case opc_i2c: case opc_i2s: - return new InstructionHeader + return InstructionHeader.createNormal (addr, 1, new ConvertOperator (ALL_INT_TYPE, types[1][(opcode-opc_i2b)+5])); case opc_lcmp: case opc_fcmpl: case opc_fcmpg: case opc_dcmpl: case opc_dcmpg: - return new InstructionHeader + return InstructionHeader.createNormal (addr, 1, new CompareToIntOperator (types[0][(opcode-opc_lcmp+3)/2], (opcode-opc_lcmp+3)%2)); case opc_ifeq: case opc_ifne: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: - return InstructionHeader.conditional + return InstructionHeader.createIfGoto (addr, 3, addr+stream.readShort(), new CompareUnaryOperator (ALL_INT_TYPE, opcode - opc_ifeq+Operator.COMPARE_OP)); case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: - return InstructionHeader.conditional + return InstructionHeader.createIfGoto (addr, 3, addr+stream.readShort(), new CompareBinaryOperator (ALL_INT_TYPE, opcode - opc_if_icmpeq+Operator.COMPARE_OP)); case opc_if_acmpeq: case opc_if_acmpne: - return InstructionHeader.conditional + return InstructionHeader.createIfGoto (addr, 3, addr+stream.readShort(), new CompareBinaryOperator (OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP)); case opc_goto: - return InstructionHeader.jump + return InstructionHeader.createGoto (addr, 3, addr+stream.readShort(), new NopOperator()); case opc_jsr: - return InstructionHeader.jump + return InstructionHeader.createGoto //XXX (addr, 3, addr+stream.readShort(), new JsrOperator()); case opc_ret: - return InstructionHeader.ret + return InstructionHeader.createReturn //XXX (addr, 2, new LocalLoadOperator - (INT_TYPE, - stream.readUnsignedByte())); + (OBJECT_TYPE, stream.readUnsignedByte())); case opc_tableswitch: { int length = 3-(addr % 4); stream.skip(length); @@ -261,9 +260,8 @@ public abstract class Opcodes implements RuntimeConstants{ } dests[cases.length] = def; length += 13 + 4 * cases.length; - return new InstructionHeader - (addr, length, new NopOperator(), - ALL_INT_TYPE, cases, dests); + return InstructionHeader.createSwitch + (addr, length, new NopOperator(), cases, dests); } case opc_lookupswitch: { int length = 3-(addr % 4); @@ -278,35 +276,34 @@ public abstract class Opcodes implements RuntimeConstants{ } dests[npairs] = def; length += 9 + 8 * npairs; - return new InstructionHeader - (addr, length, new NopOperator(), - ALL_INT_TYPE, cases, dests); + return InstructionHeader.createSwitch + (addr, length, new NopOperator(), cases, dests); } case opc_ireturn: case opc_lreturn: case opc_freturn: case opc_dreturn: case opc_areturn: { Type retType = MyType.intersection (ca.getMethod().mdef.getType().getReturnType(), types[0][opcode-opc_ireturn]); - return InstructionHeader.ret + return InstructionHeader.createReturn (addr, 1, new ReturnOperator(retType)); } case opc_return: { Type retType = MyType.intersection (ca.getMethod().mdef.getType().getReturnType(), VOID_TYPE); - return InstructionHeader.ret + return InstructionHeader.createReturn (addr, 1, new ReturnOperator(retType)); } case opc_getstatic: case opc_getfield: - return new InstructionHeader + return InstructionHeader.createNormal (addr, 3, new GetFieldOperator (ca, opcode == opc_getstatic, (FieldDefinition)ca.env.getConstant (stream.readUnsignedShort()))); case opc_putstatic: case opc_putfield: - return new InstructionHeader + return InstructionHeader.createNormal (addr, 3, new PutFieldOperator (ca, opcode == opc_putstatic, (FieldDefinition)ca.env.getConstant @@ -314,14 +311,14 @@ public abstract class Opcodes implements RuntimeConstants{ case opc_invokevirtual: case opc_invokespecial: case opc_invokestatic : - return new InstructionHeader + return InstructionHeader.createNormal (addr, 3, new InvokeOperator (ca, opcode == opc_invokestatic, opcode == opc_invokespecial, (FieldDefinition)ca.env.getConstant (stream.readUnsignedShort()))); case opc_invokeinterface: { - InstructionHeader ih = new InstructionHeader + InstructionHeader ih = InstructionHeader.createNormal (addr, 5, new InvokeOperator (ca, false, false, (FieldDefinition)ca.env.getConstant @@ -333,7 +330,7 @@ public abstract class Opcodes implements RuntimeConstants{ ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant(stream.readUnsignedShort()); Type type = MyType.tClassOrArray(cldec.getName()); - return new InstructionHeader + return InstructionHeader.createNormal (addr, 3, new NewOperator(type, ca.env.getTypeString(type))); } case opc_newarray: { @@ -350,7 +347,7 @@ public abstract class Opcodes implements RuntimeConstants{ default: throw new ClassFormatError("Invalid newarray operand"); } - return new InstructionHeader + return InstructionHeader.createNormal (addr, 2, new NewArrayOperator(MyType.tArray(type), type.toString(), 1)); @@ -360,21 +357,21 @@ public abstract class Opcodes implements RuntimeConstants{ (stream.readUnsignedShort()); Identifier ident = cldec.getName(); Type type = MyType.tClassOrArray(cldec.getName()); - return new InstructionHeader + return InstructionHeader.createNormal (addr, 3, new NewArrayOperator (MyType.tArray(type), ca.env.getTypeString(type),1)); } case opc_arraylength: - return new InstructionHeader + return InstructionHeader.createNormal (addr, 1, new ArrayLengthOperator()); case opc_athrow: - return InstructionHeader.ret + return InstructionHeader.createReturn (addr, 1, new ThrowOperator()); case opc_checkcast: { ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant (stream.readUnsignedShort()); Type type = MyType.tClassOrArray(cldec.getName()); - return new InstructionHeader + return InstructionHeader.createNormal (addr, 3, new CheckCastOperator (type, ca.env.getTypeString(type))); } @@ -382,27 +379,27 @@ public abstract class Opcodes implements RuntimeConstants{ ClassDeclaration cldec = (ClassDeclaration) ca.env.getConstant (stream.readUnsignedShort()); Type type = MyType.tClassOrArray(cldec.getName()); - return new InstructionHeader + return InstructionHeader.createNormal (addr, 3, new InstanceOfOperator(type, ca.env.getTypeString(type))); } case opc_monitorenter: - return new InstructionHeader(addr, 1, + return InstructionHeader.createNormal(addr, 1, new MonitorEnterOperator()); case opc_monitorexit: - return new InstructionHeader(addr, 1, + return InstructionHeader.createNormal(addr, 1, new MonitorExitOperator()); case opc_wide: { switch (opcode=stream.readUnsignedByte()) { case opc_iload: case opc_lload: case opc_fload: case opc_dload: case opc_aload: - return new InstructionHeader + return InstructionHeader.createNormal (addr, 4, new LocalLoadOperator(types[0][opcode-opc_iload], stream.readUnsignedShort())); case opc_istore: case opc_lstore: case opc_fstore: case opc_dstore: case opc_astore: - return new InstructionHeader + return InstructionHeader.createNormal (addr, 4, new LocalStoreOperator(types[0][opcode-opc_istore], stream.readUnsignedShort(), @@ -415,7 +412,7 @@ public abstract class Opcodes implements RuntimeConstants{ value = -value; operation = Operator.NEG_OP; } - return new InstructionHeader + return InstructionHeader.createNormal (addr, 6, new IIncOperator (local, Integer.toString(value), operation + Operator.OPASSIGN_OP)); @@ -437,21 +434,21 @@ public abstract class Opcodes implements RuntimeConstants{ Type baseType = type; for (int i=0; i= 0 && instr[i] == null; i--) {} - return i; - */ - return addr; - } - - int getNextAddr(int addr) { - /* - return addr + instr[addr].getLength(); - */ - return addr; - } - - 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 { - InstructionHeader ih; - for (ih = methodHeader.getNextInstruction(); ih != null; - ih = ih.getNextInstruction()) { - - ih.dumpSource(writer); - } + methodHeader.dumpSource(writer); } public CodeAnalyzer(MethodAnalyzer ma, BinaryCode bc, JodeEnvironment e) @@ -121,593 +55,37 @@ public class CodeAnalyzer implements Analyzer, Constants { method = ma; env = e; bincode = bc; - readCode(bincode.getCode()); - BinaryExceptionHandler[] handlers = bincode.getExceptionHandlers(); - for (int i=0; i 0) { - ih = ih.getSimpleUniquePredecessor(); - ArrayStoreOperator store2 = - (ArrayStoreOperator) ih.getInstruction(); - ih = ih.getSimpleUniquePredecessor(); - lastconst = (Expression) ih.getInstruction(); - ih = ih.getSimpleUniquePredecessor(); - Expression indexexpr = (Expression) ih.getInstruction(); - ConstOperator indexop = - (ConstOperator) indexexpr.getOperator(); - if (!MyType.isOfType(indexop.getType(), MyType.tUInt)) - return null; - int index = Integer.parseInt(indexop.getValue()); - if (index > lastindex) - return null; - while (index < lastindex) { - consts[lastindex] = new Expression - (new ConstOperator(MyType.tUnknown, ""), - new Expression[0]); - lastindex--; - } - consts[lastindex] = lastconst; - ih = ih.getSimpleUniquePredecessor(); - dup = (DupOperator) ih.getInstruction(); - if (dup.getDepth() != 0 || - dup.getCount() != store.getLValueType().stackSize()) - return null; - count++; - } - ih = ih.getSimpleUniquePredecessor(); - Expression newArrayExpr = (Expression) ih.getInstruction(); - NewArrayOperator newArrayOp = - (NewArrayOperator) newArrayExpr.getOperator(); - type = newArrayOp.getType(); - if (newArrayOp.getOperandCount() != 1) - return null; - Expression countexpr = - (Expression) newArrayExpr.getSubExpressions()[0]; - ConstOperator countop = - (ConstOperator) countexpr.getOperator(); - if (!MyType.isOfType(countop.getType(), MyType.tUInt)) - return null; - if (Integer.parseInt(countop.getValue()) != consts.length) - return null; - } catch (NullPointerException ex) { - return null; - } catch (ClassCastException ex) { - return null; - } - Operator op = new ConstantArrayOperator(type, consts.length); - ih.combine(4*count+1, new Expression(op, consts)); - return ih; - } - - public InstructionHeader createExpression(InstructionHeader ih) { - Operator op; - Expression exprs[]; - int params; - try { - op = (Operator) ih.getInstruction(); - params = op.getOperandCount(); - exprs = new Expression[params]; - for (int i = params-1; i>=0; i--) { - ih = ih.getSimpleUniquePredecessor(); - exprs[i] = (Expression) ih.getInstruction(); - if (exprs[i].isVoid()) { - if (i == params-1) - return null; - Expression e = exprs[i+1].tryToCombine(exprs[i]); - if (e == null) - return null; - i++; - exprs[i] = e; - ih.combine(2, e); - } - } - } catch (NullPointerException ex) { - return null; - } catch (ClassCastException ex) { - return null; - } - ih.combine(params+1, new Expression(op, exprs)); - return ih; - } - -// 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 InstructionHeader createAssignExpression(InstructionHeader ih) { - StoreInstruction store; - try { - store = (StoreInstruction) ih.getInstruction(); - ih = ih.getSimpleUniquePredecessor(); - - DupOperator dup = (DupOperator) ih.getInstruction(); - if (dup.getDepth() != store.getLValueOperandCount() && - dup.getCount() != store.getLValueType().stackSize()) - return null; - } catch (NullPointerException ex) { - return null; - } catch (ClassCastException ex) { - return null; - } - ih.combine(2, new AssignOperator(Operator.ASSIGN_OP, store)); - return ih; - } - - public InstructionHeader createLocalPostIncExpression(InstructionHeader ih) - { - IIncOperator iinc; - int op; - Type type; - try { - Expression iincExpr = (Expression) ih.getInstruction(); - iinc = (IIncOperator) iincExpr.getOperator(); - if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP) - op = Operator.INC_OP; - else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP) - op = Operator.DEC_OP; - else - return null; - if (!iinc.getValue().equals("1") && - !iinc.getValue().equals("-1")) - return null; - if (iinc.getValue().equals("-1")) - op ^= 1; - ih = ih.getSimpleUniquePredecessor(); - Expression loadExpr = (Expression) ih.getInstruction(); - LocalLoadOperator load = - (LocalLoadOperator)loadExpr.getOperator(); - if (!iinc.matches(load)) - return null; - - type = MyType.intersection(load.getType(), MyType.tUInt); - } catch (NullPointerException ex) { - return null; - } catch (ClassCastException ex) { - return null; - } - Operator postop = new LocalPostFixOperator(type, op, iinc); - ih.combine(2, postop); - return ih; - } - - public InstructionHeader createPostIncExpression(InstructionHeader ih) { - StoreInstruction store; - int op; - Type type; - try { - store = (StoreInstruction) ih.getInstruction(); - if (store.getLValueOperandCount() == 0) - return null; - ih = ih.getSimpleUniquePredecessor(); - BinaryOperator binOp = (BinaryOperator) ih.getInstruction(); - if (binOp.getOperator() == store.ADD_OP) - op = Operator.INC_OP; - else if (store.getOperator() == store.NEG_OP) - op = Operator.DEC_OP; - else - return null; - ih = ih.getSimpleUniquePredecessor(); - Expression expr = (Expression) ih.getInstruction(); - ConstOperator constOp = (ConstOperator) expr.getOperator(); - if (!constOp.getValue().equals("1") && - !constOp.getValue().equals("-1")) - return null; - if (constOp.getValue().equals("-1")) - op ^= 1; - ih = ih.getSimpleUniquePredecessor(); - DupOperator dup = (DupOperator) ih.getInstruction(); - if (dup.getCount() != store.getLValueType().stackSize() || - dup.getDepth() != store.getLValueOperandCount()) - return null; - ih = ih.getSimpleUniquePredecessor(); - Operator load = (Operator) ih.getInstruction(); - - if (!store.matches(load)) - return null; - - ih = ih.getSimpleUniquePredecessor(); - DupOperator dup2 = (DupOperator) ih.getInstruction(); - if (dup2.getCount() != store.getLValueOperandCount() || - dup2.getDepth() != 0) - return null; - - type = MyType.intersection(load.getType(), store.getLValueType()); - } catch (NullPointerException ex) { - return null; - } catch (ClassCastException ex) { - return null; - } - Operator postop = new PostFixOperator(type, op, store); - ih.combine(6, postop); - return ih; - } - - public InstructionHeader createAssignOp(InstructionHeader ih) { - Expression rightHandSide; - StoreInstruction store; - BinaryOperator binop; - try { - store = (StoreInstruction) ih.getInstruction(); - ih = ih.getSimpleUniquePredecessor(); - binop = (BinaryOperator) ih.getInstruction(); - if (binop.getOperator() < binop.ADD_OP || - binop.getOperator() >= binop.ASSIGN_OP) - return null; - ih = ih.getSimpleUniquePredecessor(); - rightHandSide = (Expression) ih.getInstruction(); - if (rightHandSide.isVoid()) - return null; /* XXX */ - ih = ih.getSimpleUniquePredecessor(); - Operator load = (Operator) ih.getInstruction(); - if (!store.matches(load)) - return null; - ih = ih.getSimpleUniquePredecessor(); - DupOperator dup = (DupOperator) ih.getInstruction(); - if (dup.getDepth() != 0 && - dup.getCount() != store.getLValueOperandCount()) - return null; - } catch (ClassCastException ex) { - return null; - } catch (NullPointerException ex) { - return null; - } - ih.combine(3, rightHandSide); - InstructionHeader storeIH = ih.getNextInstruction(); - store.setOperator(store.OPASSIGN_OP+binop.getOperator()); - store.setLValueType(MyType.intersection(binop.getType(), - store.getLValueType())); - storeIH.combine(2, store); - return ih; - } - - public InstructionHeader combineNewConstructor(InstructionHeader ih) { - InvokeOperator constrCall; - Expression exprs[]; - try { - constrCall = (InvokeOperator) ih.getInstruction(); - if (!constrCall.isConstructor()) - return null; - int params = constrCall.getOperandCount(); - exprs = new Expression[params]; - for (int i = params-1; i>0; i--) { - ih = ih.getSimpleUniquePredecessor(); - exprs[i] = (Expression) ih.getInstruction(); - if (exprs[i].isVoid()) - return null; /* XXX */ - } - ih = ih.getSimpleUniquePredecessor(); - DupOperator dup = (DupOperator) ih.getInstruction(); - if (dup.getCount() != 1 && dup.getDepth() != 0) - return null; - ih = ih.getSimpleUniquePredecessor(); - exprs[0] = (Expression) ih.getInstruction(); - if (exprs[0].isVoid()) - return null; - NewOperator op = (NewOperator) exprs[0].getOperator(); - if (constrCall.getClassType() != op.getType()) - return null; - } catch (ClassCastException ex) { - return null; - } catch (NullPointerException ex) { - return null; - } - ConstructorOperator conOp = - new ConstructorOperator(constrCall.getClassType(), - constrCall.getField()); - - ih.combine(exprs.length+2, new Expression(conOp, exprs)); - return ih; - } - - public InstructionHeader combineIfGotoExpressions(InstructionHeader ih2) { - InstructionHeader ih1; - Expression[] e; - int operator; - try { - if (ih2.switchType != MyType.tBoolean) - return null; - InstructionHeader[] dests2 = ih2.getSuccessors(); - - /* if ih2.getSimpleUniquePredecessor.getOperator().isVoid() XXX */ - - Vector predec = ih2.getPredecessors(); - if (predec.size() != 1) - return null; - - ih1 = (InstructionHeader) predec.elementAt(0); - if (ih1.switchType != MyType.tBoolean) - return null; - InstructionHeader[] dests1 = ih1.getSuccessors(); - if (dests1[0] != ih2) - return null; - - if (dests1[1] == dests2[0]) { - e = new Expression[2]; - operator = Operator.LOG_AND_OP; - e[1] = (Expression)ih2.getInstruction(); - e[0] = ((Expression)ih1.getInstruction()).negate(); - } else if (dests1[1] == dests2[1]) { - e = new Expression[2]; - operator = Operator.LOG_OR_OP; - e[1] = (Expression)ih2.getInstruction(); - e[0] = (Expression)ih1.getInstruction(); - } else - return null; - } catch (ClassCastException ex) { - return null; - } catch (NullPointerException ex) { - return null; - } - - Expression cond = - new Expression(new BinaryOperator(Type.tBoolean, operator), e); - - ih1.combineConditional(cond); - return ih1; - } - - public InstructionHeader createFunnyIfThenElseOp(InstructionHeader ih) { - Expression cond = null; - try { - InstructionHeader ifHeader= ih; - if (ifHeader.switchType != MyType.tBoolean) - return null; - CompareUnaryOperator compare = - (CompareUnaryOperator) ifHeader.getInstruction(); - if ((compare.getOperator() & ~1) != compare.EQUALS_OP) - return null; - Enumeration enum = ih.getPredecessors().elements(); - while (enum.hasMoreElements()) { - try { - ih = (InstructionHeader) enum.nextElement(); - Expression zeroExpr = (Expression) ih.getInstruction(); - ConstOperator zero = - (ConstOperator) zeroExpr.getOperator(); - if (!zero.getValue().equals("0")) - continue; - - ih = ih.getUniquePredecessor(); - if (ih.switchType != MyType.tBoolean) - continue; - - if (compare.getOperator() == compare.EQUALS_OP && - ih.getSuccessors()[1] != ifHeader.getSuccessors()[0] - || compare.getOperator() == compare.NOTEQUALS_OP && - ih.getSuccessors()[1] != ifHeader.getSuccessors()[1]) - continue; - - cond = (Expression) ih.getInstruction(); - break; - } catch (ClassCastException ex) { - } catch (NullPointerException ex) { - } - } - - if (cond == null) - return null; - - } catch (ClassCastException ex) { - return null; - } catch (NullPointerException ex) { - return null; - } - - InstructionHeader next = ih.nextInstruction; - ih.nextInstruction = next.nextInstruction; - ih.successors[1].predecessors.removeElement(ih); - ih.switchType = MyType.tVoid; - ih.successors = next.successors; - ih.successors[0].predecessors.removeElement(next); - ih.successors[0].predecessors.addElement(ih); - ih.succs = next.succs; - ih.length += next.length; - return ih; - } - - public InstructionHeader createIfThenElseOperator(InstructionHeader ih) { - InstructionHeader ifHeader; - Expression e[] = new Expression[3]; - InstructionHeader[] succs; - try { - Vector predec = ih.getPredecessors(); - - if (predec.size() != 1) - return null; - ifHeader = (InstructionHeader) predec.elementAt(0); - if (ifHeader.switchType != Type.tBoolean) - return null; - succs = ifHeader.getSuccessors(); - if (succs[1] != ih || - succs[0].getNextInstruction() != succs[1] || - succs[0].getSuccessors().length != 1 || - succs[1].getSuccessors().length != 1 || - succs[0].getSuccessors()[0] != succs[1].getSuccessors()[0]) - return null; - - e[0] = ((Expression) ifHeader.getInstruction()).negate(); - e[1] = (Expression) succs[0].getInstruction(); - e[2] = (Expression) succs[1].getInstruction(); - } catch (ClassCastException ex) { - return null; - } catch (NullPointerException ex) { - return null; - } - IfThenElseOperator iteo = new IfThenElseOperator - (MyType.intersection(e[1].getType(),e[2].getType())); - ifHeader.instr = new Expression(iteo, e); - ifHeader.nextInstruction = ih.nextInstruction; - ifHeader.length = ih.addr + ih.length - ifHeader.addr; - ifHeader.succs = ih.succs; - ifHeader.successors = ih.successors; - ifHeader.switchType = Type.tVoid; - ifHeader.successors[0].predecessors.removeElement(succs[0]); - ifHeader.successors[0].predecessors.removeElement(succs[1]); - ifHeader.successors[0].predecessors.addElement(ifHeader); - return ifHeader; - } + readCode(); + } + + static Transformation[] exprTrafos = { + new RemoveNop(), + new CombineCatchLocal(), + new CreateExpression(), + new CreatePostIncExpression(), + new CreateAssignExpression(), + new CreateNewConstructor(), + new CombineIfGotoExpressions(), + new CreateIfThenElseOperator(), + new CreateConstantArray() + }; + + static Transformation[] simplifyTrafos = { new SimplifyExpression() }; + static Transformation[] blockTrafos = { + new CreateTryCatchStatements(), + new CreateIfStatements(), + new CreateWhileStatements() + }; public void analyze() { - InstructionHeader ih, next; - for (ih = methodHeader.getNextInstruction(); ih != null; - ih = next) { - if (env.isVerbose) - System.err.print("."); -// System.err.println(""+ih.getAddress()); - if ((next = removeNop(ih)) != null) continue; - if ((next = createExpression(ih)) != null) continue; - if ((next = createPostIncExpression(ih)) != null) continue; - if ((next = createLocalPostIncExpression(ih)) != null) continue; - if ((next = createAssignOp(ih)) != null) continue; - if ((next = combineNewConstructor(ih)) != null) continue; - if ((next = combineIfGotoExpressions(ih)) != null) continue; - if ((next = createFunnyIfThenElseOp(ih)) != null) continue; - if ((next = createIfThenElseOperator(ih)) != null) continue; - if ((next = createAssignExpression(ih)) != null) continue; - if ((next = createConstantArray(ih)) != null) continue; - next = ih.getNextInstruction(); - } - - for (ih = methodHeader.getNextInstruction(); ih != null; - ih = ih.getNextInstruction()) { - ih.instr = ih.getInstruction().simplify(); - } -// 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 = 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(); -// } + methodHeader.doTransformations(exprTrafos); + methodHeader.doTransformations(simplifyTrafos); + methodHeader.doTransformations(blockTrafos); } public String getTypeString(Type type) { - return type.toString(); + return env.getTypeString(type); } public ClassDefinition getClassDefinition() { diff --git a/jode/jode/decompiler/ImportHandler.java b/jode/jode/decompiler/ImportHandler.java index d071092..1049814 100644 --- a/jode/jode/decompiler/ImportHandler.java +++ b/jode/jode/decompiler/ImportHandler.java @@ -8,9 +8,6 @@ public class JodeEnvironment extends LoadEnvironment { BinaryClass main; Identifier pkg; - public boolean isVerbose = false; - public boolean isDebugging = false; - JodeEnvironment() { super(null); MyType.setEnvironment(this); @@ -91,7 +88,6 @@ public class JodeEnvironment extends LoadEnvironment { a.analyze(); TabbedPrintWriter writer = new TabbedPrintWriter(System.out, " "); - writer.verbosity = isDebugging?10:0; a.dumpSource(writer); } catch (ClassNotFound e) { error(e.toString()); diff --git a/jode/jode/decompiler/LocalInfo.java b/jode/jode/decompiler/LocalInfo.java index dbf7ced..eb3fab7 100644 --- a/jode/jode/decompiler/LocalInfo.java +++ b/jode/jode/decompiler/LocalInfo.java @@ -14,6 +14,7 @@ import sun.tools.java.*; */ public class LocalInfo { private static int serialnr = 0; + private int slot; private Identifier name; private Type type; private LocalInfo shadow; @@ -25,9 +26,9 @@ public class LocalInfo { * @param slot The slot of this variable. */ public LocalInfo(int slot) { - name = Identifier.lookup("local_"+slot+"__"+serialnr); + name = null; type = MyType.tUnknown; - serialnr++; + this.slot = slot; } /** @@ -39,11 +40,11 @@ public class LocalInfo { * @param li the local info that we want to shadow. */ public void combineWith(LocalInfo li) { - if (this == li) - return; if (shadow != null) shadow.combineWith(li); - shadow = li; + li = li.getLocalInfo(); + if (this != li) + shadow = li; } /** @@ -62,6 +63,8 @@ public class LocalInfo { public Identifier getName() { if (shadow != null) return shadow.getName(); + if (name == null) + name = Identifier.lookup("local_"+slot+"__"+serialnr++); return name; } diff --git a/jode/jode/decompiler/LocalVariableAnalyzer.java b/jode/jode/decompiler/LocalVariableAnalyzer.java index c9c8ab7..83003be 100644 --- a/jode/jode/decompiler/LocalVariableAnalyzer.java +++ b/jode/jode/decompiler/LocalVariableAnalyzer.java @@ -61,14 +61,28 @@ public class LocalVariableAnalyzer { } public void analyze(MethodInstructionHeader mih) { - + { + Type[] paramTypes = mdef.getType().getArgumentTypes(); + int length = (mdef.isStatic() ? 0 : 1) + paramTypes.length; + argLocals = new LocalInfo[length]; + int offset = 0; + if (!mdef.isStatic()) { + argLocals[0] = new LocalInfo(0); + argLocals[0].setType(mdef.getClassDefinition().getType()); + offset++; + } + for (int i=0; i< paramTypes.length; i++) { + argLocals[offset+i] = new LocalInfo(i+offset); + argLocals[offset+i].setType(paramTypes[i]); + } + } + Hashtable done = new Hashtable(); Stack instrStack = new Stack(); Stack readsStack = new Stack(); + LocalInfo[] reads = new LocalInfo[maxlocals]; - LocalInfo[] reads = new LocalInfo[maxlocals]; - - Enumeration predec = mih.getPredecessors().elements(); + Enumeration predec = mih.getReturns().elements(); while (predec.hasMoreElements()) { instrStack.push(predec.nextElement()); readsStack.push(reads); @@ -81,8 +95,6 @@ public class LocalVariableAnalyzer { (LocalInfo[]) done.get(instr); reads = (LocalInfo[]) readsStack.pop(); - if (env.isVerbose) - System.err.print("."); // System.err.println(""); // System.err.print("Addr: "+instr.getAddress()+ " ["); // for (int i=0; i< maxlocals; i++) { @@ -108,60 +120,49 @@ public class LocalVariableAnalyzer { continue; } - if (!(instr instanceof MethodInstructionHeader)) { - if (instr.getInstruction() instanceof LocalVarOperator) { - LocalVarOperator op = - (LocalVarOperator)instr.getInstruction(); - int slot = op.getSlot(); - - LocalInfo li = combine(slot, op.getLocalInfo(), - reads[slot]); - - LocalInfo[] newReads = new LocalInfo[maxlocals]; - System.arraycopy(reads, 0, newReads, 0, maxlocals); - - op.setLocalInfo(li); - if (op.isRead()) - newReads[slot] = li; - else - newReads[slot] = null; - - reads = newReads; - } - - predec = instr.getPredecessors().elements(); + if (instr.getInstruction() instanceof LocalVarOperator) { + + if (Decompiler.isVerbose) + System.err.print("."); + + LocalVarOperator op = + (LocalVarOperator)instr.getInstruction(); + int slot = op.getSlot(); + + LocalInfo li = combine(slot, op.getLocalInfo(), + reads[slot]); + + LocalInfo[] newReads = new LocalInfo[maxlocals]; + System.arraycopy(reads, 0, newReads, 0, maxlocals); + + op.setLocalInfo(li); + if (op.isRead()) + newReads[slot] = li; + else + newReads[slot] = null; + + reads = newReads; + done.put(instr, reads); + } + + predec = instr.getPredecessors().elements(); + if (predec.hasMoreElements()) { while (predec.hasMoreElements()) { instrStack.push(predec.nextElement()); readsStack.push(reads); } + } else { + /* This is the first instruction + */ + for (int i=0; i < argLocals.length; i++) { + if (reads[i] != null) + argLocals[i].combineWith(reads[i]); + } } - done.put(instr, reads); } - // System.err.println(""); - - reads = (LocalInfo[]) done.get(mih); - - - Type[] paramTypes = mdef.getType().getArgumentTypes(); - int length = (mdef.isStatic() ? 0 : 1) + paramTypes.length; - argLocals = new LocalInfo[length]; - int offset = 0; - if (!mdef.isStatic()) { - LocalInfo li = reads[0]; - if (li == null) - li = new LocalInfo(0); - li.setName(Constants.idThis); - li.setType(mdef.getClassDefinition().getType()); - argLocals[0] = li.getLocalInfo(); - offset++; - } - for (int i=0; i< paramTypes.length; i++) { - LocalInfo li = reads[i+offset]; - if (li == null) - li = new LocalInfo(i+offset); - li.setType(paramTypes[i]); - argLocals[offset+i] = li.getLocalInfo(); - } + if (!mdef.isStatic()) + argLocals[0].setName(Constants.idThis); +// System.err.println("done!"); } public void createLocalInfo(CodeAnalyzer code) { @@ -175,13 +176,14 @@ public class LocalVariableAnalyzer { argLocals = new LocalInfo[length]; for (int i=0; i < length; i++) argLocals[i] = lvt.getLocal(i).getInfo(-1); - for (InstructionHeader ih = mih.getNextInstruction(); + for (InstructionHeader ih = mih.getFirst(); ih != null; ih = ih.getNextInstruction()) { if (ih.getInstruction() instanceof LocalVarOperator) { LocalVarOperator op = (LocalVarOperator)ih.getInstruction(); int slot = op.getSlot(); - LocalInfo li = lvt.getLocal(slot).getInfo(ih.getAddress()); + LocalInfo li = + lvt.getLocal(slot).getInfo(ih.getAddress()); op.setLocalInfo(li); } } diff --git a/jode/jode/decompiler/MethodAnalyzer.java b/jode/jode/decompiler/MethodAnalyzer.java index cf616c9..48a8cf0 100644 --- a/jode/jode/decompiler/MethodAnalyzer.java +++ b/jode/jode/decompiler/MethodAnalyzer.java @@ -35,15 +35,15 @@ public class MethodAnalyzer implements Analyzer, Constants { { if (code == null) return; - if (env.isVerbose) + if (Decompiler.isVerbose) System.err.print(mdef.getName().toString()+": locals "); lva.createLocalInfo(code); - if (env.isVerbose) { + if (Decompiler.isVerbose) { System.err.println(""); System.err.print("code "); } code.analyze(); - if (env.isVerbose) + if (Decompiler.isVerbose) System.err.println(""); } diff --git a/jode/jode/decompiler/TabbedPrintWriter.java b/jode/jode/decompiler/TabbedPrintWriter.java index afa6ff2..0c3b925 100644 --- a/jode/jode/decompiler/TabbedPrintWriter.java +++ b/jode/jode/decompiler/TabbedPrintWriter.java @@ -6,7 +6,6 @@ public class TabbedPrintWriter { String tabstr; StringBuffer indent; PrintWriter pw; - int verbosity=0; public TabbedPrintWriter (OutputStream os, String tabstr) { pw = new PrintWriter(os); diff --git a/jode/jode/expr/AssignOperator.java b/jode/jode/expr/AssignOperator.java index a0d1ebc..513bea1 100644 --- a/jode/jode/expr/AssignOperator.java +++ b/jode/jode/expr/AssignOperator.java @@ -9,6 +9,10 @@ public class AssignOperator extends Operator { this.store = store; } + public StoreInstruction getStore() { + return store; + } + public int getPriority() { return store.getPriority(); } diff --git a/jode/jode/expr/CatchInstructionHeader.java b/jode/jode/expr/CatchInstructionHeader.java new file mode 100644 index 0000000..d3a9d9c --- /dev/null +++ b/jode/jode/expr/CatchInstructionHeader.java @@ -0,0 +1,75 @@ +package jode; +import sun.tools.java.Type; +import java.util.Vector; + +public class CatchInstructionHeader extends InstructionHeader { + + Type type; + String typeString; + LocalInfo local; + + CatchInstructionHeader(Type type, String typeString, + InstructionHeader firstInstr, + InstructionHeader outer) { + super(CATCH, firstInstr.addr, firstInstr.addr, + new InstructionHeader[1], outer); + + movePredecessors(firstInstr); + successors[0] = firstInstr; + firstInstr.predecessors = new Vector(); + firstInstr.predecessors.addElement(this); + + prevInstruction = firstInstr.prevInstruction; + if (prevInstruction != null) + prevInstruction.nextInstruction = this; + + nextInstruction = firstInstr; + firstInstr.prevInstruction = this; + + this.type = type; + this.typeString = typeString; + } + + public LocalInfo getLocal() { + return local; + } + + /** + * Combines this catch instruction header with the next instruction + * header which should containt only a LocalStoreOperator or a pop + * according to the parameter. (This is where the exception gets + * stored. + * @param local The local where the exception is stored. + * @return true if the operation succeeded. + */ + public boolean combineWithLocal(LocalInfo local) { + InstructionHeader next = nextInstruction; + if (this.local != null || successors[0] != next) + return false; + + this.local = local; + successors = next.successors; + nextInstruction = next.nextInstruction; + if (nextInstruction != null) + nextInstruction.prevInstruction = this; + + for (int i=0; i< successors.length; i++) { + successors[i].predecessors.removeElement(next); + successors[i].predecessors.addElement(this); + } + return true; + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (Decompiler.isDebugging) + dumpDebugging(writer); + + writer.println("} catch ("+typeString+" "+ + (local != null ? local.getName() + : (Object) "stack_0") + ") {"); + } +} + + diff --git a/jode/jode/expr/CombineIfGotoExpressions.java b/jode/jode/expr/CombineIfGotoExpressions.java new file mode 100644 index 0000000..240a08f --- /dev/null +++ b/jode/jode/expr/CombineIfGotoExpressions.java @@ -0,0 +1,51 @@ +package jode; +import java.util.Vector; + +public class CombineIfGotoExpressions implements Transformation{ + + public InstructionHeader transform(InstructionHeader ih2) { + InstructionHeader ih1; + Expression[] e; + int operator; + try { + if (ih2.getFlowType() != ih2.IFGOTO) + return null; + InstructionHeader[] dests2 = ih2.getSuccessors(); + + /* if ih2.getSimpleUniquePredecessor.getOperator().isVoid() XXX */ + + Vector predec = ih2.getPredecessors(); + if (predec.size() != 1) + return null; + + ih1 = (InstructionHeader) predec.elementAt(0); + if (ih1.getFlowType() != ih1.IFGOTO) + return null; + InstructionHeader[] dests1 = ih1.getSuccessors(); + if (dests1[0] != ih2) + return null; + + if (dests1[1] == dests2[0]) { + e = new Expression[2]; + operator = Operator.LOG_AND_OP; + e[1] = (Expression)ih2.getInstruction(); + e[0] = ((Expression)ih1.getInstruction()).negate(); + } else if (dests1[1] == dests2[1]) { + e = new Expression[2]; + operator = Operator.LOG_OR_OP; + e[1] = (Expression)ih2.getInstruction(); + e[0] = (Expression)ih1.getInstruction(); + } else + return null; + } catch (ClassCastException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + + Expression cond = + new Expression(new BinaryOperator(MyType.tBoolean, operator), e); + + return ih1.combineConditional(cond); + } +} diff --git a/jode/jode/expr/CompareBinaryOperator.java b/jode/jode/expr/CompareBinaryOperator.java index 3631697..2d2a4cd 100644 --- a/jode/jode/expr/CompareBinaryOperator.java +++ b/jode/jode/expr/CompareBinaryOperator.java @@ -25,13 +25,6 @@ public class CompareBinaryOperator extends SimpleOperator { return getPriority()+i; } - public void setOperandType(Type[] inputTypes) { - super.setOperandType(inputTypes); - Type operandType = - MyType.intersection(operandTypes[0],operandTypes[1]); - operandTypes[0] = operandTypes[1] = operandType; - } - public boolean equals(Object o) { return (o instanceof CompareBinaryOperator) && ((CompareBinaryOperator)o).operator == operator; diff --git a/jode/jode/expr/CompareUnaryOperator.java b/jode/jode/expr/CompareUnaryOperator.java index b865234..3c9adc3 100644 --- a/jode/jode/expr/CompareUnaryOperator.java +++ b/jode/jode/expr/CompareUnaryOperator.java @@ -2,9 +2,12 @@ package jode; import sun.tools.java.Type; public class CompareUnaryOperator extends SimpleOperator { + boolean objectType; + public CompareUnaryOperator(Type type, int op) { super(Type.tBoolean, op, 1); operandTypes[0] = type; + objectType = (type == MyType.tUObject); } public int getPriority() { @@ -31,8 +34,6 @@ public class CompareUnaryOperator extends SimpleOperator { } public String toString(String[] operands) { - return operands[0] + getOperatorString() + - (MyType.isOfType(operandTypes[0], - MyType.tObject)?"null":"0"); + return operands[0] + getOperatorString() + (objectType?"null":"0"); } } diff --git a/jode/jode/expr/ConstOperator.java b/jode/jode/expr/ConstOperator.java index 4e06b90..baaf3c0 100644 --- a/jode/jode/expr/ConstOperator.java +++ b/jode/jode/expr/ConstOperator.java @@ -6,6 +6,8 @@ public class ConstOperator extends NoArgOperator { public ConstOperator(Type type, String value) { super(type); + if (type == MyType.tString) + value = quoted(value); this.value = value; } @@ -17,10 +19,10 @@ public class ConstOperator extends NoArgOperator { return 1000; } - public String quoted(String str) { + public static String quoted(String str) { StringBuffer result = new StringBuffer("\""); - for (int i=0; i< value.length(); i++) { - switch (value.charAt(i)) { + for (int i=0; i< str.length(); i++) { + switch (str.charAt(i)) { case '\t': result.append("\\t"); break; @@ -34,7 +36,7 @@ public class ConstOperator extends NoArgOperator { result.append("\\\""); break; default: - result.append(value.charAt(i)); + result.append(str.charAt(i)); } } return result.append("\"").toString(); @@ -46,8 +48,6 @@ public class ConstOperator extends NoArgOperator { } public String toString(String[] operands) { - if (MyType.isOfType(type, Type.tString)) - return quoted(value); if (type == Type.tBoolean) { if (value.equals("0")) return "false"; diff --git a/jode/jode/expr/ConstantArrayOperator.java b/jode/jode/expr/ConstantArrayOperator.java index c5acf42..6ccca86 100644 --- a/jode/jode/expr/ConstantArrayOperator.java +++ b/jode/jode/expr/ConstantArrayOperator.java @@ -6,7 +6,7 @@ public class ConstantArrayOperator extends SimpleOperator { public ConstantArrayOperator(Type type, int size) { super(type, 0, size); for (int i=0; i< size; i++) - operandTypes[i] = type.getElementType(); + operandTypes[i] = MyType.tSubType(type.getElementType()); } public int getPriority() { diff --git a/jode/jode/expr/ConstructorOperator.java b/jode/jode/expr/ConstructorOperator.java index f9653ed..264e3fb 100644 --- a/jode/jode/expr/ConstructorOperator.java +++ b/jode/jode/expr/ConstructorOperator.java @@ -25,7 +25,7 @@ public class ConstructorOperator extends Operator { public Type getOperandType(int i) { if (i == 0) - return MyType.tSubType(type); + return field.getClassDeclaration().getType(); // or subtype? XXX return MyType.tSubType(field.getType().getArgumentTypes()[i-1]); } diff --git a/jode/jode/expr/CreateAssignExpression.java b/jode/jode/expr/CreateAssignExpression.java new file mode 100644 index 0000000..9a97d03 --- /dev/null +++ b/jode/jode/expr/CreateAssignExpression.java @@ -0,0 +1,67 @@ +package jode; + +public class CreateAssignExpression implements Transformation{ + + public InstructionHeader transform(InstructionHeader ih) { + InstructionHeader next = createAssignOp(ih); + if (next != null) + return next; + return createAssignExpression(ih); + } + + public InstructionHeader createAssignOp(InstructionHeader ih) { + Expression rightHandSide; + StoreInstruction store; + BinaryOperator binop; + try { + store = (StoreInstruction) ih.getInstruction(); + ih = ih.getSimpleUniquePredecessor(); + binop = (BinaryOperator) ih.getInstruction(); + if (binop.getOperator() < binop.ADD_OP || + binop.getOperator() >= binop.ASSIGN_OP) + return null; + ih = ih.getSimpleUniquePredecessor(); + rightHandSide = (Expression) ih.getInstruction(); + if (rightHandSide.isVoid()) + return null; /* XXX */ + ih = ih.getSimpleUniquePredecessor(); + Operator load = (Operator) ih.getInstruction(); + if (!store.matches(load)) + return null; + ih = ih.getSimpleUniquePredecessor(); + DupOperator dup = (DupOperator) ih.getInstruction(); + if (dup.getDepth() != 0 && + dup.getCount() != store.getLValueOperandCount()) + return null; + } catch (ClassCastException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + ih = ih.combine(3, rightHandSide); + InstructionHeader storeIH = ih.getNextInstruction(); + store.setOperator(store.OPASSIGN_OP+binop.getOperator()); + store.setLValueType(MyType.intersection(binop.getType(), + store.getLValueType())); + storeIH.combine(2, store); + return ih; + } + + public InstructionHeader createAssignExpression(InstructionHeader ih) { + StoreInstruction store; + try { + store = (StoreInstruction) ih.getInstruction(); + ih = ih.getSimpleUniquePredecessor(); + + DupOperator dup = (DupOperator) ih.getInstruction(); + if (dup.getDepth() != store.getLValueOperandCount() && + dup.getCount() != store.getLValueType().stackSize()) + return null; + } catch (NullPointerException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + return ih.combine(2, new AssignOperator(Operator.ASSIGN_OP, store)); + } +} diff --git a/jode/jode/expr/CreateExpression.java b/jode/jode/expr/CreateExpression.java new file mode 100644 index 0000000..a79300f --- /dev/null +++ b/jode/jode/expr/CreateExpression.java @@ -0,0 +1,36 @@ +package jode; + +public class CreateExpression implements Transformation { + + public InstructionHeader transform(InstructionHeader ih) { + Operator op; + Expression exprs[]; + int params; + try { + op = (Operator) ih.getInstruction(); + params = op.getOperandCount(); + exprs = new Expression[params]; + for (int i = params-1; i>=0; i--) { + ih = ih.getSimpleUniquePredecessor(); + exprs[i] = (Expression) ih.getInstruction(); + if (exprs[i].isVoid()) { + if (i == params-1) + return null; + Expression e = exprs[i+1].tryToCombine(exprs[i]); + if (e == null) + return null; + i++; + exprs[i] = e; + ih = ih.combine(2, e); + } + } + } catch (NullPointerException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + if(Decompiler.isVerbose && params > 0) + System.err.print("x"); + return ih.combine(params+1, new Expression(op, exprs)); + } +} diff --git a/jode/jode/expr/CreateIfThenElseOperator.java b/jode/jode/expr/CreateIfThenElseOperator.java new file mode 100644 index 0000000..8032d7f --- /dev/null +++ b/jode/jode/expr/CreateIfThenElseOperator.java @@ -0,0 +1,108 @@ +package jode; +import java.util.Enumeration; +import java.util.Vector; + +public class CreateIfThenElseOperator implements Transformation{ + + public InstructionHeader createFunny(InstructionHeader ih) { + Expression cond = null; + try { + InstructionHeader ifHeader= ih; + if (ifHeader.getFlowType() != ifHeader.IFGOTO) + return null; + CompareUnaryOperator compare = + (CompareUnaryOperator) ifHeader.getInstruction(); + if ((compare.getOperator() & ~1) != compare.EQUALS_OP) + return null; + Enumeration enum = ih.getPredecessors().elements(); + while (enum.hasMoreElements()) { + try { + ih = (InstructionHeader) enum.nextElement(); + Expression zeroExpr = (Expression) ih.getInstruction(); + ConstOperator zero = + (ConstOperator) zeroExpr.getOperator(); + if (!zero.getValue().equals("0")) + continue; + + ih = ih.getUniquePredecessor(); + if (ih.getFlowType() != ih.IFGOTO) + continue; + + if (compare.getOperator() == compare.EQUALS_OP && + ih.getSuccessors()[1] != ifHeader.getSuccessors()[0] + || compare.getOperator() == compare.NOTEQUALS_OP && + ih.getSuccessors()[1] != ifHeader.getSuccessors()[1]) + continue; + + cond = (Expression) ih.getInstruction(); + break; + } catch (ClassCastException ex) { + } catch (NullPointerException ex) { + } + } + + if (cond == null) + return null; + + } catch (ClassCastException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + + InstructionHeader next = ih.nextInstruction; + ih.successors[1].predecessors.removeElement(ih); + next.instr = ih.instr; + next.movePredecessors(ih); + return next; + } + + public InstructionHeader create(InstructionHeader ih) { + InstructionHeader ifHeader; + Expression e[] = new Expression[3]; + InstructionHeader[] succs; + try { + Vector predec = ih.getPredecessors(); + + if (predec.size() != 1) + return null; + ifHeader = (InstructionHeader) predec.elementAt(0); + if (ifHeader.getFlowType() != ifHeader.IFGOTO) + return null; + succs = ifHeader.getSuccessors(); + if (succs[1] != ih || + succs[0].getNextInstruction() != succs[1] || + succs[0].getSuccessors().length != 1 || + succs[1].getSuccessors().length != 1 || + succs[0].getSuccessors()[0] != succs[1].getSuccessors()[0]) + return null; + + e[0] = ((Expression) ifHeader.getInstruction()).negate(); + e[1] = (Expression) succs[0].getInstruction(); + if (e[1].isVoid()) + return null; + e[2] = (Expression) succs[1].getInstruction(); + if (e[2].isVoid()) + return null; + } catch (ClassCastException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + + IfThenElseOperator iteo = new IfThenElseOperator + (MyType.intersection(e[1].getType(),e[2].getType())); + + ih.instr = new Expression(iteo, e); + ih.movePredecessors(ifHeader); + ih.nextInstruction.predecessors.removeElement(ifHeader.successors[0]); + return ih; + } + + public InstructionHeader transform(InstructionHeader ih) { + InstructionHeader next = createFunny(ih); + if (next != null) + return next; + return create(ih); + } +} diff --git a/jode/jode/expr/CreatePostIncExpression.java b/jode/jode/expr/CreatePostIncExpression.java new file mode 100644 index 0000000..a0518e8 --- /dev/null +++ b/jode/jode/expr/CreatePostIncExpression.java @@ -0,0 +1,99 @@ +package jode; +import sun.tools.java.Type; + +public class CreatePostIncExpression implements Transformation { + + public InstructionHeader transform(InstructionHeader ih) + { + InstructionHeader next = createLocalPostInc(ih); + if (next != null) + return next; + return createPostInc(ih); + } + + public InstructionHeader createLocalPostInc(InstructionHeader ih) { + IIncOperator iinc; + int op; + Type type; + try { + Expression iincExpr = (Expression) ih.getInstruction(); + iinc = (IIncOperator) iincExpr.getOperator(); + if (iinc.getOperator() == iinc.ADD_OP + iinc.OPASSIGN_OP) + op = Operator.INC_OP; + else if (iinc.getOperator() == iinc.NEG_OP + iinc.OPASSIGN_OP) + op = Operator.DEC_OP; + else + return null; + if (!iinc.getValue().equals("1") && + !iinc.getValue().equals("-1")) + return null; + if (iinc.getValue().equals("-1")) + op ^= 1; + ih = ih.getSimpleUniquePredecessor(); + Expression loadExpr = (Expression) ih.getInstruction(); + LocalLoadOperator load = + (LocalLoadOperator)loadExpr.getOperator(); + if (!iinc.matches(load)) + return null; + + type = MyType.intersection(load.getType(), MyType.tUInt); + } catch (NullPointerException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + Operator postop = new LocalPostFixOperator(type, op, iinc); + return ih.combine(2, postop); + } + + public InstructionHeader createPostInc(InstructionHeader ih) { + StoreInstruction store; + int op; + Type type; + try { + store = (StoreInstruction) ih.getInstruction(); + if (store.getLValueOperandCount() == 0) + return null; + ih = ih.getSimpleUniquePredecessor(); + BinaryOperator binOp = (BinaryOperator) ih.getInstruction(); + if (binOp.getOperator() == store.ADD_OP) + op = Operator.INC_OP; + else if (store.getOperator() == store.NEG_OP) + op = Operator.DEC_OP; + else + return null; + ih = ih.getSimpleUniquePredecessor(); + Expression expr = (Expression) ih.getInstruction(); + ConstOperator constOp = (ConstOperator) expr.getOperator(); + if (!constOp.getValue().equals("1") && + !constOp.getValue().equals("-1")) + return null; + if (constOp.getValue().equals("-1")) + op ^= 1; + ih = ih.getSimpleUniquePredecessor(); + DupOperator dup = (DupOperator) ih.getInstruction(); + if (dup.getCount() != store.getLValueType().stackSize() || + dup.getDepth() != store.getLValueOperandCount()) + return null; + ih = ih.getSimpleUniquePredecessor(); + Operator load = (Operator) ih.getInstruction(); + + if (!store.matches(load)) + return null; + + ih = ih.getSimpleUniquePredecessor(); + DupOperator dup2 = (DupOperator) ih.getInstruction(); + if (dup2.getCount() != store.getLValueOperandCount() || + dup2.getDepth() != 0) + return null; + + type = MyType.intersection(load.getType(), store.getLValueType()); + } catch (NullPointerException ex) { + return null; + } catch (ClassCastException ex) { + return null; + } + Operator postop = new PostFixOperator(type, op, store); + return ih.combine(6, postop); + } +} diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java index 2f1cd96..3baf7f6 100644 --- a/jode/jode/expr/Expression.java +++ b/jode/jode/expr/Expression.java @@ -6,11 +6,13 @@ import sun.tools.java.FieldDefinition; public class Expression extends Instruction { Operator operator; Expression[] subExpressions; + Expression parent = null; public Expression(Operator op, Expression[] sub) { super(MyType.tUnknown); operator = op; subExpressions = sub; + operator.setExpression(this); if (subExpressions.length != op.getOperandCount()) throw new AssertError ("Operand count mismatch: "+ subExpressions.length + " != " + @@ -18,6 +20,7 @@ public class Expression extends Instruction { if (subExpressions.length > 0) { Type types[] = new Type[subExpressions.length]; for (int i=0; i < types.length; i++) { + subExpressions[i].parent = this; types[i] = subExpressions[i].getType(); } operator.setOperandType(types); @@ -95,10 +98,12 @@ public class Expression extends Instruction { } } - public void setType(Type type) { - if (operator.setType(type)) - updateSubTypes(); - this.type = operator.getType(); + public void setType(Type newType) { + newType = MyType.intersection(type, newType); + if (newType != type) { + type = newType; + operator.setType(type); + } } public boolean isVoid() { @@ -193,6 +198,38 @@ public class Expression extends Instruction { return subExpressions[0].negate().simplify(); } } +// if ((operator instanceof AssignOperator || +// operator instanceof StoreInstruction) && +// subExpressions[subExpressions.length-1] +// .operator instanceof ConstOperator) { +// StoreInstruction store; +// if (operator instanceof AssignOperator) +// store = ((AssignOperator)operator).getStore(); +// else +// store = (StoreInstruction)operator; + +// ConstOperator one = (ConstOperator) +// subExpressions[subExpressions.length-1].operator; + +// if ((operator.getOperator() == +// operator.OPASSIGN_OP+operator.ADD_OP || +// operator.getOperator() == +// operator.OPASSIGN_OP+operator.NEG_OP) && +// (one.getValue().equals("1") || +// one.getValue().equals("-1"))) { + +// int op = ((operator.getOperator() == +// operator.OPASSIGN_OP+operator.ADD_OP) == +// one.getValue().equals("1"))? +// operator.INC_OP : operator.DEC_OP; + +// return new Expression +// (new PostFixOperator +// (store.getType(), op, store, +// operator instanceof StoreInstruction), +// new Expression[0]).simplify(); +// } +// } if (operator instanceof CompareUnaryOperator && subExpressions[0].operator instanceof CompareToIntOperator) { CompareBinaryOperator newOp = new CompareBinaryOperator diff --git a/jode/jode/expr/IfInstructionHeader.java b/jode/jode/expr/IfInstructionHeader.java new file mode 100644 index 0000000..98f9567 --- /dev/null +++ b/jode/jode/expr/IfInstructionHeader.java @@ -0,0 +1,173 @@ +package jode; +import java.util.Enumeration; + +/** + * This instruction header represents an if instruction. The + * linkage of the instructions is as follow: + *
+ *  A: ....
+ * 

+ * prev = A, next = H, pred = normal, succ = {C,E} + * B: if ( instr ) { + *

+ * prev = null, next = D, pred = {B}, succ = {D} + * C: then-instr 1 + *

+ * prev = C, next = H!, pred = normal succ = normal + * D: instructions of then part + *

+ * } else { + *

+ * prev = null, next = D, pred = {B}, succ = {D} + * E: else-instr 1 + *

+ * prev = E, next = null, pred = normal, succ = normal + * F: instructions of then part + *

+ * } + * prev = B, ..., pred = normal, succ = normal + * H: ... + *

+ */ +public class IfInstructionHeader extends InstructionHeader { + + boolean hasElsePart; + + /** + * Creates a new if statement. There are several conditions that + * must be met: + *
    + *
  • ifHeader.successors[0] == thenStart + *
  • + *
  • ifHeader.successors[1] == thenEnd.nextInstruction + *
  • + *
  • elseStart == null || (thenEnd.flowType = GOTO && + * elseEnd.nextInstruction == thenEnd.successors[0]) + *
  • + *
  • elseStart == null || elseStart = thenEnd.nextInstruction + *
  • + *
  • thenStart.nextInstruction....nextInstruction = thenEnd + *
  • + *
  • elseStart.nextInstruction....nextInstruction = elseEnd + *
  • + *
+ * @param ifHeader the instruction header whichs contains the + * if goto statement. + * @param thenStart the start of the then part. + * @param thenEnd the end of the then part. + * @param elseStart the start of the else part. + * @param elseEnd the end of the then part. + * @param next the next instruction after the if statement. + */ + public IfInstructionHeader(InstructionHeader ifHeader, + boolean hasElsePart, + InstructionHeader thenEnd, + InstructionHeader elseEnd, + InstructionHeader endBlock) { + + super(IFSTATEMENT, ifHeader.addr, endBlock.addr, + ifHeader.successors, ifHeader.outer); + + this.instr = ((Expression)ifHeader.getInstruction()).negate(); + + this.movePredecessors(ifHeader); + this.outer = ifHeader.outer; + this.endBlock = endBlock; + successors[0].predecessors.removeElement(ifHeader); + successors[1].predecessors.removeElement(ifHeader); + successors[0].predecessors.addElement(this); + successors[1].predecessors.addElement(this); + + successors[0].prevInstruction = null; + InstructionHeader next = thenEnd.nextInstruction; + thenEnd.nextInstruction = null; + + for (InstructionHeader ih = successors[0]; ih != null; + ih = ih.nextInstruction) + if (ih.outer == outer) + ih.outer = this; + + this.hasElsePart = hasElsePart; + if (hasElsePart) { + thenEnd.flowType = thenEnd.NORMAL; + + successors[1].prevInstruction = null; + next = elseEnd.nextInstruction; + elseEnd.nextInstruction = null; + + for (InstructionHeader ih = successors[1]; ih != null; + ih = ih.nextInstruction) + if (ih.outer == outer) + ih.outer = this; + } + + this.nextInstruction = next; + if (next != null) + next.prevInstruction = this; + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (Decompiler.isDebugging) { + dumpDebugging(writer); + writer.tab(); + } + + if (needsLabel()) { + writer.untab(); + writer.println(getLabel()+": "); + writer.tab(); + } + + boolean braces = successors[0].flowType != NORMAL || + successors[0].nextInstruction != null; + writer.println("if (" + instr.toString() + ")" + (braces ? " {": "")); + + writer.tab(); + for (InstructionHeader ih = successors[0]; ih != null; + ih = ih.nextInstruction) + ih.dumpSource(writer); + writer.untab(); + + if (hasElsePart) { + if (braces) + writer.print("} "); + + braces = successors[1].flowType != NORMAL || + successors[1].nextInstruction != null; + + if (!braces && successors[1].flowType == IFSTATEMENT) { + writer.print("else "); + successors[1].dumpSource(writer); + } else { + writer.println("else" + (braces ? " {": "")); + writer.tab(); + for (InstructionHeader ih = successors[1]; + ih != null; ih = ih.nextInstruction) + ih.dumpSource(writer); + writer.untab(); + } + } + if (braces) + writer.println("} "); + + if (Decompiler.isDebugging) + writer.untab(); + } + + public InstructionHeader doTransformations(Transformation[] trafo) { + InstructionHeader next; + for (InstructionHeader ih = successors[0]; ih != null; ih = next) { + if ((next = ih.doTransformations(trafo)) == null) + next = ih.getNextInstruction(); + } + if (hasElsePart) { + for (InstructionHeader ih = successors[1]; ih != null; ih = next) { + if ((next = ih.doTransformations(trafo)) == null) + next = ih.getNextInstruction(); + } + } + return super.doTransformations(trafo); + } +} diff --git a/jode/jode/expr/InstructionHeader.java b/jode/jode/expr/InstructionHeader.java index 94ec185..65051b3 100644 --- a/jode/jode/expr/InstructionHeader.java +++ b/jode/jode/expr/InstructionHeader.java @@ -11,50 +11,131 @@ import sun.tools.java.Type; * @author Jochen Hoenicke */ public class InstructionHeader { - int addr, length; + public final static int METHOD =-1; + public final static int NORMAL = 0; + public final static int GOTO = 1; + public final static int IFGOTO = 2; + public final static int SWITCH = 3; + public final static int JSR = 4; + public final static int RET = 5; + public final static int RETURN = 6; + public final static int TRY = 7; + public final static int CATCH = 8; + public final static int IFSTATEMENT = 10; + public final static int WHILESTATEMENT = 11; + public final static int DOWHILESTATEMENT = 12; + public final static int FORSTATEMENT = 13; + public final static int TRYCATCHBLOCK = 14; + + public final static int EMPTY = 99; + + /** + * The flow type of the instruction header, this is one of the + * above constants. + */ + int flowType; + /** + * The address of this and the following instruction header. + */ + int addr, nextAddr; + /** + * The underlying instruction. This is null for some special + * instructions (depends on flowType). + */ Instruction instr; - InstructionHeader nextInstruction; + /** + * The instruction header representing the surrounding block. + */ + InstructionHeader outer = null; + /** + * A simple doubly linked list of instructions in code order + * (without caring about jump instructions). + */ + InstructionHeader nextInstruction, prevInstruction; + /** + * The first instruction after this block. This should be only + * set for blocks, that is headers which are outer of other headers. + * This gives the instruction where the control flows after this + * block. + */ + InstructionHeader endBlock; - Type switchType; - int[] cases; - int[] succs; + /** + * A more complex doubly linked list of instructions. The + * successors are the possible destinations of jump and switch + * instructions. The predecessors are the reverse things. + * The predeccors sits in a vector to make it easier to add + * or remove one, when creating or manipulating other instruction + * headers. + */ InstructionHeader[] successors; - Vector predecessors = new Vector(); - + /** - * Create a new InstructionHeader. - * @param addr The address of this Instruction. - * @param length The length of this Instruction. - * @param instr The underlying Instruction. + * The addresses of the successors of this header. This are + * resolved by resolveSuccessors and then deleted. */ - public InstructionHeader(int addr, int length, Instruction instr) { - int[] succs = { addr + length }; + int[] succs = null; + + /** + * Create a new InstructionHeader, that must be resolved later. + * @param flowType The type of this instruction header. + * @param addr The address of this instruction header. + * @param nextAddr The address of the next instruction header. + * @param instr The underlying Instruction. + * @param succs The successors of this instruction header + * (the addresses, are resolved later). + */ + protected InstructionHeader(int flowType, int addr, int nextAddr, + Instruction instr, int[] succs) { + this.flowType = flowType; this.addr = addr; - this.length = length; + this.nextAddr = nextAddr; this.instr = instr; - switchType = MyType.tVoid; - this.cases = new int[0]; this.succs = succs; } /** * Create a new InstructionHeader. - * @param addr The address of this Instruction. - * @param length The length of this Instruction. - * @param instr The underlying Instruction. - * @param type The type of the switch - * @param cases The possible cases - * @param succs The destinations (one longer for default) + * @param flowType The type of this instruction header. + * @param addr The address of this instruction header. + * @param nextAddr The address of the next instruction header. + * @param successors The successors of this instruction header. + * @param outer The instruction header of the surrounding block. */ - public InstructionHeader(int addr, int length, Instruction instr, - Type type, int[] cases, int[] succs) { + protected InstructionHeader(int flowType, int addr, int nextAddr, + InstructionHeader[] successors, + InstructionHeader outer) { + this.flowType = flowType; this.addr = addr; - this.length = length; + this.nextAddr = nextAddr; this.instr = instr; - switchType = type; - this.cases = cases; - this.succs = succs; + this.successors = successors; + this.outer = outer; + } + + /** + * Create a new InstructionHeader of zero length. + * @param flowType The type of this instruction header. + * @param addr The address of this Instruction. + * @param outer The instruction header of the surrounding block. + */ + protected InstructionHeader(int flowType, int addr, + InstructionHeader outer) { + this(flowType, addr, addr, new InstructionHeader[0], outer); + } + + /** + * Create an InstructionHeader for a normal instruction. + * @param addr The address of this instruction. + * @param length The length of this instruction. + * @param instr The underlying Instruction. + */ + public static InstructionHeader createNormal(int addr, int length, + Instruction instr) { + int[] succs = { addr + length }; + return new InstructionHeader(NORMAL, addr, addr + length, + instr, succs); } /** @@ -63,10 +144,10 @@ public class InstructionHeader { * @param length The length of this instruction. * @param instr The underlying Instruction. */ - public static InstructionHeader ret(int addr, int length, - Instruction instr) { - return new InstructionHeader (addr, length, instr, - MyType.tVoid, new int[0], new int[0]); + public static InstructionHeader createReturn(int addr, int length, + Instruction instr) { + return new InstructionHeader(RETURN, addr, addr + length, + instr, new int[0]); } /** @@ -76,11 +157,11 @@ public class InstructionHeader { * @param instr The underlying Instruction. * @param dest The destination address of the jump. */ - public static InstructionHeader jump(int addr, int length, int dest, - Instruction instr) { + public static InstructionHeader createGoto(int addr, int length, int dest, + Instruction instr) { int [] succs = { dest }; - return new InstructionHeader (addr, length, instr, - MyType.tVoid, new int[0], succs); + return new InstructionHeader (GOTO, addr, addr + length, + instr, succs); } /** @@ -90,21 +171,80 @@ public class InstructionHeader { * @param instr The underlying Instruction. * @param dest The destination address of the jump. */ - public static InstructionHeader conditional(int addr, int length, int dest, - Instruction instr) { - int[] cases = { 0 }; + public static InstructionHeader createIfGoto(int addr, int length, + int dest, Instruction instr) { int[] succs = { addr+length , dest }; - return new InstructionHeader (addr, length, instr, - MyType.tBoolean, cases, succs); + return new InstructionHeader (IFGOTO, addr, addr + length, + instr, succs); } + /** + * Create an InstructionHeader for a switch. + * @param addr The address of this Instruction. + * @param length The length of this Instruction. + * @param instr The underlying Instruction. + * @param cases The possible cases + * @param succs The destinations (one longer for default) + */ + public static InstructionHeader createSwitch(int addr, int length, + Instruction instr, + int[] cases, int[] succs) { + InstructionHeader ih = + new SimpleSwitchInstructionHeader(addr, addr+length, instr, + cases, succs); + return ih; + } + + static int ids =0; + int id = -1; public String toString() { - return instr.toString(); + if (id == -1) id = ids++; + return addr+"__"+id; + } + + /** + * Returns the InstructionHeader where a break of this instruction + * would jump to. Does only make sense for do/while/for-loops and + * switch instructions. + */ + public InstructionHeader getBreak() { + return null; } /** - * Get the address of this instruction. - * @return The address. + * Returns the InstructionHeader where a continue of this instruction + * would jump to. Does only make sense for do/while/for-loops. + */ + public InstructionHeader getContinue() { + return null; + } + + /** + * Get the flow type of this instruction. + * @return the flow type. + */ + public int getFlowType() { + return flowType; + } + + static int serialnr = 0; + String label = null; + + /** + * Get the label of this instruction. It is created on the fly + * if it didn't exists before. + * @return the label. + */ + public String getLabel() { + if (label == null) + label = "label_" + serialnr++; + return label; + } + + /** + * Get the address of this instruction. This is probably only useful + * for debugging purposes. + * @return the address. */ public int getAddress() { return addr; @@ -112,25 +252,33 @@ public class InstructionHeader { /** * Get the next address in code order. - * @return The next instruction + * @return the next instruction */ public int getNextAddr() { - return addr+length; + return nextAddr; } /** * Get the underlying instruction. - * @return The underlying instruction. + * @return the underlying instruction. */ public Instruction getInstruction() { return instr; } + /** + * Set the underlying instruction. + * @param instr the underlying instruction. + */ + public void setInstruction(Instruction instr) { + this.instr = instr; + } + /** * Get the next instruction in code order. This function mustn't * be called before resolveSuccessors is executed for this * InstructionHeaders. - * @return The next instruction + * @return the next instruction */ public InstructionHeader getNextInstruction() { return nextInstruction; @@ -146,10 +294,22 @@ public class InstructionHeader { return successors; } - public boolean hasDirectPredecessor() { - return predecessors.size() == 1 && - ((InstructionHeader)predecessors.elementAt(0)). - getNextInstruction() == this; + /** + * Returns true if this instruction header needs a label. + */ + protected boolean needsLabel() { + /* An instruction my have only one prevInstruction, but + * may have more then one predecessor that has its + * nextInstruction pointing to us. + */ + for (int i=0; i preds: "); + for (int i=0; i0) writer.print(", "); + writer.print(""+predecessors.elementAt(i)); + } + writer.println(""); + writer.print("outend: "+outer.endBlock+ + " prev: "+prevInstruction+", next: "+ nextInstruction + + " succs: "); + for (int i=0; i0) writer.print(", "); + writer.print(""+successors[i]); + } + writer.println(""); + } + + public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { - if (writer.verbosity > 5) { - writer.println("<"+addr + " - "+(addr+length-1)+">"); + if (Decompiler.isDebugging) { + dumpDebugging(writer); writer.tab(); } - -// writer.print("predecs: "); -// for (int i=0; i0) writer.print(", "); -// writer.print(""+((InstructionHeader)predecessors.elementAt(i)). -// getAddress()); -// } -// writer.println(""); - - if (!hasDirectPredecessor() && addr != 0) - writer.print("addr_"+addr+": "); - - if (switchType == MyType.tBoolean) { - - writer.println("if ("+instr.toString()+") goto addr_"+succs[1]); - if (succs[0] != addr + length) - writer.println("goto addr_"+succs[0]); - - } else if (switchType == MyType.tVoid) { - - if (instr.getType() != MyType.tVoid) - writer.print("push "); - writer.println(instr.toString()+";"); - if (succs.length > 0 && succs[0] != addr + length) - writer.println("goto addr_"+succs[0]); + + if (needsLabel()) { + writer.untab(); + writer.println(getLabel()+": "); + writer.tab(); + } + + if (flowType == IFGOTO) { + + writer.println("if ("+instr.toString()+") goto "+ + successors[1].getLabel()); } else { - writer.println("switch ("+instr.toString()+") {"); - writer.tab(); - writer.untab(); + + if (flowType != EMPTY) { + if (!(instr instanceof NopOperator)) { + if (instr.getType() != MyType.tVoid) + writer.print("push "); + writer.println(instr.toString()+";"); + } + if (flowType == GOTO) + writer.println("goto "+successors[0].getLabel()); + } + } - if (writer.verbosity > 5) + if (Decompiler.isDebugging) writer.untab(); } + + /** + * Moves the predecessors from the InstructionHeader from to + * the current instruction. The current predecessors are overwritten + * and you must make sure that no live InstructionHeader points to + * the current.

+ * The predecessors of from are informed about this change. + * @param from The instruction header which predecessors are moved. + */ + public void movePredecessors(InstructionHeader from) { + addr = from.addr; + prevInstruction = from.prevInstruction; + if (prevInstruction != null) + prevInstruction.nextInstruction = this; + + predecessors = from.predecessors; + for (int i=0; i < predecessors.size(); i++) { + InstructionHeader pre = + (InstructionHeader)predecessors.elementAt(i); + + for (int j=0; jcount void for an unconditional Jsr. */ public JsrInstructionHeader(int addr, int length, int dest, - Instruction instr) { - super(addr,length, instr); + Instruction instr, int[] succs) { + super(JSR, addr, addr+length, instr, succs); this.dest = dest; } - /** - * Get the successors of this instructions. This function mustn't - * be called before resolveSuccessors is executed for this - * InstructionHeaders. - * @return Array of successors. - */ - public InstructionHeader[] getSuccessors() { - InstructionHeader[] result = { destination }; - return result; - } - /** * Resolve the successors and predecessors and build a doubly * linked list. @@ -43,7 +32,7 @@ public class JsrInstructionHeader extends InstructionHeader { * by addresses. */ public void resolveSuccessors(InstructionHeader[] instHeaders) { - nextInstruction = instHeaders[addr+length]; + nextInstruction = instHeaders[nextAddr]; destination = instHeaders[dest]; destination.predecessors.addElement(this); /* Ret.successors.addElement(nextInstruction); XXX */ diff --git a/jode/jode/expr/MethodInstructionHeader.java b/jode/jode/expr/MethodInstructionHeader.java index bf6634d..c0f41ad 100644 --- a/jode/jode/expr/MethodInstructionHeader.java +++ b/jode/jode/expr/MethodInstructionHeader.java @@ -1,35 +1,91 @@ package jode; import java.util.Vector; +import sun.tools.java.BinaryExceptionHandler; +import sun.tools.java.Type; /** * This class is the end point of the InstructionHeader list. * @author Jochen Hoenicke */ public class MethodInstructionHeader extends InstructionHeader { + InstructionHeader first, last; + /** * Create a new InstructionHeader. * @param addr The address of this Instruction. * @param length The length of this Instruction. * @param instr The underlying Instruction. */ - public MethodInstructionHeader(InstructionHeader[] instr) { - super(-1,1,null); - nextInstruction = instr[0]; - nextInstruction.predecessors.addElement(this); - for (int addr = 0; addr < instr.length; ) { + public MethodInstructionHeader(JodeEnvironment env, + InstructionHeader[] instr, + BinaryExceptionHandler[] handlers) { + super(METHOD, 0, instr.length, new InstructionHeader[0], null); + first = new InstructionHeader(EMPTY, 0, this); + last = new InstructionHeader(EMPTY, instr.length, this); + + first.nextInstruction = instr[0]; + instr[0].prevInstruction = first; + + for (int addr = 0; ; addr = instr[addr].nextAddr) { + + instr[addr].outer = this; instr[addr].resolveSuccessors(instr); - if (instr[addr].succs.length == 0) - predecessors.addElement(instr[addr]); - addr = instr[addr].getNextAddr(); + + if (instr[addr].flowType == RETURN) { + InstructionHeader[] lastArr = { last }; + instr[addr].successors = lastArr; + last.predecessors.addElement(instr[addr]); + } + + if (instr[addr].nextAddr == instr.length) { + instr[addr].nextInstruction = last; + last.prevInstruction = instr[addr]; + break; + } + } + for (int i=0; i + * A: .... + *

+ * prev = A, next = H, pred = normal, succ = {C,E} + * B: try { + *

+ * prev = null, next = D, pred = {B}, succ = {D} + * C: then-instr 1 + *

+ * prev = C, next = H!, pred = normal succ = normal + * D: instructions of then part + *

+ * } catch (...) { + *

+ * prev = null, next = D, pred = {B}, succ = {D} + * E: else-instr 1 + *

+ * prev = E, next = null, pred = normal, succ = normal + * F: instructions of then part + *

+ * } + * prev = B, ..., pred = normal, succ = normal + * H: ... + * + * + * TODO: Implement finally. + */ +public class TryCatchInstructionHeader extends InstructionHeader { + + /** + * Creates a try catch statement. There are several conditions that + * must be met: + *

    + *
  • + *
  • + *
+ * @param successors the successors of this try, that is + * the try header and the catch headers. + * @param endHeader the end hader of the first try block. + * This must be successors[1] or a single goto or return + * statement jumping to endBlock. + * @param remaining the remaining successors of the old try header. + * @param endBlock the endBlock of this try statement + */ + public TryCatchInstructionHeader(InstructionHeader[] successors, + InstructionHeader endHeader, + InstructionHeader[] remaining, + InstructionHeader endBlock) { + + super(TRYCATCHBLOCK, successors[0].addr, endBlock.addr, + successors, successors[0].outer); + + InstructionHeader tryHeader = successors[0]; + this.movePredecessors(tryHeader); + if (remaining.length > 1) { + tryHeader.predecessors = new Vector(); + tryHeader.predecessors.addElement(this); + tryHeader.prevInstruction = null; + tryHeader.successors = remaining; + } else { + successors[0] = tryHeader.nextInstruction; + if (successors[0] != null) { + successors[0].prevInstruction = null; + successors[0].predecessors.addElement(this); + } + } + this.endBlock = endBlock; + this.nextInstruction = (endBlock.outer == outer) ? endBlock : null; + if (nextInstruction != null) + endBlock.prevInstruction = this; + + if (endHeader != successors[1]) + endHeader.successors[0].predecessors.removeElement(endHeader); + + for (int i=1; i< successors.length; i++) { + endHeader.predecessors.removeElement(tryHeader); + successors[i].predecessors.removeElement(tryHeader); + successors[i].predecessors.addElement(this); + } + + for (InstructionHeader ih = successors[0]; ih != null; + ih = ih.nextInstruction) { + if (ih.outer == outer) + ih.outer = this; + if (ih.nextInstruction == endHeader) + ih.nextInstruction = null; + } + for (int i=1; i< successors.length; i++) { + for (InstructionHeader ih = successors[i]; ih != null; + ih = ih.nextInstruction) { + if (ih.outer == outer) + ih.outer = this; + if ((i < successors.length-1 && + ih.nextInstruction == successors[i+1]) + || ih.nextInstruction == endBlock) + + ih.nextInstruction = null; + + if (ih.nextInstruction == null && + (ih.flowType == GOTO || + (ih.flowType == RETURN && + ih.getInstruction().getType() == MyType.tVoid)) && + ih.successors[0] == endBlock) + + ih.flowType = NORMAL; + } + } + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (Decompiler.isDebugging) { + dumpDebugging(writer); + writer.tab(); + } + + if (needsLabel()) { + writer.untab(); + writer.println(getLabel()+": "); + writer.tab(); + } + + writer.println("try {"); + writer.tab(); + if (successors[0] == null) + writer.print("/* empty */"); + else { + for (InstructionHeader ih = successors[0]; ih != null; + ih = ih.nextInstruction) + ih.dumpSource(writer); + } + writer.untab(); + + for (int i=1; i< successors.length; i++) { + InstructionHeader catchIH = successors[i]; + catchIH.dumpSource(writer); + + writer.tab(); + if (catchIH.nextInstruction == null) + writer.println("/* empty */"); + else { + for (InstructionHeader ih = catchIH.nextInstruction; + ih != null; ih = ih.nextInstruction) + ih.dumpSource(writer); + } + writer.untab(); + } + writer.println("} "); + + if (Decompiler.isDebugging) + writer.untab(); + } + + public InstructionHeader doTransformations(Transformation[] trafo) { + InstructionHeader next; + for (int i=0; i < successors.length; i++) { + for (InstructionHeader ih = successors[i]; ih != null; ih = next) { + if ((next = ih.doTransformations(trafo)) == null) + next = ih.getNextInstruction(); + } + } + return null; + } +} diff --git a/jode/jode/expr/TryInstructionHeader.java b/jode/jode/expr/TryInstructionHeader.java new file mode 100644 index 0000000..4399329 --- /dev/null +++ b/jode/jode/expr/TryInstructionHeader.java @@ -0,0 +1,54 @@ +package jode; +import java.util.Vector; + +public class TryInstructionHeader extends InstructionHeader { + + TryInstructionHeader(InstructionHeader firstInstr, + InstructionHeader outer) { + super(TRY, firstInstr.addr, firstInstr.addr, + new InstructionHeader[1], outer); + + movePredecessors(firstInstr); + successors[0] = firstInstr; + firstInstr.predecessors = new Vector(); + firstInstr.predecessors.addElement(this); + + prevInstruction = firstInstr.prevInstruction; + if (prevInstruction != null) + prevInstruction.nextInstruction = this; + + nextInstruction = firstInstr; + firstInstr.prevInstruction = this; + } + + public void addHandler(InstructionHeader endInstr, + InstructionHeader catchInstr) { + InstructionHeader[] newSuccessors = + new InstructionHeader[successors.length+2]; + System.arraycopy(successors, 0, newSuccessors, 0, successors.length); + successors = newSuccessors; + successors[successors.length-2] = endInstr; + successors[successors.length-1] = catchInstr; + endInstr.predecessors.addElement(this); + catchInstr.predecessors.addElement(this); + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (Decompiler.isDebugging) + dumpDebugging(writer); + + if (successors.length > 1) { + writer.print ("try: "); + for (int i=1; i + * A: .... + *

+ * prev = A, next = H or null, pred = normal, succ = {H,C} + * B: while ( instr ) { + *

+ * prev = null, next = D, pred = {B}, succ = {D} + * C: first block-instr + *

+ * prev = C, next = E, pred = normal succ = normal + * D: ... + *

+ * prev = D, next = null, pred = normal succ = {B} + * E: last block-instr + * } + *

+ * prev = B, ..., pred = (normal+{G}) \ {C..F}, succ = normal + * H: ... + * + */ +public class WhileInstructionHeader extends InstructionHeader { + /** + * Creates a new while statement. + * @param prev the goto instruction in front of this while loop. + * @param ifHeader the instruction header which contains the + * if-goto statement. + * @param blockStart the start of the inner block. + * @param blockEnd the end of the inner block. + * @param next the instruction header after this if block. + */ + public WhileInstructionHeader(InstructionHeader prev, + InstructionHeader ifHeader, + InstructionHeader block) { + + super(WHILESTATEMENT, + ifHeader.successors[1].addr, ifHeader.successors[0].addr, + ifHeader.successors, ifHeader.outer); + + this.instr = ifHeader.instr; + + this.outer = ifHeader.outer; + this.endBlock = this; + + this.movePredecessors(ifHeader); + this.addr = successors[1].addr; + prev.flowType = NORMAL; + + this.prevInstruction = successors[1].prevInstruction; + if (prevInstruction != null) + prevInstruction.nextInstruction = this; + + this.nextInstruction = ifHeader.nextInstruction; + if (nextInstruction != null) + nextInstruction.prevInstruction = this; + + successors[1].prevInstruction = null; + ifHeader.prevInstruction.nextInstruction = null; + + successors[0].predecessors.removeElement(ifHeader); + successors[1].predecessors.removeElement(ifHeader); + successors[0].predecessors.addElement(this); + successors[1].predecessors.addElement(this); + + for (InstructionHeader ih = successors[1]; ih != null; + ih = ih.nextInstruction) + if (ih.outer == outer) + ih.outer = this; + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (Decompiler.isDebugging) { + dumpDebugging(writer); + writer.tab(); + } + + if (needsLabel()) { + writer.untab(); + writer.println(getLabel()+": "); + writer.tab(); + } + + boolean braces = successors[1].nextInstruction != null; + writer.println("while (" + instr.toString() + ")" + + (braces ? " {": "")); + + writer.tab(); + for (InstructionHeader ih = successors[1]; ih != null; + ih = ih.nextInstruction) + ih.dumpSource(writer); + writer.untab(); + + if (braces) + writer.println("} "); + + if (Decompiler.isDebugging) + writer.untab(); + } + + /** + * Returns the InstructionHeader where a break of this instruction + * would jump to. Does only make sense for do/while/for-loops and + * switch instructions. + */ + public InstructionHeader getBreak() { + return successors[0]; + } + + /** + * Returns the InstructionHeader where a continue of this instruction + * would jump to. Does only make sense for do/while/for-loops. + */ + public InstructionHeader getContinue() { + return this; + } + + public InstructionHeader doTransformations(Transformation[] trafo) { + InstructionHeader next; + for (InstructionHeader ih = successors[1]; ih != null; ih = next) { + if ((next = ih.doTransformations(trafo)) == null) + next = ih.getNextInstruction(); + } + return super.doTransformations(trafo); + } +} diff --git a/jode/jode/type/ClassRangeType.java b/jode/jode/type/ClassRangeType.java index dba967c..7f7f07d 100644 --- a/jode/jode/type/ClassRangeType.java +++ b/jode/jode/type/ClassRangeType.java @@ -239,9 +239,9 @@ public class ClassRangeType extends MyType { if (t1.getTypeCode() <= 4 && t2.getTypeCode() <= 4) { if (t1.getTypeCode() < t2.getTypeCode()) - return t2; - else return t1; + else + return t2; } if ((t1.getTypeCode() != 9 && t1.getTypeCode() != 10) || (t1.getTypeCode() != 9 && t1.getTypeCode() != 10)) @@ -315,10 +315,12 @@ public class ClassRangeType extends MyType { Type top = getGeneralizedType(topType, type.topType); Type newType = createRangeType(bottom,top); - if (newType == tError) + if (newType == tError) { System.err.println("intersecting "+ this +" and "+ type + " to <" + bottom + "-" + top + "> to "); + Thread.dumpStack(); + } return newType; } diff --git a/jode/jode/type/MyType.java b/jode/jode/type/MyType.java index 4d37446..d8c696d 100644 --- a/jode/jode/type/MyType.java +++ b/jode/jode/type/MyType.java @@ -97,6 +97,12 @@ public class MyType extends Type { // System.err.println("intersecting "+ t1 +" and "+ t2); /* Trivial cases first. */ + if (t1 == tError || t2 == tError) { + System.err.println("intersecting "+ t1 +" and "+ t2 + + " to "); + Thread.dumpStack(); + return tError; + } if (t1 == t2 || t2 == tUnknown) return t1; if (t1 == tUnknown) @@ -126,6 +132,7 @@ public class MyType extends Type { if (t1.getTypeCode() != 103 || t2.getTypeCode() != 103) { System.err.println("intersecting "+ t1 +" and "+ t2 + " to "); + Thread.dumpStack(); return tError; }