add new sanity check to ReturnBlock.

TransformExceptionHandlers rewritten AGAIN!  Lots of changes, still not
perfect.  Nested synchronized in javac are still not supported.


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1274 379699f6-c40d-0410-875b-85095c16579e
master
hoenicke 24 years ago
parent 712f5d03dd
commit 8f00154e64
  1. 8
      jode/jode/flow/ReturnBlock.java
  2. 618
      jode/jode/flow/TransformExceptionHandlers.java

@ -42,6 +42,12 @@ public class ReturnBlock extends InstructionContainer {
return true;
}
public void checkConsistent() {
super.checkConsistent();
if (jump != null && jump.destination != FlowBlock.END_OF_METHOD)
throw new InternalError("Inconsistency");
}
/**
* This does take the instr into account and modifies stack
* accordingly. It then calls super.mapStackToLocal.
@ -57,8 +63,6 @@ public class ReturnBlock extends InstructionContainer {
newStack = stack.pop(params);
}
}
if (jump != null)
jump.stackMap = newStack;
return null;
}

@ -115,16 +115,11 @@ public class TransformExceptionHandlers {
* | ...
* `- catch block
*/
static void analyzeCatchBlock(Type type,
FlowBlock tryFlow, FlowBlock catchFlow) {
StructuredBlock catchBlock = catchFlow.block;
static void analyzeCatchBlock(Type type, FlowBlock tryFlow,
StructuredBlock catchBlock) {
CatchBlock newBlock = new CatchBlock(type);
((TryBlock)tryFlow.block).addCatchBlock(newBlock);
newBlock.setCatchBlock(catchFlow.block);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeBlockNr(catchFlow);
newBlock.setCatchBlock(catchBlock);
}
/* And now the complicated parts. */
@ -134,44 +129,84 @@ public class TransformExceptionHandlers {
* local assignment matches the final ret and then returns.
*/
boolean transformSubRoutine(StructuredBlock subRoutine) {
if (!(subRoutine instanceof SequentialBlock)
|| !(subRoutine.getSubBlocks()[0] instanceof InstructionBlock))
return false;
SequentialBlock sequBlock = (SequentialBlock) subRoutine;
InstructionBlock instr = (InstructionBlock)sequBlock.subBlocks[0];
if (!(subRoutine instanceof SequentialBlock))
return false;
SequentialBlock sequBlock = (SequentialBlock) subRoutine;
StructuredBlock firstBlock = sequBlock.getSubBlocks()[0];
LocalInfo local = null;
if (firstBlock instanceof SpecialBlock) {
SpecialBlock popBlock
= (SpecialBlock) firstBlock;
if (popBlock.type != SpecialBlock.POP
|| popBlock.count != 1)
return false;
} else if (firstBlock instanceof InstructionBlock) {
Expression expr
= ((InstructionBlock) firstBlock).getInstruction();
if (expr instanceof StoreInstruction
&& ((StoreInstruction)
expr).getLValue() instanceof LocalStoreOperator) {
LocalStoreOperator store = (LocalStoreOperator)
((StoreInstruction)expr).getLValue();
local = store.getLocalInfo();
expr = ((StoreInstruction) expr).getSubExpressions()[1];
}
if (!(expr instanceof NopOperator))
return false;
} else
return false;
if (!(instr.getInstruction() instanceof StoreInstruction)
|| !(((StoreInstruction) instr.getInstruction()).getLValue()
instanceof LocalStoreOperator))
return false;
LocalStoreOperator store = (LocalStoreOperator)
((StoreInstruction)instr.getInstruction()).getLValue();
/* We are now committed. Remove the first Statement which
* stores/removes the return address.
*/
firstBlock.removeBlock();
/* XXX - Replace any RET with a jump to end of this flow block.
*
* This is a complicated task which isn't needed for javac nor
* jikes. We just check if the last instruction is a ret and
* replace this. This will never produce code with wrong semantic,
* as long as the bytecode was verified correctly.
*/
while (sequBlock.subBlocks[1] instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.subBlocks[1];
/* XXX - Check that the local isn't used for any other purposes
* than RET and replace any RET with a flow control to end of
* flow block.
*
* This is a complicated task which isn't needed for javac nor jikes.
*/
if (sequBlock.subBlocks[1].jump != null
&& sequBlock.subBlocks[1].jump.destination
== FlowBlock.END_OF_METHOD) {
instr.removeBlock();
return true;
if (sequBlock.subBlocks[1] instanceof RetBlock
&& (((RetBlock) sequBlock.subBlocks[1]).local.equals(local))) {
sequBlock.subBlocks[1].removeBlock();
}
if (! (sequBlock.subBlocks[1] instanceof RetBlock)
|| !(((RetBlock)sequBlock.subBlocks[1])
.local.equals(store.getLocalInfo())))
return false;
instr.removeBlock();
sequBlock.subBlocks[1].removeBlock();
return true;
}
/**
* Remove the locale that javac introduces to temporary store the return
* value, when it executes a finally block resp. monitorexit
* @param ret the ReturnBlock.
*/
private void removeReturnLocal(ReturnBlock ret) {
if (ret.outer == null
|| !(ret.outer instanceof SequentialBlock))
return;
StructuredBlock pred = ret.outer.getSubBlocks()[0];
if (!(pred instanceof InstructionBlock))
return;
Expression instr = ((InstructionBlock) pred).getInstruction();
if (!(instr instanceof StoreInstruction))
return;
Expression retInstr = ret.getInstruction();
if (!(retInstr instanceof LocalLoadOperator
&& ((StoreInstruction) instr).lvalueMatches
((LocalLoadOperator) retInstr)))
return;
Expression rvalue = ((StoreInstruction) instr).getSubExpressions()[1];
ret.setInstruction(rvalue);
ret.replace(ret.outer);
}
/**
* Remove the JSR's jumping to the specified subRoutine. It
* is checked if the next block is a leaving instruction, and
@ -181,16 +216,24 @@ public class TransformExceptionHandlers {
* @param tryFlow the FlowBLock of the try block.
* @param subRoutine the FlowBlock of the sub routine.
*/
private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) {
for (Jump jumps = tryFlow.removeJumps(subRoutine);
jumps != null; jumps = jumps.next) {
private void removeJSR(FlowBlock tryFlow, StructuredBlock catchBlock,
FlowBlock subRoutine) {
Jump nextJump;
for (Jump jumps = tryFlow.getJumps(subRoutine);
jumps != null; jumps = nextJump) {
StructuredBlock prev = jumps.prev;
prev.removeJump();
nextJump = jumps.next;
if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) {
if (prev.outer == catchBlock) {
/* This is the mandatory jsr in the catch block */
continue;
}
if (prev.outer.getNextFlowBlock() != null) {
/* The jsr is directly before a jump, okay. */
tryFlow.removeSuccessor(jumps);
prev.removeJump();
prev.outer.removeBlock();
continue;
}
@ -202,6 +245,8 @@ public class TransformExceptionHandlers {
&& seq.subBlocks[1].getSubBlocks()[0]
instanceof JsrBlock)) {
/* The jsr is followed by a jsr, okay. */
tryFlow.removeSuccessor(jumps);
prev.removeJump();
prev.outer.removeBlock();
continue;
}
@ -209,33 +254,12 @@ public class TransformExceptionHandlers {
&& !(seq.subBlocks[1] instanceof ThrowBlock)) {
/* The jsr is followed by a return, okay. */
tryFlow.removeSuccessor(jumps);
prev.removeJump();
ReturnBlock ret = (ReturnBlock) seq.subBlocks[1];
prev.outer.removeBlock();
if (ret.outer != null
&& ret.outer instanceof SequentialBlock) {
/* Try to eliminate the local that javac uses
* in this case.
*/
try {
StoreInstruction store = (StoreInstruction)
((InstructionBlock)
ret.outer.getSubBlocks()[0]).instr;
LocalInfo local =
((LocalStoreOperator) store.getLValue())
.getLocalInfo();
if (store.lvalueMatches
((LocalLoadOperator)
ret.getInstruction())) {
Expression expr =
store.getSubExpressions()[1];
ret.setInstruction(expr);
ret.replace(ret.outer);
}
} catch(ClassCastException ex) {
/* didn't succeed */
}
}
removeReturnLocal(ret);
continue;
}
}
@ -245,11 +269,15 @@ public class TransformExceptionHandlers {
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!");
tryFlow.removeSuccessor(jumps);
prev.removeJump();
prev.appendBlock(msg);
}
}
public void checkAndRemoveJSR(FlowBlock tryFlow, FlowBlock subRoutine,
public void checkAndRemoveJSR(FlowBlock tryFlow,
StructuredBlock catchBlock,
FlowBlock subRoutine,
int startOutExit, int endOutExit) {
boolean foundSub = false;
Iterator iter = tryFlow.getSuccessors().iterator();
@ -336,7 +364,7 @@ public class TransformExceptionHandlers {
}
}
if (foundSub)
removeJSR(tryFlow, subRoutine);
removeJSR(tryFlow, catchBlock, subRoutine);
}
static boolean isMonitorExit(Expression instr, LocalInfo local) {
@ -366,9 +394,10 @@ public class TransformExceptionHandlers {
return false;
}
public void checkAndRemoveMonitorExit(FlowBlock tryFlow, LocalInfo local,
int startOutExit, int endOutExit,
int startMonExit, int endMonExit) {
public void checkAndRemoveMonitorExit(FlowBlock tryFlow,
StructuredBlock catchBlock,
LocalInfo local,
int start, int end) {
FlowBlock subRoutine = null;
Iterator succs = tryFlow.getSuccessors().iterator();
dest_loop:
@ -415,8 +444,12 @@ public class TransformExceptionHandlers {
if (pred instanceof InstructionBlock) {
Expression instr =
((InstructionBlock)pred).getInstruction();
if (isMonitorExit(instr, local))
continue;
if (isMonitorExit(instr, local)) {
pred.removeBlock();
if (prev instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) prev);
continue;
}
}
}
}
@ -442,9 +475,9 @@ public class TransformExceptionHandlers {
*/
if (prev instanceof JsrBlock) {
if (subRoutine == null
&& successor.getBlockNr() >= startMonExit
&& successor.getNextBlockNr() <= endMonExit) {
successor.analyze(startMonExit, endMonExit);
&& successor.getBlockNr() >= start
&& successor.getNextBlockNr() <= end) {
successor.analyze(start, end);
if (isMonitorExitSubRoutine(successor, local))
subRoutine = successor;
@ -461,9 +494,9 @@ public class TransformExceptionHandlers {
* block.
*/
if (successor.predecessors.size() == 1
&& successor.getBlockNr() >= startOutExit
&& successor.getNextBlockNr() <= endOutExit) {
successor.analyze(startOutExit, endOutExit);
&& successor.getBlockNr() >= start
&& successor.getNextBlockNr() <= end) {
successor.analyze(start, end);
StructuredBlock sb = successor.block;
if (sb instanceof SequentialBlock)
@ -473,9 +506,9 @@ public class TransformExceptionHandlers {
StructuredBlock jsrInner = sb.getSubBlocks()[0];
FlowBlock dest = jsrInner.jump.destination;
if (subRoutine == null
&& dest.getBlockNr() >= startMonExit
&& dest.getNextBlockNr() <= endMonExit) {
dest.analyze(startMonExit, endMonExit);
&& dest.getBlockNr() >= start
&& dest.getNextBlockNr() <= end) {
dest.analyze(start, end);
if (isMonitorExitSubRoutine(dest, local))
subRoutine = dest;
}
@ -506,86 +539,115 @@ public class TransformExceptionHandlers {
}
if (subRoutine != null) {
removeJSR(tryFlow, subRoutine);
removeJSR(tryFlow, catchBlock, subRoutine);
tryFlow.mergeBlockNr(subRoutine);
}
}
private StoreInstruction getExceptionStore(StructuredBlock catchBlock) {
if (!(catchBlock instanceof SequentialBlock)
|| !(catchBlock.getSubBlocks()[0] instanceof InstructionBlock))
return null;
Expression instr =
((InstructionBlock)catchBlock.getSubBlocks()[0]).getInstruction();
if (!(instr instanceof StoreInstruction))
return null;
StoreInstruction store = (StoreInstruction) instr;
if (!(store.getLValue() instanceof LocalStoreOperator
&& store.getSubExpressions()[1] instanceof NopOperator))
return null;
return store;
}
private boolean analyzeSynchronized(FlowBlock tryFlow,
FlowBlock catchFlow,
StructuredBlock catchBlock,
int endHandler) {
if (!(catchFlow.block instanceof SequentialBlock
&& catchFlow.block.getSubBlocks()[0]
StoreInstruction excStore = getExceptionStore(catchBlock);
if (excStore != null)
catchBlock = catchBlock.getSubBlocks()[1];
if (!(catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0]
instanceof InstructionBlock))
return false;
SequentialBlock catchBlock = (SequentialBlock) catchFlow.block;
Expression instr =
((InstructionBlock)catchBlock.subBlocks[0]).getInstruction();
((InstructionBlock)catchBlock.getSubBlocks()[0]).getInstruction();
if (instr instanceof MonitorExitOperator
&& instr.getFreeOperandCount() == 0
&& (((MonitorExitOperator)instr).getSubExpressions()[0]
instanceof LocalLoadOperator)
&& catchBlock.subBlocks[1] instanceof ThrowBlock
&& (((ThrowBlock)catchBlock.subBlocks[1]).instr
instanceof NopOperator)) {
if (!(instr instanceof MonitorExitOperator
&& instr.getFreeOperandCount() == 0
&& (((MonitorExitOperator)instr).getSubExpressions()[0]
instanceof LocalLoadOperator)
&& catchBlock.getSubBlocks()[1] instanceof ThrowBlock))
return false;
/* This is a synchronized block:
*
* local_x = monitor object; // later
* monitorenter local_x // later
* tryFlow:
* |- synchronized block
* | ...
* | every jump to outside is preceded by jsr subroutine-,
* | ... |
* |- monitorexit local_x |
* ` jump after this block (without jsr monexit) |
* |
* catchFlow: |
* local_n = stack |
* monitorexit local_x |
* throw local_n |
* optional subroutine: <-----------------------------------'
* astore_n
* monitorexit local_x
* return_n
*/
Expression throwInstr =
((ThrowBlock)catchBlock.getSubBlocks()[1]).getInstruction();
MonitorExitOperator monexit = (MonitorExitOperator)
((InstructionBlock) catchBlock.subBlocks[0]).instr;
LocalInfo local =
((LocalLoadOperator)monexit.getSubExpressions()[0])
.getLocalInfo();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeSynchronized(" + tryFlow.getBlockNr()
+ "," + tryFlow.getNextBlockNr() + "," + catchFlow.getBlockNr()
+ "," + catchFlow.getNextBlockNr() + "," + endHandler + ")");
checkAndRemoveMonitorExit
(tryFlow, local,
tryFlow.getNextBlockNr(), catchFlow.getBlockNr(),
catchFlow.getNextBlockNr(), endHandler);
tryFlow.mergeBlockNr(catchFlow);
SynchronizedBlock syncBlock = new SynchronizedBlock(local);
TryBlock tryBlock = (TryBlock) tryFlow.block;
syncBlock.replace(tryBlock);
syncBlock.moveJump(tryBlock.jump);
syncBlock.setBodyBlock(tryBlock.subBlocks.length == 1
? tryBlock.subBlocks[0] : tryBlock);
tryFlow.lastModified = syncBlock;
return true;
}
return false;
if (excStore != null) {
if (!(throwInstr instanceof Operator
&& excStore.lvalueMatches((Operator)throwInstr)))
return false;
} else {
if (!(throwInstr instanceof NopOperator))
return false;
}
/* This is a synchronized block:
*
* local_x = monitor object; // later
* monitorenter local_x // later
* tryFlow:
* |- synchronized block
* | ...
* | every jump to outside is preceded by jsr subroutine-,
* | ... |
* |- monitorexit local_x |
* ` jump after this block (without jsr monexit) |
* |
* catchBlock: |
* local_n = stack |
* monitorexit local_x |
* throw local_n |
* [OR ALTERNATIVELY:] |
* monitorexit local_x |
* throw stack |
* optional subroutine: <-----------------------------------'
* astore_n
* monitorexit local_x
* return_n
*/
MonitorExitOperator monexit = (MonitorExitOperator)
((InstructionBlock) catchBlock.getSubBlocks()[0]).instr;
LocalInfo local =
((LocalLoadOperator)monexit.getSubExpressions()[0])
.getLocalInfo();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeSynchronized(" + tryFlow.getBlockNr()
+ "," + tryFlow.getNextBlockNr() + "," + endHandler + ")");
checkAndRemoveMonitorExit
(tryFlow, catchBlock, local, tryFlow.getNextBlockNr(), endHandler);
SynchronizedBlock syncBlock = new SynchronizedBlock(local);
TryBlock tryBlock = (TryBlock) tryFlow.block;
syncBlock.replace(tryBlock);
syncBlock.moveJump(tryBlock.jump);
syncBlock.setBodyBlock(tryBlock.subBlocks.length == 1
? tryBlock.subBlocks[0] : tryBlock);
tryFlow.lastModified = syncBlock;
return true;
}
private boolean analyzeFinally(FlowBlock tryFlow, FlowBlock catchFlow,
int end) {
private boolean analyzeFinally(FlowBlock tryFlow,
StructuredBlock catchBlock, int end) {
/* Layout of a try-finally block:
*
@ -597,7 +659,7 @@ public class TransformExceptionHandlers {
* | jsr finally -----------------,
* `- jump after finally |
* |
* catchFlow: (already checked) |
* catchBlock: |
* local_n = stack v
* jsr finally ---------------->|
* throw local_n; |
@ -607,20 +669,17 @@ public class TransformExceptionHandlers {
* return_n
*/
if (!(catchFlow.block instanceof SequentialBlock)
|| !(catchFlow.block.getSubBlocks()[0]
instanceof InstructionBlock)
|| !(catchFlow.block.getSubBlocks()[1]
instanceof SequentialBlock))
StoreInstruction excStore = getExceptionStore(catchBlock);
if (excStore == null)
return false;
catchBlock = catchBlock.getSubBlocks()[1];
if (!(catchBlock instanceof SequentialBlock))
return false;
StructuredBlock finallyBlock = null;
SequentialBlock catchBlock = (SequentialBlock) catchFlow.block;
Expression instr =
((InstructionBlock)catchBlock.subBlocks[0]).getInstruction();
catchBlock = (SequentialBlock)catchBlock.subBlocks[1];
if (catchBlock.subBlocks[0] instanceof LoopBlock) {
if (catchBlock.getSubBlocks()[0] instanceof LoopBlock) {
/* In case the try block has no exit (that means, it throws
* an exception), the finallyBlock was already merged with
* the catchBlock. We have to check for this case separately:
@ -630,20 +689,21 @@ public class TransformExceptionHandlers {
* break;
* throw local_x
* } while(false);
* finallyBlock;
* finallyBlock; (starts with POP / local_y = POP)
*/
LoopBlock doWhileFalse = (LoopBlock)catchBlock.subBlocks[0];
LoopBlock doWhileFalse = (LoopBlock)catchBlock.getSubBlocks()[0];
if (doWhileFalse.type == LoopBlock.DOWHILE
&& doWhileFalse.cond == LoopBlock.FALSE
&& doWhileFalse.bodyBlock instanceof SequentialBlock) {
finallyBlock = catchBlock.subBlocks[1];
catchBlock = (SequentialBlock) doWhileFalse.bodyBlock;
if (transformSubRoutine(catchBlock.getSubBlocks()[1])) {
finallyBlock = catchBlock.getSubBlocks()[1];
catchBlock = (SequentialBlock) doWhileFalse.bodyBlock;
}
}
}
if (!(catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0] instanceof JsrBlock
&& instr instanceof StoreInstruction
&& catchBlock.getSubBlocks()[1] instanceof ThrowBlock))
return false;
@ -652,21 +712,12 @@ public class TransformExceptionHandlers {
ThrowBlock throwBlock = (ThrowBlock) catchBlock.getSubBlocks()[1];
if (!(throwBlock.instr instanceof LocalLoadOperator)
|| !(((StoreInstruction) instr).lvalueMatches
((LocalLoadOperator) throwBlock.instr)))
if (!(throwBlock.getInstruction() instanceof Operator
&& excStore.lvalueMatches((Operator)
throwBlock.getInstruction())))
return false;
/* 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.
*/
FlowBlock subRoutine;
if (finallyBlock != null) {
/* Check if the jsr breaks (see two comments above). We don't
* need to check if it breaks to the right block, because
@ -676,146 +727,128 @@ public class TransformExceptionHandlers {
return false;
/* Check if the try block has no exit
* XXX - Unfortunately the try block already has the
* successors of catch block.
*/
if (tryFlow.getSuccessors().size() > 0)
return false;
// if (tryFlow.getSuccessors().size() > 0)
// return false;
/* Replace the catchBlock with the finallyBlock.
*/
finallyBlock.replace(catchFlow.block);
transformSubRoutine(finallyBlock);
catchBlock = finallyBlock;
subRoutine = null;
} else {
if (!(jsrBlock.innerBlock instanceof EmptyBlock))
return false;
catchBlock = jsrBlock;
subRoutine = jsrBlock.innerBlock.jump.destination;
checkAndRemoveJSR(tryFlow, catchBlock, subRoutine,
tryFlow.getNextBlockNr(),
subRoutine.getBlockNr());
}
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeBlockNr(catchFlow);
finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow);
/* Wow that was complicated :-)
* But now we know that the catch block looks
* exactly like it should:
*
* local_n = POP
* catchBlock:
* JSR
* finally
* throw local_n
*/
} else {
FlowBlock subRoutine = jsrBlock.innerBlock.jump.destination;
checkAndRemoveJSR(tryFlow, subRoutine,
tryFlow.getNextBlockNr(), catchFlow.getBlockNr());
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(catchBlock);
tryBlock.addCatchBlock(newBlock);
while (subRoutine.analyze(catchFlow.getNextBlockNr(), end));
if (subRoutine != null) {
while (subRoutine.analyze(tryFlow.getNextBlockNr(), end));
System.err.println("Finally: "+subRoutine+
" Try: "+tryFlow+
" preds: "+subRoutine.predecessors);
/* Now check if the subroutine is correct and has only the
* catchFlow as predecessor.
*/
if (subRoutine.predecessors.size() == 1
&& transformSubRoutine(subRoutine.block)) {
subRoutine.mergeBlockNr(catchFlow);
/* Now remove the jump to the JSR from the catch block
*/
catchFlow.removeSuccessor(jsrBlock.innerBlock.jump);
jsrBlock.innerBlock.removeJump();
tryFlow.updateInOutCatch(subRoutine);
tryFlow.removeSuccessor(jsrBlock.innerBlock.jump);
tryFlow.mergeBlockNr(subRoutine);
tryFlow.mergeSuccessors(subRoutine);
finallyBlock = subRoutine.block;
} else {
finallyBlock = jsrBlock;
subRoutine.block.replace(catchBlock);
tryFlow.updateInOutCatch(subRoutine);
}
}
return true;
}
finallyBlock.replace(catchFlow.block);
transformSubRoutine(finallyBlock);
private boolean analyzeSpecialFinally(FlowBlock tryFlow,
StructuredBlock catchBlock,
int end) {
StructuredBlock firstInstr =
catchBlock instanceof SequentialBlock
? catchBlock.getSubBlocks()[0]: catchBlock;
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeBlockNr(catchFlow);
finallyBlock = catchFlow.block;
tryFlow.mergeSuccessors(catchFlow);
}
if (!(firstInstr instanceof SpecialBlock
&& ((SpecialBlock)firstInstr).type == SpecialBlock.POP
&& ((SpecialBlock)firstInstr).count == 1))
return false;
/* This may be a special try/finally-block, where
* the finally block ends with a break, return or
* similar.
*/
FlowBlock succ = null;
/* remove the pop now */
if (catchBlock instanceof SequentialBlock)
catchBlock = catchBlock.getSubBlocks()[1];
else {
catchBlock = new EmptyBlock();
catchBlock.moveJump(firstInstr.jump);
succ = firstInstr.jump.destination;
}
// Set trySuccs = tryFlow.getSuccessors();
// if (trySuccs.size() > 1
// || (trySuccs.size() == 1
// && trySuccs.iterator().next() != succ))
// return false;
if (succ != null) {
/* Handle the jumps in the tryFlow.
*/
Jump jumps = tryFlow.removeJumps(succ);
jumps = tryFlow.resolveSomeJumps(jumps, succ);
tryFlow.resolveRemaining(jumps);
}
TryBlock tryBlock = (TryBlock)tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* remove the surrounding tryBlock */
/* remove the unnecessary tryBlock */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = tryBlock;
tryFlow.block = tryBlock;
tryFlow.lastModified = innerTry;
}
FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(finallyBlock);
tryBlock.addCatchBlock(newBlock);
newBlock.setCatchBlock(catchBlock);
return true;
}
private boolean analyzeSpecialFinally(FlowBlock tryFlow,
FlowBlock catchFlow, int end) {
StructuredBlock firstInstr =
catchFlow.block instanceof SequentialBlock
? catchFlow.block.getSubBlocks()[0]: catchFlow.block;
if (firstInstr instanceof SpecialBlock
&& ((SpecialBlock)firstInstr).type == SpecialBlock.POP
&& ((SpecialBlock)firstInstr).count == 1) {
/* This is a special try/finally-block, where
* the finally block ends with a break, return or
* similar.
*/
FlowBlock succ = (firstInstr.jump != null) ?
firstInstr.jump.destination : null;
boolean hasExit = false;
Iterator iter = tryFlow.getSuccessors().iterator();
while (iter.hasNext()) {
FlowBlock dest = (FlowBlock) iter.next();
if (dest == succ)
continue;
/* There is another exit in the try block, bad */
return false;
}
/* remove the pop now */
EmptyBlock eb = new EmptyBlock();
eb.moveJump(firstInstr.jump);
eb.replace(firstInstr);
if (catchFlow.lastModified == firstInstr)
catchFlow.lastModified = eb;
if (succ != null) {
Jump jumps = tryFlow.removeJumps(succ);
/* Handle the jumps in the tryFlow.
*/
jumps = tryFlow.resolveSomeJumps(jumps, succ);
tryFlow.resolveRemaining(jumps);
}
TryBlock tryBlock = (TryBlock)tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* remove the unnecessary tryBlock */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = innerTry;
}
FinallyBlock newBlock = new FinallyBlock();
tryBlock.addCatchBlock(newBlock);
/* try block has no successors */
if (succ != null && succ.predecessors.size() == 1) {
catchFlow.checkConsistent();
while (catchFlow.analyze(catchFlow.getBlockNr(), end));
newBlock.setCatchBlock(catchFlow.block);
tryFlow.mergeBlockNr(catchFlow);
tryFlow.mergeSuccessors(catchFlow);
} else {
/* Put the catchBlock in instead.
*/
newBlock.setCatchBlock(catchFlow.block);
tryFlow.mergeBlockNr(catchFlow);
tryFlow.mergeSuccessors(catchFlow);
}
return true;
}
return false;
}
/**
* Analyzes all exception handlers to try/catch/finally or
* synchronized blocks.
@ -937,16 +970,21 @@ public class TransformExceptionHandlers {
endHandler));
}
/* Merge the try-block with the catch-block now */
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeBlockNr(catchFlow);
if (exc.type != null)
analyzeCatchBlock(exc.type, tryFlow, catchFlow);
analyzeCatchBlock(exc.type, tryFlow, catchFlow.block);
else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler)
&& ! analyzeFinally(tryFlow, catchFlow, endHandler)
&& ! analyzeSpecialFinally(tryFlow, catchFlow,
else if (!analyzeSynchronized(tryFlow, catchFlow.block,
endHandler)
&& ! analyzeFinally(tryFlow, catchFlow.block,
endHandler)
&& ! analyzeSpecialFinally(tryFlow, catchFlow.block,
endHandler))
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow);
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow.block);
tryFlow.checkConsistent();
if ((GlobalOptions.debuggingFlags

Loading…
Cancel
Save