|
|
|
@ -28,11 +28,13 @@ import jode.expr.CombineableOperator; |
|
|
|
|
import jode.util.SimpleMap; |
|
|
|
|
import jode.util.SimpleSet; |
|
|
|
|
|
|
|
|
|
import @COLLECTIONS@.Map; |
|
|
|
|
import @COLLECTIONS@.Iterator; |
|
|
|
|
import @COLLECTIONS@.Set; |
|
|
|
|
import @COLLECTIONS@.ArrayList; |
|
|
|
|
import @COLLECTIONS@.List; |
|
|
|
|
///#def COLLECTIONS java.util
|
|
|
|
|
import java.util.Map; |
|
|
|
|
import java.util.Iterator; |
|
|
|
|
import java.util.Set; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.List; |
|
|
|
|
///#enddef
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* A flow block is the structure of which the flow graph consists. A |
|
|
|
@ -49,16 +51,15 @@ import @COLLECTIONS@.List; |
|
|
|
|
public class FlowBlock { |
|
|
|
|
|
|
|
|
|
public static FlowBlock END_OF_METHOD; |
|
|
|
|
public static FlowBlock NEXT_BY_ADDR; |
|
|
|
|
// public static FlowBlock NEXT_BY_ADDR;
|
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
END_OF_METHOD = new FlowBlock(null, Integer.MAX_VALUE); |
|
|
|
|
END_OF_METHOD.appendBlock(new EmptyBlock(), 0); |
|
|
|
|
END_OF_METHOD = new FlowBlock(null, Integer.MAX_VALUE, null); |
|
|
|
|
END_OF_METHOD.label = "END_OF_METHOD"; |
|
|
|
|
|
|
|
|
|
NEXT_BY_ADDR = new FlowBlock(null, -1); |
|
|
|
|
NEXT_BY_ADDR.appendBlock(new DescriptionBlock("FALL THROUGH"), 0); |
|
|
|
|
NEXT_BY_ADDR.label = "NEXT_BY_ADDR"; |
|
|
|
|
// NEXT_BY_ADDR = new FlowBlock(null, -1);
|
|
|
|
|
// NEXT_BY_ADDR.appendBlock(new DescriptionBlock("FALL THROUGH"), 0);
|
|
|
|
|
// NEXT_BY_ADDR.label = "NEXT_BY_ADDR";
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -75,21 +76,33 @@ public class FlowBlock { |
|
|
|
|
* uses that variable, on which it is never assigned |
|
|
|
|
*/ |
|
|
|
|
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 |
|
|
|
|
* catch blocks. |
|
|
|
|
*/ |
|
|
|
|
VariableSet used = new VariableSet(); |
|
|
|
|
/** |
|
|
|
|
* The gen locals. This are the locals, to which are written |
|
|
|
|
* somewhere in this flow block. This is only used for try |
|
|
|
|
* catch blocks. |
|
|
|
|
*/ |
|
|
|
|
VariableSet gen = new VariableSet(); |
|
|
|
|
/** |
|
|
|
|
* The gen locals. This are the locals, to which are written |
|
|
|
|
* somewhere in this flow block. This is only used for try |
|
|
|
|
* catch blocks. |
|
|
|
|
*/ |
|
|
|
|
SlotSet kill = new SlotSet(); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* The starting address of this flow block. This is mainly used |
|
|
|
|
* The starting blockNr of this flow block. This is mainly used |
|
|
|
|
* to produce the source code in code order. |
|
|
|
|
*/ |
|
|
|
|
private int addr; |
|
|
|
|
private int blockNr; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* The length of the structured block, only needed at the beginning. |
|
|
|
|
* The number of flow blocks that were combined into this block so far. |
|
|
|
|
*/ |
|
|
|
|
private int length; |
|
|
|
|
|
|
|
|
@ -127,13 +140,13 @@ public class FlowBlock { |
|
|
|
|
* This is a pointer to the next flow block in byte code order. |
|
|
|
|
* It is null for the last flow block. |
|
|
|
|
*/ |
|
|
|
|
FlowBlock nextByAddr; |
|
|
|
|
FlowBlock nextByCodeOrder; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* This is a pointer to the previous flow block in byte code order. |
|
|
|
|
* It is null for the first flow block. |
|
|
|
|
*/ |
|
|
|
|
FlowBlock prevByAddr; |
|
|
|
|
FlowBlock prevByCodeOrder; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* The stack map. This tells how many objects are on stack at |
|
|
|
@ -168,17 +181,24 @@ public class FlowBlock { |
|
|
|
|
Jump jumps; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* The default constructor. Creates a new empty flowblock. |
|
|
|
|
*/ |
|
|
|
|
public FlowBlock(MethodAnalyzer method, int addr) { |
|
|
|
|
public FlowBlock(MethodAnalyzer method, int blockNr, FlowBlock lastFlow) { |
|
|
|
|
this.method = method; |
|
|
|
|
this.addr = addr; |
|
|
|
|
this.blockNr = blockNr; |
|
|
|
|
|
|
|
|
|
length = 1; |
|
|
|
|
prevByCodeOrder = lastFlow; |
|
|
|
|
if (lastFlow != null) |
|
|
|
|
lastFlow.nextByCodeOrder = this; |
|
|
|
|
block = new EmptyBlock(); |
|
|
|
|
block.setFlowBlock(this); |
|
|
|
|
lastModified = block; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public final int getNextAddr() { |
|
|
|
|
return addr+length; |
|
|
|
|
public int getNextBlockNr() { |
|
|
|
|
return blockNr + length; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public boolean hasNoJumps() { |
|
|
|
@ -379,9 +399,22 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
newIfBlock.moveJump(jump); |
|
|
|
|
/* consider this jump again */ |
|
|
|
|
jumps = jump; |
|
|
|
|
continue; |
|
|
|
|
// /* consider this jump again */
|
|
|
|
|
// jumps = jump;
|
|
|
|
|
/* Consider all jumps again, since the ones that moved |
|
|
|
|
* into the thenBlock may be obsolete now. |
|
|
|
|
* XXX only jumps in then should be considered. |
|
|
|
|
*/ |
|
|
|
|
if (remainingJumps == null) |
|
|
|
|
jumps = jump; |
|
|
|
|
else { |
|
|
|
|
jumps = remainingJumps; |
|
|
|
|
while (remainingJumps.next != null) |
|
|
|
|
remainingJumps = remainingJumps.next; |
|
|
|
|
remainingJumps.next = jump; |
|
|
|
|
remainingJumps = null; |
|
|
|
|
} |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
@ -394,19 +427,37 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now find the real outer block, that is ascend the chain |
|
|
|
|
* of SequentialBlocks. |
|
|
|
|
/* Now find the real outer block, that is ascend the |
|
|
|
|
* chain of SequentialBlocks. |
|
|
|
|
* |
|
|
|
|
* Note that only the last instr in a SequentialBlock chain |
|
|
|
|
* can have a jump. |
|
|
|
|
* |
|
|
|
|
* We rely on the fact, that instanceof returns false |
|
|
|
|
* for a null pointer. |
|
|
|
|
*/ |
|
|
|
|
*/ |
|
|
|
|
StructuredBlock sb = jump.prev.outer; |
|
|
|
|
while (sb instanceof SequentialBlock) |
|
|
|
|
sb = sb.outer; |
|
|
|
|
|
|
|
|
|
while (sb instanceof SequentialBlock) |
|
|
|
|
sb = sb.outer; |
|
|
|
|
|
|
|
|
|
/* If the block is a catch, go up to the try block. |
|
|
|
|
*/ |
|
|
|
|
if (sb instanceof CatchBlock |
|
|
|
|
&& sb.jumpMayBeChanged()) |
|
|
|
|
sb = sb.outer; |
|
|
|
|
|
|
|
|
|
/* If the block is a synchronized or try block |
|
|
|
|
* and the jump may be changed, move the jump up. |
|
|
|
|
*/ |
|
|
|
|
if ((sb instanceof CatchBlock |
|
|
|
|
|| sb instanceof SynchronizedBlock |
|
|
|
|
|| sb instanceof TryBlock) |
|
|
|
|
&& sb.jumpMayBeChanged()) { |
|
|
|
|
sb.moveJump(jump); |
|
|
|
|
/* consider this jump again */ |
|
|
|
|
jumps = jump; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* if this is an unconditional jump at the end of a |
|
|
|
|
* then block belonging to a if-then block without |
|
|
|
@ -461,9 +512,22 @@ public class FlowBlock { |
|
|
|
|
lastModified = ifBlock; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Consider all jumps again, since the ones that moved |
|
|
|
|
* into the thenBlock may be obsolete now. |
|
|
|
|
* XXX only jumps in then should be considered. |
|
|
|
|
*/ |
|
|
|
|
if (remainingJumps == null) |
|
|
|
|
jumps = jump; |
|
|
|
|
else { |
|
|
|
|
jumps = remainingJumps; |
|
|
|
|
while (remainingJumps.next != null) |
|
|
|
|
remainingJumps = remainingJumps.next; |
|
|
|
|
remainingJumps.next = jump; |
|
|
|
|
remainingJumps = null; |
|
|
|
|
} |
|
|
|
|
/* consider this jump again */ |
|
|
|
|
ifBlock.moveJump(jump); |
|
|
|
|
jumps = jump; |
|
|
|
|
// ifBlock.moveJump(jump);
|
|
|
|
|
// jumps = jump;
|
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -601,67 +665,76 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Fixes the addr chained list, after merging this block with succ. |
|
|
|
|
* Fixes the blockNr chained list, after merging this block with succ. |
|
|
|
|
*/ |
|
|
|
|
public void mergeAddr(FlowBlock succ) { |
|
|
|
|
if (succ.nextByAddr == this || succ.prevByAddr == null) { |
|
|
|
|
/* Merge succ with its nextByAddr. |
|
|
|
|
* Note: succ.nextByAddr != null, since this is on the |
|
|
|
|
* nextByAddr chain. */ |
|
|
|
|
succ.nextByAddr.addr = succ.addr; |
|
|
|
|
succ.nextByAddr.length += succ.length; |
|
|
|
|
|
|
|
|
|
succ.nextByAddr.prevByAddr = succ.prevByAddr; |
|
|
|
|
if (succ.prevByAddr != null) |
|
|
|
|
succ.prevByAddr.nextByAddr = succ.nextByAddr; |
|
|
|
|
public void mergeBlockNr(FlowBlock succ) { |
|
|
|
|
if (succ.nextByCodeOrder == this || succ.prevByCodeOrder == null) { |
|
|
|
|
/* Merge succ with its nextByCodeOrder. |
|
|
|
|
* Note: succ.nextByCodeOrder != null, since this is on the |
|
|
|
|
* nextByCodeOrder chain. */ |
|
|
|
|
succ.nextByCodeOrder.blockNr = succ.blockNr; |
|
|
|
|
succ.nextByCodeOrder.length += succ.length; |
|
|
|
|
|
|
|
|
|
succ.nextByCodeOrder.prevByCodeOrder = succ.prevByCodeOrder; |
|
|
|
|
if (succ.prevByCodeOrder != null) |
|
|
|
|
succ.prevByCodeOrder.nextByCodeOrder = succ.nextByCodeOrder; |
|
|
|
|
} else { |
|
|
|
|
/* Merge succ with its prevByAddr */ |
|
|
|
|
succ.prevByAddr.length += succ.length; |
|
|
|
|
/* Merge succ with its prevByCodeOrder */ |
|
|
|
|
succ.prevByCodeOrder.length += succ.length; |
|
|
|
|
|
|
|
|
|
succ.prevByAddr.nextByAddr = succ.nextByAddr; |
|
|
|
|
if (succ.nextByAddr != null) |
|
|
|
|
succ.nextByAddr.prevByAddr = succ.prevByAddr; |
|
|
|
|
succ.prevByCodeOrder.nextByCodeOrder = succ.nextByCodeOrder; |
|
|
|
|
if (succ.nextByCodeOrder != null) |
|
|
|
|
succ.nextByCodeOrder.prevByCodeOrder = succ.prevByCodeOrder; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Updates the gen/kill Sets of all jumps in this block. |
|
|
|
|
* @param gens The locals in this block that are visible at the |
|
|
|
|
* begin of successor. |
|
|
|
|
* @param kills The slots that are always overwritten on the way to |
|
|
|
|
* successor. This may be null. |
|
|
|
|
* @return The variables that must be defined * in this block. |
|
|
|
|
*/ |
|
|
|
|
void updateGenKill(VariableSet gens, SlotSet kills) { |
|
|
|
|
/* Merge the locals used in successing block with those written |
|
|
|
|
* by this blocks. |
|
|
|
|
*/ |
|
|
|
|
in.merge(gens); |
|
|
|
|
|
|
|
|
|
/* The gen/kill sets must be updated for every jump |
|
|
|
|
* in the other block */ |
|
|
|
|
Iterator i = successors.values().iterator(); |
|
|
|
|
while (i.hasNext()) { |
|
|
|
|
SuccessorInfo succInfo = (SuccessorInfo) i.next(); |
|
|
|
|
succInfo.gen.mergeGenKill(gens, succInfo.kill); |
|
|
|
|
if (kills != null) |
|
|
|
|
succInfo.kill.mergeKill(kills); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Updates the in/out-Vectors of the structured block of the |
|
|
|
|
* successing flow block simultanous to a T2 transformation. |
|
|
|
|
* @param successor The flow block which is unified with this flow |
|
|
|
|
* block. |
|
|
|
|
* @param jumps The list of jumps to successor in this block. |
|
|
|
|
* @return The variables that must be defined in this block. |
|
|
|
|
* @param gens The locals in this block that are visible at the |
|
|
|
|
* begin of successor. |
|
|
|
|
* @param kills The slots that are always overwritten on the way to |
|
|
|
|
* successor. |
|
|
|
|
* @return The variables that must be defined * in this block. |
|
|
|
|
*/ |
|
|
|
|
void updateInOut(FlowBlock successor, SuccessorInfo succInfo) { |
|
|
|
|
/* First get the gen/kill sets of all jumps to successor and |
|
|
|
|
* calculate the intersection. |
|
|
|
|
*/ |
|
|
|
|
SlotSet kills = succInfo.kill; |
|
|
|
|
VariableSet gens = succInfo.gen; |
|
|
|
|
void updateInOut(FlowBlock successor, VariableSet gens, SlotSet kills) { |
|
|
|
|
successor.updateGenKill(gens, kills); |
|
|
|
|
|
|
|
|
|
/* Merge the locals used in successing block with those written |
|
|
|
|
* by this blocks. |
|
|
|
|
*/ |
|
|
|
|
successor.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) successor.in.clone(); |
|
|
|
|
newIn.removeAll(kills); |
|
|
|
|
|
|
|
|
|
/* The gen/kill sets must be updated for every jump |
|
|
|
|
* in the other block */ |
|
|
|
|
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.mergeKill(kills); |
|
|
|
|
} |
|
|
|
|
this.in.addAll(newIn); |
|
|
|
|
this.gen.addAll(successor.gen); |
|
|
|
|
this.used.addAll(successor.used); |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { |
|
|
|
|
GlobalOptions.err.println("UpdateInOut: gens : "+gens); |
|
|
|
@ -708,7 +781,7 @@ public class FlowBlock { |
|
|
|
|
succSuccInfo.gen.mergeGenKill(gens, succSuccInfo.kill); |
|
|
|
|
} |
|
|
|
|
in.addAll(catchFlow.in); |
|
|
|
|
gen.addAll(catchFlow.gen); |
|
|
|
|
used.addAll(catchFlow.used); |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { |
|
|
|
|
GlobalOptions.err.println("UpdateInOutCatch: gens : "+gens); |
|
|
|
@ -795,95 +868,110 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void appendBlock(StructuredBlock block, int length) { |
|
|
|
|
SlotSet succIn = new SlotSet(); |
|
|
|
|
SlotSet succKill = new SlotSet(); |
|
|
|
|
VariableSet succGen = new VariableSet(); |
|
|
|
|
block.fillInGenSet(succIn, succKill); |
|
|
|
|
succGen.addAll(succKill); |
|
|
|
|
|
|
|
|
|
if (this.block == null) { |
|
|
|
|
this.block = block; |
|
|
|
|
lastModified = block; |
|
|
|
|
block.setFlowBlock(this); |
|
|
|
|
block.fillSuccessors(); |
|
|
|
|
this.length = length; |
|
|
|
|
|
|
|
|
|
in = succIn; |
|
|
|
|
gen = succGen; |
|
|
|
|
for (Iterator i = successors.values().iterator(); i.hasNext();) { |
|
|
|
|
SuccessorInfo info = (SuccessorInfo) i.next(); |
|
|
|
|
info.gen = new VariableSet(); |
|
|
|
|
info.kill = new SlotSet(); |
|
|
|
|
info.gen.addAll(succGen); |
|
|
|
|
info.kill.addAll(succKill); |
|
|
|
|
} |
|
|
|
|
} else if (!(block instanceof EmptyBlock)) { |
|
|
|
|
checkConsistent(); |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_FLOW) != 0) { |
|
|
|
|
GlobalOptions.err.println("appending Block: "+block); |
|
|
|
|
} |
|
|
|
|
public void prependBlock(StructuredBlock insertBlock) { |
|
|
|
|
lastModified = insertBlock.appendBlock(block); |
|
|
|
|
SlotSet blockIn = new SlotSet(); |
|
|
|
|
SlotSet blockKill = new SlotSet(); |
|
|
|
|
VariableSet blockGen = new VariableSet(); |
|
|
|
|
|
|
|
|
|
insertBlock.fillInGenSet(blockIn, blockKill); |
|
|
|
|
blockGen.addAll(blockKill); |
|
|
|
|
|
|
|
|
|
updateGenKill(blockGen, blockKill); |
|
|
|
|
in.removeAll(blockKill); |
|
|
|
|
in.addAll(blockIn); |
|
|
|
|
used.addAll(blockGen); |
|
|
|
|
|
|
|
|
|
doTransformations(); |
|
|
|
|
checkConsistent(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void appendReadBlock(StructuredBlock newBlock, LocalInfo local) { |
|
|
|
|
used.add(local); |
|
|
|
|
if (!kill.contains(local)) |
|
|
|
|
in.add(local); |
|
|
|
|
gen.mergeRead(local); |
|
|
|
|
kill.mergeKill(local); |
|
|
|
|
|
|
|
|
|
SuccessorInfo succInfo |
|
|
|
|
= (SuccessorInfo) successors.get(NEXT_BY_ADDR); |
|
|
|
|
succIn.merge(succInfo.gen); |
|
|
|
|
succIn.removeAll(succInfo.kill); |
|
|
|
|
|
|
|
|
|
succGen.mergeGenKill(succInfo.gen, succKill); |
|
|
|
|
succKill.mergeKill(succInfo.kill); |
|
|
|
|
this.in.addAll(succIn); |
|
|
|
|
this.gen.addAll(succKill); |
|
|
|
|
|
|
|
|
|
removeSuccessor(lastModified.jump); |
|
|
|
|
lastModified.removeJump(); |
|
|
|
|
lastModified = lastModified.appendBlock(block); |
|
|
|
|
block.fillSuccessors(); |
|
|
|
|
succInfo = (SuccessorInfo) successors.get(NEXT_BY_ADDR); |
|
|
|
|
succInfo.gen = succGen; |
|
|
|
|
succInfo.kill = succKill; |
|
|
|
|
this.length += length; |
|
|
|
|
checkConsistent(); |
|
|
|
|
doTransformations(); |
|
|
|
|
} |
|
|
|
|
newBlock.setFlowBlock(this); |
|
|
|
|
lastModified = lastModified.appendBlock(newBlock); |
|
|
|
|
doTransformations(); |
|
|
|
|
checkConsistent(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Append the given flowblock to the nextByAddr/prevByAddr chain. |
|
|
|
|
* nextByAddr should be null, when calling this. |
|
|
|
|
* @param flow The flowBlock to append |
|
|
|
|
*/ |
|
|
|
|
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, info); |
|
|
|
|
if (flowInfo != null) { |
|
|
|
|
info.gen.addAll(flowInfo.gen); |
|
|
|
|
info.kill.retainAll(flowInfo.kill); |
|
|
|
|
jumps.next = flowInfo.jumps; |
|
|
|
|
} else |
|
|
|
|
flow.predecessors.add(this); |
|
|
|
|
} |
|
|
|
|
public void appendWriteBlock(StructuredBlock newBlock, LocalInfo local) { |
|
|
|
|
used.add(local); |
|
|
|
|
gen.mergeWrite(local); |
|
|
|
|
kill.mergeKill(local); |
|
|
|
|
|
|
|
|
|
newBlock.setFlowBlock(this); |
|
|
|
|
lastModified = lastModified.appendBlock(newBlock); |
|
|
|
|
doTransformations(); |
|
|
|
|
checkConsistent(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void appendBlock(StructuredBlock newBlock) { |
|
|
|
|
newBlock.setFlowBlock(this); |
|
|
|
|
lastModified = lastModified.appendBlock(newBlock); |
|
|
|
|
doTransformations(); |
|
|
|
|
checkConsistent(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void oldAppendBlock(StructuredBlock newBlock) { |
|
|
|
|
SlotSet blockIn = new SlotSet(); |
|
|
|
|
SlotSet blockKill = new SlotSet(); |
|
|
|
|
VariableSet blockGen = new VariableSet(); |
|
|
|
|
newBlock.setFlowBlock(this); |
|
|
|
|
newBlock.fillInGenSet(blockIn, blockKill); |
|
|
|
|
this.used.addAll(blockKill); |
|
|
|
|
blockGen.addAll(blockKill); |
|
|
|
|
|
|
|
|
|
/* Merge the locals used in new block with those written |
|
|
|
|
* by this blocks. |
|
|
|
|
*/ |
|
|
|
|
blockIn.merge(this.gen); |
|
|
|
|
blockGen.mergeGenKill(this.gen, blockKill); |
|
|
|
|
blockKill.mergeKill(this.kill); |
|
|
|
|
|
|
|
|
|
blockIn.removeAll(this.kill); |
|
|
|
|
this.in.addAll(blockIn); |
|
|
|
|
this.gen = blockGen; |
|
|
|
|
this.kill = blockKill; |
|
|
|
|
|
|
|
|
|
lastModified = lastModified.appendBlock(newBlock); |
|
|
|
|
checkConsistent(); |
|
|
|
|
doTransformations(); |
|
|
|
|
checkConsistent(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nextByAddr = flow; |
|
|
|
|
flow.prevByAddr = this; |
|
|
|
|
public void setSuccessors(FlowBlock[] succs) { |
|
|
|
|
SlotSet blockIn = new SlotSet(); |
|
|
|
|
SlotSet blockKill = new SlotSet(); |
|
|
|
|
VariableSet blockGen = new VariableSet(); |
|
|
|
|
|
|
|
|
|
Jump[] jumps = new Jump[succs.length]; |
|
|
|
|
for (int i=0; i< succs.length; i++) { |
|
|
|
|
Jump jump = new Jump(succs[i]); |
|
|
|
|
SuccessorInfo info = (SuccessorInfo) successors.get(succs[i]); |
|
|
|
|
if (info == null) { |
|
|
|
|
info = new SuccessorInfo(); |
|
|
|
|
info.gen = (VariableSet) gen.clone(); |
|
|
|
|
info.kill = (SlotSet) kill.clone(); |
|
|
|
|
info.jumps = jump; |
|
|
|
|
if (jump.destination != END_OF_METHOD) |
|
|
|
|
jump.destination.predecessors.add(this); |
|
|
|
|
successors.put(succs[i], info); |
|
|
|
|
} else { |
|
|
|
|
jump.next = info.jumps; |
|
|
|
|
info.jumps = jump; |
|
|
|
|
} |
|
|
|
|
jumps[i] = jump; |
|
|
|
|
} |
|
|
|
|
if (jumps.length > 0) |
|
|
|
|
lastModified.setSuccessors(jumps); |
|
|
|
|
gen = null; |
|
|
|
|
kill = null; |
|
|
|
|
checkConsistent(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -905,13 +993,13 @@ public class FlowBlock { |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
|
GlobalOptions.err.println |
|
|
|
|
("T2(["+addr+","+getNextAddr()+"],[" |
|
|
|
|
+succ.addr+","+succ.getNextAddr()+"])"); |
|
|
|
|
("T2(["+blockNr+","+getNextBlockNr()+"],[" |
|
|
|
|
+succ.blockNr+","+succ.getNextBlockNr()+"])"); |
|
|
|
|
|
|
|
|
|
SuccessorInfo succInfo = (SuccessorInfo) successors.remove(succ); |
|
|
|
|
|
|
|
|
|
/* Update the in/out-Vectors now */ |
|
|
|
|
updateInOut(succ, succInfo); |
|
|
|
|
updateInOut(succ, succInfo.gen, succInfo.kill); |
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("before Resolve: "+this); |
|
|
|
|
|
|
|
|
@ -932,8 +1020,8 @@ public class FlowBlock { |
|
|
|
|
/* This will also set last modified to the new correct value. */ |
|
|
|
|
doTransformations(); |
|
|
|
|
|
|
|
|
|
/* Set addr and length to correct value and update nextByAddr */ |
|
|
|
|
mergeAddr(succ); |
|
|
|
|
/* Set blockNr and length to correct value and update nextByCodeOrder */ |
|
|
|
|
mergeBlockNr(succ); |
|
|
|
|
|
|
|
|
|
/* T2 transformation succeeded */ |
|
|
|
|
checkConsistent(); |
|
|
|
@ -968,10 +1056,16 @@ public class FlowBlock { |
|
|
|
|
jumps = jump; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("before resolve: "+this); |
|
|
|
|
|
|
|
|
|
/* Try to eliminate as many jumps as possible. |
|
|
|
|
*/ |
|
|
|
|
jumps = resolveSomeJumps(jumps, END_OF_METHOD); |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("before remaining: "+this); |
|
|
|
|
|
|
|
|
|
next_jump: |
|
|
|
|
for (; jumps != null; jumps = jumps.next) { |
|
|
|
|
|
|
|
|
@ -1011,7 +1105,14 @@ public class FlowBlock { |
|
|
|
|
if (lastModified.jump.destination == END_OF_METHOD) |
|
|
|
|
lastModified.removeJump(); |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("before Transformation: "+this); |
|
|
|
|
|
|
|
|
|
doTransformations(); |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("after Transformation: "+this); |
|
|
|
|
|
|
|
|
|
/* transformation succeeded */ |
|
|
|
|
checkConsistent(); |
|
|
|
|
} |
|
|
|
@ -1019,7 +1120,7 @@ public class FlowBlock { |
|
|
|
|
public boolean doT1(int start, int end) { |
|
|
|
|
/* If there are no jumps to the beginning of this flow block |
|
|
|
|
* or if this block has other predecessors with a not yet |
|
|
|
|
* considered address, return false. The second condition |
|
|
|
|
* considered block number, return false. The second condition |
|
|
|
|
* make sure that not for each continue a while is created. |
|
|
|
|
*/ |
|
|
|
|
if (!predecessors.contains(this)) |
|
|
|
@ -1027,7 +1128,7 @@ public class FlowBlock { |
|
|
|
|
for (Iterator i = predecessors.iterator(); i.hasNext(); ) { |
|
|
|
|
FlowBlock predFlow = (FlowBlock) i.next(); |
|
|
|
|
if (predFlow != null && predFlow != this |
|
|
|
|
&& predFlow.addr >= start && predFlow.addr < end) { |
|
|
|
|
&& predFlow.blockNr >= start && predFlow.blockNr < end) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1035,11 +1136,11 @@ public class FlowBlock { |
|
|
|
|
checkConsistent(); |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
|
GlobalOptions.err.println("T1(["+addr+","+getNextAddr()+"])"); |
|
|
|
|
GlobalOptions.err.println("T1(["+blockNr+","+getNextBlockNr()+"])"); |
|
|
|
|
SuccessorInfo succInfo = (SuccessorInfo) successors.remove(this); |
|
|
|
|
|
|
|
|
|
/* Update the in/out-Vectors now */ |
|
|
|
|
updateInOut(this, succInfo); |
|
|
|
|
updateGenKill(succInfo.gen, null); |
|
|
|
|
Jump jumps = succInfo.jumps; |
|
|
|
|
|
|
|
|
|
StructuredBlock bodyBlock = block; |
|
|
|
@ -1174,8 +1275,14 @@ public class FlowBlock { |
|
|
|
|
*/ |
|
|
|
|
predecessors.remove(this); |
|
|
|
|
lastModified = block; |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("before Transformation: "+this); |
|
|
|
|
|
|
|
|
|
doTransformations(); |
|
|
|
|
// mergeCondition();
|
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("after Transformation: "+this); |
|
|
|
|
|
|
|
|
|
/* T1 analysis succeeded */ |
|
|
|
|
checkConsistent(); |
|
|
|
@ -1184,9 +1291,6 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void doTransformations() { |
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("before Transformation: "+this); |
|
|
|
|
|
|
|
|
|
while (lastModified instanceof SequentialBlock) { |
|
|
|
|
if (lastModified.getSubBlocks()[0].doTransformations()) |
|
|
|
|
continue; |
|
|
|
@ -1194,28 +1298,25 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
while (lastModified.doTransformations()) |
|
|
|
|
{ /* empty */ } |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("after Transformation: "+this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Search for an apropriate successor. |
|
|
|
|
* @param prevSucc The successor, that was previously tried. |
|
|
|
|
* @param start The minimum address. |
|
|
|
|
* @param end The maximum address + 1. |
|
|
|
|
* @return the successor with smallest address greater than prevSucc |
|
|
|
|
* @param start The minimum blockNr |
|
|
|
|
* @param end The maximum blockNr + 1. |
|
|
|
|
* @return the successor with smallest block number greater than prevSucc |
|
|
|
|
* or null if there isn't any further successor at all. |
|
|
|
|
*/ |
|
|
|
|
FlowBlock getSuccessor(int start, int end) { |
|
|
|
|
/* search successor with smallest addr. */ |
|
|
|
|
/* search successor with smallest blockNr. */ |
|
|
|
|
Iterator keys = successors.keySet().iterator(); |
|
|
|
|
FlowBlock succ = null; |
|
|
|
|
while (keys.hasNext()) { |
|
|
|
|
FlowBlock fb = (FlowBlock) keys.next(); |
|
|
|
|
if (fb.addr < start || fb.addr >= end || fb == this) |
|
|
|
|
if (fb.blockNr < start || fb.blockNr >= end || fb == this) |
|
|
|
|
continue; |
|
|
|
|
if (succ == null || fb.addr < succ.addr) { |
|
|
|
|
if (succ == null || fb.blockNr < succ.blockNr) { |
|
|
|
|
succ = fb; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1228,16 +1329,17 @@ public class FlowBlock { |
|
|
|
|
* block. |
|
|
|
|
*/ |
|
|
|
|
public void analyze() { |
|
|
|
|
analyze(0, Integer.MAX_VALUE); |
|
|
|
|
while (analyze(0, Integer.MAX_VALUE)) |
|
|
|
|
{ } |
|
|
|
|
mergeEndBlock(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* The main analyzation. This calls doT1 and doT2 on apropriate |
|
|
|
|
* regions. Only blocks whose address lies in the given address |
|
|
|
|
* regions. Only blocks whose block number lies in the given block number |
|
|
|
|
* range are considered. |
|
|
|
|
* @param start the start of the address range. |
|
|
|
|
* @param end the end of the address range. |
|
|
|
|
* @param start the start of the block number range. |
|
|
|
|
* @param end the end of the block number range. |
|
|
|
|
*/ |
|
|
|
|
public boolean analyze(int start, int end) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
@ -1251,7 +1353,7 @@ public class FlowBlock { |
|
|
|
|
if (lastModified instanceof SwitchBlock) { |
|
|
|
|
/* analyze the switch first. |
|
|
|
|
*/ |
|
|
|
|
analyzeSwitch(start, end); |
|
|
|
|
changed |= analyzeSwitch(start, end); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1264,8 +1366,7 @@ public class FlowBlock { |
|
|
|
|
* make another T2 analysis in the previous |
|
|
|
|
* block possible. |
|
|
|
|
*/ |
|
|
|
|
if (addr != 0) |
|
|
|
|
return true; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
FlowBlock succ = getSuccessor(start, end); |
|
|
|
@ -1279,68 +1380,71 @@ public class FlowBlock { |
|
|
|
|
GlobalOptions.err.println |
|
|
|
|
("No more successors applicable: " |
|
|
|
|
+ start + " - " + end + "; " |
|
|
|
|
+ addr + " - " + getNextAddr()); |
|
|
|
|
+ blockNr + " - " + getNextBlockNr()); |
|
|
|
|
return changed; |
|
|
|
|
} else { |
|
|
|
|
if ((nextByAddr == succ || succ.nextByAddr == this) |
|
|
|
|
/* Only do T2 transformation if the blocks are |
|
|
|
|
* adjacent. |
|
|
|
|
*/ |
|
|
|
|
&& doT2(succ)) { |
|
|
|
|
/* T2 transformation succeeded. */ |
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("after T2: "+this); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} else if ((nextByCodeOrder == succ |
|
|
|
|
|| succ.nextByCodeOrder == this) |
|
|
|
|
/* Only do T2 transformation if the blocks are |
|
|
|
|
* adjacent. |
|
|
|
|
*/ |
|
|
|
|
&& doT2(succ)) { |
|
|
|
|
/* T2 transformation succeeded. */ |
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_FLOW) != 0) |
|
|
|
|
GlobalOptions.err.println("after T2: "+this); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
/* Check if all predecessors of succ |
|
|
|
|
* lie in range [start,end). Otherwise |
|
|
|
|
* we have no chance to combine succ |
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
/* Check if all predecessors of either succ or this |
|
|
|
|
* block lie in range [start,end). Otherwise |
|
|
|
|
* we have no chance to combine these two blocks. |
|
|
|
|
*/ |
|
|
|
|
boolean predOutOfRange = false; |
|
|
|
|
for (Iterator i = succ.predecessors.iterator(); |
|
|
|
|
i.hasNext(); ) { |
|
|
|
|
int predAddr = ((FlowBlock)i.next()).addr; |
|
|
|
|
if (predAddr < start || predAddr >= end) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
int predBlockNr = ((FlowBlock)i.next()).blockNr; |
|
|
|
|
if (predBlockNr < start || predBlockNr >= end) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags |
|
|
|
|
& GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
|
GlobalOptions.err.println |
|
|
|
|
("breaking analyze(" |
|
|
|
|
+ start + ", " + end + "); " |
|
|
|
|
+ addr + " - " + getNextAddr()); |
|
|
|
|
return changed; |
|
|
|
|
|
|
|
|
|
GlobalOptions.err.println |
|
|
|
|
("breaking analyze(" |
|
|
|
|
+ start + ", " + end + "); " |
|
|
|
|
+ blockNr + " - " + getNextBlockNr()); |
|
|
|
|
return changed; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
/* analyze succ, the new region is the |
|
|
|
|
* continuous region of |
|
|
|
|
* [start,end) \cap \compl [addr, getNextAddr()) |
|
|
|
|
* where succ.addr lies in. |
|
|
|
|
* [start,end) \cap \compl [blockNr, getNextBlockNr()) |
|
|
|
|
* where succ.blockNr lies in. |
|
|
|
|
*/ |
|
|
|
|
int newStart = (succ.addr > addr) |
|
|
|
|
? getNextAddr() : start; |
|
|
|
|
int newEnd = (succ.addr > addr) |
|
|
|
|
? end : addr; |
|
|
|
|
int newStart = (succ.blockNr > blockNr) |
|
|
|
|
? getNextBlockNr() : start; |
|
|
|
|
int newEnd = (succ.blockNr > blockNr) |
|
|
|
|
? end : blockNr; |
|
|
|
|
if (succ.analyze(newStart, newEnd)) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Try the next successor. |
|
|
|
|
*/ |
|
|
|
|
succ = getSuccessor(succ.addr+1, end); |
|
|
|
|
succ = getSuccessor(succ.blockNr+1, end); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* The switch analyzation. This calls doSwitchT2 and doT1 on apropriate |
|
|
|
|
* regions. Only blocks whose address lies in the given address |
|
|
|
|
* regions. Only blocks whose block number lies in the given block number |
|
|
|
|
* range are considered and it is taken care of, that the switch |
|
|
|
|
* is never leaved. <p> |
|
|
|
|
* The current flow block must contain the switch block as lastModified. |
|
|
|
|
* @param start the start of the address range. |
|
|
|
|
* @param end the end of the address range. |
|
|
|
|
* @param start the start of the block number range. |
|
|
|
|
* @param end the end of the block number range. |
|
|
|
|
*/ |
|
|
|
|
public boolean analyzeSwitch(int start, int end) { |
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
@ -1356,18 +1460,18 @@ public class FlowBlock { |
|
|
|
|
&& switchBlock.caseBlocks[i].subBlock.jump != null) { |
|
|
|
|
FlowBlock nextFlow = switchBlock.caseBlocks[i]. |
|
|
|
|
subBlock.jump.destination; |
|
|
|
|
if (nextFlow.addr >= end) |
|
|
|
|
if (nextFlow.blockNr >= end) |
|
|
|
|
break; |
|
|
|
|
else if (nextFlow.addr >= start) { |
|
|
|
|
else if (nextFlow.blockNr >= start) { |
|
|
|
|
|
|
|
|
|
/* First analyze the nextFlow block. It may |
|
|
|
|
* return early after a T1 trafo so call it |
|
|
|
|
* until nothing more is possible. |
|
|
|
|
*/ |
|
|
|
|
while (nextFlow.analyze(getNextAddr(), end)) |
|
|
|
|
while (nextFlow.analyze(getNextBlockNr(), end)) |
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
|
|
if (nextFlow.addr != getNextAddr()) |
|
|
|
|
if (nextFlow.blockNr != getNextBlockNr()) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
/* Check if nextFlow has only the previous case |
|
|
|
@ -1405,7 +1509,7 @@ public class FlowBlock { |
|
|
|
|
lastFlow.resolveRemaining(lastJumps); |
|
|
|
|
switchBlock.caseBlocks[last+1].isFallThrough = true; |
|
|
|
|
} |
|
|
|
|
updateInOut(nextFlow, info); |
|
|
|
|
updateInOut(nextFlow, info.gen, info.kill); |
|
|
|
|
|
|
|
|
|
if (lastFlow != null) { |
|
|
|
|
lastFlow.block.replace |
|
|
|
@ -1418,7 +1522,7 @@ public class FlowBlock { |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
switchBlock.caseBlocks[i].subBlock.removeJump(); |
|
|
|
|
mergeAddr(nextFlow); |
|
|
|
|
mergeBlockNr(nextFlow); |
|
|
|
|
|
|
|
|
|
lastFlow = nextFlow; |
|
|
|
|
last = i; |
|
|
|
@ -1440,7 +1544,7 @@ public class FlowBlock { |
|
|
|
|
& GlobalOptions.DEBUG_ANALYZE) != 0) |
|
|
|
|
GlobalOptions.err.println |
|
|
|
|
("analyzeSwitch done: " + start + " - " + end + "; " |
|
|
|
|
+ addr + " - " + getNextAddr()); |
|
|
|
|
+ blockNr + " - " + getNextBlockNr()); |
|
|
|
|
checkConsistent(); |
|
|
|
|
return changed; |
|
|
|
|
} |
|
|
|
@ -1463,7 +1567,7 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
if (destJumps == null) |
|
|
|
|
throw new IllegalArgumentException |
|
|
|
|
(addr+": removing non existent jump: " + jump); |
|
|
|
|
(blockNr+": removing non existent jump: " + jump); |
|
|
|
|
|
|
|
|
|
if (prev != null) |
|
|
|
|
prev.next = destJumps.next; |
|
|
|
@ -1490,19 +1594,19 @@ public class FlowBlock { |
|
|
|
|
return successors.keySet(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void addSuccessor(Jump jump) { |
|
|
|
|
SuccessorInfo info = (SuccessorInfo) successors.get(jump.destination); |
|
|
|
|
if (info == null) { |
|
|
|
|
info = new SuccessorInfo(); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// public void addSuccessor(Jump jump) {
|
|
|
|
|
// SuccessorInfo info = (SuccessorInfo) successors.get(jump.destination);
|
|
|
|
|
// if (info == null) {
|
|
|
|
|
// info = new SuccessorInfo();
|
|
|
|
|
// 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 |
|
|
|
@ -1564,8 +1668,8 @@ public class FlowBlock { |
|
|
|
|
|
|
|
|
|
public void removeOnetimeLocals() { |
|
|
|
|
block.removeOnetimeLocals(); |
|
|
|
|
if (nextByAddr != null) |
|
|
|
|
nextByAddr.removeOnetimeLocals(); |
|
|
|
|
if (nextByCodeOrder != null) |
|
|
|
|
nextByCodeOrder.removeOnetimeLocals(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void promoteInSets() { |
|
|
|
@ -1594,8 +1698,8 @@ public class FlowBlock { |
|
|
|
|
pred.promoteInSets(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (nextByAddr != null) |
|
|
|
|
nextByAddr.promoteInSets(); |
|
|
|
|
if (nextByCodeOrder != null) |
|
|
|
|
nextByCodeOrder.promoteInSets(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -1617,8 +1721,8 @@ public class FlowBlock { |
|
|
|
|
public void makeDeclaration(Set done) { |
|
|
|
|
block.propagateUsage(); |
|
|
|
|
block.makeDeclaration(done); |
|
|
|
|
if (nextByAddr != null) |
|
|
|
|
nextByAddr.makeDeclaration(done); |
|
|
|
|
if (nextByCodeOrder != null) |
|
|
|
|
nextByCodeOrder.makeDeclaration(done); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -1626,8 +1730,8 @@ public class FlowBlock { |
|
|
|
|
*/ |
|
|
|
|
public void simplify() { |
|
|
|
|
block.simplify(); |
|
|
|
|
if (nextByAddr != null) |
|
|
|
|
nextByAddr.simplify(); |
|
|
|
|
if (nextByCodeOrder != null) |
|
|
|
|
nextByCodeOrder.simplify(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -1665,8 +1769,8 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (nextByAddr != null) |
|
|
|
|
nextByAddr.dumpSource(writer); |
|
|
|
|
if (nextByCodeOrder != null) |
|
|
|
|
nextByCodeOrder.dumpSource(writer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -1680,10 +1784,10 @@ public class FlowBlock { |
|
|
|
|
String label = null; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the address, where the code in this flow block starts. |
|
|
|
|
* Returns the block number, where the code in this flow block starts. |
|
|
|
|
*/ |
|
|
|
|
public int getAddr() { |
|
|
|
|
return addr; |
|
|
|
|
public int getBlockNr() { |
|
|
|
|
return blockNr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -1692,7 +1796,7 @@ public class FlowBlock { |
|
|
|
|
*/ |
|
|
|
|
public String getLabel() { |
|
|
|
|
if (label == null) |
|
|
|
|
label = "flow_"+addr+"_"+(serialno++)+"_"; |
|
|
|
|
label = "flow_"+blockNr+"_"+(serialno++)+"_"; |
|
|
|
|
return label; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1707,7 +1811,7 @@ public class FlowBlock { |
|
|
|
|
try { |
|
|
|
|
java.io.StringWriter strw = new java.io.StringWriter(); |
|
|
|
|
TabbedPrintWriter writer = new TabbedPrintWriter(strw); |
|
|
|
|
writer.println(super.toString() + ": "+addr+"-"+(addr+length)); |
|
|
|
|
writer.println(super.toString() + ": "+blockNr); |
|
|
|
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_INOUT) != 0) { |
|
|
|
|
writer.println("in: "+in); |
|
|
|
|
} |
|
|
|
@ -1728,6 +1832,8 @@ public class FlowBlock { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return strw.toString(); |
|
|
|
|
} catch (RuntimeException ex) { |
|
|
|
|
return super.toString(); |
|
|
|
|
} catch (java.io.IOException ex) { |
|
|
|
|
return super.toString(); |
|
|
|
|
} |