*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@40 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 27 years ago
parent 5544356bf9
commit e353bf575c
  1. 6
      jode/jode/Decompiler.java
  2. 131
      jode/jode/decompiler/CodeAnalyzer.java
  3. 9
      jode/jode/decompiler/LocalInfo.java
  4. 5
      jode/jode/expr/ArrayLoadOperator.java
  5. 6
      jode/jode/expr/AssignOperator.java
  6. 10
      jode/jode/expr/BinaryOperator.java
  7. 7
      jode/jode/expr/CompareBinaryOperator.java
  8. 4
      jode/jode/expr/Expression.java
  9. 4
      jode/jode/expr/IfThenElseOperator.java
  10. 4
      jode/jode/expr/Instruction.java
  11. 6
      jode/jode/expr/LocalLoadOperator.java
  12. 7
      jode/jode/expr/LocalStoreOperator.java
  13. 4
      jode/jode/expr/Operator.java
  14. 6
      jode/jode/expr/PostFixOperator.java
  15. 9
      jode/jode/expr/UnaryOperator.java
  16. 8
      jode/jode/flow/BreakBlock.java
  17. 3
      jode/jode/flow/CatchBlock.java
  18. 7
      jode/jode/flow/ConditionalBlock.java
  19. 17
      jode/jode/flow/EmptyBlock.java
  20. 559
      jode/jode/flow/FlowBlock.java
  21. 14
      jode/jode/flow/IfThenElseBlock.java
  22. 10
      jode/jode/flow/InstructionBlock.java
  23. 3
      jode/jode/flow/InstructionContainer.java
  24. 18
      jode/jode/flow/Jump.java
  25. 2
      jode/jode/flow/LoopBlock.java
  26. 10
      jode/jode/flow/RemoveEmpty.java
  27. 8
      jode/jode/flow/ReturnBlock.java
  28. 11
      jode/jode/flow/SequentialBlock.java
  29. 10
      jode/jode/flow/SimplifyExpression.java
  30. 106
      jode/jode/flow/StructuredBlock.java
  31. 23
      jode/jode/flow/VariableSet.java

@ -25,7 +25,9 @@ public class Decompiler {
public static boolean isVerbose = false; public static boolean isVerbose = false;
public static boolean isDebugging = false; public static boolean isDebugging = false;
public static boolean isTypeDebugging = false; public static boolean isTypeDebugging = false;
public static boolean isFlowDebugging = false;
public static boolean showLVT = false; public static boolean showLVT = false;
public static boolean doChecks = false;
public static void main(String[] params) { public static void main(String[] params) {
JodeEnvironment env = new JodeEnvironment(); JodeEnvironment env = new JodeEnvironment();
@ -36,8 +38,12 @@ public class Decompiler {
isDebugging = true; isDebugging = true;
else if (params[i].equals("-type")) else if (params[i].equals("-type"))
isTypeDebugging = true; isTypeDebugging = true;
else if (params[i].equals("-flow"))
isFlowDebugging = true;
else if (params[i].equals("-lvt")) else if (params[i].equals("-lvt"))
showLVT = true; showLVT = true;
else if (params[i].equals("-check"))
doChecks = true;
else else
env.doClass(params[i]); env.doClass(params[i]);
} }

@ -154,62 +154,99 @@ public class CodeAnalyzer implements Analyzer, Constants {
/* XXX optimize */ /* XXX optimize */
Stack todo = new Stack(); Stack todo = new Stack();
FlowBlock flow = methodHeader; FlowBlock flow = methodHeader;
analyzation: try {
while (true) { jode.TabbedPrintWriter writer = null;
if (Decompiler.isFlowDebugging) {
/* First do some non flow transformations. */ writer = new jode.TabbedPrintWriter(System.err, " ");
int i=0;
while (i < exprTrafos.length) {
if (exprTrafos[i].transform(flow))
i = 0;
else
i++;
} }
analyzation:
while (true) {
if (flow.doT2(todo)) { if (Decompiler.isFlowDebugging) {
/* T2 transformation succeeded. This may writer.println("before Transformation: ");
* make another T1 analysis in the previous writer.tab();
* block possible. flow.dumpSource(writer);
*/ writer.untab();
if (!todo.isEmpty()) }
flow = (FlowBlock) todo.pop();
} /* First do some non flow transformations. */
int i=0;
while (i < exprTrafos.length) {
if (exprTrafos[i].transform(flow))
i = 0;
else
i++;
}
if (Decompiler.isFlowDebugging) {
writer.println("after Transformation: ");
writer.tab();
flow.dumpSource(writer);
writer.untab();
}
if (flow.doT2(todo)) {
FlowBlock succ = flow.getSuccessor(); if (Decompiler.isFlowDebugging) {
while (succ != null && !flow.doT1(succ)) { writer.println("after T2: ");
writer.tab();
flow.dumpSource(writer);
writer.untab();
}
/* T1 transformation failed. */ /* T2 transformation succeeded. This may
if (!todo.contains(succ) && succ != flow) { * make another T1 analysis in the previous
/* succ wasn't tried before, succeed with * block possible.
* successor and put flow on the stack.
*/ */
todo.push(flow); if (!todo.isEmpty())
flow = succ; flow = (FlowBlock) todo.pop();
continue analyzation;
} }
/* Try the next successor. FlowBlock succ = flow.getSuccessor();
*/ while (true) {
succ = flow.getSuccessor(succ); if (succ == null) {
} /* the Block has no successor where t1 is applicable.
if (succ == null) { *
/* the Block has no successor where t1 is applicable. * If everything is okay the stack should be empty now,
* * and the program is transformed correctly.
* If everything is okay the stack should be empty now, */
* and the program is transformed correctly. if (todo.isEmpty())
* break analyzation;
* Otherwise flow transformation didn't succeeded.
*/ /* Otherwise pop the last flow block from stack and
// System.err.println("breaking analyzation; flow: " * try another successor.
// + flow.getLabel()); */
while (!todo.isEmpty()) { succ = flow;
System.err.println("on Stack: " flow = (FlowBlock) todo.pop();
+ ((FlowBlock)todo.pop()).getLabel()); } else if (flow.doT1(succ)) {
/* T1 transformation succeeded. */
if (Decompiler.isFlowDebugging) {
writer.println("after T1: ");
writer.tab();
flow.dumpSource(writer);
writer.untab();
}
if (Decompiler.isVerbose)
System.err.print(".");
continue analyzation;
} else if (!todo.contains(succ) && succ != flow) {
/* succ wasn't tried before, succeed with
* successor and put flow on the stack.
*/
todo.push(flow);
flow = succ;
continue analyzation;
}
/* Try the next successor.
*/
succ = flow.getSuccessor(succ);
} }
break analyzation;
} }
if (Decompiler.isVerbose) } catch (java.io.IOException ioex) {
System.err.print(".");
} }
} }

