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