WALA/com.ibm.wala.core/src/com/ibm/wala/dataflow/ssa/SSAInference.java

168 lines
5.5 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.dataflow.ssa;
import java.util.Iterator;
import com.ibm.wala.analysis.typeInference.TypeInference;
import com.ibm.wala.fixedpoint.impl.DefaultFixedPointSolver;
import com.ibm.wala.fixedpoint.impl.NullaryOperator;
import com.ibm.wala.fixpoint.AbstractOperator;
import com.ibm.wala.fixpoint.IVariable;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SymbolTable;
/**
* This class performs intra-procedural propagation over an SSA form.
*
* A client will subclass an {@link SSAInference} by providing factories that generate {@link IVariable}s corresponding to SSA value
* numbers, and {@link AbstractOperator}s corresponding to SSA instructions. This class will set up a dataflow system induced by the
* SSA def-use graph, and solve the system by iterating to a fixed point.
*
* @see TypeInference for the canonical client of this machinery.
*/
public abstract class SSAInference<T extends IVariable> extends DefaultFixedPointSolver<T> {
static final boolean DEBUG = false;
/**
* The governing SSA form
*/
private IR ir;
/**
* The governing symbol table
*/
private SymbolTable symbolTable;
/**
* Dataflow variables, one for each value in the symbol table.
*/
private IVariable[] vars;
public interface OperatorFactory<T extends IVariable> {
/**
* Get the dataflow operator induced by an instruction in SSA form.
*
* @param instruction
* @return dataflow operator for the instruction, or null if the instruction is not applicable to the dataflow system.
*/
AbstractOperator<T> get(SSAInstruction instruction);
}
public interface VariableFactory {
/**
* Make the variable for a given value number.
*
* @return a newly created dataflow variable, or null if not applicable.
*/
public IVariable makeVariable(int valueNumber);
}
/**
* initializer for SSA Inference equations.
*/
protected void init(IR ir, VariableFactory varFactory, OperatorFactory<T> opFactory) {
this.ir = ir;
this.symbolTable = ir.getSymbolTable();
createVariables(varFactory);
createEquations(opFactory);
}
private void createEquations(OperatorFactory<T> opFactory) {
SSAInstruction[] instructions = ir.getInstructions();
for (int i = 0; i < instructions.length; i++) {
SSAInstruction s = instructions[i];
makeEquationForInstruction(opFactory, s);
}
for (Iterator it = ir.iteratePhis(); it.hasNext();) {
SSAInstruction s = (SSAInstruction) it.next();
makeEquationForInstruction(opFactory, s);
}
for (Iterator it = ir.iteratePis(); it.hasNext();) {
SSAInstruction s = (SSAInstruction) it.next();
makeEquationForInstruction(opFactory, s);
}
for (Iterator it = ir.iterateCatchInstructions(); it.hasNext();) {
SSAInstruction s = (SSAInstruction) it.next();
makeEquationForInstruction(opFactory, s);
}
}
/**
* Create a dataflow equation induced by a given instruction
*/
private void makeEquationForInstruction(OperatorFactory<T> opFactory, SSAInstruction s) {
if (s != null && s.hasDef()) {
AbstractOperator<T> op = opFactory.get(s);
if (op != null) {
T def = getVariable(s.getDef());
if (op instanceof NullaryOperator) {
newStatement(def, (NullaryOperator<T>) op, false, false);
} else {
int n = s.getNumberOfUses();
T[] uses = makeStmtRHS(n);
for (int j = 0; j < n; j++) {
if (s.getUse(j) > -1) {
uses[j] = getVariable(s.getUse(j));
assert uses[j] != null;
}
}
newStatement(def, op, uses, false, false);
}
}
}
}
/**
* Create a dataflow variable for each value number
*/
private void createVariables(VariableFactory factory) {
vars = new IVariable[symbolTable.getMaxValueNumber() + 1];
for (int i = 1; i < vars.length; i++) {
vars[i] = factory.makeVariable(i);
}
}
/**
* @return the dataflow variable representing the value number, or null if none found.
*/
@SuppressWarnings("unchecked")
protected T getVariable(int valueNumber) {
if (valueNumber < 0) {
throw new IllegalArgumentException("Illegal valueNumber " + valueNumber);
}
if (DEBUG) {
System.err.println(("getVariable for " + valueNumber + " returns " + vars[valueNumber]));
}
assert vars != null : "null vars array";
return (T) vars[valueNumber];
}
/**
* Return a string representation of the system
*
* @return a string representation of the system
*/
@Override
public String toString() {
StringBuffer result = new StringBuffer("Type inference : \n");
for (int i = 0; i < vars.length; i++) {
result.append("v").append(i).append(" ").append(vars[i]).append("\n");
}
return result.toString();
}
}