//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Cci;
using Microsoft.Cci.MetadataReader;
using Microsoft.Cci.MutableCodeModel;
using Microsoft.Cci.Contracts;
using Microsoft.Cci.ILToCodeModel;
using Bpl = Microsoft.Boogie;
namespace BytecodeTranslator {
///
/// Implementations of this interface determine how the heap is represented in
/// the translated Boogie program.
///
public interface IHeap {
///
/// Creates a fresh BPL variable to represent , deciding
/// on its type based on the heap representation.
///
Bpl.Variable CreateFieldVariable(IFieldReference field);
/// Creates a fresh BPL variable to represent , deciding
/// on its type based on the heap representation. I.e., the value of this
/// variable represents the value of the expression "typeof(type)".
///
Bpl.Variable CreateTypeVariable(ITypeReference type, List parents);
Bpl.Variable CreateEventVariable(IEventDefinition e);
///
/// Returns the (typed) BPL expression that corresponds to the value of the field
/// belonging to the object (which should be non-null).
///
/// The expression that represents the object to be dereferenced.
///
/// The field that is used to dereference the object .
///
Bpl.Expr ReadHeap(Bpl.Expr/*?*/ o, Bpl.Expr f, AccessType accessType, Bpl.Type unboxType);
///
/// Returns the BPL command that corresponds to assigning the value
/// to the field of the object (which should be non-null).
///
Bpl.Cmd WriteHeap(Bpl.IToken tok, Bpl.Expr/*?*/ o, Bpl.Expr f, Bpl.Expr value, AccessType accessType, Bpl.Type boxType);
///
/// Returns the BPL expression that corresponds to the value of the dynamic type
/// of the object represented by the expression .
///
Bpl.Expr DynamicType(Bpl.Expr o);
}
public enum AccessType { Array, Heap, Struct };
public abstract class Heap : HeapFactory, IHeap
{
[RepresentationFor("$ArrayContents", "var $ArrayContents: [Ref][int]Union;")]
public Bpl.Variable ArrayContentsVariable = null;
[RepresentationFor("$ArrayLength", "function $ArrayLength(Ref): int;")]
public Bpl.Function ArrayLengthFunction = null;
public abstract Bpl.Variable CreateFieldVariable(IFieldReference field);
#region Boogie Types
[RepresentationFor("Delegate", "type {:datatype} Delegate;")]
public Bpl.TypeCtorDecl DelegateTypeDecl = null;
public Bpl.CtorType DelegateType;
[RepresentationFor("DelegateMultiset", "type DelegateMultiset = [Delegate]int;")]
public Bpl.TypeSynonymDecl DelegateMultisetTypeDecl = null;
public Bpl.TypeSynonymAnnotation DelegateMultisetType;
[RepresentationFor("MultisetEmpty", "const unique MultisetEmpty: DelegateMultiset;")]
public Bpl.Constant MultisetEmpty = null;
[RepresentationFor("MultisetSingleton", "function {:inline} MultisetSingleton(x: Delegate): DelegateMultiset { MultisetEmpty[x := 1] }")]
public Bpl.Function MultisetSingleton = null;
[RepresentationFor("MultisetPlus", "function {:inline} MultisetPlus(x: DelegateMultiset, y: DelegateMultiset): DelegateMultiset { mapadd(x, y) }")]
public Bpl.Function MultisetPlus = null;
[RepresentationFor("MultisetMinus", "function {:inline} MultisetMinus(x: DelegateMultiset, y: DelegateMultiset): DelegateMultiset { mapiteint(mapgt(x, y), mapsub(x, y), mapconstint(0)) }")]
public Bpl.Function MultisetMinus = null;
[RepresentationFor("Field", "type Field;")]
public Bpl.TypeCtorDecl FieldTypeDecl = null;
public Bpl.CtorType FieldType;
[RepresentationFor("Union", "type {:datatype} Union;")]
public Bpl.TypeCtorDecl UnionTypeDecl = null;
public Bpl.CtorType UnionType;
[RepresentationFor("$DefaultHeapValue", "const unique $DefaultHeapValue : Union;")]
public Bpl.Constant DefaultHeapValue;
[RepresentationFor("Ref", "type Ref;")]
public Bpl.TypeCtorDecl RefTypeDecl = null;
public Bpl.CtorType RefType;
[RepresentationFor("null", "const unique null : Ref;")]
public Bpl.Constant NullRef;
[RepresentationFor("Type", "type {:datatype} Type;")]
public Bpl.TypeCtorDecl TypeTypeDecl = null;
public Bpl.CtorType TypeType;
[RepresentationFor("Real", "type Real;")]
protected Bpl.TypeCtorDecl RealTypeDecl = null;
public Bpl.CtorType RealType;
[RepresentationFor("$DefaultReal", "const unique $DefaultReal : Real;")]
public Bpl.Constant DefaultReal;
#endregion
#region CLR Boxing
[RepresentationFor("$BoxFromBool", "procedure $BoxFromBool(b: bool) returns (r: Ref) free ensures $BoxedValue(r) == Bool2Union(b); { call r := Alloc(); assume $BoxedValue(r) == Bool2Union(b); }")]
public Bpl.Procedure BoxFromBool = null;
[RepresentationFor("$BoxFromInt", "procedure $BoxFromInt(i: int) returns (r: Ref) free ensures $BoxedValue(r) == Int2Union(i); { call r := Alloc(); assume $BoxedValue(r) == Int2Union(i); }")]
public Bpl.Procedure BoxFromInt = null;
[RepresentationFor("$BoxFromReal", "procedure $BoxFromReal(r: Real) returns (rf: Ref) free ensures $BoxedValue(rf) == Real2Union(r); { call rf := Alloc(); assume $BoxedValue(rf) == Real2Union(r); }")]
public Bpl.Procedure BoxFromReal = null;
[RepresentationFor("$BoxFromStruct", "procedure $BoxFromStruct(s: Ref) returns (r: Ref) free ensures $BoxedValue(r) == Struct2Union(s); { call r := Alloc(); assume $BoxedValue(r) == Struct2Union(s); }")]
public Bpl.Procedure BoxFromStruct = null;
[RepresentationFor("$BoxFromUnion", "procedure {:inline 1} $BoxFromUnion(u: Union) returns (r: Ref) { if (is#Ref2Union(u)) { r := refValue#Ref2Union(u); } else { call r := Alloc(); assume $BoxedValue(r) == u; } }")]
public Bpl.Procedure BoxFromUnion = null;
[RepresentationFor("$BoxedValue", "function $BoxedValue(r: Ref): Union;")]
public Bpl.Function BoxedValue = null;
[RepresentationFor("$Unbox2Bool", "function $Unbox2Bool(r: Ref): (bool) { boolValue#Bool2Union($BoxedValue(r)) }")]
public Bpl.Function Unbox2Bool = null;
[RepresentationFor("$Unbox2Int", "function $Unbox2Int(r: Ref): (int) { intValue#Int2Union($BoxedValue(r)) }")]
public Bpl.Function Unbox2Int = null;
[RepresentationFor("$Unbox2Real", "function $Unbox2Real(r: Ref): (Real) { realValue#Real2Union($BoxedValue(r)) }")]
public Bpl.Function Unbox2Real = null;
[RepresentationFor("$Unbox2Struct", "function $Unbox2Struct(r: Ref): (Ref) { structValue#Struct2Union($BoxedValue(r)) }")]
public Bpl.Function Unbox2Struct = null;
[RepresentationFor("$Unbox2Union", "function $Unbox2Union(r: Ref): (Union) { $BoxedValue(r) }")]
public Bpl.Function Unbox2Union = null;
#endregion
#region Conversions
#region Heap values
[RepresentationFor("Union2Bool", "function Union2Bool(u: Union): (bool) { boolValue#Bool2Union(u) }")]
public Bpl.Function Union2Bool = null;
[RepresentationFor("Union2Int", "function Union2Int(u: Union): (int) { intValue#Int2Union(u) }")]
public Bpl.Function Union2Int = null;
[RepresentationFor("Union2Ref", "function Union2Ref(u: Union): (Ref) { refValue#Ref2Union(u) }")]
public Bpl.Function Union2Ref = null;
[RepresentationFor("Union2Real", "function Union2Real(u: Union): (Real) { realValue#Real2Union(u) }")]
public Bpl.Function Union2Real = null;
[RepresentationFor("Union2Struct", "function Union2Struct(u: Union): (Ref) { structValue#Struct2Union(u) }")]
public Bpl.Function Union2Struct = null;
[RepresentationFor("Bool2Union", "function {:constructor} Bool2Union(boolValue: bool): Union;")]
public Bpl.Function Bool2Union = null;
[RepresentationFor("Int2Union", "function {:constructor} Int2Union(intValue: int): Union;")]
public Bpl.Function Int2Union = null;
[RepresentationFor("Ref2Union", "function {:constructor} Ref2Union(refValue: Ref): Union;")]
public Bpl.Function Ref2Union = null;
[RepresentationFor("Real2Union", "function {:constructor} Real2Union(realValue: Real): Union;")]
public Bpl.Function Real2Union = null;
[RepresentationFor("Struct2Union", "function {:constructor} Struct2Union(structValue: Ref): Union;")]
public Bpl.Function Struct2Union = null;
[RepresentationFor("Union2Union", "function {:inline true} Union2Union(u: Union): Union { u }")]
public Bpl.Function Union2Union = null;
public Bpl.Expr ToUnion(Bpl.IToken tok, Bpl.Type boogieType, Bpl.Expr expr) {
Bpl.Function conversion;
if (boogieType == Bpl.Type.Bool)
conversion = this.Bool2Union;
else if (boogieType == Bpl.Type.Int)
conversion = this.Int2Union;
else if (boogieType == RefType)
conversion = this.Ref2Union;
else if (boogieType == RealType)
conversion = this.Real2Union;
else if (boogieType == UnionType)
conversion = this.Union2Union;
else
throw new InvalidOperationException(String.Format("Unknown Boogie type: '{0}'", boogieType.ToString()));
var callConversion = new Bpl.NAryExpr(
tok,
new Bpl.FunctionCall(conversion),
new Bpl.ExprSeq(expr)
);
return callConversion;
}
public Bpl.Expr FromUnion(Bpl.IToken tok, Bpl.Type boogieType, Bpl.Expr expr) {
Bpl.Function conversion = null;
if (boogieType == Bpl.Type.Bool)
conversion = this.Union2Bool;
else if (boogieType == Bpl.Type.Int)
conversion = this.Union2Int;
else if (boogieType == RefType)
conversion = this.Union2Ref;
else if (boogieType == RealType)
conversion = this.Union2Real;
else if (boogieType == UnionType)
conversion = this.Union2Union;
else
throw new InvalidOperationException(String.Format("Unknown Boogie type: '{0}'", boogieType.ToString()));
var callExpr = new Bpl.NAryExpr(
tok,
new Bpl.FunctionCall(conversion),
new Bpl.ExprSeq(expr)
);
callExpr.Type = boogieType;
return callExpr;
}
#endregion
#region Real number conversions
[RepresentationFor("Int2Real", "function Int2Real(int): Real;")]
public Bpl.Function Int2Real = null;
[RepresentationFor("Real2Int", "function Real2Int(Real): int;")]
public Bpl.Function Real2Int = null;
#endregion
#region Real number operations
[RepresentationFor("RealPlus", "function RealPlus(Real, Real): Real;")]
public Bpl.Function RealPlus = null;
[RepresentationFor("RealMinus", "function RealMinus(Real, Real): Real;")]
public Bpl.Function RealMinus = null;
[RepresentationFor("RealTimes", "function RealTimes(Real, Real): Real;")]
public Bpl.Function RealTimes = null;
[RepresentationFor("RealDivide", "function RealDivide(Real, Real): Real;")]
public Bpl.Function RealDivide = null;
[RepresentationFor("RealModulus", "function RealModulus(Real, Real): Real;")]
public Bpl.Function RealModulus = null;
[RepresentationFor("RealLessThan", "function RealLessThan(Real, Real): bool;")]
public Bpl.Function RealLessThan = null;
[RepresentationFor("RealLessThanOrEqual", "function RealLessThanOrEqual(Real, Real): bool;")]
public Bpl.Function RealLessThanOrEqual = null;
[RepresentationFor("RealGreaterThan", "function RealGreaterThan(Real, Real): bool;")]
public Bpl.Function RealGreaterThan = null;
[RepresentationFor("RealGreaterThanOrEqual", "function RealGreaterThanOrEqual(Real, Real): bool;")]
public Bpl.Function RealGreaterThanOrEqual = null;
#endregion
#region Bitwise operations
[RepresentationFor("BitwiseAnd", "function BitwiseAnd(int, int): int;")]
public Bpl.Function BitwiseAnd = null;
[RepresentationFor("BitwiseOr", "function BitwiseOr(int, int): int;")]
public Bpl.Function BitwiseOr = null;
[RepresentationFor("BitwiseExclusiveOr", "function BitwiseExclusiveOr(int, int): int;")]
public Bpl.Function BitwiseExclusiveOr = null;
[RepresentationFor("BitwiseNegation", "function BitwiseNegation(int): int;")]
public Bpl.Function BitwiseNegation = null;
[RepresentationFor("RightShift", "function RightShift(int,int): int;")]
public Bpl.Function RightShift = null;
[RepresentationFor("LeftShift", "function LeftShift(int,int): int;")]
public Bpl.Function LeftShift = null;
#endregion
#endregion
///
/// Creates a fresh BPL variable to represent , deciding
/// on its type based on the heap representation. I.e., the value of this
/// variable represents the value of the expression "typeof(type)".
///
public Bpl.Variable CreateTypeVariable(ITypeReference type, List parents)
{
string typename = TypeHelper.GetTypeName(type, NameFormattingOptions.DocumentationId);
typename = TranslationHelper.TurnStringIntoValidIdentifier(typename);
Bpl.IToken tok = type.Token();
Bpl.TypedIdent tident = new Bpl.TypedIdent(tok, typename, this.TypeType);
Bpl.Constant v = new Bpl.Constant(tok, tident, true /*unique*/, parents, false, null);
return v;
}
public Bpl.Function CreateTypeFunction(ITypeReference type, int parameterCount) {
System.Diagnostics.Debug.Assert(parameterCount >= 0);
string typename = TypeHelper.GetTypeName(type, NameFormattingOptions.DocumentationId);
typename = TranslationHelper.TurnStringIntoValidIdentifier(typename);
Bpl.IToken tok = type.Token();
Bpl.VariableSeq inputs = new Bpl.VariableSeq();
//for (int i = 0; i < parameterCount; i++) {
// inputs.Add(new Bpl.Formal(tok, new Bpl.TypedIdent(tok, "arg"+i, this.TypeType), true));
//}
foreach (var t in TranslationHelper.ConsolidatedGenericParameters(type)) {
var n = t.Name.Value;
var n2 = TranslationHelper.TurnStringIntoValidIdentifier(n);
inputs.Add(new Bpl.Formal(Bpl.Token.NoToken, new Bpl.TypedIdent(Bpl.Token.NoToken, n2, this.TypeType), true));
}
Bpl.Variable output = new Bpl.Formal(tok, new Bpl.TypedIdent(tok, "result", this.TypeType), false);
Bpl.Function func = new Bpl.Function(tok, typename, inputs, output);
var attrib = new Bpl.QKeyValue(Bpl.Token.NoToken, "constructor", new List