Commit 417310f7 authored by Lubomir Bulej's avatar Lubomir Bulej

DiSL: BasicBlockCalc: simple but extensive code cleanup

parent ad59bd6b
package ch.usi.dag.disl.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
......@@ -9,101 +10,152 @@ import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LookupSwitchInsnNode;
import org.objectweb.asm.tree.TableSwitchInsnNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
public class BasicBlockCalc {
// Get basic blocks of the given method node.
public static List<AbstractInsnNode> getAll(InsnList instructions,
List<TryCatchBlockNode> tryCatchBlocks, boolean isPrecise) {
// add method automatically skips all the labels
Set<AbstractInsnNode> bbStarts = new HashSet<AbstractInsnNode>() {
private static final long serialVersionUID = 1L;
public class BasicBlockCalc {
/**
* Returns all basic blocks of a given method node.
*/
public static List <AbstractInsnNode> getAll (
final InsnList instructions, final List <TryCatchBlockNode> tryCatchBlocks,
final boolean isPrecise
) {
//
// A holder for instructions that mark the beginning of a basic block.
//
// We override the add() method to automatically skip all virtual
// instructions that are added.
//
// We also override the addAll() method to ensure that our modified
// add() method is used to add the individual elements, because there
// is no contract in HashSet or Collection to guarantee that.
//
@SuppressWarnings ("serial")
Set <AbstractInsnNode> bbStarts = new HashSet <AbstractInsnNode> () {
@Override
public boolean add(AbstractInsnNode e) {
return super.add(AsmHelper.skipVirtualInsns(e, true));
public boolean add (AbstractInsnNode insn) {
return super.add (AsmHelper.skipVirtualInsnsForward (insn));
}
};
bbStarts.add(instructions.getFirst());
for (int i = 0; i < instructions.size(); i++) {
AbstractInsnNode instruction = instructions.get(i);
int opcode = instruction.getOpcode();
@Override
public boolean addAll (Collection <? extends AbstractInsnNode> insns) {
boolean result = false;
for (final AbstractInsnNode insn : insns) {
final boolean modified = add (insn);
result = result || modified;
}
return result;
}
};
switch (instruction.getType()) {
//
// The first instruction starts a basic block.
//
bbStarts.add (instructions.getFirst ());
//
// Scan all the instructions, identify those that terminate their basic
// block and collect the starting instructions of the basic blocks
// that follow them.
//
for (final AbstractInsnNode insn : AsmHelper.allInsnsFrom (instructions)) {
SWITCH: switch (insn.getType ()) {
//
// IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
// IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
// IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL, and IFNONNULL.
//
// For all jump instructions, a basic block starts where the
// instruction jumps.
//
// For conditional jumps or jumps to subroutines, a basic block
// also starts with the next instruction.
//
// The GOTO instruction changes the control flow unconditionally,
// so only one basic block follows it.
//
case AbstractInsnNode.JUMP_INSN: {
// Covers IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
// IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
// IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL, and IFNONNULL.
bbStarts.add(((JumpInsnNode) instruction).label);
if (instruction.getOpcode () != Opcodes.GOTO) {
bbStarts.add (((JumpInsnNode) insn).label);
if (insn.getOpcode () != Opcodes.GOTO) {
//
// There must be a valid (non-virtual) instruction
// following a conditional/subroutine jump instruction.
//
AbstractInsnNode nextInsn = AsmHelper.nextNonVirtualInsn (instruction);
AbstractInsnNode nextInsn = AsmHelper.nextNonVirtualInsn (insn);
if (nextInsn != null) {
bbStarts.add (nextInsn);
}
}
break;
break SWITCH;
}
//
// LOOKUPSWITCH, TABLESWITCH
//
// For the LOOKUPSWITCH and TABLESWITCH instructions, all the
// targets in the table represent a new basic block, including
// the default target.
//
// Since they are two unrelated classes in ASM, we have to handle
// each case separately, yet with the same code.
//
case AbstractInsnNode.LOOKUPSWITCH_INSN: {
// Covers LOOKUPSWITCH
LookupSwitchInsnNode lsin = (LookupSwitchInsnNode) instruction;
for (LabelNode label : lsin.labels) {
bbStarts.add(label);
}
final LookupSwitchInsnNode lsInsn = (LookupSwitchInsnNode) insn;
bbStarts.add(lsin.dflt);
break;
bbStarts.addAll (lsInsn.labels);
bbStarts.add (lsInsn.dflt);
break SWITCH;
}
case AbstractInsnNode.TABLESWITCH_INSN: {
// Covers TABLESWITCH
TableSwitchInsnNode tsin = (TableSwitchInsnNode) instruction;
for (LabelNode label : tsin.labels) {
bbStarts.add(label);
}
final TableSwitchInsnNode tsInsn = (TableSwitchInsnNode) insn;
bbStarts.add(tsin.dflt);
break;
bbStarts.addAll (tsInsn.labels);
bbStarts.add (tsInsn.dflt);
break SWITCH;
}
//
// Don't do anything for other instruction types.
//
default:
break;
break SWITCH;
}
if (isPrecise && AsmHelper.mightThrowException(instruction)) {
bbStarts.add(instruction.getNext());
//
// In case of precise basic block marking, any instruction that
// might throw an exception is potentially the last instruction of
// a basic block, with the next instruction the beginning of the
// next basic block.
//
if (isPrecise && AsmHelper.mightThrowException (insn)) {
bbStarts.add (insn.getNext ());
}
}
// add also starts of the handlers
for (TryCatchBlockNode tryCatchBlock : tryCatchBlocks) {
bbStarts.add(tryCatchBlock.handler);
//
// All exception handlers start a basic block as well.
//
for (final TryCatchBlockNode tryCatchBlock : tryCatchBlocks) {
bbStarts.add (tryCatchBlock.handler);
}
// sort starting instructions
List<AbstractInsnNode> bbSortedList = new ArrayList<AbstractInsnNode>();
for (AbstractInsnNode instruction : AsmHelper.allInsnsFrom (instructions)) {
if (bbStarts.contains(instruction)) {
bbSortedList.add(instruction);
//
// Sort the basic block starting instructions. A LinkedHashSet would
// not help here, because we were adding entries out-of-order (jumps).
//
List <AbstractInsnNode> result = new ArrayList <AbstractInsnNode> ();
for (final AbstractInsnNode insn : AsmHelper.allInsnsFrom (instructions)) {
if (bbStarts.contains (insn)) {
result.add (insn);
}
}
return bbSortedList;
return result;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment