diff --git a/jode/src/net/sf/jode/flow/FlowBlock.java b/jode/src/net/sf/jode/flow/FlowBlock.java index bbfa54f..c59033c 100644 --- a/jode/src/net/sf/jode/flow/FlowBlock.java +++ b/jode/src/net/sf/jode/flow/FlowBlock.java @@ -226,7 +226,13 @@ public class FlowBlock { if (jumps == null) return null; Jump remainingJumps = null; + + /* find the smallest block containing all jumps */ lastModified = jumps.prev; + for (Jump jump = jumps.next; jump != null; jump = jump.next) { + while (!lastModified.contains(jump.prev)) + lastModified = lastModified.outer; + } StructuredBlock b = lastModified.outer; while (b != null) { if (b.outer instanceof TryBlock @@ -282,7 +288,7 @@ public class FlowBlock { ConditionalBlock cb = (ConditionalBlock) prev.outer; Expression instr = cb.getInstruction(); - /* This is a jump inside an ConditionalBlock. + /* This is a jump inside a ConditionalBlock. * * cb is the conditional block, * prev the empty block containing the jump @@ -290,7 +296,7 @@ public class FlowBlock { if (cb.jump != null) { /* This can only happen if cb also jumps to succ. - * This is a weired "if (cond) empty"-block. We + * This is a weird "if (cond) empty"-block. We * transform it by hand. */ prev.removeJump(); @@ -335,6 +341,8 @@ public class FlowBlock { loopBlock.setCondition(instr.negate()); loopBlock.moveDefinitions(cb, null); + if (loopBlock.contains(lastModified)) + lastModified = loopBlock; cb.removeBlock(); continue; } @@ -371,6 +379,8 @@ public class FlowBlock { loopBlock.setType(LoopBlock.DOWHILE); loopBlock.setCondition(instr.negate()); loopBlock.moveDefinitions(cb, null); + if (loopBlock.contains(lastModified)) + lastModified = loopBlock; cb.removeBlock(); continue; } @@ -590,11 +600,11 @@ public class FlowBlock { /** * Resolve remaining jumps to the successor by generating break - * instructions. As last resort generate a do while(false) block. + * instructions. As last resort generate a labelled block. * @param jumps The jump list that need to be resolved. */ void resolveRemaining(Jump jumps) { - LoopBlock doWhileFalse = null; + LabelledBlock labelledBlock = null; StructuredBlock outerMost = lastModified; boolean removeLast = false; for (; jumps != null; jumps = jumps.next) { @@ -622,19 +632,18 @@ public class FlowBlock { prevBlock.removeJump(); if (breakToBlock == null) { - /* Nothing else helped, so put a do/while(0) + /* Nothing else helped, so put a labelled * block around outerMost and break to that * block. */ - if (doWhileFalse == null) { - doWhileFalse = new LoopBlock(LoopBlock.DOWHILE, - LoopBlock.FALSE); + if (labelledBlock == null) { + labelledBlock = new LabelledBlock(); } /* Adapt outermost, so that it contains the break. */ while (!outerMost.contains(prevBlock)) outerMost = outerMost.outer; prevBlock.appendBlock - (new BreakBlock(doWhileFalse, breaklevel > 0)); + (new BreakBlock(labelledBlock, true)); } else prevBlock.appendBlock (new BreakBlock(breakToBlock, breaklevel > 1)); @@ -643,10 +652,10 @@ public class FlowBlock { if (removeLast) lastModified.removeJump(); - if (doWhileFalse != null) { - doWhileFalse.replace(outerMost); - doWhileFalse.setBody(outerMost); - lastModified = doWhileFalse; + if (labelledBlock != null) { + labelledBlock.replace(outerMost); + labelledBlock.setBody(outerMost); + lastModified = labelledBlock; } } diff --git a/jode/src/net/sf/jode/flow/LabelledBlock.java b/jode/src/net/sf/jode/flow/LabelledBlock.java new file mode 100644 index 0000000..0730d8d --- /dev/null +++ b/jode/src/net/sf/jode/flow/LabelledBlock.java @@ -0,0 +1,161 @@ +/* LoopBlock Copyright (C) 1998-2002 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; see the file COPYING.LESSER. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: LoopBlock.java 1411 2012-03-01 22:39:08Z hoenicke $ + */ + +package net.sf.jode.flow; +import net.sf.jode.decompiler.TabbedPrintWriter; + +/** + * This is the structured block for an Loop block. + */ +public class LabelledBlock extends StructuredBlock implements BreakableBlock { + + /** + * The body of this labelled block. This is always a valid block and not null. + */ + StructuredBlock bodyBlock; + + /** + * The stack after the break. + */ + VariableStack breakedStack; + + /** + * The serial number for labels. + */ + static int serialno = 0; + + /** + * The label of this instruction, or null if it needs no label. + */ + String label = null; + + public LabelledBlock() { + } + + public void setBody(StructuredBlock body) { + bodyBlock = body; + bodyBlock.outer = this; + body.setFlowBlock(flowBlock); + } + + /** + * Replaces the given sub block with a new block. + * @param oldBlock the old sub block. + * @param newBlock the new sub block. + * @return false, if oldBlock wasn't a direct sub block. + */ + public boolean replaceSubBlock(StructuredBlock oldBlock, + StructuredBlock newBlock) { + if (bodyBlock != oldBlock) + return false; + + bodyBlock = newBlock; + newBlock.outer = this; + oldBlock.outer = null; + return true; + } + + /** + * Returns all sub block of this structured block. + */ + public StructuredBlock[] getSubBlocks() { + return new StructuredBlock[] { bodyBlock }; + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + super.dumpSource(writer); + } + + public void dumpInstruction(TabbedPrintWriter writer) + throws java.io.IOException + { + if (label != null) { + writer.untab(); + writer.println(label+":"); + writer.tab(); + } + boolean needBrace = bodyBlock.needsBraces(); + if (needBrace) + writer.openBrace(); + else + writer.println(); + writer.tab(); + bodyBlock.dumpSource(writer); + writer.untab(); + writer.closeBrace(); + } + + /** + * Returns the label of this block and creates a new label, if + * there wasn't a label previously. + */ + public String getLabel() { + if (label == null) + label = "label_"+(serialno++); + return label; + } + + /** + * Is called by BreakBlock, to tell us that this block is breaked. + */ + public void setBreaked() { + } + + /** + * 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) { + VariableStack afterBody = bodyBlock.mapStackToLocal(stack); + mergeBreakedStack(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 mergeBreakedStack(VariableStack stack) { + if (breakedStack != null) + breakedStack.merge(stack); + else + breakedStack = stack; + } + + public void removePush() { + bodyBlock.removePush(); + } + + /** + * 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. + * @return true, if the jump may be safely changed. + */ + public boolean jumpMayBeChanged() { + return false; + } +} + diff --git a/jode/src/net/sf/jode/flow/StructuredBlock.java b/jode/src/net/sf/jode/flow/StructuredBlock.java index 546f8cf..ff671bd 100644 --- a/jode/src/net/sf/jode/flow/StructuredBlock.java +++ b/jode/src/net/sf/jode/flow/StructuredBlock.java @@ -336,8 +336,11 @@ public abstract class StructuredBlock { if (jump != null) outer.getSubBlocks()[0].moveJump(jump); outer.getSubBlocks()[0].replace(outer); - } else + } else { + if (outer.jump != null) + outer.getSubBlocks()[1].moveJump(outer.jump); outer.getSubBlocks()[1].replace(outer); + } return; }