From c885953efd74a1a2ecce929056db26686752074d Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 17 Sep 1998 15:50:03 +0000 Subject: [PATCH] *** empty log message *** git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@18 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/flow/FlowBlock.java | 564 +++++++++++++++++++--------- jode/jode/flow/IfThenElseBlock.java | 56 ++- jode/jode/flow/StructuredBlock.java | 84 ++++- 3 files changed, 508 insertions(+), 196 deletions(-) diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index fe77ea9..c1912bb 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -47,8 +47,8 @@ public class FlowBlock { StructuredBlock lastModified; /** - * All Jumps that this flow block contains. - */ + * All Jumps that this flow block contains. The objects may be + * null, if they were marked as deleted. */ Vector successors; /** @@ -60,200 +60,407 @@ public class FlowBlock { /** * This method optimizes the jumps to successor. - * Returns true, if all jumps could be eliminated. + * Returns the new appendBlock, it may have changed. */ - public boolean optimizeJumps(FlowBlock successor, - StructuredBlock structBlock) { - /* if the jump is the jump of the structBlock, skip it. - */ - - /* remove all jumps to the successor which have the successor - * as getNextFlowBlock(). */ + public StructuredBlock optimizeJumps(FlowBlock successor, + StructuredBlock appendBlock) { + Enumeration enum = successors.elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); - /* 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 == null || jump.destination != successor) + continue; - /* if the successor is the dummy return instruction, replace all - * jumps with a return. - */ + /* if the jump is the jump of the appendBlock, skip it. + */ + if (jump == appendBlock.jump) + continue; - /* 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. - * - * If this is a while and the condition of the while is true, - * and this jump belongs to the first instruction in this - * while block and is inside a ConditionalBlock remove that - * ConditionalBlock an move the condition to the while block. - */ - - /* 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. - */ - } + /* Note: jump.parent.outer != null, since appendBlock is + * an outer block of jump.parent + */ + + /* remove all jumps to the successor which have the successor + * as getNextFlowBlock(). */ + if (jump.parent.outer.getNextFlowBlock(jump.parent) == successor) + jump.parent.removeJump(); + + /* 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.parent instanceof ConditionalBlock && + jump.parent.outer instanceof SequentialBlock && + jump.parent.outer.getSubBlocks()[0] = jump.parent && + jump.parent.outer.getNextFlowBlock() == successor) { + ConditionalBlock cb = (ConditionalBlock) jump.parent; + cb.removeJump(); - /* Special cases: - * - * try-header - * |- first instruction - * | ... - * | last instruction - * |- optional jump (last+1) - * | ... - * `- catch block - * - * A try block may have many try-headers with different catch blocks - * and there may be a finally block: - * - * try-header any - * | try-header - * |--|- first instruction - * | | ... - * | | every jump to outside is preceded by jsr finally - * | | ... - * | | last instruction - * | |- optional jump after catch block (last+1) - * | | ... | - * | `- catch block | - * | ... | - * | ,-----------------' - * | |-jump after all catch blocks - * | v - * | jsr finally -----------------, - * |- jump after finally | - * `- catch any (local_n) v - * jsr finally ---------------->| - * throw local_n; | - * finally: <-----------------------' - * astore_n - * ... - * return_n - * - * - * flow-block - * finally-block - * ---> try-header - * finally { - * ---> first-finally-instruction - * - * A synchronized block uses a similar technique: - * - * local_x = monitor object; - * monitorenter local_x - * try-header any - * |- syncronized block - * | ... - * | every jump to outside is preceded by jsr monexit ---, - * | ... | - * |- monitorexit local_x | - * | jump after this block (without jsr monexit) | - * `- catch any (local_n) | - * monitorexit local_x | - * throw local_n | - * monexit: <-----------------------------------------------' - * astore_n - * monitorexit local_x - * return_n - */ + SequentialBlock sequBlock = + (SequentialBlock) cb.outer; - public boolean doT1 { - /* search successor with smallest addr. */ - Enumeration enum = successors.elements(); - FlowBlock succ = null; - while (enum.hasMoreElements()) { - FlowBlock fb = ((Jump) enum.nextElement()).destination; - if (succ == null || fb.addr < succ.addr) { - succ = fb; - } - } - if (succ == null) { - /* There are no successors at all */ - return false; - } - - /* check if this successor has only this block as predecessor. */ - /* if not, return false. */ - if (succ.predecessors.size() != 1) - return false; - - /* First find the innermost block that contains all jumps to this - * successor and the last modified block. - */ - Enumeration enum = successors.elements(); - StructuredBlock structBlock = lastModified; - while(enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); + IfThenElseBlock newIfBlock = + new IfThenElseBlock(cb.getCondition().negate(), + sequBlock.getSubBlocks()[1], null); - while (!structBlock.contains(jump.parent)) - structBlock = structBlock.outer; - /* structBlock can't be null now, because the - * outermost block contains every structured block. - */ - } + newIfBlock.replace(sequBlock); - /* The switch "fall through" case: if the structBlock is a - * switch, and the successor is the address of a case, and all - * other successors are inside the block preceding that case. - */ - if (case != null) { - SwitchBlock switchBlock = (StructuredBlock) structBlock; + if (appendBlock == sequBlock) + appendBlock = newIfBlock; + continue; + } - /* Now put the succ.block into the next case. + /* if the successor is the dummy return instruction, replace all + * jumps with a return. */ - switchBlock.replaceSubBlock(nextcase,succ.block); + if (successor.block.instanceof ReturnBlock) { + SequentialBlock sequBlock = new SequentialBlock(); + StructuredBlock prevBlock = jump.parent; + prevBlock.removeJump(); + sequBlock.replace(prevBlock); + sequBlock.setFirst(prevBlock); + sequBlock.setSecond(new ReturnBlock()); + continue; + } - /* Do the following modifications on the struct block. */ - structBlock = precedingcase; + /* 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. + */ - } else { + /* This is the first instruction in a while block */ + if (jump.parent instanceof ConditionalBlock && + jump.parent.outer instanceof SequentialBlock && + jump.parent.outer.getSubBlocks()[0] == this && + jump.parent.outer.outer instanceof LoopBlock) { + ConditionalBlock cb = (ConditionalBlock) jump.parent; + LoopBlock loopBlock = (LoopBlock) cb.outer.outer; + if (loopBlock.getCondition() == LoopBlock.TRUE && + loopBlock.getType() != LoopBlock.DOWHILE && + loopBlock.getNextFlowBlock() == successor) { + + cb.removeJump(); + loopBlock.setCondition(cb); + cb.outer.getSubBlocks()[1].replace(cb.outer); + /* cb and cb.outer are not used any more */ + /* Note that cb.outer != appendBlock because + * appendBlock contains loopBlock + */ + } + } + /* Now the same for the empty loop. In this case there is + * no sequential block. + */ + if (jump.parent instanceof ConditionalBlock && + jump.parent.outer instanceof LoopBlock) { + ConditionalBlock cb = (ConditionalBlock) jump.parent; + LoopBlock loopBlock = (LoopBlock) cb.outer; + if (loopBlock.getCondition() == LoopBlock.TRUE && + loopBlock.getType() != LoopBlock.DOWHILE && + loopBlock.getNextFlowBlock() == successor) { + + cb.removeJump(); + loopBlock.setCondition(cb); + EmptyBlock empty = new EmptyBlock(); + empty.replace(cb); + /* cb is not used any more */ + } + } - /* Prepare the unification of the blocks: Make sure that - * structBlock has a successor outside of this block. This is - * always possible, because it contains lastModified. + /* 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. */ - if (structBlock.jump == null) { - /* assert(structBlock.jump.getNextFlowBlock() != null) */ - structBlock.setJump(structBlock.getNextFlowBlock()); + int breaklevel = 0; + for (StructuredBlock surrounder = jump.parent.outer; + surrounder != null; surrounder = surrounder.outer) { + if (surrounder instanceof BreakableBlock) { + breaklevel++; + if (surrounder.getNextFlowBlock() == successor || + surrounder.jumpMayBeChanged()) { + + SequentialBlock sequBlock = new SequentialBlock(); + StructuredBlock prevBlock = jump.parent; + if (surrounder.getNextFlowBlock() != successor) { + surrounder.jump = jump; + prevBlock.jump = null; + jump.parent = surrounder; + } else { + prevBlock.removeJump(); + } + sequBlock.replace(prevBlock); + sequBlock.setFirst(prevBlock); + sequBlock.setSecond(new BreakBlock(surrounder, + breaklevel > 1)); + continue; + } + } } - /* Now unify the blocks: Create a new SequentialBlock - * containing structBlock and successor.block. Then replace - * structBlock with the new sequential block. + + /* 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.parent.outer.getNextBlock(jump.parent); + 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.getElseBlock() == null) { + if (elseBlock.getNextFlowBlock() != successor) { + elseBlock.outer.jump = jump; + jump.parent.jump = null; + jump.parent = elseBlock.outer; + } else { + jump.parent.removeJump(); + } + ifBlock.replace(elseBlock.outer) + ifBlock.setElseBlock(elseBlock); + if (appendBlock = elseBlock.outer) + appendBlock = ifBlock; + } + } } - - /* Try to eliminate as many jumps as possible. - */ - - optimizeJumps(succ, structBlock); - - /* Now remove the jump of the structBlock if it points to successor. - */ - - if (structBlock.jump == null) - structBlock.removeJump(); - - /* If there are further jumps, put a do/while(0) block around - * structBlock and replace every remaining jump with a break - * to the do/while block. - */ - - /* Set last modified to correct value. - */ - lastModified = succ.lastModified; + return appendBlock; } + /** + * Updates the in/out-Vectors of the structured block of the + * successing flow block simultanous to a T1 transformation. + * @param successor The flow block which is unified with this flow + * block. + */ + 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; + Enumeration enum = successors; + while (enum.hasMoreElement()) { + Jump jump = (Jump) enum.nextElement(); + if (jump == null || jump.destination != successor) + continue; + + allOuts.union(jump.parent.out); + if (intersectOut == null) + intersectOut = jump.parent.out; + else + intersectOut = intersectOut.intersect(jump.parent.out); + } + + /* Now work on each block of the successor */ + Stack todo = new Stack(); + todo.push(successor.block); + while (!todo.empty()) { + StructuredBlock block = (StructuredBlock) todo.pop(); + StructuredBlock[] subBlocks = block.getSubBlocks(); + for (int i=0; i| + * throw local_n; | + * finally: <-----------------------' + * astore_n + * ... + * return_n + * + * + * flow-block + * finally-block + * ---> try-header + * finally { + * ---> first-finally-instruction + * + * A synchronized block uses a similar technique: + * + * local_x = monitor object; + * monitorenter local_x + * try-header any + * |- syncronized block + * | ... + * | every jump to outside is preceded by jsr monexit ---, + * | ... | + * |- monitorexit local_x | + * | jump after this block (without jsr monexit) | + * `- catch any (local_n) | + * monitorexit local_x | + * throw local_n | + * monexit: <-----------------------------------------------' + * astore_n + * monitorexit local_x + * return_n + */ + + public boolean doT1 { + /* search successor with smallest addr. */ + Enumeration enum = successors.elements(); + FlowBlock succ = null; + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + if (jump == null) + continue; + FlowBlock fb = jump.destination; + if (succ == null || fb.addr < succ.addr) { + succ = fb; + } + } + if (succ == null) { + /* There are no successors at all */ + return false; + } + + /* check if this successor has only this block as predecessor. */ + /* if not, return false. */ + if (succ.predecessors.size() != 1) + return false; + + /* First find the innermost block that contains all jumps to this + * successor and the last modified block. + */ + Enumeration enum = successors.elements(); + StructuredBlock appendBlock = lastModified; + while(enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + if (jump == null || jump.destination != successors) + continue; + + while (!appendBlock.contains(jump.parent)) + appendBlock = appendBlock.outer; + /* appendBlock can't be null now, because the + * outermost block contains every structured block. + */ + } + + /* Update the in/out-Vectors now */ + updateInOut(successor, true); + + /* The switch "fall through" case: if the appendBlock is a + * switch, and the successor is the address of a case, and all + * other successors are inside the block preceding that case. + */ + if (case != null) { + SwitchBlock switchBlock = (StructuredBlock) appendBlock; + + /* Now put the succ.block into the next case. + */ + switchBlock.replaceSubBlock(nextcase,succ.block); + succ.block.outer = switchBlock; + /* nextcase is not referenced any more */ + + /* Do the following modifications on the struct block. */ + appendBlock = precedingcase; + + } else { + + /* Prepare the unification of the blocks: Make sure that + * appendBlock has a successor outside of this block. This is + * always possible, because it contains lastModified. + */ + if (appendBlock.jump == null) { + /* assert(appendBlock.jump.getNextFlowBlock() != null) */ + appendBlock.setJump(appendBlock.getNextFlowBlock()); + } + + /* Now unify the blocks: Create a new SequentialBlock + * containing appendBlock and successor.block. Then replace + * appendBlock with the new sequential block. + */ + StructuredBlock outer = appendBlock.outer; + StructuredBlock sequBlock = + new SequentialBlock(appendBlock, switchBlock); + outer.replaceSubBlock(appendBlock, sequBlock); + sequBlock.outer = outer; + } + + /* Try to eliminate as many jumps as possible. + */ + + optimizeJumps(succ, appendBlock); + + /* Now remove the jump of the appendBlock if it points to successor. + */ + + if (appendBlock.jump == 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. + */ + + /* Believe it or not: Now the rule, that the first part of a + * SequentialBlock shouldn't be another SequentialBlock is + * fulfilled.

+ * + * This isn't easy to prove, it has a lot to do with the + * transformation in optimizeJump and the fact that + * appendBlock was the innermost Block containing all jumps + * and lastModified. + */ + + /* Set last modified to correct value. */ + lastModified = succ.lastModified; + } + public boolean doT2() { /* If there are no jumps to the beginning of this flow block * or if this block has other predecessors which weren't @@ -261,6 +468,9 @@ public class FlowBlock { * sure that the while isn't created up to the first continue. */ + /* Update the in/out-Vectors now */ + updateInOut(successor, false); + /* 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 @@ -286,6 +496,10 @@ public class FlowBlock { */ } } + + public void removeSuccessor(Jump jump) { + successors.setElementAt(null, successors.indexOf(jump)); + } } diff --git a/jode/jode/flow/IfThenElseBlock.java b/jode/jode/flow/IfThenElseBlock.java index e2d903a..3a7b869 100644 --- a/jode/jode/flow/IfThenElseBlock.java +++ b/jode/jode/flow/IfThenElseBlock.java @@ -39,21 +39,31 @@ public class IfThenElseBlock extends StructuredBlock { StructuredBlock elseBlock; /** - * Creates a new if then else block. - * @param thenBlock the then block, must be non null. - * @param elseBlock the else block, may be null. + * Creates a new if then else block. The method setThenBlock must + * be called shortly after the creation. */ - public IfThenElseBlock(Instruction cond, - StructuredBlock thenBlock, - StructuredBlock elseBlock) { + public IfThenElseBlock(Instruction cond) { this.cond = cond; + } + + /** + * Sets the then block. + * @param thenBlock the then block, must be non null. + */ + public void setThenBlock(StructuredBlock thenBlock) { this.thenBlock = thenBlock; - this.elseBlock = elseBlock; thenBlock.outer = this; - if (elseBlock != null) - elseBlock.outer = this; } + /** + * Sets the else block. + * @param elseBlock the else block + */ + public void setElseBlock(StructuredBlock elseBlock) { + this.elseBlock = elseBlock; + elseBlock.outer = this; + } + /* The implementation of getNext[Flow]Block is the standard * implementation */ @@ -98,4 +108,32 @@ public class IfThenElseBlock extends StructuredBlock { if (needBrace) writer.println("}"); } + + /** + * Returns all sub block of this structured block. + */ + StructuredBlock[] getSubBlocks() { + if (elseBlock == null) { + StructuredBlock result = { thenBlock }; + return result; + } else { + StructuredBlock result = { thenBlock, elseBlock }; + return result; + } + } + + /** + * 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() { + if (thenBlock.jump == null && !thenBlock.jumpMayBeChanged()) + return false; + + if (elseBlock != null && elseBlock.jump == null && + !elseBlock.jumpMayBeChanged) + return false; + return true; + } } diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index 8a6fd06..18fa67a 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -65,7 +65,7 @@ public abstract class StructuredBlock { * path from the start of the current flow block, on which the * local variable is never assigned */ - Vector in; + VariableSet in; /** * The out locals. This are the locals, which must be overwritten @@ -74,12 +74,18 @@ public abstract class StructuredBlock { * structured block contain a (unconditional) assignment to this * local */ - Vector out; + VariableSet out; /** - * The surrounding structured block. If this is the outermost - * block in a flow block, outer is null. + * The variable set containing all variables that must be defined + * in this block (or maybe an outer block, this changes as the + * blocks are put together). */ + VariableSet defineHere; + + /** + * The surrounding structured block. If this is the outermost + * block in a flow block, outer is null. */ StructuredBlock outer; /** @@ -96,9 +102,11 @@ public abstract class StructuredBlock { /** * Returns the block where the control will normally flow to, when - * this block is finished (ignoring the jump after this block). + * this block is finished (not ignoring the jump after this block). */ StructuredBlock getNextBlock() { + if (jump != null) + return null; if (outer != null) outer.getNextBlock(this); else @@ -107,12 +115,14 @@ public abstract class StructuredBlock { /** * Returns the flow block where the control will normally flow to, - * when this block is finished (ignoring the jump after this + * when this block is finished (not ignoring the jump after this * block). * @return null, if the control flows into a non empty structured * block or if this is the outermost block. */ FlowBlock getNextFlowBlock() { + if (jump != null) + return jump.destination; if (outer != null) outer.getNextFlowBlock(this); else @@ -142,14 +152,10 @@ public abstract class StructuredBlock { * the behaviour is undefined, so take care. * @return null, if the control flows to another FlowBlock. */ StructuredBlock getNextBlock(StructuredBlock subBlock) { - if (jump != null) - return null; return getNextBlock(); } FlowBlock getNextFlowBlock(StructuredBlock subBlock) { - if (jump != null) - return jump.destination; return getNextFlowBlock(); } @@ -164,6 +170,13 @@ public abstract class StructuredBlock { return false; } + /** + * Returns all sub block of this structured block. + */ + StructuredBlock[] getSubBlocks() { + return new StructuredBlock[0]; + } + /** * Returns if this block contains the given block. * @param child the block which should be contained by this block. @@ -175,11 +188,58 @@ public abstract class StructuredBlock { return (child == this); } + + /** + * Removes the jump after this structured block. This does also update + * the successors vector of the flow block. + */ + public void removeJump() { + if (jump != null) { + flowBlock.removeSuccessor(jump); + jump = null; + } + } + + /** + * This function replaces sb with this block. It copies outer and + * the following jump from sb, and updates them, so they know that + * sb was replaced. + * The jump field of sb is removed afterwards. You have to replace + * sb.outer or mustn't use sb anymore. + * @param sb The structured block that should be replaced. + */ + public void replace(StructuredBlock sb) { + in = sb.in; + out = sb.out; + defineHere = sb.defineHere; + outer = sb.outer; + flowBlock = sb.flowBlock; + jump = sb.jump; + + if (jump != null) { + jump.parent = this; + sb.jump = null; + } + if (outer != null) { + outer.replaceSubBlock(sb, this); + } else { + flowBlock.block = this; + } + } + + /** + * 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; + } + /** * Print the source code for this structured block. This may be * called only once, because it remembers which local variables - * were declared. - */ + * were declared. */ public abstract void dumpSource(TabbedPrintWriter writer) throws java.io.IOException; }