* Walk the control flow graph and remove unreachable blocks.
*/
@Override
public void visitEnd()
{
IFlowgraph cfg = this.mbi.getCfg();
List<IBasicBlock> blocks = cfg.getBlocksInEntryOrder();
boolean lastBlockWasReachable = true;
int blockIdx = 0;
while ( blockIdx < blocks.size() )
{
IBasicBlock b = blocks.get(blockIdx);
boolean isReachable = cfg.isReachable(b);
// Only advance the block index if the current
// block is removed.
int previousBlockCount = blocks.size();
if ( ! isReachable )
{
// Don't remove unreachable blocks that are the final block in an exception handler,
// unless they're also the first block in the exception handler. The AVM depends on
// these blocks under some circumstances. However, the block's instructions can be
// coalesced to a single OP_nop.
boolean safeToRemove = true;
for ( ExceptionInfo ex: this.mbi.getExceptions() )
{
IBasicBlock toBlock = this.mbi.getCfg().getBlock(ex.getTo());
if ( b.equals(toBlock) )
{
IBasicBlock fromBlock = this.mbi.getCfg().getBlock(ex.getFrom());
int tryFrom = blocks.indexOf(fromBlock);
int tryTo = blocks.indexOf(toBlock);
assert tryFrom >= 0 && tryTo >= tryFrom;
for ( int j = tryTo - 1; safeToRemove && j >= tryFrom; j-- )
safeToRemove = !cfg.isReachable(blocks.get(j));
if ( !safeToRemove )
{
// Can't remove it, but compact it: remove executable
// instructions, then write a single OP_nop as necessary.
Iterator<Instruction> it = b.getInstructions().iterator();
while ( it.hasNext() )
{
Instruction insn = it.next();
if ( insn.isExecutable() )
it.remove();
}
b.getInstructions().add(InstructionFactory.getInstruction(ABCConstants.OP_nop));
break;
}
}
}
if ( safeToRemove )
{
// Only remove the Block if it contains executable and non-NOP instructions.
for ( int j = 0; j < b.size(); j++ )
{
Instruction insn = b.get(j);
if ( insn.isExecutable() && insn.getOpcode() != ABCConstants.OP_nop )
{
// Only emit a diagnostic if b is the first unreachable block
// encountered in this sequence.
if ( lastBlockWasReachable )
this.diagnostics.unreachableBlock(this.mbi, this.mbi.getCfg(), b);
cfg.removeUnreachableBlock(b);
break;
}
}
}
}