dead code elimination

print all flow blocks


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@205 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent cf1ef397e5
commit acfe14f7af
  1. 249
      jode/jode/flow/FlowBlock.java

@ -37,6 +37,9 @@ public class FlowBlock {
static FlowBlock END_OF_METHOD = static FlowBlock END_OF_METHOD =
new FlowBlock(null, Integer.MAX_VALUE, 0, new EmptyBlock()); new FlowBlock(null, Integer.MAX_VALUE, 0, new EmptyBlock());
static FlowBlock ILLEGAL =
new FlowBlock(null, -1, 0, new DescriptionBlock("ILLEGAL BLOCK"));
static { static {
END_OF_METHOD.label = "END_OF_METHOD"; END_OF_METHOD.label = "END_OF_METHOD";
} }
@ -88,7 +91,7 @@ public class FlowBlock {
/** /**
* This contains a map of all successing flow blocks and there * This contains a map of all successing flow blocks and there
* jumps. The key of this dictionary are the flow blocks, while * jumps. The key of this dictionary are the flow blocks, while
* the elements is the first jump to that dictionary. 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.
*/ */
Dictionary successors = new SimpleDictionary(); Dictionary successors = new SimpleDictionary();
@ -103,6 +106,25 @@ public class FlowBlock {
*/ */
Vector predecessors = new Vector(); Vector predecessors = new Vector();
/**
* This is set if the block is reachable. If this is false after
* marking the start block and the catch blocks as reachable, this
* block is dead code and may (must) be removed.
*/
boolean reachable = false;
/**
* This is a pointer to the next flow block in byte code order.
* It is null for the last flow block.
*/
FlowBlock nextByAddr;
/**
* This is a pointer to the previous flow block in byte code order.
* It is null for the first flow block.
*/
FlowBlock prevByAddr;
/** /**
* The default constructor. Creates a new flowblock containing * The default constructor. Creates a new flowblock containing
* only the given structured block. * only the given structured block.
@ -118,7 +140,7 @@ public class FlowBlock {
block.fillInGenSet(in, gen); block.fillInGenSet(in, gen);
} }
public int getNextAddr() { public final int getNextAddr() {
return addr+length; return addr+length;
} }
@ -168,47 +190,47 @@ public class FlowBlock {
* be lastModified. * be lastModified.
*/ */
/* remove this jump if it jumps to the getNextFlowBlock().
*/
if (jump.destination
== jump.prev.outer.getNextFlowBlock(jump.prev)) {
jump.prev.removeJump();
continue;
}
if (jump.prev.outer instanceof ConditionalBlock) { if (jump.prev.outer instanceof ConditionalBlock) {
StructuredBlock prev = jump.prev; StructuredBlock prev = jump.prev;
ConditionalBlock cb = (ConditionalBlock) prev.outer; ConditionalBlock cb = (ConditionalBlock) prev.outer;
Expression instr = cb.getInstruction(); Expression instr = cb.getInstruction();
/* This is a jump inside an ConditionalBlock.
*
* cb is the conditional block,
* prev the empty block containing the jump
* instr is the condition */
if (cb.jump != null) { if (cb.jump != null) {
/* This can only happen if cb also jumps to succ. /* This can only happen if cb also jumps to succ.
* This is a weired "if (cond) empty"-block. We * This is a weired "if (cond) empty"-block. We
* transform it by hand. * transform it by hand.
*/ */
prev.removeJump(); prev.removeJump();
IfThenElseBlock ifBlock = IfThenElseBlock ifBlock =
new IfThenElseBlock(cb.getInstruction()); new IfThenElseBlock(cb.getInstruction().negate());
ifBlock.moveDefinitions(cb, prev); ifBlock.moveDefinitions(cb, prev);
ifBlock.replace(cb); ifBlock.replace(cb);
ifBlock.moveJump(cb.jump);
ifBlock.setThenBlock(prev); ifBlock.setThenBlock(prev);
if (cb == lastModified)
lastModified = ifBlock;
continue; continue;
} }
/* Now cb.jump is null, so cb.outer is not null, /* Now cb.jump is null, so cb.outer is not null,
* since otherwise it would have no successor. */ * since otherwise it would have no successor. */
/* If this is the first instruction of a
* while/for(true) block, make this the loop condition
* (negated of course).
*/
if (cb.outer instanceof LoopBlock if (cb.outer instanceof LoopBlock
|| (cb.outer instanceof SequentialBlock || (cb.outer instanceof SequentialBlock
&& cb.outer.getSubBlocks()[0] == cb && cb.outer.getSubBlocks()[0] == cb
&& cb.outer.outer instanceof LoopBlock)) { && cb.outer.outer instanceof LoopBlock)) {
/* If this is the first instruction of a
* while/for(true) block, make this the loop condition
* (negated of course).
*/
LoopBlock loopBlock = (cb.outer instanceof LoopBlock) ? LoopBlock loopBlock = (cb.outer instanceof LoopBlock) ?
(LoopBlock) cb.outer : (LoopBlock) cb.outer.outer; (LoopBlock) cb.outer : (LoopBlock) cb.outer.outer;
@ -268,9 +290,19 @@ public class FlowBlock {
} }
} }
/* This is still a jump inside an ConditionalBlock.
*
* cb is the conditional block,
* prev the empty block containing the jump
* instr is the condition */
/* replace all conditional jumps to the successor, which /* replace all conditional jumps to the successor, which
* are followed by a block which has the end of the block * are followed by a block which has the end of the block
* as normal successor, with "if (not condition) block". * as normal successor, with "if (not condition) block":
*
* /IF cond GOTO succ if (!cond)
* \block ===> block
* -> normal Succesor succ -> normal Successor succ
*/ */
if (cb.outer instanceof SequentialBlock && if (cb.outer instanceof SequentialBlock &&
cb.outer.getSubBlocks()[0] == cb && cb.outer.getSubBlocks()[0] == cb &&
@ -303,6 +335,15 @@ public class FlowBlock {
continue; continue;
} }
} else { } else {
/* remove this jump if it jumps to the
* getNextFlowBlock(). */
if (jump.destination
== jump.prev.outer.getNextFlowBlock(jump.prev)) {
jump.prev.removeJump();
continue;
}
/* Now find the real outer block, that is ascend the chain /* Now find the real outer block, that is ascend the chain
* of SequentialBlocks. * of SequentialBlocks.
@ -317,11 +358,31 @@ public class FlowBlock {
while (sb instanceof SequentialBlock) while (sb instanceof SequentialBlock)
sb = sb.outer; sb = sb.outer;
/* if this is a unconditional jump at the end of a
* then block belonging to a if-then block without
* else part, but a single jump, then replace the
* if-then block with a if-then-else block with an
* empty block as else block that jumps and move the
* unconditional jump to the if.
*/
if (sb instanceof IfThenElseBlock) {
IfThenElseBlock ifBlock = (IfThenElseBlock) sb;
if (ifBlock.elseBlock == null && ifBlock.jump != null) {
ifBlock.setElseBlock(new EmptyBlock());
ifBlock.elseBlock.moveJump(ifBlock.jump);
ifBlock.moveJump(jump);
/* consider this jump again */
jumps = jump;
continue;
}
}
/* if this is a jump at the end of a then block belonging /* if this is a jump at the end of a then block belonging
* to a if-then block without else part, and the if-then * to a if-then block without else part, and the if-then
* block is followed by a single block, then replace the * block is followed by a single block, then replace the
* if-then block with a if-then-else block and remove the * if-then block with a if-then-else block and move the
* unconditional jump. * unconditional jump to the if.
*/ */
if (sb instanceof IfThenElseBlock if (sb instanceof IfThenElseBlock
&& sb.outer instanceof SequentialBlock && sb.outer instanceof SequentialBlock
@ -333,6 +394,7 @@ public class FlowBlock {
if (ifBlock.elseBlock == null if (ifBlock.elseBlock == null
&& (elseBlock.getNextFlowBlock() == succ && (elseBlock.getNextFlowBlock() == succ
|| elseBlock.jump != null
|| elseBlock.jumpMayBeChanged())) { || elseBlock.jumpMayBeChanged())) {
ifBlock.replace(sequBlock); ifBlock.replace(sequBlock);
@ -470,7 +532,52 @@ public class FlowBlock {
} }
} }
} }
/**
* Fixes the addr chained list, after merging this block with succ.
*/
public void mergeAddr(FlowBlock succ) {
if (succ.nextByAddr == this || succ.prevByAddr == null) {
/* Merge succ with its nextByAddr.
* Note: succ.nextByAddr != null, since this is on the
* nextByAddr chain. */
succ.nextByAddr.addr = succ.addr;
succ.nextByAddr.length += succ.length;
succ.nextByAddr.prevByAddr = succ.prevByAddr;
if (succ.prevByAddr != null)
succ.prevByAddr.nextByAddr = succ.nextByAddr;
} else {
/* Merge succ with its prevByAddr */
succ.prevByAddr.length += succ.length;
succ.prevByAddr.nextByAddr = succ.nextByAddr;
if (succ.nextByAddr != null)
succ.nextByAddr.prevByAddr = succ.prevByAddr;
}
}
// /**
// * Mark all predecessors of this block as illegal, i.e. change the
// * successor to the ILLEGAL block.
// */
// public void markPredecessorsIllegal() {
// Enumeration preds = predecessors.elements();
// while (preds.hasMoreElements()) {
// FlowBlock pred = (FlowBlock) preds.nextElement();
// Jump jump = (Jump)pred.successors.remove(this);
// for (/**/; jump.next != null; jump = jump.next)
// jump.destination = ILLEGAL;
// jump.destination = ILLEGAL;
// jump.next = (Jump) pred.successors.get(jump.destination);
// if (jump.next == null)
// ILLEGAL.predecessors.addElement(this);
// pred.successors.put(jump.destination, jump);
// }
// predecessors.removeAllElements();
// }
/** /**
* Updates the in/out-Vectors of the structured block of the * Updates the in/out-Vectors of the structured block of the
* successing flow block simultanous to a T1 transformation. * successing flow block simultanous to a T1 transformation.
@ -606,8 +713,14 @@ public class FlowBlock {
* a special precondition: The succ must be a simple instruction block, * a special precondition: The succ must be a simple instruction block,
* mustn't have another predecessor and all structured blocks in this * mustn't have another predecessor and all structured blocks in this
* flow block must be simple instruction blocks. * flow block must be simple instruction blocks.
* @param succ The successing structured block that should be merged.
* @param length the length of the structured block.
*/ */
public void doSequentialT1(StructuredBlock succ, int length) { public void doSequentialT1(StructuredBlock succ, int length) {
if (Decompiler.isFlowDebugging) {
Decompiler.err.println("merging sequentialBlock: "+this);
Decompiler.err.println("and: "+succ);
}
VariableSet succIn = new VariableSet(); VariableSet succIn = new VariableSet();
succ.fillInGenSet(succIn, this.gen); succ.fillInGenSet(succIn, this.gen);
@ -663,10 +776,8 @@ public class FlowBlock {
/* This will also set last modified to the new correct value. */ /* This will also set last modified to the new correct value. */
doTransformations(); doTransformations();
/* Set addr+length to correct value. */ /* Set addr and length to correct value and update nextByAddr */
if (succ.addr < addr) mergeAddr(succ);
addr = succ.addr;
length += succ.length;
/* T1 transformation succeeded */ /* T1 transformation succeeded */
checkConsistent(); checkConsistent();
@ -703,7 +814,7 @@ public class FlowBlock {
// } // }
// if (cb != null // if (cb != null
// && cb.trueBlock.jump.destination.addr == addr + length) { // && cb.trueBlock.jump.destination.addr == getNextAddr()) {
// loopBlock.moveJump(cb.trueBlock.jump); // loopBlock.moveJump(cb.trueBlock.jump);
// loopBlock.setCondition(cb.getInstruction().negate()); // loopBlock.setCondition(cb.getInstruction().negate());
// loopBlock.setType(loopType); // loopBlock.setType(loopType);
@ -1028,8 +1139,8 @@ public class FlowBlock {
Decompiler.err.println("after T2: "+this); Decompiler.err.println("after T2: "+this);
if (Decompiler.debugAnalyze) if (Decompiler.debugAnalyze)
Decompiler.err.println("T2("+addr+","+(addr+length) Decompiler.err.println("T2("+addr+","+getNextAddr()
+") succeeded"); +") succeeded");
/* T2 transformation succeeded. This may /* T2 transformation succeeded. This may
* make another T1 analysis in the previous * make another T1 analysis in the previous
* block possible. * block possible.
@ -1048,11 +1159,10 @@ public class FlowBlock {
Decompiler.err.println Decompiler.err.println
("No more successors applicable: " ("No more successors applicable: "
+ start + " - " + end + "; " + start + " - " + end + "; "
+ addr + " - " + (addr+length)); + addr + " - " + getNextAddr());
return changed; return changed;
} else { } else {
if ((succ.addr == addr+length if ((nextByAddr == succ || succ.nextByAddr == this)
|| succ.addr+succ.length == addr)
/* Only do T1 transformation if the blocks are /* Only do T1 transformation if the blocks are
* adjacent. */ * adjacent. */
&& doT1(succ)) { && doT1(succ)) {
@ -1077,17 +1187,17 @@ public class FlowBlock {
Decompiler.err.println Decompiler.err.println
("breaking analyze(" ("breaking analyze("
+ start + ", " + end + "); " + start + ", " + end + "); "
+ addr + " - " + (addr+length)); + addr + " - " + getNextAddr());
return changed; return changed;
} }
} }
/* analyze succ, the new region is the /* analyze succ, the new region is the
* continuous region of * continuous region of
* [start,end) \cap \compl [addr, addr+length) * [start,end) \cap \compl [addr, getNextAddr())
* where succ.addr lies in. * where succ.addr lies in.
*/ */
int newStart = (succ.addr > addr) int newStart = (succ.addr > addr)
? addr+length : start; ? getNextAddr() : start;
int newEnd = (succ.addr > addr) int newEnd = (succ.addr > addr)
? end : addr; ? end : addr;
if (succ.analyze(newStart, newEnd)) if (succ.analyze(newStart, newEnd))
@ -1129,10 +1239,10 @@ public class FlowBlock {
* return early after a T2 trafo so call it * return early after a T2 trafo so call it
* until nothing more is possible. * until nothing more is possible.
*/ */
while (nextFlow.analyze(addr + length, end)) while (nextFlow.analyze(getNextAddr(), end))
changed = changed || true; changed = changed || true;
if (nextFlow.addr != addr + length) if (nextFlow.addr != getNextAddr())
break; break;
/* Check if nextFlow has only the previous case /* Check if nextFlow has only the previous case
@ -1179,7 +1289,7 @@ public class FlowBlock {
*/ */
switchBlock.caseBlocks[i].subBlock.removeJump(); switchBlock.caseBlocks[i].subBlock.removeJump();
length += nextFlow.length; mergeAddr(nextFlow);
lastFlow = nextFlow; lastFlow = nextFlow;
last = i; last = i;
@ -1211,13 +1321,22 @@ public class FlowBlock {
if (jump != null && jump.destination == null) { if (jump != null && jump.destination == null) {
if (jump.destAddr == -1) if (jump.destAddr == -1)
jump.destination = END_OF_METHOD; jump.destination = END_OF_METHOD;
else else if (jump.destAddr == instr.length)
// In this case, the jump must belong to dead code.
jump.destination = ILLEGAL;
else {
jump.destination = instr[jump.destAddr]; jump.destination = instr[jump.destAddr];
if (jump.destination == null) if (jump.destination == null)
throw new AssertError("Missing dest: "+jump.destAddr); throw new AssertError("Missing dest: "+jump.destAddr);
}
addSuccessor(jump); addSuccessor(jump);
} }
} }
if (getNextAddr() < instr.length) {
nextByAddr = instr[getNextAddr()];
nextByAddr.prevByAddr = this;
}
} }
/** /**
@ -1261,6 +1380,45 @@ public class FlowBlock {
block.makeDeclaration(param); block.makeDeclaration(param);
} }
/**
* Mark this block and all successing blocks as reachable.
*/
public void markReachable() {
if (reachable) {
// This block was already checked. This prevents infinite
// recursion.
return;
}
reachable = true;
Enumeration succs = successors.keys();
while (succs.hasMoreElements())
((FlowBlock) succs.nextElement()).markReachable();
}
/**
* Removes dead code, i.e. merges the dead flow block with there
* prevByAddr and removing their code completely. <br>
*
* Why is it necessary? Because jikes actually generates a lot
* of dead code in try, catch and finally blocks. This will break
* a lot of other code, e.g. checking that a catch handler has no
* entries or merging only adjacent blocks.
*
* @param flow The first flow block in this method.
*/
public static void removeDeadCode(FlowBlock flow) {
while (flow.nextByAddr != null) {
if (!flow.nextByAddr.reachable) {
Enumeration succs = flow.nextByAddr.successors.keys();
while (succs.hasMoreElements())
((FlowBlock) succs.nextElement()).predecessors
.removeElement(flow.nextByAddr);
flow.mergeAddr(flow.nextByAddr);
} else
flow = flow.nextByAddr;
}
}
/** /**
* Print the source code for this structured block. This handles * Print the source code for this structured block. This handles
* everything that is unique for all structured blocks and calls * everything that is unique for all structured blocks and calls
@ -1272,7 +1430,7 @@ public class FlowBlock {
{ {
if (predecessors.size() != 0) { if (predecessors.size() != 0) {
writer.untab(); writer.untab();
writer.println(label+":"); writer.println(getLabel()+":");
writer.tab(); writer.tab();
} }
@ -1281,6 +1439,9 @@ public class FlowBlock {
} }
block.dumpSource(writer); block.dumpSource(writer);
if (nextByAddr != null)
nextByAddr.dumpSource(writer);
} }
/** /**
@ -1313,10 +1474,10 @@ public class FlowBlock {
public String toString() { public String toString() {
try { try {
java.io.StringWriter strw = new java.io.StringWriter(); java.io.StringWriter strw = new java.io.StringWriter();
TabbedPrintWriter writer = new TabbedPrintWriter(strw, " "); TabbedPrintWriter writer = new TabbedPrintWriter(strw);
writer.println(super.toString()); writer.println(super.toString());
writer.tab(); writer.tab();
dumpSource(writer); block.dumpSource(writer);
return strw.toString(); return strw.toString();
} catch (java.io.IOException ex) { } catch (java.io.IOException ex) {
return super.toString(); return super.toString();

Loading…
Cancel
Save