summaryrefslogtreecommitdiff
path: root/BCT/BytecodeTranslator
diff options
context:
space:
mode:
authorGravatar Unknown <mbarnett@MBARNETT-LAP2.redmond.corp.microsoft.com>2011-04-27 20:42:05 -0700
committerGravatar Unknown <mbarnett@MBARNETT-LAP2.redmond.corp.microsoft.com>2011-04-27 20:42:05 -0700
commitb7ff2a37f38f5045ae636aa544bbe623dec46187 (patch)
tree9730f7495ae6c9b84744ad0589307efc3e9cc30d /BCT/BytecodeTranslator
parente45880eaaae633b0d4627503d873433af9cb125b (diff)
Trying to get structs supported.
Diffstat (limited to 'BCT/BytecodeTranslator')
-rw-r--r--BCT/BytecodeTranslator/ExpressionTraverser.cs39
-rw-r--r--BCT/BytecodeTranslator/MetadataTraverser.cs46
-rw-r--r--BCT/BytecodeTranslator/Sink.cs34
3 files changed, 118 insertions, 1 deletions
diff --git a/BCT/BytecodeTranslator/ExpressionTraverser.cs b/BCT/BytecodeTranslator/ExpressionTraverser.cs
index b077d66c..b189b4eb 100644
--- a/BCT/BytecodeTranslator/ExpressionTraverser.cs
+++ b/BCT/BytecodeTranslator/ExpressionTraverser.cs
@@ -586,6 +586,35 @@ namespace BytecodeTranslator
public override void Visit(IAssignment assignment) {
Contract.Assert(TranslatedExpressions.Count == 0);
+ #region Special case for s := default(S) when S is a struct
+
+ // The C# source "s = new S()" when S is a struct is compiled
+ // into an "initobj" instruction. That is decompiled into the
+ // assignment: "s = DefaultValue(S)".
+ // We translate it as a call to a pseduo-ctor that is created for S:
+ // "s := S.#default_ctor()".
+
+ if (assignment.Target.Type.ResolvedType.IsStruct &&
+ assignment.Target.Type.TypeCode == PrimitiveTypeCode.NotPrimitive &&
+ assignment.Source is IDefaultValue) {
+
+ this.Visit(assignment.Target);
+ var s = this.TranslatedExpressions.Pop();
+
+ var structType = assignment.Target.Type;
+ Bpl.IToken tok = assignment.Token();
+ var proc = this.sink.FindOrCreateProcedureForDefaultStructCtor(structType);
+ string methodname = proc.Name;
+ var inexpr = new List<Bpl.Expr>();
+ var outvars = new List<Bpl.IdentifierExpr>();
+ outvars.Add((Bpl.IdentifierExpr)s);
+ var call = new Bpl.CallCmd(tok, methodname, inexpr, outvars);
+ this.StmtTraverser.StmtBuilder.Add(call);
+
+ return;
+ }
+ #endregion
+
#region Transform Right Hand Side ...
this.Visit(assignment.Source);
Bpl.Expr sourceexp = this.TranslatedExpressions.Pop();
@@ -938,6 +967,12 @@ namespace BytecodeTranslator
{
var tok = conversion.ValueToConvert.Token();
Visit(conversion.ValueToConvert);
+ var boogieTypeOfValue = this.sink.CciTypeToBoogie(conversion.ValueToConvert.Type);
+ var boogieTypeToBeConvertedTo = this.sink.CciTypeToBoogie(conversion.TypeAfterConversion);
+ if (boogieTypeOfValue == boogieTypeToBeConvertedTo) {
+ // then this conversion is a nop, just ignore it
+ return;
+ }
var exp = TranslatedExpressions.Pop();
switch (conversion.TypeAfterConversion.TypeCode) {
case PrimitiveTypeCode.Int16:
@@ -950,6 +985,10 @@ namespace BytecodeTranslator
new Bpl.NAryExpr(tok, new Bpl.IfThenElse(tok), new Bpl.ExprSeq(exp, Bpl.Expr.Literal(1), Bpl.Expr.Literal(0)))
);
return;
+ case PrimitiveTypeCode.IntPtr:
+ // just ignore the conversion. REVIEW: is that the right thing to do?
+ this.TranslatedExpressions.Push(exp);
+ return;
default:
throw new NotImplementedException();
}
diff --git a/BCT/BytecodeTranslator/MetadataTraverser.cs b/BCT/BytecodeTranslator/MetadataTraverser.cs
index bbcc81f5..9482573f 100644
--- a/BCT/BytecodeTranslator/MetadataTraverser.cs
+++ b/BCT/BytecodeTranslator/MetadataTraverser.cs
@@ -73,6 +73,7 @@ namespace BytecodeTranslator {
return; // enums just are translated as ints
} else if (typeDefinition.IsStruct) {
sink.FindOrCreateType(typeDefinition);
+ CreateDefaultStructConstructor(typeDefinition);
base.Visit(typeDefinition);
} else {
Console.WriteLine("Unknown kind of type definition '{0}' was found",
@@ -81,6 +82,49 @@ namespace BytecodeTranslator {
}
}
+ private void CreateDefaultStructConstructor(ITypeDefinition typeDefinition) {
+ Contract.Requires(typeDefinition.IsStruct);
+
+ var proc = this.sink.FindOrCreateProcedureForDefaultStructCtor(typeDefinition);
+
+ var stmtBuilder = new Bpl.StmtListBuilder();
+
+ foreach (var f in typeDefinition.Fields) {
+ Bpl.Expr e;
+ var bplType = this.sink.CciTypeToBoogie(f.Type);
+ if (bplType == Bpl.Type.Int) {
+ e = Bpl.Expr.Literal(0);
+ e.Type = Bpl.Type.Int;
+ } else if (bplType == Bpl.Type.Bool) {
+ e = Bpl.Expr.False;
+ e.Type = Bpl.Type.Bool;
+ } else {
+ throw new NotImplementedException("Don't know how to translate type");
+ }
+
+ var fExp = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(f));
+ var o = Bpl.Expr.Ident(proc.OutParams[0]);
+ var c = this.sink.Heap.WriteHeap(Bpl.Token.NoToken, o, fExp, e, true);
+ stmtBuilder.Add(c);
+ }
+
+ var attrib = new Bpl.QKeyValue(typeDefinition.Token(), "inline", new List<object>(1), null); // TODO: Need to have it be {:inine 1} (and not just {:inline})?
+ Bpl.Implementation impl =
+ new Bpl.Implementation(Bpl.Token.NoToken,
+ proc.Name,
+ new Bpl.TypeVariableSeq(),
+ proc.InParams,
+ proc.OutParams,
+ new Bpl.VariableSeq(),
+ stmtBuilder.Collect(Bpl.Token.NoToken),
+ attrib,
+ new Bpl.Errors()
+ );
+
+ impl.Proc = (Bpl.Procedure) proc; // TODO: get rid of cast
+ this.sink.TranslatedProgram.TopLevelDeclarations.Add(impl);
+ }
+
private bool sawCctor = false;
private void CreateStaticConstructor(ITypeDefinition typeDefinition) {
@@ -290,7 +334,7 @@ namespace BytecodeTranslator {
foreach (var f in method.ContainingTypeDefinition.Fields) {
if (f.IsStatic == method.IsStatic) {
var a = new Assignment() {
- Source = new DefaultValue() { Type = f.Type, },
+ Source = new DefaultValue() { DefaultValueType = f.Type, Type = f.Type, },
Target = new TargetExpression() { Definition = f, Instance = method.IsConstructor ? thisExp : null, Type = f.Type },
Type = f.Type,
};
diff --git a/BCT/BytecodeTranslator/Sink.cs b/BCT/BytecodeTranslator/Sink.cs
index c6fadd5f..488edb9f 100644
--- a/BCT/BytecodeTranslator/Sink.cs
+++ b/BCT/BytecodeTranslator/Sink.cs
@@ -415,6 +415,40 @@ namespace BytecodeTranslator {
return procAndFormalMap.Decl;
}
+ /// <summary>
+ /// Struct "creation" (source code that looks like "new S()" for a struct type S) is modeled
+ /// by a call to the nullary "ctor" that initializes all of the structs fields to zero-
+ /// equivalent values. Note that the generated procedure has no contract. So if the struct
+ /// is defined in an assembly that is not being translated, then its behavior is unspecified.
+ /// </summary>
+ /// <param name="structType">A type reference to the value type for which the ctor should be returned.</param>
+ /// <returns>A nullary procedure that returns an initialized value of type <paramref name="structType"/>.</returns>
+ public Bpl.DeclWithFormals FindOrCreateProcedureForDefaultStructCtor(ITypeReference structType) {
+ Contract.Requires(structType.IsValueType);
+
+ ProcedureInfo procAndFormalMap;
+ var key = structType.InternedKey;
+ if (!this.declaredMethods.TryGetValue(key, out procAndFormalMap)) {
+ var typename = TranslationHelper.TurnStringIntoValidIdentifier(TypeHelper.GetTypeName(structType));
+ var tok = structType.Token();
+ var selfType = new Bpl.MapType(Bpl.Token.NoToken, new Bpl.TypeVariableSeq(), new Bpl.TypeSeq(Heap.FieldType), Heap.BoxType);
+ var selfOut = new Bpl.Formal(tok, new Bpl.TypedIdent(tok, "this", selfType), false);
+ var outvars = new Bpl.Formal[]{ selfOut };
+ var proc = new Bpl.Procedure(Bpl.Token.NoToken, typename + ".#default_ctor",
+ new Bpl.TypeVariableSeq(),
+ new Bpl.VariableSeq(), // in
+ new Bpl.VariableSeq(outvars),
+ new Bpl.RequiresSeq(),
+ new Bpl.IdentifierExprSeq(), // modifies
+ new Bpl.EnsuresSeq()
+ );
+ this.TranslatedProgram.TopLevelDeclarations.Add(proc);
+ procAndFormalMap = new ProcedureInfo(proc, new Dictionary<IParameterDefinition, MethodParameter>(), this.RetVariable);
+ this.declaredMethods.Add(key, procAndFormalMap);
+ }
+ return procAndFormalMap.Decl;
+ }
+
// TODO: Fix test to return true iff method is marked with the "real" [Pure] attribute
// also, should it return true for properties and all of the other things the tools
// consider pure?