//-----------------------------------------------------------------------------
//
// 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);
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]Box;")]
public Bpl.Variable ArrayContentsVariable = null;
[RepresentationFor("$ArrayLength", "function $ArrayLength(Ref): int;")]
public Bpl.Function ArrayLengthFunction = null;
public abstract Bpl.Variable CreateFieldVariable(IFieldReference field);
public abstract Bpl.Variable BoxField { get; }
#region Boogie Types
[RepresentationFor("Field", "type Field;")]
public Bpl.TypeCtorDecl FieldTypeDecl = null;
public Bpl.CtorType FieldType;
[RepresentationFor("Box", "type Box;")]
public Bpl.TypeCtorDecl BoxTypeDecl = null;
public Bpl.CtorType BoxType;
[RepresentationFor("$DefaultBox", "const unique $DefaultBox : Box;")]
public Bpl.Constant DefaultBox;
[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 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 Conversions
#region Heap values
[RepresentationFor("Box2Bool", "function Box2Bool(Box): bool;")]
public Bpl.Function Box2Bool = null;
[RepresentationFor("Box2Int", "function Box2Int(Box): int;")]
public Bpl.Function Box2Int = null;
[RepresentationFor("Box2Ref", "function Box2Ref(Box): Ref;")]
public Bpl.Function Box2Ref = null;
[RepresentationFor("Box2Real", "function Box2Real(Box): Real;")]
public Bpl.Function Box2Real = null;
[RepresentationFor("Bool2Box", "function Bool2Box(bool): Box;")]
public Bpl.Function Bool2Box = null;
[RepresentationFor("Int2Box", "function Int2Box(int): Box;")]
public Bpl.Function Int2Box = null;
[RepresentationFor("Ref2Box", "function Ref2Box(Ref): Box;")]
public Bpl.Function Ref2Box = null;
[RepresentationFor("Real2Box", "function Real2Box(Real): Box;")]
public Bpl.Function Real2Box = null;
[RepresentationFor("Box2Box", "function {:inline true} Box2Box(b: Box): Box { b }")]
public Bpl.Function Box2Box = null;
public Bpl.Expr Box(Bpl.IToken tok, Bpl.Type boogieType, Bpl.Expr expr) {
Bpl.Function conversion;
if (boogieType == Bpl.Type.Bool)
conversion = this.Bool2Box;
else if (boogieType == Bpl.Type.Int)
conversion = this.Int2Box;
else if (boogieType == RefType)
conversion = this.Ref2Box;
else if (boogieType == RealType)
conversion = this.Real2Box;
else if (boogieType == BoxType)
conversion = this.Box2Box;
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 Unbox(Bpl.IToken tok, Bpl.Type boogieType, Bpl.Expr expr) {
Bpl.Function conversion = null;
if (boogieType == Bpl.Type.Bool)
conversion = this.Box2Bool;
else if (boogieType == Bpl.Type.Int)
conversion = this.Box2Int;
else if (boogieType == RefType)
conversion = this.Box2Ref;
else if (boogieType == RealType)
conversion = this.Box2Real;
else if (boogieType == BoxType)
conversion = this.Box2Box;
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("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;
#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)
{
string typename = TypeHelper.GetTypeName(type);
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);
return v;
}
public Bpl.Function CreateTypeFunction(ITypeReference type, int parameterCount) {
System.Diagnostics.Debug.Assert(parameterCount > 0);
string typename = TypeHelper.GetTypeName(type);
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));
}
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);
return func;
}
public abstract Bpl.Variable CreateEventVariable(IEventDefinition e);
public abstract Bpl.Expr ReadHeap(Bpl.Expr o, Bpl.Expr f, AccessType accessType, Bpl.Type unboxType);
public abstract Bpl.Cmd WriteHeap(Bpl.IToken tok, Bpl.Expr o, Bpl.Expr f, Bpl.Expr value, AccessType accessType, Bpl.Type boxType);
[RepresentationFor("$DynamicType", "function $DynamicType(Ref): Type;")]
protected Bpl.Function DynamicTypeFunction = null;
///
/// Returns the BPL expression that corresponds to the value of the dynamic type
/// of the object represented by the expression .
///
public Bpl.Expr DynamicType(Bpl.Expr o) {
// $DymamicType(o)
var callDynamicType = new Bpl.NAryExpr(
o.tok,
new Bpl.FunctionCall(this.DynamicTypeFunction),
new Bpl.ExprSeq(o)
);
return callDynamicType;
}
[RepresentationFor("$TypeOf", "function $TypeOf(Type): Ref;")]
public Bpl.Function TypeOfFunction = null;
[RepresentationFor("$As", "function $As(Ref, Type): Ref;")]
public Bpl.Function AsFunction = null;
protected readonly string CommonText =
@"var $Alloc: [Ref] bool;
procedure {:inline 1} Alloc() returns (x: Ref)
modifies $Alloc;
{
assume $Alloc[x] == false && x != null;
$Alloc[x] := true;
}
function $TypeOfInv(Ref): Type;
axiom (forall t: Type :: {$TypeOf(t)} $TypeOfInv($TypeOf(t)) == t);
procedure {:inline 1} System.Object.GetType(this: Ref) returns ($result: Ref)
{
$result := $TypeOf($DynamicType(this));
}
axiom Box2Int($DefaultBox) == 0;
axiom Box2Bool($DefaultBox) == false;
axiom Box2Ref($DefaultBox) == null;
axiom (forall x: int :: { Int2Box(x) } Box2Int(Int2Box(x)) == x );
axiom (forall x: bool :: { Bool2Box(x) } Box2Bool(Bool2Box(x)) == x );
axiom (forall x: Ref :: { Ref2Box(x) } Box2Ref(Ref2Box(x)) == x );
function $ThreadDelegate(Ref) : Ref;
procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ParameterizedThreadStart(this: Ref, start$in: Ref)
{
assume $ThreadDelegate(this) == start$in;
}
procedure {:inline 1} System.Threading.Thread.Start$System.Object(this: Ref, parameter$in: Ref)
{
call {:async} Wrapper_System.Threading.ParameterizedThreadStart.Invoke$System.Object($ThreadDelegate(this), parameter$in);
}
procedure {:inline 1} Wrapper_System.Threading.ParameterizedThreadStart.Invoke$System.Object(this: Ref, obj$in: Ref) {
$Exception := null;
call System.Threading.ParameterizedThreadStart.Invoke$System.Object(this, obj$in);
}
procedure {:extern} System.Threading.ParameterizedThreadStart.Invoke$System.Object(this: Ref, obj$in: Ref);
procedure {:inline 1} System.Threading.Thread.#ctor$System.Threading.ThreadStart(this: Ref, start$in: Ref)
{
assume $ThreadDelegate(this) == start$in;
}
procedure {:inline 1} System.Threading.Thread.Start(this: Ref)
{
call {:async} Wrapper_System.Threading.ThreadStart.Invoke($ThreadDelegate(this));
}
procedure {:inline 1} Wrapper_System.Threading.ThreadStart.Invoke(this: Ref) {
$Exception := null;
call System.Threading.ThreadStart.Invoke(this);
}
procedure {:extern} System.Threading.ThreadStart.Invoke(this: Ref);
procedure DelegateAdd(a: Ref, b: Ref) returns (c: Ref)
{
var m: int;
var o: Ref;
if (a == null) {
c := b;
return;
} else if (b == null) {
c := a;
return;
}
call m, o := GetFirstElement(b);
call c := Alloc();
$Head[c] := $Head[a];
$Next[c] := $Next[a];
$Method[c] := $Method[a];
$Receiver[c] := $Receiver[a];
call c := DelegateAddHelper(c, m, o);
}
procedure DelegateRemove(a: Ref, b: Ref) returns (c: Ref)
{
var m: int;
var o: Ref;
if (a == null) {
c := null;
return;
} else if (b == null) {
c := a;
return;
}
call m, o := GetFirstElement(b);
call c := Alloc();
$Head[c] := $Head[a];
$Next[c] := $Next[a];
$Method[c] := $Method[a];
$Receiver[c] := $Receiver[a];
call c := DelegateRemoveHelper(c, m, o);
}
procedure GetFirstElement(i: Ref) returns (m: int, o: Ref)
{
var first: Ref;
first := $Next[i][$Head[i]];
m := $Method[i][first];
o := $Receiver[i][first];
}
procedure DelegateAddHelper(oldi: Ref, m: int, o: Ref) returns (i: Ref)
{
var x: Ref;
var h: Ref;
if (oldi == null) {
call i := Alloc();
call x := Alloc();
$Head[i] := x;
$Next[i] := $Next[i][x := x];
} else {
i := oldi;
}
h := $Head[i];
$Method[i] := $Method[i][h := m];
$Receiver[i] := $Receiver[i][h := o];
call x := Alloc();
$Next[i] := $Next[i][x := $Next[i][h]];
$Next[i] := $Next[i][h := x];
$Head[i] := x;
}
procedure DelegateRemoveHelper(oldi: Ref, m: int, o: Ref) returns (i: Ref)
{
var prev: Ref;
var iter: Ref;
var niter: Ref;
i := oldi;
if (i == null) {
return;
}
prev := null;
iter := $Head[i];
while (true) {
niter := $Next[i][iter];
if (niter == $Head[i]) {
break;
}
if ($Method[i][niter] == m && $Receiver[i][niter] == o) {
prev := iter;
}
iter := niter;
}
if (prev == null) {
return;
}
$Next[i] := $Next[i][prev := $Next[i][$Next[i][prev]]];
if ($Next[i][$Head[i]] == $Head[i]) {
i := null;
}
}
";
[RepresentationFor("$Head", "var $Head: [Ref]Ref;")]
public Bpl.GlobalVariable DelegateHead = null;
[RepresentationFor("$Next", "var $Next: [Ref][Ref]Ref;")]
public Bpl.GlobalVariable DelegateNext = null;
[RepresentationFor("$Method", "var $Method: [Ref][Ref]int;")]
public Bpl.GlobalVariable DelegateMethod = null;
[RepresentationFor("$Receiver", "var $Receiver: [Ref][Ref]Ref;")]
public Bpl.GlobalVariable DelegateReceiver = null;
[RepresentationFor("$Exception", "var {:thread_local} $Exception: Ref;")]
public Bpl.GlobalVariable ExceptionVariable = null;
}
public abstract class HeapFactory {
///
/// Returns two things: an object that determines the heap representation,
/// and (optionally) an initial program that contains declarations needed
/// for the heap representation.
///
///
/// The heap might need to generate declarations so it needs access to the Sink.
///
///
/// false if and only if an error occurrs and the heap and/or program are not in a
/// good state to be used.
///
public abstract bool MakeHeap(Sink sink, out Heap heap, out Bpl.Program/*?*/ program);
}
}