diff --git a/jode/jode/flow/IfThenElseBlock.java b/jode/jode/flow/IfThenElseBlock.java index cda65df..ddaa9c7 100644 --- a/jode/jode/flow/IfThenElseBlock.java +++ b/jode/jode/flow/IfThenElseBlock.java @@ -16,8 +16,10 @@ * $Id$ */ package jode.flow; +import jode.decompiler.LocalInfo; import jode.decompiler.TabbedPrintWriter; import jode.expr.Expression; +import jode.Type; /** * An IfThenElseBlock is the structured block representing an if @@ -29,6 +31,11 @@ public class IfThenElseBlock extends StructuredBlock { * The condition. Must be of boolean type. */ Expression cond; + /** + * The loads that are on the stack before cond is executed. + */ + VariableStack condStack; + /** * The then part. This is always a valid block and not null @@ -88,6 +95,34 @@ public class IfThenElseBlock extends StructuredBlock { return true; } + /** + * This does take the instr into account and modifies stack + * accordingly. It then calls super.mapStackToLocal. + * @param stack the stack before the instruction is called + * @return stack the stack afterwards. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + VariableStack newStack; + int params = cond.getOperandCount(); + if (params > 0) { + condStack = stack.peek(params); + newStack = stack.pop(params); + } else + newStack = stack; + + return VariableStack.merge(thenBlock.mapStackToLocal(newStack), + elseBlock == null ? newStack + : elseBlock.mapStackToLocal(newStack)); + } + + public void removePush() { + if (condStack != null) + cond = condStack.mergeIntoExpression(cond, used); + thenBlock.removePush(); + if (elseBlock != null) + elseBlock.removePush(); + } + /** * Print the source code for this structured block. This may be * called only once, because it remembers which local variables diff --git a/jode/jode/flow/InstructionBlock.java b/jode/jode/flow/InstructionBlock.java index eb2ba02..278e197 100644 --- a/jode/jode/flow/InstructionBlock.java +++ b/jode/jode/flow/InstructionBlock.java @@ -16,6 +16,7 @@ * $Id$ */ package jode.flow; +import jode.Type; import jode.decompiler.TabbedPrintWriter; import jode.decompiler.LocalInfo; import jode.expr.ComplexExpression; @@ -26,6 +27,14 @@ import jode.expr.LocalStoreOperator; * This is the structured block for atomic instructions. */ public class InstructionBlock extends InstructionContainer { + /** + * The loads that are on the stack before cond is executed. + */ + VariableStack stack; + /** + * The local to which we push to, if the instruction is non void + */ + LocalInfo pushedLocal = null; public InstructionBlock(Expression instr) { super(instr); @@ -35,6 +44,41 @@ public class InstructionBlock extends InstructionContainer { super(instr, jump); } + /** + * This does take the instr into account and modifies stack + * accordingly. It then calls super.mapStackToLocal. + * @param stack the stack before the instruction is called + * @return stack the stack afterwards. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + VariableStack newStack; + int params = instr.getOperandCount(); + if (params > 0) + this.stack = stack.peek(params); + + if (instr.getType() != Type.tVoid) { + pushedLocal = new LocalInfo(); + newStack = stack.poppush(params, pushedLocal); + } else if (params > 0) { + newStack = stack.pop(params); + } else + newStack = stack; + return super.mapStackToLocal(newStack); + } + + public void removePush() { + if (stack != null) + instr = stack.mergeIntoExpression(instr, used); + if (pushedLocal != null) { + LocalStoreOperator store = new LocalStoreOperator + (pushedLocal.getType(), pushedLocal, + LocalStoreOperator.ASSIGN_OP); + instr = new ComplexExpression(store, new Expression[] { instr }); + used.addElement(pushedLocal); + } + super.removePush(); + } + /** * Tells if this block needs braces when used in a if or while block. * @return true if this block should be sorrounded by braces. diff --git a/jode/jode/flow/LoopBlock.java b/jode/jode/flow/LoopBlock.java index 90a8fa4..e8bd353 100644 --- a/jode/jode/flow/LoopBlock.java +++ b/jode/jode/flow/LoopBlock.java @@ -45,6 +45,10 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { * The condition. Must be of boolean type. */ Expression cond; + /** + * The stack the condition eats. + */ + VariableStack condStack; /** * The init instruction, only valid if type == FOR or POSSFOR */ @@ -65,10 +69,20 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { int type; /** - * The body of this loop. This is always a valid block and not null + * The body of this loop. This is always a valid block and not null. */ StructuredBlock bodyBlock; + /** + * The stack after the break. + */ + VariableStack breakedStack; + + /** + * The stack at begin of the loop. + */ + VariableStack continueStack; + /*{ invariant { type != POSSFOR || (incr != null && incr.getInstruction().getOperator() @@ -297,6 +311,58 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { mayChangeJump = false; } + /** + * This is called after the analysis is completely done. It + * will remove all PUSH/stack_i expressions, (if the bytecode + * is correct). + * @param stack the stack at begin of the block + * @return null if there is no way to the end of this block, + * otherwise the stack after the block has executed. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + continueStack = stack; + VariableStack newStack; + int params = cond.getOperandCount(); + if (params > 0) { + condStack = stack.peek(params); + newStack = stack.pop(params); + } else + newStack = stack; + + VariableStack afterBody = bodyBlock.mapStackToLocal(newStack); + if (afterBody != null) + mergeContinueStack(afterBody); + + return breakedStack; + } + + /** + * Is called by BreakBlock, to tell us what the stack can be after a + * break. + * @return false if the stack is inconsistent. + */ + public void mergeContinueStack(VariableStack stack) { + continueStack.merge(stack); + } + + /** + * Is called by BreakBlock, to tell us what the stack can be after a + * break. + * @return false if the stack is inconsistent. + */ + public void mergeBreakedStack(VariableStack stack) { + if (breakedStack != null) + breakedStack.merge(stack); + else + breakedStack = stack; + } + + public void removePush() { + if (condStack != null) + cond = condStack.mergeIntoExpression(cond, used); + bodyBlock.removePush(); + } + /** * Replace all breaks to block with a continue to this. * @param block the breakable block where the breaks originally diff --git a/jode/jode/flow/RetBlock.java b/jode/jode/flow/RetBlock.java index 451a494..8c5c8ce 100644 --- a/jode/jode/flow/RetBlock.java +++ b/jode/jode/flow/RetBlock.java @@ -46,6 +46,18 @@ public class RetBlock extends StructuredBlock { gen.addElement(local); } + /** + * This does take the instr into account and modifies stack + * accordingly. It then calls super.mapStackToLocal. + * @param stack the stack before the instruction is called + * @return stack the stack afterwards. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + if (!stack.isEmpty()) + throw new IllegalArgumentException("stack is not empty at RET"); + return null; + } + public void dumpInstruction(jode.decompiler.TabbedPrintWriter writer) throws java.io.IOException { diff --git a/jode/jode/flow/ReturnBlock.java b/jode/jode/flow/ReturnBlock.java index 412ad8a..abf26d4 100644 --- a/jode/jode/flow/ReturnBlock.java +++ b/jode/jode/flow/ReturnBlock.java @@ -22,9 +22,13 @@ import jode.decompiler.TabbedPrintWriter; import jode.expr.Expression; /** - * This is the structured block for an Return block. + * This is the structured block for a Return block. */ public class ReturnBlock extends InstructionContainer { + /** + * The loads that are on the stack before instr is executed. + */ + VariableStack stack; public ReturnBlock() { super(null); @@ -34,6 +38,28 @@ public class ReturnBlock extends InstructionContainer { super(instr, new Jump(-1)); } + /** + * This does take the instr into account and modifies stack + * accordingly. It then calls super.mapStackToLocal. + * @param stack the stack before the instruction is called + * @return stack the stack afterwards. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + VariableStack newStack; + int params = instr.getOperandCount(); + if (params > 0) { + this.stack = stack.peek(params); + newStack = stack.pop(params); + } else + newStack = stack; + return null; + } + + public void removePush() { + if (stack != null) + instr = stack.mergeIntoExpression(instr, used); + } + /** * Tells if this block needs braces when used in a if or while block. * @return true if this block should be sorrounded by braces. diff --git a/jode/jode/flow/SequentialBlock.java b/jode/jode/flow/SequentialBlock.java index 49b0445..dc4e140 100644 --- a/jode/jode/flow/SequentialBlock.java +++ b/jode/jode/flow/SequentialBlock.java @@ -52,6 +52,17 @@ public class SequentialBlock extends StructuredBlock { throw new jode.AssertError("Inconsistency"); } + /** + * This does take the instr into account and modifies stack + * accordingly. It then calls super.mapStackToLocal. + * @param stack the stack before the instruction is called + * @return stack the stack afterwards. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + return subBlocks[1].mapStackToLocal + (subBlocks[0].mapStackToLocal(stack)); + } + /** * Returns the block where the control will normally flow to, when * the given sub block is finished (not ignoring the jump diff --git a/jode/jode/flow/SpecialBlock.java b/jode/jode/flow/SpecialBlock.java index 5353078..cfe0d22 100644 --- a/jode/jode/flow/SpecialBlock.java +++ b/jode/jode/flow/SpecialBlock.java @@ -52,6 +52,19 @@ public class SpecialBlock extends StructuredBlock { setJump(jump); } + /** + * This does take the instr into account and modifies stack + * accordingly. It then calls super.mapStackToLocal. + * @param stack the stack before the instruction is called + * @return stack the stack afterwards. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + /* a SpecialBlock is special :-) */ + VariableStack after = stack.executeSpecial(this); + return super.mapStackToLocal(after); + } + + public void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException { diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index 19b6dbc..b572214 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -351,6 +351,45 @@ public abstract class StructuredBlock { return allUse; } + /** + * This is called after the analysis is completely done. It + * will remove all PUSH/stack_i expressions, (if the bytecode + * is correct).

+ * The default implementation merges the stack after each sub block. + * This may not be, what you want.

+ * + * @param initialStack the stackmap at begin of the block + * @return the stack after the block has executed. + * @throw RuntimeException if something did get wrong. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + StructuredBlock[] subBlocks = getSubBlocks(); + VariableStack after; + if (subBlocks.length == 0) + after = stack; + else { + after = null; + for (int i=1; i< subBlocks.length; i++) { + after = VariableStack.merge + (after, subBlocks[i].mapStackToLocal(stack)); + } + } + if (jump != null) + /* assert(after != null) */ + jump.stackMap = after; + return after; + } + + /** + * This is called after mapStackToLocal to do the stack to local + * transformation. + */ + public void removePush() { + StructuredBlock[] subBlocks = getSubBlocks(); + for (int i=0; i< subBlocks.length; i++) + subBlocks[i].removePush(); + } + /** * Make the declarations, i.e. initialize the declare variable * to correct values. This will declare every variable that diff --git a/jode/jode/flow/TryBlock.java b/jode/jode/flow/TryBlock.java index 780a0e7..36198fc 100644 --- a/jode/jode/flow/TryBlock.java +++ b/jode/jode/flow/TryBlock.java @@ -90,6 +90,23 @@ public class TryBlock extends StructuredBlock { return subBlocks; } + /** + * This does take the instr into account and modifies stack + * accordingly. It then calls super.mapStackToLocal. + * @param stack the stack before the instruction is called + * @return stack the stack afterwards. + */ + public VariableStack mapStackToLocal(VariableStack stack) { + // first the try block. + VariableStack after = subBlocks[0].mapStackToLocal(stack); + for (int i = 1; i