finally blocks reworked.

allow jsr to occur outside of try block.
handle finally blocks, whose subroutine can't be merged


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1101 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 26 years ago
parent 7c1859a4df
commit 67e5bf4656
  1. 270
      jode/jode/flow/TransformExceptionHandlers.java.in

@ -26,6 +26,7 @@ import jode.expr.*;
import @COLLECTIONS@.TreeSet; import @COLLECTIONS@.TreeSet;
import @COLLECTIONS@.SortedSet; import @COLLECTIONS@.SortedSet;
import @COLLECTIONS@.Set;
import @COLLECTIONS@.Map; import @COLLECTIONS@.Map;
import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Iterator;
import @COLLECTIONEXTRA@.Comparable; import @COLLECTIONEXTRA@.Comparable;
@ -233,23 +234,31 @@ public class TransformExceptionHandlers {
} }
} }
} }
/* Now we have a dangling JSR at the wrong place. /* Now we have a jump to the subroutine, that is wrong.
* We don't do anything, so that JSR will show up in * We complain here.
* the output.
*/ */
DescriptionBlock msg
= new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!");
prev.appendBlock(msg);
} }
} }
public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine) { public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine,
int startOutExit, int endOutExit) {
boolean foundSub = false;
FlowBlock exitBlock = null;
Iterator iter = tryFlow.getSuccessors().iterator(); Iterator iter = tryFlow.getSuccessors().iterator();
dest_loop:
while (iter.hasNext()) { while (iter.hasNext()) {
FlowBlock dest = (FlowBlock) iter.next(); FlowBlock dest = (FlowBlock) iter.next();
if (dest == subRoutine) if (dest == subRoutine) {
continue; foundSub = true;
continue dest_loop;
Jump jumps = tryFlow.getJumps(dest); }
for ( ; jumps != null; jumps = jumps.next) { boolean isFirstJump = true;
for (Jump jumps = tryFlow.getJumps(dest);
jumps != null; jumps = jumps.next, isFirstJump = false) {
StructuredBlock prev = jumps.prev; StructuredBlock prev = jumps.prev;
if (prev instanceof ThrowBlock) { if (prev instanceof ThrowBlock) {
@ -290,6 +299,45 @@ public class TransformExceptionHandlers {
continue; continue;
} }
} }
if (isFirstJump) {
/* Now we have a jump that is not preceded by the
* jsr. There's a last chance: the jump jumps
* directly to a correct jsr instruction, which
* lies outside the try/catch block.
*/
System.err.println("tick0"
+exitBlock
+" ["+startOutExit+","+endOutExit
+"]->"+subRoutine.getAddr()
+" dest "+jumps.destination
+" dest preds "+jumps.destination.predecessors);
if (exitBlock == null
&& jumps.destination.predecessors.size() == 1
&& jumps.destination.getAddr() >= startOutExit
&& jumps.destination.getNextAddr() <= endOutExit) {
System.err.println("tick1");
jumps.destination.analyze(startOutExit, endOutExit);
StructuredBlock sb = jumps.destination.block;
if (sb instanceof SequentialBlock)
sb = sb.getSubBlocks()[0];
System.err.println("tick2");
if (sb instanceof JsrBlock
&& sb.getSubBlocks()[0] instanceof EmptyBlock
&& (sb.getSubBlocks()[0].jump.destination
== subRoutine)) {
System.err.println("tick3");
StructuredBlock jsrInner = sb.getSubBlocks()[0];
exitBlock = jumps.destination;
jumps.destination.removeSuccessor(jsrInner.jump);
jsrInner.removeJump();
sb.removeBlock();
continue dest_loop;
}
}
}
/* Now we have a jump with a wrong destination. /* Now we have a jump with a wrong destination.
* Complain! * Complain!
*/ */
@ -299,7 +347,8 @@ public class TransformExceptionHandlers {
msg.moveJump(jumps); msg.moveJump(jumps);
} }
} }
removeJSR(tryFlow, subRoutine); if (foundSub)
removeJSR(tryFlow, subRoutine);
} }
static boolean isMonitorExit(Expression instr, LocalInfo local) { static boolean isMonitorExit(Expression instr, LocalInfo local) {
@ -419,6 +468,7 @@ public class TransformExceptionHandlers {
* block. * block.
*/ */
if (exitBlock == null if (exitBlock == null
&& jumps.destination.predecessors.size() != 1
&& jumps.destination.getAddr() >= startOutExit && jumps.destination.getAddr() >= startOutExit
&& jumps.destination.getNextAddr() <= endOutExit) { && jumps.destination.getNextAddr() <= endOutExit) {
jumps.destination.analyze(startOutExit, endOutExit); jumps.destination.analyze(startOutExit, endOutExit);
@ -579,106 +629,125 @@ public class TransformExceptionHandlers {
} }
} }
if (catchBlock instanceof SequentialBlock if (!(catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0] instanceof JsrBlock && catchBlock.getSubBlocks()[0] instanceof JsrBlock
&& instr instanceof StoreInstruction && instr instanceof StoreInstruction
&& catchBlock.getSubBlocks()[1] instanceof ThrowBlock && catchBlock.getSubBlocks()[1] instanceof ThrowBlock))
&& (((ThrowBlock)catchBlock.getSubBlocks()[1]).instr
instanceof LocalLoadOperator)
&& (((StoreInstruction) instr).lvalueMatches
((LocalLoadOperator)
((ThrowBlock)catchBlock.getSubBlocks()[1]).instr))) {
/* Wow that was complicated :-)
* But now we know that the catch block looks
* exactly like it should:
*
* catchBlock:
* JSR
* finally
* throw local_n <- matches the local in instr.
*/
if (finallyBlock != null) { return false;
/* Check if the jsr breaks (see two comments above). We don't
* need to check if it breaks to the right block, because
* we know that there is only one Block around the jsr.
*/
if (!(((JsrBlock)catchBlock.getSubBlocks()[0]).innerBlock
instanceof BreakBlock))
return false;
/* Check if the try block has no exit (except throws) JsrBlock jsrBlock = (JsrBlock)catchBlock.getSubBlocks()[0];
*/ ThrowBlock throwBlock = (ThrowBlock) catchBlock.getSubBlocks()[1];
Jump throwJumps = tryFlow.getJumps(FlowBlock.END_OF_METHOD);
if (tryFlow.getSuccessors().size() > 1
|| (tryFlow.getSuccessors().size() > 0
&& throwJumps == null))
return false;
for (/**/; throwJumps != null; throwJumps = throwJumps.next) {
if (!(throwJumps.prev instanceof ThrowBlock))
/* There is a return exit in the try block */
return false;
}
/* Remove the jump of the throw instruction.
*/
catchFlow.removeSuccessor(catchBlock.getSubBlocks()[1].jump);
catchBlock.getSubBlocks()[1].removeJump();
/* Replace the catchBlock with the finallyBlock. if (!(throwBlock.instr instanceof LocalLoadOperator)
*/ || !(((StoreInstruction) instr).lvalueMatches
finallyBlock.replace(catchFlow.block); ((LocalLoadOperator) throwBlock.instr)))
transformSubRoutine(finallyBlock); return false;
tryFlow.updateInOutCatch(catchFlow); /* Wow that was complicated :-)
tryFlow.mergeAddr(catchFlow); * But now we know that the catch block looks
finallyBlock = catchFlow.block; * exactly like it should:
tryFlow.mergeSuccessors(catchFlow); *
* catchBlock:
* JSR
* finally
* throw local_n <- matches the local in instr.
*/
} else { if (finallyBlock != null) {
FlowBlock subRoutine = /* Check if the jsr breaks (see two comments above). We don't
((JsrBlock)catchBlock.getSubBlocks()[0]) * need to check if it breaks to the right block, because
.innerBlock.jump.destination; * we know that there is only one Block around the jsr.
*/
if (!(jsrBlock.innerBlock instanceof BreakBlock))
return false;
subRoutine.analyze(catchFlow.getNextAddr(), end); /* Check if the try block has no exit (except throws)
if (!transformSubRoutine(subRoutine.block)) */
return false; Set succs = tryFlow.getSuccessors();
if (succs.size() > 0) {
if (!succs.contains(FlowBlock.END_OF_METHOD))
return false;
Jump throwJumps
= tryFlow.getJumps(FlowBlock.END_OF_METHOD);
for (/**/; throwJumps != null;
throwJumps = throwJumps.next) {
if (!(throwJumps.prev instanceof ThrowBlock))
/* There is a return exit in the try block */
return false;
}
}
/* Remove the jump of the throw instruction.
*/
catchFlow.removeSuccessor(throwBlock.jump);
throwBlock.removeJump();
tryFlow.mergeAddr(catchFlow); /* Replace the catchBlock with the finallyBlock.
*/
finallyBlock.replace(catchFlow.block);
transformSubRoutine(finallyBlock);
checkAndRemoveJSR(tryFlow, subRoutine); tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeAddr(catchFlow);
finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow);
tryFlow.updateInOutCatch(subRoutine); } else {
tryFlow.mergeAddr(subRoutine); FlowBlock subRoutine = jsrBlock.innerBlock.jump.destination;
tryFlow.mergeSuccessors(subRoutine); checkAndRemoveJSR(tryFlow, subRoutine,
finallyBlock = subRoutine.block; tryFlow.getNextAddr(), catchFlow.getAddr());
/* Now remove the jump to the JSR from the catch block while (subRoutine.analyze(catchFlow.getNextAddr(), end));
* and the jump of the throw instruction.
*/
catchBlock.getSubBlocks()[0].getSubBlocks()[0]
.jump.destination.predecessors.remove(catchFlow);
catchBlock.getSubBlocks()[1]
.jump.destination.predecessors.remove(catchFlow);
}
TryBlock tryBlock = (TryBlock)tryFlow.block; /* Now check if the subroutine is correct and has only the
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { * catchFlow as predecessor.
/* remove the surrounding tryBlock */ */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; if (subRoutine.predecessors.size() == 1
innerTry.gen = tryBlock.gen; && transformSubRoutine(subRoutine.block)) {
innerTry.replace(tryBlock); subRoutine.mergeAddr(catchFlow);
tryBlock = innerTry;
tryFlow.lastModified = tryBlock; /* Now remove the jump to the JSR from the catch block
tryFlow.block = tryBlock; * and the jump of the throw instruction.
} */
FinallyBlock newBlock = new FinallyBlock(); catchFlow.removeSuccessor(jsrBlock.innerBlock.jump);
newBlock.setCatchBlock(finallyBlock); jsrBlock.innerBlock.removeJump();
tryBlock.addCatchBlock(newBlock); catchFlow.removeSuccessor(throwBlock.jump);
return true; throwBlock.removeJump();
}
return false; tryFlow.updateInOutCatch(subRoutine);
tryFlow.mergeAddr(subRoutine);
tryFlow.mergeSuccessors(subRoutine);
finallyBlock = subRoutine.block;
} else {
catchFlow.removeSuccessor(throwBlock.jump);
throwBlock.removeJump();
finallyBlock = jsrBlock;
finallyBlock.replace(catchFlow.block);
transformSubRoutine(finallyBlock);
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeAddr(catchFlow);
finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow);
}
}
TryBlock tryBlock = (TryBlock)tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* remove the surrounding tryBlock */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = tryBlock;
tryFlow.block = tryBlock;
}
FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(finallyBlock);
tryBlock.addCatchBlock(newBlock);
return true;
} }
private boolean analyzeSpecialFinally(FlowBlock tryFlow, private boolean analyzeSpecialFinally(FlowBlock tryFlow,
@ -724,7 +793,6 @@ public class TransformExceptionHandlers {
if (succ != null) { if (succ != null) {
Jump jumps = tryFlow.removeJumps(succ); Jump jumps = tryFlow.removeJumps(succ);
succ.predecessors.remove(tryFlow);
/* Handle the jumps in the tryFlow. /* Handle the jumps in the tryFlow.
*/ */
jumps = tryFlow.resolveSomeJumps(jumps, succ); jumps = tryFlow.resolveSomeJumps(jumps, succ);
@ -751,7 +819,7 @@ public class TransformExceptionHandlers {
newBlock.setCatchBlock(succ.block); newBlock.setCatchBlock(succ.block);
tryFlow.mergeSuccessors(succ); tryFlow.mergeSuccessors(succ);
} else { } else {
/* Put the catchBlock in instaed. /* Put the catchBlock in instead.
*/ */
newBlock.setCatchBlock(catchFlow.block); newBlock.setCatchBlock(catchFlow.block);
tryFlow.mergeSuccessors(catchFlow); tryFlow.mergeSuccessors(catchFlow);
@ -855,7 +923,9 @@ public class TransformExceptionHandlers {
catchFlow.getAddr()); catchFlow.getAddr());
newFlow.appendBlock(jump, 0); newFlow.appendBlock(jump, 0);
catchFlow.prevByAddr.nextByAddr = newFlow; catchFlow.prevByAddr.nextByAddr = newFlow;
newFlow.prevByAddr = catchFlow.prevByAddr;
newFlow.nextByAddr = catchFlow; newFlow.nextByAddr = catchFlow;
catchFlow.prevByAddr = newFlow;
catchFlow = newFlow; catchFlow = newFlow;
} else { } else {
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags

Loading…
Cancel
Save