From a891c3b82cfa6103c57a80a13cd430f7c67c2647 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 1998 17:06:14 +0000 Subject: [PATCH] finally and synchronized improvements, clean up and speed up git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@70 379699f6-c40d-0410-875b-85095c16579e --- jode/jode/flow/CatchBlock.java | 3 +- jode/jode/flow/CatchFinallyBlock.java | 30 +- jode/jode/flow/CombineIfGotoExpressions.java | 1 + jode/jode/flow/CompleteSynchronized.java | 26 +- jode/jode/flow/CreateExpression.java | 2 +- jode/jode/flow/CreateForInitializer.java | 25 +- jode/jode/flow/CreateIfThenElseOperator.java | 54 +- jode/jode/flow/FlowBlock.java | 1584 +++++++++--------- jode/jode/flow/LoopBlock.java | 8 +- jode/jode/flow/RemoveEmpty.java | 5 +- jode/jode/flow/SequentialBlock.java | 7 + jode/jode/flow/StructuredBlock.java | 46 +- jode/jode/flow/SynchronizedBlock.java | 7 +- 13 files changed, 948 insertions(+), 850 deletions(-) diff --git a/jode/jode/flow/CatchBlock.java b/jode/jode/flow/CatchBlock.java index 01cc98a..00943bb 100644 --- a/jode/jode/flow/CatchBlock.java +++ b/jode/jode/flow/CatchBlock.java @@ -88,7 +88,8 @@ public class CatchBlock extends StructuredBlock { ? new EmptyBlock() : catchBlock.getSubBlocks()[1]); - newCatchBlock.moveJump(catchBlock.jump); + if (catchBlock.jump != null) + newCatchBlock.moveJump(catchBlock.jump); catchBlock = newCatchBlock; } } diff --git a/jode/jode/flow/CatchFinallyBlock.java b/jode/jode/flow/CatchFinallyBlock.java index 5b988b0..c6e0c04 100644 --- a/jode/jode/flow/CatchFinallyBlock.java +++ b/jode/jode/flow/CatchFinallyBlock.java @@ -36,22 +36,22 @@ public class CatchFinallyBlock extends CatchBlock { fin.setFlowBlock(flowBlock); } - /** - * Returns the block where the control will normally flow to, when - * the given sub block is finished (not ignoring the jump - * after this block). FinallyBlock have a special behaviour, since - * the try block has the finallyblock as successor and the - * finallyblock has no default successor at all!! - * - * @return null, if the control flows to another FlowBlock. - */ - public StructuredBlock getNextBlock(StructuredBlock subBlock) { - return subBlock == tryBlock ? finallyBlock : null; - } +// /** +// * Returns the block where the control will normally flow to, when +// * the given sub block is finished (not ignoring the jump +// * after this block). FinallyBlock have a special behaviour, since +// * the try block has the finallyblock as successor and the +// * finallyblock has no default successor at all!! +// * +// * @return null, if the control flows to another FlowBlock. +// */ +// public StructuredBlock getNextBlock(StructuredBlock subBlock) { +// return subBlock == tryBlock ? finallyBlock : null; +// } - public FlowBlock getNextFlowBlock(StructuredBlock subBlock) { - return null; - } +// public FlowBlock getNextFlowBlock(StructuredBlock subBlock) { +// return null; +// } /** * Replaces the given sub block with a new block. diff --git a/jode/jode/flow/CombineIfGotoExpressions.java b/jode/jode/flow/CombineIfGotoExpressions.java index f589a0a..ffaf13a 100644 --- a/jode/jode/flow/CombineIfGotoExpressions.java +++ b/jode/jode/flow/CombineIfGotoExpressions.java @@ -80,6 +80,7 @@ public class CombineIfGotoExpressions implements Transformation{ } catch (NullPointerException ex) { return false; } + flow.removeSuccessor(prevJump); prevJump.prev.removeJump(); Expression cond = new ComplexExpression diff --git a/jode/jode/flow/CompleteSynchronized.java b/jode/jode/flow/CompleteSynchronized.java index 1976bd1..3c4a324 100644 --- a/jode/jode/flow/CompleteSynchronized.java +++ b/jode/jode/flow/CompleteSynchronized.java @@ -33,32 +33,38 @@ public class CompleteSynchronized implements Transformation { */ public boolean transform(FlowBlock flow) { - SynchronizedBlock synBlock; - try { - synBlock = (SynchronizedBlock) flow.lastModified; + if (!(flow.lastModified instanceof SynchronizedBlock) + || flow.lastModified.outer == null) + return false; - SequentialBlock sequBlock = - (SequentialBlock) synBlock.outer; + /* If the program is well formed, the following succeed */ + SynchronizedBlock synBlock = (SynchronizedBlock) flow.lastModified; + try { + SequentialBlock sequBlock = (SequentialBlock) synBlock.outer; + ComplexExpression monenter = (ComplexExpression) ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); - + if (!(monenter.getOperator() instanceof MonitorEnterOperator) || ((LocalLoadOperator) monenter.getSubExpressions()[0]). getLocalInfo() != synBlock.local.getLocalInfo()) return false; + } catch (ClassCastException ex) { return false; - } catch (NullPointerException ex) { - return false; } if (jode.Decompiler.isVerbose) - System.err.print("f"); + System.err.print('s'); synBlock.isEntered = true; synBlock.replace(synBlock.outer, synBlock); + /* Is there another expression? */ + if (synBlock.outer == null) + return false; + Expression object; try { SequentialBlock sequBlock = @@ -75,8 +81,6 @@ public class CompleteSynchronized implements Transformation { } catch (ClassCastException ex) { return true; - } catch (NullPointerException ex) { - return true; } synBlock.object = object; diff --git a/jode/jode/flow/CreateExpression.java b/jode/jode/flow/CreateExpression.java index 934b444..87ec4ab 100644 --- a/jode/jode/flow/CreateExpression.java +++ b/jode/jode/flow/CreateExpression.java @@ -106,7 +106,7 @@ public class CreateExpression implements Transformation { return false; } if(jode.Decompiler.isVerbose) - System.err.print("x"); + System.err.print('x'); ((InstructionContainer) flow.lastModified).setInstruction (new ComplexExpression(op, exprs)); diff --git a/jode/jode/flow/CreateForInitializer.java b/jode/jode/flow/CreateForInitializer.java index 0da699b..9c8c762 100644 --- a/jode/jode/flow/CreateForInitializer.java +++ b/jode/jode/flow/CreateForInitializer.java @@ -30,32 +30,33 @@ public class CreateForInitializer implements Transformation { */ public boolean transform(FlowBlock flow) { - LoopBlock forBlock; + if (!(flow.lastModified instanceof LoopBlock) + || flow.lastModified.outer == null) + return false; + + LoopBlock forBlock = (LoopBlock) flow.lastModified; + if (forBlock.type != forBlock.FOR || forBlock.init != null) + return false; + + /* The following succeed, with high probability */ + Instruction initializer; try { - forBlock = (LoopBlock) flow.lastModified; - - if (forBlock.type != forBlock.FOR || forBlock.init != null) - return false; - SequentialBlock sequBlock = (SequentialBlock) forBlock.outer; initializer = ((InstructionBlock) sequBlock.subBlocks[0]).getInstruction(); - if (!(initializer instanceof Expression) - || !( ((Expression)initializer).getOperator() - instanceof StoreInstruction)) + if (!( ((Expression)initializer).getOperator() + instanceof StoreInstruction)) return false; } catch (ClassCastException ex) { return false; - } catch (NullPointerException ex) { - return false; } if (jode.Decompiler.isVerbose) - System.err.print("f"); + System.err.print('f'); forBlock.init = initializer; forBlock.replace(forBlock.outer, forBlock); diff --git a/jode/jode/flow/CreateIfThenElseOperator.java b/jode/jode/flow/CreateIfThenElseOperator.java index 1aac5e5..df95585 100644 --- a/jode/jode/flow/CreateIfThenElseOperator.java +++ b/jode/jode/flow/CreateIfThenElseOperator.java @@ -61,28 +61,31 @@ public class CreateIfThenElseOperator implements Transformation { */ public boolean createFunny(FlowBlock flow) { - Expression[] e = new Expression[3]; - IfThenElseBlock ifBlock; - try { - ConditionalBlock conditional = - (ConditionalBlock) flow.lastModified; + if (!(flow.lastModified instanceof ConditionalBlock)) + return false; - if (!(conditional.trueBlock instanceof EmptyBlock) - || conditional.trueBlock.jump == null - || conditional.jump == null) - return false; + ConditionalBlock conditional = (ConditionalBlock) flow.lastModified; - CompareUnaryOperator compare = - (CompareUnaryOperator) conditional.getInstruction(); + if (!(conditional.trueBlock instanceof EmptyBlock) + || conditional.trueBlock.jump == null + || conditional.jump == null + || !(conditional.getInstruction() instanceof CompareUnaryOperator)) + return false; + + CompareUnaryOperator compare = + (CompareUnaryOperator) conditional.getInstruction(); + + FlowBlock trueDestination; + if (compare.getOperatorIndex() == compare.EQUALS_OP) + trueDestination = conditional.jump.destination; + else if (compare.getOperatorIndex() == compare.NOTEQUALS_OP) + trueDestination = conditional.trueBlock.jump.destination; + else + return false; - FlowBlock trueDestination; - if (compare.getOperatorIndex() == compare.EQUALS_OP) - trueDestination = conditional.jump.destination; - else if (compare.getOperatorIndex() == compare.NOTEQUALS_OP) - trueDestination = conditional.trueBlock.jump.destination; - else - return false; - + Expression[] e = new Expression[3]; + IfThenElseBlock ifBlock; + try { SequentialBlock sequBlock = (SequentialBlock) conditional.outer; @@ -129,9 +132,11 @@ public class CreateIfThenElseOperator implements Transformation { return false; Expression cond = (Expression) condBlock.getInstruction(); + flow.removeSuccessor(condBlock.trueBlock.jump); condBlock.trueBlock.removeJump(); pushBlock.setInstruction(cond); pushBlock.replace(sequBlock, pushBlock); + e[i+1] = cond; } } catch (ClassCastException ex) { @@ -141,7 +146,7 @@ public class CreateIfThenElseOperator implements Transformation { } if (jode.Decompiler.isVerbose) - System.err.print("?"); + System.err.print('?'); IfThenElseOperator iteo = new IfThenElseOperator (e[1].getType().intersection(e[2].getType())); @@ -170,6 +175,7 @@ public class CreateIfThenElseOperator implements Transformation { */ public boolean create(FlowBlock flow) { Expression e[] = new Expression[3]; + InstructionBlock thenBlock; try { InstructionBlock elseBlock = (InstructionBlock) flow.lastModified; @@ -181,7 +187,7 @@ public class CreateIfThenElseOperator implements Transformation { if (ifBlock.elseBlock != null) return false; - InstructionBlock thenBlock = (InstructionBlock) ifBlock.thenBlock; + thenBlock = (InstructionBlock) ifBlock.thenBlock; if (thenBlock.jump.destination != elseBlock.jump.destination) return false; @@ -194,7 +200,6 @@ public class CreateIfThenElseOperator implements Transformation { return false; e[0] = (Expression) ifBlock.cond; - thenBlock.removeJump(); } catch (ClassCastException ex) { return false; } catch (NullPointerException ex) { @@ -202,7 +207,10 @@ public class CreateIfThenElseOperator implements Transformation { } if (jode.Decompiler.isVerbose) - System.err.print("?"); + System.err.print('?'); + + flow.removeSuccessor(thenBlock.jump); + thenBlock.removeJump(); IfThenElseOperator iteo = new IfThenElseOperator (e[1].getType().intersection(e[2].getType())); diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index eb8e9b4..219e701 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -76,9 +76,11 @@ public class FlowBlock { StructuredBlock lastModified; /** - * All Jumps that this flow block contains. The objects may be - * null, if they were marked as deleted. */ - Vector successors; + * This contains a map of all successing flow blocks and there + * jumps. The key of this dictionary are the flow blocks, while + * the elements are Stacks of jumps. + */ + Dictionary successors = new Hashtable(); /** * This is a vector of flow blocks, which reference this block. @@ -88,7 +90,7 @@ public class FlowBlock { * If this vectors contains the null element, this is the first * flow block in a method. */ - Vector predecessors; + Vector predecessors = new Vector(); /** * The default constructor. Creates a new flowblock containing @@ -101,11 +103,8 @@ public class FlowBlock { this.length = length; this.block = block; lastModified = block; - predecessors = new Vector(); // filled in later - successors = new Vector(); block.setFlowBlock(this); block.fillInSet(in); - block.fillSuccessors(successors); } public int getNextAddr() { @@ -118,21 +117,20 @@ public class FlowBlock { /** * This method optimizes the jumps to successor. - * @param successor The successing flow block * @param appendBlock the block where the successor is appended to. + * @param jumps The jumps that jump to successor. All jumps that + * can be optimized are removed from this stack. * @return the new appendBlock, it may have changed. */ - public StructuredBlock optimizeJumps(FlowBlock successor, - StructuredBlock appendBlock) { - Enumeration enum = successors.elements(); - next_jump: - while (enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); + public StructuredBlock optimizeJumps(StructuredBlock appendBlock, + Stack jumps) { + Stack remainingJumps = new Stack(); - if (jump == null || jump.destination != successor) - continue next_jump; + next_jump: + while (!jumps.isEmpty()) { + Jump jump = (Jump) jumps.pop(); - while(jump != null) { + FlowBlock successor = jump.destination; if (jump.prev instanceof EmptyBlock && jump.prev.outer != null @@ -144,7 +142,7 @@ public class FlowBlock { * transform it by hand. */ jump.prev.removeJump(); - continue next_jump; + continue; } /* Swap conditional blocks, that have two jumps, and where @@ -152,7 +150,7 @@ public class FlowBlock { */ StructuredBlock prev = jump.prev; ConditionalBlock cb = (ConditionalBlock) prev.outer; - jode.Instruction instr = cb.getInstruction(); + Instruction instr = cb.getInstruction(); /* XXX Expression clean up is necessary. Otherwise * this may lead to a ClassCastException. @@ -160,10 +158,17 @@ public class FlowBlock { * Our code below _depends_ on the fact that this * transformation is done. */ - cb.setInstruction(((jode.Expression)instr).negate()); + cb.setInstruction(((Expression)instr).negate()); cb.swapJump(jump.prev); } + /* if the jump is the jump of the appendBlock, skip it. + */ + if (jump.prev == appendBlock) { + remainingJumps.push(jump); + continue; + } + /* Now move the jump as far to the outer as possible, * without leaving appendBlock. * @@ -171,21 +176,24 @@ public class FlowBlock { * jump.prev.outer != null, since appendBlock is an outer * block of jump.prev */ - while (jump.prev != appendBlock - && jump.prev.outer.isSingleExit(jump.prev)) { + while (jump.prev.outer.isSingleExit(jump.prev)) { + if (jump.prev.outer == appendBlock) { + /* Okay we have reached the top. + * appendBlock should already have the right jump. + */ + jump.prev.removeJump(); + continue next_jump; + } + /* this changed jump.prev */ jump.prev.outer.moveJump(jump); } - /* if the jump is the jump of the appendBlock, skip it. - */ - if (jump.prev == appendBlock) - continue next_jump; - /* remove this jump if it jumps to the getNextFlowBlock(). */ - if (jump.prev.outer.getNextFlowBlock(jump.prev) == successor) { + if (jump.destination + == jump.prev.outer.getNextFlowBlock(jump.prev)) { jump.prev.removeJump(); - continue next_jump; + continue; } if (jump.prev instanceof EmptyBlock && @@ -193,12 +201,12 @@ public class FlowBlock { StructuredBlock prev = jump.prev; ConditionalBlock cb = (ConditionalBlock) prev.outer; - jode.Instruction instr = cb.getInstruction(); + Instruction instr = cb.getInstruction(); - /* cb.jump is null (see above), so cb must have a * + /* cb.jump is null (see above), so cb must have a * successor in this block, that means cb.outer is not - * null. - */ + * null. + */ /* If this is the first instruction of a while and the * condition of the while is true, use the condition @@ -214,34 +222,48 @@ public class FlowBlock { if (loopBlock.getCondition() == LoopBlock.TRUE && loopBlock.getType() != LoopBlock.DOWHILE && loopBlock.getNextFlowBlock() == successor && + /*XXX remove following after expression cleanup */ instr instanceof Expression) { prev.removeJump(); loopBlock.setCondition(((Expression)instr).negate()); + loopBlock.moveDefinitions(cb, null); + + /* Now remove the whole ConditionalBlock including + * the surrounding SequentialBlock. + */ if (cb.outer.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.jump); + /* Well can this happen??? + * + * Currently a sequential block can only + * temporarily have a jump (assigned in + * this method, see above). + * + * But in any case we know, that the + * second sub block can't have a jump, so + * it takes the jump of its parent. + */ + cb.outer.getSubBlocks()[1]. + moveJump(cb.outer.jump); } cb.outer.getSubBlocks()[1].replace (cb.outer, cb.outer.getSubBlocks()[1]); - /* cb and cb.outer are not used any more */ + /* Note that cb.outer != appendBlock because - * appendBlock contains loopBlock + * appendBlock contains loopBlock. This is + * because lastModified can't be an + * instruction inside a loop block. + * + * XXX I have to make a clear precondition for this. */ - continue next_jump; + continue; } } /* Now the same for the empty loop. In this case there is - * no sequential block. + * no sequential block, which simplifies the situation. */ - if (cb.outer instanceof LoopBlock) { + else if (cb.outer instanceof LoopBlock) { LoopBlock loopBlock = (LoopBlock) cb.outer; if (loopBlock.getCondition() == LoopBlock.TRUE && loopBlock.getType() != LoopBlock.DOWHILE && @@ -250,11 +272,49 @@ public class FlowBlock { prev.removeJump(); loopBlock.setCondition(((Expression)instr).negate()); + loopBlock.moveDefinitions(cb, null); EmptyBlock empty = new EmptyBlock(); empty.replace(cb, null); /* cb is not used any more */ - continue next_jump; + continue; + } + } else if (cb.outer instanceof SequentialBlock + && cb.outer.getSubBlocks()[1] == cb) { + + /* And a third time for do/while loops, where the jump + * is at the end of the loop. Note that all ifs are + * disjunct. + */ + + /* First find the beginning of the loop */ + StructuredBlock sb = cb.outer; + while (sb.outer instanceof SequentialBlock) { + sb = sb.outer; + } + /* sb is now the first and cb is the last + * instruction in the current block. + */ + if (sb.outer instanceof LoopBlock) { + LoopBlock loopBlock = (LoopBlock) sb.outer; + if (loopBlock.getCondition() == LoopBlock.TRUE && + loopBlock.getType() == LoopBlock.WHILE && + loopBlock.getNextFlowBlock() == successor && + instr instanceof Expression) { + + prev.removeJump(); + loopBlock.setType(LoopBlock.DOWHILE); + loopBlock.setCondition(((Expression)instr).negate()); + loopBlock.moveDefinitions(cb, null); + + /* We pretend here that cb.outer has no jump. + * (Note that cb.outer is a sequential block) + */ + cb.outer.getSubBlocks()[0].replace(cb.outer, + cb.outer); + /* cb and cb.outer are not used any more */ + continue; + } } } @@ -266,12 +326,12 @@ public class FlowBlock { cb.outer.getSubBlocks()[0] == cb && (cb.outer.getNextFlowBlock() == successor || cb.outer.jumpMayBeChanged()) && - instr instanceof jode.Expression) { + instr instanceof Expression) { SequentialBlock sequBlock = (SequentialBlock) cb.outer; IfThenElseBlock newIfBlock = - new IfThenElseBlock(((jode.Expression)instr).negate()); + new IfThenElseBlock(((Expression)instr).negate()); newIfBlock.replace(sequBlock, sequBlock.getSubBlocks()[1]); newIfBlock.setThenBlock(sequBlock.getSubBlocks()[1]); @@ -283,10 +343,12 @@ public class FlowBlock { if (newIfBlock.getNextFlowBlock() != successor && newIfBlock != appendBlock) { newIfBlock.moveJump(jump); + /* consider this jump again */ + jumps.push(jump); continue; } else { prev.removeJump(); - continue next_jump; + continue; } } } @@ -303,24 +365,41 @@ public class FlowBlock { 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())) { + && ifBlock.outer.getSubBlocks()[0] == ifBlock) { StructuredBlock elseBlock = ifBlock.outer.getSubBlocks()[1]; + + if (ifBlock.outer.jump != null) + /* If the sequential block has a jump, we + * move it to the else block. + * Note that only one of these blocks can + * have a jump. + */ + elseBlock.moveJump(ifBlock.outer.jump); - ifBlock.outer.removeJump(); - ifBlock.replace(ifBlock.outer, elseBlock); + if (elseBlock.getNextFlowBlock() == successor + || elseBlock.jumpMayBeChanged()) { + + if (appendBlock == elseBlock.outer) + appendBlock = ifBlock; - if (appendBlock == elseBlock.outer) - appendBlock = ifBlock; + ifBlock.replace(ifBlock.outer, elseBlock); + if (elseBlock.jump != null) + ifBlock.moveJump(elseBlock.jump); - ifBlock.moveJump(jump); - ifBlock.setElseBlock(elseBlock); - continue; + ifBlock.setElseBlock(elseBlock); + + if (ifBlock.getNextFlowBlock() != successor) { + ifBlock.moveJump(jump); + /* consider this jump again */ + jumps.push(jump); + } else + jump.prev.removeJump(); + + continue; + } } } @@ -339,13 +418,15 @@ public class FlowBlock { && surrounder.jumpMayBeChanged()) { surrounder.setJump(new Jump(successor)); - successors.addElement(surrounder.jump); + jumps.push(surrounder.jump); + break; } } } - continue next_jump; - } + remainingJumps.push(jump); } + while(!remainingJumps.isEmpty()) + jumps.push(remainingJumps.pop()); return appendBlock; } @@ -356,17 +437,20 @@ public class FlowBlock { void mergeSuccessors(FlowBlock succ) { /* Merge the sucessors from the successing flow block */ - Enumeration enum = succ.successors.elements(); - while (enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); - if (jump == null) - continue; - successors.addElement(jump); - if (jump.destination.predecessors.contains(succ)) { - /*XXX comment and make clearer, better etc.*/ - jump.destination.predecessors.removeElement(succ); - if (!jump.destination.predecessors.contains(this)) - jump.destination.predecessors.addElement(this); + Enumeration keys = succ.successors.keys(); + Enumeration stacks = succ.successors.elements(); + while (keys.hasMoreElements()) { + FlowBlock dest = (FlowBlock) keys.nextElement(); + Stack hisJumps = (Stack) stacks.nextElement(); + Stack myJumps = (Stack) successors.get(dest); + + dest.predecessors.removeElement(succ); + if (myJumps == null) { + dest.predecessors.addElement(this); + successors.put(dest, hisJumps); + } else { + while (!hisJumps.isEmpty()) + myJumps.push(hisJumps.pop()); } } } @@ -374,37 +458,39 @@ public class FlowBlock { /** * Resolve remaining jumps to the successor by generating break * instructions. As last resort generate a do while(false) block. - * @param successor The successing flow block * @param appendBlock the block where the successor is appended to. + * @param jumps The jumps that should be resolved. * @return the new appendBlock, it may have changed. */ - StructuredBlock resolveRemaining(FlowBlock succ, - StructuredBlock appendBlock) { + StructuredBlock resolveRemaining(StructuredBlock appendBlock, + Stack jumps) { LoopBlock doWhileFalse = null; - Enumeration enum = successors.elements(); + boolean removeAppendJump = false; next_jump: - while (enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); + while (!jumps.isEmpty()) { + Jump jump = (Jump) jumps.pop(); + StructuredBlock prevBlock = jump.prev; - if (jump == null || jump.destination != succ - || jump.prev == appendBlock) + if (prevBlock == appendBlock) { + /* handled below */ + removeAppendJump = true; continue; + } int breaklevel = 0; BreakableBlock breakToBlock = null; - for (StructuredBlock surrounder = jump.prev.outer; + for (StructuredBlock surrounder = prevBlock.outer; surrounder != null && surrounder != appendBlock.outer; surrounder = surrounder.outer) { if (surrounder instanceof BreakableBlock) { breaklevel++; - if (surrounder.getNextFlowBlock() == succ) { + if (surrounder.getNextFlowBlock() == jump.destination) { breakToBlock = (BreakableBlock) surrounder; break; } } } - StructuredBlock prevBlock = jump.prev; prevBlock.removeJump(); if (breakToBlock == null) { @@ -415,7 +501,7 @@ public class FlowBlock { if (doWhileFalse == null) { doWhileFalse = new LoopBlock(LoopBlock.DOWHILE, LoopBlock.FALSE); - doWhileFalse.setJump(new Jump(succ)); + doWhileFalse.setJump(new Jump(jump.destination)); } prevBlock.appendBlock (new BreakBlock(doWhileFalse, breaklevel > 0)); @@ -433,8 +519,7 @@ public class FlowBlock { /* Now remove the jump of the appendBlock if it points to * successor. */ - if (appendBlock.jump != null - && appendBlock.jump.destination == succ) + if (removeAppendJump) appendBlock.removeJump(); return appendBlock; @@ -447,18 +532,18 @@ public class FlowBlock { * block. * @return The variables that must be defined in this block. */ - void updateInOut (FlowBlock successor, boolean t1Transformation) { + void updateInOut (FlowBlock successor, boolean t1Transformation, + Stack jumps) { /* First get the out vectors of all jumps to successor and * calculate the intersection. */ VariableSet gens = new VariableSet(); VariableSet kills = null; - Enumeration enum = successors.elements(); + + Enumeration enum = jumps.elements(); while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); - if (jump == null || jump.destination != successor) - continue; - + gens.unionExact(jump.gen); if (kills == null) kills = jump.kill; @@ -475,14 +560,20 @@ public class FlowBlock { 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); + + /* The gen/kill sets must be updated for every jump + * in the other block */ + Enumeration stacks = successor.successors.elements(); + while (stacks.hasMoreElements()) { + enum = ((Stack) stacks.nextElement()).elements(); + while (enum.hasMoreElements()) { + + Jump jump = (Jump) enum.nextElement(); + if (jump != null) { + jump.gen.mergeGenKill(gens, jump.kill); + if (t1Transformation) + jump.kill.add(kills); + } } } in.unionExact(successor.in); @@ -495,113 +586,60 @@ public class FlowBlock { } } - - /* 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 - */ - public void checkConsistent() { if (!Decompiler.doChecks) return; -// try { - if (block.outer != null || block.flowBlock != this) { - throw new RuntimeException("Inconsistency"); - } - block.checkConsistent(); - Enumeration enum = successors.elements(); + + if (block.outer != null || block.flowBlock != this) { + throw new AssertError("Inconsistency"); + } + block.checkConsistent(); + Enumeration preds = predecessors.elements(); + while (preds.hasMoreElements()) { + FlowBlock pred = (FlowBlock)preds.nextElement(); + if (pred == null) + /* The special start marker */ + continue; + if (pred.successors.get(this) == null) + throw new AssertError("Inconsistency"); + } + + Enumeration keys = successors.keys(); + Enumeration stacks = successors.elements(); + while (keys.hasMoreElements()) { + FlowBlock dest = (FlowBlock) keys.nextElement(); + if (!dest.predecessors.contains(this)) + throw new AssertError("Inconsistency"); + + Enumeration enum = ((Stack)stacks.nextElement()).elements(); + if (!enum.hasMoreElements()) + throw new AssertError("Inconsistency"); + while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); - if (jump == null) - continue; + + if (jump.destination != dest) + throw new AssertError("Inconsistency"); if (jump.prev.flowBlock != this || jump.prev.jump != jump) - throw new RuntimeException("Inconsistency"); + throw new AssertError("Inconsistency"); - StructuredBlock prev = jump.prev; - while (prev != block) { + prev_loop: + for (StructuredBlock prev = jump.prev; prev != block; + prev = prev.outer) { if (prev.outer == null) throw new RuntimeException("Inconsistency"); StructuredBlock[] blocks = prev.outer.getSubBlocks(); int i; for (i=0; i 1)); - } - /* Now remove the jump of block if it points to this. + /* Now remove the jump of bodyBlock if it points to this. */ - if (bodyBlock.jump != null && - bodyBlock.jump.destination == this) + if (bodyBlock.jump != null + && bodyBlock.jump.destination == this) bodyBlock.removeJump(); lastModified = whileBlock; @@ -947,48 +935,45 @@ public class FlowBlock { /* First find the innermost block that contains all jumps to the * END_OF_METHOD block. */ - Enumeration enum = successors.elements(); + Stack jumps = new Stack(); + Stack allJumps = (Stack) successors.remove(END_OF_METHOD); + Enumeration enum = allJumps.elements(); StructuredBlock appendBlock = lastModified; while (enum.hasMoreElements()) { Jump jump = (Jump) enum.nextElement(); - if (jump == null || jump.destination != END_OF_METHOD) + + if (jump.prev instanceof ReturnBlock) { + /* This jump is implicit */ + jump.prev.removeJump(); continue; + } + jumps.push(jump); while (!appendBlock.contains(jump.prev)) appendBlock = appendBlock.outer; - + /* appendBlock can't be null now, because the * outermost block contains every structured block. */ } + /* Try to eliminate as many jumps as possible. */ - - while (enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); - - if (jump == null || jump.destination != END_OF_METHOD || - jump.prev == appendBlock) - - if (jump.prev instanceof ReturnBlock) - jump.prev.removeJump(); - } + appendBlock = optimizeJumps(appendBlock, jumps); - - appendBlock = optimizeJumps(END_OF_METHOD, appendBlock); - - enum = successors.elements(); next_jump: - while (enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); + while (!jumps.isEmpty()) { + Jump jump = (Jump) jumps.pop(); + + StructuredBlock prevBlock = jump.prev; - if (jump == null || jump.destination != END_OF_METHOD || - jump.prev == appendBlock) + if (prevBlock == appendBlock) + /* handled later */ continue; BreakableBlock breakToBlock = null; - for (StructuredBlock surrounder = jump.prev.outer; + for (StructuredBlock surrounder = prevBlock.outer; surrounder != null && surrounder != appendBlock.outer; surrounder = surrounder.outer) { if (surrounder instanceof BreakableBlock) { @@ -1000,16 +985,14 @@ public class FlowBlock { break; } } - StructuredBlock prevBlock = jump.prev; prevBlock.removeJump(); - - if (breakToBlock == null) { + if (breakToBlock == null) /* The successor is the dummy return instruction, so * replace the jump with a return. */ prevBlock.appendBlock(new ReturnBlock()); - } else + else prevBlock.appendBlock (new BreakBlock(breakToBlock, false)); } @@ -1050,13 +1033,10 @@ public class FlowBlock { */ FlowBlock getSuccessor(int start, int end) { /* search successor with smallest addr. */ - Enumeration enum = successors.elements(); + Enumeration keys = successors.keys(); FlowBlock succ = null; - while (enum.hasMoreElements()) { - Jump jump = (Jump) enum.nextElement(); - if (jump == null) - continue; - FlowBlock fb = jump.destination; + while (keys.hasMoreElements()) { + FlowBlock fb = (FlowBlock) keys.nextElement(); if (fb.addr < start || fb.addr >= end || fb == this) continue; if (succ == null || fb.addr < succ.addr) { @@ -1086,138 +1066,64 @@ public class FlowBlock { public boolean analyze(int start, int end) { if (Decompiler.debugAnalyze) System.err.println("analyze("+start+", "+end+")"); - try { - jode.TabbedPrintWriter writer = null; - if (Decompiler.isFlowDebugging) - writer = new jode.TabbedPrintWriter(System.err, " "); - boolean changed = false; + boolean changed = false; - if (block instanceof RawTryCatchBlock) { - /* analyze the try and catch blocks separately - * and create a new CatchBlock afterwards. - */ - changed |= analyzeCatchBlock(start, end); - } + if (block instanceof RawTryCatchBlock) { + /* analyze the try and catch blocks separately + * and create a new CatchBlock afterwards. + */ + changed |= analyzeCatchBlock(start, end); + } - while (true) { + while (true) { - if (Decompiler.isFlowDebugging) { - writer.println("before Transformation: "); - writer.tab(); - dumpSource(writer); - writer.untab(); - } + if (Decompiler.isFlowDebugging) + System.err.println("before Transformation: "+this); - /* First do some non flow transformations. */ - int i=0; - while (i < exprTrafos.length) { - if (exprTrafos[i].transform(this)) - i = 0; - else - i++; - } + /* First do some non flow transformations. */ + int i=0; + while (i < exprTrafos.length) { + if (exprTrafos[i].transform(this)) + i = 0; + else + i++; + checkConsistent(); + } - if (Decompiler.isFlowDebugging) { - writer.println("after Transformation: "); - writer.tab(); - dumpSource(writer); - writer.untab(); - } + if (Decompiler.isFlowDebugging) + System.err.println("after Transformation: "+this); - if (doT2(start, end)) { + if (doT2(start, end)) { - if (Decompiler.isFlowDebugging) { - writer.println("after T2: "); - writer.tab(); - dumpSource(writer); - writer.untab(); - } + if (Decompiler.isFlowDebugging) + System.err.println("after T2: "+this); - 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. - */ - if (addr != 0) - return true; - } - - FlowBlock succ = getSuccessor(start, end); - while (true) { - if (succ == null) { - /* the Block has no successor where t1 is applicable. - * Finish this analyzation. - */ - if (Decompiler.debugAnalyze) - System.err.println - ("No more successors applicable: " - + start + " - " + end + "; " - + addr + " - " + (addr+length)); - return changed; - } else { - if (succ.block instanceof SwitchBlock) { - /* 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.analyzeSwitch(newStart, newEnd)) - break; - - } - 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; - - if (Decompiler.isFlowDebugging) { - writer.println("after T1: "); - writer.tab(); - dumpSource(writer); - writer.untab(); - } - break; - } + 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. + */ + if (addr != 0) + return true; + } - /* 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; - } - } + FlowBlock succ = getSuccessor(start, end); + while (true) { + if (succ == null) { + /* the Block has no successor where t1 is applicable. + * Finish this analyzation. + */ + if (Decompiler.debugAnalyze) + System.err.println + ("No more successors applicable: " + + start + " - " + end + "; " + + addr + " - " + (addr+length)); + return changed; + } else { + if (succ.block instanceof SwitchBlock) { /* analyze succ, the new region is the * continuous region of * [start,end) \cap \compl [addr, addr+length) @@ -1227,250 +1133,312 @@ public class FlowBlock { ? addr+length : start; int newEnd = (succ.addr > addr) ? end : addr; - if (succ.analyze(newStart, newEnd)) + if (succ.analyzeSwitch(newStart, newEnd)) break; - } - - /* Try the next successor. + + } + 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; + + if (Decompiler.isFlowDebugging) + System.err.println("after T1: "+this); + 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. */ - succ = getSuccessor(succ.addr+1, end); + 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) { - throw new AssertError(ioex.toString()); } } - public void checkAndRemoveJSR(FlowBlock subRoutine) { - Enumeration enum = successors.elements(); + public void removeJSR(FlowBlock subRoutine) { + Enumeration enum = ((Stack)successors.remove(subRoutine)).elements(); while (enum.hasMoreElements()) { Jump jump = (Jump)enum.nextElement(); - if (jump == null || jump.destination == subRoutine) - continue; StructuredBlock prev = jump.prev; - if (prev instanceof JsrBlock) { - /* The jump is directly preceeded by a jsr. - * Everything okay. - */ - continue; - } - + prev.removeJump(); if (prev instanceof EmptyBlock && prev.outer instanceof JsrBlock) { - /* If jump is a jsr check the outer - * block instead. - */ - prev = prev.outer; - } - if ((prev instanceof EmptyBlock - || prev instanceof ReturnBlock) - && prev.outer instanceof SequentialBlock) { - SequentialBlock seq = (SequentialBlock) prev.outer; - if (seq.subBlocks[1] == prev - && (seq.subBlocks[0] instanceof JsrBlock - || seq.subBlocks[0].jump != null)) { - /* The jump is preceeded by another jump - * or jsr and last in its block, okay. - */ + if (prev.outer.getNextFlowBlock() != null) { + /* The jsr is directly before a jump, okay. */ + prev.outer.removeBlock(); continue; } - if (seq.subBlocks[0] == prev - && seq.outer instanceof SequentialBlock - && (seq.outer.getSubBlocks()[0] instanceof JsrBlock - ||seq.outer.getSubBlocks()[0].jump != null)) { - /* The jump is preceeded by another jump - * or jsr and not last in its block, okay. - */ - } - } - /* Now we have a jump with a wrong destination. - * Complain! - */ - System.err.println("non well formed try-finally block"); - } - enum = successors.elements(); - while (enum.hasMoreElements()) { - Jump jump = (Jump)enum.nextElement(); - if (jump == null || jump.destination != subRoutine) - continue; + if (prev.outer.outer instanceof SequentialBlock + && prev.outer.outer.getSubBlocks()[0] == prev.outer) { + SequentialBlock seq = (SequentialBlock) prev.outer.outer; + if (seq.subBlocks[1] instanceof JsrBlock) { + /* The jsr is followed by a jsr, okay. */ + prev.outer.removeBlock(); + continue; + } + if (seq.subBlocks[1] instanceof ReturnBlock + && !(seq.subBlocks[1] instanceof ThrowBlock)) { - StructuredBlock prev = jump.prev; - if (prev instanceof EmptyBlock - && prev.outer instanceof JsrBlock) { - StructuredBlock sb = prev.outer.getNextBlock(); - if (sb == null - || ((sb instanceof EmptyBlock - || sb instanceof ReturnBlock) - && sb.jump != null)) { + /* The jsr is followed by a return, okay. */ + ReturnBlock ret = (ReturnBlock) seq.subBlocks[1]; + prev.outer.removeBlock(); - StructuredBlock pred = null; - StructuredBlock jsrBlock = prev.outer; - if (jsrBlock.outer instanceof SequentialBlock) { - - if (jsrBlock.outer.getSubBlocks()[1] - == jsrBlock) { - pred = - jsrBlock.outer.getSubBlocks()[0]; - pred.replace(jsrBlock.outer, - jsrBlock.outer); - } else if (jsrBlock.outer.outer instanceof - SequentialBlock) { - pred = - jsrBlock.outer.outer - .getSubBlocks()[0]; - jsrBlock.outer.getSubBlocks()[1] - .replace(jsrBlock.outer, - jsrBlock.outer); + if (ret.outer != null + && ret.outer instanceof SequentialBlock) { + /* Try to eliminate the local that javac uses + * in this case. + */ + try { + ComplexExpression expr = (ComplexExpression) + ((InstructionBlock) + ret.outer.getSubBlocks()[0]).instr; + LocalStoreOperator store = + (LocalStoreOperator) expr.getOperator(); + if (store.matches((LocalLoadOperator) + ret.getInstruction())) { + ret.setInstruction(expr. + getSubExpressions()[0]); + ret.replace(ret.outer, null); + ret.used.removeElement + (store.getLocalInfo()); + } + } catch(ClassCastException ex) { + /* didn't succeed */ + } } + continue; } - if (pred != null) { - if (pred.jump == null) - pred.moveJump(jsrBlock.jump); - else - jsrBlock.removeJump(); - } else { - EmptyBlock eb = new EmptyBlock(); - eb.moveJump(jsrBlock.jump); - eb.replace(jsrBlock, prev); - } - prev.removeJump(); } } + /* Now we have a dangling JSR at the wrong place. + * We don't do anything, so that JSR will show up in + * the output. + */ } } - - public void checkAndRemoveMonitorExit(LocalInfo local, int end) { - FlowBlock subRoutine = null; - Enumeration enum = successors.elements(); - while (enum.hasMoreElements()) { - Jump jump = (Jump)enum.nextElement(); - if (jump == null || jump.destination == subRoutine) + + public void checkAndRemoveJSR(FlowBlock subRoutine) { + Enumeration keys = successors.keys(); + Enumeration stacks = successors.elements(); + while (keys.hasMoreElements()) { + Stack jumps = (Stack) stacks.nextElement(); + if (keys.nextElement() == subRoutine) continue; - StructuredBlock prev = jump.prev; - if (prev instanceof EmptyBlock - && prev.outer instanceof JsrBlock - && subRoutine == null) { - - subRoutine = jump.destination; - subRoutine.analyzeSubRoutine(addr+length, end); + + Enumeration enum = jumps.elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump)enum.nextElement(); + + StructuredBlock prev = jump.prev; + if (prev instanceof ThrowBlock) { + /* The jump is a throw. We have a catch-all block + * that will do the finally. + */ + continue; + } + if (prev instanceof JsrBlock) { + /* The jump is directly preceeded by a jsr. + * Everything okay. + */ + continue; + } - if (subRoutine.block instanceof InstructionBlock) { - Instruction instr = - ((InstructionBlock)subRoutine.block).getInstruction(); - if (instr instanceof ComplexExpression - && ((ComplexExpression)instr) - .getOperator() instanceof MonitorExitOperator - && ((ComplexExpression)instr) - .getSubExpressions()[0] instanceof LocalLoadOperator - && (((LocalLoadOperator) ((ComplexExpression)instr) - .getSubExpressions()[0]).getLocalInfo().getSlot() - == local.getSlot())) { - - updateInOut(subRoutine, true); - length += subRoutine.length; + if (prev instanceof EmptyBlock + && prev.outer instanceof JsrBlock) { + /* If jump is a jsr check the outer + * block instead. + */ + prev = prev.outer; + } + if ((prev instanceof ReturnBlock + || prev instanceof JsrBlock) + && prev.outer instanceof SequentialBlock) { + SequentialBlock seq = (SequentialBlock) prev.outer; + if (seq.subBlocks[1] == prev + && (seq.subBlocks[0] instanceof JsrBlock)) { + /* The jump is preceeded by another jsr, okay. + */ continue; } - } - } - if (prev instanceof JsrBlock) { - /* The jump is directly preceeded by a jsr. - */ - continue; - } - if (prev instanceof EmptyBlock - && prev.outer instanceof JsrBlock) { - /* If jump is a jsr check the outer - * block instead. - */ - prev = prev.outer; - } - - if ((prev instanceof EmptyBlock - || prev instanceof ReturnBlock) - && prev.outer instanceof SequentialBlock) { - SequentialBlock seq = (SequentialBlock) prev.outer; - StructuredBlock pred = null; - if (seq.subBlocks[1] == prev) - pred = seq.subBlocks[0]; - else if (seq.outer instanceof SequentialBlock) - pred = seq.outer.getSubBlocks()[0]; - - if (pred != null) { - if (pred instanceof JsrBlock || pred.jump != null) - /* The jump is preceeded by another jump - * or jsr and last in its block, okay. + if (seq.subBlocks[0] == prev + && seq.outer instanceof SequentialBlock + && (seq.outer.getSubBlocks()[0] instanceof JsrBlock)) { + /* Again the jump is preceeded by another jsr, okay. */ continue; - - if (pred instanceof InstructionBlock) { - Instruction instr = - ((InstructionBlock)pred).getInstruction(); - if (instr instanceof ComplexExpression - && ((ComplexExpression)instr) - .getOperator() instanceof MonitorExitOperator - && ((ComplexExpression)instr) - .getSubExpressions()[0] - instanceof LocalLoadOperator - && (((LocalLoadOperator) - ((ComplexExpression)instr) - .getSubExpressions()[0]).getLocalInfo() - .getSlot() - == local.getSlot())) - continue; } } - /* Now we have a jump with a wrong destination. * Complain! */ - System.err.println("non well formed synchronized block"); - } + System.err.println("non well formed try-finally block"); + } } - enum = successors.elements(); - while (enum.hasMoreElements()) { - Jump jump = (Jump)enum.nextElement(); - if (jump == null || - jump.destination != subRoutine) - continue; + removeJSR(subRoutine); + } - StructuredBlock prev = jump.prev; - if (prev instanceof EmptyBlock - && prev.outer instanceof JsrBlock) { - StructuredBlock sb = prev.outer.getNextBlock(); - if (sb == null - || ((sb instanceof EmptyBlock - || sb instanceof ReturnBlock) - && sb.jump != null)) { + public boolean isMonitorExit(Instruction instr, LocalInfo local) { + if (instr instanceof ComplexExpression) { + ComplexExpression expr = (ComplexExpression)instr; + if (expr.getOperator() instanceof MonitorExitOperator + && expr.getSubExpressions()[0] instanceof LocalLoadOperator + && (((LocalLoadOperator) expr.getSubExpressions()[0]) + .getLocalInfo().getSlot() == local.getSlot())) { + return true; + } + } + return false; + } + + public void checkAndRemoveMonitorExit(LocalInfo local, int end) { + FlowBlock subRoutine = null; + Enumeration stacks = successors.elements(); + dest_loop: + while (stacks.hasMoreElements()) { + Enumeration enum = ((Stack) stacks.nextElement()).elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump)enum.nextElement(); + + StructuredBlock prev = jump.prev; + if (prev instanceof EmptyBlock + && prev.outer instanceof JsrBlock + && subRoutine == null) { - StructuredBlock pred = null; - StructuredBlock jsrBlock = prev.outer; - if (jsrBlock.outer instanceof SequentialBlock) { - - if (jsrBlock.outer.getSubBlocks()[1] == jsrBlock) { - pred = jsrBlock.outer.getSubBlocks()[0]; - pred.replace(jsrBlock.outer, jsrBlock.outer); - } else if (jsrBlock.outer.outer instanceof - SequentialBlock) { - pred = jsrBlock.outer.outer.getSubBlocks()[0]; - jsrBlock.outer.getSubBlocks()[1] - .replace(jsrBlock.outer, jsrBlock.outer); + subRoutine = jump.destination; + subRoutine.analyzeSubRoutine(addr+length, end); + + if (subRoutine.block instanceof InstructionBlock) { + Instruction instr = + ((InstructionBlock)subRoutine.block) + .getInstruction(); + if (isMonitorExit(instr, local)) { + + updateInOut(subRoutine, true, + (Stack)successors.get(subRoutine)); + length += subRoutine.length; + continue dest_loop; } } + } + + if (prev instanceof ThrowBlock) { + /* The jump is a throw. We have a catch all block + * that will do the monitorexit. + */ + continue; + } + if (prev instanceof JsrBlock) { + /* The jump is directly preceeded by a jsr. + */ + continue; + } + if (prev instanceof EmptyBlock + && prev.outer instanceof JsrBlock) { + /* If jump is a jsr check the outer + * block instead. + */ + prev = prev.outer; + } + + if ((prev instanceof JsrBlock + || prev instanceof ReturnBlock) + && prev.outer instanceof SequentialBlock) { + SequentialBlock seq = (SequentialBlock) prev.outer; + StructuredBlock pred = null; + if (seq.subBlocks[1] == prev) + pred = seq.subBlocks[0]; + else if (seq.outer instanceof SequentialBlock) + pred = seq.outer.getSubBlocks()[0]; + if (pred != null) { - if (pred.jump == null) - pred.moveJump(jsrBlock.jump); - else - jsrBlock.removeJump(); - } else { - EmptyBlock eb = new EmptyBlock(); - eb.moveJump(jsrBlock.jump); - eb.replace(jsrBlock, prev); + if (pred instanceof JsrBlock || pred.jump != null) + /* The jump is preceeded by another jump + * or jsr and last in its block, okay. + */ + continue; + + if (pred instanceof InstructionBlock) { + Instruction instr = + ((InstructionBlock)pred).getInstruction(); + if (instr instanceof ComplexExpression + && ((ComplexExpression)instr) + .getOperator() instanceof MonitorExitOperator + && ((ComplexExpression)instr) + .getSubExpressions()[0] + instanceof LocalLoadOperator + && (((LocalLoadOperator) + ((ComplexExpression)instr) + .getSubExpressions()[0]).getLocalInfo() + .getSlot() == local.getSlot())) + continue; + } } - prev.removeJump(); - } - } + } + + if (prev instanceof InstructionBlock + && isMonitorExit(((InstructionBlock)prev).instr, local)) { + /* This is probably the last expression in the + * synchronized block, and has the right monitor exit + * attached. Remove this block. + */ + prev.removeBlock(); + continue; + } + + /* Now we have a jump that is not preceded by a monitorexit. + * Complain! + */ + System.err.println("non well formed synchronized block"); + } } + + if (subRoutine != null) + removeJSR(subRoutine); } @@ -1486,23 +1454,40 @@ public class FlowBlock { RawTryCatchBlock rawBlock = (RawTryCatchBlock) block; FlowBlock tryFlow = rawBlock.tryBlock.jump.destination; FlowBlock catchFlow = rawBlock.catchBlock.jump.destination; + + /* This are the only jumps in this block. Make sure they + * are disjunct, the successing code relies on that! + */ + if (tryFlow == catchFlow) + throw new AssertError("try == catch"); + boolean changed = false; tryFlow.analyze(addr, catchFlow.addr); catchFlow.analyze(catchFlow.addr, end); - updateInOut(tryFlow, true); + updateInOut(tryFlow, true, (Stack) successors.remove(tryFlow)); rawBlock.tryBlock.removeJump(); tryFlow.getBlock().replace(rawBlock.tryBlock, null); mergeSuccessors(tryFlow); length += tryFlow.length; - - updateInOut(catchFlow, true); + + updateInOut(catchFlow, true, (Stack) successors.remove(catchFlow)); rawBlock.catchBlock.removeJump(); catchFlow.block.replace(rawBlock.catchBlock, null); mergeSuccessors(catchFlow); length += catchFlow.length; - + if (rawBlock.type != null) { + /* simple try catch block: + * + * try-header + * |- first instruction + * | ... + * | last instruction + * |- optional jump (last+1) + * | ... + * `- catch block + */ CatchBlock newBlock = new CatchBlock(rawBlock.type); newBlock.replace(rawBlock, rawBlock); @@ -1527,16 +1512,40 @@ public class FlowBlock { instanceof LocalLoadOperator && catchBlock.subBlocks[1] instanceof ThrowBlock && ((ThrowBlock)catchBlock.subBlocks[1]).instr - instanceof jode.NopOperator) { + instanceof NopOperator) { - /* This is a synchronized block */ - ((ThrowBlock)catchBlock.subBlocks[1]).removeJump(); + /* This is a synchronized block: + * + * local_x = monitor object; // later + * monitorenter local_x // later + * 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 = stack | + * monitorexit local_x | + * throw local_n | + * monexit: <-----------------------------------------------' + * astore_n + * monitorexit local_x + * return_n + */ + + /* First remove the jump after the throw */ + removeSuccessor(catchBlock.subBlocks[1].jump); + catchBlock.subBlocks[1].removeJump(); + ComplexExpression monexit = (ComplexExpression) ((InstructionBlock) catchBlock.subBlocks[0]).instr; LocalInfo local = ((LocalLoadOperator)monexit.getSubExpressions()[0]) .getLocalInfo(); checkAndRemoveMonitorExit(local, end); + SynchronizedBlock syncBlock = new SynchronizedBlock(local); syncBlock.replace(rawBlock, rawBlock); syncBlock.moveJump(rawBlock.jump); @@ -1559,7 +1568,24 @@ public class FlowBlock { .getSubBlocks()[1]).instr)) { /* Wow that was complicated :-) * But now we know that the catch block looks - * exactly like an try finally block. + * exactly like an try finally block: + * + * try-header any + * | + * |- first instruction + * | ... + * | every jump to outside is preceded by jsr finally + * | ... + * | jsr finally -----------------, + * |- jump after finally | + * `- catch any | + * local_n = stack v + * jsr finally ---------------->| + * throw local_n; | + * finally: <-----------------------' + * astore_n + * ... + * return_n */ FlowBlock subRoutine = ((JsrBlock)catchBlock.subBlocks[1].getSubBlocks()[0]) @@ -1569,14 +1595,20 @@ public class FlowBlock { * so that we can forget about them. * This are the throw and the jsr. */ + removeSuccessor(catchBlock.subBlocks[1] + .getSubBlocks()[1].jump); + removeSuccessor(catchBlock.subBlocks[1] + .getSubBlocks()[0].getSubBlocks()[0].jump); catchBlock.subBlocks[1].getSubBlocks()[1].removeJump(); catchBlock.subBlocks[1] .getSubBlocks()[0].getSubBlocks()[0].removeJump(); subRoutine.analyzeSubRoutine(addr+length, end); - updateInOut(subRoutine, true); - + updateInOut(subRoutine, true, + (Stack)successors.get(subRoutine)); + if (subRoutine.successors.size() != 0) + throw new AssertError("Jump inside subroutine"); length += subRoutine.length; checkAndRemoveJSR(subRoutine); @@ -1591,12 +1623,27 @@ public class FlowBlock { } else if (catchFlow.block instanceof InstructionBlock && ((InstructionBlock) catchFlow.block).instr instanceof PopOperator - && catchFlow.block.jump != null) { + && successors.size() == 1) { /* This is a special try/finally-block, where * the finally block ends with a break, return or * similar. */ + FlowBlock succ = catchFlow.block.jump.destination; + Stack jumps = (Stack) successors.get(succ); + Stack newJumps = new Stack(); + newJumps.push(catchFlow.block.jump); + successors.put(succ, newJumps); + jumps.removeElement(catchFlow.block.jump); + + if (rawBlock.tryBlock.jump == null) { + Jump jump = new Jump(succ); + rawBlock.tryBlock.setJump(jump); + jumps.push(jump); + } + + optimizeJumps(rawBlock.tryBlock, jumps); + resolveRemaining(rawBlock.tryBlock, jumps); CatchFinallyBlock newBlock = new CatchFinallyBlock(); newBlock.replace(rawBlock, rawBlock); @@ -1605,8 +1652,6 @@ public class FlowBlock { newBlock.moveJump(rawBlock.jump); lastModified = newBlock.finallyBlock; lastModified.moveJump(catchFlow.block.jump); - - Enumeration enum = successors.elements(); changed = true; } checkConsistent(); @@ -1651,85 +1696,91 @@ public class FlowBlock { * @param end the end of the address range. */ public boolean analyzeSwitch(int start, int end) { - SwitchBlock switchBlock = (SwitchBlock) block; - boolean changed = false; - StructuredBlock lastBlock = null; - lastModified = block; - /* XXX - move to switchBlock??? */ - for (int i=0; i < switchBlock.caseBlocks.length; i++) { - if (switchBlock.caseBlocks[i].subBlock != null - && switchBlock.caseBlocks[i].subBlock.jump != null) { - FlowBlock next = switchBlock.caseBlocks[i]. - subBlock.jump.destination; - if (next.addr >= end) + SwitchBlock switchBlock = (SwitchBlock) block; + boolean changed = false; + StructuredBlock lastBlock = null; + lastModified = block; + /* XXX - move to switchBlock??? */ + for (int i=0; i < switchBlock.caseBlocks.length; i++) { + if (switchBlock.caseBlocks[i].subBlock != null + && switchBlock.caseBlocks[i].subBlock.jump != null) { + FlowBlock next = switchBlock.caseBlocks[i]. + subBlock.jump.destination; + if (next.addr >= end) + return changed; + else if (next.addr >= start) { + + /* First analyze the next block. It may + * return early after a T2 trafo so call it + * until nothing more is possible. + */ + while (next.analyze(addr + length, end)) + changed = changed || true; + + if (next.addr != addr + length) return changed; - else if (next.addr >= start) { - - /* First analyze the next block. It may - * return early after a T2 trafo so call it - * until nothing more is possible. - */ - while (next.analyze(addr + length, end)) - changed = changed || true; - - if (next.addr != addr + length) + + /* Check if next has only the previous case + * and this case as predecessor. Otherwise + * break the analysis. + */ + if (next.predecessors.size() != 1 + || next.predecessors.elementAt(0) != this) return changed; + + boolean lastContains = false; + Stack jumps = new Stack(); + + Enumeration enum = + ((Stack) successors.get(next)).elements(); + while (enum.hasMoreElements()) { + Jump jump = (Jump) enum.nextElement(); + if (jump == switchBlock.caseBlocks[i].subBlock.jump) + continue; - /* Check if next has only the previous case - * and this case as predecessor. Otherwise - * break the analysis. - */ - if (next.predecessors.size() != 1 - || next.predecessors.elementAt(0) != this) + jumps.push(jump); + if (lastBlock == null + || !lastBlock.contains(jump.prev)) + return changed; - - boolean lastContains = false; - for (int j=0; jnot ignoring the jump diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index f46d3d9..ac58959 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -19,6 +19,7 @@ package jode.flow; import jode.TabbedPrintWriter; +import jode.AssertError; import jode.LocalInfo; /** @@ -181,12 +182,11 @@ public abstract class StructuredBlock { } /** - * Removes the jump. This does also update the successors vector - * of the flow block. */ + * Removes the jump. This does not update the successors vector + * of the flow block, you have to do it yourself. */ public void removeJump() { if (jump != null) { jump.prev = null; - flowBlock.removeSuccessor(jump); jump = null; } } @@ -262,7 +262,8 @@ public abstract class StructuredBlock { * @param jump The jump that should be moved, may be null. */ public void moveJump(Jump jump) { - removeJump(); + if (this.jump != null) + throw new AssertError("overriding with moveJump()"); this.jump = jump; if (jump != null) { jump.prev.jump = null; @@ -282,6 +283,31 @@ public abstract class StructuredBlock { return sequBlock; } + /** + * Removes this block, or replaces it with an EmptyBlock. + */ + public void removeBlock() { + + if (outer instanceof SequentialBlock) { + + if (outer.getSubBlocks()[1] == this) { + if (jump != null) + outer.getSubBlocks()[0].moveJump(jump); + outer.getSubBlocks()[0].replace(outer, null); + return; + } else if (outer.outer instanceof SequentialBlock) { + if (jump != null) + outer.outer.getSubBlocks()[0].moveJump(jump); + outer.getSubBlocks()[1].replace(outer, null); + return; + } + } + + EmptyBlock eb = new EmptyBlock(); + eb.moveJump(jump); + eb.replace(this, null); + } + /** * 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. @@ -340,16 +366,14 @@ public abstract class StructuredBlock { for (int i=0; i