WALA/com.ibm.wala.core/src/com/ibm/wala/cfg/Util.java

227 lines
7.8 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.cfg;
import java.util.Iterator;
import com.ibm.wala.shrikeBT.ConditionalBranchInstruction;
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSASwitchInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.util.debug.Assertions;
/**
* Convenience methods for navigating a {@link ControlFlowGraph}.
*/
public class Util {
/**
* @return the last instruction in basic block b, as stored in the instruction array for cfg
*/
public static SSAInstruction getLastInstruction(ControlFlowGraph cfg, IBasicBlock b) {
if (b == null) {
throw new IllegalArgumentException("b is null");
}
if (cfg == null) {
throw new IllegalArgumentException("G is null");
}
return (SSAInstruction) cfg.getInstructions()[b.getLastInstructionIndex()];
}
/**
* Does basic block b end with a conditional branch instruction?
*/
public static boolean endsWithConditionalBranch(ControlFlowGraph G, IBasicBlock b) {
return getLastInstruction(G, b) instanceof SSAConditionalBranchInstruction;
}
/**
* Does basic block b end with a switch instruction?
*/
public static boolean endsWithSwitch(ControlFlowGraph G, IBasicBlock b) {
return getLastInstruction(G, b) instanceof SSASwitchInstruction;
}
/**
* Given that b falls through to the next basic block, what basic block does it fall through to?
*/
public static <I, T extends IBasicBlock<I>> T getFallThruBlock(ControlFlowGraph<I, T> G, T b) {
if (b == null) {
throw new IllegalArgumentException("b is null");
}
if (G == null) {
throw new IllegalArgumentException("G is null");
}
return G.getBlockForInstruction(b.getLastInstructionIndex() + 1);
}
/**
* Given that b ends with a conditional branch, return the basic block to
* which control transfers if the branch is not taken.
*/
public static <I, T extends IBasicBlock<I>> T getNotTakenSuccessor(ControlFlowGraph<I, T> G, T b) {
if (G == null) {
throw new IllegalArgumentException("G is null");
}
if (!endsWithConditionalBranch(G, b)) {
throw new IllegalArgumentException(b.toString() + " does not end with a conditional branch");
}
return getFallThruBlock(G, b);
}
/**
* Given that b ends with a conditional branch, return the basic block to
* which control transfers if the branch is taken.
*/
public static <I, T extends IBasicBlock<I>> T getTakenSuccessor(ControlFlowGraph<I, T> G, T b) {
if (G == null) {
throw new IllegalArgumentException("G is null");
}
if (!endsWithConditionalBranch(G, b)) {
throw new IllegalArgumentException(b.toString() + " does not end with a conditional branch");
}
T fs = getNotTakenSuccessor(G, b);
for (Iterator<? extends T> ss = G.getSuccNodes(b); ss.hasNext();) {
T s = ss.next();
if (s != fs)
return s;
}
// under pathological conditions, b may have exactly one successor (in other
// words, the
// branch is irrelevant
return fs;
}
/**
* When the tested value of the switch statement in b has value c, which basic
* block does control transfer to.
*/
public static <I, T extends IBasicBlock<I>> T resolveSwitch(ControlFlowGraph<I, T> G, T b, int c) {
assert endsWithSwitch(G, b);
SSASwitchInstruction s = (SSASwitchInstruction) getLastInstruction(G, b);
int[] casesAndLabels = s.getCasesAndLabels();
for (int i = 0; i < casesAndLabels.length; i += 2)
if (casesAndLabels[i] == c)
return G.getBlockForInstruction(casesAndLabels[i + 1]);
return G.getBlockForInstruction(s.getDefault());
}
/**
* Is block s the default case for the switch instruction which is the last instruction of block b?
*/
public static <I, T extends IBasicBlock<I>> boolean isSwitchDefault(ControlFlowGraph<I, T> G, T b, T s) {
if (G == null) {
throw new IllegalArgumentException("G is null");
}
assert endsWithSwitch(G, b);
SSASwitchInstruction sw = (SSASwitchInstruction) getLastInstruction(G, b);
assert G.getBlockForInstruction(sw.getDefault()) != null;
return G.getBlockForInstruction(sw.getDefault()).equals(s);
}
/**
* When a switch statement at the end of block b transfers control to block s,
* which case was taken? TODO: Is this correct? Can't we have multiple cases
* that apply? Check on this.
*/
public static <I, T extends IBasicBlock<I>> int getSwitchLabel(ControlFlowGraph<I, T> G, T b, T s) {
assert endsWithSwitch(G, b);
SSASwitchInstruction sw = (SSASwitchInstruction) getLastInstruction(G, b);
int[] casesAndLabels = sw.getCasesAndLabels();
for (int i = 0; i < casesAndLabels.length; i += 2) {
if (G.getBlockForInstruction(casesAndLabels[i + 1]).equals(s)) {
return casesAndLabels[i];
}
}
Assertions.UNREACHABLE();
return -1;
}
/**
* To which {@link IBasicBlock} does control flow from basic block bb, which ends in a
* conditional branch, when the conditional branch operands evaluate to the
* constants c1 and c2, respectively.
*
* Callers must resolve the constant values from the {@link SymbolTable}
* before calling this method. These integers are <bf>not</bf> value numbers;
*/
public static <I, T extends IBasicBlock<I>> T resolveBranch(ControlFlowGraph<I, T> G, T bb, int c1, int c2) {
SSAConditionalBranchInstruction c = (SSAConditionalBranchInstruction) getLastInstruction(G, bb);
final ConditionalBranchInstruction.Operator operator = (ConditionalBranchInstruction.Operator) c.getOperator();
switch (operator) {
case EQ:
if (c1 == c2)
return getTakenSuccessor(G, bb);
else
return getNotTakenSuccessor(G, bb);
case NE:
if (c1 != c2)
return getTakenSuccessor(G, bb);
else
return getNotTakenSuccessor(G, bb);
case LT:
if (c1 < c2)
return getTakenSuccessor(G, bb);
else
return getNotTakenSuccessor(G, bb);
case GE:
if (c1 >= c2)
return getTakenSuccessor(G, bb);
else
return getNotTakenSuccessor(G, bb);
case GT:
if (c1 > c2)
return getTakenSuccessor(G, bb);
else
return getNotTakenSuccessor(G, bb);
case LE:
if (c1 <= c2)
return getTakenSuccessor(G, bb);
else
return getNotTakenSuccessor(G, bb);
default:
throw new UnsupportedOperationException(String.format("unexpected operator %s", operator));
}
}
/**
* Given that a is a predecessor of b in the cfg ..
*
* When we enumerate the predecessors of b in order, which is the first index
* in this order in which a appears? Note that this order corresponds to the
* order of operands in a phi instruction.
*/
public static <I, T extends IBasicBlock<I>> int whichPred(ControlFlowGraph<I, T> cfg, T a, T b) {
if (cfg == null) {
throw new IllegalArgumentException("cfg is null");
}
if (a == null) {
throw new IllegalArgumentException("a is null");
}
if (b == null) {
throw new IllegalArgumentException("b is null");
}
int i = 0;
for (Iterator it = cfg.getPredNodes(b); it.hasNext();) {
if (it.next().equals(a)) {
return i;
}
i++;
}
Assertions.UNREACHABLE("Invalid: a must be a predecessor of b! " + a + " " + b);
return -1;
}
}