*** empty log message ***

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@18 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 27 years ago
parent 2427c7f532
commit c885953efd
  1. 564
      jode/jode/flow/FlowBlock.java
  2. 56
      jode/jode/flow/IfThenElseBlock.java
  3. 84
      jode/jode/flow/StructuredBlock.java

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

@ -39,21 +39,31 @@ public class IfThenElseBlock extends StructuredBlock {
StructuredBlock elseBlock; StructuredBlock elseBlock;
/** /**
* Creates a new if then else block. * Creates a new if then else block. The method setThenBlock must
* @param thenBlock the then block, must be non null. * be called shortly after the creation.
* @param elseBlock the else block, may be null.
*/ */
public IfThenElseBlock(Instruction cond, public IfThenElseBlock(Instruction cond) {
StructuredBlock thenBlock,
StructuredBlock elseBlock) {
this.cond = cond; this.cond = cond;
}
/**
* Sets the then block.
* @param thenBlock the then block, must be non null.
*/
public void setThenBlock(StructuredBlock thenBlock) {
this.thenBlock = thenBlock; this.thenBlock = thenBlock;
this.elseBlock = elseBlock;
thenBlock.outer = this; thenBlock.outer = this;
if (elseBlock != null)
elseBlock.outer = this;
} }
/**
* Sets the else block.
* @param elseBlock the else block
*/
public void setElseBlock(StructuredBlock elseBlock) {
this.elseBlock = elseBlock;
elseBlock.outer = this;
}
/* The implementation of getNext[Flow]Block is the standard /* The implementation of getNext[Flow]Block is the standard
* implementation */ * implementation */
@ -98,4 +108,32 @@ public class IfThenElseBlock extends StructuredBlock {
if (needBrace) if (needBrace)
writer.println("}"); writer.println("}");
} }
/**
* Returns all sub block of this structured block.
*/
StructuredBlock[] getSubBlocks() {
if (elseBlock == null) {
StructuredBlock result = { thenBlock };
return result;
} else {
StructuredBlock result = { thenBlock, elseBlock };
return result;
}
}
/**
* Determines if there is a sub block, that flows through to the end
* of this block. If this returns true, you know that jump is null.
* @return true, if the jump may be safely changed.
*/
public boolean jumpMayBeChanged() {
if (thenBlock.jump == null && !thenBlock.jumpMayBeChanged())
return false;
if (elseBlock != null && elseBlock.jump == null &&
!elseBlock.jumpMayBeChanged)
return false;
return true;
}
} }

@ -65,7 +65,7 @@ public abstract class StructuredBlock {
* path from the start of the current flow block, on which the * path from the start of the current flow block, on which the
* local variable is never assigned * local variable is never assigned
*/ */
Vector in; VariableSet in;
/** /**
* The out locals. This are the locals, which must be overwritten * The out locals. This are the locals, which must be overwritten
@ -74,12 +74,18 @@ public abstract class StructuredBlock {
* structured block contain a (unconditional) assignment to this * structured block contain a (unconditional) assignment to this
* local * local
*/ */
Vector out; VariableSet out;
/** /**
* The surrounding structured block. If this is the outermost * The variable set containing all variables that must be defined
* block in a flow block, outer is null. * in this block (or maybe an outer block, this changes as the
* blocks are put together).
*/ */
VariableSet defineHere;
/**
* The surrounding structured block. If this is the outermost
* block in a flow block, outer is null. */
StructuredBlock outer; StructuredBlock outer;
/** /**
@ -96,9 +102,11 @@ public abstract class StructuredBlock {
/** /**
* Returns the block where the control will normally flow to, when * Returns the block where the control will normally flow to, when
* this block is finished (ignoring the jump after this block). * this block is finished (not ignoring the jump after this block).
*/ */
StructuredBlock getNextBlock() { StructuredBlock getNextBlock() {
if (jump != null)
return null;
if (outer != null) if (outer != null)
outer.getNextBlock(this); outer.getNextBlock(this);
else else
@ -107,12 +115,14 @@ public abstract class StructuredBlock {
/** /**
* Returns the flow block where the control will normally flow to, * Returns the flow block where the control will normally flow to,
* when this block is finished (ignoring the jump after this * when this block is finished (not ignoring the jump after this
* block). * block).
* @return null, if the control flows into a non empty structured * @return null, if the control flows into a non empty structured
* block or if this is the outermost block. * block or if this is the outermost block.
*/ */
FlowBlock getNextFlowBlock() { FlowBlock getNextFlowBlock() {
if (jump != null)
return jump.destination;
if (outer != null) if (outer != null)
outer.getNextFlowBlock(this); outer.getNextFlowBlock(this);
else else
@ -142,14 +152,10 @@ public abstract class StructuredBlock {
* the behaviour is undefined, so take care. * the behaviour is undefined, so take care.
* @return null, if the control flows to another FlowBlock. */ * @return null, if the control flows to another FlowBlock. */
StructuredBlock getNextBlock(StructuredBlock subBlock) { StructuredBlock getNextBlock(StructuredBlock subBlock) {
if (jump != null)
return null;
return getNextBlock(); return getNextBlock();
} }
FlowBlock getNextFlowBlock(StructuredBlock subBlock) { FlowBlock getNextFlowBlock(StructuredBlock subBlock) {
if (jump != null)
return jump.destination;
return getNextFlowBlock(); return getNextFlowBlock();
} }
@ -164,6 +170,13 @@ public abstract class StructuredBlock {
return false; return false;
} }
/**
* Returns all sub block of this structured block.
*/
StructuredBlock[] getSubBlocks() {
return new StructuredBlock[0];
}
/** /**
* Returns if this block contains the given block. * Returns if this block contains the given block.
* @param child the block which should be contained by this block. * @param child the block which should be contained by this block.
@ -175,11 +188,58 @@ public abstract class StructuredBlock {
return (child == this); return (child == this);
} }
/**
* Removes the jump after this structured block. This does also update
* the successors vector of the flow block.
*/
public void removeJump() {
if (jump != null) {
flowBlock.removeSuccessor(jump);
jump = null;
}
}
/**
* This function replaces sb with this block. It copies outer and
* the following jump from sb, and updates them, so they know that
* sb was replaced.
* The jump field of sb is removed afterwards. You have to replace
* sb.outer or mustn't use sb anymore.
* @param sb The structured block that should be replaced.
*/
public void replace(StructuredBlock sb) {
in = sb.in;
out = sb.out;
defineHere = sb.defineHere;
outer = sb.outer;
flowBlock = sb.flowBlock;
jump = sb.jump;
if (jump != null) {
jump.parent = this;
sb.jump = null;
}
if (outer != null) {
outer.replaceSubBlock(sb, this);
} else {
flowBlock.block = this;
}
}
/**
* Determines if there is a sub block, that flows through to the end
* of this block. If this returns true, you know that jump is null.
* @return true, if the jump may be safely changed.
*/
public boolean jumpMayBeChanged() {
return false;
}
/** /**
* Print the source code for this structured block. This may be * Print the source code for this structured block. This may be
* called only once, because it remembers which local variables * called only once, because it remembers which local variables
* were declared. * were declared. */
*/
public abstract void dumpSource(TabbedPrintWriter writer) public abstract void dumpSource(TabbedPrintWriter writer)
throws java.io.IOException; throws java.io.IOException;
} }

Loading…
Cancel
Save