git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@11 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 27 years ago
parent f3f21e7d2c
commit 3360965bb1
  1. 30
      jode/CreateBreakStatement.java
  2. 78
      jode/CreateConstantArray.java
  3. 100
      jode/CreateIfStatements.java
  4. 132
      jode/CreateSwitchStatements.java
  5. 11
      jode/CreateTryCatchStatements.java
  6. 31
      jode/CreateWhileStatements.java
  7. 79
      jode/FlowTransformation.java
  8. 2
      jode/RemoveNop.java
  9. 14
      jode/jode/bytecode/Opcodes.java
  10. 3
      jode/jode/decompiler/ClassAnalyzer.java
  11. 2
      jode/jode/decompiler/CodeAnalyzer.java
  12. 19
      jode/jode/expr/BreakInstructionHeader.java
  13. 58
      jode/jode/expr/CaseInstructionHeader.java
  14. 44
      jode/jode/expr/CreateIfThenElseOperator.java
  15. 77
      jode/jode/expr/IfInstructionHeader.java
  16. 112
      jode/jode/expr/InstructionHeader.java
  17. 23
      jode/jode/expr/MethodInstructionHeader.java
  18. 126
      jode/jode/expr/SwitchInstructionHeader.java
  19. 19
      jode/jode/expr/TryCatchInstructionHeader.java
  20. 57
      jode/jode/expr/WhileInstructionHeader.java

