@ -103,35 +103,62 @@ public class TransformExceptionHandlers {
handlers . add ( new Handler ( tryBlock , endBlock , catchBlock , type ) ) ;
}
/ * *
* 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 >
*
* This method doesn ' t actually merge the contents of the blocks . The
* caller should do it right afterwards . < br >
*
* The flow block catchFlow mustn ' t have any predecessors .
* @param tryFlow the flow block containing the try .
* @param catchFlow the flow block containing the catch handler .
* /
static void mergeTryCatch ( FlowBlock tryFlow , FlowBlock catchFlow ) {
if ( ( GlobalOptions . debuggingFlags
& GlobalOptions . DEBUG_ANALYZE ) ! = 0 )
GlobalOptions . err . println
( "mergeTryCatch(" + tryFlow . getBlockNr ( )
+ ", " + catchFlow . getBlockNr ( ) + ")" ) ;
tryFlow . updateInOutCatch ( catchFlow ) ;
tryFlow . mergeSuccessors ( catchFlow ) ;
tryFlow . mergeBlockNr ( catchFlow ) ;
}
/ * simple try catch block :
/ * *
* 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 .
*
* try - header
* | - first instruction
* | . . .
* | last instruction
* | - optional jump ( last + 1 )
* | . . .
* ` - catch block
* @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 ,
StructuredBlock catchBlock ) {
FlowBlock catchFlow ) {
/* Merge try and catch flow blocks */
mergeTryCatch ( tryFlow , catchFlow ) ;
/* Insert catch block into tryFlow */
CatchBlock newBlock = new CatchBlock ( type ) ;
( ( TryBlock ) tryFlow . block ) . addCatchBlock ( newBlock ) ;
newBlock . setCatchBlock ( catchBlock ) ;
newBlock . setCatchBlock ( catchFlow . block ) ;
tryFlow . lastModified = tryFlow . block ;
}
/* And now the complicated parts. */
/ * *
* This transforms a sub routine , that is checks if the beginning
* local assignment matches the final ret and then returns .
* This transforms a sub routine , i . e . it checks if the beginning
* local assignment matches the final ret and removes both . It also
* accepts sub routines that just pop their return address .
* /
boolean transformSubRoutine ( StructuredBlock subRoutine ) {
if ( ! ( subRoutine instanceof SequentialBlock ) )
return false ;
SequentialBlock sequBlock = ( SequentialBlock ) subRoutine ;
StructuredBlock firstBlock = sequBlock . getSubBlocks ( ) [ 0 ] ;
boolean transformSubRoutine ( StructuredBlock subRoutineBlock ) {
StructuredBlock firstBlock = subRoutineBlock ;
if ( firstBlock instanceof SequentialBlock )
firstBlock = subRoutineBlock . getSubBlocks ( ) [ 0 ] ;
LocalInfo local = null ;
if ( firstBlock instanceof SpecialBlock ) {
@ -156,24 +183,25 @@ public class TransformExceptionHandlers {
} else
return false ;
/ * We are now committed . Remove the first Statement which
* stores / removes the return address .
/ * We are now committed and can start changing code . 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 .
/ * We don ' t check if there is a RET in the middle .
*
* This is a complicated task which isn ' t needed for javac nor
* jikes . We just check if the last instruction is a ret and
* replac e this . This will never produce code with wrong semantic ,
* remov e this . This will never produce code with wrong semantic ,
* as long as the bytecode was verified correctly .
* /
while ( sequBlock . subBlocks [ 1 ] instanceof SequentialBlock )
seq uBlock = ( SequentialBlock ) sequBlock . subBlocks [ 1 ] ;
while ( subRoutineBlock instanceof SequentialBlock )
subRoutine Block = subRoutineBlock . getSubBlocks ( ) [ 1 ] ;
if ( sequBlock . subBlocks [ 1 ] instanceof RetBlock
& & ( ( ( RetBlock ) sequBlock . subBlocks [ 1 ] ) . local . equals ( local ) ) ) {
sequBlock . subBlocks [ 1 ] . removeBlock ( ) ;
if ( subRoutineBlock instanceof RetBlock
& & ( ( ( RetBlock ) subRoutineBlock ) . local . equals ( local ) ) ) {
subRoutineBlock . removeBlock ( ) ;
}
return true ;
}
@ -203,51 +231,32 @@ public class TransformExceptionHandlers {
}
/ * *
* Remove the wrongly placed JSRs jumping to the specified
* subRoutine . The right JSRs are already removed , but we have to
* replace the wrong ones with a warning .
* @param tryFlow the FlowBL ock of the try block .
* Remove the JSRs jumping to the specified subRoutine . The right
* JSRs are marked and we can just remove them . For the other JSR
* instructions we replace them with a warning .
* @param tryFlow the FlowBl ock of the try block .
* @param subRoutine the FlowBlock of the sub routine .
* /
private void removeJSR ( FlowBlock tryFlow , StructuredBlock catchBlock ,
FlowBlock subRoutine ) {
Jump nextJump ;
for ( Jump jumps = tryFlow . getJumps ( subRoutine ) ;
jumps ! = null ; jumps = nextJump ) {
private void removeJSR ( FlowBlock tryFlow , FlowBlock subRoutine ) {
for ( Jump jumps = tryFlow . removeJumps ( subRoutine ) ;
jumps ! = null ; jumps = jumps . next ) {
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 ;
}
prev . removeJump ( ) ;
tryFlow . removeSuccessor ( jumps ) ;
prev . removeJump ( ) ;
if ( jsr . isGood ( ) ) {
StructuredBlock next = jsr . getNextBlock ( ) ;
jsr . removeBlock ( ) ;
if ( next instanceof ReturnBlock )
removeReturnLocal ( ( ReturnBlock ) next ) ;
} else {
/ * We have a JSR to the subroutine , which 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 .
if ( prev instanceof EmptyBlock
& & prev . outer instanceof JsrBlock
& & ( ( JsrBlock ) prev . outer ) . isGood ( ) ) {
StructuredBlock next = prev . outer . getNextBlock ( ) ;
prev . outer . removeBlock ( ) ;
if ( next instanceof ReturnBlock )
removeReturnLocal ( ( ReturnBlock ) next ) ;
} else {
/ * We have a jump to the subroutine , that is badly placed .
* We complain here .
* /
DescriptionBlock msg
= new DescriptionBlock ( "ERROR: GOTO FINALLY BLOCK!" ) ;
tryFlow . removeSuccessor ( jumps ) ;
prev . removeJump ( ) ;
DescriptionBlock msg = new DescriptionBlock
( "ERROR: invalid jump to finally block!" ) ;
prev . appendBlock ( msg ) ;
}
}
@ -313,7 +322,6 @@ public class TransformExceptionHandlers {
private void checkAndRemoveJSR ( FlowBlock tryFlow ,
StructuredBlock catchBlock ,
FlowBlock subRoutine ,
int startOutExit , int endOutExit ) {
Iterator iter = tryFlow . getSuccessors ( ) . iterator ( ) ;
@ -330,8 +338,8 @@ public class TransformExceptionHandlers {
StructuredBlock prev = jumps . prev ;
if ( prev instanceof EmptyBlock
& & prev . outer instanceof JsrBlock ) {
/ * This jump is really a jsr , since it doesn ' t
* leave the block forever , we can ignore it .
/ * This jump is a jsr , since it doesn ' t leave the
* block forever , we can ignore it .
* /
continue ;
}
@ -382,7 +390,7 @@ public class TransformExceptionHandlers {
* Complain !
* /
DescriptionBlock msg
= new DescriptionBlock ( "ERROR: NO JSR TO FINALLY " ) ;
= new DescriptionBlock ( "ERROR: no jsr to finally " ) ;
if ( pred ! = null )
pred . prependBlock ( msg ) ;
else {
@ -392,11 +400,10 @@ public class TransformExceptionHandlers {
}
}
if ( tryFlow . getSuccessors ( ) . contains ( subRoutine ) )
removeJSR ( tryFlow , catchBlock , subRoutine ) ;
removeJSR ( tryFlow , subRoutine ) ;
}
private void checkAndRemoveMonitorExit ( FlowBlock tryFlow ,
StructuredBlock catchBlock ,
LocalInfo local ,
int start , int end ) {
FlowBlock subRoutine = null ;
@ -494,7 +501,7 @@ public class TransformExceptionHandlers {
/ * Complain !
* /
DescriptionBlock msg
= new DescriptionBlock ( "ERROR: NO MONITOREXIT " ) ;
= new DescriptionBlock ( "ERROR: no monitorexit " ) ;
prev . appendBlock ( msg ) ;
msg . moveJump ( jumps ) ;
}
@ -502,8 +509,9 @@ public class TransformExceptionHandlers {
if ( subRoutine ! = null ) {
if ( tryFlow . getSuccessors ( ) . contains ( subRoutine ) )
removeJSR ( tryFlow , catchBlock , subRoutine ) ;
tryFlow . mergeBlockNr ( subRoutine ) ;
removeJSR ( tryFlow , subRoutine ) ;
if ( subRoutine . predecessors . size ( ) = = 0 )
tryFlow . mergeBlockNr ( subRoutine ) ;
}
}
@ -526,20 +534,25 @@ public class TransformExceptionHandlers {
}
private boolean analyzeSynchronized ( FlowBlock tryFlow ,
StructuredBlock catchBlock ,
FlowBlock catchFlow ,
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 ) ;
if ( excStore ! = null )
catchBlock = catchBlock . getSubBlocks ( ) [ 1 ] ;
/* Check for the monitorexit instruction */
if ( ! ( catchBlock instanceof SequentialBlock
& & catchBlock . getSubBlocks ( ) [ 0 ]
instanceof InstructionBlock ) )
return false ;
Expression instr =
( ( InstructionBlock ) catchBlock . getSubBlocks ( ) [ 0 ] ) . getInstruction ( ) ;
if ( ! ( instr instanceof MonitorExitOperator
& & instr . getFreeOperandCount ( ) = = 0
& & ( ( ( MonitorExitOperator ) instr ) . getSubExpressions ( ) [ 0 ]
@ -547,9 +560,9 @@ public class TransformExceptionHandlers {
& & catchBlock . getSubBlocks ( ) [ 1 ] instanceof ThrowBlock ) )
return false ;
/* Check for the throw instruction */
Expression throwInstr =
( ( ThrowBlock ) catchBlock . getSubBlocks ( ) [ 1 ] ) . getInstruction ( ) ;
if ( excStore ! = null ) {
if ( ! ( throwInstr instanceof Operator
& & excStore . lvalueMatches ( ( Operator ) throwInstr ) ) )
@ -583,6 +596,12 @@ public class TransformExceptionHandlers {
* monitorexit local_x
* 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 .
* /
mergeTryCatch ( tryFlow , catchFlow ) ;
MonitorExitOperator monexit = ( MonitorExitOperator )
( ( InstructionBlock ) catchBlock . getSubBlocks ( ) [ 0 ] ) . instr ;
@ -597,7 +616,7 @@ public class TransformExceptionHandlers {
+ "," + tryFlow . getNextBlockNr ( ) + "," + endHandler + ")" ) ;
checkAndRemoveMonitorExit
( tryFlow , catchBlock , local , tryFlow . getNextBlockNr ( ) , endHandler ) ;
( tryFlow , local , tryFlow . getNextBlockNr ( ) , endHandler ) ;
SynchronizedBlock syncBlock = new SynchronizedBlock ( local ) ;
TryBlock tryBlock = ( TryBlock ) tryFlow . block ;
@ -609,8 +628,41 @@ public class TransformExceptionHandlers {
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 ,
StructuredBlock catchBlock , int end ) {
FlowBlock catchFlow , int end ) {
/ * Layout of a try - finally block :
*
@ -632,6 +684,7 @@ public class TransformExceptionHandlers {
* return_n
* /
StructuredBlock catchBlock = catchFlow . block ;
StoreInstruction excStore = getExceptionStore ( catchBlock ) ;
if ( excStore = = null )
return false ;
@ -643,9 +696,10 @@ public class TransformExceptionHandlers {
StructuredBlock finallyBlock = null ;
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 :
/ * In case the try block has no exit ( that means , it
* throws an exception or loops forever ) , the finallyBlock
* was already merged with the catchBlock . We have to
* check for this case separately :
*
* do {
* JSR
@ -682,7 +736,7 @@ public class TransformExceptionHandlers {
FlowBlock subRoutine ;
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
* we know that there is only one Block around the jsr .
* /
@ -690,269 +744,255 @@ 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 ;
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 ( ) ) ;
}
/ * 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
* /
finallyBlock = jsrBlock . innerBlock ;
subRoutine = finallyBlock . jump . destination ;
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 ) ;
/ * We are committed now and can start changing the try
* block .
* /
checkAndRemoveJSR ( tryFlow , subRoutine ,
tryFlow . getNextBlockNr ( ) , end ) ;
if ( subRoutine ! = null ) {
while ( subRoutine . analyze ( tryFlow . getNextBlockNr ( ) , end ) ) ;
/ * Now check if the subroutine is correct and has only the
* catchFlow as predecessor .
/ * Now analyze and transform the subroutine .
* /
if ( subRoutine . predecessors . size ( ) = = 1
& & transformSubRoutine ( subRoutine . block ) ) {
tryFlow . removeSuccessor ( jsrBlock . innerBlock . jump ) ;
tryFlow . mergeBlockNr ( subRoutine ) ;
tryFlow . mergeSuccessors ( subRoutine ) ;
subRoutine . block . replace ( catchBlock ) ;
tryFlow . updateInOutCatch ( subRoutine ) ;
while ( subRoutine . analyze ( tryFlow . getNextBlockNr ( ) , end ) ) ;
if ( subRoutine . predecessors . size ( ) = = 1 ) {
/ * catchFlow is synthetic , so we can safely remove it
* here .
* /
subRoutine . mergeBlockNr ( catchFlow ) ;
catchFlow = subRoutine ;
if ( ! transformSubRoutine ( subRoutine . block ) ) {
finallyBlock = subRoutine . block ;
DescriptionBlock msg = new DescriptionBlock
( "ERROR: Missing return address handling" ) ;
StructuredBlock subblock = subRoutine . block ;
msg . replace ( finallyBlock ) ;
msg . appendBlock ( finallyBlock ) ;
}
finallyBlock = subRoutine . block ;
}
}
/ * Now finish it .
* /
mergeFinallyBlock ( tryFlow , catchFlow , finallyBlock ) ;
return true ;
}
private boolean analyzeSpecialFinally ( FlowBlock tryFlow ,
StructuredBlock catchBlock ,
int end ) {
FlowBlock catchFlow , int end ) {
StructuredBlock finallyBlock = catchFlow . block ;
StructuredBlock firstInstr =
catch Block instanceof SequentialBlock
? catch Block. getSubBlocks ( ) [ 0 ] : catch Block;
finally Block instanceof SequentialBlock
? finally Block. getSubBlocks ( ) [ 0 ] : finally Block;
if ( ! ( firstInstr instanceof SpecialBlock
& & ( ( SpecialBlock ) firstInstr ) . type = = SpecialBlock . POP
& & ( ( SpecialBlock ) firstInstr ) . count = = 1 ) )
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
* similar .
* /
FlowBlock succ = null ;
/* remove the pop now */
if ( catchBlock instanceof SequentialBlock )
catchBlock = catchBlock . getSubBlocks ( ) [ 1 ] ;
/ * Make sure that resolveJump only works on the inside of the try
* /
tryFlow . lastModified = tryFlow . block . getSubBlocks ( ) [ 0 ] ;
if ( finallyBlock instanceof SequentialBlock )
finallyBlock = finallyBlock . getSubBlocks ( ) [ 1 ] ;
else {
catchBlock = new EmptyBlock ( ) ;
catch Block. moveJump ( firstInstr . jump ) ;
finally Block = new EmptyBlock ( ) ;
finally Block. moveJump ( firstInstr . jump ) ;
succ = firstInstr . jump . destination ;
/ * Handle the jumps in the tryFlow to finallyFlow .
* /
FlowBlock 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();
// if (trySuccs.size() > 1
// || (trySuccs.size() == 1
// && trySuccs.iterator().next() != succ))
// return false;
/* Complain about all other jumps in try block */
Set trySuccs = tryFlow . getSuccessors ( ) ;
for ( Iterator i = trySuccs . iterator ( ) ; i . hasNext ( ) ; ) {
for ( Jump jumps = tryFlow . getJumps ( ( FlowBlock ) i . next ( ) ) ;
jumps ! = null ; jumps = jumps . next ) {
DescriptionBlock msg =
new DescriptionBlock
( "ERROR: doesn't go through finally block!" ) ;
if ( jumps . prev instanceof ReturnBlock ) {
msg . replace ( jumps . prev ) ;
msg . appendBlock ( jumps . prev ) ;
} else {
jumps . prev . appendBlock ( msg ) ;
msg . moveJump ( jumps ) ;
}
}
}
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 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 ) ;
newBlock . setCatchBlock ( catchBlock ) ;
mergeFinallyBlock ( tryFlow , catchFlow , finallyBlock ) ;
/* Following code will work be put inside the finallyBlock */
tryFlow . lastModified = finallyBlock ;
return true ;
}
/ * *
* Analyzes all exception handlers to try / catch / finally or
* synchronized blocks .
* /
public void analyze ( ) {
void checkTryCatchOrder ( ) {
/ * Check if try / catch ranges are okay . The following succeeds
* for all classes generated by the sun java compiler , but hand
* optimized classes ( or generated by other compilers ) will fail .
* /
{
Handler last = null ;
for ( Iterator i = handlers . iterator ( ) ; i . hasNext ( ) ; ) {
Handler exc = ( Handler ) i . next ( ) ;
int start = exc . start . getBlockNr ( ) ;
int end = exc . end . getBlockNr ( ) ;
int handler = exc . handler . getBlockNr ( ) ;
if ( start > end | | handler < = end )
throw new InternalError
Handler last = null ;
for ( Iterator i = handlers . iterator ( ) ; i . hasNext ( ) ; ) {
Handler exc = ( Handler ) i . next ( ) ;
int start = exc . start . getBlockNr ( ) ;
int end = exc . end . getBlockNr ( ) ;
int handler = exc . handler . getBlockNr ( ) ;
if ( start > end | | handler < = end )
throw new InternalError
( "ExceptionHandler order failed: not "
+ start + " < " + end + " <= " + handler ) ;
if ( last ! = null
& & ( last . start . getBlockNr ( ) ! = start
| | last . end . getBlockNr ( ) ! = end ) ) {
/ * The last handler does catch another range .
* Due to the order :
* start < last . start . getBlockNr ( )
* | | end > last . end . getBlockNr ( )
* /
if ( end > = last . start . getBlockNr ( )
& & end < last . end . getBlockNr ( ) )
throw new InternalError
( "Exception handlers ranges are intersecting: ["
+ last . start . getBlockNr ( ) + ", "
+ last . end . getBlockNr ( ) + "] and ["
+ start + ", " + end + "]." ) ;
}
last = exc ;
if ( last ! = null
& & ( last . start . getBlockNr ( ) ! = start
| | last . end . getBlockNr ( ) ! = end ) ) {
/ * The last handler does catch another range .
* Due to the order :
* start < last . start . getBlockNr ( )
* | | end > last . end . getBlockNr ( )
* /
if ( end > = last . start . getBlockNr ( )
& & end < last . end . getBlockNr ( ) )
throw new InternalError
( "Exception handlers ranges are intersecting: ["
+ last . start . getBlockNr ( ) + ", "
+ last . end . getBlockNr ( ) + "] and ["
+ start + ", " + end + "]." ) ;
}
last = exc ;
}
}
{
Iterator i = handlers . iterator ( ) ;
Handler exc = null ;
Handler next = i . hasNext ( ) ? ( Handler ) i . next ( ) : null ;
while ( next ! = null ) {
Handler last = exc ;
exc = next ;
int startNr = exc . start . getBlockNr ( ) ;
int endNr = exc . end . getBlockNr ( ) ;
next = i . hasNext ( ) ? ( Handler ) i . next ( ) : null ;
int endHandler = Integer . MAX_VALUE ;
/ * If the next exception handler catches a bigger range
* it must surround the handler completely .
/ * *
* Analyzes all exception handlers to try / catch / finally or
* synchronized blocks .
* /
public void analyze ( ) {
checkTryCatchOrder ( ) ;
Iterator i = handlers . iterator ( ) ;
Handler exc = null ;
Handler next = i . hasNext ( ) ? ( Handler ) i . next ( ) : null ;
while ( next ! = null ) {
Handler last = exc ;
exc = next ;
next = i . hasNext ( ) ? ( Handler ) i . next ( ) : null ;
int startNr = exc . start . getBlockNr ( ) ;
int endNr = exc . end . getBlockNr ( ) ;
int endHandler = Integer . MAX_VALUE ;
/ * If the next exception handler catches a bigger range
* it must surround the handler completely .
* /
if ( next ! = null
& & next . end . getBlockNr ( ) > endNr )
endHandler = next . end . getBlockNr ( ) + 1 ;
FlowBlock tryFlow = exc . start ;
tryFlow . checkConsistent ( ) ;
if ( last = = null | | exc . type = = null
| | last . start . getBlockNr ( ) ! = startNr
| | last . end . getBlockNr ( ) ! = endNr ) {
/ * The last handler does catch another range .
* Create a new try block .
* /
if ( next ! = null
& & next . end . getBlockNr ( ) > endNr )
endHandler = next . end . getBlockNr ( ) + 1 ;
FlowBlock tryFlow = exc . start ;
tryFlow . checkConsistent ( ) ;
if ( last = = null | | exc . type = = null
| | last . start . getBlockNr ( ) ! = startNr
| | last . end . getBlockNr ( ) ! = endNr ) {
/ * The last handler does catch another range .
* Create a new try block .
* /
if ( ( GlobalOptions . debuggingFlags
& GlobalOptions . DEBUG_ANALYZE ) ! = 0 )
GlobalOptions . err . println
( "analyzeTry(" + startNr + ", " + endNr + ")" ) ;
while ( true ) {
while ( tryFlow . analyze ( startNr ,
endNr + 1 ) ) ;
int nextNr = tryFlow . getNextBlockNr ( ) ;
if ( nextNr > endNr )
break ;
tryFlow = flowBlocks [ nextNr ] ;
}
if ( tryFlow . getBlockNr ( ) ! = startNr )
GlobalOptions . err . println
( "Warning: Can't completely analyze try." ) ;
TryBlock tryBlock = new TryBlock ( tryFlow ) ;
} else if ( ! ( tryFlow . block instanceof TryBlock ) )
throw new InternalError ( "no TryBlock" ) ;
FlowBlock catchFlow = exc . handler ;
boolean isMultiUsed = catchFlow . predecessors . size ( ) ! = 0 ;
if ( ! isMultiUsed & & next ! = null ) {
for ( Iterator j = handlers . tailSet ( next ) . iterator ( ) ;
j . hasNext ( ) ; ) {
Handler h = ( Handler ) j . next ( ) ;
if ( h . handler = = catchFlow ) {
isMultiUsed = true ;
break ;
}
}
if ( ( GlobalOptions . debuggingFlags
& GlobalOptions . DEBUG_ANALYZE ) ! = 0 )
GlobalOptions . err . println
( "analyzeTry(" + startNr + ", " + endNr + ")" ) ;
while ( true ) {
while ( tryFlow . analyze ( startNr , endNr + 1 ) ) ;
int nextNr = tryFlow . getNextBlockNr ( ) ;
if ( nextNr > endNr )
break ;
tryFlow = flowBlocks [ nextNr ] ;
}
if ( isMultiUsed ) {
/ * If this exception is used in other exception handlers ,
* create a new flow block , that jumps to the handler .
* This will be our new exception handler .
* /
FlowBlock newFlow = new FlowBlock
( catchFlow . method , catchFlow . getBlockNr ( ) ,
catchFlow . prevByCodeOrder ) ;
newFlow . setSuccessors ( new FlowBlock [ ] { catchFlow } ) ;
newFlow . nextByCodeOrder = catchFlow ;
catchFlow . prevByCodeOrder = newFlow ;
catchFlow = newFlow ;
} else {
if ( ( GlobalOptions . debuggingFlags
& GlobalOptions . DEBUG_ANALYZE ) ! = 0 )
GlobalOptions . err . println
( "analyzeCatch("
+ catchFlow . getBlockNr ( ) + ", " + endHandler + ")" ) ;
while ( catchFlow . analyze ( catchFlow . getBlockNr ( ) ,
endHandler ) ) ;
if ( tryFlow . getBlockNr ( ) ! = startNr ) {
GlobalOptions . err . println
( "Warning: Can't completely analyze try." ) ;
}
/* 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 . block ) ;
else if ( ! analyzeSynchronized ( tryFlow , catchFlow . block ,
endHandler )
& & ! analyzeFinally ( tryFlow , catchFlow . block ,
endHandler )
& & ! analyzeSpecialFinally ( tryFlow , catchFlow . block ,
endHandler ) )
analyzeCatchBlock ( Type . tObject , tryFlow , catchFlow . block ) ;
tryFlow . checkConsistent ( ) ;
TryBlock tryBlock = new TryBlock ( tryFlow ) ;
} else if ( ! ( tryFlow . block instanceof TryBlock ) )
throw new InternalError ( "no TryBlock" ) ;
FlowBlock catchFlow = exc . handler ;
boolean isMultiUsed = catchFlow . predecessors . size ( ) ! = 0 ;
if ( ! isMultiUsed & & next ! = null ) {
for ( Iterator j = handlers . tailSet ( next ) . iterator ( ) ;
j . hasNext ( ) ; ) {
Handler h = ( Handler ) j . next ( ) ;
if ( h . handler = = catchFlow ) {
isMultiUsed = true ;
break ;
}
}
}
if ( isMultiUsed ) {
/ * If this exception is used in other exception handlers ,
* create a new flow block , that jumps to the handler .
* This will be our new exception handler .
* /
FlowBlock newFlow = new FlowBlock
( catchFlow . method , catchFlow . getBlockNr ( ) ,
catchFlow . prevByCodeOrder ) ;
newFlow . setSuccessors ( new FlowBlock [ ] { catchFlow } ) ;
newFlow . nextByCodeOrder = catchFlow ;
catchFlow . prevByCodeOrder = newFlow ;
catchFlow = newFlow ;
} else {
if ( ( GlobalOptions . debuggingFlags
& GlobalOptions . DEBUG_ANALYZE ) ! = 0 )
GlobalOptions . err . println
( "analyzeTryCatch(" + tryFlow . getBlockNr ( ) + ", "
+ tryFlow . getNextBlockNr ( ) + ") done." ) ;
( "analyzeCatch("
+ catchFlow . getBlockNr ( ) + ", " + endHandler + ")" ) ;
while ( catchFlow . analyze ( catchFlow . getBlockNr ( ) ,
endHandler ) ) ;
}
if ( exc . type ! = null )
analyzeCatchBlock ( exc . type , tryFlow , catchFlow ) ;
else if ( ! analyzeSynchronized ( tryFlow , catchFlow , endHandler )
& & ! analyzeFinally ( tryFlow , catchFlow , endHandler )
& & ! analyzeSpecialFinally ( tryFlow , catchFlow ,
endHandler ) )
/ * As last resort make a catch ( Object ) block . This doesn ' t
* compile , but at least it gives a hint what the code
* does .
* /
analyzeCatchBlock ( Type . tObject , tryFlow , catchFlow ) ;
tryFlow . checkConsistent ( ) ;
if ( ( GlobalOptions . debuggingFlags
& GlobalOptions . DEBUG_ANALYZE ) ! = 0 )
GlobalOptions . err . println
( "analyzeTryCatch(" + tryFlow . getBlockNr ( ) + ", "
+ tryFlow . getNextBlockNr ( ) + ") done." ) ;
}
}
}