@ -115,16 +115,11 @@ public class TransformExceptionHandlers {
* | . . .
* | . . .
* ` - catch block
* ` - catch block
* /
* /
static void analyzeCatchBlock ( Type type ,
static void analyzeCatchBlock ( Type type , FlowBlock tryFlow ,
FlowBlock tryFlow , FlowBlock catchFlow ) {
StructuredBlock catchBlock ) {
StructuredBlock catchBlock = catchFlow . block ;
CatchBlock newBlock = new CatchBlock ( type ) ;
CatchBlock newBlock = new CatchBlock ( type ) ;
( ( TryBlock ) tryFlow . block ) . addCatchBlock ( newBlock ) ;
( ( TryBlock ) tryFlow . block ) . addCatchBlock ( newBlock ) ;
newBlock . setCatchBlock ( catchFlow . block ) ;
newBlock . setCatchBlock ( catchBlock ) ;
tryFlow . mergeSuccessors ( catchFlow ) ;
tryFlow . mergeBlockNr ( catchFlow ) ;
}
}
/* And now the complicated parts. */
/* And now the complicated parts. */
@ -134,44 +129,84 @@ public class TransformExceptionHandlers {
* local assignment matches the final ret and then returns .
* local assignment matches the final ret and then returns .
* /
* /
boolean transformSubRoutine ( StructuredBlock subRoutine ) {
boolean transformSubRoutine ( StructuredBlock subRoutine ) {
if ( ! ( subRoutine instanceof SequentialBlock )
if ( ! ( subRoutine instanceof SequentialBlock ) )
| | ! ( subRoutine . getSubBlocks ( ) [ 0 ] instanceof InstructionBlock ) )
return false ;
return false ;
SequentialBlock sequBlock = ( SequentialBlock ) subRoutine ;
SequentialBlock sequBlock = ( SequentialBlock ) subRoutine ;
InstructionBlock instr = ( InstructionBlock ) sequBlock . subBlocks [ 0 ] ;
StructuredBlock firstBlock = sequBlock . getSubBlocks ( ) [ 0 ] ;
if ( ! ( instr . getInstruction ( ) instanceof StoreInstruction )
LocalInfo local = null ;
| | ! ( ( ( StoreInstruction ) instr . getInstruction ( ) ) . getLValue ( )
if ( firstBlock instanceof SpecialBlock ) {
instanceof LocalStoreOperator ) )
SpecialBlock popBlock
= ( SpecialBlock ) firstBlock ;
if ( popBlock . type ! = SpecialBlock . POP
| | popBlock . count ! = 1 )
return false ;
return false ;
} else if ( firstBlock instanceof InstructionBlock ) {
Expression expr
= ( ( InstructionBlock ) firstBlock ) . getInstruction ( ) ;
if ( expr instanceof StoreInstruction
& & ( ( StoreInstruction )
expr ) . getLValue ( ) instanceof LocalStoreOperator ) {
LocalStoreOperator store = ( LocalStoreOperator )
LocalStoreOperator store = ( LocalStoreOperator )
( ( StoreInstruction ) instr . getInstruction ( ) ) . getLValue ( ) ;
( ( StoreInstruction ) expr ) . getLValue ( ) ;
local = store . getLocalInfo ( ) ;
expr = ( ( StoreInstruction ) expr ) . getSubExpressions ( ) [ 1 ] ;
}
if ( ! ( expr instanceof NopOperator ) )
return false ;
} else
return false ;
while ( sequBlock . subBlocks [ 1 ] instanceof SequentialBlock )
/ * We are now committed . Remove the first Statement which
sequBlock = ( SequentialBlock ) sequBlock . subBlocks [ 1 ] ;
* stores / removes the return address .
* /
firstBlock . removeBlock ( ) ;
/ * XXX - Check that the local isn ' t used for any other purposes
/ * XXX - Replace any RET with a jump to end of this flow block .
* 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 .
* 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 .
* /
* /
if ( sequBlock . subBlocks [ 1 ] . jump ! = null
while ( sequBlock . subBlocks [ 1 ] instanceof SequentialBlock )
& & sequBlock . subBlocks [ 1 ] . jump . destination
sequBlock = ( SequentialBlock ) sequBlock . subBlocks [ 1 ] ;
= = FlowBlock . END_OF_METHOD ) {
instr . removeBlock ( ) ;
return true ;
}
if ( ! ( sequBlock . subBlocks [ 1 ] instanceof RetBlock )
| | ! ( ( ( RetBlock ) sequBlock . subBlocks [ 1 ] )
. local . equals ( store . getLocalInfo ( ) ) ) )
return false ;
instr . removeBlock ( ) ;
if ( sequBlock . subBlocks [ 1 ] instanceof RetBlock
& & ( ( ( RetBlock ) sequBlock . subBlocks [ 1 ] ) . local . equals ( local ) ) ) {
sequBlock . subBlocks [ 1 ] . removeBlock ( ) ;
sequBlock . subBlocks [ 1 ] . removeBlock ( ) ;
}
return true ;
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
* Remove the JSR ' s jumping to the specified subRoutine . It
* is checked if the next block is a leaving instruction , and
* 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 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 , FlowBlock subRoutine ) {
private void removeJSR ( FlowBlock tryFlow , StructuredBlock catchBlock ,
for ( Jump jumps = tryFlow . removeJumps ( subRoutine ) ;
FlowBlock subRoutine ) {
jumps ! = null ; jumps = jumps . next ) {
Jump nextJump ;
for ( Jump jumps = tryFlow . getJumps ( subRoutine ) ;
jumps ! = null ; jumps = nextJump ) {
StructuredBlock prev = jumps . prev ;
StructuredBlock prev = jumps . prev ;
prev . removeJump ( ) ;
nextJump = jumps . next ;
if ( prev instanceof EmptyBlock
if ( prev instanceof EmptyBlock
& & prev . outer instanceof JsrBlock ) {
& & prev . outer instanceof JsrBlock ) {
if ( prev . outer = = catchBlock ) {
/* This is the mandatory jsr in the catch block */
continue ;
}
if ( prev . outer . getNextFlowBlock ( ) ! = null ) {
if ( prev . outer . getNextFlowBlock ( ) ! = null ) {
/* The jsr is directly before a jump, okay. */
/* The jsr is directly before a jump, okay. */
tryFlow . removeSuccessor ( jumps ) ;
prev . removeJump ( ) ;
prev . outer . removeBlock ( ) ;
prev . outer . removeBlock ( ) ;
continue ;
continue ;
}
}
@ -202,6 +245,8 @@ public class TransformExceptionHandlers {
& & seq . subBlocks [ 1 ] . getSubBlocks ( ) [ 0 ]
& & seq . subBlocks [ 1 ] . getSubBlocks ( ) [ 0 ]
instanceof JsrBlock ) ) {
instanceof JsrBlock ) ) {
/* The jsr is followed by a jsr, okay. */
/* The jsr is followed by a jsr, okay. */
tryFlow . removeSuccessor ( jumps ) ;
prev . removeJump ( ) ;
prev . outer . removeBlock ( ) ;
prev . outer . removeBlock ( ) ;
continue ;
continue ;
}
}
@ -209,33 +254,12 @@ public class TransformExceptionHandlers {
& & ! ( seq . subBlocks [ 1 ] instanceof ThrowBlock ) ) {
& & ! ( seq . subBlocks [ 1 ] instanceof ThrowBlock ) ) {
/* The jsr is followed by a return, okay. */
/* The jsr is followed by a return, okay. */
tryFlow . removeSuccessor ( jumps ) ;
prev . removeJump ( ) ;
ReturnBlock ret = ( ReturnBlock ) seq . subBlocks [ 1 ] ;
ReturnBlock ret = ( ReturnBlock ) seq . subBlocks [ 1 ] ;
prev . outer . removeBlock ( ) ;
prev . outer . removeBlock ( ) ;
if ( ret . outer ! = null
removeReturnLocal ( ret ) ;
& & 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 */
}
}
continue ;
continue ;
}
}
}
}
@ -245,11 +269,15 @@ public class TransformExceptionHandlers {
* /
* /
DescriptionBlock msg
DescriptionBlock msg
= new DescriptionBlock ( "ERROR: GOTO FINALLY BLOCK!" ) ;
= new DescriptionBlock ( "ERROR: GOTO FINALLY BLOCK!" ) ;
tryFlow . removeSuccessor ( jumps ) ;
prev . removeJump ( ) ;
prev . appendBlock ( msg ) ;
prev . appendBlock ( msg ) ;
}
}
}
}
public void checkAndRemoveJSR ( FlowBlock tryFlow , FlowBlock subRoutine ,
public void checkAndRemoveJSR ( FlowBlock tryFlow ,
StructuredBlock catchBlock ,
FlowBlock subRoutine ,
int startOutExit , int endOutExit ) {
int startOutExit , int endOutExit ) {
boolean foundSub = false ;
boolean foundSub = false ;
Iterator iter = tryFlow . getSuccessors ( ) . iterator ( ) ;
Iterator iter = tryFlow . getSuccessors ( ) . iterator ( ) ;
@ -336,7 +364,7 @@ public class TransformExceptionHandlers {
}
}
}
}
if ( foundSub )
if ( foundSub )
removeJSR ( tryFlow , subRoutine ) ;
removeJSR ( tryFlow , catchBlock , subRoutine ) ;
}
}
static boolean isMonitorExit ( Expression instr , LocalInfo local ) {
static boolean isMonitorExit ( Expression instr , LocalInfo local ) {
@ -366,9 +394,10 @@ public class TransformExceptionHandlers {
return false ;
return false ;
}
}
public void checkAndRemoveMonitorExit ( FlowBlock tryFlow , LocalInfo local ,
public void checkAndRemoveMonitorExit ( FlowBlock tryFlow ,
int startOutExit , int endOutExit ,
StructuredBlock catchBlock ,
int startMonExit , int endMonExit ) {
LocalInfo local ,
int start , int end ) {
FlowBlock subRoutine = null ;
FlowBlock subRoutine = null ;
Iterator succs = tryFlow . getSuccessors ( ) . iterator ( ) ;
Iterator succs = tryFlow . getSuccessors ( ) . iterator ( ) ;
dest_loop :
dest_loop :
@ -415,11 +444,15 @@ public class TransformExceptionHandlers {
if ( pred instanceof InstructionBlock ) {
if ( pred instanceof InstructionBlock ) {
Expression instr =
Expression instr =
( ( InstructionBlock ) pred ) . getInstruction ( ) ;
( ( InstructionBlock ) pred ) . getInstruction ( ) ;
if ( isMonitorExit ( instr , local ) )
if ( isMonitorExit ( instr , local ) ) {
pred . removeBlock ( ) ;
if ( prev instanceof ReturnBlock )
removeReturnLocal ( ( ReturnBlock ) prev ) ;
continue ;
continue ;
}
}
}
}
}
}
}
if ( prev instanceof InstructionBlock
if ( prev instanceof InstructionBlock
& & isMonitorExit ( ( ( InstructionBlock ) prev ) . instr , local ) ) {
& & isMonitorExit ( ( ( InstructionBlock ) prev ) . instr , local ) ) {
@ -442,9 +475,9 @@ public class TransformExceptionHandlers {
* /
* /
if ( prev instanceof JsrBlock ) {
if ( prev instanceof JsrBlock ) {
if ( subRoutine = = null
if ( subRoutine = = null
& & successor . getBlockNr ( ) > = startMonExit
& & successor . getBlockNr ( ) > = start
& & successor . getNextBlockNr ( ) < = endMonExit ) {
& & successor . getNextBlockNr ( ) < = end ) {
successor . analyze ( startMonExit , endMonExit ) ;
successor . analyze ( start , end ) ;
if ( isMonitorExitSubRoutine ( successor , local ) )
if ( isMonitorExitSubRoutine ( successor , local ) )
subRoutine = successor ;
subRoutine = successor ;
@ -461,9 +494,9 @@ public class TransformExceptionHandlers {
* block .
* block .
* /
* /
if ( successor . predecessors . size ( ) = = 1
if ( successor . predecessors . size ( ) = = 1
& & successor . getBlockNr ( ) > = startOutExit
& & successor . getBlockNr ( ) > = start
& & successor . getNextBlockNr ( ) < = endOutExit ) {
& & successor . getNextBlockNr ( ) < = end ) {
successor . analyze ( startOutExit , endOutExit ) ;
successor . analyze ( start , end ) ;
StructuredBlock sb = successor . block ;
StructuredBlock sb = successor . block ;
if ( sb instanceof SequentialBlock )
if ( sb instanceof SequentialBlock )
@ -473,9 +506,9 @@ public class TransformExceptionHandlers {
StructuredBlock jsrInner = sb . getSubBlocks ( ) [ 0 ] ;
StructuredBlock jsrInner = sb . getSubBlocks ( ) [ 0 ] ;
FlowBlock dest = jsrInner . jump . destination ;
FlowBlock dest = jsrInner . jump . destination ;
if ( subRoutine = = null
if ( subRoutine = = null
& & dest . getBlockNr ( ) > = startMonExit
& & dest . getBlockNr ( ) > = start
& & dest . getNextBlockNr ( ) < = endMonExit ) {
& & dest . getNextBlockNr ( ) < = end ) {
dest . analyze ( startMonExit , endMonExit ) ;
dest . analyze ( start , end ) ;
if ( isMonitorExitSubRoutine ( dest , local ) )
if ( isMonitorExitSubRoutine ( dest , local ) )
subRoutine = dest ;
subRoutine = dest ;
}
}
@ -506,30 +539,62 @@ public class TransformExceptionHandlers {
}
}
if ( subRoutine ! = null ) {
if ( subRoutine ! = null ) {
removeJSR ( tryFlow , subRoutine ) ;
removeJSR ( tryFlow , catchBlock , subRoutine ) ;
tryFlow . mergeBlockNr ( 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 ,
private boolean analyzeSynchronized ( FlowBlock tryFlow ,
FlowBlock catchFlow ,
StructuredBlock catchBlock ,
int endHandler ) {
int endHandler ) {
if ( ! ( catchFlow . block instanceof SequentialBlock
StoreInstruction excStore = getExceptionStore ( catchBlock ) ;
& & catchFlow . block . getSubBlocks ( ) [ 0 ]
if ( excStore ! = null )
catchBlock = catchBlock . getSubBlocks ( ) [ 1 ] ;
if ( ! ( catchBlock instanceof SequentialBlock
& & catchBlock . getSubBlocks ( ) [ 0 ]
instanceof InstructionBlock ) )
instanceof InstructionBlock ) )
return false ;
return false ;
SequentialBlock catchBlock = ( SequentialBlock ) catchFlow . block ;
Expression instr =
Expression instr =
( ( InstructionBlock ) catchBlock . subBlocks [ 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 ]
instanceof LocalLoadOperator )
instanceof LocalLoadOperator )
& & catchBlock . subBlocks [ 1 ] instanceof ThrowBlock
& & catchBlock . getSubBlocks ( ) [ 1 ] instanceof ThrowBlock ) )
& & ( ( ( ThrowBlock ) catchBlock . subBlocks [ 1 ] ) . instr
return false ;
instanceof NopOperator ) ) {
Expression throwInstr =
( ( ThrowBlock ) catchBlock . getSubBlocks ( ) [ 1 ] ) . getInstruction ( ) ;
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 :
/ * This is a synchronized block :
*
*
@ -543,10 +608,13 @@ public class TransformExceptionHandlers {
* | - monitorexit local_x |
* | - monitorexit local_x |
* ` jump after this block ( without jsr monexit ) |
* ` jump after this block ( without jsr monexit ) |
* |
* |
* catchFlow : |
* catchBlock : |
* local_n = stack |
* local_n = stack |
* monitorexit local_x |
* monitorexit local_x |
* throw local_n |
* throw local_n |
* [ OR ALTERNATIVELY : ] |
* monitorexit local_x |
* throw stack |
* optional subroutine : < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '
* optional subroutine : < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '
* astore_n
* astore_n
* monitorexit local_x
* monitorexit local_x
@ -554,7 +622,7 @@ public class TransformExceptionHandlers {
* /
* /
MonitorExitOperator monexit = ( MonitorExitOperator )
MonitorExitOperator monexit = ( MonitorExitOperator )
( ( InstructionBlock ) catchBlock . subBlocks [ 0 ] ) . instr ;
( ( InstructionBlock ) catchBlock . getSubBlocks ( ) [ 0 ] ) . instr ;
LocalInfo local =
LocalInfo local =
( ( LocalLoadOperator ) monexit . getSubExpressions ( ) [ 0 ] )
( ( LocalLoadOperator ) monexit . getSubExpressions ( ) [ 0 ] )
. getLocalInfo ( ) ;
. getLocalInfo ( ) ;
@ -563,15 +631,11 @@ public class TransformExceptionHandlers {
& GlobalOptions . DEBUG_ANALYZE ) ! = 0 )
& GlobalOptions . DEBUG_ANALYZE ) ! = 0 )
GlobalOptions . err . println
GlobalOptions . err . println
( "analyzeSynchronized(" + tryFlow . getBlockNr ( )
( "analyzeSynchronized(" + tryFlow . getBlockNr ( )
+ "," + tryFlow . getNextBlockNr ( ) + "," + catchFlow . getBlockNr ( )
+ "," + tryFlow . getNextBlockNr ( ) + "," + endHandler + ")" ) ;
+ "," + catchFlow . getNextBlockNr ( ) + "," + endHandler + ")" ) ;
checkAndRemoveMonitorExit
checkAndRemoveMonitorExit
( tryFlow , local ,
( tryFlow , catchBlock , local , tryFlow . getNextBlockNr ( ) , endHandler ) ;
tryFlow . getNextBlockNr ( ) , catchFlow . getBlockNr ( ) ,
catchFlow . getNextBlockNr ( ) , endHandler ) ;
tryFlow . mergeBlockNr ( catchFlow ) ;
SynchronizedBlock syncBlock = new SynchronizedBlock ( local ) ;
SynchronizedBlock syncBlock = new SynchronizedBlock ( local ) ;
TryBlock tryBlock = ( TryBlock ) tryFlow . block ;
TryBlock tryBlock = ( TryBlock ) tryFlow . block ;
syncBlock . replace ( tryBlock ) ;
syncBlock . replace ( tryBlock ) ;
@ -581,11 +645,9 @@ public class TransformExceptionHandlers {
tryFlow . lastModified = syncBlock ;
tryFlow . lastModified = syncBlock ;
return true ;
return true ;
}
}
return false ;
}
private boolean analyzeFinally ( FlowBlock tryFlow , FlowBlock catchFlow ,
private boolean analyzeFinally ( FlowBlock tryFlow ,
int end ) {
StructuredBlock catchBlock , int end ) {
/ * Layout of a try - finally block :
/ * Layout of a try - finally block :
*
*
@ -597,7 +659,7 @@ public class TransformExceptionHandlers {
* | jsr finally - - - - - - - - - - - - - - - - - ,
* | jsr finally - - - - - - - - - - - - - - - - - ,
* ` - jump after finally |
* ` - jump after finally |
* |
* |
* catchFlow : ( already checked ) |
* catchBlock : |
* local_n = stack v
* local_n = stack v
* jsr finally - - - - - - - - - - - - - - - - > |
* jsr finally - - - - - - - - - - - - - - - - > |
* throw local_n ; |
* throw local_n ; |
@ -607,20 +669,17 @@ public class TransformExceptionHandlers {
* return_n
* return_n
* /
* /
if ( ! ( catchFlow . block instanceof SequentialBlock )
StoreInstruction excStore = getExceptionStore ( catchBlock ) ;
| | ! ( catchFlow . block . getSubBlocks ( ) [ 0 ]
if ( excStore = = null )
instanceof InstructionBlock )
return false ;
| | ! ( catchFlow . block . getSubBlocks ( ) [ 1 ]
instanceof SequentialBlock ) )
catchBlock = catchBlock . getSubBlocks ( ) [ 1 ] ;
if ( ! ( catchBlock instanceof SequentialBlock ) )
return false ;
return false ;
StructuredBlock finallyBlock = null ;
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
/ * In case the try block has no exit ( that means , it throws
* an exception ) , the finallyBlock was already merged with
* an exception ) , the finallyBlock was already merged with
* the catchBlock . We have to check for this case separately :
* the catchBlock . We have to check for this case separately :
@ -630,20 +689,21 @@ public class TransformExceptionHandlers {
* break ;
* break ;
* throw local_x
* throw local_x
* } while ( false ) ;
* } 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
if ( doWhileFalse . type = = LoopBlock . DOWHILE
& & doWhileFalse . cond = = LoopBlock . FALSE
& & doWhileFalse . cond = = LoopBlock . FALSE
& & doWhileFalse . bodyBlock instanceof SequentialBlock ) {
& & doWhileFalse . bodyBlock instanceof SequentialBlock ) {
finallyBlock = catchBlock . subBlocks [ 1 ] ;
if ( transformSubRoutine ( catchBlock . getSubBlocks ( ) [ 1 ] ) ) {
finallyBlock = catchBlock . getSubBlocks ( ) [ 1 ] ;
catchBlock = ( SequentialBlock ) doWhileFalse . bodyBlock ;
catchBlock = ( SequentialBlock ) doWhileFalse . bodyBlock ;
}
}
}
}
}
if ( ! ( catchBlock instanceof SequentialBlock
if ( ! ( catchBlock instanceof SequentialBlock
& & catchBlock . getSubBlocks ( ) [ 0 ] instanceof JsrBlock
& & catchBlock . getSubBlocks ( ) [ 0 ] instanceof JsrBlock
& & instr instanceof StoreInstruction
& & catchBlock . getSubBlocks ( ) [ 1 ] instanceof ThrowBlock ) )
& & catchBlock . getSubBlocks ( ) [ 1 ] instanceof ThrowBlock ) )
return false ;
return false ;
@ -652,21 +712,12 @@ public class TransformExceptionHandlers {
ThrowBlock throwBlock = ( ThrowBlock ) catchBlock . getSubBlocks ( ) [ 1 ] ;
ThrowBlock throwBlock = ( ThrowBlock ) catchBlock . getSubBlocks ( ) [ 1 ] ;
if ( ! ( throwBlock . instr instanceof LocalLoadOperator )
if ( ! ( throwBlock . getInstruction ( ) instanceof Operator
| | ! ( ( ( StoreInstruction ) instr ) . lvalueMatches
& & excStore . lvalueMatches ( ( Operator )
( ( LocalLoadOperator ) throwBlock . instr ) ) )
throwBlock . getInstruction ( ) ) ) )
return false ;
return false ;
/ * Wow that was complicated : - )
FlowBlock subRoutine ;
* 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 ) {
if ( finallyBlock ! = null ) {
/ * Check if the jsr breaks ( see two comments above ) . We don ' t
/ * Check if the jsr breaks ( see two comments 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
@ -676,55 +727,34 @@ public class TransformExceptionHandlers {
return false ;
return false ;
/ * Check if the try block has no exit
/ * 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 )
// if (tryFlow.getSuccessors().size() > 0)
return false ;
// return false;
/ * Replace the catchBlock with the finallyBlock .
* /
finallyBlock . replace ( catchFlow . block ) ;
transformSubRoutine ( finallyBlock ) ;
tryFlow . updateInOutCatch ( catchFlow ) ;
tryFlow . mergeBlockNr ( catchFlow ) ;
finallyBlock = catchFlow . block ;
tryFlow . mergeSuccessors ( catchFlow ) ;
catchBlock = finallyBlock ;
subRoutine = null ;
} else {
} else {
FlowBlock subRoutine = jsrBlock . innerBlock . jump . destination ;
if ( ! ( jsrBlock . innerBlock instanceof EmptyBlock ) )
checkAndRemoveJSR ( tryFlow , subRoutine ,
return false ;
tryFlow . getNextBlockNr ( ) , catchFlow . getBlockNr ( ) ) ;
catchBlock = jsrBlock ;
subRoutine = jsrBlock . innerBlock . jump . destination ;
while ( subRoutine . analyze ( catchFlow . getNextBlockNr ( ) , end ) ) ;
checkAndRemoveJSR ( tryFlow , catchBlock , subRoutine ,
tryFlow . getNextBlockNr ( ) ,
/ * Now check if the subroutine is correct and has only the
subRoutine . getBlockNr ( ) ) ;
* 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
/ * 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
* /
* /
catchFlow . removeSuccessor ( jsrBlock . innerBlock . jump ) ;
jsrBlock . innerBlock . removeJump ( ) ;
tryFlow . updateInOutCatch ( subRoutine ) ;
tryFlow . mergeBlockNr ( subRoutine ) ;
tryFlow . mergeSuccessors ( subRoutine ) ;
finallyBlock = subRoutine . block ;
} else {
finallyBlock = jsrBlock ;
finallyBlock . replace ( catchFlow . block ) ;
transformSubRoutine ( finallyBlock ) ;
tryFlow . updateInOutCatch ( catchFlow ) ;
tryFlow . mergeBlockNr ( catchFlow ) ;
finallyBlock = catchFlow . block ;
tryFlow . mergeSuccessors ( catchFlow ) ;
}
}
TryBlock tryBlock = ( TryBlock ) tryFlow . block ;
TryBlock tryBlock = ( TryBlock ) tryFlow . block ;
if ( tryBlock . getSubBlocks ( ) [ 0 ] instanceof TryBlock ) {
if ( tryBlock . getSubBlocks ( ) [ 0 ] instanceof TryBlock ) {
@ -737,50 +767,69 @@ public class TransformExceptionHandlers {
tryFlow . block = tryBlock ;
tryFlow . block = tryBlock ;
}
}
FinallyBlock newBlock = new FinallyBlock ( ) ;
FinallyBlock newBlock = new FinallyBlock ( ) ;
newBlock . setCatchBlock ( finally Block) ;
newBlock . setCatchBlock ( catch Block) ;
tryBlock . addCatchBlock ( newBlock ) ;
tryBlock . addCatchBlock ( newBlock ) ;
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 ) ) {
tryFlow . removeSuccessor ( jsrBlock . innerBlock . jump ) ;
tryFlow . mergeBlockNr ( subRoutine ) ;
tryFlow . mergeSuccessors ( subRoutine ) ;
subRoutine . block . replace ( catchBlock ) ;
tryFlow . updateInOutCatch ( subRoutine ) ;
}
}
return true ;
return true ;
}
}
private boolean analyzeSpecialFinally ( FlowBlock tryFlow ,
private boolean analyzeSpecialFinally ( FlowBlock tryFlow ,
FlowBlock catchFlow , int end ) {
StructuredBlock catchBlock ,
int end ) {
StructuredBlock firstInstr =
StructuredBlock firstInstr =
catchFlow . block instanceof SequentialBlock
catchB lock instanceof SequentialBlock
? catchFlow . block . getSubBlocks ( ) [ 0 ] : catchFlow . block ;
? catchB lock . getSubBlocks ( ) [ 0 ] : catchB lock ;
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 ;
/ * This is a special try / finally - block , where
/ * This may be 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 ;
FlowBlock succ = ( firstInstr . jump ! = null ) ?
/* remove the pop now */
firstInstr . jump . destination : null ;
if ( catchBlock instanceof SequentialBlock )
boolean hasExit = false ;
catchBlock = catchBlock . getSubBlocks ( ) [ 1 ] ;
Iterator iter = tryFlow . getSuccessors ( ) . iterator ( ) ;
else {
while ( iter . hasNext ( ) ) {
catchBlock = new EmptyBlock ( ) ;
FlowBlock dest = ( FlowBlock ) iter . next ( ) ;
catchBlock . moveJump ( firstInstr . jump ) ;
if ( dest = = succ )
continue ;
succ = firstInstr . jump . destination ;
/* There is another exit in the try block, bad */
return false ;
}
}
/* remove the pop now */
// Set trySuccs = tryFlow.getSuccessors();
EmptyBlock eb = new EmptyBlock ( ) ;
// if (trySuccs.size() > 1
eb . moveJump ( firstInstr . jump ) ;
// || (trySuccs.size() == 1
eb . replace ( firstInstr ) ;
// && trySuccs.iterator().next() != succ))
if ( catchFlow . lastModified = = firstInstr )
// return false;
catchFlow . lastModified = eb ;
if ( succ ! = null ) {
if ( succ ! = null ) {
Jump jumps = tryFlow . removeJumps ( succ ) ;
/ * Handle the jumps in the tryFlow .
/ * Handle the jumps in the tryFlow .
* /
* /
Jump jumps = tryFlow . removeJumps ( succ ) ;
jumps = tryFlow . resolveSomeJumps ( jumps , succ ) ;
jumps = tryFlow . resolveSomeJumps ( jumps , succ ) ;
tryFlow . resolveRemaining ( jumps ) ;
tryFlow . resolveRemaining ( jumps ) ;
}
}
@ -796,25 +845,9 @@ public class TransformExceptionHandlers {
}
}
FinallyBlock newBlock = new FinallyBlock ( ) ;
FinallyBlock newBlock = new FinallyBlock ( ) ;
tryBlock . addCatchBlock ( newBlock ) ;
tryBlock . addCatchBlock ( newBlock ) ;
/* try block has no successors */
newBlock . setCatchBlock ( catchBlock ) ;
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 true ;
}
}
return false ;
}
/ * *
/ * *
* Analyzes all exception handlers to try / catch / finally or
* Analyzes all exception handlers to try / catch / finally or
@ -937,16 +970,21 @@ public class TransformExceptionHandlers {
endHandler ) ) ;
endHandler ) ) ;
}
}
/* Merge the try-block with the catch-block now */
tryFlow . updateInOutCatch ( catchFlow ) ;
tryFlow . updateInOutCatch ( catchFlow ) ;
tryFlow . mergeSuccessors ( catchFlow ) ;
tryFlow . mergeBlockNr ( catchFlow ) ;
if ( exc . type ! = null )
if ( exc . type ! = null )
analyzeCatchBlock ( exc . type , tryFlow , catchFlow ) ;
analyzeCatchBlock ( exc . type , tryFlow , catchFlow . block ) ;
else if ( ! analyzeSynchronized ( tryFlow , catchFlow , endHandler )
else if ( ! analyzeSynchronized ( tryFlow , catchFlow . block ,
& & ! analyzeFinally ( tryFlow , catchFlow , endHandler )
endHandler )
& & ! analyzeSpecialFinally ( tryFlow , catchFlow ,
& & ! analyzeFinally ( tryFlow , catchFlow . block ,
endHandler )
& & ! analyzeSpecialFinally ( tryFlow , catchFlow . block ,
endHandler ) )
endHandler ) )
analyzeCatchBlock ( Type . tObject , tryFlow , catchFlow ) ;
analyzeCatchBlock ( Type . tObject , tryFlow , catchFlow . block ) ;
tryFlow . checkConsistent ( ) ;
tryFlow . checkConsistent ( ) ;
if ( ( GlobalOptions . debuggingFlags
if ( ( GlobalOptions . debuggingFlags