diff --git a/jode/jode/flow/CaseBlock.java b/jode/jode/flow/CaseBlock.java index 71312e9..386143a 100644 --- a/jode/jode/flow/CaseBlock.java +++ b/jode/jode/flow/CaseBlock.java @@ -81,11 +81,9 @@ public class CaseBlock extends StructuredBlock { * Returns all sub block of this structured block. */ public StructuredBlock[] getSubBlocks() { - if (subBlock != null) { - StructuredBlock[] result = { subBlock }; - return result; - } - return new StructuredBlock[0]; + return (subBlock != null) + ? new StructuredBlock[] { subBlock } + : new StructuredBlock[0]; } public void dumpInstruction(jode.TabbedPrintWriter writer) diff --git a/jode/jode/flow/CatchBlock.java b/jode/jode/flow/CatchBlock.java index 2d59682..01cc98a 100644 --- a/jode/jode/flow/CatchBlock.java +++ b/jode/jode/flow/CatchBlock.java @@ -46,14 +46,18 @@ public class CatchBlock extends StructuredBlock { */ LocalInfo exceptionLocal; - public CatchBlock(RawTryCatchBlock rawBlock) { - exceptionType = rawBlock.type; - this.tryBlock = rawBlock.tryBlock; - tryBlock.outer = this; + public CatchBlock(Type type) { + exceptionType = type; } static int serialno=0; + public void setTryBlock(StructuredBlock tryBlock) { + this.tryBlock = tryBlock; + tryBlock.outer = this; + tryBlock.setFlowBlock(flowBlock); + } + /** * Sets the catch block. * @param catchBlock the catch block. @@ -122,9 +126,8 @@ public class CatchBlock extends StructuredBlock { /** * Returns all sub block of this structured block. */ - public StructuredBlock[] getSubBlocks() { - StructuredBlock[] result = { tryBlock, catchBlock }; - return result; + public StructuredBlock[] getSubBlocks() { + return new StructuredBlock[] { tryBlock, catchBlock }; } /** diff --git a/jode/jode/flow/CatchFinallyBlock.java b/jode/jode/flow/CatchFinallyBlock.java new file mode 100644 index 0000000..0e6e3cd --- /dev/null +++ b/jode/jode/flow/CatchFinallyBlock.java @@ -0,0 +1,95 @@ +/* CatchFinallyBlock Copyright (C) 1997-1998 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +package jode.flow; + +/** + * + * @author Jochen Hoenicke + */ +public class CatchFinallyBlock extends CatchBlock { + + StructuredBlock finallyBlock; + + public CatchFinallyBlock() { + super(null); + } + + public void setFinallyBlock(StructuredBlock fin) { + finallyBlock = fin; + fin.outer = this; + fin.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 (tryBlock == oldBlock) + tryBlock = newBlock; + else if (finallyBlock == oldBlock) + finallyBlock = newBlock; + else + return false; + return true; + } + + /** + * Returns all sub block of this structured block. + */ + public StructuredBlock[] getSubBlocks() { + return new StructuredBlock[] { tryBlock, finallyBlock }; + } + + /** + * 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 ( tryBlock.jump != null || tryBlock.jumpMayBeChanged()) + && (finallyBlock.jump != null || finallyBlock.jumpMayBeChanged()); + } + + public void dumpInstruction(jode.TabbedPrintWriter writer) + throws java.io.IOException { + /* avoid ugly nested tries */ + if (!(outer instanceof CatchBlock + /* XXX || outer instanceof FinallyBlock*/)) { + writer.println("try {"); + writer.tab(); + } + tryBlock.dumpSource(writer); + writer.untab(); + writer.println("} finally {"); + writer.tab(); + finallyBlock.dumpSource(writer); + if (!(outer instanceof CatchBlock + /* XXX || outer instanceof FinallyBlock*/)) { + writer.untab(); + writer.println("}"); + } + } +} + + + diff --git a/jode/jode/flow/ConditionalBlock.java b/jode/jode/flow/ConditionalBlock.java index 2d83cb7..40746c0 100644 --- a/jode/jode/flow/ConditionalBlock.java +++ b/jode/jode/flow/ConditionalBlock.java @@ -49,8 +49,7 @@ public class ConditionalBlock extends InstructionContainer { * Returns all sub block of this structured block. */ public StructuredBlock[] getSubBlocks() { - StructuredBlock[] result = { trueBlock }; - return result; + return new StructuredBlock[] { trueBlock }; } /** diff --git a/jode/jode/flow/CreateForInitializer.java b/jode/jode/flow/CreateForInitializer.java index b2e10b4..0da699b 100644 --- a/jode/jode/flow/CreateForInitializer.java +++ b/jode/jode/flow/CreateForInitializer.java @@ -19,6 +19,8 @@ package jode.flow; import jode.Instruction; +import jode.Expression; +import jode.StoreInstruction; public class CreateForInitializer implements Transformation { @@ -41,7 +43,11 @@ public class CreateForInitializer implements Transformation { initializer = ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); - + + if (!(initializer instanceof Expression) + || !( ((Expression)initializer).getOperator() + instanceof StoreInstruction)) + return false; } catch (ClassCastException ex) { return false; } catch (NullPointerException ex) { diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index bfe0fc6..ab89ffb 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -19,10 +19,7 @@ package jode.flow; import java.util.*; -import jode.TabbedPrintWriter; -import jode.Expression; -import jode.CodeAnalyzer; -import jode.Decompiler; +import jode.*; /** * A flow block is the structure of which the flow graph consists. A @@ -112,37 +109,13 @@ public class FlowBlock { } public int getNextAddr() { - return addr+length; + if (block instanceof RawTryCatchBlock) + return ((RawTryCatchBlock)block).getTryBlock() + .jump.destination.getNextAddr(); + else + return addr+length; } - - /** - * Create a Catch- resp. FinallyBlock (maybe even SynchronizedBlock) - * @param sequBlock a SequentialBlock whose first sub block is a - * RawTryCatchBlock. - */ - public StructuredBlock createCatchBlock(SequentialBlock sequBlock) { - RawTryCatchBlock tryBlock = (RawTryCatchBlock) sequBlock.subBlocks[0]; - StructuredBlock catchBlock = sequBlock.subBlocks[1]; - if (tryBlock.type != null) { - /*XXX crude hack */ - catchBlock.replace(sequBlock, tryBlock); - CatchBlock newBlock = new CatchBlock(tryBlock); - newBlock.replace(catchBlock, catchBlock); - newBlock.setCatchBlock(catchBlock); - if (sequBlock.jump != null) { - if (newBlock.catchBlock.jump == null) - newBlock.catchBlock.moveJump(sequBlock.jump); - else - sequBlock.removeJump(); - } - return newBlock; - } else { - /* XXX implement finally */ - return sequBlock; - } - } - /** * This method optimizes the jumps to successor. * @param successor The successing flow block @@ -659,16 +632,6 @@ public class FlowBlock { while (!appendBlock.contains(jump.prev)) { appendBlock = appendBlock.outer; - if (appendBlock instanceof SequentialBlock - && appendBlock.getSubBlocks()[0] - instanceof RawTryCatchBlock) { - - /* We leave the catch block of a raw-try-catch-block. - * We shall now create the Catch- resp. FinallyBlock. - */ - appendBlock = - createCatchBlock((SequentialBlock)appendBlock); - } } /* appendBlock can't be null now, because the * outermost block contains every structured block. @@ -813,32 +776,96 @@ public class FlowBlock { updateInOut(this, false); - while (lastModified != block) { + while (lastModified != block) lastModified = lastModified.outer; - if (lastModified instanceof SequentialBlock - && lastModified.getSubBlocks()[0] - instanceof RawTryCatchBlock) { - - /* We leave the catch block of a raw-try-catch-block. - * We shall now create the Catch- resp. FinallyBlock. - */ - lastModified = - createCatchBlock((SequentialBlock)lastModified); - } - } - /* If there is only one jump to the beginning and it is the - * last jump and (there is a do/while(0) block surrounding - * everything but the last instruction, or the last - * instruction is a increase/decrease statement), replace the - * do/while(0) with a for(;;last_instr) resp. create a new one - * and replace breaks to do/while with continue to for. - */ - /* XXX implement above */ - /* XXX condition for do/while(cond) blocks */ - { - /* Otherwise: */ + transformation: + do { + /* If there is only one jump to the beginning and it is the + * last jump and (there is a do/while(0) block surrounding + * everything but the last instruction, or the last + * instruction is a increase/decrease statement), replace the + * do/while(0) with a for(;;last_instr) resp. create a new one + * and replace breaks to do/while with continue to for. + */ + + Jump onlyJump = null; + Enumeration enum = successors.elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + + if (jump == null || jump.destination != this) + continue; + if (onlyJump == null) + onlyJump = jump; + else { + onlyJump = null; + break; + } + } + if (onlyJump != null && + onlyJump.prev instanceof InstructionBlock) { + + InstructionBlock prev = (InstructionBlock) onlyJump.prev; + + if (prev.outer != null && prev.outer.outer == null + && prev.outer instanceof SequentialBlock + && prev.outer.getSubBlocks()[0] instanceof LoopBlock) { + LoopBlock lb = (LoopBlock) prev.outer.getSubBlocks()[0]; + if (lb.cond == lb.FALSE && lb.type == lb.DOWHILE) { + /* Replace the do/while(0) with a + * for(;;last_instr) and replace breaks to + * do/while with continue to for. + */ + + lb.type = lb.FOR; + lb.cond = lb.TRUE; + lb.incr = prev.getInstruction(); + lb.init = null; + + lb.replaceBreakContinue(); + lb.replace(prev.outer, prev); + prev.removeJump(); + lastModified = lb; + break transformation; + } + } + + StructuredBlock sb = prev; + while (sb.outer != null + && sb.outer instanceof SequentialBlock + && sb.outer.getSubBlocks()[1] == sb) + sb = sb.outer; + + Instruction instr = prev.getInstruction(); + Operator op; + if (instr instanceof Expression + && ((op = ((Expression)instr).getOperator()) + instanceof jode.StoreInstruction + || op instanceof jode.IIncOperator) + && sb.outer == null) { + + /* The only jump is the jump of the last + * instruction prev */ + + LoopBlock forBlock = + new LoopBlock(LoopBlock.FOR, LoopBlock.TRUE); + forBlock.replace(sb, sb); + forBlock.setBody(sb); + + prev.outer.getSubBlocks()[0].replace(prev.outer, null); + forBlock.incr = instr; + prev.removeJump(); + lastModified = forBlock; + break transformation; + } + } + + /* XXX condition for do/while(cond) blocks */ + + /* Otherwise: */ + /* create a new while(true) block. */ StructuredBlock bodyBlock = block; @@ -853,18 +880,18 @@ public class FlowBlock { LoopBlock whileBlock = new LoopBlock(LoopBlock.WHILE, LoopBlock.TRUE); - + whileBlock.replace(bodyBlock, bodyBlock); whileBlock.setBody(bodyBlock); - + /* Try to eliminate as many jumps as possible. */ bodyBlock = optimizeJumps(this, bodyBlock); - + /* if there are further jumps to this, replace every jump with a * continue to while block and return true. */ - Enumeration enum = successors.elements(); + enum = successors.elements(); while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); @@ -897,7 +924,7 @@ public class FlowBlock { (new BreakBlock(breakToBlock, breaklevel > 1)); } - + /* Now remove the jump of block if it points to this. */ if (bodyBlock.jump != null && @@ -905,7 +932,7 @@ public class FlowBlock { bodyBlock.removeJump(); lastModified = whileBlock; - } + } while (false); /* remove ourself from the predecessor list. */ @@ -934,19 +961,9 @@ public class FlowBlock { if (jump == null || jump.destination != END_OF_METHOD) continue; - while (!appendBlock.contains(jump.prev)) { + while (!appendBlock.contains(jump.prev)) appendBlock = appendBlock.outer; - if (appendBlock instanceof SequentialBlock - && appendBlock.getSubBlocks()[0] - instanceof RawTryCatchBlock) { - - /* We leave the catch block of a raw-try-catch-block. - * We shall now create the Catch- resp. FinallyBlock. - */ - appendBlock = - createCatchBlock((SequentialBlock)appendBlock); - } - } + /* appendBlock can't be null now, because the * outermost block contains every structured block. */ @@ -1007,12 +1024,13 @@ public class FlowBlock { static Transformation[] exprTrafos = { new RemoveEmpty(), new CreateExpression(), - new CreatePostIncExpression(), + new CreatePrePostIncExpression(), new CreateAssignExpression(), new CreateNewConstructor(), new CombineIfGotoExpressions(), new CreateIfThenElseOperator(), new CreateConstantArray(), + new CreateForInitializer(), }; @@ -1060,6 +1078,8 @@ public class FlowBlock { * @param end the end of the address range. */ public boolean analyze(int start, int end) { + if (Decompiler.debugAnalyze) + System.err.println("analyze("+start+", "+end+")"); try { jode.TabbedPrintWriter writer = null; if (Decompiler.isFlowDebugging) @@ -1067,6 +1087,13 @@ public class FlowBlock { boolean changed = false; + if (block instanceof RawTryCatchBlock) { + /* analyze the try and catch blocks separately + * and create a new CatchBlock afterwards. + */ + changed |= analyzeCatchBlock(start, end); + } + while (true) { if (Decompiler.isFlowDebugging) { @@ -1101,6 +1128,9 @@ public class FlowBlock { writer.untab(); } + if (Decompiler.debugAnalyze) + System.err.println("T2("+addr+","+(addr+length) + +") succeeded"); /* T2 transformation succeeded. This may * make another T1 analysis in the previous * block possible. @@ -1115,18 +1145,16 @@ public class FlowBlock { /* the Block has no successor where t1 is applicable. * Finish this analyzation. */ - if (Decompiler.isFlowDebugging) { - writer.println("No more successors applicable: " - + start + " - " + end + "; " - + addr + " - " + (addr+length)); - } + if (Decompiler.debugAnalyze) + System.err.println + ("No more successors applicable: " + + start + " - " + end + "; " + + addr + " - " + (addr+length)); return changed; } else { - /* Only do T1 transformation if the blocks are - * adjacent. */ if (succ.block instanceof SwitchBlock) { /* analyze succ, the new region is the - * continous region of + * continuous region of * [start,end) \cap \compl [addr, addr+length) * where succ.addr lies in. */ @@ -1137,8 +1165,23 @@ public class FlowBlock { if (succ.analyzeSwitch(newStart, newEnd)) break; - } if ((succ.addr == addr+length + } + if (succ.block instanceof RawTryCatchBlock) { + /* analyze the try and catch blocks separately + * and create a new CatchBlock afterwards. + */ + int newStart = (succ.addr > addr) + ? addr+length : start; + int newEnd = (succ.addr > addr) + ? end : addr; + if (succ.analyzeCatchBlock(newStart, newEnd)) { + break; + } + } + if ((succ.addr == addr+length || succ.addr+succ.length == addr) + /* Only do T1 transformation if the blocks are + * adjacent. */ && doT1(succ)) { /* T1 transformation succeeded. */ changed = true; @@ -1148,30 +1191,221 @@ public class FlowBlock { writer.tab(); dumpSource(writer); writer.untab(); - } + } + break; + } + + /* Check if all predecessors of succ + * lie in range [start,end). Otherwise + * we have no chance to combine succ + */ + Enumeration enum = succ.predecessors.elements(); + while (enum.hasMoreElements()) { + int predAddr = + ((FlowBlock)enum.nextElement()).addr; + if (predAddr < start || predAddr >= end) { + if (Decompiler.debugAnalyze) + System.err.println + ("breaking analyze(" + + start + ", " + end + "); " + + addr + " - " + (addr+length)); + return changed; + } + } + /* analyze succ, the new region is the + * continuous region of + * [start,end) \cap \compl [addr, addr+length) + * where succ.addr lies in. + */ + int newStart = (succ.addr > addr) + ? addr+length : start; + int newEnd = (succ.addr > addr) + ? end : addr; + if (succ.analyze(newStart, newEnd)) break; - } else { - /* analyze succ, the new region is the - * continous region of - * [start,end) \cap \compl [addr, addr+length) - * where succ.addr lies in. - */ - int newStart = (succ.addr > addr) - ? addr+length : start; - int newEnd = (succ.addr > addr) - ? end : addr; - if (succ.analyze(newStart, newEnd)) - break; - } } - + /* Try the next successor. */ succ = getSuccessor(succ.addr+1, end); } } } catch (java.io.IOException ioex) { - return false; + throw new AssertError(ioex.toString()); + } + } + + /** + * Create a Catch- resp. FinallyBlock (maybe even SynchronizedBlock). + * The root block MUST be a RawTryCatchBlock. + * @param start the start address + * @param end and the end address of FlowBlocks, we may use. + */ + public boolean analyzeCatchBlock(int start, int end) { + if (Decompiler.debugAnalyze) + System.err.println("analyzeCatch("+start+", "+end+")"); + RawTryCatchBlock rawBlock = (RawTryCatchBlock) block; + FlowBlock tryFlow = rawBlock.tryBlock.jump.destination; + FlowBlock catchFlow = rawBlock.catchBlock.jump.destination; + boolean changed = false; + tryFlow.analyze(addr, catchFlow.addr); + catchFlow.analyze(catchFlow.addr, end); + + updateInOut(tryFlow, true); + rawBlock.tryBlock.removeJump(); + tryFlow.getBlock().replace(rawBlock.tryBlock, null); + mergeSuccessors(tryFlow); + length += tryFlow.length; + + updateInOut(catchFlow, true); + rawBlock.catchBlock.removeJump(); + catchFlow.block.replace(rawBlock.catchBlock, null); + mergeSuccessors(catchFlow); + length += catchFlow.length; + + if (rawBlock.type != null) { + + CatchBlock newBlock = new CatchBlock(rawBlock.type); + newBlock.replace(rawBlock, rawBlock); + newBlock.setTryBlock(rawBlock.tryBlock); + newBlock.setCatchBlock(rawBlock.catchBlock); + lastModified = newBlock; + changed = true; + } else if (catchFlow.block instanceof SequentialBlock) { + SequentialBlock catchBlock = null; + int type = 0; + + try { + catchBlock = (SequentialBlock) catchFlow.block; + if (((Expression)((InstructionBlock)catchBlock.subBlocks[0]) + .instr).getOperator() instanceof jode.MonitorExitOperator + && ((ThrowBlock)catchBlock.subBlocks[1]).instr + instanceof jode.NopOperator) + + /* This is a synchronized block */ + type = 2; + + else if + (((SequentialBlock)catchBlock.subBlocks[1]).subBlocks[0] + instanceof JsrBlock + && ((LocalStoreOperator) + ((Expression) + ((InstructionBlock)catchBlock.subBlocks[0]) + .instr).getOperator()) + .matches((LocalLoadOperator) + ((Expression) + ((ThrowBlock) + ((SequentialBlock)catchBlock.subBlocks[1]). + subBlocks[1]) + .instr).getOperator())) + /* Wow that was complicated :-) + * But now we know that the catch block looks + * exactly like we exspected. + */ + type = 1; + } catch (ClassCastException ex) { + /* don't do transformations */ + } + + + if (type == 2) { + + /* This is a synchronized block */ + throw new AssertError ("Synchronized not implemented yet"); + + } else if (type == 1) { + + /* Finally block */ + + FlowBlock subRoutine = + ((JsrBlock)catchBlock.subBlocks[1].getSubBlocks()[0]) + .innerBlock.jump.destination; + + subRoutine.analyzeSubRoutine(addr+length, end); + updateInOut(subRoutine, true); + + length += subRoutine.length; + Enumeration enum = successors.elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump)enum.nextElement(); + if (jump != null && jump.destination == subRoutine) { + if (jump.prev instanceof EmptyBlock + && jump.prev.outer instanceof JsrBlock) { + /* XXX + * Could check much more here! + */ + StructuredBlock prevBlock = null; + StructuredBlock jsrBlock = jump.prev.outer; + if (jsrBlock.outer instanceof SequentialBlock) { + + if (jsrBlock.outer.getSubBlocks()[1] + == jsrBlock) { + prevBlock = + jsrBlock.outer.getSubBlocks()[0]; + prevBlock.replace(jsrBlock.outer, + jsrBlock.outer); + } else if (jsrBlock.outer.outer instanceof + SequentialBlock) { + prevBlock = + jsrBlock.outer.outer + .getSubBlocks()[0]; + jsrBlock.outer.getSubBlocks()[1] + .replace(jsrBlock.outer, + jsrBlock.outer); + } + } + if (prevBlock != null) { + if (prevBlock.jump == null) + prevBlock.moveJump(jsrBlock.jump); + else + jsrBlock.removeJump(); + } else { + EmptyBlock eb = new EmptyBlock(); + eb.moveJump(jsrBlock.jump); + eb.replace(jsrBlock, jump.prev); + } + jump.prev.removeJump(); + } else + throw new AssertError("wrong jsr"); + } + } + + CatchFinallyBlock newBlock = new CatchFinallyBlock(); + newBlock.replace(rawBlock, rawBlock); + newBlock.setTryBlock(rawBlock.tryBlock); + newBlock.setFinallyBlock(subRoutine.block); + lastModified = newBlock; + changed = true; + } + } + checkConsistent(); + if (Decompiler.debugAnalyze) + System.err.println("analyzeCatch("+start+", "+end+") " + +(changed?"succeeded":"failed") + +"; "+addr+","+(addr+length)); + return changed; + } + + public void analyzeSubRoutine(int start, int end) { + analyze(start, end); + /* throws ClassCastException if something isn't as exspected. */ + SequentialBlock sequBlock = (SequentialBlock) block; + LocalStoreOperator store = (LocalStoreOperator) + ((Expression)((InstructionBlock)sequBlock.subBlocks[0]).instr) + .getOperator(); + + while (sequBlock.subBlocks[1] instanceof SequentialBlock) + sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; + + if (! ((RetBlock)sequBlock.subBlocks[1]).local + .equals(store.getLocalInfo())) + throw new AssertError("Ret doesn't match"); + + if (sequBlock.outer == null) { + new EmptyBlock().replace(sequBlock, sequBlock); + } else { + sequBlock.subBlocks[0].replace(sequBlock, sequBlock); + block.getSubBlocks()[1].replace(block, block); } } @@ -1260,17 +1494,21 @@ public class FlowBlock { * Resolves the destinations of all jumps. */ public void resolveJumps(FlowBlock[] instr) { + if (block instanceof RawTryCatchBlock) { + ((RawTryCatchBlock)block).getTryBlock() + .jump.destination.resolveJumps(instr); + } Enumeration enum = successors.elements(); while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); - if (jump != null) { + if (jump != null && jump.destination == null) { if (jump.destAddr == -1) jump.destination = END_OF_METHOD; else jump.destination = instr[jump.destAddr]; - if (!jump.destination.predecessors.contains(this)) - jump.destination.predecessors.addElement(this); } + if (!jump.destination.predecessors.contains(this)) + jump.destination.predecessors.addElement(this); } } @@ -1347,4 +1585,18 @@ public class FlowBlock { public StructuredBlock getBlock() { return block; } + + public String toString() { + try { + java.io.StringWriter strw = new java.io.StringWriter(); + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(strw, " "); + writer.println(super.toString()); + writer.tab(); + dumpSource(writer); + return strw.toString(); + } catch (java.io.IOException ex) { + return super.toString(); + } + } } diff --git a/jode/jode/flow/IfThenElseBlock.java b/jode/jode/flow/IfThenElseBlock.java index 28afc27..82c21d8 100644 --- a/jode/jode/flow/IfThenElseBlock.java +++ b/jode/jode/flow/IfThenElseBlock.java @@ -126,13 +126,9 @@ public class IfThenElseBlock extends StructuredBlock { * Returns all sub block of this structured block. */ public StructuredBlock[] getSubBlocks() { - if (elseBlock == null) { - StructuredBlock[] result = { thenBlock }; - return result; - } else { - StructuredBlock[] result = { thenBlock, elseBlock }; - return result; - } + return (elseBlock == null) + ? new StructuredBlock[] { thenBlock } + : new StructuredBlock[] { thenBlock, elseBlock }; } /** diff --git a/jode/jode/flow/JsrBlock.java b/jode/jode/flow/JsrBlock.java index 5bcfc88..3efc2ab 100644 --- a/jode/jode/flow/JsrBlock.java +++ b/jode/jode/flow/JsrBlock.java @@ -60,8 +60,7 @@ public class JsrBlock extends StructuredBlock { * Returns all sub block of this structured block. */ public StructuredBlock[] getSubBlocks() { - StructuredBlock[] result = { innerBlock }; - return result; + return new StructuredBlock[] { innerBlock }; } public void dumpInstruction(jode.TabbedPrintWriter writer) diff --git a/jode/jode/flow/LoopBlock.java b/jode/jode/flow/LoopBlock.java index 90be3aa..3a6798d 100644 --- a/jode/jode/flow/LoopBlock.java +++ b/jode/jode/flow/LoopBlock.java @@ -47,6 +47,11 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { */ Instruction incr; + /** + * True, if the initializer is a declaration. + */ + boolean isDeclaration; + /** * The type of the loop. This must be one of DOWHILE, WHILE or FOR. */ @@ -120,8 +125,28 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { * Returns all sub block of this structured block. */ public StructuredBlock[] getSubBlocks() { - StructuredBlock[] result = { bodyBlock }; - return result; + return new StructuredBlock[] { bodyBlock }; + } + + public void dumpDeclaration(TabbedPrintWriter writer, LocalInfo local) + throws java.io.IOException + { + if (type == FOR && init != null + && (outer == null || !outer.used.contains(local)) + && init instanceof Expression + && ((Expression)init).getOperator() instanceof LocalStoreOperator + && ((LocalStoreOperator) ((Expression)init).getOperator()) + .getLocalInfo() == local.getLocalInfo()) { + isDeclaration = true; + } else + super.dumpDeclaration(writer, local); + } + + public void dumpSource(TabbedPrintWriter writer) + throws java.io.IOException + { + isDeclaration = false; + super.dumpSource(writer); } public void dumpInstruction(TabbedPrintWriter writer) @@ -141,9 +166,16 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { writer.print("do"); break; case FOR: - writer.print("for (" - +(init != null ? init.simplify().toString() : "") - +"; "+cond.simplify().toString()+"; " + writer.print("for ("); + if (isDeclaration) + writer.print(((LocalStoreOperator) + ((Expression)init).getOperator()) + .getLocalInfo().getType().toString() + + " " + init.simplify().toString()); + else if (init != null) + writer.print(init.simplify().toString()); + + writer.print("; "+cond.simplify().toString()+"; " +incr.simplify().toString()+")"); break; } @@ -188,6 +220,28 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { mayChangeJump = false; } + /** + * Replace all breaks to this block with a continue to this block. + */ + public void replaceBreakContinue() { + java.util.Stack todo = new java.util.Stack(); + todo.push(this); + while (!todo.isEmpty()) { + StructuredBlock[] subs = + ((StructuredBlock)todo.pop()).getSubBlocks(); + for (int i=0; i this.getCatchAddr())) { -// endBlock.setFlowBlock(flowBlock); -// if (tryBlock instanceof RawTryCatchBlock -// && ((RawTryCatchBlock)tryBlock).endBlock.jump.destination -// == endDest.destination) -// endBlock.jump = null; -// else -// flowBlock.addSuccessor(endDest); + parent = (RawTryCatchBlock) flow.getBlock(); + flow = parent.getTryBlock().jump.destination; + } - catchBlock.setFlowBlock(flowBlock); - flowBlock.addSuccessor(catchDest); + tryBlock = new EmptyBlock(new Jump(flow)); + tryBlock.outer = this; + new FlowBlock(flow.code, flow.addr, 0, this); + + if (parent == null) { + /* We are the outermost try block */ + return flowBlock; + } else { + /* Chain into existing try block list */ + parent.getTryBlock().jump.destination = flowBlock; + return first; + } } /** @@ -74,12 +83,6 @@ public class RawTryCatchBlock extends StructuredBlock { */ StructuredBlock tryBlock; -// /** -// * An empty block containing an unconditional jump to the EndBlock. -// * Or null if the try block is completely read. -// */ -// StructuredBlock endBlock; - /** * The catch block. */ @@ -101,14 +104,6 @@ public class RawTryCatchBlock extends StructuredBlock { StructuredBlock newBlock) { if (tryBlock == oldBlock) tryBlock = newBlock; - -// if (tryBlock instanceof RawTryCatchBlock -// && ((RawTryCatchBlock)tryBlock).endBlock.jump.destination -// == endBlock.jump.destination) { -// endBlock.removeJump(); -// } -// } else if (endBlock == oldBlock) { -// endBlock = newBlock; else if (catchBlock == oldBlock) catchBlock = newBlock; else @@ -120,30 +115,15 @@ public class RawTryCatchBlock extends StructuredBlock { * Returns all sub block of this structured block. */ public StructuredBlock[] getSubBlocks() { - StructuredBlock[] result = { tryBlock/*, endBlock*/, catchBlock }; - return result; + return new StructuredBlock[] { tryBlock, catchBlock }; } -// /** -// * 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 ( tryBlock.jump != null || tryBlock.jumpMayBeChanged()) -// && (catchBlock.jump != null || catchBlock.jumpMayBeChanged()); -// } - public void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException { writer.println("TRY "+(type != null ? type.toString() : "ALL")); writer.tab(); tryBlock.dumpSource(writer); writer.untab(); -// writer.println("UNTIL"); -// writer.tab(); -// endBlock.dumpSource(writer); -// writer.untab(); writer.println("CATCH TO"); writer.tab(); catchBlock.dumpSource(writer); diff --git a/jode/jode/flow/RemoveEmpty.java b/jode/jode/flow/RemoveEmpty.java index 8988308..c35cff2 100644 --- a/jode/jode/flow/RemoveEmpty.java +++ b/jode/jode/flow/RemoveEmpty.java @@ -47,7 +47,7 @@ public class RemoveEmpty implements Transformation { if (prev.jump != null) return false; instr = (Instruction) prev.getInstruction(); - instr.setType(instr.getType().intersection(prevInstr.getType())); + instr.setType(prevInstr.getType()); } catch (NullPointerException ex) { return false; } catch (ClassCastException ex) { diff --git a/jode/jode/flow/ReturnBlock.java b/jode/jode/flow/ReturnBlock.java index 6f4e476..d31229b 100644 --- a/jode/jode/flow/ReturnBlock.java +++ b/jode/jode/flow/ReturnBlock.java @@ -39,7 +39,7 @@ public class ReturnBlock extends InstructionContainer { * @return true if this block should be sorrounded by braces. */ public boolean needsBraces() { - return false; + return declare != null && !declare.isEmpty(); } /** diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index c99b82e..21e2df9 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -278,7 +278,7 @@ public abstract class StructuredBlock { * @param jump The jump that should be moved, may be null. */ public void moveJump(Jump jump) { - removeJump(); + removeJump(); this.jump = jump; if (jump != null) { jump.prev.jump = null; @@ -458,5 +458,19 @@ public abstract class StructuredBlock { */ public abstract void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException; + + public String toString() { + try { + java.io.StringWriter strw = new java.io.StringWriter(); + jode.TabbedPrintWriter writer = + new jode.TabbedPrintWriter(strw, " "); + writer.println(super.toString()); + writer.tab(); + dumpSource(writer); + return strw.toString(); + } catch (java.io.IOException ex) { + return super.toString(); + } + } } diff --git a/jode/jode/flow/ThrowBlock.java b/jode/jode/flow/ThrowBlock.java index f40052c..fc13d61 100644 --- a/jode/jode/flow/ThrowBlock.java +++ b/jode/jode/flow/ThrowBlock.java @@ -29,6 +29,14 @@ public class ThrowBlock 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 declare != null && !declare.isEmpty(); + } + public void dumpInstruction(TabbedPrintWriter writer) throws java.io.IOException {