blob: 0c2e74cf957fed9f1a02d291aacea21ee865dc92 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.flex.abc.optimize;
import java.util.Iterator;
import java.util.List;
import org.apache.flex.abc.ABCConstants;
import org.apache.flex.abc.graph.IBasicBlock;
import org.apache.flex.abc.graph.IFlowgraph;
import org.apache.flex.abc.semantics.ExceptionInfo;
import org.apache.flex.abc.semantics.Instruction;
import org.apache.flex.abc.semantics.InstructionFactory;
import org.apache.flex.abc.semantics.MethodBodyInfo;
import org.apache.flex.abc.visitors.DelegatingMethodBodyVisitor;
import org.apache.flex.abc.visitors.IDiagnosticsVisitor;
import org.apache.flex.abc.visitors.IMethodBodyVisitor;
/**
* DeadCodeFilter rebuilds the method's result InstructionList by walking the
* control flow graph at visitEnd() time, and resets its delegate's instructions
* to the pruned InstructionList.
*/
public class DeadCodeFilter extends DelegatingMethodBodyVisitor
{
/**
* Constructor.
*
* @param mbi - the MethodBodyInfo to be analyzed.
* @param delegate - the next IMethodBodyVisitor in the chain.
*/
public DeadCodeFilter(MethodBodyInfo mbi, IMethodBodyVisitor delegate, IDiagnosticsVisitor diagnostics)
{
super(delegate);
this.mbi = mbi;
this.diagnostics = diagnostics;
}
/**
* The MethodBodyInfo under analysis.
*/
protected final MethodBodyInfo mbi;
/**
*/
protected final IDiagnosticsVisitor diagnostics;
/**
* 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;
}
}
}
}
if ( previousBlockCount == blocks.size() )
blockIdx++;
// Remember the state of the last-visited block.
lastBlockWasReachable = isReachable;
}
super.visitEnd();
}
}