diff --git a/jode/jode/flow/CatchBlock.java b/jode/jode/flow/CatchBlock.java index 69cbc7b..716ca9a 100644 --- a/jode/jode/flow/CatchBlock.java +++ b/jode/jode/flow/CatchBlock.java @@ -26,6 +26,15 @@ import jode.expr.LocalStoreOperator; import jode.expr.StoreInstruction; import jode.util.SimpleSet; +///#ifdef JDK12 +///import java.util.Collections; +///import java.util.Set; +///#else +import jode.util.Collections; +import jode.util.Set; +///#endif + + /** * * @author Jochen Hoenicke @@ -121,11 +130,10 @@ public class CatchBlock extends StructuredBlock { super.removePush(); } - public SimpleSet getDeclarables() { - SimpleSet used = new SimpleSet(); + public Set getDeclarables() { if (exceptionLocal != null) - used.add(exceptionLocal); - return used; + return Collections.singleton(exceptionLocal); + return Collections.EMPTY_SET; } /** @@ -134,7 +142,7 @@ public class CatchBlock extends StructuredBlock { * is marked as used, but not done. * @param done The set of the already declare variables. */ - public void makeDeclaration(SimpleSet done) { + public void makeDeclaration(Set done) { super.makeDeclaration(done); /* Normally we have to declare our exceptionLocal. This * is automatically done in dumpSource. diff --git a/jode/jode/flow/CombineIfGotoExpressions.java b/jode/jode/flow/CombineIfGotoExpressions.java index 4e90194..e3090ca 100644 --- a/jode/jode/flow/CombineIfGotoExpressions.java +++ b/jode/jode/flow/CombineIfGotoExpressions.java @@ -67,13 +67,9 @@ public class CombineIfGotoExpressions { if (prevJump.destination == cb.jump.destination) { operator = BinaryOperator.LOG_AND_OP; firstCond = cbprev.getInstruction().negate(); - cb.jump.gen.unionExact(prevJump.gen); - cb.jump.kill.intersect(prevJump.kill); } else if (prevJump.destination == cb.trueBlock.jump.destination) { operator = BinaryOperator.LOG_OR_OP; firstCond = cbprev.getInstruction(); - cb.trueBlock.jump.gen.unionExact(prevJump.gen); - cb.trueBlock.jump.kill.intersect(prevJump.kill); } else return false; diff --git a/jode/jode/flow/FlowBlock.java b/jode/jode/flow/FlowBlock.java index e932ea5..57a36e1 100644 --- a/jode/jode/flow/FlowBlock.java +++ b/jode/jode/flow/FlowBlock.java @@ -34,10 +34,14 @@ import jode.util.SimpleSet; ///import java.util.Iterator; ///import java.util.Set; ///import java.util.SimpleSet; +///import java.util.ArrayList; +///import java.util.List; ///#else import jode.util.Map; import jode.util.Iterator; import jode.util.Set; +import jode.util.ArrayList; +import jode.util.List; import jode.util.SimpleSet; ///#endif @@ -80,7 +84,7 @@ public class FlowBlock { * path from the start of the flow block to the instruction that * uses that variable, on which it is never assigned */ - VariableSet in = new VariableSet(); + private SlotSet in = new SlotSet(); /** * The gen locals. This are the locals, to which are written * somewhere in this flow block. This is only used for try @@ -92,12 +96,12 @@ public class FlowBlock { * The starting address of this flow block. This is mainly used * to produce the source code in code order. */ - int addr; + private int addr; /** * The length of the structured block, only needed at the beginning. */ - int length; + private int length; /** * The outermost structructed block in this flow block. @@ -117,7 +121,7 @@ public class FlowBlock { * the elements is the first jump to that flow block. The other * jumps are accessible via the jump.next field. */ - Map successors = new SimpleMap(); + private Map successors = new SimpleMap(); /** * This is a vector of flow blocks, which reference this block. @@ -127,7 +131,7 @@ public class FlowBlock { * If this vectors contains the null element, this is the first * flow block in a method. */ - Vector predecessors = new Vector(); + List predecessors = new ArrayList(); /** * This is a pointer to the next flow block in byte code order. @@ -148,6 +152,33 @@ public class FlowBlock { */ VariableStack stackMap; + static class SuccessorInfo { + /** + * The kill locals. This are the slots, which must be + * overwritten in this block on every path to the successor. + * That means, that all paths from the start of the current + * flow block to the successor contain (unconditional) + * assignments to this slot. + */ + SlotSet kill; + + /** + * The gen locals. This are the locals, which can be + * overwritten in this block on a path to the successor. That + * means, that there exists a path form the start of the + * current flow block to the successor that contains a + * assignments to this local, and that is not overwritten + * afterwards. + */ + VariableSet gen; + + /** + * The linked list of jumps. + */ + Jump jumps; + } + + /** * The default constructor. Creates a new empty flowblock. */ @@ -577,25 +608,28 @@ public class FlowBlock { * @param succ the other flow block */ void mergeSuccessors(FlowBlock succ) { - /* Merge the sucessors from the successing flow block + /* Merge the successors from the successing flow block */ Iterator iter = succ.successors.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); FlowBlock dest = (FlowBlock) entry.getKey(); - Jump hisJumps = (Jump) entry.getValue(); - Jump myJumps = (Jump) successors.get(dest); + SuccessorInfo hisInfo = (SuccessorInfo) entry.getValue(); + SuccessorInfo myInfo = (SuccessorInfo) successors.get(dest); if (dest != END_OF_METHOD) - dest.predecessors.removeElement(succ); - if (myJumps == null) { + dest.predecessors.remove(succ); + if (myInfo == null) { if (dest != END_OF_METHOD) - dest.predecessors.addElement(this); - successors.put(dest, hisJumps); + dest.predecessors.add(this); + successors.put(dest, hisInfo); } else { - while (myJumps.next != null) + myInfo.gen.addAll(hisInfo.gen); + myInfo.kill.retainAll(hisInfo.kill); + Jump myJumps = myInfo.jumps; + while (myJumps.next != null) myJumps = myJumps.next; - myJumps.next = hisJumps; + myJumps.next = hisInfo.jumps; } } } @@ -632,45 +666,36 @@ public class FlowBlock { * @param jumps The list of jumps to successor in this block. * @return The variables that must be defined in this block. */ - void updateInOut (FlowBlock successor, Jump jumps) { - /* First get the out vectors of all jumps to successor and + void updateInOut(FlowBlock successor, SuccessorInfo succInfo) { + /* First get the gen/kill sets of all jumps to successor and * calculate the intersection. - */ - VariableSet gens = new VariableSet(); - VariableSet kills = null; + */ + SlotSet kills = succInfo.kill; + VariableSet gens = succInfo.gen; - for (;jumps != null; jumps = jumps.next) { - gens.unionExact(jumps.gen); - if (kills == null) - kills = jumps.kill; - else - kills = kills.intersect(jumps.kill); - } - /* Merge the locals used in successing block with those written - * by this blocks + * by this blocks. */ successor.in.merge(gens); - /* Now update in and out set of successing block */ - - if (successor != this) - successor.in.subtract(kills); + /* The ins of the successor that are not killed + * (i.e. unconditionally overwritten) by this block are new + * ins for this block. + */ + SlotSet newIn = (SlotSet) successor.in.clone(); + newIn.removeAll(kills); /* The gen/kill sets must be updated for every jump * in the other block */ - Iterator succSuccs = successor.successors.values().iterator(); - while (succSuccs.hasNext()) { - Jump succJumps = (Jump) succSuccs.next(); - for (; succJumps != null; succJumps = succJumps.next) { - - succJumps.gen.mergeGenKill(gens, succJumps.kill); - if (successor != this) - succJumps.kill.add(kills); - } + Iterator i = successor.successors.values().iterator(); + while (i.hasNext()) { + SuccessorInfo succSuccInfo = (SuccessorInfo) i.next(); + succSuccInfo.gen.mergeGenKill(gens, succSuccInfo.kill); + if (successor != this) + succSuccInfo.kill.addAll(kills); } - this.in.unionExact(successor.in); - this.gen.unionExact(successor.gen); + this.in.addAll(newIn); + this.gen.addAll(successor.gen); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { GlobalOptions.err.println("UpdateInOut: gens : "+gens); @@ -679,6 +704,53 @@ public class FlowBlock { GlobalOptions.err.println(" in : "+in); } } + + /** + * Updates the in/out-Vectors of the structured block of the + * successing flow block for a try catch block. The main difference + * to updateInOut in FlowBlock is, that this function works, as if + * every instruction would have a jump. This is because every + * instruction can throw an exception and thus enter the catch block.
+ * + * For example this code prints 0: + *
+     *   int a=3;
+     *   try {
+     *     a = 5 / (a=0);
+     *   } catch (DivideByZeroException ex) {
+     *     System.out.println(a);
+     *   }
+     * 
+ * + * @param successor The flow block which is unified with this flow + * block. + * @return The variables that must be defined in this block. + */ + public void updateInOutCatch (FlowBlock catchFlow) { + VariableSet gens = ((TryBlock)block).gen; + + /* Merge the locals used in the catch block with those written + * by the try block + */ + catchFlow.in.merge(gens); + + /* The gen/kill sets must be updated for every jump + * in the other block */ + Iterator i = catchFlow.successors.values().iterator(); + while (i.hasNext()) { + SuccessorInfo succSuccInfo = (SuccessorInfo) i.next(); + succSuccInfo.gen.mergeGenKill(gens, succSuccInfo.kill); + } + in.addAll(catchFlow.in); + gen.addAll(catchFlow.gen); + + if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { + GlobalOptions.err.println("UpdateInOutCatch: gens : "+gens); + GlobalOptions.err.println(" s.in : "+catchFlow.in); + GlobalOptions.err.println(" in : "+in); + } + } + /** * Checks if the FlowBlock and its StructuredBlocks are @@ -699,9 +771,8 @@ public class FlowBlock { } block.checkConsistent(); - Enumeration preds = predecessors.elements(); - while (preds.hasMoreElements()) { - FlowBlock pred = (FlowBlock)preds.nextElement(); + for (Iterator i = predecessors.iterator(); i.hasNext(); ) { + FlowBlock pred = (FlowBlock)i.next(); if (pred == null) /* The special start marker */ continue; @@ -723,7 +794,7 @@ public class FlowBlock { if (dest.predecessors.contains(this) == (dest == END_OF_METHOD)) throw new AssertError("Inconsistency"); - Jump jumps = (Jump)entry.getValue(); + Jump jumps = ((SuccessorInfo) entry.getValue()).jumps; if (jumps == null) throw new AssertError("Inconsistency"); @@ -774,20 +845,28 @@ public class FlowBlock { GlobalOptions.err.println("merging sequentialBlock: "+this); GlobalOptions.err.println("and: "+succ); } - VariableSet succIn = new VariableSet(); - succ.fillInGenSet(succIn, this.gen); - - succIn.merge(lastModified.jump.gen); - succIn.subtract(lastModified.jump.kill); + SlotSet succIn = new SlotSet(); + SlotSet succKill = new SlotSet(); + VariableSet succGen = new VariableSet(); + succ.fillInGenSet(succIn, succKill); + succGen.addAll(succKill); + + SuccessorInfo succInfo = (SuccessorInfo) successors.get(NEXT_BY_ADDR); + succIn.merge(succInfo.gen); + succIn.removeAll(succInfo.kill); - succ.jump.gen.mergeGenKill(lastModified.jump.gen, succ.jump.kill); - succ.jump.kill.add(lastModified.jump.kill); - this.in.unionExact(succIn); + succGen.mergeGenKill(succInfo.gen, succKill); + succKill.addAll(succInfo.kill); + this.in.addAll(succIn); + this.gen.addAll(succKill); removeSuccessor(lastModified.jump); lastModified.removeJump(); lastModified = lastModified.appendBlock(succ); succ.fillSuccessors(); + succInfo = (SuccessorInfo) successors.get(NEXT_BY_ADDR); + succInfo.gen = succGen; + succInfo.kill = succKill; this.length += length; checkConsistent(); doTransformations(); @@ -798,21 +877,31 @@ public class FlowBlock { * nextByAddr should be null, when calling this. * @param flow The flowBlock to append */ - public void setNextByAddr(FlowBlock flow) { - Jump jumps = (Jump) successors.remove(NEXT_BY_ADDR); - Jump flowJumps = (Jump) successors.get(flow); - if (jumps != null) { - NEXT_BY_ADDR.predecessors.removeElement(this); + public void setNextByAddr(FlowBlock flow) + { + /* nextByAddr can be set, when reordering block in transform exc */ +// if (nextByAddr != null) +// throw new IllegalStateException("nextByAddr already set"); + if (flow == END_OF_METHOD || flow == NEXT_BY_ADDR) + throw new IllegalArgumentException + ("nextByAddr mustn't be special"); + SuccessorInfo info = (SuccessorInfo) successors.remove(NEXT_BY_ADDR); + SuccessorInfo flowInfo = (SuccessorInfo) successors.get(flow); + if (info != null) { + NEXT_BY_ADDR.predecessors.remove(this); + Jump jumps = info.jumps; jumps.destination = flow; while (jumps.next != null) { jumps = jumps.next; jumps.destination = flow; } - successors.put(flow, jumps); - if (flowJumps != null) - jumps.next = flowJumps; - else if (flow != END_OF_METHOD) - flow.predecessors.addElement(this); + successors.put(flow, info); + if (flowInfo != null) { + info.gen.addAll(flowInfo.gen); + info.kill.retainAll(flowInfo.kill); + jumps.next = flowInfo.jumps; + } else + flow.predecessors.add(this); } checkConsistent(); @@ -830,22 +919,22 @@ public class FlowBlock { /* check if this successor has only this block as predecessor. * if the predecessor is not unique, return false. */ if (succ.predecessors.size() != 1 || - succ.predecessors.elementAt(0) != this) + succ.predecessors.get(0) != this) return false; checkConsistent(); succ.checkConsistent(); - Jump jumps = (Jump) successors.remove(succ); + SuccessorInfo succInfo = (SuccessorInfo) successors.remove(succ); /* Update the in/out-Vectors now */ - updateInOut(succ, jumps); + updateInOut(succ, succInfo); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) GlobalOptions.err.println("before Resolve: "+this); /* Try to eliminate as many jumps as possible. */ - jumps = resolveSomeJumps(jumps, succ); + Jump jumps = resolveSomeJumps(succInfo.jumps, succ); if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) GlobalOptions.err.println("before Remaining: "+this); resolveRemaining(jumps); @@ -868,44 +957,81 @@ public class FlowBlock { return true; } -// /** -// * Find the exit condition of a for/while block. The loop block -// * mustn't have an exit condition yet. -// */ -// public void mergeCondition() { -// /* If the first instruction of a while is a conditional -// * block, which jumps to the next address use the condition -// * as while condition. -// */ -// LoopBlock loopBlock = (LoopBlock) lastModified; -// int loopType = loopBlock.getType(); - -// ConditionalBlock cb = null; -// if (loopBlock.bodyBlock instanceof ConditionalBlock) -// cb = (ConditionalBlock) loopBlock.bodyBlock; -// else if (loopBlock.bodyBlock instanceof SequentialBlock -// && loopBlock.bodyBlock.getSubBlocks()[0] -// instanceof ConditionalBlock) -// cb = (ConditionalBlock) loopBlock.bodyBlock.getSubBlocks()[0]; -// else if (loopBlock.bodyBlock instanceof SequentialBlock -// && loopType == LoopBlock.WHILE) { -// loopType = LoopBlock.DOWHILE; -// SequentialBlock sequBlock = (SequentialBlock) loopBlock.bodyBlock; -// while (sequBlock.subBlocks[1] instanceof SequentialBlock) -// sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; -// if (sequBlock.subBlocks[1] instanceof ConditionalBlock) -// cb = (ConditionalBlock) sequBlock.subBlocks[1]; -// } - -// if (cb != null -// && cb.trueBlock.jump.destination.addr == getNextAddr()) { -// loopBlock.moveJump(cb.trueBlock.jump); -// loopBlock.setCondition(cb.getInstruction().negate()); -// loopBlock.setType(loopType); -// loopBlock.moveDefinitions(cb, null); -// cb.removeBlock(); -// } -// } + /** + * Do a T2 transformation with the end_of_method block. + */ + public void mergeEndBlock() { + checkConsistent(); + + SuccessorInfo endInfo + = (SuccessorInfo) successors.remove(END_OF_METHOD); + if (endInfo == null) + return; + + Jump allJumps = endInfo.jumps; + /* First remove all implicit jumps to the END_OF_METHOD block. + */ + Jump jumps = null; + for (; allJumps != null; ) { + Jump jump = allJumps; + allJumps = allJumps.next; + + if (jump.prev instanceof ReturnBlock) { + /* This jump is implicit */ + jump.prev.removeJump(); + continue; + } + jump.next = jumps; + jumps = jump; + } + + /* Try to eliminate as many jumps as possible. + */ + jumps = resolveSomeJumps(jumps, END_OF_METHOD); + + next_jump: + for (; jumps != null; jumps = jumps.next) { + + StructuredBlock prevBlock = jumps.prev; + + if (lastModified == prevBlock) + /* handled later */ + continue; + + BreakableBlock breakToBlock = null; + for (StructuredBlock surrounder = prevBlock.outer; + surrounder != null; surrounder = surrounder.outer) { + if (surrounder instanceof BreakableBlock) { + if (surrounder.getNextFlowBlock() == END_OF_METHOD) + breakToBlock = (BreakableBlock) surrounder; + + /* We don't want labeled breaks, because we can + * simply return. */ + break; + } + } + prevBlock.removeJump(); + + if (breakToBlock == null) + /* The successor is the dummy return instruction, so + * replace the jump with a return. + */ + prevBlock.appendBlock(new ReturnBlock()); + else + prevBlock.appendBlock + (new BreakBlock(breakToBlock, false)); + } + + /* Now remove the jump of the lastModified if it points to + * END_OF_METHOD. + */ + if (lastModified.jump.destination == END_OF_METHOD) + lastModified.removeJump(); + + doTransformations(); + /* transformation succeeded */ + checkConsistent(); + } public boolean doT1(int start, int end) { /* If there are no jumps to the beginning of this flow block @@ -915,9 +1041,8 @@ public class FlowBlock { */ if (!predecessors.contains(this)) return false; - Enumeration preds = predecessors.elements(); - while (preds.hasMoreElements()) { - FlowBlock predFlow = (FlowBlock) preds.nextElement(); + for (Iterator i = predecessors.iterator(); i.hasNext(); ) { + FlowBlock predFlow = (FlowBlock) i.next(); if (predFlow != null && predFlow != this && predFlow.addr >= start && predFlow.addr < end) { return false; @@ -926,10 +1051,11 @@ public class FlowBlock { checkConsistent(); - Jump jumps = (Jump) successors.remove(this); + SuccessorInfo succInfo = (SuccessorInfo) successors.remove(this); /* Update the in/out-Vectors now */ - updateInOut(this, jumps); + updateInOut(this, succInfo); + Jump jumps = succInfo.jumps; StructuredBlock bodyBlock = block; @@ -1061,7 +1187,7 @@ public class FlowBlock { /* remove ourself from the predecessor list. */ - predecessors.removeElement(this); + predecessors.remove(this); lastModified = block; doTransformations(); // mergeCondition(); @@ -1072,81 +1198,6 @@ public class FlowBlock { return true; } - - /** - * Do a T2 transformation with the end_of_method block. - */ - public void mergeEndBlock() { - checkConsistent(); - - Jump allJumps = (Jump) successors.remove(END_OF_METHOD); - if (allJumps == null) - return; - - /* First remove all implicit jumps to the END_OF_METHOD block. - */ - Jump jumps = null; - for (; allJumps != null; ) { - Jump jump = allJumps; - allJumps = allJumps.next; - - if (jump.prev instanceof ReturnBlock) { - /* This jump is implicit */ - jump.prev.removeJump(); - continue; - } - jump.next = jumps; - jumps = jump; - } - - /* Try to eliminate as many jumps as possible. - */ - jumps = resolveSomeJumps(jumps, END_OF_METHOD); - - next_jump: - for (; jumps != null; jumps = jumps.next) { - - StructuredBlock prevBlock = jumps.prev; - - if (lastModified == prevBlock) - /* handled later */ - continue; - - BreakableBlock breakToBlock = null; - for (StructuredBlock surrounder = prevBlock.outer; - surrounder != null; surrounder = surrounder.outer) { - if (surrounder instanceof BreakableBlock) { - if (surrounder.getNextFlowBlock() == END_OF_METHOD) - breakToBlock = (BreakableBlock) surrounder; - - /* We don't want labeled breaks, because we can - * simply return. */ - break; - } - } - prevBlock.removeJump(); - - if (breakToBlock == null) - /* The successor is the dummy return instruction, so - * replace the jump with a return. - */ - prevBlock.appendBlock(new ReturnBlock()); - else - prevBlock.appendBlock - (new BreakBlock(breakToBlock, false)); - } - - /* Now remove the jump of the lastModified if it points to - * END_OF_METHOD. - */ - if (lastModified.jump.destination == END_OF_METHOD) - lastModified.removeJump(); - - doTransformations(); - /* transformation succeeded */ - checkConsistent(); - } - public void doTransformations() { if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) GlobalOptions.err.println("before Transformation: "+this); @@ -1269,12 +1320,12 @@ public class FlowBlock { * 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; + for (Iterator i = succ.predecessors.iterator(); + i.hasNext(); ) { + int predAddr = ((FlowBlock)i.next()).addr; if (predAddr < start || predAddr >= end) { - if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) + if ((GlobalOptions.debuggingFlags + & GlobalOptions.DEBUG_ANALYZE) != 0) GlobalOptions.err.println ("breaking analyze(" + start + ", " + end + "); " @@ -1331,7 +1382,7 @@ public class FlowBlock { * until nothing more is possible. */ while (nextFlow.analyze(getNextAddr(), end)) - changed = changed || true; + changed = true; if (nextFlow.addr != getNextAddr()) break; @@ -1344,31 +1395,34 @@ public class FlowBlock { || (nextFlow.predecessors.size() > 1 && (lastFlow == null || !nextFlow.predecessors.contains(lastFlow))) - || ((Jump)successors.get(nextFlow)).next != null) + || (((SuccessorInfo)successors.get(nextFlow)) + .jumps.next != null)) break; checkConsistent(); - - Jump jumps = (Jump) successors.remove(nextFlow); - /* note that this is the single caseBlock jump */ + + /* note that this info only contains + * the single caseBlock jump */ + SuccessorInfo info = (SuccessorInfo) + successors.remove(nextFlow); if (nextFlow.predecessors.size() == 2) { - Jump lastJumps = - (Jump) lastFlow.successors.remove(nextFlow); + SuccessorInfo lastInfo = (SuccessorInfo) + lastFlow.successors.remove(nextFlow); /* Do the in/out analysis with all jumps * Note that this won't update lastFlow.in, but * this will not be used anymore. */ - jumps.next = lastJumps; - updateInOut(nextFlow, jumps); + info.kill.retainAll(lastInfo.kill); + info.gen.addAll(lastInfo.gen); - lastJumps = - lastFlow.resolveSomeJumps(lastJumps, nextFlow); + Jump lastJumps = lastFlow.resolveSomeJumps + (lastInfo.jumps, nextFlow); lastFlow.resolveRemaining(lastJumps); switchBlock.caseBlocks[last+1].isFallThrough = true; - } else - updateInOut(nextFlow, jumps); + } + updateInOut(nextFlow, info); if (lastFlow != null) { lastFlow.block.replace @@ -1407,54 +1461,72 @@ public class FlowBlock { * Mark the flow block as first flow block in a method. */ public void makeStartBlock() { - predecessors.addElement(null); + predecessors.add(null); } public void removeSuccessor(Jump jump) { - Jump destJumps = (Jump) successors.get(jump.destination); + SuccessorInfo destInfo + = (SuccessorInfo) successors.get(jump.destination); Jump prev = null; + Jump destJumps = destInfo.jumps; while (destJumps != jump && destJumps != null) { prev = destJumps; destJumps = destJumps.next; } if (destJumps == null) - throw new AssertError(addr+": removing non existent jump: " + jump); + throw new IllegalArgumentException + (addr+": removing non existent jump: " + jump); + if (prev != null) prev.next = destJumps.next; else { if (destJumps.next == null) { successors.remove(jump.destination); - jump.destination.predecessors.removeElement(this); + jump.destination.predecessors.remove(this); } else - successors.put(jump.destination, destJumps.next); + destInfo.jumps = destJumps.next; } } + public Jump getJumps(FlowBlock dest) { + return ((SuccessorInfo) successors.get(dest)).jumps; + } + + public Jump removeJumps(FlowBlock dest) { + return ((SuccessorInfo) successors.remove(dest)).jumps; + } + + public Set getSuccessors() { + return successors.keySet(); + } + public void addSuccessor(Jump jump) { - jump.next = (Jump) successors.get(jump.destination); - if (jump.next == null && jump.destination != END_OF_METHOD) - jump.destination.predecessors.addElement(this); - - successors.put(jump.destination, jump); + SuccessorInfo info = (SuccessorInfo) successors.get(jump.destination); + if (info == null) { + info = new SuccessorInfo(); + info.gen = new VariableSet(); + info.kill = new SlotSet(); + block.fillInGenSet(null, info.kill); + info.gen.addAll(info.kill); + info.jumps = jump; + if (jump.destination != END_OF_METHOD) + jump.destination.predecessors.add(this); + successors.put(jump.destination, info); + } else { + jump.next = info.jumps; + info.jumps = jump; + } } /** * This is called after the analysis is completely done. It * will remove all PUSH/stack_i expressions, (if the bytecode * is correct). - * @return false if the bytecode isn't correct and stack mapping - * didn't worked. + * @return true, if the stack mapping succeeded. */ public final boolean mapStackToLocal() { -// try { - mapStackToLocal(VariableStack.EMPTY); - return true; -// } catch (RuntimeException ex) { -// GlobalOptions.err.println("Can't resolve all PUSHes, " -// +"this is probably illegal bytecode:"); -// ex.printStackTrace(GlobalOptions.err); -// return false; -// } + mapStackToLocal(VariableStack.EMPTY); + return true; } /** @@ -1472,7 +1544,8 @@ public class FlowBlock { block.mapStackToLocal(initialStack); Iterator iter = successors.values().iterator(); while (iter.hasNext()) { - Jump jumps = (Jump) iter.next(); + SuccessorInfo succInfo = (SuccessorInfo) iter.next(); + Jump jumps = succInfo.jumps; VariableStack stack; FlowBlock succ = jumps.destination; if (succ == END_OF_METHOD) @@ -1509,44 +1582,76 @@ public class FlowBlock { nextByAddr.removeOnetimeLocals(); } + private void promoteInSets() { + for (Iterator i = predecessors.iterator(); i.hasNext(); ) { + FlowBlock pred = (FlowBlock) i.next(); + SuccessorInfo succInfo = (SuccessorInfo) pred.successors.get(this); + + /* First get the gen/kill sets of all jumps of predecessor + * to this block and calculate the intersection. + */ + VariableSet gens = succInfo.gen; + SlotSet kills = succInfo.kill; + + /* Merge in locals of this block with those condionally + * written by previous blocks */ + in.merge(gens); + + /* The ins of the successor that are not killed + * (i.e. unconditionally overwritten) by this block are new + * ins for this block. + */ + SlotSet newIn = (SlotSet) in.clone(); + newIn.removeAll(kills); + + if (pred.in.addAll(newIn)) + pred.promoteInSets(); + } + + if (nextByAddr != null) + nextByAddr.promoteInSets(); + } + + /** + * Merge the parameter locals with the in set of this flow block. + * This will also make a successive analysis to merge the gen/kill + * set of the jumps with the next flow block. */ public void mergeParams(LocalInfo[] param) { + // Now we promote the final (maybe slow) in set analysis + promoteInSets(); + VariableSet paramSet = new VariableSet(param); in.merge(paramSet); - in.subtract(paramSet); } - public void makeDeclaration(LocalInfo[] param) { + /** + * Make declarations. It will determine, where in each block the + * + */ + public void makeDeclaration() { block.propagateUsage(); - SimpleSet declared = new SimpleSet(); - for (int i=0; i < param.length; i++) { - declared.add(param[i]); - } - block.makeDeclaration(declared); + Set done = new SimpleSet(); + done.addAll(in); + block.makeDeclaration(done); + if (nextByAddr != null) + nextByAddr.makeDeclaration(); } /** - * Simplify all reachable flowblocks, that are not already - * simplified, i.e. that don't occur in doneSet. + * Make declarations. It will determine, where in each block the + * */ - private void simplify(Set doneSet) { - if (doneSet.contains(this)) - return; - doneSet.add(this); - block.simplify(); - Iterator iter = successors.keySet().iterator(); - while (iter.hasNext()) { - FlowBlock succ = (FlowBlock)iter.next(); - succ.simplify(doneSet); - } + public void makeDeclaration(LocalInfo[] param) { + makeDeclaration(); } + /** + * Simplify this and all following flowblocks. + */ public void simplify() { - if (successors.size() == 0) { - // optimize default path. - block.simplify(); - return; - } - simplify(new SimpleSet()); + block.simplify(); + if (nextByAddr != null) + nextByAddr.simplify(); } /** @@ -1570,6 +1675,20 @@ public class FlowBlock { block.dumpSource(writer); + if ((GlobalOptions.debuggingFlags + & GlobalOptions.DEBUG_INOUT) != 0) { + + Iterator iter = successors.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + FlowBlock dest = (FlowBlock) entry.getKey(); + SuccessorInfo info = (SuccessorInfo) entry.getValue(); + writer.println("successor: "+dest.getLabel() + +" gen : "+ info.gen + +" kill: "+ info.kill); + } + } + if (nextByAddr != null) nextByAddr.dumpSource(writer); } @@ -1618,9 +1737,24 @@ public class FlowBlock { } writer.tab(); block.dumpSource(writer); + writer.untab(); + if ((GlobalOptions.debuggingFlags + & GlobalOptions.DEBUG_INOUT) != 0) { + + Iterator iter = successors.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + FlowBlock dest = (FlowBlock) entry.getKey(); + SuccessorInfo info = (SuccessorInfo) entry.getValue(); + writer.println("successor: "+dest.getLabel() + +" gen : "+ info.gen + +" kill: "+ info.kill); + } + } 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 0e8c07d..cf0e95f 100644 --- a/jode/jode/flow/IfThenElseBlock.java +++ b/jode/jode/flow/IfThenElseBlock.java @@ -24,6 +24,12 @@ import jode.expr.Expression; import jode.type.Type; import jode.util.SimpleSet; +///#ifdef JDK12 +///import java.util.Set; +///#else +import jode.util.Set; +///#endif + /** * An IfThenElseBlock is the structured block representing an if * instruction. The else part may be null. @@ -132,8 +138,8 @@ public class IfThenElseBlock extends StructuredBlock { elseBlock.removePush(); } - public SimpleSet getDeclarables() { - SimpleSet used = new SimpleSet(); + public Set getDeclarables() { + Set used = new SimpleSet(); cond.fillDeclarables(used); return used; } diff --git a/jode/jode/flow/InstructionBlock.java b/jode/jode/flow/InstructionBlock.java index 35ecfd5..cdda53e 100644 --- a/jode/jode/flow/InstructionBlock.java +++ b/jode/jode/flow/InstructionBlock.java @@ -26,6 +26,12 @@ import jode.expr.StoreInstruction; import jode.expr.LocalStoreOperator; import jode.util.SimpleSet; +///#ifdef JDK12 +///import java.util.Set; +///#else +import jode.util.Set; +///#endif + /** * This is the structured block for atomic instructions. */ @@ -101,7 +107,7 @@ public class InstructionBlock extends InstructionContainer { * variable. In that case mark this as declaration and return the * variable. */ - public void checkDeclaration(SimpleSet declareSet) { + public void checkDeclaration(Set declareSet) { if (instr instanceof StoreInstruction && (((StoreInstruction)instr).getLValue() instanceof LocalStoreOperator)) { @@ -126,7 +132,7 @@ public class InstructionBlock extends InstructionContainer { * is marked as used, but not done. * @param done The set of the already declare variables. */ - public void makeDeclaration(SimpleSet done) { + public void makeDeclaration(Set done) { super.makeDeclaration(done); checkDeclaration(declare); } diff --git a/jode/jode/flow/InstructionContainer.java b/jode/jode/flow/InstructionContainer.java index d907b7b..17c3fd2 100644 --- a/jode/jode/flow/InstructionContainer.java +++ b/jode/jode/flow/InstructionContainer.java @@ -24,6 +24,12 @@ import jode.expr.InvokeOperator; import jode.expr.LocalVarOperator; import jode.util.SimpleSet; +///#ifdef JDK12 +///import java.util.Set; +///#else +import jode.util.Set; +///#endif + /** * This is a method for block containing a single instruction. */ @@ -40,11 +46,6 @@ public abstract class InstructionContainer extends StructuredBlock { public InstructionContainer(Expression instr, Jump jump) { this(instr); setJump(jump); - if (instr != null) { - VariableSet gen = new VariableSet(); - instr.fillInGenSet(null, jump.gen); - instr.fillInGenSet(null, jump.kill); - } } /** @@ -66,13 +67,13 @@ public abstract class InstructionContainer extends StructuredBlock { * Fill all in variables into the given VariableSet. * @param in The VariableSet, the in variables should be stored to. */ - public void fillInGenSet(VariableSet in, VariableSet gen) { + public void fillInGenSet(Set in, Set gen) { if (instr != null) instr.fillInGenSet(in, gen); } - public SimpleSet getDeclarables() { - SimpleSet used = new SimpleSet(); + public Set getDeclarables() { + Set used = new SimpleSet(); if (instr != null) instr.fillDeclarables(used); return used; diff --git a/jode/jode/flow/Jump.java b/jode/jode/flow/Jump.java index e7ff528..6f11419 100644 --- a/jode/jode/flow/Jump.java +++ b/jode/jode/flow/Jump.java @@ -39,23 +39,6 @@ public class Jump { */ Jump next; - /** - * The kill locals. This are the slots, which must be overwritten - * in this block on every path to this jump. That means, that all - * paths form the start of the current flow block to this jump - * contain (unconditional) assignments to this slot. - */ - VariableSet kill; - - /** - * The gen locals. This are the locals, which can be overwritten - * in this block on a path to this jump. That means, that there - * exists a path form the start of the current flow block to this - * jump that contains an (unconditional) assignments to this - * local, and that is not overwritten afterwards. - */ - VariableSet gen; - /** * The stack map. This tells how many objects are on stack at * begin of the flow block, and to what locals they are maped. @@ -65,16 +48,12 @@ public class Jump { public Jump (FlowBlock dest) { this.destination = dest; - kill = new VariableSet(); - gen = new VariableSet(); } public Jump (Jump jump) { destination = jump.destination; next = jump.next; jump.next = this; - gen = (VariableSet) jump.gen.clone(); - kill = (VariableSet) jump.kill.clone(); } /** @@ -86,11 +65,6 @@ public class Jump { public void dumpSource(jode.decompiler.TabbedPrintWriter writer) throws java.io.IOException { - if ((GlobalOptions.debuggingFlags - & GlobalOptions.DEBUG_INOUT) != 0) { - writer.println("gen : "+ gen.toString()); - writer.println("kill: "+ kill.toString()); - } if (destination == null) writer.println ("GOTO null-ptr!!!!!"); else diff --git a/jode/jode/flow/LoopBlock.java b/jode/jode/flow/LoopBlock.java index 4bf053e..17e82a9 100644 --- a/jode/jode/flow/LoopBlock.java +++ b/jode/jode/flow/LoopBlock.java @@ -28,6 +28,12 @@ import jode.expr.LocalStoreOperator; import jode.expr.CombineableOperator; import jode.util.SimpleSet; +///#ifdef JDK12 +///import java.util.Set; +///#else +import jode.util.Set; +///#endif + /** * This is the structured block for an Loop block. */ @@ -201,7 +207,7 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { * Remove all variables from set, that we can declare inside the * loop-block. This is the initializer for for-blocks. */ - public void removeLocallyDeclareable(SimpleSet set) { + public void removeLocallyDeclareable(Set set) { if (type == FOR && initInstr instanceof StoreInstruction) { StoreInstruction storeOp = (StoreInstruction) initInstr; if (storeOp.getLValue() instanceof LocalStoreOperator) { @@ -212,8 +218,8 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { } } - public SimpleSet getDeclarables() { - SimpleSet used = new SimpleSet(); + public Set getDeclarables() { + Set used = new SimpleSet(); if (type == FOR) { incrInstr.fillDeclarables(used); if (initInstr != null) @@ -250,7 +256,7 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { * variable. In that case mark this as declaration and return the * variable. */ - public void checkDeclaration(SimpleSet declareSet) { + public void checkDeclaration(Set declareSet) { if (initInstr instanceof StoreInstruction && (((StoreInstruction)initInstr).getLValue() instanceof LocalStoreOperator)) { @@ -275,7 +281,7 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock { * is marked as used, but not done. * @param done The set of the already declare variables. */ - public void makeDeclaration(SimpleSet done) { + public void makeDeclaration(Set done) { super.makeDeclaration(done); if (type == FOR && initInstr != null) checkDeclaration(declare); diff --git a/jode/jode/flow/RetBlock.java b/jode/jode/flow/RetBlock.java index f90e97b..6ee36b3 100644 --- a/jode/jode/flow/RetBlock.java +++ b/jode/jode/flow/RetBlock.java @@ -19,7 +19,14 @@ package jode.flow; import jode.decompiler.LocalInfo; -import jode.util.SimpleSet; + +///#ifdef JDK12 +///import java.util.Collections; +///import java.util.Set; +///#else +import jode.util.Collections; +import jode.util.Set; +///#endif /** * This block represents a ret instruction. A ret instruction is @@ -42,9 +49,9 @@ public class RetBlock extends StructuredBlock { * Fill all in variables into the given VariableSet. * @param in The VariableSet, the in variables should be stored to. */ - public void fillInGenSet(VariableSet in, VariableSet gen) { - in.addElement(local); - gen.addElement(local); + public void fillInGenSet(Set in, Set gen) { + in.add(local); + gen.add(local); } /** @@ -59,10 +66,8 @@ public class RetBlock extends StructuredBlock { return null; } - public SimpleSet getDeclarables() { - SimpleSet used = new SimpleSet(); - used.add(local); - return used; + public Set getDeclarables() { + return Collections.singleton(local); } public void dumpInstruction(jode.decompiler.TabbedPrintWriter writer) diff --git a/jode/jode/flow/SequentialBlock.java b/jode/jode/flow/SequentialBlock.java index f898973..0275692 100644 --- a/jode/jode/flow/SequentialBlock.java +++ b/jode/jode/flow/SequentialBlock.java @@ -24,6 +24,12 @@ import jode.expr.LocalStoreOperator; import jode.expr.StoreInstruction; import jode.util.SimpleSet; +///#ifdef JDK12 +///import java.util.Set; +///#else +import jode.util.Set; +///#endif + /** * A sequential block combines exactly two structured blocks to a new * one. The first sub block mustn't be another sequential block, @@ -168,16 +174,17 @@ public class SequentialBlock extends StructuredBlock { * @return all locals that are used in this block or in some sub * block (this is not the used set). */ - public SimpleSet propagateUsage() { - used = getDeclarables(); - SimpleSet allUse = new SimpleSet(); - SimpleSet childUse0 = subBlocks[0].propagateUsage(); - SimpleSet childUse1 = subBlocks[1].propagateUsage(); + public Set propagateUsage() { + used = new SimpleSet(); + Set allUse = new SimpleSet(); + Set childUse0 = subBlocks[0].propagateUsage(); + Set childUse1 = subBlocks[1].propagateUsage(); /* All variables used somewhere inside both sub blocks, are * used in this block, too. * Also the variables used in first block are used in this * block, except when it can be declared locally. (Note that - * subBlocks[0].used != childUse0) */ + * subBlocks[0].used != childUse0) + */ used.addAll(subBlocks[0].used); if (subBlocks[0] instanceof LoopBlock) ((LoopBlock) subBlocks[0]).removeLocallyDeclareable(used); @@ -194,7 +201,7 @@ public class SequentialBlock extends StructuredBlock { * is marked as used, but not done. * @param done The set of the already declare variables. */ - public void makeDeclaration(SimpleSet done) { + public void makeDeclaration(Set done) { super.makeDeclaration(done); if (subBlocks[0] instanceof InstructionBlock) /* An instruction block may declare a variable for us. diff --git a/jode/jode/flow/StructuredBlock.java b/jode/jode/flow/StructuredBlock.java index 3349d8a..dbfdf1e 100644 --- a/jode/jode/flow/StructuredBlock.java +++ b/jode/jode/flow/StructuredBlock.java @@ -26,9 +26,13 @@ import jode.decompiler.Declarable; import jode.util.SimpleSet; ///#ifdef JDK12 +///import java.util.Collections; ///import java.util.Iterator; +///import java.util.Set; ///#else +import jode.util.Collections; import jode.util.Iterator; +import jode.util.Set; ///#endif /** @@ -71,17 +75,17 @@ public abstract class StructuredBlock { */ /** - * The SimpleSet containing all Declarables that are used in this + * The Set containing all Declarables that are used in this * block. */ - SimpleSet used; + Set used; /** - * The SimpleSet containing all Declarables we must declare. + * The Set containing all Declarables we must declare. * The analyzation is done in makeDeclaration */ - SimpleSet declare; - SimpleSet done; + Set declare; + Set done; /** * The surrounding structured block. If this is the outermost @@ -218,16 +222,6 @@ public abstract class StructuredBlock { * will be moved to this block (may be this). */ void moveDefinitions(StructuredBlock from, StructuredBlock sub) { -// while (from != sub && from != this) { -// used.unionExact(from.used); -// from.used.removeAllElements(); -// StructuredBlock[] subs = from.getSubBlocks(); -// if (subs.length == 0) -// return; -// for (int i=0; inot the used set). */ - public SimpleSet propagateUsage() { - used = getDeclarables(); + public Set propagateUsage() { + used = new SimpleSet(); + used.addAll(getDeclarables()); StructuredBlock[] subs = getSubBlocks(); - SimpleSet allUse = (SimpleSet) used.clone(); + Set allUse = new SimpleSet(); + allUse.addAll(used); for (int i=0; i - * - * For example this code prints 0: - *
-     *   int a=3;
-     *   try {
-     *     a = 5 / (a=0);
-     *   } catch (DivideByZeroException ex) {
-     *     System.out.println(a);
-     *   }
-     * 
- * - * @param successor The flow block which is unified with this flow - * block. - * @return The variables that must be defined in this block. - */ - static void updateInOutCatch (FlowBlock tryFlow, FlowBlock catchFlow) { - VariableSet gens = ((TryBlock)tryFlow.block).gen; - - /* Merge the locals used in the catch block with those written - * by the try block - */ - catchFlow.in.merge(gens); - - /* The gen/kill sets must be updated for every jump - * in the catch block */ - Iterator succs = catchFlow.successors.values().iterator(); - while (succs.hasNext()) { - for (Jump succJumps = (Jump) succs.next(); - succJumps != null; succJumps = succJumps.next) { - succJumps.gen.mergeGenKill(gens, succJumps.kill); - } - } - tryFlow.in.unionExact(catchFlow.in); - tryFlow.gen.unionExact(catchFlow.gen); - - if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { - GlobalOptions.err.println("UpdateInOutCatch: gens : "+gens); - GlobalOptions.err.println(" s.in : "+catchFlow.in); - GlobalOptions.err.println(" in : "+tryFlow.in); - } - } - /* simple try catch block: * @@ -230,8 +182,8 @@ public class TransformExceptionHandlers { * @param subRoutine the FlowBlock of the sub routine. */ private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) { - for (Jump jumps = (Jump)tryFlow.successors.remove(subRoutine); - jumps != null; jumps = jumps.next) { + for (Jump jumps = tryFlow.removeJumps(subRoutine); + jumps != null; jumps = jumps.next) { StructuredBlock prev = jumps.prev; prev.removeJump(); @@ -296,13 +248,14 @@ public class TransformExceptionHandlers { } public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine) { - Iterator iter = tryFlow.successors.entrySet().iterator(); + Iterator iter = tryFlow.getSuccessors().iterator(); while (iter.hasNext()) { - Map.Entry entry = (Map.Entry) iter.next(); - Jump jumps = (Jump) entry.getValue(); - if (entry.getKey() == subRoutine) + FlowBlock dest = (FlowBlock) iter.next(); + if (dest == subRoutine) continue; + Jump jumps = tryFlow.getJumps(dest); + for ( ; jumps != null; jumps = jumps.next) { StructuredBlock prev = jumps.prev; @@ -372,10 +325,10 @@ public class TransformExceptionHandlers { public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local, int startMonExit, int endMonExit) { FlowBlock subRoutine = null; - Iterator succs = tryFlow.successors.values().iterator(); + Iterator succs = tryFlow.getSuccessors().iterator(); dest_loop: while (succs.hasNext()) { - for (Jump jumps = (Jump) succs.next(); + for (Jump jumps = tryFlow.getJumps((FlowBlock) succs.next()); jumps != null; jumps = jumps.next) { StructuredBlock prev = jumps.prev; @@ -628,10 +581,10 @@ public class TransformExceptionHandlers { /* Check if the try block has no exit (except throws) */ - Jump throwJumps = (Jump) - tryFlow.successors.get(FlowBlock.END_OF_METHOD); - if (tryFlow.successors.size() > 1 - || (tryFlow.successors.size() > 0 && throwJumps == null)) + Jump throwJumps = tryFlow.getJumps(FlowBlock.END_OF_METHOD); + if (tryFlow.getSuccessors().size() > 1 + || (tryFlow.getSuccessors().size() > 0 + && throwJumps == null)) return false; for (/**/; throwJumps != null; throwJumps = throwJumps.next) { @@ -649,7 +602,7 @@ public class TransformExceptionHandlers { finallyBlock.replace(catchFlow.block); transformSubRoutine(finallyBlock); - updateInOutCatch(tryFlow, catchFlow); + tryFlow.updateInOutCatch(catchFlow); tryFlow.mergeAddr(catchFlow); finallyBlock = catchFlow.block; tryFlow.mergeSuccessors(catchFlow); @@ -667,7 +620,7 @@ public class TransformExceptionHandlers { checkAndRemoveJSR(tryFlow, subRoutine); - updateInOutCatch(tryFlow, subRoutine); + tryFlow.updateInOutCatch(subRoutine); tryFlow.mergeAddr(subRoutine); tryFlow.mergeSuccessors(subRoutine); finallyBlock = subRoutine.block; @@ -676,9 +629,9 @@ public class TransformExceptionHandlers { * and the jump of the throw instruction. */ catchBlock.getSubBlocks()[0].getSubBlocks()[0] - .jump.destination.predecessors.removeElement(catchFlow); + .jump.destination.predecessors.remove(catchFlow); catchBlock.getSubBlocks()[1] - .jump.destination.predecessors.removeElement(catchFlow); + .jump.destination.predecessors.remove(catchFlow); } TryBlock tryBlock = (TryBlock)tryFlow.block; @@ -715,19 +668,18 @@ public class TransformExceptionHandlers { */ FlowBlock succ = (firstInstr.jump != null) ? - firstInstr.jump.destination : null; + firstInstr.jump.destination : null; boolean hasExit = false; - Iterator iter = tryFlow.successors.entrySet().iterator(); + Iterator iter = tryFlow.getSuccessors().iterator(); while (iter.hasNext()) { - Map.Entry entry = (Map.Entry) iter.next(); - Object key = entry.getKey(); - if (key == succ) + FlowBlock dest = (FlowBlock) iter.next(); + if (dest == succ) continue; - if (key != FlowBlock.END_OF_METHOD) { + if (dest != FlowBlock.END_OF_METHOD) { /* There is another exit in the try block, bad */ return false; } - for (Jump throwJumps = (Jump) entry.getValue(); + for (Jump throwJumps = (Jump) tryFlow.getJumps(dest); throwJumps != null; throwJumps = throwJumps.next) { if (!(throwJumps.prev instanceof ThrowBlock)) { /* There is a return exit in the try block */ @@ -741,8 +693,8 @@ public class TransformExceptionHandlers { tryFlow.mergeAddr(catchFlow); if (succ != null) { - Jump jumps = (Jump) tryFlow.successors.remove(succ); - succ.predecessors.removeElement(tryFlow); + Jump jumps = tryFlow.removeJumps(succ); + succ.predecessors.remove(tryFlow); /* Handle the jumps in the tryFlow. */ jumps = tryFlow.resolveSomeJumps(jumps, succ); @@ -765,7 +717,7 @@ public class TransformExceptionHandlers { if (succ != null && succ.predecessors.size() == 1) { while (succ.analyze(catchFlow.getNextAddr(), end)); tryFlow.mergeAddr(succ); - tryFlow.successors.remove(succ); + tryFlow.removeJumps(succ); newBlock.setCatchBlock(succ.block); tryFlow.mergeSuccessors(succ); } else { @@ -792,23 +744,23 @@ public class TransformExceptionHandlers { Handler last = null; for (Iterator i = handlers.iterator(); i.hasNext(); ) { Handler exc = (Handler) i.next(); - int start = exc.start.addr; + int start = exc.start.getAddr(); int end = exc.endAddr; - int handler = exc.handler.addr; + int handler = exc.handler.getAddr(); if (start >= end || handler < end) throw new AssertError ("ExceptionHandler order failed: not " + start + " < " + end + " <= " + handler); if (last != null - && (last.start.addr != start || last.endAddr != end)) { + && (last.start.getAddr() != start || last.endAddr != end)) { /* The last handler does catch another range. * Due to the order: - * start < last.start.addr || end > last.end.addr + * start < last.start.getAddr() || end > last.end.getAddr() */ - if (end > last.start.addr && end < last.endAddr) + if (end > last.start.getAddr() && end < last.endAddr) throw new AssertError ("Exception handlers ranges are intersecting: [" - + last.start.addr+", "+last.endAddr+"] and [" + + last.start.getAddr()+", "+last.endAddr+"] and [" + start+", "+end+"]."); } last = exc; @@ -836,11 +788,11 @@ public class TransformExceptionHandlers { & GlobalOptions.DEBUG_ANALYZE) != 0) GlobalOptions.err.println ("analyzeTry(" - + exc.start.addr + ", " + exc.endAddr+")"); - while (tryFlow.analyze(tryFlow.addr, exc.endAddr)); + + exc.start.getAddr() + ", " + exc.endAddr+")"); + while (tryFlow.analyze(tryFlow.getAddr(), exc.endAddr)); if (last == null - || last.start.addr != exc.start.addr + || last.start.getAddr() != exc.start.getAddr() || last.endAddr != exc.endAddr) { /* The last handler does catch another range. * Create a new try block. @@ -869,7 +821,7 @@ public class TransformExceptionHandlers { */ EmptyBlock jump = new EmptyBlock(new Jump(catchFlow)); FlowBlock newFlow = new FlowBlock(catchFlow.method, - catchFlow.addr, 0); + catchFlow.getAddr(), 0); newFlow.setBlock(jump); catchFlow.prevByAddr.setNextByAddr(newFlow); newFlow.setNextByAddr(catchFlow); @@ -879,11 +831,11 @@ public class TransformExceptionHandlers { & GlobalOptions.DEBUG_ANALYZE) != 0) GlobalOptions.err.println ("analyzeCatch(" - + catchFlow.addr + ", " + endHandler + ")"); - while (catchFlow.analyze(catchFlow.addr, endHandler)); + + catchFlow.getAddr() + ", " + endHandler + ")"); + while (catchFlow.analyze(catchFlow.getAddr(), endHandler)); } - updateInOutCatch(tryFlow, catchFlow); + tryFlow.updateInOutCatch(catchFlow); if (exc.type != null) analyzeCatchBlock(exc.type, tryFlow, catchFlow); @@ -898,8 +850,8 @@ public class TransformExceptionHandlers { if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) GlobalOptions.err.println - ("analyzeCatch(" + tryFlow.addr + ", " - + (tryFlow.addr + tryFlow.length) + ") done."); + ("analyzeCatch(" + tryFlow.getAddr() + ", " + + tryFlow.getNextAddr() + ") done."); } } } diff --git a/jode/jode/flow/VariableSet.java b/jode/jode/flow/VariableSet.java index c8d2017..e490a17 100644 --- a/jode/jode/flow/VariableSet.java +++ b/jode/jode/flow/VariableSet.java @@ -21,6 +21,16 @@ package jode.flow; import jode.decompiler.LocalInfo; import jode.util.ArrayEnum; +///#ifdef JDK12 +///import java.util.Collection; +///import java.util.AbstractSet; +///import java.util.Iterator; +///#else +import jode.util.Collection; +import jode.util.AbstractSet; +import jode.util.Iterator; +///#endif + /** * This class represents a set of Variables, which are mainly used in * the in/out sets of StructuredBlock. The type of the Variables is @@ -32,7 +42,7 @@ import jode.util.ArrayEnum; * Note that a variable set can contain LocalInfos that use the same * slot, but are different. */ -public final class VariableSet implements Cloneable { +public final class VariableSet extends AbstractSet implements Cloneable { LocalInfo[] locals; int count; @@ -68,25 +78,34 @@ public final class VariableSet implements Cloneable { } /** - * Adds a local info to this variable set. It doesn't check for - * duplicates. + * Adds a local info to this variable set. */ - public void addElement(LocalInfo li) { + public boolean add(Object li) { + if (contains(li)) + return false; grow(1); - locals[count++] = li; + locals[count++] = (LocalInfo) li; + return true; } /** * Checks if the variable set contains the given local info. */ - public boolean contains(LocalInfo li) { - li = li.getLocalInfo(); + public boolean contains(Object li) { + li = ((LocalInfo) li).getLocalInfo(); for (int i=0; i0) - result.append(", "); - result.append(locals[i].getName()); + for (Iterator i = gen.iterator(); i.hasNext(); ) { + LocalInfo li2 = (LocalInfo) i.next(); + if (!kill.containsSlot(li2.getSlot())) + add(li2.getLocalInfo()); } - return result.append("]").toString(); } }