diff --git a/jode/jode/Decompiler.java b/jode/jode/Decompiler.java index 7baf69d..90de94a 100644 --- a/jode/jode/Decompiler.java +++ b/jode/jode/Decompiler.java @@ -25,7 +25,9 @@ public class Decompiler { public static boolean isVerbose = false; public static boolean isDebugging = false; public static boolean isTypeDebugging = false; + public static boolean isFlowDebugging = false; public static boolean showLVT = false; + public static boolean doChecks = false; public static void main(String[] params) { JodeEnvironment env = new JodeEnvironment(); @@ -36,8 +38,12 @@ public class Decompiler { isDebugging = true; else if (params[i].equals("-type")) isTypeDebugging = true; + else if (params[i].equals("-flow")) + isFlowDebugging = true; else if (params[i].equals("-lvt")) showLVT = true; + else if (params[i].equals("-check")) + doChecks = true; else env.doClass(params[i]); } diff --git a/jode/jode/decompiler/CodeAnalyzer.java b/jode/jode/decompiler/CodeAnalyzer.java index 422372a..14de8b1 100644 --- a/jode/jode/decompiler/CodeAnalyzer.java +++ b/jode/jode/decompiler/CodeAnalyzer.java @@ -154,62 +154,99 @@ public class CodeAnalyzer implements Analyzer, Constants { /* XXX optimize */ Stack todo = new Stack(); FlowBlock flow = methodHeader; - analyzation: - while (true) { - - /* First do some non flow transformations. */ - int i=0; - while (i < exprTrafos.length) { - if (exprTrafos[i].transform(flow)) - i = 0; - else - i++; + try { + jode.TabbedPrintWriter writer = null; + if (Decompiler.isFlowDebugging) { + writer = new jode.TabbedPrintWriter(System.err, " "); } + analyzation: + while (true) { + + if (Decompiler.isFlowDebugging) { + writer.println("before Transformation: "); + writer.tab(); + flow.dumpSource(writer); + writer.untab(); + } + + /* First do some non flow transformations. */ + int i=0; + while (i < exprTrafos.length) { + if (exprTrafos[i].transform(flow)) + i = 0; + else + i++; + } - if (flow.doT2(todo)) { - /* T2 transformation succeeded. This may - * make another T1 analysis in the previous - * block possible. - */ - if (!todo.isEmpty()) - flow = (FlowBlock) todo.pop(); - } + if (Decompiler.isFlowDebugging) { + writer.println("after Transformation: "); + writer.tab(); + flow.dumpSource(writer); + writer.untab(); + } - FlowBlock succ = flow.getSuccessor(); - while (succ != null && !flow.doT1(succ)) { + if (flow.doT2(todo)) { - /* T1 transformation failed. */ - if (!todo.contains(succ) && succ != flow) { - /* succ wasn't tried before, succeed with - * successor and put flow on the stack. + if (Decompiler.isFlowDebugging) { + writer.println("after T2: "); + writer.tab(); + flow.dumpSource(writer); + writer.untab(); + } + + /* T2 transformation succeeded. This may + * make another T1 analysis in the previous + * block possible. */ - todo.push(flow); - flow = succ; - continue analyzation; + if (!todo.isEmpty()) + flow = (FlowBlock) todo.pop(); } + + FlowBlock succ = flow.getSuccessor(); + while (true) { + 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 (todo.isEmpty()) + break analyzation; + + /* Otherwise pop the last flow block from stack and + * try another successor. + */ + succ = flow; + flow = (FlowBlock) todo.pop(); + } 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); - } - 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. - * - * Otherwise flow transformation didn't succeeded. - */ -// System.err.println("breaking analyzation; flow: " -// + flow.getLabel()); - while (!todo.isEmpty()) { - System.err.println("on Stack: " - + ((FlowBlock)todo.pop()).getLabel()); + /* Try the next successor. + */ + succ = flow.getSuccessor(succ); } - break analyzation; } - if (Decompiler.isVerbose) - System.err.print("."); + } catch (java.io.IOException ioex) { } } diff --git a/jode/jode/decompiler/LocalInfo.java b/jode/jode/decompiler/LocalInfo.java index 3276916..e5c424f 100644 --- a/jode/jode/decompiler/LocalInfo.java +++ b/jode/jode/decompiler/LocalInfo.java @@ -37,7 +37,6 @@ public class LocalInfo { private Identifier name; private Type type; private LocalInfo shadow; - private jode.flow.StructuredBlock defining; /* The current implementation may use very much stack. This * should be changed someday. @@ -156,14 +155,6 @@ public class LocalInfo { return this.type; } - public jode.flow.StructuredBlock getDefining() { - return getLocalInfo().defining; - } - - public void setDefining(jode.flow.StructuredBlock structuredBlock) { - getLocalInfo().defining = structuredBlock; - } - public boolean isShadow() { return (shadow != null); } diff --git a/jode/jode/expr/ArrayLoadOperator.java b/jode/jode/expr/ArrayLoadOperator.java index 2f02e15..902416e 100644 --- a/jode/jode/expr/ArrayLoadOperator.java +++ b/jode/jode/expr/ArrayLoadOperator.java @@ -40,15 +40,12 @@ public class ArrayLoadOperator extends SimpleOperator { /** * 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) { super.setType(type); operandTypes[0] = Type.tArray(type); - return true; } - return false; } public void setOperandType(Type[] t) { diff --git a/jode/jode/expr/AssignOperator.java b/jode/jode/expr/AssignOperator.java index f6f76de..003a013 100644 --- a/jode/jode/expr/AssignOperator.java +++ b/jode/jode/expr/AssignOperator.java @@ -50,12 +50,10 @@ public class AssignOperator extends Operator { /** * Sets the return type of this operator. - * @return true if the operand types changed */ - public boolean setType(Type type) { - boolean result = store.setLValueType(type); + public void setType(Type type) { + store.setLValueType(type); super.setType(store.getLValueType()); - return result; } /** diff --git a/jode/jode/expr/BinaryOperator.java b/jode/jode/expr/BinaryOperator.java index 14bfb31..ff0b0ea 100644 --- a/jode/jode/expr/BinaryOperator.java +++ b/jode/jode/expr/BinaryOperator.java @@ -74,15 +74,9 @@ public class BinaryOperator extends Operator { /** * Sets the return type of this operator. - * @return true if the operand types changed */ - public boolean setType(Type newType) { - operandType = MyType.intersection(operandType, newType); - if (type != operandType) { - type = operandType; - return true; - } - return false; + public void setType(Type newType) { + type = operandType = MyType.intersection(operandType, newType); } public boolean equals(Object o) { diff --git a/jode/jode/expr/CompareBinaryOperator.java b/jode/jode/expr/CompareBinaryOperator.java index 4912701..94556d9 100644 --- a/jode/jode/expr/CompareBinaryOperator.java +++ b/jode/jode/expr/CompareBinaryOperator.java @@ -44,6 +44,13 @@ public class CompareBinaryOperator extends SimpleOperator { return getPriority()+i; } + public void setOperandType(Type[] inputTypes) { + super.setOperandType(inputTypes); + Type operandType = + MyType.intersection(operandTypes[0],operandTypes[1]); + operandTypes[0] = operandTypes[1] = operandType; + } + public boolean equals(Object o) { return (o instanceof CompareBinaryOperator) && ((CompareBinaryOperator)o).operator == operator; diff --git a/jode/jode/expr/Expression.java b/jode/jode/expr/Expression.java index 16ba75e..fded40d 100644 --- a/jode/jode/expr/Expression.java +++ b/jode/jode/expr/Expression.java @@ -134,7 +134,9 @@ public class Expression extends Instruction { if (operator.getPriority() < minPriority) { result = "("+result+")"; } - if (operator.getType() == MyType.tError) + if (Decompiler.isTypeDebugging) + result = "(("+operator.getType()+")"+result+")"; + else if (operator.getType() == MyType.tError) result = "(/*type error */" + result+")"; return result; } diff --git a/jode/jode/expr/IfThenElseOperator.java b/jode/jode/expr/IfThenElseOperator.java index 4061e2e..8638442 100644 --- a/jode/jode/expr/IfThenElseOperator.java +++ b/jode/jode/expr/IfThenElseOperator.java @@ -58,14 +58,12 @@ public class IfThenElseOperator extends SimpleOperator { * Sets the return type of this operator. * @return true if the operand types changed */ - public boolean setType(Type newType) { + public void setType(Type newType) { Type operandType = MyType.intersection(operandTypes[1], newType); if (type != operandType) { type = operandTypes[1] = operandTypes[2] = operandType; - return true; } - return false; } public boolean equals(Object o) { diff --git a/jode/jode/expr/Instruction.java b/jode/jode/expr/Instruction.java index 980c4c2..9a7e820 100644 --- a/jode/jode/expr/Instruction.java +++ b/jode/jode/expr/Instruction.java @@ -31,6 +31,10 @@ public abstract class Instruction { return type; } + public void setType(Type newType) { + this.type = newType; + } + public Instruction simplify() { return this; } diff --git a/jode/jode/expr/LocalLoadOperator.java b/jode/jode/expr/LocalLoadOperator.java index 389c630..45d95b4 100644 --- a/jode/jode/expr/LocalLoadOperator.java +++ b/jode/jode/expr/LocalLoadOperator.java @@ -43,7 +43,7 @@ implements LocalVarOperator { // } public LocalInfo getLocalInfo() { - return local; + return local.getLocalInfo(); } public Type getType() { @@ -51,9 +51,9 @@ implements LocalVarOperator { return local.getType(); } - public boolean setType(Type type) { + public void setType(Type type) { // System.err.println("LocalLoad.setType of "+local.getName()+": "+local.getType()); - return super.setType(local.setType(type)); + super.setType(local.setType(type)); } // public int getSlot() { diff --git a/jode/jode/expr/LocalStoreOperator.java b/jode/jode/expr/LocalStoreOperator.java index 83d7bf4..bbae3a6 100644 --- a/jode/jode/expr/LocalStoreOperator.java +++ b/jode/jode/expr/LocalStoreOperator.java @@ -37,13 +37,8 @@ implements LocalVarOperator { return true; } -// public void setLocalInfo(LocalInfo local) { -// local.setType(lvalueType); -// this.local = local; -// } - public LocalInfo getLocalInfo() { - return local; + return local.getLocalInfo(); } public Type getLValueType() { diff --git a/jode/jode/expr/Operator.java b/jode/jode/expr/Operator.java index 204cc39..c9501f0 100644 --- a/jode/jode/expr/Operator.java +++ b/jode/jode/expr/Operator.java @@ -68,11 +68,9 @@ public abstract class Operator extends Instruction { /** * 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; - return false; } public String getOperatorString() { diff --git a/jode/jode/expr/PostFixOperator.java b/jode/jode/expr/PostFixOperator.java index a62d4a3..a53601d 100644 --- a/jode/jode/expr/PostFixOperator.java +++ b/jode/jode/expr/PostFixOperator.java @@ -53,12 +53,10 @@ public class PostFixOperator extends Operator { /** * Sets the return type of this operator. - * @return true if the operand types changed */ - public boolean setType(Type type) { - boolean result = store.setLValueType(type); + public void setType(Type type) { + store.setLValueType(type); super.setType(store.getLValueType()); - return result; } public void setOperandType(Type[] inputTypes) { diff --git a/jode/jode/expr/UnaryOperator.java b/jode/jode/expr/UnaryOperator.java index 2a2917d..936aed0 100644 --- a/jode/jode/expr/UnaryOperator.java +++ b/jode/jode/expr/UnaryOperator.java @@ -35,16 +35,11 @@ public class UnaryOperator extends SimpleOperator { /** * 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); Type newOpType = MyType.intersection(type, operandTypes[0]); - if (newOpType != operandTypes[0]) { - operandTypes[0] = newOpType; - return true; - } - return false; + operandTypes[0] = newOpType; } public boolean equals(Object o) { diff --git a/jode/jode/flow/BreakBlock.java b/jode/jode/flow/BreakBlock.java index f0124d1..72331da 100644 --- a/jode/jode/flow/BreakBlock.java +++ b/jode/jode/flow/BreakBlock.java @@ -63,6 +63,14 @@ public class BreakBlock extends StructuredBlock { 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) throws java.io.IOException { diff --git a/jode/jode/flow/CatchBlock.java b/jode/jode/flow/CatchBlock.java index 0f7a0be..c79ec30 100644 --- a/jode/jode/flow/CatchBlock.java +++ b/jode/jode/flow/CatchBlock.java @@ -85,8 +85,7 @@ public class CatchBlock extends StructuredBlock { ? new EmptyBlock() : catchBlock.getSubBlocks()[1]); - if (catchBlock.jump != null) - newCatchBlock.moveJump(catchBlock); + newCatchBlock.moveJump(catchBlock.jump); catchBlock = newCatchBlock; } } diff --git a/jode/jode/flow/ConditionalBlock.java b/jode/jode/flow/ConditionalBlock.java index a0648eb..bc24b22 100644 --- a/jode/jode/flow/ConditionalBlock.java +++ b/jode/jode/flow/ConditionalBlock.java @@ -34,10 +34,9 @@ public class ConditionalBlock extends InstructionContainer { */ public ConditionalBlock(Instruction cond, Jump condJump, Jump elseJump) { super(cond, elseJump); - if (cond instanceof LocalVarOperator) { - LocalVarOperator varOp = (LocalVarOperator) cond; - condJump.out.addElement(varOp.getLocalInfo()); - } + /* cond is a CompareBinary or CompareUnary operator, so no + * check for LocalVarOperator (for condJump) is needed here. + */ trueBlock = new EmptyBlock(condJump); trueBlock.outer = this; } diff --git a/jode/jode/flow/EmptyBlock.java b/jode/jode/flow/EmptyBlock.java index a33e0f9..e092194 100644 --- a/jode/jode/flow/EmptyBlock.java +++ b/jode/jode/flow/EmptyBlock.java @@ -31,6 +31,23 @@ public class EmptyBlock extends StructuredBlock { 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) throws java.io.IOException { diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index fd0795f..124a2c7 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -131,7 +131,7 @@ public class FlowBlock { newBlock.setCatchBlock(catchBlock); if (sequBlock.jump != null) { if (newBlock.catchBlock.jump == null) - newBlock.catchBlock.moveJump(sequBlock); + newBlock.catchBlock.moveJump(sequBlock.jump); else sequBlock.removeJump(); } @@ -156,28 +156,62 @@ public class FlowBlock { if (jump == null || jump.destination != successor) 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 (jump.prev == null || jump.prev == appendBlock) + if (jump.prev == appendBlock) continue next_jump; - /* Note: jump.prev.outer != null, since appendBlock is - * an outer block of jump.prev - */ - - /* remove all jumps to the successor which have the successor - * as getNextFlowBlock(). - */ + /* remove this jump if it jumps to the getNextFlowBlock(). + */ if (jump.prev.outer.getNextFlowBlock(jump.prev) == successor) { jump.prev.removeJump(); 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 && jump.prev.outer instanceof ConditionalBlock) { @@ -185,126 +219,15 @@ public class FlowBlock { ConditionalBlock cb = (ConditionalBlock) prev.outer; 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 || - cb.outer.getNextFlowBlock(cb) == successor - /*XXX jumpMayBeChanged()??? */) && - 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(); + /* If this is the first instruction of a while and the + * condition of the while is true, use the condition + * as while condition. + */ /* This is the first instruction in a while block */ if (cb.outer instanceof SequentialBlock && @@ -320,10 +243,14 @@ public class FlowBlock { prev.removeJump(); loopBlock.setCondition(((Expression)instr).negate()); 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(); - else - cb.outer.getSubBlocks()[1].moveJump(cb.outer); + } else + cb.outer.getSubBlocks()[1]. + moveJump(cb.outer.jump); } cb.outer.getSubBlocks()[1].replace (cb.outer, cb.outer.getSubBlocks()[1]); @@ -354,58 +281,134 @@ public class FlowBlock { 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 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 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 this is a jump in a breakable block, and that block + * has not yet a next block, then create a new jump to that + * successor. * - * 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. + * The break to the block will be generated later. */ - 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); - 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; + if (surrounder.getNextFlowBlock() != successor + && surrounder.jumpMayBeChanged()) { + + surrounder.setJump(new Jump(successor)); + successors.addElement(surrounder.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; } } @@ -419,23 +422,23 @@ public class FlowBlock { * 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 * calculate the intersection. */ - VariableSet allOuts = new VariableSet(); - VariableSet intersectOut = null; + VariableSet gens = new VariableSet(); + VariableSet kills = null; Enumeration enum = successors.elements(); while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); if (jump == null || jump.destination != successor) continue; - allOuts.union(jump.out); - if (intersectOut == null) - intersectOut = jump.out; + gens.unionExact(jump.gen); + if (kills == null) + kills = jump.kill; else - intersectOut = intersectOut.intersect(jump.out); + kills = kills.intersect(jump.kill); } // System.err.println("UpdateInOut: allOuts : "+allOuts); @@ -444,26 +447,25 @@ public class FlowBlock { /* Merge the locals used in successing block with those written * by this blocks */ - VariableSet defineHere = successor.in.merge(allOuts); - defineHere.subtractExact(in); + successor.in.merge(gens); -// System.err.println(" defineHere : "+defineHere); - if (t1Transformation) { - /* Now update in and out set of successing block */ - successor.in.subtract(intersectOut); - /* The out set must be updated for every jump in the block */ - enum = successor.successors.elements(); - while (enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); - if (jump != null) - jump.out.add(intersectOut); + /* Now update in and out set of successing block */ + + if (t1Transformation) + successor.in.subtract(kills); + /* The gen/kill sets must be updated for every jump in the block */ + enum = successor.successors.elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + if (jump != null) { + jump.gen.mergeGenKill(gens, jump.kill); + if (t1Transformation) + jump.kill.add(kills); } } // System.err.println(" successor.in: "+successor.in); - in.union(successor.in); + in.unionExact(successor.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() { + if (!jode.Decompiler.doChecks) + return; if (block.outer != null || block.flowBlock != this) { throw new RuntimeException("Inconsistency"); } @@ -611,11 +615,7 @@ public class FlowBlock { return false; try{ -// System.err.println("doing T1 analysis on: "+getLabel()); -// System.err.println("***in: "+in); checkConsistent(); -// System.err.println("and "+succ.getLabel()); -// System.err.println("+++in: "+succ.in); succ.checkConsistent(); } catch (RuntimeException ex) { ex.printStackTrace(); @@ -624,7 +624,7 @@ public class FlowBlock { new jode.TabbedPrintWriter(System.err, " "); writer.tab(); block.dumpSource(writer); - succ.block.dumpSource(writer); + succ.block.dumpSource(writer); } catch (java.io.IOException ioex) { } } @@ -658,7 +658,7 @@ public class FlowBlock { } /* Update the in/out-Vectors now */ - VariableSet defineHere = updateInOut(succ, true); + updateInOut(succ, true); /* The switch "fall through" case: if the appendBlock is a * switch, and the successor is the address of a case, and all @@ -669,7 +669,7 @@ public class FlowBlock { if (appendBlock instanceof SwitchBlock) { nextcase = ((SwitchBlock) appendBlock).findCase(succ); precedingcase = - ((SwitchBlock) appendBlock).prevCase(precedingcase); + ((SwitchBlock) appendBlock).prevCase(nextcase); enum = successors.elements(); while (nextcase != null && enum.hasMoreElements()) { @@ -680,8 +680,7 @@ public class FlowBlock { || (precedingcase != null && precedingcase.contains(jump.prev))) continue; - - nextcase = null; + nextcase = null; } } if (succ == END_OF_METHOD) { @@ -696,8 +695,6 @@ public class FlowBlock { /* Do the following modifications on the struct block. */ appendBlock = precedingcase; - succ.block.setFlowBlock(this); -// switchBlock.define(defineHere); } else { @@ -723,8 +720,6 @@ public class FlowBlock { sequBlock.replace(appendBlock, appendBlock); sequBlock.setFirst(appendBlock); sequBlock.setSecond(succ.block); - succ.block.setFlowBlock(this); -// sequBlock.define(defineHere); } /* 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 { - jode.TabbedPrintWriter writer = - new jode.TabbedPrintWriter(System.err, " "); - writer.tab(); + 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) { + } catch (java.io.IOException ioex) { + } } - } /* 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 * precedingcase = null. But in this case, there can't be * any jumps. */ 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 and replace every remaining jump with a break - * to the do/while block. - */ + appendBlock = optimizeJumps(succ, appendBlock); + + 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; enum = successors.elements(); + next_jump: while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); - if (jump == null || jump.destination != succ) + if (jump == null || jump.destination != succ || + jump.prev == appendBlock) continue; - if (doWhileFalse == null) - doWhileFalse = new LoopBlock(LoopBlock.DOWHILE, - LoopBlock.FALSE); - - int breaklevel = 1; - for (StructuredBlock surrounder = jump.prev.outer; - surrounder != appendBlock.outer; - surrounder = surrounder.outer) { - if (surrounder instanceof BreakableBlock) { - breaklevel++; - } - } - - SequentialBlock sequBlock = new SequentialBlock(); - StructuredBlock prevBlock = jump.prev; - prevBlock.removeJump(); - - sequBlock.replace(prevBlock, prevBlock); - sequBlock.setFirst(prevBlock); - sequBlock.setSecond(new BreakBlock(doWhileFalse, breaklevel > 1)); + int breaklevel = 0; + BreakableBlock breakToBlock = null; + for (StructuredBlock surrounder = jump.prev.outer; + surrounder != null && surrounder != appendBlock.outer; + surrounder = surrounder.outer) { + if (surrounder instanceof BreakableBlock) { + breaklevel++; + if (surrounder.getNextFlowBlock() == succ) { + breakToBlock = (BreakableBlock) surrounder; + break; + } + /* We don't want labeled breaks, if we can + * simply return. */ + if (succ == END_OF_METHOD) + break; + } + } + + StructuredBlock prevBlock = jump.prev; + prevBlock.removeJump(); + + if (breakToBlock == null) { + /* if the successor is the dummy return instruction + * 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) { doWhileFalse.replace(appendBlock, 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 @@ -899,7 +913,7 @@ public class FlowBlock { } /* Update the in/out-Vectors now */ - VariableSet defineHere = updateInOut(this, false); + updateInOut(this, false); while (lastModified != block) { @@ -945,7 +959,6 @@ public class FlowBlock { whileBlock.replace(bodyBlock, bodyBlock); whileBlock.setBody(bodyBlock); -// whileBlock.define(defineHere); /* Try to eliminate as many jumps as possible. */ @@ -1069,13 +1082,13 @@ public class FlowBlock { } if (!in.isEmpty()) { - writer.print("in: "+in); + writer.println("in: "+in); } block.dumpSource(writer); - FlowBlock succ = getSuccessor(); - if (succ != null) - succ.dumpSource(writer); +// FlowBlock succ = getSuccessor(); +// if (succ != null) +// succ.dumpSource(writer); } /** diff --git a/jode/jode/flow/IfThenElseBlock.java b/jode/jode/flow/IfThenElseBlock.java index 0777600..e7fd4bc 100644 --- a/jode/jode/flow/IfThenElseBlock.java +++ b/jode/jode/flow/IfThenElseBlock.java @@ -96,7 +96,7 @@ public class IfThenElseBlock extends StructuredBlock { public void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException { - boolean needBrace = ! (thenBlock instanceof InstructionBlock); + boolean needBrace = thenBlock.needsBraces(); writer.println("if ("+cond.toString()+")"+(needBrace?" {":"")); writer.tab(); thenBlock.dumpSource(writer); @@ -109,7 +109,7 @@ public class IfThenElseBlock extends StructuredBlock { writer.print("else "); elseBlock.dumpSource(writer); } else { - needBrace = ! (elseBlock instanceof InstructionBlock); + needBrace = elseBlock.needsBraces(); writer.println("else" + (needBrace ? " {" : "")); writer.tab(); elseBlock.dumpSource(writer); @@ -139,12 +139,8 @@ public class IfThenElseBlock extends StructuredBlock { * @return true, if the jump may be safely changed. */ public boolean jumpMayBeChanged() { - if (thenBlock.jump == null && !thenBlock.jumpMayBeChanged()) - return false; - - if (elseBlock != null && elseBlock.jump == null && - !elseBlock.jumpMayBeChanged()) - return false; - return true; + return (thenBlock.jump != null || thenBlock.jumpMayBeChanged()) + && elseBlock != null + && (elseBlock.jump != null || elseBlock.jumpMayBeChanged()); } } diff --git a/jode/jode/flow/InstructionBlock.java b/jode/jode/flow/InstructionBlock.java index e63d625..be01c8c 100644 --- a/jode/jode/flow/InstructionBlock.java +++ b/jode/jode/flow/InstructionBlock.java @@ -31,6 +31,14 @@ public class InstructionBlock extends InstructionContainer { 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. */ @@ -42,7 +50,7 @@ public class InstructionBlock extends InstructionContainer { if (instr instanceof Expression && ((Expression)instr).getOperator() instanceof LocalStoreOperator && ((LocalStoreOperator) ((Expression)instr).getOperator()) - .getLocalInfo() == local) { + .getLocalInfo() == local.getLocalInfo()) { isDeclaration = true; } else super.dumpDeclaration(writer, local); diff --git a/jode/jode/flow/InstructionContainer.java b/jode/jode/flow/InstructionContainer.java index e9bb350..5586b3b 100644 --- a/jode/jode/flow/InstructionContainer.java +++ b/jode/jode/flow/InstructionContainer.java @@ -36,7 +36,8 @@ public abstract class InstructionContainer extends StructuredBlock { if (instr instanceof LocalVarOperator) { LocalVarOperator varOp = (LocalVarOperator) instr; used.addElement(varOp.getLocalInfo()); - jump.out.addElement(varOp.getLocalInfo()); + jump.gen.addElement(varOp.getLocalInfo()); + jump.kill.addElement(varOp.getLocalInfo()); } setJump(jump); } diff --git a/jode/jode/flow/Jump.java b/jode/jode/flow/Jump.java index fb9bf56..db96c66 100644 --- a/jode/jode/flow/Jump.java +++ b/jode/jode/flow/Jump.java @@ -36,12 +36,21 @@ public class Jump { 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 * 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) { this.destAddr = destAddr; @@ -75,7 +84,8 @@ public class Jump { throws java.io.IOException { if (jode.Decompiler.isDebugging) { - writer.println("out: "+ out.toString()); + writer.println("gen : "+ gen.toString()); + writer.println("kill: "+ kill.toString()); } writer.println("Attachments: "+describeAttachments()); if (destination == null) diff --git a/jode/jode/flow/LoopBlock.java b/jode/jode/flow/LoopBlock.java index c891b9e..7527de0 100644 --- a/jode/jode/flow/LoopBlock.java +++ b/jode/jode/flow/LoopBlock.java @@ -135,7 +135,7 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { writer.println(label+":"); writer.tab(); } - boolean needBrace = ! (bodyBlock instanceof InstructionBlock); + boolean needBrace = bodyBlock.needsBraces(); switch (type) { case WHILE: writer.print("while ("+cond.toString()+")"); diff --git a/jode/jode/flow/RemoveEmpty.java b/jode/jode/flow/RemoveEmpty.java index dbbdf0c..50fe8ad 100644 --- a/jode/jode/flow/RemoveEmpty.java +++ b/jode/jode/flow/RemoveEmpty.java @@ -33,8 +33,9 @@ public class RemoveEmpty implements Transformation { Instruction instr; try { block = flow.lastModified; - if (!(((InstructionContainer)block).getInstruction() - instanceof NopOperator)) + Instruction prevInstr = + ((InstructionContainer)block).getInstruction(); + if (!(prevInstr instanceof NopOperator)) return false; sequBlock = (SequentialBlock)block.outer; @@ -46,6 +47,8 @@ public class RemoveEmpty implements Transformation { if (prev.jump != null) return false; instr = (Instruction) prev.getInstruction(); + instr.setType(jode.MyType.intersection + (instr.getType(), prevInstr.getType())); } catch (NullPointerException ex) { return false; } catch (ClassCastException ex) { @@ -66,7 +69,8 @@ public class RemoveEmpty implements Transformation { StructuredBlock block = lastBlock.outer.getSubBlocks()[0]; block.replace(block.outer, block); if (block.jump == null) - block.moveJump(lastBlock); + /*XXX can this happen */ + block.moveJump(lastBlock.jump); else lastBlock.removeJump(); flow.lastModified = block; diff --git a/jode/jode/flow/ReturnBlock.java b/jode/jode/flow/ReturnBlock.java index 4ae22e0..bcf4284 100644 --- a/jode/jode/flow/ReturnBlock.java +++ b/jode/jode/flow/ReturnBlock.java @@ -34,6 +34,14 @@ public class ReturnBlock extends InstructionContainer { 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. * @return the underlying instruction. diff --git a/jode/jode/flow/SequentialBlock.java b/jode/jode/flow/SequentialBlock.java index 4c43f68..86c1dfb 100644 --- a/jode/jode/flow/SequentialBlock.java +++ b/jode/jode/flow/SequentialBlock.java @@ -62,6 +62,16 @@ public class SequentialBlock extends StructuredBlock { return null; 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 @@ -74,6 +84,7 @@ public class SequentialBlock extends StructuredBlock { * any local Variable, but let the first sub block do this. */ declare = new VariableSet(); + subBlocks[0].used.addExact(used); subBlocks[0].makeDeclaration(done); done.addExact(used); subBlocks[1].makeDeclaration(done); diff --git a/jode/jode/flow/SimplifyExpression.java b/jode/jode/flow/SimplifyExpression.java index df6cbaf..3e09e70 100644 --- a/jode/jode/flow/SimplifyExpression.java +++ b/jode/jode/flow/SimplifyExpression.java @@ -21,10 +21,20 @@ package jode.flow; public class SimplifyExpression implements Transformation { 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) { InstructionContainer ic = (InstructionContainer) flow.lastModified; ic.setInstruction(ic.getInstruction().simplify()); } +// System.out.println("Result: "); +// flow.lastModified.dumpSource(writer); +// } catch (java.io.IOException ex) { +// } + return false; } } diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index e890da9..56b587e 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -150,6 +150,16 @@ public abstract class StructuredBlock { 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. * @param oldBlock the old sub block. @@ -179,12 +189,9 @@ public abstract class StructuredBlock { return (child == this); } - /** - * Removes the given jump if it is our jump. This does also - * update the successors vector of the flow block. - * - * @param jump The jump that should be removed. - */ + /** + * Removes the jump. This does also update the successors vector + * of the flow block. */ public void removeJump() { if (jump != null) { jump.prev = null; @@ -211,8 +218,8 @@ public abstract class StructuredBlock { while (enum.hasMoreElements()) { LocalInfo var = ((LocalInfo) enum.nextElement()).getLocalInfo(); - used.addElement(var); - var.setDefining(this); + if (!used.contains(var)) + used.addElement(var); } from.used.removeAllElements(); StructuredBlock[] subs = from.getSubBlocks(); @@ -236,8 +243,7 @@ public abstract class StructuredBlock { public void replace(StructuredBlock sb, StructuredBlock sub) { moveDefinitions(sb, sub); outer = sb.outer; - flowBlock = sb.flowBlock; - + setFlowBlock(sb.flowBlock); if (outer != null) { outer.replaceSubBlock(sb, this); } else { @@ -246,18 +252,45 @@ public abstract class StructuredBlock { } /** - * This function moves the jumps from sb to this block. - * The jump field of sb is removed afterwards. - * @param sb The structured block whose jump is copied. + * This function swaps the jump with another block. + * @param block The block whose jump is swapped. + */ + 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) { - jump = sb.jump; + public void moveJump(Jump jump) { + removeJump(); + this.jump = jump; if (jump != null) { + jump.prev.jump = null; 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 * of this block. If this returns true, you know that jump is null. @@ -277,18 +310,14 @@ public abstract class StructuredBlock { public VariableSet propagateUsage() { StructuredBlock[] subs = getSubBlocks(); - VariableSet[] childUse = new VariableSet[subs.length]; VariableSet allUse = (VariableSet) used.clone(); for (int i=0; i