//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////////////// // The Abstract domain for determining "constant" expressions // i.e. It determines which expression are statically binded ///////////////////////////////////////////////////////////////////////////////// /* using System; namespace Microsoft.AbstractInterpretationFramework { using Microsoft.Contracts; using System.Collections.Generic; using Microsoft.AbstractInterpretationFramework; /// /// This is an abstract domain for inferring constant expressions /// public class ConstantExpressions : Lattice { /// /// An abstract element is made of two maps: /// + A map from variables to expressions \cup top ( i.e. for each variable, the expression it is binded ) /// + A map from variables to set of variabes ( i.e. for each variable, the set of variables that depends on its value ) /// private class AbstractElement: Element { private Dictionary variableBindings; private Dictionary> variableDependences; static private AbstractElement! bottom; static public Element! Bottom { get { if(bottom == null) { bottom = new AbstractElement(); bottom.variableBindings = null; bottom.variableDependences = null; } assert bottom.variableBindings == null && bottom.variableDependences == null; return bottom; } } static public Element! Top { get { return new AbstractElement(); } } AbstractElement() { this.variableBindings = new Dictionary(); this.variableDependences = new Dictionary>(); } /// /// Our abstract element is top if and only if it has any constraint on variables /// public bool IsTop { get { return this.variableBindings.Keys.Count == 0 && this.variableDependences.Keys.Count == 0; } } /// /// Our abstract element is bottom if and only if the maps are null /// public bool IsBottom { get { assert (this.variableBindings == null) <==> (this.variableDependences == null); return this.variableBindings == null && this.variableDependences == null; } } /// /// The pointwise join... /// public static AbstractElement! Join(AbstractElement! left, AbstractElement! right) { AbstractElement! result = new AbstractElement(); // Put all the variables in the left foreach(IVariable! var in left.variableBindings.Keys) { BindExpr leftVal = left.variableBindings[var]; assert leftVal != null; BindExpr rightVal = right.variableBindings[var]; if(rightVal== null) // the expression is not there { result.variableBindings.Add(var, leftVal); } else // both abstract elements have a definition for the variable.... { result.variableBindings.Add(var, BindExpr.Join(leftVal, rightVal)); } } // Put all the variables in the right foreach(IVariable! var in right.variableBindings.Keys) { BindExpr rightVal = right.variableBindings[var]; assert rightVal != null; BindExpr leftVal = left.variableBindings[var]; if(rightVal== null) // the expression is not there { result.variableBindings.Add(var, rightVal); } else // both abstract elements have a definition for the variable.... { result.variableBindings.Add(var, BindExpr.Join(rightVal, leftVal)); } } // Join the dependencies... foreach(IVariable! var in left.variableDependences.Keys) { List dependencies = left.variableDependences[var]; List dup = new List(dependencies); result.variableDependences.Add(var, dup); } foreach(IVariable! var in right.variableDependences.Keys) { if(result.variableDependences.ContainsKey(var)) { List dependencies = result.variableDependences[var]; dependencies.AddRange(right.variableDependences[var]); } else { List dependencies = right.variableDependences[var]; List dup = new List(dependencies); result.variableDependences.Add(var, dup); } } // Normalize... i.e. for the variables such thas they point to an unknown expression (top) we have to update also their values result.Normalize(); return result; } /// /// Normalize the current abstract element, in that it propagetes the "dynamic" information throughtout the abstract element /// public void Normalize() { if(this.IsBottom) return; if(this.IsTop) return; assert this.variableBindings != null; bool atFixpoint = false; while(!atFixpoint) { atFixpoint = true; // guess that we've got the fixpoint... foreach(IVariable x in this.variableBindings.Keys) { if(this.variableBindings[x].IsTop) // It means that the variable is tied to a dynamic expression { foreach(IVariable y in this.variableDependences[x]) // The all the variables that depend on x are also dynamic... { assert x != y; // A variable cannot depend on itself... if(!this.variableBindings[y].IsTop) { this.variableBindings[y] = BindExpr.Top; atFixpoint = false; // the assumption that we were at the fixpoint was false, we have still to propagate some information... } } } } } } /// /// The pointwise meet... /// public static AbstractElement! Meet(AbstractElement! left, AbstractElement! right) { AbstractElement! result = new AbstractElement(); // Put the variables that are both in left and right foreach(IVariable var in left.variableBindings.Keys) { if(right.variableBindings.ContainsKey(var)) { result.variableBindings.Add(var, BindExpr.Meet(left.variableBindings[var], right.variableBindings[var])); } } // Intersect the dependencies foreach(IVariable var in result.variableBindings.Keys) { List depLeft = left.variableDependences[var]; List depRight = right.variableDependences[var]; // Intersect the two sets result.variableDependences.Add(var, depLeft); foreach(IVariable v in depRight) { if(!result.variableDependences.ContainsKey(v)) { result.variableDependences.Remove(v); } } } // Now we remove the dependencies with variables not in variableBindings List! varsToRemove = new List(); foreach(IVariable var in result. } /// /// Clone the current abstract element /// public override Element! Clone() { AbstractElement cloned = new AbstractElement(); foreach(IVariable var in this.variableBindings.Keys) { cloned.variableBindings.Add(var, this.variableBindings[var]); } foreach(IVariable var in this.variableDependences.Keys) { List dependingVars = this.variableDependences[var]; List clonedDependingVars = new List(dependingVars); cloned.variableDependences.Add(var, clonedDependingVars); } } /// /// Return the variables that have a binding /// public override ICollection! FreeVariables() { List vars = new List(this.variableBindings.Keys); return vars; } public override string! ToString() { string! retString = ""; retString += "Bindings"; foreach(IVariable var in this.variableBindings.Keys) { string! toAdd = var.ToString() + " -> " + this.variableBindings[var]; retString += toAdd + ","; } retString += "\nDependencies"; foreach(IVariable var in this.variableDependences.Keys) { string! toAdd = var.ToString() + " -> " + this.variableDependences[var]; retString += toAdd + ","; } return retString; } } public override Element! Top { get { return AbstractElement.Top; } } public override Element! Bottom { get { return AbstractElement.Bottom; } } public override bool IsTop(Element! e) { assert e is AbstractElement; AbstractElement! absElement = (AbstractElement) e; return absElement.IsTop; } public override bool IsBottom(Element! e) { assert e is AbstractElement; AbstractElement absElement = (AbstractElement) e; return absElement.IsBottom; } /// /// Perform the pointwise join of the two abstract elements /// public override Element! NontrivialJoin(Element! a, Element! b) { assert a is AbstractElement; assert b is AbstractElement; AbstractElement! left = (AbstractElement!) a; AbstractElement! right = (AbstractElement!) b; return AbstractElement.Join(left, right); } /// /// Perform the pointwise meet of two abstract elements /// public override Element! NontrivialMeet(Element! a, Element!b) { assert a is AbstractElement; assert b is AbstractElement; AbstractElement! left = (AbstractElement!) a; AbstractElement! right = (AbstractElement!) b; return AbstractElement.Meet(left, right); } } /// /// A wrapper in order to have the algebraic datatype BindExpr := IExpr | Top /// abstract class BindExpr { /// /// True iff this expression is instance of BindExprTop /// public bool IsTop { get { return this is BindExprTop; } } static public BindExpr Top { get { return BindExprTop.UniqueTop; } } /// /// True iff this expression is instance of BindExprBottom /// public bool IsBottom { get { return this is BindExprBottom; } } static public BindExpr Bottom { get { return BindExprBottom.UniqueBottom; } } public static BindExpr! Join(BindExpr! left, BindExpr! right) { if(left.IsTop || right.IsTop) { return BindExpr.Top; } else if(left.IsBottom) { return right; } else if(right.IsBottom) { return left; } else if(left.EmbeddedExpr != right.EmbeddedExpr) { return BindExpr.Top; } else // left.EmbeddedExpr == right.EmbeddedExpr { return left; } } public static BindExpr! Meet(BindExpr! left, BindExpr! right) { if(left.IsTop) { return right; } else if(right.IsTop) { return right; } else if(left.IsBottom || right.IsBottom) { return BindExpr.Bottom; } else if(left.EmbeddedExpr != right.EmbeddedExpr) { return BindExpr.Bottom; } else // left.EmbeddedExpr == right.EmbeddedExpr { return left; } } abstract public IExpr! EmbeddedExpr { get; } } /// /// A wrapper for an integer /// class Expr : BindExpr { private IExpr! exp; public Expr(IExpr! exp) { this.exp = exp; } override public IExpr! EmbeddedExpr { get { return this.exp; } } public override string! ToString() { return this.exp.ToString(); } } /// /// The dynamic expression /// class BindExprTop : BindExpr { private BindExprTop top = new BindExprTop(); static public BindExprTop! UniqueTop { get { return this.top; } } private BindExprTop() {} override public IExpr! EmbeddedExpr { get { assert false; // If we get there, we have an error } } public override string! ToString() { return ""; } } /// /// The unreachable expression /// class BindExprBottom : BindExpr { private BindExprBottom! bottom = new BindExprBottom(); static public BindExprBottom! UniqueBottom { get { return this.bottom; } } private BindExprBottom() {} override public IExpr! EmbeddedExpr { get { assert false; } } public override string! ToString() { return ""; } } } // end namespace Microsoft.AbstractInterpretationFramework */