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 25 years ago
parent efdfcbf7bc
commit ec1e63532c
  1. 18
      jode/jode/flow/CatchBlock.java
  2. 4
      jode/jode/flow/CombineIfGotoExpressions.java
  3. 640
      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. 270
      jode/jode/flow/VariableSet.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.

@ -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;

@ -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.<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
@ -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();
}
}
}

@ -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;
}

@ -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);
}

@ -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;

@ -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

@ -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);

@ -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)

@ -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 <i>not</i> 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.

@ -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; i<subs.length - 1; i++)
// moveDefinitions(subs[i], sub);
// from = subs[subs.length-1];
// }
}
/**
@ -347,8 +341,8 @@ public abstract class StructuredBlock {
return false;
}
public SimpleSet getDeclarables() {
return new SimpleSet();
public Set getDeclarables() {
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
* block (this is <i>not</i> 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<subs.length; i++) {
SimpleSet childUse = subs[i].propagateUsage();
Set childUse = subs[i].propagateUsage();
/* All variables used in more than one sub blocks, are
* used in this block, too.
*/
SimpleSet intersection = new SimpleSet();
Set intersection = new SimpleSet();
intersection.addAll(childUse);
intersection.retainAll(allUse);
used.addAll(intersection);
@ -443,8 +439,10 @@ public abstract class StructuredBlock {
*
* @param done The set of the already declare variables.
*/
public void makeDeclaration(SimpleSet done) {
this.done = (SimpleSet) done.clone();
public void makeDeclaration(Set done) {
this.done = new SimpleSet();
this.done.addAll(done);
declare = new SimpleSet();
Iterator iter = used.iterator();
next_used:
@ -532,7 +530,7 @@ public abstract class StructuredBlock {
subs[i].checkConsistent();
}
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) {
if (jumps == null)
throw new AssertError("Inconsistency");
@ -567,7 +565,7 @@ public abstract class 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) {
/* overwritten by InstructionContainer */
}

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

@ -62,9 +62,9 @@ public class TransformExceptionHandlers {
Handler second = (Handler) o;
/* 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 */
return second.start.addr - start.addr;
return second.start.getAddr() - start.getAddr();
/* ...Second sort by end offsets, lowest address first...
* this will move the innermost blocks to the beginning. */
@ -72,8 +72,8 @@ public class TransformExceptionHandlers {
return endAddr - second.endAddr;
/* ...Last sort by handler offsets, lowest first */
if (handler.addr != second.handler.addr)
return handler.addr - second.handler.addr;
if (handler.getAddr() != second.handler.getAddr())
return handler.getAddr() - second.handler.getAddr();
/* ...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));
}
/**
* 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:
*
@ -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.");
}
}
}

@ -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; i<count;i++)
if (locals[i].getLocalInfo() == li)
return true;
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.
*/
@ -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) {
li = li.getLocalInfo();
public LocalInfo findSlot(int slot) {
for (int i=0; i<count;i++)
if (locals[i].getLocalInfo() == li)
locals[i] = locals[--count];
if (locals[i].getSlot() == slot)
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() {
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.
*/
public void removeAllElements() {
public void clear() {
locals = null;
count = 0;
}
public java.util.Enumeration elements() {
return new ArrayEnum(count, locals);
}
public boolean isEmpty() {
return count == 0;
}
public Object clone() {
try {
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
* intersection. The existing VariableSet are not changed.
@ -189,154 +199,26 @@ public final class VariableSet implements Cloneable {
for (int i=0; i<count; i++) {
LocalInfo li = locals[i];
int slot = li.getSlot();
for (int j=0; j<vs.count; j++) {
if (slot == vs.locals[j].getSlot()) {
for (int k=0; k<intersection.count; k++) {
if (slot == intersection.locals[k].getSlot())
continue big_loop;
}
intersection.locals[intersection.count++]
= li.getLocalInfo();
continue big_loop;
}
}
if (vs.containsSlot(slot)
&& !intersection.containsSlot(slot))
intersection.locals[intersection.count++] = li.getLocalInfo();
}
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
* variables in kill using the same slot.
* @param gen The gen set.
* @param kill The kill set.
*/
public void mergeGenKill(VariableSet gen, VariableSet kill) {
grow(gen.count);
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) {
public void mergeGenKill(Collection gen, SlotSet kill) {
grow(gen.size());
big_loop:
for (int i=0; i < count;) {
LocalInfo li1 = locals[i];
int slot = li1.getSlot();
for (int j=0; j<vs.count; j++) {
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());
for (Iterator i = gen.iterator(); i.hasNext(); ) {
LocalInfo li2 = (LocalInfo) i.next();
if (!kill.containsSlot(li2.getSlot()))
add(li2.getLocalInfo());
}
return result.append("]").toString();
}
}

Loading…
Cancel
Save