package dk.brics.xact.analysis.dataflow;
import java.util.Set;
import dk.brics.xact.analysis.flowgraph.FlowGraph;
import dk.brics.xact.analysis.flowgraph.Statement;
import dk.brics.xact.analysis.flowgraph.VariableFilter;
import dk.brics.xact.analysis.flowgraph.Variable;
import dk.brics.xact.analysis.flowgraph.statements.AnalyzeStm;
import dk.brics.xact.analysis.flowgraph.statements.ArrayReadStm;
import dk.brics.xact.analysis.flowgraph.statements.ArrayWriteStm;
import dk.brics.xact.analysis.flowgraph.statements.ArrayWriteStringStm;
import dk.brics.xact.analysis.flowgraph.statements.Assignment;
import dk.brics.xact.analysis.flowgraph.statements.CallStm;
import dk.brics.xact.analysis.flowgraph.statements.CastStm;
import dk.brics.xact.analysis.flowgraph.statements.CheckStm;
import dk.brics.xact.analysis.flowgraph.statements.ConcatStm;
import dk.brics.xact.analysis.flowgraph.statements.ConstStm;
import dk.brics.xact.analysis.flowgraph.statements.CopyStm;
import dk.brics.xact.analysis.flowgraph.statements.EmptyStm;
import dk.brics.xact.analysis.flowgraph.statements.EscapeStm;
import dk.brics.xact.analysis.flowgraph.statements.GapifyStm;
import dk.brics.xact.analysis.flowgraph.statements.GetStm;
import dk.brics.xact.analysis.flowgraph.statements.InsertStm;
import dk.brics.xact.analysis.flowgraph.statements.NodeStm;
import dk.brics.xact.analysis.flowgraph.statements.NopStm;
import dk.brics.xact.analysis.flowgraph.statements.PlugStm;
import dk.brics.xact.analysis.flowgraph.statements.RemoveStm;
import dk.brics.xact.analysis.flowgraph.statements.SetStm;
import dk.brics.xact.analysis.flowgraph.statements.StatementVisitor;
import dk.brics.xact.analysis.flowgraph.statements.UnknownStm;
import dk.brics.xact.analysis.flowgraph.statements.ValidateStm;
import dk.brics.xact.analysis.flowgraph.statements.VarStm;
/**
* Lattice and transfer functions for a dataflow analysis that
* tracks values for program variables.
*/
public class VariableAnalysis<VariableElementType> implements AnalysisInterface<VariableAnalysisElement<VariableElementType>> {
private VariableAnalysisInterface<VariableElementType> val;
public boolean isForward() {
return true;
}
public Set<Statement> getInitial(FlowGraph g) {
return g.getEntries();
}
/**
* Constructs a new variable analysis using the given lattice.
*/
public VariableAnalysis(VariableAnalysisInterface<VariableElementType> val) {
this.val = val;
}
public VariableAnalysisElement<VariableElementType> newBottomElement() {
return new VariableAnalysisElement<VariableElementType>();
}
public boolean merge(VariableAnalysisElement<VariableElementType> source, VariableFilter filter, VariableAnalysisElement<VariableElementType> dest) {
boolean changed = false;
for (Variable v : source.getVariables()) {
if (filter.containsVariable(v)) {
changed |= val.merge(getVar(source, v), getVar(dest, v));
}
}
return changed;
}
private VariableElementType getVar(VariableAnalysisElement<VariableElementType> elem, Variable var) {
if (var == null)
return null;
VariableElementType t = elem.get(var);
if (t == null) {
t = val.newBottomElement();
elem.put(var, t);
}
return t;
}
public boolean transfer(final VariableAnalysisElement<VariableElementType> in, Statement s, final VariableAnalysisElement<VariableElementType> out) {
final boolean[] changed = new boolean[1];
s.visitBy(new StatementVisitor() {
private void handleAssign(Assignment s, VariableElementType value) {
val.assign(value, s);
if (s instanceof AnalyzeStm) {
AnalyzeStm as = (AnalyzeStm) s;
if (as.getDest().getID() == as.getBase().getID())
return; // skip AnalyzeStm assignment if dest==base
}
for (Variable v : in.getVariables()) {
if (v == s.getDest()) {
changed[0] |= val.merge(getVar(in, v), getVar(out, v));
}
}
changed[0] |= val.merge(value, getVar(out, s.getDest()));
}
public void visitAnalyzeStm(AnalyzeStm s) {
handleAssign(s, getVar(in, s.getBase()));
}
public void visitCastStm(CastStm s) {
handleAssign(s, val.transferCast(s, getVar(in, s.getBase())));
}
public void visitConcatStm(ConcatStm s) {
handleAssign(s, val.transferConcat(s, getVar(in, s.getXMLSource())));
}
public void visitConstStm(ConstStm s) {
handleAssign(s, val.transferConst(s));
}
public void visitCopyStm(CopyStm s) {
handleAssign(s, val.transferCopy(s, getVar(in, s.getBase()), getVar(in, s.getFirstAttr()),
getVar(in, s.getFirstChild()), getVar(in, s.getNextNode())));
}
public void visitEmptyStm(EmptyStm s) {
handleAssign(s, val.transferEmpty(s));
}
public void visitGapifyStm(GapifyStm s) {
handleAssign(s, val.transferGapify(s, getVar(in, s.getBase())));
}
public void visitGetStm(GetStm s) {
handleAssign(s, val.transferGet(s, getVar(in, s.getBase())));
}
public void visitInsertStm(InsertStm s) {
handleAssign(s, val.transferInsert(s, getVar(in, s.getBase()), getVar(in, s.getXMLSource())));
}
public void visitNodeStm(NodeStm s) {
handleAssign(s, val.transferNode(s, getVar(in, s.getFirstAttr()), getVar(in, s.getFirstChild()),
getVar(in, s.getNextNode())));
}
public void visitPlugStm(PlugStm s) {
handleAssign(s, val.transferPlug(s, getVar(in, s.getBase()),
getVar(in, s.getXMLSource())));
}
public void visitRemoveStm(RemoveStm s) {
handleAssign(s, val.transferRemove(s, getVar(in, s.getBase())));
}
public void visitSetStm(SetStm s) {
handleAssign(s, val.transferSet(s, getVar(in, s.getBase()), getVar(in, s.getXMLSource())));
}
public void visitUnknownStm(UnknownStm s) {
handleAssign(s, val.transferUnknown(s));
}
public void visitValidateStm(ValidateStm s) {
handleAssign(s, val.transferValidate(s, getVar(in, s.getBase())));
}
public void visitVarStm(VarStm s) {
if (s.getDest().getID() != s.getSource().getID())
handleAssign(s, getVar(in, s.getSource()));
else {
changed[0] |= out.copyFrom(in);
}
}
public void visitNopStm(NopStm s) {
changed[0] = merge(in, new VariableFilter(true), out);
}
public void visitEscapeStm(EscapeStm s) {
changed[0] = merge(in, new VariableFilter(true), out);
}
public void visitCheckStm(CheckStm s) {
val.transferCheck(s, getVar(in, s.getBase()));
changed[0] = merge(in, new VariableFilter(true), out);
}
// not in this phase
// XXX it makes sense to support these, but VariableAnalysis is never used in a phase that uses them
public void visitArrayReadStm(ArrayReadStm s) {
}
public void visitArrayWriteStm(ArrayWriteStm s) {
}
public void visitArrayWriteStringStm(ArrayWriteStringStm s) {
}
public void visitCallStm(CallStm s) {
}
});
return changed[0];
}
}