diff --git a/jode/CombineCatchLocal.java b/jode/CombineCatchLocal.java index b20c2d7..13f3827 100644 --- a/jode/CombineCatchLocal.java +++ b/jode/CombineCatchLocal.java @@ -4,7 +4,7 @@ import sun.tools.java.Identifier; public class CombineCatchLocal implements Transformation{ - static Identifier idException = Identifier.lookup("exception"); +// static Identifier idException = Identifier.lookup("exception"); public InstructionHeader transform(InstructionHeader ih) { CatchInstructionHeader catchIH; @@ -17,10 +17,8 @@ public class CombineCatchLocal implements Transformation{ 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) { diff --git a/jode/CreateBreakStatement.java b/jode/CreateBreakStatement.java new file mode 100644 index 0000000..038fcdc --- /dev/null +++ b/jode/CreateBreakStatement.java @@ -0,0 +1,37 @@ +package jode; + +public class CreateBreakStatement implements Transformation { + public InstructionHeader transform(InstructionHeader ih) { + InstructionHeader breakDest; + if (ih.getFlowType() == ih.GOTO) + breakDest = ih.successors[0]; + else if (ih.getFlowType() == ih.IFGOTO) + breakDest = ih.successors[1]; + else + return null; + + boolean needBreakLabel = false, needContLabel = false; + InstructionHeader outer = ih.outer; + while (outer != null) { + if (outer.getBreak() == breakDest) { + if (Decompiler.isVerbose) + System.err.print("b"); + return new BreakInstructionHeader + (ih, needBreakLabel?outer.getLabel(): null, true); + } + if (outer.getContinue() == breakDest) { + if (Decompiler.isVerbose) + System.err.print("b"); + return new BreakInstructionHeader + (ih, needContLabel?outer.getLabel(): null, false); + } + if (outer.getBreak() != null) + needBreakLabel = true; + if (outer.getContinue() != null) + needContLabel = true; + outer = outer.outer; + } + return null; + } +} + diff --git a/jode/CreateSwitchStatements.java b/jode/CreateSwitchStatements.java new file mode 100644 index 0000000..e14a6a8 --- /dev/null +++ b/jode/CreateSwitchStatements.java @@ -0,0 +1,84 @@ +package jode; +import java.util.Enumeration; + +public class CreateSwitchStatements implements Transformation { + + public InstructionHeader transform(InstructionHeader ih) { + if (ih.getFlowType() != ih.SWITCH) + return null; + + SimpleSwitchInstructionHeader switchIH = + (SimpleSwitchInstructionHeader) ih; + + int defaultCase = switchIH.successors.length - 1; + 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 ++; + } + + int[] cases = new int[count]; + InstructionHeader[] sorted = new InstructionHeader[count]; + count = 0; + for (int i=0; i < switchIH.successors.length; i++) { + if (i != defaultCase && + switchIH.successors[i] == switchIH.successors[defaultCase]) + continue; + int insert; + for (insert = 0; insert < count; insert++) { + if (sorted[insert].addr > switchIH.successors[i].addr) + break; + } + if (insert < count) { + System.arraycopy(cases, insert, + cases, insert+1, count-insert); + System.arraycopy(sorted, insert, + sorted, insert+1, count-insert); + } + if (i == defaultCase) + defaultCase = insert; + else + cases[insert] = switchIH.cases[i]; + sorted[insert] = switchIH.successors[i]; + count++; + } + InstructionHeader endBlock = switchIH.outer.endBlock; + ih = sorted[count-1]; + if (ih.outer == switchIH.outer) { + EndSearch: + while (ih != null) { + Enumeration enum = ih.getPredecessors().elements(); + while (enum.hasMoreElements()) { + InstructionHeader pred = + (InstructionHeader)enum.nextElement(); + if (pred.addr < sorted[count-1].addr && + (pred.flowType == ih.GOTO || + (pred.flowType == ih.IFGOTO && + pred.successors[1] == ih))) { + endBlock = ih; + break EndSearch; + } + } +// 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; + + if(Decompiler.isVerbose) + System.err.print("s"); + return new SwitchInstructionHeader + (switchIH, cases, sorted, defaultCase, endBlock); + } +} + + diff --git a/jode/CreateTryCatchStatements.java b/jode/CreateTryCatchStatements.java index d24be9f..44fd084 100644 --- a/jode/CreateTryCatchStatements.java +++ b/jode/CreateTryCatchStatements.java @@ -44,24 +44,19 @@ public class CreateTryCatchStatements implements Transformation { remaining[index2++] = tryIH.successors[i+1]; } } - InstructionHeader endBlock = tryIH.outer.endBlock; + InstructionHeader 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; - } + endBlock = endIH.successors[0]; + } else + endBlock = tryIH.outer.endBlock; if (Decompiler.isVerbose) System.err.print("t"); return new TryCatchInstructionHeader (catchIH, endIH, remaining, endBlock); } } - - - diff --git a/jode/CreateWhileStatements.java b/jode/CreateWhileStatements.java index 003b11b..c70aedb 100644 --- a/jode/CreateWhileStatements.java +++ b/jode/CreateWhileStatements.java @@ -9,9 +9,6 @@ public class CreateWhileStatements implements Transformation { return null; InstructionHeader block = gotoIH.nextInstruction; - if (block == null) - block = gotoIH.outer.endBlock; - InstructionHeader ifgoto = gotoIH.successors[0]; if (ifgoto.getFlowType() != ifgoto.IFGOTO || diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index 8483de4..e34e8a5 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -73,8 +73,10 @@ public class CodeAnalyzer implements Analyzer, Constants { static Transformation[] simplifyTrafos = { new SimplifyExpression() }; static Transformation[] blockTrafos = { new CreateTryCatchStatements(), + new CreateBreakStatement(), new CreateIfStatements(), - new CreateWhileStatements() + new CreateWhileStatements(), + new CreateSwitchStatements() }; public void analyze() diff --git a/jode/jode/decompiler/LocalInfo.java b/jode/jode/decompiler/LocalInfo.java index eb3fab7..98daf04 100644 --- a/jode/jode/decompiler/LocalInfo.java +++ b/jode/jode/decompiler/LocalInfo.java @@ -43,8 +43,10 @@ public class LocalInfo { if (shadow != null) shadow.combineWith(li); li = li.getLocalInfo(); - if (this != li) + if (this != li) { shadow = li; + li.setType(type); + } } /** @@ -98,7 +100,7 @@ public class LocalInfo { return shadow.setType(newType); this.type = MyType.intersection(this.type, newType); if (this.type == MyType.tError) - System.err.println("Type error in "+name.toString()); + System.err.println("Type error in "+getName()); return this.type; } diff --git a/jode/jode/decompiler/LocalVariableAnalyzer.java b/jode/jode/decompiler/LocalVariableAnalyzer.java index 83003be..01165bb 100644 --- a/jode/jode/decompiler/LocalVariableAnalyzer.java +++ b/jode/jode/decompiler/LocalVariableAnalyzer.java @@ -120,7 +120,14 @@ public class LocalVariableAnalyzer { continue; } - if (instr.getInstruction() instanceof LocalVarOperator) { + if (instr instanceof MethodInstructionHeader) { + /* This is the first instruction + */ + for (int i=0; i < argLocals.length; i++) { + if (reads[i] != null) + argLocals[i].combineWith(reads[i]); + } + } else if (instr.getInstruction() instanceof LocalVarOperator) { if (Decompiler.isVerbose) System.err.print("."); @@ -146,23 +153,13 @@ public class LocalVariableAnalyzer { } 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]); - } + while (predec.hasMoreElements()) { + instrStack.push(predec.nextElement()); + readsStack.push(reads); } } if (!mdef.isStatic()) argLocals[0].setName(Constants.idThis); -// System.err.println("done!"); } public void createLocalInfo(CodeAnalyzer code) { diff --git a/jode/jode/decompiler/MethodAnalyzer.java b/jode/jode/decompiler/MethodAnalyzer.java index 48a8cf0..59cb7a0 100644 --- a/jode/jode/decompiler/MethodAnalyzer.java +++ b/jode/jode/decompiler/MethodAnalyzer.java @@ -35,21 +35,26 @@ public class MethodAnalyzer implements Analyzer, Constants { { if (code == null) return; - if (Decompiler.isVerbose) - System.err.print(mdef.getName().toString()+": locals "); - lva.createLocalInfo(code); - if (Decompiler.isVerbose) { - System.err.println(""); - System.err.print("code "); - } - code.analyze(); - if (Decompiler.isVerbose) - System.err.println(""); +// if (Decompiler.isVerbose) +// System.err.print(mdef.getName().toString()+": "); +// lva.createLocalInfo(code); +// code.analyze(); +// if (Decompiler.isVerbose) +// System.err.println(""); } public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException { + if (code != null) { + if (Decompiler.isVerbose) + System.err.print(mdef.getName().toString()+": "); + lva.createLocalInfo(code); + code.analyze(); + if (Decompiler.isVerbose) + System.err.println(""); + } + writer.println(""); String modif = Modifier.toString(mdef.getModifiers()); if (modif.length() > 0) diff --git a/jode/jode/expr/BreakInstructionHeader.java b/jode/jode/expr/BreakInstructionHeader.java new file mode 100644 index 0000000..bfd83ab --- /dev/null +++ b/jode/jode/expr/BreakInstructionHeader.java @@ -0,0 +1,77 @@ +package jode; +import java.util.Enumeration; + +/** This instruction header represents an break, continue or an + * if + break/continue statement. + */ + +public class BreakInstructionHeader extends InstructionHeader { + + boolean conditional; + boolean isBreak; + String breakLabel; + + /** + * Creates a new break statement. + * @param gotoHeader the instruction header whichs contains the + * (maybe conditonal) goto statement. + * @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) { + + super(BREAKSTATEMENT, gotoHeader.addr, gotoHeader.nextAddr, + gotoHeader.successors, gotoHeader.outer); + + this.instr = gotoHeader.getInstruction(); + this.isBreak = isBreak; + this.conditional = (gotoHeader.flowType == IFGOTO); + this.breakLabel = label; + + this.movePredecessors(gotoHeader); + this.successors = gotoHeader.successors; + for (int i=0; i< successors.length; i++) { + successors[i].predecessors.removeElement(gotoHeader); + successors[i].predecessors.addElement(this); + } + this.nextInstruction = gotoHeader.nextInstruction; + if (nextInstruction != null) + nextInstruction.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(); + } + + 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") + + (breakLabel != null?" "+breakLabel:"")+";"); + + if (conditional) + writer.untab(); + + if (Decompiler.isDebugging) + writer.untab(); + } +} diff --git a/jode/jode/expr/CatchInstructionHeader.java b/jode/jode/expr/CatchInstructionHeader.java index d3a9d9c..0520ca1 100644 --- a/jode/jode/expr/CatchInstructionHeader.java +++ b/jode/jode/expr/CatchInstructionHeader.java @@ -48,6 +48,7 @@ public class CatchInstructionHeader extends InstructionHeader { return false; this.local = local; + local.setType(type); successors = next.successors; nextInstruction = next.nextInstruction; if (nextInstruction != null) diff --git a/jode/jode/expr/IfInstructionHeader.java b/jode/jode/expr/IfInstructionHeader.java index 98f9567..765ce70 100644 --- a/jode/jode/expr/IfInstructionHeader.java +++ b/jode/jode/expr/IfInstructionHeader.java @@ -71,7 +71,6 @@ public class IfInstructionHeader extends InstructionHeader { 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); diff --git a/jode/jode/expr/InstructionHeader.java b/jode/jode/expr/InstructionHeader.java index 65051b3..e7d9de9 100644 --- a/jode/jode/expr/InstructionHeader.java +++ b/jode/jode/expr/InstructionHeader.java @@ -25,7 +25,9 @@ public class InstructionHeader { 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 SWITCHSTATEMENT = 14; + public final static int TRYCATCHBLOCK = 15; + public final static int BREAKSTATEMENT = 19; public final static int EMPTY = 99; @@ -298,6 +300,8 @@ public class InstructionHeader { * Returns true if this instruction header needs a label. */ protected boolean needsLabel() { + if (label != null) + return true; /* An instruction my have only one prevInstruction, but * may have more then one predecessor that has its * nextInstruction pointing to us. @@ -371,7 +375,7 @@ public class InstructionHeader { writer.print(""+predecessors.elementAt(i)); } writer.println(""); - writer.print("outend: "+outer.endBlock+ + writer.print("out: "+outer+" end: "+endBlock+ " prev: "+prevInstruction+", next: "+ nextInstruction + " succs: "); for (int i=0; i + * A: .... + *

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

+ * case 1: + *

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

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

+ * case 2: + *

+ * 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 SwitchInstructionHeader extends InstructionHeader { + + int[] cases; + int defaultCase; + + /** + * Creates a new if statement. There are several conditions that + * must be met: + *

+ * @param ifHeader the instruction header whichs contains the + * if goto statement. + * @param cases the values belonging to the case labels. + * @param successors the successors of this instruction (the cases). + * This array must be sorted from low to high addresses. + * @param defaultCase the position of the default case in the array. + * @param endBlock the next instruction after this switch statement. + */ + public SwitchInstructionHeader(InstructionHeader switchIH, + int []cases, + InstructionHeader []successors, + int defaultCase, + InstructionHeader endBlock) { + + super(SWITCHSTATEMENT, switchIH.addr, endBlock.addr, + successors, switchIH.outer); + + this.instr = switchIH.getInstruction(); + this.movePredecessors(switchIH); + this.endBlock = endBlock; + this.defaultCase = defaultCase; + this.cases = cases; + + /* switchIH may have more succesors than we: + * CreateSwitchStatements removes case labels, that are the + * default. + */ + for (int i=0; i