|
|
@ -47,8 +47,8 @@ public class FlowBlock { |
|
|
|
StructuredBlock lastModified; |
|
|
|
StructuredBlock lastModified; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* All Jumps that this flow block contains. |
|
|
|
* All Jumps that this flow block contains. The objects may be |
|
|
|
*/ |
|
|
|
* null, if they were marked as deleted. */ |
|
|
|
Vector successors; |
|
|
|
Vector successors; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -60,200 +60,407 @@ public class FlowBlock { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* This method optimizes the jumps to successor. |
|
|
|
* This method optimizes the jumps to successor. |
|
|
|
* Returns true, if all jumps could be eliminated. |
|
|
|
* Returns the new appendBlock, it may have changed. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public boolean optimizeJumps(FlowBlock successor, |
|
|
|
public StructuredBlock optimizeJumps(FlowBlock successor, |
|
|
|
StructuredBlock structBlock) { |
|
|
|
StructuredBlock appendBlock) { |
|
|
|
/* if the jump is the jump of the structBlock, skip it. |
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
*/ |
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
/* remove all jumps to the successor which have the successor |
|
|
|
|
|
|
|
* as getNextFlowBlock(). */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* replace all conditional jumps to the successor, which are followed |
|
|
|
if (jump == null || jump.destination != successor) |
|
|
|
* by a block which has the end of the block as normal successor, |
|
|
|
continue; |
|
|
|
* with "if (not condition) block". |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* if the successor is the dummy return instruction, replace all |
|
|
|
/* if the jump is the jump of the appendBlock, skip it. |
|
|
|
* jumps with a return. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (jump == appendBlock.jump) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
/* if there are jumps in a while block or switch block and the |
|
|
|
/* Note: jump.parent.outer != null, since appendBlock is |
|
|
|
* while/switch block is followed by a jump to successor or has |
|
|
|
* an outer block of jump.parent |
|
|
|
* successor as getNextFlowBlock(), replace jump with break to |
|
|
|
*/ |
|
|
|
* the innermost such while/switch block. |
|
|
|
|
|
|
|
* |
|
|
|
/* remove all jumps to the successor which have the successor |
|
|
|
* If the switch block hasn't been breaked before we could |
|
|
|
* as getNextFlowBlock(). */ |
|
|
|
* take some heuristics and add a jump after the switch to |
|
|
|
if (jump.parent.outer.getNextFlowBlock(jump.parent) == successor) |
|
|
|
* succesor, so that the above succeeds. |
|
|
|
jump.parent.removeJump(); |
|
|
|
* |
|
|
|
|
|
|
|
* If this is a while and the condition of the while is true, |
|
|
|
/* replace all conditional jumps to the successor, which |
|
|
|
* and this jump belongs to the first instruction in this |
|
|
|
* are followed by a block which has the end of the block |
|
|
|
* while block and is inside a ConditionalBlock remove that |
|
|
|
* as normal successor, with "if (not condition) block". |
|
|
|
* ConditionalBlock an move the condition to the while block. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (jump.parent instanceof ConditionalBlock && |
|
|
|
|
|
|
|
jump.parent.outer instanceof SequentialBlock && |
|
|
|
/* if there are jumps in an if-then block, which |
|
|
|
jump.parent.outer.getSubBlocks()[0] = jump.parent && |
|
|
|
* have as normal successor the end of the if-then block, and |
|
|
|
jump.parent.outer.getNextFlowBlock() == successor) { |
|
|
|
* the if-then block is followed by a single block, then replace |
|
|
|
|
|
|
|
* the if-then block with a if-then-else block and remove the |
|
|
|
|
|
|
|
* unconditional jump. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ConditionalBlock cb = (ConditionalBlock) jump.parent; |
|
|
|
|
|
|
|
cb.removeJump(); |
|
|
|
|
|
|
|
|
|
|
|
/* Special cases: |
|
|
|
SequentialBlock sequBlock = |
|
|
|
* |
|
|
|
(SequentialBlock) cb.outer; |
|
|
|
* try-header |
|
|
|
|
|
|
|
* |- first instruction |
|
|
|
|
|
|
|
* | ... |
|
|
|
|
|
|
|
* | last instruction |
|
|
|
|
|
|
|
* |- optional jump (last+1) |
|
|
|
|
|
|
|
* | ... |
|
|
|
|
|
|
|
* `- catch block |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* A try block may have many try-headers with different catch blocks |
|
|
|
|
|
|
|
* and there may be a finally block: |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* try-header any |
|
|
|
|
|
|
|
* | try-header |
|
|
|
|
|
|
|
* |--|- first instruction |
|
|
|
|
|
|
|
* | | ... |
|
|
|
|
|
|
|
* | | every jump to outside is preceded by jsr finally |
|
|
|
|
|
|
|
* | | ... |
|
|
|
|
|
|
|
* | | last instruction |
|
|
|
|
|
|
|
* | |- optional jump after catch block (last+1) |
|
|
|
|
|
|
|
* | | ... | |
|
|
|
|
|
|
|
* | `- catch block | |
|
|
|
|
|
|
|
* | ... | |
|
|
|
|
|
|
|
* | ,-----------------' |
|
|
|
|
|
|
|
* | |-jump after all catch blocks |
|
|
|
|
|
|
|
* | v |
|
|
|
|
|
|
|
* | jsr finally -----------------, |
|
|
|
|
|
|
|
* |- jump after finally | |
|
|
|
|
|
|
|
* `- catch any (local_n) v |
|
|
|
|
|
|
|
* jsr finally ---------------->| |
|
|
|
|
|
|
|
* throw local_n; | |
|
|
|
|
|
|
|
* finally: <-----------------------' |
|
|
|
|
|
|
|
* astore_n |
|
|
|
|
|
|
|
* ... |
|
|
|
|
|
|
|
* return_n |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* flow-block |
|
|
|
|
|
|
|
* finally-block |
|
|
|
|
|
|
|
* ---> try-header |
|
|
|
|
|
|
|
* finally { |
|
|
|
|
|
|
|
* ---> first-finally-instruction |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* A synchronized block uses a similar technique: |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* local_x = monitor object; |
|
|
|
|
|
|
|
* monitorenter local_x |
|
|
|
|
|
|
|
* try-header any |
|
|
|
|
|
|
|
* |- syncronized block |
|
|
|
|
|
|
|
* | ... |
|
|
|
|
|
|
|
* | every jump to outside is preceded by jsr monexit ---, |
|
|
|
|
|
|
|
* | ... | |
|
|
|
|
|
|
|
* |- monitorexit local_x | |
|
|
|
|
|
|
|
* | jump after this block (without jsr monexit) | |
|
|
|
|
|
|
|
* `- catch any (local_n) | |
|
|
|
|
|
|
|
* monitorexit local_x | |
|
|
|
|
|
|
|
* throw local_n | |
|
|
|
|
|
|
|
* monexit: <-----------------------------------------------' |
|
|
|
|
|
|
|
* astore_n |
|
|
|
|
|
|
|
* monitorexit local_x |
|
|
|
|
|
|
|
* return_n |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public boolean doT1 { |
|
|
|
IfThenElseBlock newIfBlock = |
|
|
|
/* search successor with smallest addr. */ |
|
|
|
new IfThenElseBlock(cb.getCondition().negate(), |
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
sequBlock.getSubBlocks()[1], null); |
|
|
|
FlowBlock succ = null; |
|
|
|
|
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
|
|
|
FlowBlock fb = ((Jump) enum.nextElement()).destination; |
|
|
|
|
|
|
|
if (succ == null || fb.addr < succ.addr) { |
|
|
|
|
|
|
|
succ = fb; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (succ == null) { |
|
|
|
|
|
|
|
/* There are no successors at all */ |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* check if this successor has only this block as predecessor. */ |
|
|
|
|
|
|
|
/* if not, return false. */ |
|
|
|
|
|
|
|
if (succ.predecessors.size() != 1) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* First find the innermost block that contains all jumps to this |
|
|
|
|
|
|
|
* successor and the last modified block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
|
|
|
|
StructuredBlock structBlock = lastModified; |
|
|
|
|
|
|
|
while(enum.hasMoreElements()) { |
|
|
|
|
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (!structBlock.contains(jump.parent)) |
|
|
|
newIfBlock.replace(sequBlock); |
|
|
|
structBlock = structBlock.outer; |
|
|
|
|
|
|
|
/* structBlock can't be null now, because the |
|
|
|
|
|
|
|
* outermost block contains every structured block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The switch "fall through" case: if the structBlock is a |
|
|
|
if (appendBlock == sequBlock) |
|
|
|
* switch, and the successor is the address of a case, and all |
|
|
|
appendBlock = newIfBlock; |
|
|
|
* other successors are inside the block preceding that case. |
|
|
|
continue; |
|
|
|
*/ |
|
|
|
} |
|
|
|
if (case != null) { |
|
|
|
|
|
|
|
SwitchBlock switchBlock = (StructuredBlock) structBlock; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now put the succ.block into the next case. |
|
|
|
/* if the successor is the dummy return instruction, replace all |
|
|
|
|
|
|
|
* jumps with a return. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
switchBlock.replaceSubBlock(nextcase,succ.block); |
|
|
|
if (successor.block.instanceof ReturnBlock) { |
|
|
|
|
|
|
|
SequentialBlock sequBlock = new SequentialBlock(); |
|
|
|
|
|
|
|
StructuredBlock prevBlock = jump.parent; |
|
|
|
|
|
|
|
prevBlock.removeJump(); |
|
|
|
|
|
|
|
sequBlock.replace(prevBlock); |
|
|
|
|
|
|
|
sequBlock.setFirst(prevBlock); |
|
|
|
|
|
|
|
sequBlock.setSecond(new ReturnBlock()); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Do the following modifications on the struct block. */ |
|
|
|
/* If this is a conditional jump, the first instruction of |
|
|
|
structBlock = precedingcase; |
|
|
|
* a while and the condition of the while is true, use |
|
|
|
|
|
|
|
* the condition as while condition. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
/* This is the first instruction in a while block */ |
|
|
|
|
|
|
|
if (jump.parent instanceof ConditionalBlock && |
|
|
|
|
|
|
|
jump.parent.outer instanceof SequentialBlock && |
|
|
|
|
|
|
|
jump.parent.outer.getSubBlocks()[0] == this && |
|
|
|
|
|
|
|
jump.parent.outer.outer instanceof LoopBlock) { |
|
|
|
|
|
|
|
ConditionalBlock cb = (ConditionalBlock) jump.parent; |
|
|
|
|
|
|
|
LoopBlock loopBlock = (LoopBlock) cb.outer.outer; |
|
|
|
|
|
|
|
if (loopBlock.getCondition() == LoopBlock.TRUE && |
|
|
|
|
|
|
|
loopBlock.getType() != LoopBlock.DOWHILE && |
|
|
|
|
|
|
|
loopBlock.getNextFlowBlock() == successor) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cb.removeJump(); |
|
|
|
|
|
|
|
loopBlock.setCondition(cb); |
|
|
|
|
|
|
|
cb.outer.getSubBlocks()[1].replace(cb.outer); |
|
|
|
|
|
|
|
/* cb and cb.outer are not used any more */ |
|
|
|
|
|
|
|
/* Note that cb.outer != appendBlock because |
|
|
|
|
|
|
|
* appendBlock contains loopBlock |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Now the same for the empty loop. In this case there is |
|
|
|
|
|
|
|
* no sequential block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (jump.parent instanceof ConditionalBlock && |
|
|
|
|
|
|
|
jump.parent.outer instanceof LoopBlock) { |
|
|
|
|
|
|
|
ConditionalBlock cb = (ConditionalBlock) jump.parent; |
|
|
|
|
|
|
|
LoopBlock loopBlock = (LoopBlock) cb.outer; |
|
|
|
|
|
|
|
if (loopBlock.getCondition() == LoopBlock.TRUE && |
|
|
|
|
|
|
|
loopBlock.getType() != LoopBlock.DOWHILE && |
|
|
|
|
|
|
|
loopBlock.getNextFlowBlock() == successor) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cb.removeJump(); |
|
|
|
|
|
|
|
loopBlock.setCondition(cb); |
|
|
|
|
|
|
|
EmptyBlock empty = new EmptyBlock(); |
|
|
|
|
|
|
|
empty.replace(cb); |
|
|
|
|
|
|
|
/* cb is not used any more */ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Prepare the unification of the blocks: Make sure that |
|
|
|
/* if there are jumps in a while block or switch block and the |
|
|
|
* structBlock has a successor outside of this block. This is |
|
|
|
* while/switch block is followed by a jump to successor or has |
|
|
|
* always possible, because it contains lastModified. |
|
|
|
* successor as getNextFlowBlock(), replace jump with break to |
|
|
|
|
|
|
|
* the innermost such while/switch block. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* If the switch block hasn't been breaked before we could |
|
|
|
|
|
|
|
* take some heuristics and add a jump after the switch to |
|
|
|
|
|
|
|
* succesor, so that the above succeeds. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (structBlock.jump == null) { |
|
|
|
int breaklevel = 0; |
|
|
|
/* assert(structBlock.jump.getNextFlowBlock() != null) */ |
|
|
|
for (StructuredBlock surrounder = jump.parent.outer; |
|
|
|
structBlock.setJump(structBlock.getNextFlowBlock()); |
|
|
|
surrounder != null; surrounder = surrounder.outer) { |
|
|
|
|
|
|
|
if (surrounder instanceof BreakableBlock) { |
|
|
|
|
|
|
|
breaklevel++; |
|
|
|
|
|
|
|
if (surrounder.getNextFlowBlock() == successor || |
|
|
|
|
|
|
|
surrounder.jumpMayBeChanged()) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SequentialBlock sequBlock = new SequentialBlock(); |
|
|
|
|
|
|
|
StructuredBlock prevBlock = jump.parent; |
|
|
|
|
|
|
|
if (surrounder.getNextFlowBlock() != successor) { |
|
|
|
|
|
|
|
surrounder.jump = jump; |
|
|
|
|
|
|
|
prevBlock.jump = null; |
|
|
|
|
|
|
|
jump.parent = surrounder; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
prevBlock.removeJump(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sequBlock.replace(prevBlock); |
|
|
|
|
|
|
|
sequBlock.setFirst(prevBlock); |
|
|
|
|
|
|
|
sequBlock.setSecond(new BreakBlock(surrounder, |
|
|
|
|
|
|
|
breaklevel > 1)); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Now unify the blocks: Create a new SequentialBlock |
|
|
|
|
|
|
|
* containing structBlock and successor.block. Then replace |
|
|
|
/* if there are jumps in an if-then block, which |
|
|
|
* structBlock with the new sequential block. |
|
|
|
* have as normal successor the end of the if-then block, and |
|
|
|
|
|
|
|
* the if-then block is followed by a single block, then replace |
|
|
|
|
|
|
|
* the if-then block with a if-then-else block and remove the |
|
|
|
|
|
|
|
* unconditional jump. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
StructuredBlock elseBlock = |
|
|
|
|
|
|
|
jump.parent.outer.getNextBlock(jump.parent); |
|
|
|
|
|
|
|
if (elseBlock != null && |
|
|
|
|
|
|
|
elseBlock.outer != null && |
|
|
|
|
|
|
|
elseBlock.outer instanceof SequentialBlock && |
|
|
|
|
|
|
|
elseBlock.outer.getSubBlocks()[0] instanceof IfThenElseBlock && |
|
|
|
|
|
|
|
(elseBlock.outer.getNextFlowBlock() == successor || |
|
|
|
|
|
|
|
elseBlock.outer.jumpMayBeChanged()) { |
|
|
|
|
|
|
|
IfThenElseBlock ifBlock = |
|
|
|
|
|
|
|
(IfThenElseBlock)elseBlock.outer.getSubBlocks()[0]; |
|
|
|
|
|
|
|
if (ifBlock.getElseBlock() == null) { |
|
|
|
|
|
|
|
if (elseBlock.getNextFlowBlock() != successor) { |
|
|
|
|
|
|
|
elseBlock.outer.jump = jump; |
|
|
|
|
|
|
|
jump.parent.jump = null; |
|
|
|
|
|
|
|
jump.parent = elseBlock.outer; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
jump.parent.removeJump(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ifBlock.replace(elseBlock.outer) |
|
|
|
|
|
|
|
ifBlock.setElseBlock(elseBlock); |
|
|
|
|
|
|
|
if (appendBlock = elseBlock.outer) |
|
|
|
|
|
|
|
appendBlock = ifBlock; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return appendBlock; |
|
|
|
/* Try to eliminate as many jumps as possible. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
optimizeJumps(succ, structBlock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now remove the jump of the structBlock if it points to successor. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (structBlock.jump == null) |
|
|
|
|
|
|
|
structBlock.removeJump(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If there are further jumps, put a do/while(0) block around |
|
|
|
|
|
|
|
* structBlock and replace every remaining jump with a break |
|
|
|
|
|
|
|
* to the do/while block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Set last modified to correct value. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
lastModified = succ.lastModified; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Updates the in/out-Vectors of the structured block of the |
|
|
|
|
|
|
|
* successing flow block simultanous to a T1 transformation. |
|
|
|
|
|
|
|
* @param successor The flow block which is unified with this flow |
|
|
|
|
|
|
|
* block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
void updateInOut (FlowBlock successor, boolean t1Transformation) { |
|
|
|
|
|
|
|
/* First get the out vectors of all jumps to successor and |
|
|
|
|
|
|
|
* calculate the intersection. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
VariableSet allOuts = new VariableSet(); |
|
|
|
|
|
|
|
VariableSet intersectOut = null; |
|
|
|
|
|
|
|
Enumeration enum = successors; |
|
|
|
|
|
|
|
while (enum.hasMoreElement()) { |
|
|
|
|
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
|
|
|
|
if (jump == null || jump.destination != successor) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
allOuts.union(jump.parent.out); |
|
|
|
|
|
|
|
if (intersectOut == null) |
|
|
|
|
|
|
|
intersectOut = jump.parent.out; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
intersectOut = intersectOut.intersect(jump.parent.out); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now work on each block of the successor */ |
|
|
|
|
|
|
|
Stack todo = new Stack(); |
|
|
|
|
|
|
|
todo.push(successor.block); |
|
|
|
|
|
|
|
while (!todo.empty()) { |
|
|
|
|
|
|
|
StructuredBlock block = (StructuredBlock) todo.pop(); |
|
|
|
|
|
|
|
StructuredBlock[] subBlocks = block.getSubBlocks(); |
|
|
|
|
|
|
|
for (int i=0; i<subBlocks.length; i++) |
|
|
|
|
|
|
|
todo.push(subBlocks[i]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Merge the locals used in successing block with those written |
|
|
|
|
|
|
|
* by this blocks |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
block.in.merge(allOuts); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (t1Transformation) { |
|
|
|
|
|
|
|
/* Now update in and out set of successing block */ |
|
|
|
|
|
|
|
block.in.subtract(intersectOut); |
|
|
|
|
|
|
|
block.out.add(intersectOut); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Special cases: |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* try-header |
|
|
|
|
|
|
|
* |- first instruction |
|
|
|
|
|
|
|
* | ... |
|
|
|
|
|
|
|
* | last instruction |
|
|
|
|
|
|
|
* |- optional jump (last+1) |
|
|
|
|
|
|
|
* | ... |
|
|
|
|
|
|
|
* `- catch block |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* A try block may have many try-headers with different catch blocks |
|
|
|
|
|
|
|
* and there may be a finally block: |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* try-header any |
|
|
|
|
|
|
|
* | try-header |
|
|
|
|
|
|
|
* |--|- first instruction |
|
|
|
|
|
|
|
* | | ... |
|
|
|
|
|
|
|
* | | every jump to outside is preceded by jsr finally |
|
|
|
|
|
|
|
* | | ... |
|
|
|
|
|
|
|
* | | last instruction |
|
|
|
|
|
|
|
* | |- optional jump after catch block (last+1) |
|
|
|
|
|
|
|
* | | ... | |
|
|
|
|
|
|
|
* | `- catch block | |
|
|
|
|
|
|
|
* | ... | |
|
|
|
|
|
|
|
* | ,-----------------' |
|
|
|
|
|
|
|
* | |-jump after all catch blocks |
|
|
|
|
|
|
|
* | v |
|
|
|
|
|
|
|
* | jsr finally -----------------, |
|
|
|
|
|
|
|
* |- jump after finally | |
|
|
|
|
|
|
|
* `- catch any (local_n) v |
|
|
|
|
|
|
|
* jsr finally ---------------->| |
|
|
|
|
|
|
|
* throw local_n; | |
|
|
|
|
|
|
|
* finally: <-----------------------' |
|
|
|
|
|
|
|
* astore_n |
|
|
|
|
|
|
|
* ... |
|
|
|
|
|
|
|
* return_n |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* flow-block |
|
|
|
|
|
|
|
* finally-block |
|
|
|
|
|
|
|
* ---> try-header |
|
|
|
|
|
|
|
* finally { |
|
|
|
|
|
|
|
* ---> first-finally-instruction |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* A synchronized block uses a similar technique: |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* local_x = monitor object; |
|
|
|
|
|
|
|
* monitorenter local_x |
|
|
|
|
|
|
|
* try-header any |
|
|
|
|
|
|
|
* |- syncronized block |
|
|
|
|
|
|
|
* | ... |
|
|
|
|
|
|
|
* | every jump to outside is preceded by jsr monexit ---, |
|
|
|
|
|
|
|
* | ... | |
|
|
|
|
|
|
|
* |- monitorexit local_x | |
|
|
|
|
|
|
|
* | jump after this block (without jsr monexit) | |
|
|
|
|
|
|
|
* `- catch any (local_n) | |
|
|
|
|
|
|
|
* monitorexit local_x | |
|
|
|
|
|
|
|
* throw local_n | |
|
|
|
|
|
|
|
* monexit: <-----------------------------------------------' |
|
|
|
|
|
|
|
* astore_n |
|
|
|
|
|
|
|
* monitorexit local_x |
|
|
|
|
|
|
|
* return_n |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public boolean doT1 { |
|
|
|
|
|
|
|
/* search successor with smallest addr. */ |
|
|
|
|
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
|
|
|
|
FlowBlock succ = null; |
|
|
|
|
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
|
|
|
|
if (jump == null) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
FlowBlock fb = jump.destination; |
|
|
|
|
|
|
|
if (succ == null || fb.addr < succ.addr) { |
|
|
|
|
|
|
|
succ = fb; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (succ == null) { |
|
|
|
|
|
|
|
/* There are no successors at all */ |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* check if this successor has only this block as predecessor. */ |
|
|
|
|
|
|
|
/* if not, return false. */ |
|
|
|
|
|
|
|
if (succ.predecessors.size() != 1) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* First find the innermost block that contains all jumps to this |
|
|
|
|
|
|
|
* successor and the last modified block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
|
|
|
|
StructuredBlock appendBlock = lastModified; |
|
|
|
|
|
|
|
while(enum.hasMoreElements()) { |
|
|
|
|
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
|
|
|
|
if (jump == null || jump.destination != successors) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (!appendBlock.contains(jump.parent)) |
|
|
|
|
|
|
|
appendBlock = appendBlock.outer; |
|
|
|
|
|
|
|
/* appendBlock can't be null now, because the |
|
|
|
|
|
|
|
* outermost block contains every structured block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Update the in/out-Vectors now */ |
|
|
|
|
|
|
|
updateInOut(successor, true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The switch "fall through" case: if the appendBlock is a |
|
|
|
|
|
|
|
* switch, and the successor is the address of a case, and all |
|
|
|
|
|
|
|
* other successors are inside the block preceding that case. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (case != null) { |
|
|
|
|
|
|
|
SwitchBlock switchBlock = (StructuredBlock) appendBlock; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now put the succ.block into the next case. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
switchBlock.replaceSubBlock(nextcase,succ.block); |
|
|
|
|
|
|
|
succ.block.outer = switchBlock; |
|
|
|
|
|
|
|
/* nextcase is not referenced any more */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Do the following modifications on the struct block. */ |
|
|
|
|
|
|
|
appendBlock = precedingcase; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Prepare the unification of the blocks: Make sure that |
|
|
|
|
|
|
|
* appendBlock has a successor outside of this block. This is |
|
|
|
|
|
|
|
* always possible, because it contains lastModified. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (appendBlock.jump == null) { |
|
|
|
|
|
|
|
/* assert(appendBlock.jump.getNextFlowBlock() != null) */ |
|
|
|
|
|
|
|
appendBlock.setJump(appendBlock.getNextFlowBlock()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now unify the blocks: Create a new SequentialBlock |
|
|
|
|
|
|
|
* containing appendBlock and successor.block. Then replace |
|
|
|
|
|
|
|
* appendBlock with the new sequential block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
StructuredBlock outer = appendBlock.outer; |
|
|
|
|
|
|
|
StructuredBlock sequBlock = |
|
|
|
|
|
|
|
new SequentialBlock(appendBlock, switchBlock); |
|
|
|
|
|
|
|
outer.replaceSubBlock(appendBlock, sequBlock); |
|
|
|
|
|
|
|
sequBlock.outer = outer; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Try to eliminate as many jumps as possible. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
optimizeJumps(succ, appendBlock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Now remove the jump of the appendBlock if it points to successor. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (appendBlock.jump == succ) |
|
|
|
|
|
|
|
appendBlock.removeJump(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If there are further jumps, put a do/while(0) block around |
|
|
|
|
|
|
|
* appendBlock and replace every remaining jump with a break |
|
|
|
|
|
|
|
* to the do/while block. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Believe it or not: Now the rule, that the first part of a |
|
|
|
|
|
|
|
* SequentialBlock shouldn't be another SequentialBlock is |
|
|
|
|
|
|
|
* fulfilled. <p> |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* This isn't easy to prove, it has a lot to do with the |
|
|
|
|
|
|
|
* transformation in optimizeJump and the fact that |
|
|
|
|
|
|
|
* appendBlock was the innermost Block containing all jumps |
|
|
|
|
|
|
|
* and lastModified. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Set last modified to correct value. */ |
|
|
|
|
|
|
|
lastModified = succ.lastModified; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public boolean doT2() { |
|
|
|
public boolean doT2() { |
|
|
|
/* If there are no jumps to the beginning of this flow block |
|
|
|
/* If there are no jumps to the beginning of this flow block |
|
|
|
* or if this block has other predecessors which weren't |
|
|
|
* or if this block has other predecessors which weren't |
|
|
@ -261,6 +468,9 @@ public class FlowBlock { |
|
|
|
* sure that the while isn't created up to the first continue. |
|
|
|
* sure that the while isn't created up to the first continue. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Update the in/out-Vectors now */ |
|
|
|
|
|
|
|
updateInOut(successor, false); |
|
|
|
|
|
|
|
|
|
|
|
/* If there is only one jump to the beginning and it is the |
|
|
|
/* If there is only one jump to the beginning and it is the |
|
|
|
* last jump and (there is a do/while(0) block surrounding |
|
|
|
* last jump and (there is a do/while(0) block surrounding |
|
|
|
* everything but the last instruction, or the last |
|
|
|
* everything but the last instruction, or the last |
|
|
@ -286,6 +496,10 @@ public class FlowBlock { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void removeSuccessor(Jump jump) { |
|
|
|
|
|
|
|
successors.setElementAt(null, successors.indexOf(jump)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|