@ -37,7 +37,6 @@ public class LocalInfo {
private Identifier name; private Identifier name;
private Type type; private Type type;
private LocalInfo shadow; private LocalInfo shadow;
private jode.flow.StructuredBlock defining;
/* The current implementation may use very much stack. This /* The current implementation may use very much stack. This
* should be changed someday. * should be changed someday.
@ -156,14 +155,6 @@ public class LocalInfo {
return this.type; return this.type;
} }
public jode.flow.StructuredBlock getDefining() {
return getLocalInfo().defining;
}
public void setDefining(jode.flow.StructuredBlock structuredBlock) {
getLocalInfo().defining = structuredBlock;
}
public boolean isShadow() { public boolean isShadow() {
return (shadow != null); return (shadow != null);
} }

@ -40,15 +40,12 @@ public class ArrayLoadOperator extends SimpleOperator {
/** /**
* Sets the return type of this operator. * Sets the return type of this operator.
* @return true if the operand types changed
*/ */
public boolean setType(Type type) { public void setType(Type type) {
if (type != this.type) { if (type != this.type) {
super.setType(type); super.setType(type);
operandTypes[0] = Type.tArray(type); operandTypes[0] = Type.tArray(type);
return true;
} }
return false;
} }
public void setOperandType(Type[] t) { public void setOperandType(Type[] t) {

@ -50,12 +50,10 @@ public class AssignOperator extends Operator {
/** /**
* Sets the return type of this operator. * Sets the return type of this operator.
* @return true if the operand types changed
*/ */
public boolean setType(Type type) { public void setType(Type type) {
boolean result = store.setLValueType(type); store.setLValueType(type);
super.setType(store.getLValueType()); super.setType(store.getLValueType());
return result;
} }
/** /**

@ -74,15 +74,9 @@ public class BinaryOperator extends Operator {
/** /**
* Sets the return type of this operator. * Sets the return type of this operator.
* @return true if the operand types changed
*/ */
public boolean setType(Type newType) { public void setType(Type newType) {
operandType = MyType.intersection(operandType, newType); type = operandType = MyType.intersection(operandType, newType);
if (type != operandType) {
type = operandType;
return true;
}
return false;
} }
public boolean equals(Object o) { public boolean equals(Object o) {

@ -44,6 +44,13 @@ public class CompareBinaryOperator extends SimpleOperator {
return getPriority()+i; return getPriority()+i;
} }
public void setOperandType(Type[] inputTypes) {
super.setOperandType(inputTypes);
Type operandType =
MyType.intersection(operandTypes[0],operandTypes[1]);
operandTypes[0] = operandTypes[1] = operandType;
}
public boolean equals(Object o) { public boolean equals(Object o) {
return (o instanceof CompareBinaryOperator) && return (o instanceof CompareBinaryOperator) &&
((CompareBinaryOperator)o).operator == operator; ((CompareBinaryOperator)o).operator == operator;

@ -134,7 +134,9 @@ public class Expression extends Instruction {
if (operator.getPriority() < minPriority) { if (operator.getPriority() < minPriority) {
result = "("+result+")"; result = "("+result+")";
} }
if (operator.getType() == MyType.tError) if (Decompiler.isTypeDebugging)
result = "(("+operator.getType()+")"+result+")";
else if (operator.getType() == MyType.tError)
result = "(/*type error */" + result+")"; result = "(/*type error */" + result+")";
return result; return result;
} }

@ -58,14 +58,12 @@ public class IfThenElseOperator extends SimpleOperator {
* Sets the return type of this operator. * Sets the return type of this operator.
* @return true if the operand types changed * @return true if the operand types changed
*/ */
public boolean setType(Type newType) { public void setType(Type newType) {
Type operandType = Type operandType =
MyType.intersection(operandTypes[1], newType); MyType.intersection(operandTypes[1], newType);
if (type != operandType) { if (type != operandType) {
type = operandTypes[1] = operandTypes[2] = operandType; type = operandTypes[1] = operandTypes[2] = operandType;
return true;
} }
return false;
} }
public boolean equals(Object o) { public boolean equals(Object o) {

@ -31,6 +31,10 @@ public abstract class Instruction {
return type; return type;
} }
public void setType(Type newType) {
this.type = newType;
}
public Instruction simplify() { public Instruction simplify() {
return this; return this;
} }

@ -43,7 +43,7 @@ implements LocalVarOperator {
// } // }
public LocalInfo getLocalInfo() { public LocalInfo getLocalInfo() {
return local; return local.getLocalInfo();
} }
public Type getType() { public Type getType() {
@ -51,9 +51,9 @@ implements LocalVarOperator {
return local.getType(); return local.getType();
} }
public boolean setType(Type type) { public void setType(Type type) {
// System.err.println("LocalLoad.setType of "+local.getName()+": "+local.getType()); // System.err.println("LocalLoad.setType of "+local.getName()+": "+local.getType());
return super.setType(local.setType(type)); super.setType(local.setType(type));
} }
// public int getSlot() { // public int getSlot() {

@ -37,13 +37,8 @@ implements LocalVarOperator {
return true; return true;
} }
// public void setLocalInfo(LocalInfo local) {
// local.setType(lvalueType);
// this.local = local;
// }
public LocalInfo getLocalInfo() { public LocalInfo getLocalInfo() {
return local; return local.getLocalInfo();
} }
public Type getLValueType() { public Type getLValueType() {

@ -68,11 +68,9 @@ public abstract class Operator extends Instruction {
/** /**
* Sets the return type of this operator. * Sets the return type of this operator.
* @return true if the operand types changed
*/ */
public boolean setType(Type type) { public void setType(Type type) {
this.type = type; this.type = type;
return false;
} }
public String getOperatorString() { public String getOperatorString() {

@ -53,12 +53,10 @@ public class PostFixOperator extends Operator {
/** /**
* Sets the return type of this operator. * Sets the return type of this operator.
* @return true if the operand types changed
*/ */
public boolean setType(Type type) { public void setType(Type type) {
boolean result = store.setLValueType(type); store.setLValueType(type);
super.setType(store.getLValueType()); super.setType(store.getLValueType());
return result;
} }
public void setOperandType(Type[] inputTypes) { public void setOperandType(Type[] inputTypes) {

@ -35,16 +35,11 @@ public class UnaryOperator extends SimpleOperator {
/** /**
* Sets the return type of this operator. * Sets the return type of this operator.
* @return true if the operand types changed
*/ */
public boolean setType(Type type) { public void setType(Type type) {
super.setType(type); super.setType(type);
Type newOpType = MyType.intersection(type, operandTypes[0]); Type newOpType = MyType.intersection(type, operandTypes[0]);
if (newOpType != operandTypes[0]) { operandTypes[0] = newOpType;
operandTypes[0] = newOpType;
return true;
}
return false;
} }
public boolean equals(Object o) { public boolean equals(Object o) {

@ -63,6 +63,14 @@ public class BreakBlock extends StructuredBlock {
return breaksBlock.getNextFlowBlock(); return breaksBlock.getNextFlowBlock();
} }
/**
* Tells if this block needs braces when used in a if or while block.
* @return true if this block should be sorrounded by braces.
*/
public boolean needsBraces() {
return false;
}
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {

@ -85,8 +85,7 @@ public class CatchBlock extends StructuredBlock {
? new EmptyBlock() ? new EmptyBlock()
: catchBlock.getSubBlocks()[1]); : catchBlock.getSubBlocks()[1]);
if (catchBlock.jump != null) newCatchBlock.moveJump(catchBlock.jump);
newCatchBlock.moveJump(catchBlock);
catchBlock = newCatchBlock; catchBlock = newCatchBlock;
} }
} }

@ -34,10 +34,9 @@ public class ConditionalBlock extends InstructionContainer {
*/ */
public ConditionalBlock(Instruction cond, Jump condJump, Jump elseJump) { public ConditionalBlock(Instruction cond, Jump condJump, Jump elseJump) {
super(cond, elseJump); super(cond, elseJump);
if (cond instanceof LocalVarOperator) { /* cond is a CompareBinary or CompareUnary operator, so no
LocalVarOperator varOp = (LocalVarOperator) cond; * check for LocalVarOperator (for condJump) is needed here.
condJump.out.addElement(varOp.getLocalInfo()); */
}
trueBlock = new EmptyBlock(condJump); trueBlock = new EmptyBlock(condJump);
trueBlock.outer = this; trueBlock.outer = this;
} }

@ -31,6 +31,23 @@ public class EmptyBlock extends StructuredBlock {
setJump(jump); setJump(jump);
} }
/**
* Appends a block to this block.
* @return the new combined block.
*/
public StructuredBlock appendBlock(StructuredBlock block) {
if (outer instanceof ConditionalBlock) {
IfThenElseBlock ifBlock =
new IfThenElseBlock(((ConditionalBlock)outer).
getInstruction());
ifBlock.replace(outer, this);
ifBlock.moveJump(outer.jump);
ifBlock.setThenBlock(this);
}
block.replace(this, null);
return block;
}
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {

@ -131,7 +131,7 @@ public class FlowBlock {
newBlock.setCatchBlock(catchBlock); newBlock.setCatchBlock(catchBlock);
if (sequBlock.jump != null) { if (sequBlock.jump != null) {
if (newBlock.catchBlock.jump == null) if (newBlock.catchBlock.jump == null)
newBlock.catchBlock.moveJump(sequBlock); newBlock.catchBlock.moveJump(sequBlock.jump);
else else
sequBlock.removeJump(); sequBlock.removeJump();
} }
@ -156,28 +156,62 @@ public class FlowBlock {
if (jump == null || jump.destination != successor) if (jump == null || jump.destination != successor)
continue next_jump; continue next_jump;
same_jump: while(true) { while(jump != null) {
if (jump.prev instanceof EmptyBlock
&& jump.prev.outer != null
&& jump.prev.outer instanceof ConditionalBlock
&& jump.prev.outer.jump != null) {
if (jump.prev.outer.jump.destination == jump.destination) {
/* This is a weired "if (cond) empty"-block. We
* transform it by hand.
*/
jump.prev.removeJump();
continue next_jump;
}
/* Swap conditional blocks, that have two jumps, and where
* this jump is the inner jump.
*/
StructuredBlock prev = jump.prev;
ConditionalBlock cb = (ConditionalBlock) prev.outer;
jode.Instruction instr = cb.getInstruction();
/* XXX Expression clean up is necessary. Otherwise
* this may lead to a ClassCastException.
*
* Our code below _depends_ on the fact that this
* transformation is done.
*/
cb.setInstruction(((jode.Expression)instr).negate());
cb.swapJump(jump.prev);
}
/* Now move the jump as far to the outer as possible,
* without leaving appendBlock.
*
* Note: jump.prev != appendblock implies
* jump.prev.outer != null, since appendBlock is an outer
* block of jump.prev
*/
while (jump.prev != appendBlock
&& jump.prev.outer.isSingleExit(jump.prev)) {
jump.prev.outer.moveJump(jump);
}
/* if the jump is the jump of the appendBlock, skip it. /* if the jump is the jump of the appendBlock, skip it.
*/ */
if (jump.prev == null || jump.prev == appendBlock) if (jump.prev == appendBlock)
continue next_jump; continue next_jump;
/* Note: jump.prev.outer != null, since appendBlock is /* remove this jump if it jumps to the getNextFlowBlock().
* an outer block of jump.prev */
*/
/* remove all jumps to the successor which have the successor
* as getNextFlowBlock().
*/
if (jump.prev.outer.getNextFlowBlock(jump.prev) == successor) { if (jump.prev.outer.getNextFlowBlock(jump.prev) == successor) {
jump.prev.removeJump(); jump.prev.removeJump();
continue next_jump; continue next_jump;
} }
/* replace all conditional jumps to the successor, which
* are followed by a block which has the end of the block
* as normal successor, with "if (not condition) block".
*/
if (jump.prev instanceof EmptyBlock && if (jump.prev instanceof EmptyBlock &&
jump.prev.outer instanceof ConditionalBlock) { jump.prev.outer instanceof ConditionalBlock) {
@ -185,126 +219,15 @@ public class FlowBlock {
ConditionalBlock cb = (ConditionalBlock) prev.outer; ConditionalBlock cb = (ConditionalBlock) prev.outer;
jode.Instruction instr = cb.getInstruction(); jode.Instruction instr = cb.getInstruction();
/* cb.jump is null (see above), so cb must have a *
* successor in this block, that means cb.outer is not
* null.
*/
if ((cb == appendBlock || /* If this is the first instruction of a while and the
cb.outer.getNextFlowBlock(cb) == successor * condition of the while is true, use the condition
/*XXX jumpMayBeChanged()??? */) && * as while condition.
instr instanceof jode.Expression) { */
cb.setInstruction(((jode.Expression)instr).negate());
prev.removeJump();
prev.moveJump(cb);
continue next_jump;
}
/* cb.outer is not null,
* since appendBlock outers cb */
if (cb.outer instanceof SequentialBlock &&
cb.outer.getSubBlocks()[0] == cb &&
(cb.outer.getNextFlowBlock() == successor ||
cb.outer.jumpMayBeChanged()) &&
instr instanceof jode.Expression) {
SequentialBlock sequBlock =
(SequentialBlock) cb.outer;
IfThenElseBlock newIfBlock =
new IfThenElseBlock(((jode.Expression)instr).negate());
newIfBlock.replace(sequBlock, sequBlock.getSubBlocks()[1]);
newIfBlock.setThenBlock(sequBlock.getSubBlocks()[1]);
newIfBlock.moveJump(sequBlock);
if (appendBlock == sequBlock)
appendBlock = newIfBlock;
if (newIfBlock.getNextFlowBlock() != successor &&
newIfBlock != appendBlock) {
newIfBlock.moveJump(prev);
continue same_jump;
} else {
prev.removeJump();
continue next_jump;
}
}
}
/* if there are jumps in an if-then block, which
* have as normal successor the end of the if-then block, and
* the if-then block is followed by a single block, then replace
* the if-then block with a if-then-else block and remove the
* unconditional jump.
*/
StructuredBlock elseBlock =
jump.prev.outer.getNextBlock(jump.prev);
if (elseBlock != null
&& elseBlock.outer != null
&& elseBlock.outer instanceof SequentialBlock
&& elseBlock.outer.getSubBlocks()[0] instanceof IfThenElseBlock
&& (elseBlock.outer.getNextFlowBlock() == successor
|| elseBlock.outer.jumpMayBeChanged())) {
IfThenElseBlock ifBlock =
(IfThenElseBlock)elseBlock.outer.getSubBlocks()[0];
if (ifBlock.getSubBlocks().length == 1) {
/* make sure that only sequential blocks are between
* jump.prev and the ifBlock
*/
StructuredBlock block = jump.prev.outer;
while (block instanceof SequentialBlock)
block = block.outer;
if (block == ifBlock) {
elseBlock.outer.removeJump();
ifBlock.replace(elseBlock.outer, elseBlock);
if (appendBlock == elseBlock.outer)
appendBlock = ifBlock;
ifBlock.moveJump(jump.prev);
ifBlock.setElseBlock(elseBlock);
continue same_jump;
}
}
}
/* if the successor is the dummy return instruction, replace all
* jumps with a return.
*/
if (successor == END_OF_METHOD) {
SequentialBlock sequBlock = new SequentialBlock();
StructuredBlock prevBlock = jump.prev;
prevBlock.removeJump();
if (prevBlock instanceof EmptyBlock) {
if (prevBlock.outer instanceof ConditionalBlock) {
IfThenElseBlock ifBlock =
new IfThenElseBlock
(((ConditionalBlock)prevBlock.outer).
getInstruction());
ifBlock.replace(prevBlock.outer, prevBlock);
ifBlock.moveJump(prevBlock.outer);
ifBlock.setThenBlock(prevBlock);
}
new ReturnBlock().replace(prevBlock, null);
} else {
sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond(new ReturnBlock());
}
continue next_jump;
}
/* If this is a conditional jump, the first instruction of
* a while and the condition of the while is true, use
* the condition as while condition.
*/
if (jump.prev instanceof EmptyBlock &&
jump.prev.outer instanceof ConditionalBlock &&
jump.prev.outer.jump == null) {
StructuredBlock prev = jump.prev;
ConditionalBlock cb = (ConditionalBlock) prev.outer;
jode.Instruction instr = cb.getInstruction();
/* This is the first instruction in a while block */ /* This is the first instruction in a while block */
if (cb.outer instanceof SequentialBlock && if (cb.outer instanceof SequentialBlock &&
@ -320,10 +243,14 @@ public class FlowBlock {
prev.removeJump(); prev.removeJump();
loopBlock.setCondition(((Expression)instr).negate()); loopBlock.setCondition(((Expression)instr).negate());
if (cb.outer.jump != null) { if (cb.outer.jump != null) {
if (cb.outer.getSubBlocks()[1].jump != null) /* XXX can this happen */
if (cb.outer.getSubBlocks()[1].jump != null) {
/* XXX if above can happen,
* can this happen at all??? */
cb.outer.removeJump(); cb.outer.removeJump();
else } else
cb.outer.getSubBlocks()[1].moveJump(cb.outer); cb.outer.getSubBlocks()[1].
moveJump(cb.outer.jump);
} }
cb.outer.getSubBlocks()[1].replace cb.outer.getSubBlocks()[1].replace
(cb.outer, cb.outer.getSubBlocks()[1]); (cb.outer, cb.outer.getSubBlocks()[1]);
@ -354,58 +281,134 @@ public class FlowBlock {
continue next_jump; continue next_jump;
} }
} }
/* replace all conditional jumps to the successor, which
* are followed by a block which has the end of the block
* as normal successor, with "if (not condition) block".
*/
if (cb.outer instanceof SequentialBlock &&
cb.outer.getSubBlocks()[0] == cb &&
(cb.outer.getNextFlowBlock() == successor ||
cb.outer.jumpMayBeChanged()) &&
instr instanceof jode.Expression) {
SequentialBlock sequBlock =
(SequentialBlock) cb.outer;
IfThenElseBlock newIfBlock =
new IfThenElseBlock(((jode.Expression)instr).negate());
newIfBlock.replace(sequBlock, sequBlock.getSubBlocks()[1]);
newIfBlock.setThenBlock(sequBlock.getSubBlocks()[1]);
newIfBlock.moveJump(sequBlock.jump);
if (appendBlock == sequBlock)
appendBlock = newIfBlock;
if (newIfBlock.getNextFlowBlock() != successor &&
newIfBlock != appendBlock) {
newIfBlock.moveJump(jump);
continue;
} else {
prev.removeJump();
continue next_jump;
}
}
}
/* if this is a jumps at the end of a then block belonging
* to a if-then block without else part, and the if-then
* block is followed by a single block, then replace the
* if-then block with a if-then-else block and remove the
* unconditional jump.
*/
else if (jump.prev.outer instanceof IfThenElseBlock) {
IfThenElseBlock ifBlock =
(IfThenElseBlock)jump.prev.outer;
if (ifBlock.elseBlock == null
&& ifBlock.jump == null
&& ifBlock.outer instanceof SequentialBlock
&& ifBlock.outer.getSubBlocks()[0] == ifBlock
&& (ifBlock.outer.getNextFlowBlock() == successor
|| ifBlock.outer.jumpMayBeChanged())) {
StructuredBlock elseBlock =
ifBlock.outer.getSubBlocks()[1];
ifBlock.outer.removeJump();
ifBlock.replace(ifBlock.outer, elseBlock);
if (appendBlock == elseBlock.outer)
appendBlock = ifBlock;
ifBlock.moveJump(jump);
ifBlock.setElseBlock(elseBlock);
continue;
}
} }
/* if there are jumps in a while block or switch block and the /* if this is a jump in a breakable block, and that block
* while/switch block is followed by a jump to successor or has * has not yet a next block, then create a new jump to that
* successor as getNextFlowBlock(), replace jump with break to * successor.
* the innermost such while/switch block.
* *
* If the switch block hasn't been breaked before we could * The break to the block will be generated later.
* take some heuristics and add a jump after the switch to
* succesor, so that the above succeeds.
*/ */
int breaklevel = 0;
for (StructuredBlock surrounder = jump.prev.outer; for (StructuredBlock surrounder = jump.prev.outer;
surrounder != null && surrounder != appendBlock.outer; surrounder != null && surrounder != appendBlock.outer;
surrounder = surrounder.outer) { surrounder = surrounder.outer) {
if (surrounder instanceof BreakableBlock) { if (surrounder instanceof BreakableBlock) {
breaklevel++; if (surrounder.getNextFlowBlock() != successor
if (surrounder.getNextFlowBlock() == successor || && surrounder.jumpMayBeChanged()) {
surrounder.jumpMayBeChanged()) {
surrounder.setJump(new Jump(successor));
SequentialBlock sequBlock = new SequentialBlock(); successors.addElement(surrounder.jump);
StructuredBlock prevBlock = jump.prev;
if (surrounder.getNextFlowBlock() != successor)
surrounder.moveJump(prevBlock);
else
prevBlock.removeJump();
if (prevBlock instanceof EmptyBlock) {
if (prevBlock.outer instanceof ConditionalBlock) {
IfThenElseBlock ifBlock =
new IfThenElseBlock
(((ConditionalBlock)prevBlock.outer)
.getInstruction());
ifBlock.replace(prevBlock.outer, prevBlock);
ifBlock.moveJump(prevBlock.outer);
ifBlock.setThenBlock(prevBlock);
}
new BreakBlock((BreakableBlock) surrounder,
breaklevel >1
).replace(prevBlock, null);
} else {
sequBlock.replace(prevBlock, prevBlock);
sequBlock.setFirst(prevBlock);
sequBlock.setSecond
(new BreakBlock((BreakableBlock) surrounder,
breaklevel > 1));
}
continue same_jump;
} }
} }
} }
// /* XXX - There is a problem with this.
// * The here created break could be obsoleted later.
// * We should instead only add the jump to surrounder
// * if necessary and add the break after all jumps
// * has been considered.
// */
// /* if there are jumps in a while block or switch block and the
// * while/switch block is followed by a jump to successor or has
// * successor as getNextFlowBlock(), replace jump with break to
// * the innermost such while/switch block.
// *
// * If the switch block hasn't been breaked before we could
// * take some heuristics and add a jump after the switch to
// * succesor, so that the above succeeds.
// */
// int breaklevel = 0;
// for (StructuredBlock surrounder = jump.prev.outer;
// surrounder != null && surrounder != appendBlock.outer;
// surrounder = surrounder.outer) {
// if (surrounder instanceof BreakableBlock) {
// breaklevel++;
// if (surrounder.getNextFlowBlock() == successor ||
// surrounder.jumpMayBeChanged()) {
// SequentialBlock sequBlock = new SequentialBlock();
// StructuredBlock prevBlock = jump.prev;
// if (surrounder.getNextFlowBlock() != successor)
// surrounder.moveJump(prevBlock.jump);
// else {
// prevBlock.removeJump();
// jump = null;
// }
// prevBlock.appendBlock
// (new BreakBlock((BreakableBlock) surrounder,
// breaklevel >1));
// continue;
// }
// }
// }
continue next_jump; continue next_jump;
} }
} }
@ -419,23 +422,23 @@ public class FlowBlock {
* block. * block.
* @return The variables that must be defined in this block. * @return The variables that must be defined in this block.
*/ */
VariableSet updateInOut (FlowBlock successor, boolean t1Transformation) { void updateInOut (FlowBlock successor, boolean t1Transformation) {
/* First get the out vectors of all jumps to successor and /* First get the out vectors of all jumps to successor and
* calculate the intersection. * calculate the intersection.
*/ */
VariableSet allOuts = new VariableSet(); VariableSet gens = new VariableSet();
VariableSet intersectOut = null; VariableSet kills = null;
Enumeration enum = successors.elements(); Enumeration enum = successors.elements();
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement(); Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != successor) if (jump == null || jump.destination != successor)
continue; continue;
allOuts.union(jump.out); gens.unionExact(jump.gen);
if (intersectOut == null) if (kills == null)
intersectOut = jump.out; kills = jump.kill;
else else
intersectOut = intersectOut.intersect(jump.out); kills = kills.intersect(jump.kill);
} }
// System.err.println("UpdateInOut: allOuts : "+allOuts); // System.err.println("UpdateInOut: allOuts : "+allOuts);
@ -444,26 +447,25 @@ public class FlowBlock {
/* Merge the locals used in successing block with those written /* Merge the locals used in successing block with those written
* by this blocks * by this blocks
*/ */
VariableSet defineHere = successor.in.merge(allOuts); successor.in.merge(gens);
defineHere.subtractExact(in);
/* Now update in and out set of successing block */
// System.err.println(" defineHere : "+defineHere);
if (t1Transformation) { if (t1Transformation)
/* Now update in and out set of successing block */ successor.in.subtract(kills);
successor.in.subtract(intersectOut); /* The gen/kill sets must be updated for every jump in the block */
/* The out set must be updated for every jump in the block */ enum = successor.successors.elements();
enum = successor.successors.elements(); while (enum.hasMoreElements()) {
while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement();
Jump jump = (Jump) enum.nextElement(); if (jump != null) {
if (jump != null) jump.gen.mergeGenKill(gens, jump.kill);
jump.out.add(intersectOut); if (t1Transformation)
jump.kill.add(kills);
} }
} }
// System.err.println(" successor.in: "+successor.in); // System.err.println(" successor.in: "+successor.in);
in.union(successor.in); in.unionExact(successor.in);
// System.err.println(" in : "+in); // System.err.println(" in : "+in);
/* XXX - do something with defineHere */
return defineHere; /*XXX - correct???*/
} }
@ -566,6 +568,8 @@ public class FlowBlock {
} }
public void checkConsistent() { public void checkConsistent() {
if (!jode.Decompiler.doChecks)
return;
if (block.outer != null || block.flowBlock != this) { if (block.outer != null || block.flowBlock != this) {
throw new RuntimeException("Inconsistency"); throw new RuntimeException("Inconsistency");
} }
@ -611,11 +615,7 @@ public class FlowBlock {
return false; return false;
try{ try{
// System.err.println("doing T1 analysis on: "+getLabel());
// System.err.println("***in: "+in);
checkConsistent(); checkConsistent();
// System.err.println("and "+succ.getLabel());
// System.err.println("+++in: "+succ.in);
succ.checkConsistent(); succ.checkConsistent();
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
ex.printStackTrace(); ex.printStackTrace();
@ -624,7 +624,7 @@ public class FlowBlock {
new jode.TabbedPrintWriter(System.err, " "); new jode.TabbedPrintWriter(System.err, " ");
writer.tab(); writer.tab();
block.dumpSource(writer); block.dumpSource(writer);
succ.block.dumpSource(writer); succ.block.dumpSource(writer);
} catch (java.io.IOException ioex) { } catch (java.io.IOException ioex) {
} }
} }
@ -658,7 +658,7 @@ public class FlowBlock {
} }
/* Update the in/out-Vectors now */ /* Update the in/out-Vectors now */
VariableSet defineHere = updateInOut(succ, true); updateInOut(succ, true);
/* The switch "fall through" case: if the appendBlock is a /* The switch "fall through" case: if the appendBlock is a
* switch, and the successor is the address of a case, and all * switch, and the successor is the address of a case, and all
@ -669,7 +669,7 @@ public class FlowBlock {
if (appendBlock instanceof SwitchBlock) { if (appendBlock instanceof SwitchBlock) {
nextcase = ((SwitchBlock) appendBlock).findCase(succ); nextcase = ((SwitchBlock) appendBlock).findCase(succ);
precedingcase = precedingcase =
((SwitchBlock) appendBlock).prevCase(precedingcase); ((SwitchBlock) appendBlock).prevCase(nextcase);
enum = successors.elements(); enum = successors.elements();
while (nextcase != null && enum.hasMoreElements()) { while (nextcase != null && enum.hasMoreElements()) {
@ -680,8 +680,7 @@ public class FlowBlock {
|| (precedingcase != null || (precedingcase != null
&& precedingcase.contains(jump.prev))) && precedingcase.contains(jump.prev)))
continue; continue;
nextcase = null;
nextcase = null;
} }
} }
if (succ == END_OF_METHOD) { if (succ == END_OF_METHOD) {
@ -696,8 +695,6 @@ public class FlowBlock {
/* Do the following modifications on the struct block. */ /* Do the following modifications on the struct block. */
appendBlock = precedingcase; appendBlock = precedingcase;
succ.block.setFlowBlock(this);
// switchBlock.define(defineHere);
} else { } else {
@ -723,8 +720,6 @@ public class FlowBlock {
sequBlock.replace(appendBlock, appendBlock); sequBlock.replace(appendBlock, appendBlock);
sequBlock.setFirst(appendBlock); sequBlock.setFirst(appendBlock);
sequBlock.setSecond(succ.block); sequBlock.setSecond(succ.block);
succ.block.setFlowBlock(this);
// sequBlock.define(defineHere);
} }
/* Merge the sucessors from the successing flow block /* Merge the sucessors from the successing flow block
@ -743,89 +738,108 @@ public class FlowBlock {
} }
} }
try {
// System.err.println("before optimizeJump: "+getLabel());
checkConsistent();
} catch (RuntimeException ex) {
ex.printStackTrace();
try { try {
jode.TabbedPrintWriter writer = checkConsistent();
new jode.TabbedPrintWriter(System.err, " "); } catch (RuntimeException ex) {
writer.tab(); ex.printStackTrace();
try {
jode.TabbedPrintWriter writer =
new jode.TabbedPrintWriter(System.err, " ");
writer.tab();
block.dumpSource(writer); block.dumpSource(writer);
} catch (java.io.IOException ioex) { } catch (java.io.IOException ioex) {
}
} }
}
/* Try to eliminate as many jumps as possible. /* Try to eliminate as many jumps as possible.
*/ */
appendBlock = optimizeJumps(succ, appendBlock);
try {
// System.err.println("after optimizeJump: "+getLabel());
checkConsistent();
} catch (RuntimeException ex) {
ex.printStackTrace();
try {
jode.TabbedPrintWriter writer =
new jode.TabbedPrintWriter(System.err, " ");
writer.tab();
block.dumpSource(writer);
} catch (java.io.IOException ioex) {
}
}
/* appendBlock may be zero, if this is the switchcase with /* appendBlock may be zero, if this is the switchcase with
* precedingcase = null. But in this case, there can't be * precedingcase = null. But in this case, there can't be
* any jumps. * any jumps.
*/ */
if (appendBlock != null) { if (appendBlock != null) {
/* Now remove the jump of the appendBlock if it points to
* successor.
*/
if (appendBlock.jump != null
&& appendBlock.jump.destination == succ)
appendBlock.removeJump();
/* If there are further jumps, put a do/while(0) block around appendBlock = optimizeJumps(succ, appendBlock);
* appendBlock and replace every remaining jump with a break
* to the do/while block. try {
*/ checkConsistent();
} catch (RuntimeException ex) {
ex.printStackTrace();
try {
jode.TabbedPrintWriter writer =
new jode.TabbedPrintWriter(System.err, " ");
writer.tab();
block.dumpSource(writer);
} catch (java.io.IOException ioex) {
}
}
LoopBlock doWhileFalse = null; LoopBlock doWhileFalse = null;
enum = successors.elements(); enum = successors.elements();
next_jump:
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
Jump jump = (Jump) enum.nextElement(); Jump jump = (Jump) enum.nextElement();
if (jump == null || jump.destination != succ) if (jump == null || jump.destination != succ ||
jump.prev == appendBlock)
continue; continue;
if (doWhileFalse == null) int breaklevel = 0;
doWhileFalse = new LoopBlock(LoopBlock.DOWHILE, BreakableBlock breakToBlock = null;
LoopBlock.FALSE); for (StructuredBlock surrounder = jump.prev.outer;
surrounder != null && surrounder != appendBlock.outer;
int breaklevel = 1; surrounder = surrounder.outer) {
for (StructuredBlock surrounder = jump.prev.outer; if (surrounder instanceof BreakableBlock) {
surrounder != appendBlock.outer; breaklevel++;
surrounder = surrounder.outer) { if (surrounder.getNextFlowBlock() == succ) {
if (surrounder instanceof BreakableBlock) { breakToBlock = (BreakableBlock) surrounder;
breaklevel++; break;
} }
} /* We don't want labeled breaks, if we can
* simply return. */
if (succ == END_OF_METHOD)
break;
}
}
SequentialBlock sequBlock = new SequentialBlock(); StructuredBlock prevBlock = jump.prev;
StructuredBlock prevBlock = jump.prev; prevBlock.removeJump();
prevBlock.removeJump();
sequBlock.replace(prevBlock, prevBlock); if (breakToBlock == null) {
sequBlock.setFirst(prevBlock); /* if the successor is the dummy return instruction
sequBlock.setSecond(new BreakBlock(doWhileFalse, breaklevel > 1)); * and no simple breakToBlock could be found above,
* replace the jump with a return.
*/
if (succ == END_OF_METHOD && breakToBlock == null)
prevBlock.appendBlock(new ReturnBlock());
else {
/* Nothing else helped, so put a do/while(0)
* block around appendBlock and break to that
* block.
*/
if (doWhileFalse == null)
doWhileFalse = new LoopBlock(LoopBlock.DOWHILE,
LoopBlock.FALSE);
prevBlock.appendBlock
(new BreakBlock(doWhileFalse, breaklevel > 0));
}
} else
prevBlock.appendBlock
(new BreakBlock(breakToBlock, breaklevel > 1));
} }
if (doWhileFalse != null) { if (doWhileFalse != null) {
doWhileFalse.replace(appendBlock, appendBlock); doWhileFalse.replace(appendBlock, appendBlock);
doWhileFalse.setBody(appendBlock); doWhileFalse.setBody(appendBlock);
} }
/* Now remove the jump of the appendBlock if it points to
* successor.
*/
if (appendBlock.jump != null
&& appendBlock.jump.destination == succ)
appendBlock.removeJump();
} }
/* Believe it or not: Now the rule, that the first part of a /* Believe it or not: Now the rule, that the first part of a
@ -899,7 +913,7 @@ public class FlowBlock {
} }
/* Update the in/out-Vectors now */ /* Update the in/out-Vectors now */
VariableSet defineHere = updateInOut(this, false); updateInOut(this, false);
while (lastModified != block) { while (lastModified != block) {
@ -945,7 +959,6 @@ public class FlowBlock {
whileBlock.replace(bodyBlock, bodyBlock); whileBlock.replace(bodyBlock, bodyBlock);
whileBlock.setBody(bodyBlock); whileBlock.setBody(bodyBlock);
// whileBlock.define(defineHere);
/* Try to eliminate as many jumps as possible. /* Try to eliminate as many jumps as possible.
*/ */
@ -1069,13 +1082,13 @@ public class FlowBlock {
} }
if (!in.isEmpty()) { if (!in.isEmpty()) {
writer.print("in: "+in); writer.println("in: "+in);
} }
block.dumpSource(writer); block.dumpSource(writer);
FlowBlock succ = getSuccessor(); // FlowBlock succ = getSuccessor();
if (succ != null) // if (succ != null)
succ.dumpSource(writer); // succ.dumpSource(writer);
} }
/** /**

@ -96,7 +96,7 @@ public class IfThenElseBlock extends StructuredBlock {
public void dumpInstruction(TabbedPrintWriter writer) public void dumpInstruction(TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
boolean needBrace = ! (thenBlock instanceof InstructionBlock); boolean needBrace = thenBlock.needsBraces();
writer.println("if ("+cond.toString()+")"+(needBrace?" {":"")); writer.println("if ("+cond.toString()+")"+(needBrace?" {":""));
writer.tab(); writer.tab();
thenBlock.dumpSource(writer); thenBlock.dumpSource(writer);
@ -109,7 +109,7 @@ public class IfThenElseBlock extends StructuredBlock {
writer.print("else "); writer.print("else ");
elseBlock.dumpSource(writer); elseBlock.dumpSource(writer);
} else { } else {
needBrace = ! (elseBlock instanceof InstructionBlock); needBrace = elseBlock.needsBraces();
writer.println("else" + (needBrace ? " {" : "")); writer.println("else" + (needBrace ? " {" : ""));
writer.tab(); writer.tab();
elseBlock.dumpSource(writer); elseBlock.dumpSource(writer);
@ -139,12 +139,8 @@ public class IfThenElseBlock extends StructuredBlock {
* @return true, if the jump may be safely changed. * @return true, if the jump may be safely changed.
*/ */
public boolean jumpMayBeChanged() { public boolean jumpMayBeChanged() {
if (thenBlock.jump == null && !thenBlock.jumpMayBeChanged()) return (thenBlock.jump != null || thenBlock.jumpMayBeChanged())
return false; && elseBlock != null
&& (elseBlock.jump != null || elseBlock.jumpMayBeChanged());
if (elseBlock != null && elseBlock.jump == null &&
!elseBlock.jumpMayBeChanged())
return false;
return true;
} }
} }

@ -31,6 +31,14 @@ public class InstructionBlock extends InstructionContainer {
super(instr, jump); super(instr, jump);
} }
/**
* Tells if this block needs braces when used in a if or while block.
* @return true if this block should be sorrounded by braces.
*/
public boolean needsBraces() {
return declare != null && !declare.isEmpty();
}
/** /**
* True if this is a declaration. * True if this is a declaration.
*/ */
@ -42,7 +50,7 @@ public class InstructionBlock extends InstructionContainer {
if (instr instanceof Expression if (instr instanceof Expression
&& ((Expression)instr).getOperator() instanceof LocalStoreOperator && ((Expression)instr).getOperator() instanceof LocalStoreOperator
&& ((LocalStoreOperator) ((Expression)instr).getOperator()) && ((LocalStoreOperator) ((Expression)instr).getOperator())
.getLocalInfo() == local) { .getLocalInfo() == local.getLocalInfo()) {
isDeclaration = true; isDeclaration = true;
} else } else
super.dumpDeclaration(writer, local); super.dumpDeclaration(writer, local);

@ -36,7 +36,8 @@ public abstract class InstructionContainer extends StructuredBlock {
if (instr instanceof LocalVarOperator) { if (instr instanceof LocalVarOperator) {
LocalVarOperator varOp = (LocalVarOperator) instr; LocalVarOperator varOp = (LocalVarOperator) instr;
used.addElement(varOp.getLocalInfo()); used.addElement(varOp.getLocalInfo());
jump.out.addElement(varOp.getLocalInfo()); jump.gen.addElement(varOp.getLocalInfo());
jump.kill.addElement(varOp.getLocalInfo());
} }
setJump(jump); setJump(jump);
} }

@ -36,12 +36,21 @@ public class Jump {
int destAddr; int destAddr;
/** /**
* The out locals. This are the locals, which must be overwritten * The kill locals. This are the slots, which must be overwritten
* in this block on every path to this jump. That means, that all * in this block on every path to this jump. That means, that all
* paths form the start of the current flow block to this jump * paths form the start of the current flow block to this jump
* contain (unconditional) assignments to this local. * contain (unconditional) assignments to this slot.
*/ */
VariableSet out = new VariableSet(); VariableSet kill = new VariableSet();
/**
* The gen locals. This are the locals, which can be overwritten
* in this block on a path to this jump. That means, that there
* exists a path form the start of the current flow block to this
* jump that contains an (unconditional) assignments to this
* local, and that is not overwritten afterwards.
*/
VariableSet gen = new VariableSet();
public Jump (int destAddr) { public Jump (int destAddr) {
this.destAddr = destAddr; this.destAddr = destAddr;
@ -75,7 +84,8 @@ public class Jump {
throws java.io.IOException throws java.io.IOException
{ {
if (jode.Decompiler.isDebugging) { if (jode.Decompiler.isDebugging) {
writer.println("out: "+ out.toString()); writer.println("gen : "+ gen.toString());
writer.println("kill: "+ kill.toString());
} }
writer.println("Attachments: "+describeAttachments()); writer.println("Attachments: "+describeAttachments());
if (destination == null) if (destination == null)

@ -135,7 +135,7 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
writer.println(label+":"); writer.println(label+":");
writer.tab(); writer.tab();
} }
boolean needBrace = ! (bodyBlock instanceof InstructionBlock); boolean needBrace = bodyBlock.needsBraces();
switch (type) { switch (type) {
case WHILE: case WHILE:
writer.print("while ("+cond.toString()+")"); writer.print("while ("+cond.toString()+")");

@ -33,8 +33,9 @@ public class RemoveEmpty implements Transformation {
Instruction instr; Instruction instr;
try { try {
block = flow.lastModified; block = flow.lastModified;
if (!(((InstructionContainer)block).getInstruction() Instruction prevInstr =
instanceof NopOperator)) ((InstructionContainer)block).getInstruction();
if (!(prevInstr instanceof NopOperator))
return false; return false;
sequBlock = (SequentialBlock)block.outer; sequBlock = (SequentialBlock)block.outer;
@ -46,6 +47,8 @@ public class RemoveEmpty implements Transformation {
if (prev.jump != null) if (prev.jump != null)
return false; return false;
instr = (Instruction) prev.getInstruction(); instr = (Instruction) prev.getInstruction();
instr.setType(jode.MyType.intersection
(instr.getType(), prevInstr.getType()));
} catch (NullPointerException ex) { } catch (NullPointerException ex) {
return false; return false;
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
@ -66,7 +69,8 @@ public class RemoveEmpty implements Transformation {
StructuredBlock block = lastBlock.outer.getSubBlocks()[0]; StructuredBlock block = lastBlock.outer.getSubBlocks()[0];
block.replace(block.outer, block); block.replace(block.outer, block);
if (block.jump == null) if (block.jump == null)
block.moveJump(lastBlock); /*XXX can this happen */
block.moveJump(lastBlock.jump);
else else
lastBlock.removeJump(); lastBlock.removeJump();
flow.lastModified = block; flow.lastModified = block;

@ -34,6 +34,14 @@ public class ReturnBlock extends InstructionContainer {
super(instr); super(instr);
} }
/**
* Tells if this block needs braces when used in a if or while block.
* @return true if this block should be sorrounded by braces.
*/
public boolean needsBraces() {
return false;
}
/** /**
* Get the underlying instruction. * Get the underlying instruction.
* @return the underlying instruction. * @return the underlying instruction.

@ -63,6 +63,16 @@ public class SequentialBlock extends StructuredBlock {
return getNextFlowBlock(); return getNextFlowBlock();
} }
/**
* Tells if the sub block is the single exit point of the current block.
* @param subBlock the sub block.
* @return true, if the sub block is the single exit point of the
* current block.
*/
public boolean isSingleExit(StructuredBlock subBlock) {
return (subBlock == subBlocks[1]);
}
/** /**
* Make the declarations, i.e. initialize the declare variable * Make the declarations, i.e. initialize the declare variable
* to correct values. This will declare every variable that * to correct values. This will declare every variable that
@ -74,6 +84,7 @@ public class SequentialBlock extends StructuredBlock {
* any local Variable, but let the first sub block do this. * any local Variable, but let the first sub block do this.
*/ */
declare = new VariableSet(); declare = new VariableSet();
subBlocks[0].used.addExact(used);
subBlocks[0].makeDeclaration(done); subBlocks[0].makeDeclaration(done);
done.addExact(used); done.addExact(used);
subBlocks[1].makeDeclaration(done); subBlocks[1].makeDeclaration(done);

@ -21,10 +21,20 @@ package jode.flow;
public class SimplifyExpression implements Transformation { public class SimplifyExpression implements Transformation {
public boolean transform(FlowBlock flow) { public boolean transform(FlowBlock flow) {
// try {
// jode.TabbedPrintWriter writer =
// new jode.TabbedPrintWriter(System.err, " ");
// System.out.println("Transforming: ");
// flow.lastModified.dumpSource(writer);
if (flow.lastModified instanceof InstructionContainer) { if (flow.lastModified instanceof InstructionContainer) {
InstructionContainer ic = (InstructionContainer) flow.lastModified; InstructionContainer ic = (InstructionContainer) flow.lastModified;
ic.setInstruction(ic.getInstruction().simplify()); ic.setInstruction(ic.getInstruction().simplify());
} }
// System.out.println("Result: ");
// flow.lastModified.dumpSource(writer);
// } catch (java.io.IOException ex) {
// }
return false; return false;
} }
} }

@ -150,6 +150,16 @@ public abstract class StructuredBlock {
return getNextFlowBlock(); return getNextFlowBlock();
} }
/**
* Tells if the sub block is the single exit point of the current block.
* @param subBlock the sub block.
* @return true, if the sub block is the single exit point of the
* current block.
*/
public boolean isSingleExit(StructuredBlock subBlock) {
return false;
}
/** /**
* Replaces the given sub block with a new block. * Replaces the given sub block with a new block.
* @param oldBlock the old sub block. * @param oldBlock the old sub block.
@ -180,11 +190,8 @@ public abstract class StructuredBlock {
} }
/** /**
* Removes the given jump if it is our jump. This does also * Removes the jump. This does also update the successors vector
* update the successors vector of the flow block. * of the flow block. */
*
* @param jump The jump that should be removed.
*/
public void removeJump() { public void removeJump() {
if (jump != null) { if (jump != null) {
jump.prev = null; jump.prev = null;
@ -211,8 +218,8 @@ public abstract class StructuredBlock {
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
LocalInfo var = LocalInfo var =
((LocalInfo) enum.nextElement()).getLocalInfo(); ((LocalInfo) enum.nextElement()).getLocalInfo();
used.addElement(var); if (!used.contains(var))
var.setDefining(this); used.addElement(var);
} }
from.used.removeAllElements(); from.used.removeAllElements();
StructuredBlock[] subs = from.getSubBlocks(); StructuredBlock[] subs = from.getSubBlocks();
@ -236,8 +243,7 @@ public abstract class StructuredBlock {
public void replace(StructuredBlock sb, StructuredBlock sub) { public void replace(StructuredBlock sb, StructuredBlock sub) {
moveDefinitions(sb, sub); moveDefinitions(sb, sub);
outer = sb.outer; outer = sb.outer;
flowBlock = sb.flowBlock; setFlowBlock(sb.flowBlock);
if (outer != null) { if (outer != null) {
outer.replaceSubBlock(sb, this); outer.replaceSubBlock(sb, this);
} else { } else {
@ -246,18 +252,45 @@ public abstract class StructuredBlock {
} }
/** /**
* This function moves the jumps from sb to this block. * This function swaps the jump with another block.
* The jump field of sb is removed afterwards. * @param block The block whose jump is swapped.
* @param sb The structured block whose jump is copied. */
public void swapJump(StructuredBlock block) {
Jump tmp = block.jump;
block.jump = jump;
jump = tmp;
jump.prev = this;
block.jump.prev = block;
}
/**
* This function moves the jump to this block.
* The jump field of the previous owner is cleared afterwards.
* If the given jump is null, nothing bad happens.
* @param jump The jump that should be moved, may be null.
*/ */
public void moveJump(StructuredBlock sb) { public void moveJump(Jump jump) {
jump = sb.jump; removeJump();
this.jump = jump;
if (jump != null) { if (jump != null) {
jump.prev.jump = null;
jump.prev = this; jump.prev = this;
sb.jump = null;
} }
} }
/**
* Appends a block to this block.
* @return the new combined block.
*/
public StructuredBlock appendBlock(StructuredBlock block) {
SequentialBlock sequBlock = new SequentialBlock();
sequBlock.replace(this, this);
sequBlock.setFirst(this);
sequBlock.setSecond(block);
return sequBlock;
}
/** /**
* Determines if there is a sub block, that flows through to the end * Determines if there is a sub block, that flows through to the end
* of this block. If this returns true, you know that jump is null. * of this block. If this returns true, you know that jump is null.
@ -277,18 +310,14 @@ public abstract class StructuredBlock {
public VariableSet propagateUsage() { public VariableSet propagateUsage() {
StructuredBlock[] subs = getSubBlocks(); StructuredBlock[] subs = getSubBlocks();
VariableSet[] childUse = new VariableSet[subs.length];
VariableSet allUse = (VariableSet) used.clone(); VariableSet allUse = (VariableSet) used.clone();
for (int i=0; i<subs.length; i++) { for (int i=0; i<subs.length; i++) {
childUse[i] = subs[i].propagateUsage(); VariableSet childUse = subs[i].propagateUsage();
allUse.addExact(childUse[i]); /* All variables used in more than one sub blocks, are
} * used in this block, too.
if (subs.length == 2) { */
/* All variables used in both sub blocks, are used in used.addExact(allUse.intersectExact(childUse));
* this block, too. allUse.addExact(childUse);
*/
VariableSet newUse = childUse[0].intersectExact(childUse[1]);
used.addExact(newUse);
} }
return allUse; return allUse;
} }
@ -341,11 +370,20 @@ public abstract class StructuredBlock {
this.flowBlock = flowBlock; this.flowBlock = flowBlock;
StructuredBlock[] subs = getSubBlocks(); StructuredBlock[] subs = getSubBlocks();
for (int i=0; i<subs.length; i++) { for (int i=0; i<subs.length; i++) {
subs[i].setFlowBlock(flowBlock); if (subs[i] != null)
subs[i].setFlowBlock(flowBlock);
} }
} }
} }
/**
* Tells if this block needs braces when used in a if or while block.
* @return true if this block should be sorrounded by braces.
*/
public boolean needsBraces() {
return true;
}
/** /**
* Fill all in variables into the given VariableSet. * Fill all in variables into the given VariableSet.
* @param in The VariableSet, the in variables should be stored to. * @param in The VariableSet, the in variables should be stored to.
@ -377,13 +415,17 @@ public abstract class StructuredBlock {
public void dumpSource(jode.TabbedPrintWriter writer) public void dumpSource(jode.TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
if (jode.Decompiler.isDebugging) if (declare != null) {
writer.println("declaring: "+declare); if (jode.Decompiler.isDebugging) {
writer.println("declaring: "+declare);
writer.println("using: "+used);
}
java.util.Enumeration enum = declare.elements(); java.util.Enumeration enum = declare.elements();
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
LocalInfo local = (LocalInfo) enum.nextElement(); LocalInfo local = (LocalInfo) enum.nextElement();
dumpDeclaration(writer, local); dumpDeclaration(writer, local);
}
} }
dumpInstruction(writer); dumpInstruction(writer);

@ -116,7 +116,7 @@ public class VariableSet extends java.util.Vector {
/** /**
* Union the other variable set to the current. * Union the other variable set to the current.
*/ */
public void union(VariableSet vs) { public void unionExact(VariableSet vs) {
int oldSize = elementCount; int oldSize = elementCount;
iloop: iloop:
for (int i=0; i< vs.elementCount; i++) { for (int i=0; i< vs.elementCount; i++) {
@ -172,6 +172,27 @@ public class VariableSet extends java.util.Vector {
} }
} }
/**
* Add the variables in gen to the current set, unless there are
* variables in kill using the same slot.
* @param gen The gen set.
* @param kill The kill set.
*/
public void mergeGenKill(VariableSet gen, VariableSet kill) {
iloop:
for (int i=0; i< gen.elementCount; i++) {
LocalInfo li2 = ((LocalInfo) gen.elementData[i]).getLocalInfo();
/* check if this slot was already overwritten (kill set) */
for (int j=0; j< kill.elementCount; j++) {
LocalInfo li1 = (LocalInfo) kill.elementData[j];
if (li2.getSlot() == li1.getSlot())
/* Yes it was, take next variable */
continue iloop;
}
addElement(li2);
}
}
/** /**
* Subtract the other variable set from this one. This removes * Subtract the other variable set from this one. This removes
* every variable from this set, that uses a slot in the other * every variable from this set, that uses a slot in the other

Loading…
Cancel
Save