final ExceptionBlock handlerTry = handler.getTryBlock();
for (final ExceptionHandler other : _exceptionHandlers) {
final ExceptionBlock otherTry = other.getTryBlock();
final HandlerInfo finallyInfo = handlers.get(handler);
final ControlFlowNode firstInFinally = firstOrDefault(finallyInfo.handlerNodes);
if (firstInFinally == null) {
continue;
}
Instruction firstFinallyInstruction = firstInFinally.getStart();
Instruction lastFinallyInstruction = lastOrDefault(finallyInfo.handlerNodes).getEnd();
if (lastFinallyInstruction.getOpCode() == OpCode.ATHROW &&
lastFinallyInstruction.getPrevious() != null) {
//
// If a finally handler catches, stores, and rethrows an exception, NOP-out the
// instructions responsible for those operations. In the decompiled output, we
// don't expect to see such behavior.
//
final Instruction rethrowException = lastFinallyInstruction;
final Instruction loadException;
final Instruction storeException;
switch (firstFinallyInstruction.getOpCode()) {
case ASTORE:
case ASTORE_1:
case ASTORE_2:
case ASTORE_3:
case ASTORE_W:
storeException = firstFinallyInstruction;
firstFinallyInstruction = firstFinallyInstruction.getNext();
break;
default:
storeException = null;
break;
}
final Instruction previousFinallyInstruction = lastFinallyInstruction.getPrevious();
switch (previousFinallyInstruction.getOpCode()) {
case ALOAD:
case ALOAD_1:
case ALOAD_2:
case ALOAD_3:
case ALOAD_W:
loadException = previousFinallyInstruction;
lastFinallyInstruction = previousFinallyInstruction.getPrevious();
break;
default:
loadException = null;
break;
}
if (storeException != null && loadException != null) {
rethrowingFinallyStarts.add(storeException);
storeException.setOpCode(OpCode.POP);
storeException.setOperand(null);
loadException.setOpCode(OpCode.NOP);
loadException.setOperand(null);
rethrowException.setOpCode(OpCode.NOP);
if (rethrowException.getNext() == null) {
_leaveFinallyInstructions.add(rethrowException);
}
}
}
else if (rethrowingFinallyStarts.contains(firstFinallyInstruction)) {
firstFinallyInstruction = firstFinallyInstruction.getNext();
lastFinallyInstruction = lastFinallyInstruction.getPrevious().getPrevious();
}
if (otherTry.getFirstInstruction().getOffset() == handlerTry.getFirstInstruction().getOffset() &&
otherTry.getLastInstruction().getOffset() == handlerTry.getLastInstruction().getOffset()) {
final HandlerInfo handlerInfo = handlers.get(other);
final ControlFlowNode lastInTry = lastOrDefault(handlerInfo.tryNodes);
if (lastInTry == null || lastInTry.precedes(firstInFinally)) {
continue;
}
ControlFlowNode firstAfterTry = null;
final Instruction lastInstructionInTry = lastInTry.getEnd();
final Instruction firstInstructionAfterTry = lastInstructionInTry.getNext();
if (firstInstructionAfterTry == null) {
continue;
}
for (final ControlFlowNode successor : lastInTry.getSuccessors()) {
if (successor.getStart() == firstInstructionAfterTry) {
firstAfterTry = successor;
break;
}
}
if (firstAfterTry == null || firstAfterTry == firstInFinally) {
continue;
}
assert firstAfterTry != null;
Instruction pTry, pFinally;
pTry = firstAfterTry.getStart();
pFinally = firstFinallyInstruction;
if ((pTry.getOpCode() == OpCode.GOTO ||
pTry.getOpCode() == OpCode.GOTO_W) &&
((Instruction) pTry.getOperand(0)).getOffset() > lastFinallyInstruction.getOffset()) {