@ -4,12 +4,26 @@ public class CreateBreakStatement implements Transformation {
public InstructionHeader transform(InstructionHeader ih) { public InstructionHeader transform(InstructionHeader ih) {
InstructionHeader breakDest; InstructionHeader breakDest;
if (ih.getFlowType() == ih.GOTO) if (ih.getFlowType() == ih.GOTO)
breakDest = ih.successors[0]; breakDest = ih.successors[0].getShadow();
else if (ih.getFlowType() == ih.IFGOTO) else if (ih.getFlowType() == ih.IFGOTO)
breakDest = ih.successors[1]; breakDest = ih.successors[1].getShadow();
else else
return null; 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; boolean needBreakLabel = false, needContLabel = false;
InstructionHeader outer = ih.outer; InstructionHeader outer = ih.outer;
while (outer != null) { while (outer != null) {
@ -17,13 +31,19 @@ public class CreateBreakStatement implements Transformation {
if (Decompiler.isVerbose) if (Decompiler.isVerbose)
System.err.print("b"); System.err.print("b");
return new BreakInstructionHeader return new BreakInstructionHeader
(ih, needBreakLabel?outer.getLabel(): null, true); (ih.BREAK, ih, needBreakLabel?outer.getLabel(): null);
} }
if (outer.getContinue() == breakDest) { if (outer.getContinue() == breakDest) {
if (Decompiler.isVerbose) 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 return new BreakInstructionHeader
(ih, needContLabel?outer.getLabel(): null, false); (ih.VOIDRETURN, ih, null);
} }
if (outer.getBreak() != null) if (outer.getBreak() != null)
needBreakLabel = true; needBreakLabel = true;

@ -4,39 +4,20 @@ import sun.tools.java.Type;
public class CreateConstantArray implements Transformation { public class CreateConstantArray implements Transformation {
public InstructionHeader transform(InstructionHeader ih) { public InstructionHeader transform(InstructionHeader ih) {
Expression[] consts; Expression[] consts = null;
int count; int count = 0;
Type type; Type type;
try { try {
if (ih.getInstruction() instanceof DupOperator) if (ih.getInstruction() instanceof DupOperator)
/* this is not the end of the array assign */ /* this is not the end of the array assign */
return null; return null;
ih = ih.getSimpleUniquePredecessor(); ih = ih.getSimpleUniquePredecessor();
ArrayStoreOperator store = int lastindex = -1;
(ArrayStoreOperator) ih.getInstruction(); while (ih.getInstruction() instanceof ArrayStoreOperator) {
ih = ih.getSimpleUniquePredecessor(); ArrayStoreOperator store =
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(); (ArrayStoreOperator) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor(); ih = ih.getSimpleUniquePredecessor();
lastconst = (Expression) ih.getInstruction(); Expression lastconst = (Expression) ih.getInstruction();
ih = ih.getSimpleUniquePredecessor(); ih = ih.getSimpleUniquePredecessor();
Expression indexexpr = (Expression) ih.getInstruction(); Expression indexexpr = (Expression) ih.getInstruction();
ConstOperator indexop = ConstOperator indexop =
@ -44,23 +25,34 @@ public class CreateConstantArray implements Transformation {
if (!MyType.isOfType(indexop.getType(), MyType.tUInt)) if (!MyType.isOfType(indexop.getType(), MyType.tUInt))
return null; return null;
int index = Integer.parseInt(indexop.getValue()); 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; return null;
while (index < lastindex) { else {
consts[lastindex] = new Expression while (index < lastindex) {
(new ConstOperator(MyType.tUnknown, ""), consts[lastindex--] = new Expression
new Expression[0]); (new ConstOperator(MyType.tUnknown, "0"),
lastindex--; new Expression[0]);
} }
consts[lastindex] = lastconst; }
consts[lastindex--] = lastconst;
ih = ih.getSimpleUniquePredecessor(); ih = ih.getSimpleUniquePredecessor();
dup = (DupOperator) ih.getInstruction(); DupOperator dup = (DupOperator) ih.getInstruction();
if (dup.getDepth() != 0 || if (dup.getDepth() != 0 ||
dup.getCount() != store.getLValueType().stackSize()) dup.getCount() != store.getLValueType().stackSize())
return null; return null;
count++; 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(); Expression newArrayExpr = (Expression) ih.getInstruction();
NewArrayOperator newArrayOp = NewArrayOperator newArrayOp =
(NewArrayOperator) newArrayExpr.getOperator(); (NewArrayOperator) newArrayExpr.getOperator();
@ -73,13 +65,25 @@ public class CreateConstantArray implements Transformation {
(ConstOperator) countexpr.getOperator(); (ConstOperator) countexpr.getOperator();
if (!MyType.isOfType(countop.getType(), MyType.tUInt)) if (!MyType.isOfType(countop.getType(), MyType.tUInt))
return null; return null;
if (Integer.parseInt(countop.getValue()) != consts.length) int arraylength = Integer.parseInt(countop.getValue());
return null; 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<arraylength; i++)
newConsts[i] = new Expression
(new ConstOperator(MyType.tUnknown, "0"),
new Expression[0]);
consts = newConsts;
}
} catch (NullPointerException ex) { } catch (NullPointerException ex) {
return null; return null;
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
return null; return null;
} }
if (Decompiler.isVerbose)
System.err.print("a");
Operator op = new ConstantArrayOperator(type, consts.length); Operator op = new ConstantArrayOperator(type, consts.length);
return ih.combine(4*count+1, new Expression(op, consts)); return ih.combine(4*count+1, new Expression(op, consts));
} }

@ -1,56 +1,88 @@
package jode; package jode;
public class CreateIfStatements implements Transformation { public class CreateIfStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader ifgoto) { public InstructionHeader transform(InstructionHeader ifgoto) {
if (ifgoto.getFlowType() != ifgoto.IFGOTO || if (ifgoto.getFlowType() != ifgoto.IFGOTO ||
ifgoto.nextInstruction == null || ifgoto.nextInstruction == null ||
ifgoto.getSuccessors()[1].getAddress() <= ifgoto.getSuccessors()[1].getAddress() <=
ifgoto.getSuccessors()[0].getAddress()) ifgoto.getSuccessors()[0].getAddress())
return null; return null;
InstructionHeader next = ifgoto.getSuccessors()[1]; /* elseBlock points to the first instruction of the
InstructionHeader endBlock = next; * elseBlock or is null if the else block is empty.
if (ifgoto.outer != next.outer) { * next points to the next instruction after this block
if (ifgoto.outer.endBlock != next) * or is null, if this if is the last instruction in
* this block.
*/
InstructionHeader elseBlock = null, next = null;
if (ifgoto.outer != ifgoto.successors[1].outer) {
if (ifgoto.outer.getEndBlock() != ifgoto.successors[1].getShadow())
/* This doesn't seem to be an if but a if-break
*/
return null; return null;
/* This is an if without else that goes to the end
* of the current block. May be this was a continue,
* but who would know it?
*
* If you like breaks and continues more than ifs,
* simply do the break transformation before the
* if transformation.
*/
next = null; next = null;
} } else {
/* This is a normal if, let us first assume, that there is
* no else part. Then end is successors[1], but that may
* be a while loop, so unoptimized it...
*/
next = UnoptimizeWhileLoops(ifgoto.successors[1]);
if (next != ifgoto.successors[1]) {
ifgoto.successors[1].predecessors.removeElement(ifgoto);
ifgoto.successors[1] = next;
ifgoto.successors[1].predecessors.addElement(ifgoto);
}
InstructionHeader thenStart = ifgoto.nextInstruction; /* next.prevInstruction is the end of the `then' block.
InstructionHeader thenEnd; * If this a goto statement that jumps downward, this is
for (thenEnd = thenStart; * probably an `if-then-else'.
thenEnd != null && thenEnd.nextInstruction != next; */
thenEnd = thenEnd.nextInstruction) { InstructionHeader thenEnd = next.prevInstruction;
} if (thenEnd.flowType == thenEnd.GOTO) {
if (thenEnd == null) if (thenEnd.successors[0].outer == next.outer &&
return null; thenEnd.successors[0].addr >= next.addr) {
InstructionHeader elseStart = null; /* this is a normal if-then-else that is
InstructionHeader elseEnd = null; * fully contained in this block.
if (next != null && */
thenEnd.getFlowType() == thenEnd.GOTO && elseBlock = next;
thenEnd.successors[0].getAddress() > next.getAddress()) { next = UnoptimizeWhileLoops(thenEnd.successors[0]);
elseStart = next;
endBlock = next = thenEnd.successors[0]; } else if (thenEnd.successors[0].getShadow() ==
if (ifgoto.outer != next.outer) { ifgoto.outer.getEndBlock()) {
if (ifgoto.outer.endBlock != next) /* this is a normal if-then-else that goes
return null; * to the end of the block.
next = null; *
} * Again this may also be a continue/break statement,
for (elseEnd = elseStart; * but again, who knows.
elseEnd != null && elseEnd.nextInstruction != next; */
elseEnd = elseEnd.nextInstruction) { 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) if(Decompiler.isVerbose)
System.err.print("i"); System.err.print("i");
return new IfInstructionHeader return new IfInstructionHeader
(ifgoto, elseStart != null, thenEnd, elseEnd, endBlock); (ifgoto, elseBlock, next);
} }
} }

@ -1,7 +1,8 @@
package jode; package jode;
import java.util.Enumeration; import java.util.Enumeration;
public class CreateSwitchStatements implements Transformation { public class CreateSwitchStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader ih) { public InstructionHeader transform(InstructionHeader ih) {
if (ih.getFlowType() != ih.SWITCH) if (ih.getFlowType() != ih.SWITCH)
@ -14,8 +15,6 @@ public class CreateSwitchStatements implements Transformation {
int addr = switchIH.nextInstruction.addr; int addr = switchIH.nextInstruction.addr;
int count = 1; int count = 1;
for (int i=0; i < switchIH.successors.length; i++) { for (int i=0; i < switchIH.successors.length; i++) {
if (switchIH.successors[i].addr < addr)
return null;
if (switchIH.successors[i] != switchIH.successors[defaultCase]) if (switchIH.successors[i] != switchIH.successors[defaultCase])
count ++; count ++;
} }
@ -27,6 +26,15 @@ public class CreateSwitchStatements implements Transformation {
if (i != defaultCase && if (i != defaultCase &&
switchIH.successors[i] == switchIH.successors[defaultCase]) switchIH.successors[i] == switchIH.successors[defaultCase])
continue; 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; int insert;
for (insert = 0; insert < count; insert++) { for (insert = 0; insert < count; insert++) {
if (sorted[insert].addr > switchIH.successors[i].addr) if (sorted[insert].addr > switchIH.successors[i].addr)
@ -45,34 +53,120 @@ public class CreateSwitchStatements implements Transformation {
sorted[insert] = switchIH.successors[i]; sorted[insert] = switchIH.successors[i];
count++; count++;
} }
InstructionHeader endBlock = switchIH.outer.endBlock;
ih = sorted[count-1]; InstructionHeader endBlock = switchIH.outer.getEndBlock();
if (ih.outer == switchIH.outer) { int lastBlock;
for (lastBlock = count-1; lastBlock>= 0; lastBlock--)
if (sorted[lastBlock].outer == switchIH.outer)
break;
if (lastBlock >= 0) {
EndSearch: EndSearch:
ih = sorted[lastBlock];
while (ih != null) { 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()) { while (enum.hasMoreElements()) {
InstructionHeader pred = InstructionHeader pred =
(InstructionHeader)enum.nextElement(); (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.GOTO ||
(pred.flowType == ih.IFGOTO && (pred.flowType == ih.IFGOTO &&
pred.successors[1] == ih))) { pred.successors[1] == ih)) &&
ih == UnoptimizeWhileLoops(ih)) {
endBlock = 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; 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; j<length; j++)
sorted[j] = dummyGoto;
i += length - 1;
} else {
/* 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 end of this array, if they
* aren't already there.
*/
if (i+length < sorted.length) {
System.arraycopy(sorted, i + length, sorted, i,
sorted.length - i - length);
for (int j=length; j>0; 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) if(Decompiler.isVerbose)
System.err.print("s"); System.err.print("s");

@ -1,6 +1,7 @@
package jode; package jode;
public class CreateTryCatchStatements implements Transformation { public class CreateTryCatchStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader tryIH) { public InstructionHeader transform(InstructionHeader tryIH) {
if (tryIH.getFlowType() != tryIH.TRY || if (tryIH.getFlowType() != tryIH.TRY ||
@ -46,14 +47,12 @@ public class CreateTryCatchStatements implements Transformation {
} }
InstructionHeader endBlock; InstructionHeader endBlock;
if (endIH != catchIH[1]) { if (endIH != catchIH[1]) {
if ((endIH.flowType != endIH.RETURN || if (endIH.flowType != endIH.GOTO)
endIH.getInstruction().getType() != MyType.tVoid) &&
endIH.flowType != endIH.GOTO)
return null; return null;
endBlock = endIH.successors[0]; endBlock = UnoptimizeWhileLoops(endIH.successors[0]);
} else } else
endBlock = tryIH.outer.endBlock; endBlock = tryIH.outer.getEndBlock();
if (Decompiler.isVerbose) if (Decompiler.isVerbose)
System.err.print("t"); System.err.print("t");
return new TryCatchInstructionHeader return new TryCatchInstructionHeader

@ -1,23 +1,40 @@
package jode; package jode;
public class CreateWhileStatements implements Transformation { public class CreateWhileStatements extends FlowTransformation
implements Transformation {
public InstructionHeader transform(InstructionHeader gotoIH) { public InstructionHeader transform(InstructionHeader gotoIH) {
if (gotoIH.flowType != gotoIH.GOTO || gotoIH.nextInstruction == null || if (gotoIH.flowType == gotoIH.IFGOTO &&
gotoIH.successors[0].addr < gotoIH.nextInstruction.addr) 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; return null;
InstructionHeader block = gotoIH.nextInstruction;
InstructionHeader ifgoto = gotoIH.successors[0]; InstructionHeader ifgoto = gotoIH.successors[0];
if (ifgoto.getFlowType() != ifgoto.IFGOTO || if (ifgoto.getFlowType() != ifgoto.IFGOTO ||
ifgoto.successors[1] != block || ifgoto.outer != ifgoto.successors[1].outer)
ifgoto.outer != block.outer) return null;
InstructionHeader next = UnoptimizeWhileLoops(ifgoto.successors[1]);
if (next != gotoIH.nextInstruction)
return null; 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) if(Decompiler.isVerbose)
System.err.print("w"); System.err.print("w");
return new WhileInstructionHeader(gotoIH, ifgoto, block); return new WhileInstructionHeader(gotoIH, ifgoto);
} }
} }

@ -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:
*
* <pre>
* loop: goto cond;
* head: <inner block>
* cond: if <condition> goto head;
* </pre>
*
* 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. <p>
*
* 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. <p>
*
* 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.<p>
*
* 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;
}
}

@ -5,6 +5,8 @@ public class RemoveNop implements Transformation {
Instruction pred; Instruction pred;
try { try {
NopOperator op = (NopOperator) ih.getInstruction(); NopOperator op = (NopOperator) ih.getInstruction();
if (op == null)
return null;
ih = ih.getSimpleUniquePredecessor(); ih = ih.getSimpleUniquePredecessor();
pred = ih.getInstruction(); pred = ih.getInstruction();
if (pred == null) if (pred == null)

@ -236,11 +236,10 @@ public abstract class Opcodes implements RuntimeConstants{
(OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP)); (OBJECT_TYPE, opcode - opc_if_acmpeq+Operator.COMPARE_OP));
case opc_goto: case opc_goto:
return InstructionHeader.createGoto return InstructionHeader.createGoto
(addr, 3, addr+stream.readShort(), new NopOperator()); (addr, 3, addr+stream.readShort());
case opc_jsr: case opc_jsr:
return InstructionHeader.createGoto //XXX return InstructionHeader.createGoto //XXX
(addr, 3, addr+stream.readShort(), (addr, 3, addr+stream.readShort());
new JsrOperator());
case opc_ret: case opc_ret:
return InstructionHeader.createReturn //XXX return InstructionHeader.createReturn //XXX
(addr, 2, (addr, 2,
@ -288,11 +287,8 @@ public abstract class Opcodes implements RuntimeConstants{
(addr, 1, new ReturnOperator(retType)); (addr, 1, new ReturnOperator(retType));
} }
case opc_return: { case opc_return: {
Type retType = MyType.intersection
(ca.getMethod().mdef.getType().getReturnType(),
VOID_TYPE);
return InstructionHeader.createReturn return InstructionHeader.createReturn
(addr, 1, new ReturnOperator(retType)); (addr, 1, null);
} }
case opc_getstatic: case opc_getstatic:
case opc_getfield: case opc_getfield:
@ -446,10 +442,10 @@ public abstract class Opcodes implements RuntimeConstants{
(OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP)); (OBJECT_TYPE, opcode - opc_ifnull+Operator.COMPARE_OP));
case opc_goto_w: case opc_goto_w:
return InstructionHeader.createGoto return InstructionHeader.createGoto
(addr, 5, addr + stream.readInt(), new NopOperator()); (addr, 5, addr + stream.readInt());
case opc_jsr_w: case opc_jsr_w:
return InstructionHeader.createGoto return InstructionHeader.createGoto
(addr, 5, addr+stream.readInt(), new JsrOperator()); (addr, 5, addr+stream.readInt()); // XXX
default: default:
throw new ClassFormatError("Invalid opcode "+opcode); throw new ClassFormatError("Invalid opcode "+opcode);
} }

@ -58,9 +58,10 @@ public class ClassAnalyzer implements Analyzer {
writer.print(", "); writer.print(", ");
writer.print(interfaces[i].getName().toString()); writer.print(interfaces[i].getName().toString());
} }
writer.println("");
} }
writer.untab(); writer.untab();
writer.println(" {"); writer.println("{");
writer.tab(); writer.tab();
for (int i=0; i< fields.length; i++) for (int i=0; i< fields.length; i++)

@ -73,8 +73,8 @@ public class CodeAnalyzer implements Analyzer, Constants {
static Transformation[] simplifyTrafos = { new SimplifyExpression() }; static Transformation[] simplifyTrafos = { new SimplifyExpression() };
static Transformation[] blockTrafos = { static Transformation[] blockTrafos = {
new CreateTryCatchStatements(), new CreateTryCatchStatements(),
new CreateBreakStatement(),
new CreateIfStatements(), new CreateIfStatements(),
new CreateBreakStatement(),
new CreateWhileStatements(), new CreateWhileStatements(),
new CreateSwitchStatements() new CreateSwitchStatements()
}; };

@ -8,7 +8,6 @@ import java.util.Enumeration;
public class BreakInstructionHeader extends InstructionHeader { public class BreakInstructionHeader extends InstructionHeader {
boolean conditional; boolean conditional;
boolean isBreak;
String breakLabel; String breakLabel;
/** /**
@ -18,15 +17,14 @@ public class BreakInstructionHeader extends InstructionHeader {
* @param label the label where to break to, may be null. * @param label the label where to break to, may be null.
* @param isBreak is this a break or a continue. * @param isBreak is this a break or a continue.
*/ */
public BreakInstructionHeader(InstructionHeader gotoHeader, public BreakInstructionHeader(int flowType,
String label, InstructionHeader gotoHeader,
boolean isBreak) { String label) {
super(BREAKSTATEMENT, gotoHeader.addr, gotoHeader.nextAddr, super(flowType, gotoHeader.addr, gotoHeader.nextAddr,
gotoHeader.successors, gotoHeader.outer); gotoHeader.successors, gotoHeader.outer);
this.instr = gotoHeader.getInstruction(); this.instr = gotoHeader.getInstruction();
this.isBreak = isBreak;
this.conditional = (gotoHeader.flowType == IFGOTO); this.conditional = (gotoHeader.flowType == IFGOTO);
this.breakLabel = label; this.breakLabel = label;
@ -58,14 +56,9 @@ public class BreakInstructionHeader extends InstructionHeader {
if (conditional) { if (conditional) {
writer.println("if ("+instr.toString()+")"); writer.println("if ("+instr.toString()+")");
writer.tab(); 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:"")+";"); (breakLabel != null?" "+breakLabel:"")+";");
if (conditional) if (conditional)

@ -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);
}
}

@ -18,6 +18,10 @@ public class CreateIfThenElseOperator implements Transformation{
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
try { try {
ih = (InstructionHeader) enum.nextElement(); ih = (InstructionHeader) enum.nextElement();
if (ih.flowType == ih.GOTO)
ih = ih.getUniquePredecessor();
Expression zeroExpr = (Expression) ih.getInstruction(); Expression zeroExpr = (Expression) ih.getInstruction();
ConstOperator zero = ConstOperator zero =
(ConstOperator) zeroExpr.getOperator(); (ConstOperator) zeroExpr.getOperator();
@ -57,46 +61,54 @@ public class CreateIfThenElseOperator implements Transformation{
return next; return next;
} }
public InstructionHeader create(InstructionHeader ih) { public InstructionHeader create(InstructionHeader ih2) {
InstructionHeader ifHeader; InstructionHeader ifHeader;
InstructionHeader gotoIH;
Expression e[] = new Expression[3]; Expression e[] = new Expression[3];
InstructionHeader[] succs;
try { try {
Vector predec = ih.getPredecessors(); Vector predec = ih2.getPredecessors();
if (predec.size() != 1) if (predec.size() != 1)
return null; return null;
ifHeader = (InstructionHeader) predec.elementAt(0); ifHeader = (InstructionHeader) predec.elementAt(0);
if (ifHeader.getFlowType() != ifHeader.IFGOTO) if (ifHeader.getFlowType() != ifHeader.IFGOTO)
return null; return null;
succs = ifHeader.getSuccessors();
if (succs[1] != ih || InstructionHeader ih1 = ifHeader.getSuccessors()[0];
succs[0].getNextInstruction() != succs[1] || gotoIH = ih1.getNextInstruction();
succs[0].getSuccessors().length != 1 ||
succs[1].getSuccessors().length != 1 || if (ifHeader.getSuccessors()[1] != ih2 ||
succs[0].getSuccessors()[0] != succs[1].getSuccessors()[0]) ih1.flowType != ifHeader.NORMAL ||
gotoIH.flowType != ifHeader.GOTO ||
ih2.flowType != ifHeader.NORMAL ||
gotoIH.getNextInstruction() != ih2 ||
gotoIH.getSuccessors()[0] != ih2.getNextInstruction())
return null; return null;
e[0] = ((Expression) ifHeader.getInstruction()).negate(); e[1] = (Expression) ih1.getInstruction();
e[1] = (Expression) succs[0].getInstruction();
if (e[1].isVoid()) if (e[1].isVoid())
return null; return null;
e[2] = (Expression) succs[1].getInstruction(); e[2] = (Expression) ih2.getInstruction();
if (e[2].isVoid()) if (e[2].isVoid())
return null; return null;
e[0] = (Expression) ifHeader.getInstruction();
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
return null; return null;
} catch (NullPointerException ex) { } catch (NullPointerException ex) {
return null; return null;
} }
if (Decompiler.isVerbose)
System.err.print("?");
e[0] = e[0].negate();
IfThenElseOperator iteo = new IfThenElseOperator IfThenElseOperator iteo = new IfThenElseOperator
(MyType.intersection(e[1].getType(),e[2].getType())); (MyType.intersection(e[1].getType(),e[2].getType()));
ih.instr = new Expression(iteo, e); ih2.instr = new Expression(iteo, e);
ih.movePredecessors(ifHeader); ih2.movePredecessors(ifHeader);
ih.nextInstruction.predecessors.removeElement(ifHeader.successors[0]); ih2.nextInstruction.predecessors.removeElement(gotoIH);
return ih; return ih2;
} }
public InstructionHeader transform(InstructionHeader ih) { public InstructionHeader transform(InstructionHeader ih) {

@ -34,65 +34,45 @@ public class IfInstructionHeader extends InstructionHeader {
boolean hasElsePart; boolean hasElsePart;
/** /**
* Creates a new if statement. There are several conditions that * Creates a new if statement.
* must be met:
* <ul>
* <li><code> ifHeader.successors[0] == thenStart
* </code></li>
* <li><code> ifHeader.successors[1] == thenEnd.nextInstruction
* </code></li>
* <li><code> elseStart == null || (thenEnd.flowType = GOTO &&
* elseEnd.nextInstruction == thenEnd.successors[0])
* </code></li>
* <li><code> elseStart == null || elseStart = thenEnd.nextInstruction
* </code></li>
* <li><code> thenStart.nextInstruction....nextInstruction = thenEnd
* </code></li>
* <li><code> elseStart.nextInstruction....nextInstruction = elseEnd
* </code></li>
* </ul>
* @param ifHeader the instruction header whichs contains the * @param ifHeader the instruction header whichs contains the
* if goto statement. * if goto statement, must have a nextInstruction.
* @param thenStart the start of the then part. * @param elseBlock the start of the else part, same outer, may be null.
* @param thenEnd the end of the then part. * if not null, it must equals ifHeader.successors[1].
* @param elseStart the start of the else part. * @param next the next instruction after the if statement,
* @param elseEnd the end of the then part. * same outer, may be null.
* @param next the next instruction after the if statement. * @param endBlock the instruction where the control flows after the if,
* outer may differ, not null.
*/ */
public IfInstructionHeader(InstructionHeader ifHeader, public IfInstructionHeader(InstructionHeader ifHeader,
boolean hasElsePart, InstructionHeader elseBlock,
InstructionHeader thenEnd, InstructionHeader next) {
InstructionHeader elseEnd,
InstructionHeader endBlock) {
super(IFSTATEMENT, ifHeader.addr, endBlock.addr, super(IFSTATEMENT, ifHeader.addr, ifHeader.addr,
ifHeader.successors, ifHeader.outer); ifHeader.successors, ifHeader.outer);
hasElsePart = elseBlock != null;
this.instr = ((Expression)ifHeader.getInstruction()).negate(); this.instr = ((Expression)ifHeader.getInstruction()).negate();
this.movePredecessors(ifHeader); this.movePredecessors(ifHeader);
this.endBlock = endBlock; /* this.moveSuccessors(ifHeader); */
successors[0].predecessors.removeElement(ifHeader); successors[0].predecessors.removeElement(ifHeader);
successors[1].predecessors.removeElement(ifHeader); successors[1].predecessors.removeElement(ifHeader);
successors[0].predecessors.addElement(this); successors[0].predecessors.addElement(this);
successors[1].predecessors.addElement(this); successors[1].predecessors.addElement(this);
successors[0].prevInstruction = null; /* unlink the first instruction of the if */
InstructionHeader next = thenEnd.nextInstruction; ifHeader.nextInstruction.prevInstruction = null;
thenEnd.nextInstruction = null; /* unlink the last instruction of the if */
if (next != null)
for (InstructionHeader ih = successors[0]; ih != null; next.prevInstruction.nextInstruction = null;
ih = ih.nextInstruction)
if (ih.outer == outer)
ih.outer = this;
this.hasElsePart = hasElsePart; this.hasElsePart = hasElsePart;
if (hasElsePart) { if (hasElsePart) {
thenEnd.flowType = thenEnd.NORMAL;
successors[1].prevInstruction = null; /* unlink the instructions around the else */
next = elseEnd.nextInstruction; elseBlock.prevInstruction.nextInstruction = null;
elseEnd.nextInstruction = null; elseBlock.prevInstruction = null;
for (InstructionHeader ih = successors[1]; ih != null; for (InstructionHeader ih = successors[1]; ih != null;
ih = ih.nextInstruction) ih = ih.nextInstruction)
@ -100,6 +80,14 @@ public class IfInstructionHeader extends InstructionHeader {
ih.outer = this; 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; this.nextInstruction = next;
if (next != null) if (next != null)
next.prevInstruction = this; next.prevInstruction = this;
@ -136,7 +124,10 @@ public class IfInstructionHeader extends InstructionHeader {
braces = successors[1].flowType != NORMAL || braces = successors[1].flowType != NORMAL ||
successors[1].nextInstruction != null; 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 "); writer.print("else ");
successors[1].dumpSource(writer); successors[1].dumpSource(writer);
} else { } else {

@ -27,7 +27,10 @@ public class InstructionHeader {
public final static int FORSTATEMENT = 13; public final static int FORSTATEMENT = 13;
public final static int SWITCHSTATEMENT = 14; public final static int SWITCHSTATEMENT = 14;
public final static int TRYCATCHBLOCK = 15; 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; public final static int EMPTY = 99;
@ -54,13 +57,26 @@ public class InstructionHeader {
* (without caring about jump instructions). * (without caring about jump instructions).
*/ */
InstructionHeader nextInstruction, prevInstruction; InstructionHeader nextInstruction, prevInstruction;
/** /**
* The first instruction after this block. This should be only * This should be implemented for those blocks, that is headers
* set for blocks, that is headers which are outer of other headers. * which are outer of other headers. This gives the instruction
* This gives the instruction where the control flows after this * where the control flows after this block.
* 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 * A more complex doubly linked list of instructions. The
@ -147,7 +163,8 @@ public class InstructionHeader {
* @param instr The underlying Instruction. * @param instr The underlying Instruction.
*/ */
public static InstructionHeader createReturn(int addr, int length, public static InstructionHeader createReturn(int addr, int length,
Instruction instr) { Instruction instr)
{
return new InstructionHeader(RETURN, addr, addr + length, return new InstructionHeader(RETURN, addr, addr + length,
instr, new int[0]); instr, new int[0]);
} }
@ -159,11 +176,10 @@ public class InstructionHeader {
* @param instr The underlying Instruction. * @param instr The underlying Instruction.
* @param dest The destination address of the jump. * @param dest The destination address of the jump.
*/ */
public static InstructionHeader createGoto(int addr, int length, int dest, public static InstructionHeader createGoto(int addr, int length, int dest)
Instruction instr) { {
int [] succs = { dest }; int [] succs = { dest };
return new InstructionHeader (GOTO, addr, addr + length, return new InstructionHeader(GOTO, addr, addr + length, null, succs);
instr, succs);
} }
/** /**
@ -309,8 +325,8 @@ public class InstructionHeader {
for (int i=0; i<predecessors.size(); i++) { for (int i=0; i<predecessors.size(); i++) {
InstructionHeader ih = InstructionHeader ih =
(InstructionHeader)predecessors.elementAt(i); (InstructionHeader)predecessors.elementAt(i);
if (ih.flowType == GOTO || if ((ih.flowType == GOTO || ih.flowType == IFGOTO) &&
(ih.flowType == IFGOTO && ih.successors[1] == this)) ih.getEndBlock() != this)
return true; return true;
} }
return false; return false;
@ -368,6 +384,7 @@ public class InstructionHeader {
public void dumpDebugging(TabbedPrintWriter writer) public void dumpDebugging(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
writer.println("");
writer.print(""+toString()+ writer.print(""+toString()+
": <"+addr + " - "+(nextAddr-1)+"> preds: "); ": <"+addr + " - "+(nextAddr-1)+"> preds: ");
for (int i=0; i<predecessors.size(); i++) { for (int i=0; i<predecessors.size(); i++) {
@ -375,7 +392,7 @@ public class InstructionHeader {
writer.print(""+predecessors.elementAt(i)); writer.print(""+predecessors.elementAt(i));
} }
writer.println(""); writer.println("");
writer.print("out: "+outer+" end: "+endBlock+ writer.print("out: "+outer +
" prev: "+prevInstruction+", next: "+ nextInstruction + " prev: "+prevInstruction+", next: "+ nextInstruction +
" succs: "); " succs: ");
for (int i=0; i<successors.length; i++) { for (int i=0; i<successors.length; i++) {
@ -402,8 +419,23 @@ public class InstructionHeader {
if (flowType == IFGOTO) { if (flowType == IFGOTO) {
writer.println("if ("+instr.toString()+") goto "+ writer.println("if ("+instr.toString()+")");
successors[1].getLabel()); writer.tab();
if (successors[1] != getEndBlock())
writer.println("goto "+successors[1].getLabel());
else
writer.println("/*empty*/;");
writer.untab();
} else if (flowType == GOTO) {
if (successors[0] != getEndBlock())
writer.println("goto "+successors[0].getLabel());
} else if (flowType == RETURN) {
writer.println((instr != null ? instr.toString() :
"return") + ";");
} else { } else {
@ -413,8 +445,6 @@ public class InstructionHeader {
writer.print("push "); writer.print("push ");
writer.println(instr.toString()+";"); writer.println(instr.toString()+";");
} }
if (flowType == GOTO)
writer.println("goto "+successors[0].getLabel());
} }
} }
@ -431,11 +461,13 @@ public class InstructionHeader {
* @param from The instruction header which predecessors are moved. * @param from The instruction header which predecessors are moved.
*/ */
public void movePredecessors(InstructionHeader from) { public void movePredecessors(InstructionHeader from) {
if (this == from)
return;
addr = from.addr; addr = from.addr;
prevInstruction = from.prevInstruction; prevInstruction = from.prevInstruction;
if (prevInstruction != null) if (prevInstruction != null) {
prevInstruction.nextInstruction = this; prevInstruction.nextInstruction = this;
}
predecessors = from.predecessors; predecessors = from.predecessors;
for (int i=0; i < predecessors.size(); i++) { for (int i=0; i < predecessors.size(); i++) {
InstructionHeader pre = InstructionHeader pre =
@ -445,6 +477,44 @@ public class InstructionHeader {
if (pre.successors[j] == from) if (pre.successors[j] == from)
pre.successors[j] = this; pre.successors[j] = this;
} }
from.predecessors = new Vector();
}
/**
* Moves the predecessors from the InstructionHeader <em>from</em> to
* the current instruction. <p>
* The predecessors of <em>from</em> 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 <em>from</em> to
* the current instruction. The current successors are overwritten
* and you must make sure that is has no live InstructionHeaders.
* Also the <em>from</em> InstructionHeader musnt't be used any more.<p>
*
* The successors of <em>from</em> 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);
}
} }
/** /**

@ -8,6 +8,7 @@ import sun.tools.java.Type;
* @author Jochen Hoenicke * @author Jochen Hoenicke
*/ */
public class MethodInstructionHeader extends InstructionHeader { public class MethodInstructionHeader extends InstructionHeader {
/** /**
* Create a new InstructionHeader. * Create a new InstructionHeader.
* @param addr The address of this Instruction. * @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); super(METHOD, 0, instr.length, new InstructionHeader[1], null);
successors[0] = instr[0]; successors[0] = instr[0];
instr[0].predecessors.addElement(this); 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) { for (int addr = 0; addr < instr.length; addr = instr[addr].nextAddr) {
@ -28,9 +30,15 @@ public class MethodInstructionHeader extends InstructionHeader {
instr[addr].resolveSuccessors(instr); instr[addr].resolveSuccessors(instr);
if (instr[addr].flowType == RETURN) { if (instr[addr].flowType == RETURN) {
InstructionHeader[] retSuccs = { endBlock }; InstructionHeader[] retSuccs = { nextInstruction };
instr[addr].successors = retSuccs; 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<handlers.length; i++) { for (int i=0; i<handlers.length; i++) {
@ -39,7 +47,9 @@ public class MethodInstructionHeader extends InstructionHeader {
instr[handlers[i].startPC] = tryIH = instr[handlers[i].startPC] = tryIH =
new TryInstructionHeader(tryIH, this); new TryInstructionHeader(tryIH, this);
Type type = handlers[i].exceptionClass.getType(); Type type =
(handlers[i].exceptionClass != null)?
handlers[i].exceptionClass.getType() : MyType.tVoid;
instr[handlers[i].handlerPC] = instr[handlers[i].handlerPC] =
new CatchInstructionHeader new CatchInstructionHeader
(type, env.getTypeString(type), (type, env.getTypeString(type),
@ -56,7 +66,7 @@ public class MethodInstructionHeader extends InstructionHeader {
} }
public Vector getReturns() { public Vector getReturns() {
return endBlock.predecessors; return nextInstruction.predecessors;
} }
public void dumpSource(TabbedPrintWriter writer) public void dumpSource(TabbedPrintWriter writer)
@ -65,6 +75,9 @@ public class MethodInstructionHeader extends InstructionHeader {
for (InstructionHeader ih = successors[0]; ih != null; for (InstructionHeader ih = successors[0]; ih != null;
ih = ih.nextInstruction) ih = ih.nextInstruction)
ih.dumpSource(writer); ih.dumpSource(writer);
// dump the last label if it was used.
nextInstruction.dumpSource(writer);
} }
public InstructionHeader doTransformations(Transformation[] trafo) { public InstructionHeader doTransformations(Transformation[] trafo) {

@ -33,9 +33,6 @@ import java.util.Enumeration;
*/ */
public class SwitchInstructionHeader extends InstructionHeader { public class SwitchInstructionHeader extends InstructionHeader {
int[] cases;
int defaultCase;
/** /**
* Creates a new if statement. There are several conditions that * Creates a new if statement. There are several conditions that
* must be met: * must be met:
@ -64,61 +61,86 @@ public class SwitchInstructionHeader extends InstructionHeader {
*/ */
public SwitchInstructionHeader(InstructionHeader switchIH, public SwitchInstructionHeader(InstructionHeader switchIH,
int []cases, int []cases,
InstructionHeader []successors, InstructionHeader []caseIHs,
int defaultCase, int defaultCase,
InstructionHeader endBlock) { InstructionHeader endBlock) {
super(SWITCHSTATEMENT, switchIH.addr, endBlock.addr, super(SWITCHSTATEMENT, switchIH.addr, switchIH.nextAddr,
successors, switchIH.outer); new InstructionHeader[caseIHs.length], switchIH.outer);
this.instr = switchIH.getInstruction(); this.instr = switchIH.getInstruction();
this.movePredecessors(switchIH); this.movePredecessors(switchIH);
this.endBlock = endBlock;
this.defaultCase = defaultCase;
this.cases = cases;
/* switchIH may have more succesors than we: /* switchIH may have more succesors than we:
* CreateSwitchStatements removes case labels, that are the * CreateSwitchStatements removes case labels, that are the
* default. * default.
* And the successors of this switch may differ in case that
* dummy gotos were inserted.
*/ */
for (int i=0; i<switchIH.successors.length; i++) for (int i=0; i<switchIH.successors.length; i++)
switchIH.successors[i].predecessors.removeElement(switchIH); switchIH.successors[i].predecessors.removeElement(switchIH);
for (int i=0; i<successors.length; i++)
successors[i].predecessors.addElement(this);
for (int i=0; i<successors.length; i++) {
if (successors[i].outer == outer) {
if (successors[i].prevInstruction != null)
successors[i].prevInstruction.nextInstruction = null;
successors[i].prevInstruction = null;
}
}
if (endBlock.outer == outer) { if (endBlock.outer == outer) {
if (endBlock.prevInstruction != null) if (endBlock.prevInstruction != null)
endBlock.prevInstruction.nextInstruction = null; endBlock.prevInstruction.nextInstruction = null;
nextInstruction = endBlock; nextInstruction = endBlock;
endBlock.prevInstruction = this; endBlock.prevInstruction = this;
} else { } else if (endBlock.getShadow() == outer.getEndBlock())
if (endBlock != outer.endBlock) { nextInstruction = null;
/* Create a goto after this block, that else {
* jumps to endBlock /* Create a goto after this block, that
*/ * jumps to endBlock
nextInstruction = new InstructionHeader */
(GOTO, endBlock.addr, endBlock.addr, nextInstruction = new InstructionHeader
new InstructionHeader[1], this); (GOTO, endBlock.addr, endBlock.addr,
nextInstruction.instr = new NopOperator(MyType.tVoid); new InstructionHeader[1], outer);
nextInstruction.prevInstruction = this; nextInstruction.prevInstruction = this;
nextInstruction.successors[0] = endBlock; nextInstruction.successors[0] = endBlock;
endBlock.predecessors.addElement(nextInstruction); endBlock.predecessors.addElement(nextInstruction);
} else
nextInstruction = null;
} }
for (int i=0; i < successors.length && successors[i] != endBlock; i++) int label = 0;
for (InstructionHeader ih = successors[i]; ih != null; InstructionHeader lastHeader = null;
ih = ih.nextInstruction)
InstructionHeader ih = switchIH.nextInstruction;
while (ih != null) {
ih.prevInstruction.nextInstruction = null;
ih.prevInstruction = null;
while (label < caseIHs.length && caseIHs[label] == ih) {
successors[label] = new CaseInstructionHeader
(cases[label], label == defaultCase, ih.addr, this);
if (label > 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) 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. * switch instructions.
*/ */
public InstructionHeader getBreak() { public InstructionHeader getBreak() {
return endBlock; return getEndBlock();
} }
public void dumpSource(TabbedPrintWriter writer) public void dumpSource(TabbedPrintWriter writer)
@ -146,23 +168,10 @@ public class SwitchInstructionHeader extends InstructionHeader {
writer.println("switch (" + instr.toString() + ") {"); writer.println("switch (" + instr.toString() + ") {");
for (int i=0; i<successors.length; i++) { int label = 0;
if (i != defaultCase) for (InstructionHeader ih = successors[0]; ih != null;
writer.println("case "+cases[i]+":"); ih = ih.nextInstruction)
ih.dumpSource(writer);
if (successors[i] == endBlock)
break;
if (i+1 < successors.length && successors[i] == successors[i+1])
continue;
if (i == defaultCase)
writer.println("default:");
writer.tab();
for (InstructionHeader ih = successors[i]; ih != null;
ih = ih.nextInstruction)
ih.dumpSource(writer);
writer.untab();
}
writer.println("} "); writer.println("} ");
if (Decompiler.isDebugging) if (Decompiler.isDebugging)
@ -171,11 +180,10 @@ public class SwitchInstructionHeader extends InstructionHeader {
public InstructionHeader doTransformations(Transformation[] trafo) { public InstructionHeader doTransformations(Transformation[] trafo) {
InstructionHeader next; InstructionHeader next;
for (int i=0; i < successors.length && successors[i] != endBlock; i++) for (InstructionHeader ih = successors[0]; ih != null; ih = next) {
for (InstructionHeader ih = successors[i]; ih != null; ih = next) { if ((next = ih.doTransformations(trafo)) == null)
if ((next = ih.doTransformations(trafo)) == null) next = ih.getNextInstruction();
next = ih.getNextInstruction(); }
}
return super.doTransformations(trafo); return super.doTransformations(trafo);
} }
} }

@ -70,13 +70,11 @@ public class TryCatchInstructionHeader extends InstructionHeader {
if (tryHeader.nextInstruction != null) if (tryHeader.nextInstruction != null)
tryHeader.nextInstruction.prevInstruction = null; tryHeader.nextInstruction.prevInstruction = null;
} }
this.endBlock = endBlock;
if (endBlock.outer == outer) { if (endBlock.outer == outer) {
nextInstruction = endBlock; nextInstruction = endBlock;
endBlock.prevInstruction = this; endBlock.prevInstruction = this;
} else { } else if (endBlock.getShadow() != outer.getEndBlock()) {
if (endBlock != outer.endBlock) {
/* Create a goto after this block, that /* Create a goto after this block, that
* jumps to endBlock * jumps to endBlock
*/ */
@ -87,9 +85,8 @@ public class TryCatchInstructionHeader extends InstructionHeader {
nextInstruction.prevInstruction = this; nextInstruction.prevInstruction = this;
nextInstruction.successors[0] = endBlock; nextInstruction.successors[0] = endBlock;
endBlock.predecessors.addElement(nextInstruction); endBlock.predecessors.addElement(nextInstruction);
} else } else
nextInstruction = null; nextInstruction = null;
}
if (endHeader != successors[1]) if (endHeader != successors[1])
endHeader.successors[0].predecessors.removeElement(endHeader); endHeader.successors[0].predecessors.removeElement(endHeader);
@ -117,14 +114,6 @@ public class TryCatchInstructionHeader extends InstructionHeader {
|| ih.nextInstruction == endBlock) || ih.nextInstruction == endBlock)
ih.nextInstruction = null; 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;
} }
} }
} }
@ -145,7 +134,7 @@ public class TryCatchInstructionHeader extends InstructionHeader {
writer.println("try {"); writer.println("try {");
writer.tab(); writer.tab();
if (successors[0] == endBlock) if (successors[0] == getEndBlock())
writer.print("/* empty?? */"); writer.print("/* empty?? */");
else { else {
for (InstructionHeader ih = successors[0]; ih != null; for (InstructionHeader ih = successors[0]; ih != null;

@ -28,31 +28,39 @@ import java.util.Enumeration;
public class WhileInstructionHeader extends InstructionHeader { public class WhileInstructionHeader extends InstructionHeader {
/** /**
* Creates a new while statement. * Creates a new while statement.
* @param prev the goto instruction in front of this while loop. * @param gotoHeader the goto instruction in front of this while loop.
* @param ifHeader the instruction header which contains the * @param ifHeader the instruction header which contains the
* if-goto statement. * 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, public WhileInstructionHeader(InstructionHeader gotoHeader,
InstructionHeader ifHeader, InstructionHeader ifHeader) {
InstructionHeader block) {
super(WHILESTATEMENT, super(WHILESTATEMENT,
ifHeader.successors[1].addr, ifHeader.successors[0].addr, gotoHeader.addr, ifHeader.nextAddr,
ifHeader.successors, ifHeader.outer); ifHeader.successors, ifHeader.outer);
this.instr = ifHeader.instr; this.instr = ifHeader.instr;
this.outer = ifHeader.outer; this.outer = ifHeader.outer;
this.endBlock = this;
this.movePredecessors(ifHeader); this.addPredecessors(ifHeader);
this.addr = successors[1].addr; for (int i=0; i < successors.length; i++) {
prev.flowType = NORMAL; successors[i].predecessors.removeElement(ifHeader);
successors[i].predecessors.addElement(this);
}
if (successors[0].flowType == GOTO) {
successors[0].predecessors.removeElement(this);
successors[0] = successors[0].successors[0];
successors[0].predecessors.addElement(this);
}
if (gotoHeader != ifHeader) {
this.addPredecessors(gotoHeader);
gotoHeader.successors[0].predecessors.removeElement(gotoHeader);
}
this.prevInstruction = successors[1].prevInstruction; this.prevInstruction = gotoHeader.prevInstruction;
if (prevInstruction != null) if (prevInstruction != null)
prevInstruction.nextInstruction = this; prevInstruction.nextInstruction = this;
@ -60,23 +68,28 @@ public class WhileInstructionHeader extends InstructionHeader {
if (nextInstruction != null) if (nextInstruction != null)
nextInstruction.prevInstruction = this; nextInstruction.prevInstruction = this;
successors[0].predecessors.removeElement(ifHeader);
successors[1].predecessors.removeElement(ifHeader);
successors[0].predecessors.addElement(this);
successors[1].predecessors.addElement(this);
if (successors[1] != this) { if (successors[1] != this) {
successors[1].prevInstruction = null; successors[1].prevInstruction = null;
for (InstructionHeader ih = successors[1]; ih != null; for (InstructionHeader ih = successors[1]; ih != null;
ih = ih.nextInstruction) { ih = ih.nextInstruction) {
if (ih.outer == outer) if (ih.outer == outer)
ih.outer = this; ih.outer = this;
if (ih.nextInstruction == this) if (ih.nextInstruction == ifHeader)
ih.nextInstruction = null; ih.nextInstruction = null;
} }
} }
} }
/**
* 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() {
return this;
}
public void dumpSource(TabbedPrintWriter writer) public void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
@ -91,7 +104,7 @@ public class WhileInstructionHeader extends InstructionHeader {
writer.tab(); writer.tab();
} }
boolean braces = (successors[1] == this || boolean braces = (successors[1].flowType != NORMAL ||
successors[1].nextInstruction != null); successors[1].nextInstruction != null);
writer.println("while (" + instr.toString() + ")" + writer.println("while (" + instr.toString() + ")" +
(braces ? " {": "")); (braces ? " {": ""));

Loading…
Cancel
Save