gen/kill set rework in FlowBlock, successors now private

Other files changed to get jumps via methods of flowblock.


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1038 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 26 years ago
parent efdfcbf7bc
commit ec1e63532c
  1. 18
      jode/jode/flow/CatchBlock.java
  2. 4
      jode/jode/flow/CombineIfGotoExpressions.java
  3. 636
      jode/jode/flow/FlowBlock.java
  4. 10
      jode/jode/flow/IfThenElseBlock.java
  5. 10
      jode/jode/flow/InstructionBlock.java
  6. 17
      jode/jode/flow/InstructionContainer.java
  7. 26
      jode/jode/flow/Jump.java
  8. 16
      jode/jode/flow/LoopBlock.java
  9. 21
      jode/jode/flow/RetBlock.java
  10. 21
      jode/jode/flow/SequentialBlock.java
  11. 50
      jode/jode/flow/StructuredBlock.java
  12. 10
      jode/jode/flow/SynchronizedBlock.java
  13. 138
      jode/jode/flow/TransformExceptionHandlers.java
  14. 268
      jode/jode/flow/VariableSet.java

@ -26,6 +26,15 @@ import jode.expr.LocalStoreOperator;
import jode.expr.StoreInstruction; import jode.expr.StoreInstruction;
import jode.util.SimpleSet; 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 * @author Jochen Hoenicke
@ -121,11 +130,10 @@ public class CatchBlock extends StructuredBlock {
super.removePush(); super.removePush();
} }
public SimpleSet getDeclarables() { public Set getDeclarables() {
SimpleSet used = new SimpleSet();
if (exceptionLocal != null) if (exceptionLocal != null)
used.add(exceptionLocal); return Collections.singleton(exceptionLocal);
return used; return Collections.EMPTY_SET;
} }
/** /**
@ -134,7 +142,7 @@ public class CatchBlock extends StructuredBlock {
* is marked as used, but not done. * is marked as used, but not done.
* @param done The set of the already declare variables. * @param done The set of the already declare variables.
*/ */
public void makeDeclaration(SimpleSet done) { public void makeDeclaration(Set done) {
super.makeDeclaration(done); super.makeDeclaration(done);
/* Normally we have to declare our exceptionLocal. This /* Normally we have to declare our exceptionLocal. This
* is automatically done in dumpSource. * is automatically done in dumpSource.

@ -67,13 +67,9 @@ public class CombineIfGotoExpressions {
if (prevJump.destination == cb.jump.destination) { if (prevJump.destination == cb.jump.destination) {
operator = BinaryOperator.LOG_AND_OP; operator = BinaryOperator.LOG_AND_OP;
firstCond = cbprev.getInstruction().negate(); firstCond = cbprev.getInstruction().negate();
cb.jump.gen.unionExact(prevJump.gen);
cb.jump.kill.intersect(prevJump.kill);
} else if (prevJump.destination == cb.trueBlock.jump.destination) { } else if (prevJump.destination == cb.trueBlock.jump.destination) {
operator = BinaryOperator.LOG_OR_OP; operator = BinaryOperator.LOG_OR_OP;
firstCond = cbprev.getInstruction(); firstCond = cbprev.getInstruction();
cb.trueBlock.jump.gen.unionExact(prevJump.gen);
cb.trueBlock.jump.kill.intersect(prevJump.kill);
} else } else
return false; return false;

@ -34,10 +34,14 @@ import jode.util.SimpleSet;
///import java.util.Iterator; ///import java.util.Iterator;
///import java.util.Set; ///import java.util.Set;
///import java.util.SimpleSet; ///import java.util.SimpleSet;
///import java.util.ArrayList;
///import java.util.List;
///#else ///#else
import jode.util.Map; import jode.util.Map;
import jode.util.Iterator; import jode.util.Iterator;
import jode.util.Set; import jode.util.Set;
import jode.util.ArrayList;
import jode.util.List;
import jode.util.SimpleSet; import jode.util.SimpleSet;
///#endif ///#endif
@ -80,7 +84,7 @@ public class FlowBlock {
* path from the start of the flow block to the instruction that * path from the start of the flow block to the instruction that
* uses that variable, on which it is never assigned * 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 * The gen locals. This are the locals, to which are written
* somewhere in this flow block. This is only used for try * 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 * The starting address of this flow block. This is mainly used
* to produce the source code in code order. * to produce the source code in code order.
*/ */
int addr; private int addr;
/** /**
* The length of the structured block, only needed at the beginning. * The length of the structured block, only needed at the beginning.
*/ */
int length; private int length;
/** /**
* The outermost structructed block in this flow block. * 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 * the elements is the first jump to that flow block. The other
* jumps are accessible via the jump.next field. * 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. * 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 * If this vectors contains the null element, this is the first
* flow block in a method. * 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. * This is a pointer to the next flow block in byte code order.
@ -148,6 +152,33 @@ public class FlowBlock {
*/ */
VariableStack stackMap; 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. * The default constructor. Creates a new empty flowblock.
*/ */
@ -577,25 +608,28 @@ public class FlowBlock {
* @param succ the other flow block * @param succ the other flow block
*/ */
void mergeSuccessors(FlowBlock succ) { 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(); Iterator iter = succ.successors.entrySet().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next(); Map.Entry entry = (Map.Entry) iter.next();
FlowBlock dest = (FlowBlock) entry.getKey(); FlowBlock dest = (FlowBlock) entry.getKey();
Jump hisJumps = (Jump) entry.getValue(); SuccessorInfo hisInfo = (SuccessorInfo) entry.getValue();
Jump myJumps = (Jump) successors.get(dest); SuccessorInfo myInfo = (SuccessorInfo) successors.get(dest);
if (dest != END_OF_METHOD) if (dest != END_OF_METHOD)
dest.predecessors.removeElement(succ); dest.predecessors.remove(succ);
if (myJumps == null) { if (myInfo == null) {
if (dest != END_OF_METHOD) if (dest != END_OF_METHOD)
dest.predecessors.addElement(this); dest.predecessors.add(this);
successors.put(dest, hisJumps); successors.put(dest, hisInfo);
} else { } 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 = 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. * @param jumps The list of jumps to successor in this block.
* @return The variables that must be defined in this block. * @return The variables that must be defined in this block.
*/ */
void updateInOut (FlowBlock successor, Jump jumps) { void updateInOut(FlowBlock successor, SuccessorInfo succInfo) {
/* First get the out vectors of all jumps to successor and /* First get the gen/kill sets of all jumps to successor and
* calculate the intersection. * calculate the intersection.
*/ */
VariableSet gens = new VariableSet(); SlotSet kills = succInfo.kill;
VariableSet kills = null; 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 /* Merge the locals used in successing block with those written
* by this blocks * by this blocks.
*/ */
successor.in.merge(gens); successor.in.merge(gens);
/* Now update in and out set of successing block */ /* The ins of the successor that are not killed
* (i.e. unconditionally overwritten) by this block are new
if (successor != this) * ins for this block.
successor.in.subtract(kills); */
SlotSet newIn = (SlotSet) successor.in.clone();
newIn.removeAll(kills);
/* The gen/kill sets must be updated for every jump /* The gen/kill sets must be updated for every jump
* in the other block */ * in the other block */
Iterator succSuccs = successor.successors.values().iterator(); Iterator i = successor.successors.values().iterator();
while (succSuccs.hasNext()) { while (i.hasNext()) {
Jump succJumps = (Jump) succSuccs.next(); SuccessorInfo succSuccInfo = (SuccessorInfo) i.next();
for (; succJumps != null; succJumps = succJumps.next) { succSuccInfo.gen.mergeGenKill(gens, succSuccInfo.kill);
if (successor != this)
succJumps.gen.mergeGenKill(gens, succJumps.kill); succSuccInfo.kill.addAll(kills);
if (successor != this)
succJumps.kill.add(kills);
}
} }
this.in.unionExact(successor.in); this.in.addAll(newIn);
this.gen.unionExact(successor.gen); this.gen.addAll(successor.gen);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) {
GlobalOptions.err.println("UpdateInOut: gens : "+gens); GlobalOptions.err.println("UpdateInOut: gens : "+gens);
@ -680,6 +705,53 @@ public class FlowBlock {
} }
} }
/**
* 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.<br>
*
* For example this code prints <code>0</code>:
* <pre>
* int a=3;
* try {
* a = 5 / (a=0);
* } catch (DivideByZeroException ex) {
* System.out.println(a);
* }
* </pre>
*
* @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 * Checks if the FlowBlock and its StructuredBlocks are
* consistent. There are to many conditions to list them * consistent. There are to many conditions to list them
@ -699,9 +771,8 @@ public class FlowBlock {
} }
block.checkConsistent(); block.checkConsistent();
Enumeration preds = predecessors.elements(); for (Iterator i = predecessors.iterator(); i.hasNext(); ) {
while (preds.hasMoreElements()) { FlowBlock pred = (FlowBlock)i.next();
FlowBlock pred = (FlowBlock)preds.nextElement();
if (pred == null) if (pred == null)
/* The special start marker */ /* The special start marker */
continue; continue;
@ -723,7 +794,7 @@ public class FlowBlock {
if (dest.predecessors.contains(this) == (dest == END_OF_METHOD)) if (dest.predecessors.contains(this) == (dest == END_OF_METHOD))
throw new AssertError("Inconsistency"); throw new AssertError("Inconsistency");
Jump jumps = (Jump)entry.getValue(); Jump jumps = ((SuccessorInfo) entry.getValue()).jumps;
if (jumps == null) if (jumps == null)
throw new AssertError("Inconsistency"); throw new AssertError("Inconsistency");
@ -774,20 +845,28 @@ public class FlowBlock {
GlobalOptions.err.println("merging sequentialBlock: "+this); GlobalOptions.err.println("merging sequentialBlock: "+this);
GlobalOptions.err.println("and: "+succ); GlobalOptions.err.println("and: "+succ);
} }
VariableSet succIn = new VariableSet(); SlotSet succIn = new SlotSet();
succ.fillInGenSet(succIn, this.gen); SlotSet succKill = new SlotSet();
VariableSet succGen = new VariableSet();
succ.fillInGenSet(succIn, succKill);
succGen.addAll(succKill);
succIn.merge(lastModified.jump.gen); SuccessorInfo succInfo = (SuccessorInfo) successors.get(NEXT_BY_ADDR);
succIn.subtract(lastModified.jump.kill); succIn.merge(succInfo.gen);
succIn.removeAll(succInfo.kill);
succ.jump.gen.mergeGenKill(lastModified.jump.gen, succ.jump.kill); succGen.mergeGenKill(succInfo.gen, succKill);
succ.jump.kill.add(lastModified.jump.kill); succKill.addAll(succInfo.kill);
this.in.unionExact(succIn); this.in.addAll(succIn);
this.gen.addAll(succKill);
removeSuccessor(lastModified.jump); removeSuccessor(lastModified.jump);
lastModified.removeJump(); lastModified.removeJump();
lastModified = lastModified.appendBlock(succ); lastModified = lastModified.appendBlock(succ);
succ.fillSuccessors(); succ.fillSuccessors();
succInfo = (SuccessorInfo) successors.get(NEXT_BY_ADDR);
succInfo.gen = succGen;
succInfo.kill = succKill;
this.length += length; this.length += length;
checkConsistent(); checkConsistent();
doTransformations(); doTransformations();
@ -798,21 +877,31 @@ public class FlowBlock {
* nextByAddr should be null, when calling this. * nextByAddr should be null, when calling this.
* @param flow The flowBlock to append * @param flow The flowBlock to append
*/ */
public void setNextByAddr(FlowBlock flow) { public void setNextByAddr(FlowBlock flow)
Jump jumps = (Jump) successors.remove(NEXT_BY_ADDR); {
Jump flowJumps = (Jump) successors.get(flow); /* nextByAddr can be set, when reordering block in transform exc */
if (jumps != null) { // if (nextByAddr != null)
NEXT_BY_ADDR.predecessors.removeElement(this); // 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; jumps.destination = flow;
while (jumps.next != null) { while (jumps.next != null) {
jumps = jumps.next; jumps = jumps.next;
jumps.destination = flow; jumps.destination = flow;
} }
successors.put(flow, jumps); successors.put(flow, info);
if (flowJumps != null) if (flowInfo != null) {
jumps.next = flowJumps; info.gen.addAll(flowInfo.gen);
else if (flow != END_OF_METHOD) info.kill.retainAll(flowInfo.kill);
flow.predecessors.addElement(this); jumps.next = flowInfo.jumps;
} else
flow.predecessors.add(this);
} }
checkConsistent(); checkConsistent();
@ -830,22 +919,22 @@ public class FlowBlock {
/* check if this successor has only this block as predecessor. /* check if this successor has only this block as predecessor.
* if the predecessor is not unique, return false. */ * if the predecessor is not unique, return false. */
if (succ.predecessors.size() != 1 || if (succ.predecessors.size() != 1 ||
succ.predecessors.elementAt(0) != this) succ.predecessors.get(0) != this)
return false; return false;
checkConsistent(); checkConsistent();
succ.checkConsistent(); succ.checkConsistent();
Jump jumps = (Jump) successors.remove(succ); SuccessorInfo succInfo = (SuccessorInfo) successors.remove(succ);
/* Update the in/out-Vectors now */ /* Update the in/out-Vectors now */
updateInOut(succ, jumps); updateInOut(succ, succInfo);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Resolve: "+this); GlobalOptions.err.println("before Resolve: "+this);
/* Try to eliminate as many jumps as possible. /* 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) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Remaining: "+this); GlobalOptions.err.println("before Remaining: "+this);
resolveRemaining(jumps); resolveRemaining(jumps);
@ -868,44 +957,81 @@ public class FlowBlock {
return true; return true;
} }
// /** /**
// * Find the exit condition of a for/while block. The loop block * Do a T2 transformation with the end_of_method block.
// * mustn't have an exit condition yet. */
// */ public void mergeEndBlock() {
// public void mergeCondition() { checkConsistent();
// /* If the first instruction of a while is a conditional
// * block, which jumps to the next address use the condition SuccessorInfo endInfo
// * as while condition. = (SuccessorInfo) successors.remove(END_OF_METHOD);
// */ if (endInfo == null)
// LoopBlock loopBlock = (LoopBlock) lastModified; return;
// int loopType = loopBlock.getType();
Jump allJumps = endInfo.jumps;
// ConditionalBlock cb = null; /* First remove all implicit jumps to the END_OF_METHOD block.
// if (loopBlock.bodyBlock instanceof ConditionalBlock) */
// cb = (ConditionalBlock) loopBlock.bodyBlock; Jump jumps = null;
// else if (loopBlock.bodyBlock instanceof SequentialBlock for (; allJumps != null; ) {
// && loopBlock.bodyBlock.getSubBlocks()[0] Jump jump = allJumps;
// instanceof ConditionalBlock) allJumps = allJumps.next;
// cb = (ConditionalBlock) loopBlock.bodyBlock.getSubBlocks()[0];
// else if (loopBlock.bodyBlock instanceof SequentialBlock if (jump.prev instanceof ReturnBlock) {
// && loopType == LoopBlock.WHILE) { /* This jump is implicit */
// loopType = LoopBlock.DOWHILE; jump.prev.removeJump();
// SequentialBlock sequBlock = (SequentialBlock) loopBlock.bodyBlock; continue;
// while (sequBlock.subBlocks[1] instanceof SequentialBlock) }
// sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; jump.next = jumps;
// if (sequBlock.subBlocks[1] instanceof ConditionalBlock) jumps = jump;
// cb = (ConditionalBlock) sequBlock.subBlocks[1]; }
// }
/* Try to eliminate as many jumps as possible.
// if (cb != null */
// && cb.trueBlock.jump.destination.addr == getNextAddr()) { jumps = resolveSomeJumps(jumps, END_OF_METHOD);
// loopBlock.moveJump(cb.trueBlock.jump);
// loopBlock.setCondition(cb.getInstruction().negate()); next_jump:
// loopBlock.setType(loopType); for (; jumps != null; jumps = jumps.next) {
// loopBlock.moveDefinitions(cb, null);
// cb.removeBlock(); 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) { public boolean doT1(int start, int end) {
/* If there are no jumps to the beginning of this flow block /* If there are no jumps to the beginning of this flow block
@ -915,9 +1041,8 @@ public class FlowBlock {
*/ */
if (!predecessors.contains(this)) if (!predecessors.contains(this))
return false; return false;
Enumeration preds = predecessors.elements(); for (Iterator i = predecessors.iterator(); i.hasNext(); ) {
while (preds.hasMoreElements()) { FlowBlock predFlow = (FlowBlock) i.next();
FlowBlock predFlow = (FlowBlock) preds.nextElement();
if (predFlow != null && predFlow != this if (predFlow != null && predFlow != this
&& predFlow.addr >= start && predFlow.addr < end) { && predFlow.addr >= start && predFlow.addr < end) {
return false; return false;
@ -926,10 +1051,11 @@ public class FlowBlock {
checkConsistent(); checkConsistent();
Jump jumps = (Jump) successors.remove(this); SuccessorInfo succInfo = (SuccessorInfo) successors.remove(this);
/* Update the in/out-Vectors now */ /* Update the in/out-Vectors now */
updateInOut(this, jumps); updateInOut(this, succInfo);
Jump jumps = succInfo.jumps;
StructuredBlock bodyBlock = block; StructuredBlock bodyBlock = block;
@ -1061,7 +1187,7 @@ public class FlowBlock {
/* remove ourself from the predecessor list. /* remove ourself from the predecessor list.
*/ */
predecessors.removeElement(this); predecessors.remove(this);
lastModified = block; lastModified = block;
doTransformations(); doTransformations();
// mergeCondition(); // mergeCondition();
@ -1072,81 +1198,6 @@ public class FlowBlock {
return true; 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() { public void doTransformations() {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Transformation: "+this); GlobalOptions.err.println("before Transformation: "+this);
@ -1269,12 +1320,12 @@ public class FlowBlock {
* lie in range [start,end). Otherwise * lie in range [start,end). Otherwise
* we have no chance to combine succ * we have no chance to combine succ
*/ */
Enumeration enum = succ.predecessors.elements(); for (Iterator i = succ.predecessors.iterator();
while (enum.hasMoreElements()) { i.hasNext(); ) {
int predAddr = int predAddr = ((FlowBlock)i.next()).addr;
((FlowBlock)enum.nextElement()).addr;
if (predAddr < start || predAddr >= end) { if (predAddr < start || predAddr >= end) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println GlobalOptions.err.println
("breaking analyze(" ("breaking analyze("
+ start + ", " + end + "); " + start + ", " + end + "); "
@ -1331,7 +1382,7 @@ public class FlowBlock {
* until nothing more is possible. * until nothing more is possible.
*/ */
while (nextFlow.analyze(getNextAddr(), end)) while (nextFlow.analyze(getNextAddr(), end))
changed = changed || true; changed = true;
if (nextFlow.addr != getNextAddr()) if (nextFlow.addr != getNextAddr())
break; break;
@ -1344,31 +1395,34 @@ public class FlowBlock {
|| (nextFlow.predecessors.size() > 1 || (nextFlow.predecessors.size() > 1
&& (lastFlow == null && (lastFlow == null
|| !nextFlow.predecessors.contains(lastFlow))) || !nextFlow.predecessors.contains(lastFlow)))
|| ((Jump)successors.get(nextFlow)).next != null) || (((SuccessorInfo)successors.get(nextFlow))
.jumps.next != null))
break; break;
checkConsistent(); checkConsistent();
Jump jumps = (Jump) successors.remove(nextFlow); /* note that this info only contains
/* note that this is the single caseBlock jump */ * the single caseBlock jump */
SuccessorInfo info = (SuccessorInfo)
successors.remove(nextFlow);
if (nextFlow.predecessors.size() == 2) { if (nextFlow.predecessors.size() == 2) {
Jump lastJumps = SuccessorInfo lastInfo = (SuccessorInfo)
(Jump) lastFlow.successors.remove(nextFlow); lastFlow.successors.remove(nextFlow);
/* Do the in/out analysis with all jumps /* Do the in/out analysis with all jumps
* Note that this won't update lastFlow.in, but * Note that this won't update lastFlow.in, but
* this will not be used anymore. * this will not be used anymore.
*/ */
jumps.next = lastJumps; info.kill.retainAll(lastInfo.kill);
updateInOut(nextFlow, jumps); info.gen.addAll(lastInfo.gen);
lastJumps = Jump lastJumps = lastFlow.resolveSomeJumps
lastFlow.resolveSomeJumps(lastJumps, nextFlow); (lastInfo.jumps, nextFlow);
lastFlow.resolveRemaining(lastJumps); lastFlow.resolveRemaining(lastJumps);
switchBlock.caseBlocks[last+1].isFallThrough = true; switchBlock.caseBlocks[last+1].isFallThrough = true;
} else }
updateInOut(nextFlow, jumps); updateInOut(nextFlow, info);
if (lastFlow != null) { if (lastFlow != null) {
lastFlow.block.replace lastFlow.block.replace
@ -1407,54 +1461,72 @@ public class FlowBlock {
* Mark the flow block as first flow block in a method. * Mark the flow block as first flow block in a method.
*/ */
public void makeStartBlock() { public void makeStartBlock() {
predecessors.addElement(null); predecessors.add(null);
} }
public void removeSuccessor(Jump jump) { public void removeSuccessor(Jump jump) {
Jump destJumps = (Jump) successors.get(jump.destination); SuccessorInfo destInfo
= (SuccessorInfo) successors.get(jump.destination);
Jump prev = null; Jump prev = null;
Jump destJumps = destInfo.jumps;
while (destJumps != jump && destJumps != null) { while (destJumps != jump && destJumps != null) {
prev = destJumps; prev = destJumps;
destJumps = destJumps.next; destJumps = destJumps.next;
} }
if (destJumps == null) if (destJumps == null)
throw new AssertError(addr+": removing non existent jump: " + jump); throw new IllegalArgumentException
(addr+": removing non existent jump: " + jump);
if (prev != null) if (prev != null)
prev.next = destJumps.next; prev.next = destJumps.next;
else { else {
if (destJumps.next == null) { if (destJumps.next == null) {
successors.remove(jump.destination); successors.remove(jump.destination);
jump.destination.predecessors.removeElement(this); jump.destination.predecessors.remove(this);
} else } else
successors.put(jump.destination, destJumps.next); destInfo.jumps = destJumps.next;
} }
} }
public void addSuccessor(Jump jump) { public Jump getJumps(FlowBlock dest) {
jump.next = (Jump) successors.get(jump.destination); return ((SuccessorInfo) successors.get(dest)).jumps;
if (jump.next == null && jump.destination != END_OF_METHOD) }
jump.destination.predecessors.addElement(this);
public Jump removeJumps(FlowBlock dest) {
return ((SuccessorInfo) successors.remove(dest)).jumps;
}
successors.put(jump.destination, jump); public Set getSuccessors() {
return successors.keySet();
}
public void addSuccessor(Jump 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 * This is called after the analysis is completely done. It
* will remove all PUSH/stack_i expressions, (if the bytecode * will remove all PUSH/stack_i expressions, (if the bytecode
* is correct). * is correct).
* @return false if the bytecode isn't correct and stack mapping * @return true, if the stack mapping succeeded.
* didn't worked.
*/ */
public final boolean mapStackToLocal() { public final boolean mapStackToLocal() {
// try { mapStackToLocal(VariableStack.EMPTY);
mapStackToLocal(VariableStack.EMPTY); return true;
return true;
// } catch (RuntimeException ex) {
// GlobalOptions.err.println("Can't resolve all PUSHes, "
// +"this is probably illegal bytecode:");
// ex.printStackTrace(GlobalOptions.err);
// return false;
// }
} }
/** /**
@ -1472,7 +1544,8 @@ public class FlowBlock {
block.mapStackToLocal(initialStack); block.mapStackToLocal(initialStack);
Iterator iter = successors.values().iterator(); Iterator iter = successors.values().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
Jump jumps = (Jump) iter.next(); SuccessorInfo succInfo = (SuccessorInfo) iter.next();
Jump jumps = succInfo.jumps;
VariableStack stack; VariableStack stack;
FlowBlock succ = jumps.destination; FlowBlock succ = jumps.destination;
if (succ == END_OF_METHOD) if (succ == END_OF_METHOD)
@ -1509,44 +1582,76 @@ public class FlowBlock {
nextByAddr.removeOnetimeLocals(); 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) { public void mergeParams(LocalInfo[] param) {
// Now we promote the final (maybe slow) in set analysis
promoteInSets();
VariableSet paramSet = new VariableSet(param); VariableSet paramSet = new VariableSet(param);
in.merge(paramSet); 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(); block.propagateUsage();
SimpleSet declared = new SimpleSet(); Set done = new SimpleSet();
for (int i=0; i < param.length; i++) { done.addAll(in);
declared.add(param[i]); block.makeDeclaration(done);
} if (nextByAddr != null)
block.makeDeclaration(declared); nextByAddr.makeDeclaration();
} }
/** /**
* Simplify all reachable flowblocks, that are not already * Make declarations. It will determine, where in each block the
* simplified, i.e. that don't occur in doneSet. *
*/ */
private void simplify(Set doneSet) { public void makeDeclaration(LocalInfo[] param) {
if (doneSet.contains(this)) makeDeclaration();
return;
doneSet.add(this);
block.simplify();
Iterator iter = successors.keySet().iterator();
while (iter.hasNext()) {
FlowBlock succ = (FlowBlock)iter.next();
succ.simplify(doneSet);
}
} }
/**
* Simplify this and all following flowblocks.
*/
public void simplify() { public void simplify() {
if (successors.size() == 0) { block.simplify();
// optimize default path. if (nextByAddr != null)
block.simplify(); nextByAddr.simplify();
return;
}
simplify(new SimpleSet());
} }
/** /**
@ -1570,6 +1675,20 @@ public class FlowBlock {
block.dumpSource(writer); 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) if (nextByAddr != null)
nextByAddr.dumpSource(writer); nextByAddr.dumpSource(writer);
} }
@ -1618,9 +1737,24 @@ public class FlowBlock {
} }
writer.tab(); writer.tab();
block.dumpSource(writer); 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(); return strw.toString();
} catch (java.io.IOException ex) { } catch (java.io.IOException ex) {
return super.toString(); return super.toString();
} }
} }
} }

@ -24,6 +24,12 @@ import jode.expr.Expression;
import jode.type.Type; import jode.type.Type;
import jode.util.SimpleSet; 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 * An IfThenElseBlock is the structured block representing an if
* instruction. The else part may be null. * instruction. The else part may be null.
@ -132,8 +138,8 @@ public class IfThenElseBlock extends StructuredBlock {
elseBlock.removePush(); elseBlock.removePush();
} }
public SimpleSet getDeclarables() { public Set getDeclarables() {
SimpleSet used = new SimpleSet(); Set used = new SimpleSet();
cond.fillDeclarables(used); cond.fillDeclarables(used);
return used; return used;
} }

@ -26,6 +26,12 @@ import jode.expr.StoreInstruction;
import jode.expr.LocalStoreOperator; import jode.expr.LocalStoreOperator;
import jode.util.SimpleSet; import jode.util.SimpleSet;
///#ifdef JDK12
///import java.util.Set;
///#else
import jode.util.Set;
///#endif
/** /**
* This is the structured block for atomic instructions. * 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. In that case mark this as declaration and return the
* variable. * variable.
*/ */
public void checkDeclaration(SimpleSet declareSet) { public void checkDeclaration(Set declareSet) {
if (instr instanceof StoreInstruction if (instr instanceof StoreInstruction
&& (((StoreInstruction)instr).getLValue() && (((StoreInstruction)instr).getLValue()
instanceof LocalStoreOperator)) { instanceof LocalStoreOperator)) {
@ -126,7 +132,7 @@ public class InstructionBlock extends InstructionContainer {
* is marked as used, but not done. * is marked as used, but not done.
* @param done The set of the already declare variables. * @param done The set of the already declare variables.
*/ */
public void makeDeclaration(SimpleSet done) { public void makeDeclaration(Set done) {
super.makeDeclaration(done); super.makeDeclaration(done);
checkDeclaration(declare); checkDeclaration(declare);
} }

@ -24,6 +24,12 @@ import jode.expr.InvokeOperator;
import jode.expr.LocalVarOperator; import jode.expr.LocalVarOperator;
import jode.util.SimpleSet; 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. * 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) { public InstructionContainer(Expression instr, Jump jump) {
this(instr); this(instr);
setJump(jump); 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. * Fill all in variables into the given VariableSet.
* @param in The VariableSet, the in variables should be stored to. * @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) if (instr != null)
instr.fillInGenSet(in, gen); instr.fillInGenSet(in, gen);
} }
public SimpleSet getDeclarables() { public Set getDeclarables() {
SimpleSet used = new SimpleSet(); Set used = new SimpleSet();
if (instr != null) if (instr != null)
instr.fillDeclarables(used); instr.fillDeclarables(used);
return used; return used;

@ -39,23 +39,6 @@ public class Jump {
*/ */
Jump next; 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 * The stack map. This tells how many objects are on stack at
* begin of the flow block, and to what locals they are maped. * begin of the flow block, and to what locals they are maped.
@ -65,16 +48,12 @@ public class Jump {
public Jump (FlowBlock dest) { public Jump (FlowBlock dest) {
this.destination = dest; this.destination = dest;
kill = new VariableSet();
gen = new VariableSet();
} }
public Jump (Jump jump) { public Jump (Jump jump) {
destination = jump.destination; destination = jump.destination;
next = jump.next; next = jump.next;
jump.next = this; 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) public void dumpSource(jode.decompiler.TabbedPrintWriter writer)
throws java.io.IOException throws java.io.IOException
{ {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_INOUT) != 0) {
writer.println("gen : "+ gen.toString());
writer.println("kill: "+ kill.toString());
}
if (destination == null) if (destination == null)
writer.println ("GOTO null-ptr!!!!!"); writer.println ("GOTO null-ptr!!!!!");
else else

@ -28,6 +28,12 @@ import jode.expr.LocalStoreOperator;
import jode.expr.CombineableOperator; import jode.expr.CombineableOperator;
import jode.util.SimpleSet; 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. * 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 * Remove all variables from set, that we can declare inside the
* loop-block. This is the initializer for for-blocks. * 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) { if (type == FOR && initInstr instanceof StoreInstruction) {
StoreInstruction storeOp = (StoreInstruction) initInstr; StoreInstruction storeOp = (StoreInstruction) initInstr;
if (storeOp.getLValue() instanceof LocalStoreOperator) { if (storeOp.getLValue() instanceof LocalStoreOperator) {
@ -212,8 +218,8 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
} }
} }
public SimpleSet getDeclarables() { public Set getDeclarables() {
SimpleSet used = new SimpleSet(); Set used = new SimpleSet();
if (type == FOR) { if (type == FOR) {
incrInstr.fillDeclarables(used); incrInstr.fillDeclarables(used);
if (initInstr != null) 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. In that case mark this as declaration and return the
* variable. * variable.
*/ */
public void checkDeclaration(SimpleSet declareSet) { public void checkDeclaration(Set declareSet) {
if (initInstr instanceof StoreInstruction if (initInstr instanceof StoreInstruction
&& (((StoreInstruction)initInstr).getLValue() && (((StoreInstruction)initInstr).getLValue()
instanceof LocalStoreOperator)) { instanceof LocalStoreOperator)) {
@ -275,7 +281,7 @@ public class LoopBlock extends StructuredBlock implements BreakableBlock {
* is marked as used, but not done. * is marked as used, but not done.
* @param done The set of the already declare variables. * @param done The set of the already declare variables.
*/ */
public void makeDeclaration(SimpleSet done) { public void makeDeclaration(Set done) {
super.makeDeclaration(done); super.makeDeclaration(done);
if (type == FOR && initInstr != null) if (type == FOR && initInstr != null)
checkDeclaration(declare); checkDeclaration(declare);

@ -19,7 +19,14 @@
package jode.flow; package jode.flow;
import jode.decompiler.LocalInfo; 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 * 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. * Fill all in variables into the given VariableSet.
* @param in The VariableSet, the in variables should be stored to. * @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) {
in.addElement(local); in.add(local);
gen.addElement(local); gen.add(local);
} }
/** /**
@ -59,10 +66,8 @@ public class RetBlock extends StructuredBlock {
return null; return null;
} }
public SimpleSet getDeclarables() { public Set getDeclarables() {
SimpleSet used = new SimpleSet(); return Collections.singleton(local);
used.add(local);
return used;
} }
public void dumpInstruction(jode.decompiler.TabbedPrintWriter writer) public void dumpInstruction(jode.decompiler.TabbedPrintWriter writer)

@ -24,6 +24,12 @@ import jode.expr.LocalStoreOperator;
import jode.expr.StoreInstruction; import jode.expr.StoreInstruction;
import jode.util.SimpleSet; 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 * A sequential block combines exactly two structured blocks to a new
* one. The first sub block mustn't be another sequential block, * 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 * @return all locals that are used in this block or in some sub
* block (this is <i>not</i> the used set). * block (this is <i>not</i> the used set).
*/ */
public SimpleSet propagateUsage() { public Set propagateUsage() {
used = getDeclarables(); used = new SimpleSet();
SimpleSet allUse = new SimpleSet(); Set allUse = new SimpleSet();
SimpleSet childUse0 = subBlocks[0].propagateUsage(); Set childUse0 = subBlocks[0].propagateUsage();
SimpleSet childUse1 = subBlocks[1].propagateUsage(); Set childUse1 = subBlocks[1].propagateUsage();
/* All variables used somewhere inside both sub blocks, are /* All variables used somewhere inside both sub blocks, are
* used in this block, too. * used in this block, too.
* Also the variables used in first block are used in this * Also the variables used in first block are used in this
* block, except when it can be declared locally. (Note that * block, except when it can be declared locally. (Note that
* subBlocks[0].used != childUse0) */ * subBlocks[0].used != childUse0)
*/
used.addAll(subBlocks[0].used); used.addAll(subBlocks[0].used);
if (subBlocks[0] instanceof LoopBlock) if (subBlocks[0] instanceof LoopBlock)
((LoopBlock) subBlocks[0]).removeLocallyDeclareable(used); ((LoopBlock) subBlocks[0]).removeLocallyDeclareable(used);
@ -194,7 +201,7 @@ public class SequentialBlock extends StructuredBlock {
* is marked as used, but not done. * is marked as used, but not done.
* @param done The set of the already declare variables. * @param done The set of the already declare variables.
*/ */
public void makeDeclaration(SimpleSet done) { public void makeDeclaration(Set done) {
super.makeDeclaration(done); super.makeDeclaration(done);
if (subBlocks[0] instanceof InstructionBlock) if (subBlocks[0] instanceof InstructionBlock)
/* An instruction block may declare a variable for us. /* An instruction block may declare a variable for us.

@ -26,9 +26,13 @@ import jode.decompiler.Declarable;
import jode.util.SimpleSet; import jode.util.SimpleSet;
///#ifdef JDK12 ///#ifdef JDK12
///import java.util.Collections;
///import java.util.Iterator; ///import java.util.Iterator;
///import java.util.Set;
///#else ///#else
import jode.util.Collections;
import jode.util.Iterator; import jode.util.Iterator;
import jode.util.Set;
///#endif ///#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. * 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 * The analyzation is done in makeDeclaration
*/ */
SimpleSet declare; Set declare;
SimpleSet done; Set done;
/** /**
* The surrounding structured block. If this is the outermost * 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). * will be moved to this block (may be this).
*/ */
void moveDefinitions(StructuredBlock from, StructuredBlock sub) { 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; i<subs.length - 1; i++)
// moveDefinitions(subs[i], sub);
// from = subs[subs.length-1];
// }
} }
/** /**
@ -347,8 +341,8 @@ public abstract class StructuredBlock {
return false; return false;
} }
public SimpleSet getDeclarables() { public Set getDeclarables() {
return new SimpleSet(); return Collections.EMPTY_SET;
} }
/** /**
@ -359,16 +353,18 @@ public abstract class StructuredBlock {
* *
* @return all locals that are used in this block or in some sub * @return all locals that are used in this block or in some sub
* block (this is <i>not</i> the used set). */ * block (this is <i>not</i> the used set). */
public SimpleSet propagateUsage() { public Set propagateUsage() {
used = getDeclarables(); used = new SimpleSet();
used.addAll(getDeclarables());
StructuredBlock[] subs = getSubBlocks(); StructuredBlock[] subs = getSubBlocks();
SimpleSet allUse = (SimpleSet) used.clone(); Set allUse = new SimpleSet();
allUse.addAll(used);
for (int i=0; i<subs.length; i++) { for (int i=0; i<subs.length; i++) {
SimpleSet childUse = subs[i].propagateUsage(); Set childUse = subs[i].propagateUsage();
/* All variables used in more than one sub blocks, are /* All variables used in more than one sub blocks, are
* used in this block, too. * used in this block, too.
*/ */
SimpleSet intersection = new SimpleSet(); Set intersection = new SimpleSet();
intersection.addAll(childUse); intersection.addAll(childUse);
intersection.retainAll(allUse); intersection.retainAll(allUse);
used.addAll(intersection); used.addAll(intersection);
@ -443,8 +439,10 @@ public abstract class StructuredBlock {
* *
* @param done The set of the already declare variables. * @param done The set of the already declare variables.
*/ */
public void makeDeclaration(SimpleSet done) { public void makeDeclaration(Set done) {
this.done = (SimpleSet) done.clone(); this.done = new SimpleSet();
this.done.addAll(done);
declare = new SimpleSet(); declare = new SimpleSet();
Iterator iter = used.iterator(); Iterator iter = used.iterator();
next_used: next_used:
@ -532,7 +530,7 @@ public abstract class StructuredBlock {
subs[i].checkConsistent(); subs[i].checkConsistent();
} }
if (jump != null && jump.destination != null) { if (jump != null && jump.destination != null) {
Jump jumps = (Jump) flowBlock.successors.get(jump.destination); Jump jumps = (Jump) flowBlock.getJumps(jump.destination);
for (; jumps != jump; jumps = jumps.next) { for (; jumps != jump; jumps = jumps.next) {
if (jumps == null) if (jumps == null)
throw new AssertError("Inconsistency"); throw new AssertError("Inconsistency");
@ -567,7 +565,7 @@ public abstract class StructuredBlock {
* Fill all in variables into the given VariableSet. * Fill all in variables into the given VariableSet.
* @param in The VariableSet, the in variables should be stored to. * @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) {
/* overwritten by InstructionContainer */ /* overwritten by InstructionContainer */
} }

@ -23,6 +23,12 @@ import jode.decompiler.TabbedPrintWriter;
import jode.expr.Expression; import jode.expr.Expression;
import jode.util.SimpleSet; import jode.util.SimpleSet;
///#ifdef JDK12
///import java.util.Set;
///#else
import jode.util.Set;
///#endif
/** /**
* This class represents a synchronized structured block. * This class represents a synchronized structured block.
* *
@ -71,8 +77,8 @@ public class SynchronizedBlock extends StructuredBlock {
return true; return true;
} }
public SimpleSet getDeclarables() { public Set getDeclarables() {
SimpleSet used = new SimpleSet(); Set used = new SimpleSet();
if (object != null) if (object != null)
object.fillDeclarables(used); object.fillDeclarables(used);
else else

@ -62,9 +62,9 @@ public class TransformExceptionHandlers {
Handler second = (Handler) o; Handler second = (Handler) o;
/* First sort by start offsets, highest address first...*/ /* First sort by start offsets, highest address first...*/
if (start.addr != second.start.addr) if (start.getAddr() != second.start.getAddr())
/* this subtraction is save since addresses are only 16 bit */ /* this subtraction is save since addresses are only 16 bit */
return second.start.addr - start.addr; return second.start.getAddr() - start.getAddr();
/* ...Second sort by end offsets, lowest address first... /* ...Second sort by end offsets, lowest address first...
* this will move the innermost blocks to the beginning. */ * this will move the innermost blocks to the beginning. */
@ -72,8 +72,8 @@ public class TransformExceptionHandlers {
return endAddr - second.endAddr; return endAddr - second.endAddr;
/* ...Last sort by handler offsets, lowest first */ /* ...Last sort by handler offsets, lowest first */
if (handler.addr != second.handler.addr) if (handler.getAddr() != second.handler.getAddr())
return handler.addr - second.handler.addr; return handler.getAddr() - second.handler.getAddr();
/* ...Last sort by typecode signature. Shouldn't happen to often. /* ...Last sort by typecode signature. Shouldn't happen to often.
*/ */
@ -104,54 +104,6 @@ public class TransformExceptionHandlers {
handlers.add(new Handler(tryBlock, end, catchBlock, type)); handlers.add(new Handler(tryBlock, end, catchBlock, type));
} }
/**
* 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.<br>
*
* For example this code prints <code>0</code>:
* <pre>
* int a=3;
* try {
* a = 5 / (a=0);
* } catch (DivideByZeroException ex) {
* System.out.println(a);
* }
* </pre>
*
* @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: /* simple try catch block:
* *
@ -230,8 +182,8 @@ public class TransformExceptionHandlers {
* @param subRoutine the FlowBlock of the sub routine. * @param subRoutine the FlowBlock of the sub routine.
*/ */
private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) { private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) {
for (Jump jumps = (Jump)tryFlow.successors.remove(subRoutine); for (Jump jumps = tryFlow.removeJumps(subRoutine);
jumps != null; jumps = jumps.next) { jumps != null; jumps = jumps.next) {
StructuredBlock prev = jumps.prev; StructuredBlock prev = jumps.prev;
prev.removeJump(); prev.removeJump();
@ -296,13 +248,14 @@ public class TransformExceptionHandlers {
} }
public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine) { public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine) {
Iterator iter = tryFlow.successors.entrySet().iterator(); Iterator iter = tryFlow.getSuccessors().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next(); FlowBlock dest = (FlowBlock) iter.next();
Jump jumps = (Jump) entry.getValue(); if (dest == subRoutine)
if (entry.getKey() == subRoutine)
continue; continue;
Jump jumps = tryFlow.getJumps(dest);
for ( ; jumps != null; jumps = jumps.next) { for ( ; jumps != null; jumps = jumps.next) {
StructuredBlock prev = jumps.prev; StructuredBlock prev = jumps.prev;
@ -372,10 +325,10 @@ public class TransformExceptionHandlers {
public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local, public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local,
int startMonExit, int endMonExit) { int startMonExit, int endMonExit) {
FlowBlock subRoutine = null; FlowBlock subRoutine = null;
Iterator succs = tryFlow.successors.values().iterator(); Iterator succs = tryFlow.getSuccessors().iterator();
dest_loop: dest_loop:
while (succs.hasNext()) { while (succs.hasNext()) {
for (Jump jumps = (Jump) succs.next(); for (Jump jumps = tryFlow.getJumps((FlowBlock) succs.next());
jumps != null; jumps = jumps.next) { jumps != null; jumps = jumps.next) {
StructuredBlock prev = jumps.prev; StructuredBlock prev = jumps.prev;
@ -628,10 +581,10 @@ public class TransformExceptionHandlers {
/* Check if the try block has no exit (except throws) /* Check if the try block has no exit (except throws)
*/ */
Jump throwJumps = (Jump) Jump throwJumps = tryFlow.getJumps(FlowBlock.END_OF_METHOD);
tryFlow.successors.get(FlowBlock.END_OF_METHOD); if (tryFlow.getSuccessors().size() > 1
if (tryFlow.successors.size() > 1 || (tryFlow.getSuccessors().size() > 0
|| (tryFlow.successors.size() > 0 && throwJumps == null)) && throwJumps == null))
return false; return false;
for (/**/; throwJumps != null; throwJumps = throwJumps.next) { for (/**/; throwJumps != null; throwJumps = throwJumps.next) {
@ -649,7 +602,7 @@ public class TransformExceptionHandlers {
finallyBlock.replace(catchFlow.block); finallyBlock.replace(catchFlow.block);
transformSubRoutine(finallyBlock); transformSubRoutine(finallyBlock);
updateInOutCatch(tryFlow, catchFlow); tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeAddr(catchFlow); tryFlow.mergeAddr(catchFlow);
finallyBlock = catchFlow.block; finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow); tryFlow.mergeSuccessors(catchFlow);
@ -667,7 +620,7 @@ public class TransformExceptionHandlers {
checkAndRemoveJSR(tryFlow, subRoutine); checkAndRemoveJSR(tryFlow, subRoutine);
updateInOutCatch(tryFlow, subRoutine); tryFlow.updateInOutCatch(subRoutine);
tryFlow.mergeAddr(subRoutine); tryFlow.mergeAddr(subRoutine);
tryFlow.mergeSuccessors(subRoutine); tryFlow.mergeSuccessors(subRoutine);
finallyBlock = subRoutine.block; finallyBlock = subRoutine.block;
@ -676,9 +629,9 @@ public class TransformExceptionHandlers {
* and the jump of the throw instruction. * and the jump of the throw instruction.
*/ */
catchBlock.getSubBlocks()[0].getSubBlocks()[0] catchBlock.getSubBlocks()[0].getSubBlocks()[0]
.jump.destination.predecessors.removeElement(catchFlow); .jump.destination.predecessors.remove(catchFlow);
catchBlock.getSubBlocks()[1] catchBlock.getSubBlocks()[1]
.jump.destination.predecessors.removeElement(catchFlow); .jump.destination.predecessors.remove(catchFlow);
} }
TryBlock tryBlock = (TryBlock)tryFlow.block; TryBlock tryBlock = (TryBlock)tryFlow.block;
@ -715,19 +668,18 @@ public class TransformExceptionHandlers {
*/ */
FlowBlock succ = (firstInstr.jump != null) ? FlowBlock succ = (firstInstr.jump != null) ?
firstInstr.jump.destination : null; firstInstr.jump.destination : null;
boolean hasExit = false; boolean hasExit = false;
Iterator iter = tryFlow.successors.entrySet().iterator(); Iterator iter = tryFlow.getSuccessors().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next(); FlowBlock dest = (FlowBlock) iter.next();
Object key = entry.getKey(); if (dest == succ)
if (key == succ)
continue; continue;
if (key != FlowBlock.END_OF_METHOD) { if (dest != FlowBlock.END_OF_METHOD) {
/* There is another exit in the try block, bad */ /* There is another exit in the try block, bad */
return false; return false;
} }
for (Jump throwJumps = (Jump) entry.getValue(); for (Jump throwJumps = (Jump) tryFlow.getJumps(dest);
throwJumps != null; throwJumps = throwJumps.next) { throwJumps != null; throwJumps = throwJumps.next) {
if (!(throwJumps.prev instanceof ThrowBlock)) { if (!(throwJumps.prev instanceof ThrowBlock)) {
/* There is a return exit in the try block */ /* There is a return exit in the try block */
@ -741,8 +693,8 @@ public class TransformExceptionHandlers {
tryFlow.mergeAddr(catchFlow); tryFlow.mergeAddr(catchFlow);
if (succ != null) { if (succ != null) {
Jump jumps = (Jump) tryFlow.successors.remove(succ); Jump jumps = tryFlow.removeJumps(succ);
succ.predecessors.removeElement(tryFlow); succ.predecessors.remove(tryFlow);
/* Handle the jumps in the tryFlow. /* Handle the jumps in the tryFlow.
*/ */
jumps = tryFlow.resolveSomeJumps(jumps, succ); jumps = tryFlow.resolveSomeJumps(jumps, succ);
@ -765,7 +717,7 @@ public class TransformExceptionHandlers {
if (succ != null && succ.predecessors.size() == 1) { if (succ != null && succ.predecessors.size() == 1) {
while (succ.analyze(catchFlow.getNextAddr(), end)); while (succ.analyze(catchFlow.getNextAddr(), end));
tryFlow.mergeAddr(succ); tryFlow.mergeAddr(succ);
tryFlow.successors.remove(succ); tryFlow.removeJumps(succ);
newBlock.setCatchBlock(succ.block); newBlock.setCatchBlock(succ.block);
tryFlow.mergeSuccessors(succ); tryFlow.mergeSuccessors(succ);
} else { } else {
@ -792,23 +744,23 @@ public class TransformExceptionHandlers {
Handler last = null; Handler last = null;
for (Iterator i = handlers.iterator(); i.hasNext(); ) { for (Iterator i = handlers.iterator(); i.hasNext(); ) {
Handler exc = (Handler) i.next(); Handler exc = (Handler) i.next();
int start = exc.start.addr; int start = exc.start.getAddr();
int end = exc.endAddr; int end = exc.endAddr;
int handler = exc.handler.addr; int handler = exc.handler.getAddr();
if (start >= end || handler < end) if (start >= end || handler < end)
throw new AssertError throw new AssertError
("ExceptionHandler order failed: not " ("ExceptionHandler order failed: not "
+ start + " < " + end + " <= " + handler); + start + " < " + end + " <= " + handler);
if (last != null if (last != null
&& (last.start.addr != start || last.endAddr != end)) { && (last.start.getAddr() != start || last.endAddr != end)) {
/* The last handler does catch another range. /* The last handler does catch another range.
* Due to the order: * 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 throw new AssertError
("Exception handlers ranges are intersecting: [" ("Exception handlers ranges are intersecting: ["
+ last.start.addr+", "+last.endAddr+"] and [" + last.start.getAddr()+", "+last.endAddr+"] and ["
+ start+", "+end+"]."); + start+", "+end+"].");
} }
last = exc; last = exc;
@ -836,11 +788,11 @@ public class TransformExceptionHandlers {
& GlobalOptions.DEBUG_ANALYZE) != 0) & GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println GlobalOptions.err.println
("analyzeTry(" ("analyzeTry("
+ exc.start.addr + ", " + exc.endAddr+")"); + exc.start.getAddr() + ", " + exc.endAddr+")");
while (tryFlow.analyze(tryFlow.addr, exc.endAddr)); while (tryFlow.analyze(tryFlow.getAddr(), exc.endAddr));
if (last == null if (last == null
|| last.start.addr != exc.start.addr || last.start.getAddr() != exc.start.getAddr()
|| last.endAddr != exc.endAddr) { || last.endAddr != exc.endAddr) {
/* The last handler does catch another range. /* The last handler does catch another range.
* Create a new try block. * Create a new try block.
@ -869,7 +821,7 @@ public class TransformExceptionHandlers {
*/ */
EmptyBlock jump = new EmptyBlock(new Jump(catchFlow)); EmptyBlock jump = new EmptyBlock(new Jump(catchFlow));
FlowBlock newFlow = new FlowBlock(catchFlow.method, FlowBlock newFlow = new FlowBlock(catchFlow.method,
catchFlow.addr, 0); catchFlow.getAddr(), 0);
newFlow.setBlock(jump); newFlow.setBlock(jump);
catchFlow.prevByAddr.setNextByAddr(newFlow); catchFlow.prevByAddr.setNextByAddr(newFlow);
newFlow.setNextByAddr(catchFlow); newFlow.setNextByAddr(catchFlow);
@ -879,11 +831,11 @@ public class TransformExceptionHandlers {
& GlobalOptions.DEBUG_ANALYZE) != 0) & GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println GlobalOptions.err.println
("analyzeCatch(" ("analyzeCatch("
+ catchFlow.addr + ", " + endHandler + ")"); + catchFlow.getAddr() + ", " + endHandler + ")");
while (catchFlow.analyze(catchFlow.addr, endHandler)); while (catchFlow.analyze(catchFlow.getAddr(), endHandler));
} }
updateInOutCatch(tryFlow, catchFlow); tryFlow.updateInOutCatch(catchFlow);
if (exc.type != null) if (exc.type != null)
analyzeCatchBlock(exc.type, tryFlow, catchFlow); analyzeCatchBlock(exc.type, tryFlow, catchFlow);
@ -898,8 +850,8 @@ public class TransformExceptionHandlers {
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0) & GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println GlobalOptions.err.println
("analyzeCatch(" + tryFlow.addr + ", " ("analyzeCatch(" + tryFlow.getAddr() + ", "
+ (tryFlow.addr + tryFlow.length) + ") done."); + tryFlow.getNextAddr() + ") done.");
} }
} }
} }

@ -21,6 +21,16 @@ package jode.flow;
import jode.decompiler.LocalInfo; import jode.decompiler.LocalInfo;
import jode.util.ArrayEnum; 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 * This class represents a set of Variables, which are mainly used in
* the in/out sets of StructuredBlock. The type of the Variables is * 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 * Note that a variable set can contain LocalInfos that use the same
* slot, but are different. * slot, but are different.
*/ */
public final class VariableSet implements Cloneable { public final class VariableSet extends AbstractSet implements Cloneable {
LocalInfo[] locals; LocalInfo[] locals;
int count; 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 * Adds a local info to this variable set.
* duplicates.
*/ */
public void addElement(LocalInfo li) { public boolean add(Object li) {
if (contains(li))
return false;
grow(1); grow(1);
locals[count++] = li; locals[count++] = (LocalInfo) li;
return true;
} }
/** /**
* Checks if the variable set contains the given local info. * Checks if the variable set contains the given local info.
*/ */
public boolean contains(LocalInfo li) { public boolean contains(Object li) {
li = li.getLocalInfo(); li = ((LocalInfo) li).getLocalInfo();
for (int i=0; i<count;i++) for (int i=0; i<count;i++)
if (locals[i].getLocalInfo() == li) if (locals[i].getLocalInfo() == li)
return true; return true;
return false; return false;
} }
/**
* Checks if the variable set contains a local with the given name.
*/
public final boolean containsSlot(int slot) {
return findSlot(slot) != null;
}
/** /**
* Checks if the variable set contains a local with the given name. * Checks if the variable set contains a local with the given name.
*/ */
@ -98,39 +117,63 @@ public final class VariableSet implements Cloneable {
} }
/** /**
* Removes a local info from this variable set. * Checks if the variable set contains a local with the given slot.
*/ */
public void removeElement(LocalInfo li) { public LocalInfo findSlot(int slot) {
li = li.getLocalInfo();
for (int i=0; i<count;i++) for (int i=0; i<count;i++)
if (locals[i].getLocalInfo() == li) if (locals[i].getSlot() == slot)
locals[i] = locals[--count]; return locals[i];
return null;
} }
public LocalInfo elementAt(int i) { /**
return locals[i]; * Removes a local info from this variable set.
*/
public boolean remove(Object li) {
li = ((LocalInfo) li).getLocalInfo();
for (int i=0; i<count;i++) {
if (locals[i].getLocalInfo() == li) {
locals[i] = locals[--count];
return true;
}
}
return false;
} }
public int size() { public int size() {
return count; return count;
} }
public Iterator iterator() {
return new Iterator() {
int pos = 0;
public boolean hasNext() {
return pos < count;
}
public Object next() {
return locals[pos++];
}
public void remove() {
if (pos < count)
System.arraycopy(locals, pos,
locals, pos-1, count - pos);
count--;
pos--;
}
};
}
/** /**
* Removes everything from this variable set. * Removes everything from this variable set.
*/ */
public void removeAllElements() { public void clear() {
locals = null; locals = null;
count = 0; count = 0;
} }
public java.util.Enumeration elements() {
return new ArrayEnum(count, locals);
}
public boolean isEmpty() {
return count == 0;
}
public Object clone() { public Object clone() {
try { try {
VariableSet other = (VariableSet) super.clone(); VariableSet other = (VariableSet) super.clone();
@ -144,39 +187,6 @@ public final class VariableSet implements Cloneable {
} }
} }
/**
* Merges the current VariableSet with another. For all slots occuring
* in both variable sets, all corresponding LocalInfos are merged.
* The variable sets are not changed (use union for this).
* @return The merged variables.
* @param vs the other variable set. */
public VariableSet merge(VariableSet vs) {
VariableSet merged = new VariableSet();
merged.grow(Math.min(count,vs.count));
big_loop:
for (int i=0; i<count; i++) {
LocalInfo li1 = locals[i];
int slot = li1.getSlot();
boolean didMerge = false;
for (int k=0; k< merged.count; k++) {
if (slot == merged.locals[k].getSlot()) {
/* This slot was already merged. */
li1.combineWith(merged.locals[k]);
continue big_loop;
}
}
for (int j=0; j<vs.count; j++) {
if (li1.getSlot() == vs.locals[j].getSlot()) {
li1.combineWith(vs.locals[j]);
didMerge = true;
}
}
if (didMerge)
merged.locals[merged.count++] = li1;
}
return merged;
}
/** /**
* Intersects the current VariableSet with another and returns the * Intersects the current VariableSet with another and returns the
* intersection. The existing VariableSet are not changed. * intersection. The existing VariableSet are not changed.
@ -189,154 +199,26 @@ public final class VariableSet implements Cloneable {
for (int i=0; i<count; i++) { for (int i=0; i<count; i++) {
LocalInfo li = locals[i]; LocalInfo li = locals[i];
int slot = li.getSlot(); int slot = li.getSlot();
for (int j=0; j<vs.count; j++) { if (vs.containsSlot(slot)
if (slot == vs.locals[j].getSlot()) { && !intersection.containsSlot(slot))
for (int k=0; k<intersection.count; k++) { intersection.locals[intersection.count++] = li.getLocalInfo();
if (slot == intersection.locals[k].getSlot())
continue big_loop;
}
intersection.locals[intersection.count++]
= li.getLocalInfo();
continue big_loop;
}
}
} }
return intersection; return intersection;
} }
/**
* Intersects the current VariableSet with another and returns the
* intersection. The existing VariableSet are not changed.
* @param vs the other variable set.
*/
public VariableSet intersectExact(VariableSet vs) {
VariableSet intersection = new VariableSet();
intersection.grow(Math.min(count, vs.count));
big_loop:
for (int i=0; i<count; i++) {
LocalInfo li1 = locals[i].getLocalInfo();
for (int j=0; j<vs.count; j++) {
if (li1 == vs.locals[j].getLocalInfo()) {
if (!intersection.contains(li1))
intersection.locals[intersection.count++] = li1;
continue big_loop;
}
}
}
return intersection;
}
/**
* Union the other variable set to the current.
*/
public void unionExact(VariableSet vs) {
grow(vs.count);
big_loop:
for (int i=0; i< vs.count; i++) {
LocalInfo li2 = (vs.locals[i]).getLocalInfo();
/* check if this particular local info is already in the set */
for (int j=0; j< count; j++) {
LocalInfo li1 = (locals[j]).getLocalInfo();
if (li1 == li2)
/* Yes it is, take next variable */
continue big_loop;
}
locals[count++] = li2;
}
}
/**
* Add the other variable set to the current, except when the slot
* is already in the current set.
*/
public void add(VariableSet vs) {
grow(vs.count);
big_loop:
for (int i=0; i< vs.count; i++) {
LocalInfo li2 = vs.locals[i];
int slot2 = li2.getSlot();
/* check if this slot is already in the current set */
for (int j=0; j< count; j++) {
if (locals[j].getSlot() == slot2)
/* Yes it is, take next variable */
continue big_loop;
}
locals[count++] = li2.getLocalInfo();
}
}
/** /**
* Add the variables in gen to the current set, unless there are * Add the variables in gen to the current set, unless there are
* variables in kill using the same slot. * variables in kill using the same slot.
* @param gen The gen set. * @param gen The gen set.
* @param kill The kill set. * @param kill The kill set.
*/ */
public void mergeGenKill(VariableSet gen, VariableSet kill) { public void mergeGenKill(Collection gen, SlotSet kill) {
grow(gen.count); grow(gen.size());
big_loop:
for (int i=0; i< gen.count; i++) {
LocalInfo li2 = gen.locals[i];
int slot = li2.getSlot();
/* check if this slot is in the kill set) */
for (int j=0; j< kill.count; j++) {
if (slot == kill.locals[j].getSlot())
/* Yes it is, take next variable */
continue big_loop;
}
locals[count++] = li2.getLocalInfo();
}
}
/**
* Subtract the other variable set from this one. This removes
* every variable from this set, that uses a slot in the other
* variable set.
* @param vs The other variable set.
*/
public void subtract(VariableSet vs) {
big_loop: big_loop:
for (int i=0; i < count;) { for (Iterator i = gen.iterator(); i.hasNext(); ) {
LocalInfo li1 = locals[i]; LocalInfo li2 = (LocalInfo) i.next();
int slot = li1.getSlot(); if (!kill.containsSlot(li2.getSlot()))
for (int j=0; j<vs.count; j++) { add(li2.getLocalInfo());
if (slot == vs.locals[j].getSlot()) {
/* remove the element from this variable list. */
locals[i] = locals[--count].getLocalInfo();
continue big_loop;
}
}
i++;
}
}
/**
* Subtract the other variable set from this one. This removes
* every variable from this set, that is in the other
* variable set.
* @param vs The other variable set.
*/
public void subtractExact(VariableSet vs) {
big_loop:
for (int i=0; i < count;) {
LocalInfo li1 = locals[i].getLocalInfo();
for (int j=0; j<vs.count; j++) {
if (li1 == vs.locals[j].getLocalInfo()) {
/* remove the element from this variable list. */
locals[i] = locals[--count].getLocalInfo();
continue big_loop;
}
}
i++;
}
}
public String toString() {
StringBuffer result = new StringBuffer("[");
for (int i=0; i < count; i++) {
if (i>0)
result.append(", ");
result.append(locals[i].getName());
} }
return result.append("]").toString();
} }
} }

Loading…
Cancel
Save