Fixed Java-1.1 and finally/synchronized blocks.

git-svn-id: https://svn.code.sf.net/p/jode/code/branches/branch_1_1@1343 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
hoenicke 24 years ago
parent c79f6122f5
commit 03497ae1a2
  1. 35
      jode/ChangeLog
  2. 5
      jode/jode/flow/FlowBlock.java.in
  3. 415
      jode/jode/flow/TransformExceptionHandlers.java.in

@ -1,3 +1,35 @@
2001-08-12 Jochen Hoenicke <jochen@gnu.org>
* jode/flow/FlowBlock.java.in:
(checkConsistent): Allow lastModified in a finally block.
* jode/flow/TransformExceptionHandlers.java.in: Reworked exception
handlers again. This time checked with javac 1.3, javac 1.1 and
jikes.
(checkTryCatchOrder): New method that was previously part of
analyze.
(analyze): Use checkTryCatchOrder. Don't merge try and catch flow
blocks anymore, leave it to the analyzeXXX methods.
(mergeTryCatch): New method.
(analyzeCatchBlock): Get catchFlow as parameter. Call
mergeTryCatch.
(transformSubroutine): Handle POP-only subroutines.
(removeJSR): Don't do special case for catchBlock any more. This
is because catchFlow isn't yet merged when this method is called.
(checkAndRemoveJSR): Likewise.
(checkAndRemoveMonitorExit): Likewise. Merge subroutine only if
we are the only predecessor.
(analyzeSynchronized): Get catchFlow as parameter. Call
mergeTryCatch.
(mergeFinallyBlocks): New method, calls mergeTryCatch and does the
common part of mergeFinally and mergeSpecialFinally.
(analyzeFinally): Simplified, after checking and removing JSR, it
does immediately analyze and transform subroutine to get the
finallyBlock. Then it throws away the catchFlow and calls
mergeFinallyBlocks.
(analyzeSpecialFinally): Simplified, after checking it only handles
the jumps in the try part and then call mergeFinallyBlocks.
2001-08-10 Jochen Hoenicke <jochen@gnu.org> 2001-08-10 Jochen Hoenicke <jochen@gnu.org>
* configure.in: Changed bash syntax to more compatible (but * configure.in: Changed bash syntax to more compatible (but
@ -32,8 +64,7 @@
2001-07-08 Jochen Hoenicke <jochen@gnu.org> 2001-07-08 Jochen Hoenicke <jochen@gnu.org>
* jode/bytecode/BytecodeInfo.java.in (calculateMaxStack): Handle * jode/bytecode/BytecodeInfo.java.in (calculateMaxStack): Handle special case for empty method. Previous code would just crash.
special case for empty method. Previous code would just crash.
2001-06-15 Jochen Hoenicke <jochen@gnu.org> 2001-06-15 Jochen Hoenicke <jochen@gnu.org>

@ -1,4 +1,4 @@
/* FlowBlock Copyright (C) 1998-1999 Jochen Hoenicke. /* FlowBlock Copyright (C) 1998-2001 Jochen Hoenicke.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -748,7 +748,8 @@ public class FlowBlock {
StructuredBlock last = lastModified; StructuredBlock last = lastModified;
while (last.outer instanceof SequentialBlock while (last.outer instanceof SequentialBlock
|| last.outer instanceof TryBlock) || last.outer instanceof TryBlock
|| last.outer instanceof FinallyBlock)
last = last.outer; last = last.outer;
if (last.outer != null) if (last.outer != null)
throw new AssertError("Inconsistency"); throw new AssertError("Inconsistency");

@ -99,35 +99,63 @@ public class TransformExceptionHandlers {
} }
/* simple try catch block: /**
* Merge the try flow block with the catch flow block. This is a kind
* of special T2 transformation, as all jumps to the catch block are
* implicit (exception can be thrown everywhere). <br>
* *
* try-header * This method doesn't actually merge the contents of the blocks. The
* |- first instruction * caller should do it right afterwards. <br>
* | ... *
* | last instruction * The flow block catchFlow mustn't have any predecessors.
* |- optional jump (last+1) * @param tryFlow the flow block containing the try.
* | ... * @param catchFlow the flow block containing the catch handler.
* `- catch block */
static void mergeTryCatch(FlowBlock tryFlow, FlowBlock catchFlow) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("mergeTryCatch(" + tryFlow.getAddr()
+ ", " + catchFlow.getAddr() + ")");
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeAddr(catchFlow);
}
/**
* Analyzes a simple try/catch block. The try and catch part are both
* analyzed, the try block is already created, but the catch block
* isn't. <br>
* The catchFlow block mustn't have any predecessors.
*
* @param type The type of the exception which is caught.
* @param tryFlow The flow block containing the try. The contained
* block must be a try block.
* @param catchFlow the flow block containing the catch handler.
*/ */
static void analyzeCatchBlock(Type type, FlowBlock tryFlow, static void analyzeCatchBlock(Type type, FlowBlock tryFlow,
StructuredBlock catchBlock) { FlowBlock catchFlow) {
/* Merge try and catch flow blocks */
mergeTryCatch(tryFlow, catchFlow);
/* Insert catch block into tryFlow */
CatchBlock newBlock = new CatchBlock(type); CatchBlock newBlock = new CatchBlock(type);
((TryBlock)tryFlow.block).addCatchBlock(newBlock); ((TryBlock)tryFlow.block).addCatchBlock(newBlock);
newBlock.setCatchBlock(catchBlock); newBlock.setCatchBlock(catchFlow.block);
} }
/* And now the complicated parts. */ /* And now the complicated parts. */
/** /**
* This transforms a sub routine, that is checks if the beginning * This transforms a sub routine, i.e. it checks if the beginning
* local assignment matches the final ret and then returns. * local assignment matches the final ret and removes both. It also
* accepts sub routines that just pop their return address.
*/ */
boolean transformSubRoutine(StructuredBlock subRoutine) { boolean transformSubRoutine(StructuredBlock subRoutineBlock) {
if (!(subRoutine instanceof SequentialBlock)) StructuredBlock firstBlock = subRoutineBlock;
return false; if (firstBlock instanceof SequentialBlock)
SequentialBlock sequBlock = (SequentialBlock) subRoutine; firstBlock = subRoutineBlock.getSubBlocks()[0];
StructuredBlock firstBlock = sequBlock.getSubBlocks()[0];
LocalInfo local = null; LocalInfo local = null;
if (firstBlock instanceof SpecialBlock) { if (firstBlock instanceof SpecialBlock) {
@ -152,24 +180,25 @@ public class TransformExceptionHandlers {
} else } else
return false; return false;
/* We have now committed. Remove the first Statement which /* We are now committed and can start changing code. Remove
* stores/removes the return address. * the first Statement which stores/removes the return
* address.
*/ */
firstBlock.removeBlock(); firstBlock.removeBlock();
/* XXX - Replace any RET with a jump to end of this flow block. /* We don't check if there is a RET in the middle.
* *
* This is a complicated task which isn't needed for javac nor * This is a complicated task which isn't needed for javac nor
* jikes. We just check if the last instruction is a ret and * jikes. We just check if the last instruction is a ret and
* replace this. This will never produce code with wrong semantic, * remove this. This will never produce code with wrong semantic,
* as long as the bytecode was verified correctly. * as long as the bytecode was verified correctly.
*/ */
while (sequBlock.subBlocks[1] instanceof SequentialBlock) while (subRoutineBlock instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; subRoutineBlock = subRoutineBlock.getSubBlocks()[1];
if (sequBlock.subBlocks[1] instanceof RetBlock if (subRoutineBlock instanceof RetBlock
&& (((RetBlock) sequBlock.subBlocks[1]).local.equals(local))) { && (((RetBlock) subRoutineBlock).local.equals(local))) {
sequBlock.subBlocks[1].removeBlock(); subRoutineBlock.removeBlock();
} }
return true; return true;
} }
@ -199,51 +228,32 @@ public class TransformExceptionHandlers {
} }
/** /**
* Remove the wrongly placed JSRs jumping to the specified * Remove the JSRs jumping to the specified subRoutine. The right
* subRoutine. The right JSRs are already removed, but we have to * JSRs are marked and we can just remove them. For the other JSR
* replace the wrong ones with a warning. * instructions we replace them with a warning.
* @param tryFlow the FlowBLock of the try block. * @param tryFlow the FlowBlock of the try block.
* @param subRoutine the FlowBlock of the sub routine. * @param subRoutine the FlowBlock of the sub routine.
*/ */
private void removeJSR(FlowBlock tryFlow, StructuredBlock catchBlock, private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) {
FlowBlock subRoutine) { for (Jump jumps = tryFlow.removeJumps(subRoutine);
Jump nextJump; jumps != null; jumps = jumps.next) {
for (Jump jumps = tryFlow.getJumps(subRoutine);
jumps != null; jumps = nextJump) {
StructuredBlock prev = jumps.prev; StructuredBlock prev = jumps.prev;
nextJump = jumps.next;
if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) {
JsrBlock jsr = (JsrBlock) prev.outer;
if (prev.outer == catchBlock) {
/* This is the mandatory jsr in the catch block */
continue;
}
tryFlow.removeSuccessor(jumps);
prev.removeJump(); prev.removeJump();
if (jsr.isGood()) {
StructuredBlock next = jsr.getNextBlock(); if (prev instanceof EmptyBlock
jsr.removeBlock(); && prev.outer instanceof JsrBlock
&& ((JsrBlock) prev.outer).isGood()) {
StructuredBlock next = prev.outer.getNextBlock();
prev.outer.removeBlock();
if (next instanceof ReturnBlock) if (next instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) next); removeReturnLocal((ReturnBlock) next);
} else { } else {
/* We have a JSR to the subroutine, which is badly placed. /* We have a jump to the subroutine, that is badly placed.
* We complain here.
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: JSR FINALLY BLOCK!");
msg.replace(prev.outer);
}
} else {
/* We have a jump to the subroutine, that is wrong.
* We complain here. * We complain here.
*/ */
DescriptionBlock msg DescriptionBlock msg = new DescriptionBlock
= new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!"); ("ERROR: invalid jump to finally block!");
tryFlow.removeSuccessor(jumps);
prev.removeJump();
prev.appendBlock(msg); prev.appendBlock(msg);
} }
} }
@ -309,7 +319,6 @@ public class TransformExceptionHandlers {
private void checkAndRemoveJSR(FlowBlock tryFlow, private void checkAndRemoveJSR(FlowBlock tryFlow,
StructuredBlock catchBlock,
FlowBlock subRoutine, FlowBlock subRoutine,
int startOutExit, int endOutExit) { int startOutExit, int endOutExit) {
Iterator iter = tryFlow.getSuccessors().iterator(); Iterator iter = tryFlow.getSuccessors().iterator();
@ -332,8 +341,8 @@ public class TransformExceptionHandlers {
} }
if (prev instanceof EmptyBlock if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) { && prev.outer instanceof JsrBlock) {
/* This jump is really a jsr, since it doesn't /* This jump is a jsr, since it doesn't leave the
* leave the block forever, we can ignore it. * block forever, we can ignore it.
*/ */
continue; continue;
} }
@ -384,7 +393,7 @@ public class TransformExceptionHandlers {
* Complain! * Complain!
*/ */
DescriptionBlock msg DescriptionBlock msg
= new DescriptionBlock("ERROR: NO JSR TO FINALLY"); = new DescriptionBlock("ERROR: no jsr to finally");
if (pred != null) if (pred != null)
pred.prependBlock(msg); pred.prependBlock(msg);
else { else {
@ -394,11 +403,10 @@ public class TransformExceptionHandlers {
} }
} }
if (tryFlow.getSuccessors().contains(subRoutine)) if (tryFlow.getSuccessors().contains(subRoutine))
removeJSR(tryFlow, catchBlock, subRoutine); removeJSR(tryFlow, subRoutine);
} }
private void checkAndRemoveMonitorExit(FlowBlock tryFlow, private void checkAndRemoveMonitorExit(FlowBlock tryFlow,
StructuredBlock catchBlock,
LocalInfo local, LocalInfo local,
int start, int end) { int start, int end) {
FlowBlock subRoutine = null; FlowBlock subRoutine = null;
@ -502,7 +510,7 @@ public class TransformExceptionHandlers {
/* Complain! /* Complain!
*/ */
DescriptionBlock msg DescriptionBlock msg
= new DescriptionBlock("ERROR: NO MONITOREXIT"); = new DescriptionBlock("ERROR: no monitorexit");
prev.appendBlock(msg); prev.appendBlock(msg);
msg.moveJump(jumps); msg.moveJump(jumps);
} }
@ -510,7 +518,8 @@ public class TransformExceptionHandlers {
if (subRoutine != null) { if (subRoutine != null) {
if (tryFlow.getSuccessors().contains(subRoutine)) if (tryFlow.getSuccessors().contains(subRoutine))
removeJSR(tryFlow, catchBlock, subRoutine); removeJSR(tryFlow, subRoutine);
if (subRoutine.predecessors.size() == 0)
tryFlow.mergeAddr(subRoutine); tryFlow.mergeAddr(subRoutine);
} }
} }
@ -534,20 +543,25 @@ public class TransformExceptionHandlers {
} }
private boolean analyzeSynchronized(FlowBlock tryFlow, private boolean analyzeSynchronized(FlowBlock tryFlow,
StructuredBlock catchBlock, FlowBlock catchFlow,
int endHandler) { int endHandler) {
/* Check if this is a synchronized block. We mustn't change
* anything until we are sure.
*/
StructuredBlock catchBlock = catchFlow.block;
/* Check for a optional exception store and skip it */
StoreInstruction excStore = getExceptionStore(catchBlock); StoreInstruction excStore = getExceptionStore(catchBlock);
if (excStore != null) if (excStore != null)
catchBlock = catchBlock.getSubBlocks()[1]; catchBlock = catchBlock.getSubBlocks()[1];
/* Check for the monitorexit instruction */
if (!(catchBlock instanceof SequentialBlock if (!(catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0] && catchBlock.getSubBlocks()[0]
instanceof InstructionBlock)) instanceof InstructionBlock))
return false; return false;
Expression instr = Expression instr =
((InstructionBlock)catchBlock.getSubBlocks()[0]).getInstruction(); ((InstructionBlock)catchBlock.getSubBlocks()[0]).getInstruction();
if (!(instr instanceof MonitorExitOperator if (!(instr instanceof MonitorExitOperator
&& instr.getFreeOperandCount() == 0 && instr.getFreeOperandCount() == 0
&& (((MonitorExitOperator)instr).getSubExpressions()[0] && (((MonitorExitOperator)instr).getSubExpressions()[0]
@ -592,6 +606,16 @@ public class TransformExceptionHandlers {
* return_n * return_n
*/ */
/* Merge try and catch flow blocks. No need to insert the
* catchFlow.block into the try flow though, since all its
* instruction are synthetic.
*
* Though we need to remove the jump of the throw
* instruction.
*/
catchFlow.removeSuccessor(catchBlock.getSubBlocks()[1].jump);
mergeTryCatch(tryFlow, catchFlow);
MonitorExitOperator monexit = (MonitorExitOperator) MonitorExitOperator monexit = (MonitorExitOperator)
((InstructionBlock) catchBlock.getSubBlocks()[0]).instr; ((InstructionBlock) catchBlock.getSubBlocks()[0]).instr;
LocalInfo local = LocalInfo local =
@ -605,7 +629,7 @@ public class TransformExceptionHandlers {
+ "," + tryFlow.getNextAddr() + "," + endHandler + ")"); + "," + tryFlow.getNextAddr() + "," + endHandler + ")");
checkAndRemoveMonitorExit checkAndRemoveMonitorExit
(tryFlow, catchBlock, local, tryFlow.getNextAddr(), endHandler); (tryFlow, local, tryFlow.getNextAddr(), endHandler);
SynchronizedBlock syncBlock = new SynchronizedBlock(local); SynchronizedBlock syncBlock = new SynchronizedBlock(local);
TryBlock tryBlock = (TryBlock) tryFlow.block; TryBlock tryBlock = (TryBlock) tryFlow.block;
@ -617,8 +641,41 @@ public class TransformExceptionHandlers {
return true; return true;
} }
/**
* Merge try and finally flow blocks.
* @param tryFlow The try flow block. Its contained block must be
* a try block.
* @param catchFlow The catch flow block that contains the finally
* block.
* @param finallyBlock block that either contains the finally block.
* It is part of the catchFlow. The other parts of catchFlow are
* synthetic and can be removed.
*/
private void mergeFinallyBlock(FlowBlock tryFlow, FlowBlock catchFlow,
StructuredBlock finallyBlock) {
TryBlock tryBlock = (TryBlock) tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* A try { try { } catch {} } finally{} is equivalent
* to a try {} catch {} finally {}
* so 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;
}
/* Now merge try and catch flow blocks */
mergeTryCatch(tryFlow, catchFlow);
FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(finallyBlock);
tryBlock.addCatchBlock(newBlock);
}
private boolean analyzeFinally(FlowBlock tryFlow, private boolean analyzeFinally(FlowBlock tryFlow,
StructuredBlock catchBlock, int end) { FlowBlock catchFlow, int end) {
/* Layout of a try-finally block: /* Layout of a try-finally block:
* *
@ -640,6 +697,7 @@ public class TransformExceptionHandlers {
* return_n * return_n
*/ */
StructuredBlock catchBlock = catchFlow.block;
StoreInstruction excStore = getExceptionStore(catchBlock); StoreInstruction excStore = getExceptionStore(catchBlock);
if (excStore == null) if (excStore == null)
return false; return false;
@ -651,9 +709,10 @@ public class TransformExceptionHandlers {
StructuredBlock finallyBlock = null; StructuredBlock finallyBlock = null;
if (catchBlock.getSubBlocks()[0] instanceof LoopBlock) { if (catchBlock.getSubBlocks()[0] instanceof LoopBlock) {
/* In case the try block has no exit (that means, it throws /* In case the try block has no exit (that means, it
* an exception), the finallyBlock was already merged with * throws an exception or loops forever), the finallyBlock
* the catchBlock. We have to check for this case separately: * was already merged with the catchBlock. We have to
* check for this case separately:
* *
* do { * do {
* JSR * JSR
@ -690,142 +749,151 @@ public class TransformExceptionHandlers {
FlowBlock subRoutine; FlowBlock subRoutine;
if (finallyBlock != null) { if (finallyBlock != null) {
/* Check if the jsr breaks (see two comments above). We don't /* Check if the jsr breaks (see comment above). We don't
* need to check if it breaks to the right block, because * need to check if it breaks to the right block, because
* we know that there is only one Block around the jsr. * we know that there is only one Block around the jsr.
*/ */
if (!(jsrBlock.innerBlock instanceof BreakBlock)) if (!(jsrBlock.innerBlock instanceof BreakBlock))
return false; return false;
/* Check if the try block has no exit (except throws) /* TODO - Check if the try block has no exit (except throws)
* XXX - Unfortunately the try block already has the
* successors of catch block.
*/ */
// if (tryFlow.getSuccessors() > 0) // if (tryFlow.getSuccessors().size() > 0)
// return false; // return false;
catchBlock = finallyBlock; catchBlock = finallyBlock;
subRoutine = null; subRoutine = null;
catchFlow.removeSuccessor(throwBlock.jump);
} else { } else {
if (!(jsrBlock.innerBlock instanceof EmptyBlock)) if (!(jsrBlock.innerBlock instanceof EmptyBlock))
return false; return false;
catchBlock = jsrBlock; finallyBlock = jsrBlock.innerBlock;
subRoutine = jsrBlock.innerBlock.jump.destination; subRoutine = finallyBlock.jump.destination;
checkAndRemoveJSR(tryFlow, catchBlock, subRoutine,
tryFlow.getNextAddr(), subRoutine.getAddr());
}
/* Wow that was complicated :-) /* We are committed now and can start changing the blocks.
* But now we know that the catch block looks
* exactly like it should:
*
* local_n = POP
* catchBlock:
* JSR
* finally
* throw local_n
*/ */
catchFlow.removeSuccessor(throwBlock.jump);
checkAndRemoveJSR(tryFlow, subRoutine,
tryFlow.getNextAddr(), end);
TryBlock tryBlock = (TryBlock) tryFlow.block; /* Now analyze and transform the subroutine.
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);
if (subRoutine != null) {
while (subRoutine.analyze(tryFlow.getNextAddr(), end)); while (subRoutine.analyze(tryFlow.getNextAddr(), end));
if (subRoutine.predecessors.size() == 1) {
/* Now check if the subroutine is correct and has only the /* catchFlow is synthetic, so we can safely remove it
* catchFlow as predecessor. * here.
*/ */
if (subRoutine.predecessors.size() == 1 catchFlow.removeSuccessor(finallyBlock.jump);
&& transformSubRoutine(subRoutine.block)) { subRoutine.mergeAddr(catchFlow);
catchFlow = subRoutine;
tryFlow.removeSuccessor(jsrBlock.innerBlock.jump); if (!transformSubRoutine(subRoutine.block)) {
tryFlow.mergeAddr(subRoutine); finallyBlock = subRoutine.block;
tryFlow.mergeSuccessors(subRoutine); DescriptionBlock msg = new DescriptionBlock
subRoutine.block.replace(catchBlock); ("ERROR: Missing return address handling");
tryFlow.updateInOutCatch(subRoutine); StructuredBlock subblock = subRoutine.block;
msg.replace(finallyBlock);
msg.appendBlock(finallyBlock);
}
finallyBlock = subRoutine.block;
} }
} }
/* Now finish it.
*/
mergeFinallyBlock(tryFlow, catchFlow, finallyBlock);
return true; return true;
} }
private boolean analyzeSpecialFinally(FlowBlock tryFlow, private boolean analyzeSpecialFinally(FlowBlock tryFlow,
StructuredBlock catchBlock, FlowBlock catchFlow, int end) {
int end) { StructuredBlock finallyBlock = catchFlow.block;
StructuredBlock firstInstr = StructuredBlock firstInstr =
catchBlock instanceof SequentialBlock finallyBlock instanceof SequentialBlock
? catchBlock.getSubBlocks()[0]: catchBlock; ? finallyBlock.getSubBlocks()[0]: finallyBlock;
if (!(firstInstr instanceof SpecialBlock if (!(firstInstr instanceof SpecialBlock
&& ((SpecialBlock)firstInstr).type == SpecialBlock.POP && ((SpecialBlock)firstInstr).type == SpecialBlock.POP
&& ((SpecialBlock)firstInstr).count == 1)) && ((SpecialBlock)firstInstr).count == 1))
return false; return false;
/* This may be a special try/finally-block, where /* This is a special try/finally-block, where
* the finally block ends with a break, return or * the finally block ends with a break, return or
* similar. * similar.
*/ */
FlowBlock succ = null;
/* remove the pop now */ /* Make sure that resolveJump only works on the inside of the try
if (catchBlock instanceof SequentialBlock) */
catchBlock = catchBlock.getSubBlocks()[1]; tryFlow.lastModified = tryFlow.block.getSubBlocks()[0];
else { FlowBlock finallyFlow;
catchBlock = new EmptyBlock(); if (finallyBlock instanceof SequentialBlock) {
catchBlock.moveJump(firstInstr.jump); finallyBlock = finallyBlock.getSubBlocks()[1];
finallyFlow = null;
} else {
finallyBlock = new EmptyBlock();
finallyBlock.moveJump(firstInstr.jump);
succ = firstInstr.jump.destination; /* Handle the jumps in the tryFlow to finallyFlow.
*/
finallyFlow = finallyBlock.jump.destination;
if (tryFlow.getSuccessors().contains(finallyFlow)) {
Jump jumps = tryFlow.removeJumps(finallyFlow);
jumps = tryFlow.resolveSomeJumps(jumps, finallyFlow);
tryFlow.resolveRemaining(jumps);
}
} }
// Set trySuccs = tryFlow.getSuccessors(); /* Complain about all other jumps in try block */
// if (trySuccs.size() > 1 Set trySuccs = tryFlow.getSuccessors();
// || (trySuccs.size() == 1 for (Iterator i = trySuccs.iterator(); i.hasNext(); ) {
// && trySuccs.iterator().next() != succ)) FlowBlock succ = (FlowBlock) i.next();
// return false; if (succ != FlowBlock.END_OF_METHOD) {
/* This seems to be a illegal succ in try block that
if (succ != null) { * doesn't go to the finally block. There is a last
Jump jumps = tryFlow.removeJumps(succ); * chance though. If the destination directly jumps
/* Handle the jumps in the tryFlow. * to the try block, its okay.
*/ */
jumps = tryFlow.resolveSomeJumps(jumps, succ); if (succ.block instanceof EmptyBlock
&& succ.block.jump.destination == finallyFlow) {
Jump jumps = tryFlow.removeJumps(succ);
jumps = tryFlow.resolveSomeJumps(jumps, finallyFlow);
tryFlow.resolveRemaining(jumps); tryFlow.resolveRemaining(jumps);
if (succ.predecessors.size() == 0) {
succ.removeJumps(finallyFlow);
tryFlow.mergeAddr(succ);
}
continue;
} }
}
for (Jump jumps = tryFlow.getJumps(succ);
jumps != null; jumps = jumps.next) {
if (jumps.prev instanceof ThrowBlock)
continue;
TryBlock tryBlock = (TryBlock)tryFlow.block; DescriptionBlock msg =
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) { new DescriptionBlock
/* remove the unnecessary tryBlock */ ("ERROR: doesn't go through finally block!");
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0]; if (jumps.prev instanceof ReturnBlock) {
innerTry.gen = tryBlock.gen; msg.replace(jumps.prev);
innerTry.replace(tryBlock); msg.appendBlock(jumps.prev);
tryBlock = innerTry; } else {
tryFlow.lastModified = innerTry; jumps.prev.appendBlock(msg);
msg.moveJump(jumps);
} }
FinallyBlock newBlock = new FinallyBlock(); }
tryBlock.addCatchBlock(newBlock); }
newBlock.setCatchBlock(catchBlock);
mergeFinallyBlock(tryFlow, catchFlow, finallyBlock);
/* Following code will work be put inside the finallyBlock */
tryFlow.lastModified = finallyBlock;
return true; return true;
} }
/** void checkTryCatchOrder() {
* Analyzes all exception handlers to try/catch/finally or
* synchronized blocks.
*/
public void analyze() {
/* Check if try/catch ranges are okay. The following succeeds /* Check if try/catch ranges are okay. The following succeeds
* for all classes generated by the sun java compiler, but hand * for all classes generated by the sun java compiler, but hand
* optimized classes (or generated by other compilers) will fail. * optimized classes (or generated by other compilers) will fail.
*/ */
{
Handler last = null; Handler last = null;
for (Iterator i = handlers.iterator(); i.hasNext(); ) { for (Iterator i = handlers.iterator(); i.hasNext(); ) {
Handler exc = (Handler) i.next(); Handler exc = (Handler) i.next();
@ -852,7 +920,13 @@ public class TransformExceptionHandlers {
} }
} }
{ /**
* Analyzes all exception handlers to try/catch/finally or
* synchronized blocks.
*/
public void analyze() {
checkTryCatchOrder();
Iterator i = handlers.iterator(); Iterator i = handlers.iterator();
Handler exc = null; Handler exc = null;
Handler next = i.hasNext() ? (Handler) i.next() : null; Handler next = i.hasNext() ? (Handler) i.next() : null;
@ -923,21 +997,15 @@ public class TransformExceptionHandlers {
while (catchFlow.analyze(catchFlow.getAddr(), endHandler)); while (catchFlow.analyze(catchFlow.getAddr(), endHandler));
} }
/* Merge the try-block with the catch-block now */
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeAddr(catchFlow);
if (exc.type != null) if (exc.type != null)
analyzeCatchBlock(exc.type, tryFlow, catchFlow.block); analyzeCatchBlock(exc.type, tryFlow, catchFlow);
else if (!analyzeSynchronized(tryFlow, catchFlow.block, else if (!analyzeSynchronized(tryFlow, catchFlow, endHandler)
endHandler) && ! analyzeFinally(tryFlow, catchFlow, endHandler)
&& ! analyzeFinally(tryFlow, catchFlow.block, && ! analyzeSpecialFinally(tryFlow, catchFlow,
endHandler)
&& ! analyzeSpecialFinally(tryFlow, catchFlow.block,
endHandler)) endHandler))
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow.block); analyzeCatchBlock(Type.tObject, tryFlow, catchFlow);
tryFlow.checkConsistent(); tryFlow.checkConsistent();
if ((GlobalOptions.debuggingFlags if ((GlobalOptions.debuggingFlags
@ -947,5 +1015,4 @@ public class TransformExceptionHandlers {
+ tryFlow.getNextAddr() + ") done."); + tryFlow.getNextAddr() + ") done.");
} }
} }
}
} }

Loading…
Cancel
Save