diff --git a/jode/CreateBreakStatement.java b/jode/CreateBreakStatement.java index 038fcdc..70ce7d3 100644 --- a/jode/CreateBreakStatement.java +++ b/jode/CreateBreakStatement.java @@ -4,12 +4,26 @@ public class CreateBreakStatement implements Transformation { public InstructionHeader transform(InstructionHeader ih) { InstructionHeader breakDest; if (ih.getFlowType() == ih.GOTO) - breakDest = ih.successors[0]; + breakDest = ih.successors[0].getShadow(); else if (ih.getFlowType() == ih.IFGOTO) - breakDest = ih.successors[1]; + breakDest = ih.successors[1].getShadow(); else return null; + if (breakDest == ih.getEndBlock()) { + /* This is an unnecessary goto, remove it. + */ + if (ih.prevInstruction != null) + ih.prevInstruction.nextInstruction = ih.nextInstruction; + if (ih.nextInstruction != null) + ih.nextInstruction.prevInstruction = ih.prevInstruction; + breakDest.addPredecessors(ih); + breakDest.predecessors.removeElement(ih); + if (Decompiler.isVerbose) + System.err.print("g"); + return null; + } + boolean needBreakLabel = false, needContLabel = false; InstructionHeader outer = ih.outer; while (outer != null) { @@ -17,13 +31,19 @@ public class CreateBreakStatement implements Transformation { if (Decompiler.isVerbose) System.err.print("b"); return new BreakInstructionHeader - (ih, needBreakLabel?outer.getLabel(): null, true); + (ih.BREAK, ih, needBreakLabel?outer.getLabel(): null); } if (outer.getContinue() == breakDest) { if (Decompiler.isVerbose) - System.err.print("b"); + System.err.print("c"); + return new BreakInstructionHeader + (ih.CONTINUE, ih, needContLabel?outer.getLabel(): null); + } + if (outer.outer == null && outer.getEndBlock() == breakDest) { + if (Decompiler.isVerbose) + System.err.print("r"); return new BreakInstructionHeader - (ih, needContLabel?outer.getLabel(): null, false); + (ih.VOIDRETURN, ih, null); } if (outer.getBreak() != null) needBreakLabel = true; diff --git a/jode/CreateConstantArray.java b/jode/CreateConstantArray.java index b113c30..f8cff1c 100644 --- a/jode/CreateConstantArray.java +++ b/jode/CreateConstantArray.java @@ -4,39 +4,20 @@ import sun.tools.java.Type; public class CreateConstantArray implements Transformation { public InstructionHeader transform(InstructionHeader ih) { - Expression[] consts; - int count; + Expression[] consts = null; + int count = 0; 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 = + int lastindex = -1; + while (ih.getInstruction() instanceof ArrayStoreOperator) { + ArrayStoreOperator store = (ArrayStoreOperator) ih.getInstruction(); ih = ih.getSimpleUniquePredecessor(); - lastconst = (Expression) ih.getInstruction(); + Expression lastconst = (Expression) ih.getInstruction(); ih = ih.getSimpleUniquePredecessor(); Expression indexexpr = (Expression) ih.getInstruction(); ConstOperator indexop = @@ -44,23 +25,34 @@ public class CreateConstantArray implements Transformation { if (!MyType.isOfType(indexop.getType(), MyType.tUInt)) return null; int index = Integer.parseInt(indexop.getValue()); - if (index > lastindex) + if (index > 0 && consts == null) { + lastindex = index; + consts = new Expression[lastindex+1]; + } else if (index < 0 || index > lastindex) return null; - while (index < lastindex) { - consts[lastindex] = new Expression - (new ConstOperator(MyType.tUnknown, ""), - new Expression[0]); - lastindex--; - } - consts[lastindex] = lastconst; + else { + while (index < lastindex) { + consts[lastindex--] = new Expression + (new ConstOperator(MyType.tUnknown, "0"), + new Expression[0]); + } + } + consts[lastindex--] = lastconst; ih = ih.getSimpleUniquePredecessor(); - dup = (DupOperator) ih.getInstruction(); + DupOperator dup = (DupOperator) ih.getInstruction(); if (dup.getDepth() != 0 || dup.getCount() != store.getLValueType().stackSize()) return null; count++; + ih = ih.getSimpleUniquePredecessor(); + } + if (count == 0) + return null; + while (lastindex >= 0) { + consts[lastindex--] = new Expression + (new ConstOperator(MyType.tUnknown, "0"), + new Expression[0]); } - ih = ih.getSimpleUniquePredecessor(); Expression newArrayExpr = (Expression) ih.getInstruction(); NewArrayOperator newArrayOp = (NewArrayOperator) newArrayExpr.getOperator(); @@ -73,13 +65,25 @@ public class CreateConstantArray implements Transformation { (ConstOperator) countexpr.getOperator(); if (!MyType.isOfType(countop.getType(), MyType.tUInt)) return null; - if (Integer.parseInt(countop.getValue()) != consts.length) - return null; + int arraylength = Integer.parseInt(countop.getValue()); + if (arraylength != consts.length) { + if (arraylength < consts.length) + return null; + Expression[] newConsts = new Expression[arraylength]; + System.arraycopy(consts, 0, newConsts, 0, consts.length); + for (int i=consts.length; i= next.addr) { - 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) { + /* this is a normal if-then-else that is + * fully contained in this block. + */ + elseBlock = next; + next = UnoptimizeWhileLoops(thenEnd.successors[0]); + + } else if (thenEnd.successors[0].getShadow() == + ifgoto.outer.getEndBlock()) { + /* this is a normal if-then-else that goes + * to the end of the block. + * + * Again this may also be a continue/break statement, + * but again, who knows. + */ + elseBlock = next; + next = null; + } } - /* XXX return error or create if-then? - */ - if (elseEnd == null) - return null; } + + /* This was all, the rest is done in the constructor of + * IfInstructionHeader. + */ if(Decompiler.isVerbose) System.err.print("i"); return new IfInstructionHeader - (ifgoto, elseStart != null, thenEnd, elseEnd, endBlock); + (ifgoto, elseBlock, next); } } diff --git a/jode/CreateSwitchStatements.java b/jode/CreateSwitchStatements.java index e14a6a8..71af9a5 100644 --- a/jode/CreateSwitchStatements.java +++ b/jode/CreateSwitchStatements.java @@ -1,7 +1,8 @@ package jode; import java.util.Enumeration; -public class CreateSwitchStatements implements Transformation { +public class CreateSwitchStatements extends FlowTransformation +implements Transformation { public InstructionHeader transform(InstructionHeader ih) { if (ih.getFlowType() != ih.SWITCH) @@ -14,8 +15,6 @@ public class CreateSwitchStatements implements Transformation { int addr = switchIH.nextInstruction.addr; int count = 1; for (int i=0; i < switchIH.successors.length; i++) { - if (switchIH.successors[i].addr < addr) - return null; if (switchIH.successors[i] != switchIH.successors[defaultCase]) count ++; } @@ -27,6 +26,15 @@ public class CreateSwitchStatements implements Transformation { if (i != defaultCase && switchIH.successors[i] == switchIH.successors[defaultCase]) continue; + + InstructionHeader next = + UnoptimizeWhileLoops(switchIH.successors[i]); + if (next != switchIH.successors[i]) { + switchIH.successors[i].predecessors.removeElement(switchIH); + switchIH.successors[i] = next; + switchIH.successors[i].predecessors.addElement(switchIH); + } + int insert; for (insert = 0; insert < count; insert++) { if (sorted[insert].addr > switchIH.successors[i].addr) @@ -45,34 +53,120 @@ public class CreateSwitchStatements implements Transformation { sorted[insert] = switchIH.successors[i]; count++; } - InstructionHeader endBlock = switchIH.outer.endBlock; - ih = sorted[count-1]; - if (ih.outer == switchIH.outer) { + + InstructionHeader endBlock = switchIH.outer.getEndBlock(); + int lastBlock; + for (lastBlock = count-1; lastBlock>= 0; lastBlock--) + if (sorted[lastBlock].outer == switchIH.outer) + break; + + if (lastBlock >= 0) { EndSearch: + ih = sorted[lastBlock]; while (ih != null) { - Enumeration enum = ih.getPredecessors().elements(); + Enumeration enum; + if (ih.flowType == ih.GOTO) + enum = ih.successors[0].getPredecessors().elements(); + else + enum = ih.getPredecessors().elements(); while (enum.hasMoreElements()) { InstructionHeader pred = (InstructionHeader)enum.nextElement(); - if (pred.addr < sorted[count-1].addr && + if (pred.addr < sorted[lastBlock].addr && + pred.outer == switchIH.outer && (pred.flowType == ih.GOTO || (pred.flowType == ih.IFGOTO && - pred.successors[1] == ih))) { + pred.successors[1] == ih)) && + ih == UnoptimizeWhileLoops(ih)) { endBlock = ih; - break EndSearch; + /* search further down, if there are other + * more suitible instructions. + */ } } -// if (ih.flowType == ih.GOTO) { -// /* XXX: while loops in default part versus -// * while loops after switches -// */ -// endBlock = ih.successors[0]; -// break EndSearch; -// } ih = ih.nextInstruction; } - } else - endBlock = ih; + } + + for (int i=0; i< sorted.length; i++) { + if (sorted[i].outer != switchIH.outer) { + if (sorted[i].getShadow() != endBlock) { + /* Create a new goto at the beginning of + * the switch statement, jumping to the right + * successor. + */ + InstructionHeader[] successors = { sorted[i] }; + InstructionHeader dummyGoto = + new InstructionHeader(switchIH.GOTO, + switchIH.addr, switchIH.addr, + successors, switchIH.outer); + sorted[i].predecessors.addElement(dummyGoto); + + /* Connect it in the prev/next Instruction chain. + */ + dummyGoto.nextInstruction = switchIH.nextInstruction; + if (dummyGoto.nextInstruction != null) + dummyGoto.nextInstruction.prevInstruction = dummyGoto; + switchIH.nextInstruction = dummyGoto; + dummyGoto.prevInstruction = switchIH; + + /* Search all instructions that jump to this point and + * stack them together. + */ + int length = 1; + while (i+length < sorted.length && + sorted[i+length] == sorted[i]) + length++; + + /* Move them to the beginning of this array. + */ + System.arraycopy(sorted, 0, sorted, length, i); + + int[] tmp = new int[length]; + System.arraycopy(cases, i, tmp, 0, length); + System.arraycopy(cases, 0, cases, length, i); + System.arraycopy(tmp, 0, cases, 0, length); + + if (defaultCase < i) + defaultCase += length; + else if (defaultCase <= i+length) + defaultCase -= i; + for (int j=0; j0; j--) + sorted[sorted.length-j] = endBlock; + + int[] tmp = new int[length]; + System.arraycopy(cases, i, tmp, 0, length); + System.arraycopy(cases, i + length, cases, i, + cases.length - i - length); + System.arraycopy(tmp, 0, cases, + sorted.length - length, length); + if (defaultCase >= i + length) + defaultCase -= length; + else if (defaultCase >=i) + defaultCase += cases.length-i-length; + } + } + } + } if(Decompiler.isVerbose) System.err.print("s"); diff --git a/jode/CreateTryCatchStatements.java b/jode/CreateTryCatchStatements.java index 44fd084..6a354a5 100644 --- a/jode/CreateTryCatchStatements.java +++ b/jode/CreateTryCatchStatements.java @@ -1,6 +1,7 @@ package jode; -public class CreateTryCatchStatements implements Transformation { +public class CreateTryCatchStatements extends FlowTransformation +implements Transformation { public InstructionHeader transform(InstructionHeader tryIH) { if (tryIH.getFlowType() != tryIH.TRY || @@ -46,14 +47,12 @@ public class CreateTryCatchStatements implements Transformation { } InstructionHeader endBlock; if (endIH != catchIH[1]) { - if ((endIH.flowType != endIH.RETURN || - endIH.getInstruction().getType() != MyType.tVoid) && - endIH.flowType != endIH.GOTO) + if (endIH.flowType != endIH.GOTO) return null; - endBlock = endIH.successors[0]; + endBlock = UnoptimizeWhileLoops(endIH.successors[0]); } else - endBlock = tryIH.outer.endBlock; + endBlock = tryIH.outer.getEndBlock(); if (Decompiler.isVerbose) System.err.print("t"); return new TryCatchInstructionHeader diff --git a/jode/CreateWhileStatements.java b/jode/CreateWhileStatements.java index c70aedb..9532eba 100644 --- a/jode/CreateWhileStatements.java +++ b/jode/CreateWhileStatements.java @@ -1,23 +1,40 @@ package jode; -public class CreateWhileStatements implements Transformation { +public class CreateWhileStatements extends FlowTransformation +implements Transformation { public InstructionHeader transform(InstructionHeader gotoIH) { - if (gotoIH.flowType != gotoIH.GOTO || gotoIH.nextInstruction == null || - gotoIH.successors[0].addr < gotoIH.nextInstruction.addr) + if (gotoIH.flowType == gotoIH.IFGOTO && + gotoIH.successors[1] == gotoIH) + /* This is an empty while loop + */ + return new WhileInstructionHeader(gotoIH, gotoIH); + + if (gotoIH.flowType != gotoIH.GOTO || + gotoIH.nextInstruction == null || + gotoIH.successors[0].addr < gotoIH.nextInstruction.addr || + gotoIH.outer != gotoIH.successors[0].outer) return null; - InstructionHeader block = gotoIH.nextInstruction; InstructionHeader ifgoto = gotoIH.successors[0]; if (ifgoto.getFlowType() != ifgoto.IFGOTO || - ifgoto.successors[1] != block || - ifgoto.outer != block.outer) + ifgoto.outer != ifgoto.successors[1].outer) + return null; + + InstructionHeader next = UnoptimizeWhileLoops(ifgoto.successors[1]); + if (next != gotoIH.nextInstruction) return null; + if (next != ifgoto.successors[1]) { + ifgoto.successors[1].predecessors.removeElement(ifgoto); + ifgoto.successors[1] = next; + ifgoto.successors[1].predecessors.addElement(ifgoto); + } + if(Decompiler.isVerbose) System.err.print("w"); - return new WhileInstructionHeader(gotoIH, ifgoto, block); + return new WhileInstructionHeader(gotoIH, ifgoto); } } diff --git a/jode/FlowTransformation.java b/jode/FlowTransformation.java new file mode 100644 index 0000000..ff73ac6 --- /dev/null +++ b/jode/FlowTransformation.java @@ -0,0 +1,79 @@ +package jode; + +abstract public class FlowTransformation { + + /** + * This class reverses javac's optimization of while loops. + * A while loop is normally implemented as follows: + * + *
+     * loop: goto cond;
+     * head:   
+     * cond: if  goto head;
+     * 
+ * + * The problem is, if a while loop is the destination of a jump + * (e.g. it's in the else-part of an if, but there are many more + * cases). Then the first goto may or may not be removed (depends + * on the special case) and the previous instruction jumps + * directly to cond.

+ * + * If we detect an if, that jumps backwards, but in the same block + * we assume that it belongs to a while statement and bring it to + * the above standard format.

+ * + * If this function returns with another Header, it is guaranteed + * that lies in the same block. + * + * @param cond The destination of a jump. + * @return loop, if this is an while. loop is generated on + * the fly if it didn't exists before. If this isn't a while at + * all, the parameter is returned unchanged. + */ + public InstructionHeader UnoptimizeWhileLoops(InstructionHeader dest) { + if (dest.flowType != dest.IFGOTO || + dest.successors[1].addr >= dest.addr || + dest.successors[1].outer != dest.outer) + return dest; + + /* Okay, initial checking done, this really looks like a while + * statement. Now we call us recursively, in case the first + * instruction of this while loop is a while loop again.

+ * + * This won't lead to infinite recursion because the + * address of the instruction will always decrease. + */ + + InstructionHeader head = UnoptimizeWhileLoops(dest.successors[1]); + + /* Now we are at head. Look in front of this if loop is + * already existing. If this is the case simply return it. + */ + if (head.prevInstruction != null && + head.prevInstruction.flowType == head.GOTO && + head.prevInstruction.successors[0] == dest) + return head.prevInstruction; + + /* No there was no loop label. Create a new one. + */ + InstructionHeader[] successors = { dest }; + InstructionHeader loop = + new InstructionHeader(head.GOTO, head.addr, head.addr, + successors, head.outer); + + /* Connect it in the prev/next Instruction chain. + */ + loop.prevInstruction = head.prevInstruction; + if (loop.prevInstruction != null) + loop.prevInstruction.nextInstruction = loop; + loop.nextInstruction = head; + head.prevInstruction = loop; + + /* Loop has no predecessors, but a successor namely dest. + * The calling function may change this situation. + */ + dest.predecessors.addElement(loop); + return loop; + } + +} diff --git a/jode/RemoveNop.java b/jode/RemoveNop.java index 499e714..a236a18 100644 --- a/jode/RemoveNop.java +++ b/jode/RemoveNop.java @@ -5,6 +5,8 @@ public class RemoveNop implements Transformation { Instruction pred; try { NopOperator op = (NopOperator) ih.getInstruction(); + if (op == null) + return null; ih = ih.getSimpleUniquePredecessor(); pred = ih.getInstruction(); if (pred == null) diff --git a/jode/jode/bytecode/Opcodes.java b/jode/jode/bytecode/Opcodes.java index f8e2afb..16f56f9 100644 --- a/jode/jode/bytecode/Opcodes.java +++ b/jode/jode/bytecode/Opcodes.java @@ -236,11 +236,10 @@ public abstract class Opcodes implements RuntimeConstants{ (OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP)); case opc_goto: return InstructionHeader.createGoto - (addr, 3, addr+stream.readShort(), new NopOperator()); + (addr, 3, addr+stream.readShort()); case opc_jsr: return InstructionHeader.createGoto //XXX - (addr, 3, addr+stream.readShort(), - new JsrOperator()); + (addr, 3, addr+stream.readShort()); case opc_ret: return InstructionHeader.createReturn //XXX (addr, 2, @@ -288,11 +287,8 @@ public abstract class Opcodes implements RuntimeConstants{ (addr, 1, new ReturnOperator(retType)); } case opc_return: { - Type retType = MyType.intersection - (ca.getMethod().mdef.getType().getReturnType(), - VOID_TYPE); return InstructionHeader.createReturn - (addr, 1, new ReturnOperator(retType)); + (addr, 1, null); } case opc_getstatic: case opc_getfield: @@ -446,10 +442,10 @@ public abstract class Opcodes implements RuntimeConstants{ (OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP)); case opc_goto_w: return InstructionHeader.createGoto - (addr, 5, addr + stream.readInt(), new NopOperator()); + (addr, 5, addr + stream.readInt()); case opc_jsr_w: return InstructionHeader.createGoto - (addr, 5, addr+stream.readInt(), new JsrOperator()); + (addr, 5, addr+stream.readInt()); // XXX default: throw new ClassFormatError("Invalid opcode "+opcode); } diff --git a/jode/jode/decompiler/ClassAnalyzer.java b/jode/jode/decompiler/ClassAnalyzer.java index bb1d3db..95decd8 100644 --- a/jode/jode/decompiler/ClassAnalyzer.java +++ b/jode/jode/decompiler/ClassAnalyzer.java @@ -58,9 +58,10 @@ public class ClassAnalyzer implements Analyzer { writer.print(", "); writer.print(interfaces[i].getName().toString()); } + writer.println(""); } writer.untab(); - writer.println(" {"); + writer.println("{"); writer.tab(); for (int i=0; i< fields.length; i++) diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index e34e8a5..2e72335 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -73,8 +73,8 @@ public class CodeAnalyzer implements Analyzer, Constants { static Transformation[] simplifyTrafos = { new SimplifyExpression() }; static Transformation[] blockTrafos = { new CreateTryCatchStatements(), - new CreateBreakStatement(), new CreateIfStatements(), + new CreateBreakStatement(), new CreateWhileStatements(), new CreateSwitchStatements() }; diff --git a/jode/jode/expr/BreakInstructionHeader.java b/jode/jode/expr/BreakInstructionHeader.java index bfd83ab..b5be7d7 100644 --- a/jode/jode/expr/BreakInstructionHeader.java +++ b/jode/jode/expr/BreakInstructionHeader.java @@ -8,7 +8,6 @@ import java.util.Enumeration; public class BreakInstructionHeader extends InstructionHeader { boolean conditional; - boolean isBreak; String breakLabel; /** @@ -18,15 +17,14 @@ public class BreakInstructionHeader extends InstructionHeader { * @param label the label where to break to, may be null. * @param isBreak is this a break or a continue. */ - public BreakInstructionHeader(InstructionHeader gotoHeader, - String label, - boolean isBreak) { + public BreakInstructionHeader(int flowType, + InstructionHeader gotoHeader, + String label) { - super(BREAKSTATEMENT, gotoHeader.addr, gotoHeader.nextAddr, + super(flowType, gotoHeader.addr, gotoHeader.nextAddr, gotoHeader.successors, gotoHeader.outer); this.instr = gotoHeader.getInstruction(); - this.isBreak = isBreak; this.conditional = (gotoHeader.flowType == IFGOTO); this.breakLabel = label; @@ -58,14 +56,9 @@ public class BreakInstructionHeader extends InstructionHeader { if (conditional) { writer.println("if ("+instr.toString()+")"); writer.tab(); - } else { - if (!(instr instanceof NopOperator)) { - if (instr.getType() != MyType.tVoid) - writer.print("push "); - writer.println(instr.toString()+";"); - } } - writer.println((isBreak?"break":"continue") + + writer.println((flowType == BREAK ? "break" : + flowType == CONTINUE ? "continue" : "return") + (breakLabel != null?" "+breakLabel:"")+";"); if (conditional) diff --git a/jode/jode/expr/CaseInstructionHeader.java b/jode/jode/expr/CaseInstructionHeader.java new file mode 100644 index 0000000..2aac7ae --- /dev/null +++ b/jode/jode/expr/CaseInstructionHeader.java @@ -0,0 +1,58 @@ +package jode; +import java.util.Enumeration; + +public class CaseInstructionHeader extends InstructionHeader { + + int label; + boolean isDefault; + + public CaseInstructionHeader(int label, boolean isDefault, + //Type type, + int addr, + InstructionHeader parent) { + super(CASESTATEMENT, addr, addr, + new InstructionHeader[1], parent); + this.label = label; + this.isDefault = isDefault; + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + if (Decompiler.isDebugging) { + dumpDebugging(writer); + writer.tab(); + } + if (isDefault) { + if (nextInstruction == null && successors[0] == null) + return; + writer.println("default:"); + } else + writer.println("case "+label+":" ); + + writer.tab(); + for (InstructionHeader ih = successors[0]; ih != null; + ih = ih.nextInstruction) + ih.dumpSource(writer); + writer.untab(); + } + + /** + * Get the instruction header where the next instruction is. + */ + InstructionHeader getShadow() { + return (successors[0] != null ? successors[0].getShadow() : + getEndBlock()); + } + + public InstructionHeader doTransformations(Transformation[] trafo) { + InstructionHeader next; + if (successors[0] != getEndBlock()) { + for (InstructionHeader ih = successors[0]; ih != null; ih = next) { + if ((next = ih.doTransformations(trafo)) == null) + next = ih.getNextInstruction(); + } + } + return super.doTransformations(trafo); + } +} diff --git a/jode/jode/expr/CreateIfThenElseOperator.java b/jode/jode/expr/CreateIfThenElseOperator.java index 8032d7f..686a319 100644 --- a/jode/jode/expr/CreateIfThenElseOperator.java +++ b/jode/jode/expr/CreateIfThenElseOperator.java @@ -18,6 +18,10 @@ public class CreateIfThenElseOperator implements Transformation{ while (enum.hasMoreElements()) { try { ih = (InstructionHeader) enum.nextElement(); + + if (ih.flowType == ih.GOTO) + ih = ih.getUniquePredecessor(); + Expression zeroExpr = (Expression) ih.getInstruction(); ConstOperator zero = (ConstOperator) zeroExpr.getOperator(); @@ -57,46 +61,54 @@ public class CreateIfThenElseOperator implements Transformation{ return next; } - public InstructionHeader create(InstructionHeader ih) { + public InstructionHeader create(InstructionHeader ih2) { InstructionHeader ifHeader; + InstructionHeader gotoIH; Expression e[] = new Expression[3]; - InstructionHeader[] succs; try { - Vector predec = ih.getPredecessors(); + Vector predec = ih2.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]) + + InstructionHeader ih1 = ifHeader.getSuccessors()[0]; + gotoIH = ih1.getNextInstruction(); + + if (ifHeader.getSuccessors()[1] != ih2 || + ih1.flowType != ifHeader.NORMAL || + gotoIH.flowType != ifHeader.GOTO || + ih2.flowType != ifHeader.NORMAL || + gotoIH.getNextInstruction() != ih2 || + gotoIH.getSuccessors()[0] != ih2.getNextInstruction()) return null; - e[0] = ((Expression) ifHeader.getInstruction()).negate(); - e[1] = (Expression) succs[0].getInstruction(); + e[1] = (Expression) ih1.getInstruction(); if (e[1].isVoid()) return null; - e[2] = (Expression) succs[1].getInstruction(); + e[2] = (Expression) ih2.getInstruction(); if (e[2].isVoid()) return null; + e[0] = (Expression) ifHeader.getInstruction(); } catch (ClassCastException ex) { return null; } catch (NullPointerException ex) { return null; } + if (Decompiler.isVerbose) + System.err.print("?"); + + e[0] = e[0].negate(); 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; + ih2.instr = new Expression(iteo, e); + ih2.movePredecessors(ifHeader); + ih2.nextInstruction.predecessors.removeElement(gotoIH); + return ih2; } public InstructionHeader transform(InstructionHeader ih) { diff --git a/jode/jode/expr/IfInstructionHeader.java b/jode/jode/expr/IfInstructionHeader.java index 765ce70..be3ebad 100644 --- a/jode/jode/expr/IfInstructionHeader.java +++ b/jode/jode/expr/IfInstructionHeader.java @@ -34,65 +34,45 @@ public class IfInstructionHeader extends InstructionHeader { boolean hasElsePart; /** - * Creates a new if statement. There are several conditions that - * must be met: - *

+ * Creates a new if statement. * @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. + * if goto statement, must have a nextInstruction. + * @param elseBlock the start of the else part, same outer, may be null. + * if not null, it must equals ifHeader.successors[1]. + * @param next the next instruction after the if statement, + * same outer, may be null. + * @param endBlock the instruction where the control flows after the if, + * outer may differ, not null. */ public IfInstructionHeader(InstructionHeader ifHeader, - boolean hasElsePart, - InstructionHeader thenEnd, - InstructionHeader elseEnd, - InstructionHeader endBlock) { + InstructionHeader elseBlock, + InstructionHeader next) { - super(IFSTATEMENT, ifHeader.addr, endBlock.addr, + super(IFSTATEMENT, ifHeader.addr, ifHeader.addr, ifHeader.successors, ifHeader.outer); + hasElsePart = elseBlock != null; this.instr = ((Expression)ifHeader.getInstruction()).negate(); this.movePredecessors(ifHeader); - this.endBlock = endBlock; + /* this.moveSuccessors(ifHeader); */ 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; - + /* unlink the first instruction of the if */ + ifHeader.nextInstruction.prevInstruction = null; + /* unlink the last instruction of the if */ + if (next != null) + next.prevInstruction.nextInstruction = null; + this.hasElsePart = hasElsePart; if (hasElsePart) { - thenEnd.flowType = thenEnd.NORMAL; - successors[1].prevInstruction = null; - next = elseEnd.nextInstruction; - elseEnd.nextInstruction = null; + /* unlink the instructions around the else */ + elseBlock.prevInstruction.nextInstruction = null; + elseBlock.prevInstruction = null; for (InstructionHeader ih = successors[1]; ih != null; ih = ih.nextInstruction) @@ -100,6 +80,14 @@ public class IfInstructionHeader extends InstructionHeader { ih.outer = this; } + /* Do this now, because the end of the then part is cut in + * the else part above. + */ + for (InstructionHeader ih = successors[0]; ih != null; + ih = ih.nextInstruction) + if (ih.outer == outer) + ih.outer = this; + this.nextInstruction = next; if (next != null) next.prevInstruction = this; @@ -136,7 +124,10 @@ public class IfInstructionHeader extends InstructionHeader { braces = successors[1].flowType != NORMAL || successors[1].nextInstruction != null; - if (!braces && successors[1].flowType == IFSTATEMENT) { + if (successors[1].flowType == IFSTATEMENT && + successors[1].nextInstruction == null) { + /* write "else if" */ + braces = false; writer.print("else "); successors[1].dumpSource(writer); } else { diff --git a/jode/jode/expr/InstructionHeader.java b/jode/jode/expr/InstructionHeader.java index e7d9de9..13acd84 100644 --- a/jode/jode/expr/InstructionHeader.java +++ b/jode/jode/expr/InstructionHeader.java @@ -27,7 +27,10 @@ public class InstructionHeader { public final static int FORSTATEMENT = 13; public final static int SWITCHSTATEMENT = 14; public final static int TRYCATCHBLOCK = 15; - public final static int BREAKSTATEMENT = 19; + public final static int CASESTATEMENT = 16; + public final static int BREAK = 20; + public final static int CONTINUE = 21; + public final static int VOIDRETURN = 22; public final static int EMPTY = 99; @@ -54,13 +57,26 @@ public class InstructionHeader { * (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. + /** + * This should be implemented for those blocks, that is headers + * which are outer of other headers. This gives the instruction + * where the control flows after this block. + * @return the first instruction after this block. + */ + InstructionHeader getEndBlock() { + if (nextInstruction != null) { + return nextInstruction.getShadow(); + } + return outer.getEndBlock(); + } + + /** + * Get the instruction header where this jumps to if this is a + * unconditional goto. Otherwise returns this header. */ - InstructionHeader endBlock; + InstructionHeader getShadow() { + return (flowType == GOTO)? successors[0].getShadow() : this; + } /** * A more complex doubly linked list of instructions. The @@ -147,7 +163,8 @@ public class InstructionHeader { * @param instr The underlying Instruction. */ public static InstructionHeader createReturn(int addr, int length, - Instruction instr) { + Instruction instr) + { return new InstructionHeader(RETURN, addr, addr + length, instr, new int[0]); } @@ -159,11 +176,10 @@ public class InstructionHeader { * @param instr The underlying Instruction. * @param dest The destination address of the jump. */ - public static InstructionHeader createGoto(int addr, int length, int dest, - Instruction instr) { + public static InstructionHeader createGoto(int addr, int length, int dest) + { int [] succs = { dest }; - return new InstructionHeader (GOTO, addr, addr + length, - instr, succs); + return new InstructionHeader(GOTO, addr, addr + length, null, succs); } /** @@ -309,8 +325,8 @@ public class InstructionHeader { for (int i=0; i preds: "); for (int i=0; ifrom to + * the current instruction.

+ * The predecessors of from are informed about this change. + * @param from The instruction header which predecessors are moved. + */ + public void addPredecessors(InstructionHeader from) { + for (int i=0; i < from.predecessors.size(); i++) { + InstructionHeader pre = + (InstructionHeader)from.predecessors.elementAt(i); + + predecessors.addElement(pre); + for (int j=0; j < pre.successors.length; j++) + if (pre.successors[j] == from) + pre.successors[j] = this; + } + from.predecessors.removeAllElements(); + } + + /** + * Moves the successors from the InstructionHeader from to + * the current instruction. The current successors are overwritten + * and you must make sure that is has no live InstructionHeaders. + * Also the from InstructionHeader musnt't be used any more.

+ * + * The successors of from are informed about this change. + * @param from The instruction header which successors are moved. + */ + public void moveSuccessors(InstructionHeader from) { + successors = from.successors; + from.successors = null; + for (int i=0; i < successors.length; i++) { + successors[i].predecessors.removeElement(from); + successors[i].predecessors.addElement(this); + } } /** diff --git a/jode/jode/expr/MethodInstructionHeader.java b/jode/jode/expr/MethodInstructionHeader.java index 284c07b..ffc8365 100644 --- a/jode/jode/expr/MethodInstructionHeader.java +++ b/jode/jode/expr/MethodInstructionHeader.java @@ -8,6 +8,7 @@ import sun.tools.java.Type; * @author Jochen Hoenicke */ public class MethodInstructionHeader extends InstructionHeader { + /** * Create a new InstructionHeader. * @param addr The address of this Instruction. @@ -20,7 +21,8 @@ public class MethodInstructionHeader extends InstructionHeader { super(METHOD, 0, instr.length, new InstructionHeader[1], null); successors[0] = instr[0]; instr[0].predecessors.addElement(this); - endBlock = new InstructionHeader(EMPTY, instr.length, null); + nextInstruction = new InstructionHeader(EMPTY, instr.length, null); + nextInstruction.prevInstruction = this; for (int addr = 0; addr < instr.length; addr = instr[addr].nextAddr) { @@ -28,9 +30,15 @@ public class MethodInstructionHeader extends InstructionHeader { instr[addr].resolveSuccessors(instr); if (instr[addr].flowType == RETURN) { - InstructionHeader[] retSuccs = { endBlock }; + InstructionHeader[] retSuccs = { nextInstruction }; instr[addr].successors = retSuccs; - endBlock.predecessors.addElement(instr[addr]); + nextInstruction.predecessors.addElement(instr[addr]); + if (instr[addr].instr == null) { + /* if this is a void return, replace it by a + * goto to the nextInstruction. + */ + instr[addr].flowType = GOTO; + } } } for (int i=0; i 0) { + successors[label-1]. + nextInstruction = successors[label]; + successors[label]. + prevInstruction = successors[label-1]; + } + label++; + } + successors[label-1].successors[0] = ih; + ih.predecessors.addElement(successors[label-1]); + + while (ih != null && + (label == caseIHs.length || + caseIHs[label] != ih)) { if (ih.outer == outer) - ih.outer = this; + ih.outer = successors[label-1]; + ih = ih.nextInstruction; + } + } + + while (label < caseIHs.length) { + successors[label] = new CaseInstructionHeader + (cases[label], label == defaultCase, getEndBlock().addr, this); + if (label > 0) { + successors[label-1]. + nextInstruction = successors[label]; + successors[label]. + prevInstruction = successors[label-1]; + } + label++; + } } /** @@ -127,7 +149,7 @@ public class SwitchInstructionHeader extends InstructionHeader { * switch instructions. */ public InstructionHeader getBreak() { - return endBlock; + return getEndBlock(); } public void dumpSource(TabbedPrintWriter writer) @@ -146,23 +168,10 @@ public class SwitchInstructionHeader extends InstructionHeader { writer.println("switch (" + instr.toString() + ") {"); - for (int i=0; i