X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fflowanalysis.cs;h=5efeccb8fb612cac28e11157553ff4285aa1dc45;hb=490a86b6ecc02fbe31445ad201f01e90678e2c21;hp=1becb532d4c0159e8395b127f57a95b348427df6;hpb=6db9dc225c63a48b6d85e412ee5cc7a8100db9ea;p=mono.git diff --git a/mcs/mcs/flowanalysis.cs b/mcs/mcs/flowanalysis.cs index 1becb532d4c..5efeccb8fb6 100644 --- a/mcs/mcs/flowanalysis.cs +++ b/mcs/mcs/flowanalysis.cs @@ -1,9 +1,10 @@ // // flowanalyis.cs: The control flow analysis code // -// Author: +// Authors: // Martin Baulig (martin@ximian.com) // Raja R Harinath (rharinath@novell.com) +// Marek Safar (marek.safar@gmail.com) // // Copyright 2001, 2002, 2003 Ximian, Inc. // Copyright 2003-2008 Novell, Inc. @@ -236,22 +237,27 @@ namespace Mono.CSharp public bool IsFieldAssigned (VariableInfo var, string name) { - if (!var.IsParameter && IsUnreachable) + if (/*!var.IsParameter &&*/ IsUnreachable) return true; - return var.IsFieldAssigned (locals, name); + return var.IsStructFieldAssigned (locals, name); } public void SetFieldAssigned (VariableInfo var, string name) { - if (!var.IsParameter && IsUnreachable) + if (/*!var.IsParameter &&*/ IsUnreachable) return; - var.SetFieldAssigned (locals, name); + var.SetStructFieldAssigned (locals, name); } public bool IsUnreachable { - get { return is_unreachable; } + get { + return is_unreachable; + } + set { + is_unreachable = value; + } } public void ResetBarrier () @@ -450,7 +456,7 @@ namespace Mono.CSharp return CurrentUsageVector.IsAssigned (vi, false); } - public bool IsFieldAssigned (VariableInfo vi, string field_name) + public bool IsStructFieldAssigned (VariableInfo vi, string field_name) { return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name); } @@ -715,10 +721,10 @@ namespace Mono.CSharp protected override UsageVector Merge () { for (UsageVector origin = return_origins; origin != null; origin = origin.Next) - Block.ParametersBlock.CheckOutParameters (origin, origin.Location); + Block.ParametersBlock.CheckOutParameters (origin); UsageVector vector = base.Merge (); - Block.ParametersBlock.CheckOutParameters (vector, Block.loc); + Block.ParametersBlock.CheckOutParameters (vector); // Note: we _do_not_ merge in the return origins return vector; } @@ -1061,8 +1067,7 @@ namespace Mono.CSharp } // - // This is used by the flow analysis code to keep track of the type of local variables - // and variables. + // This is used by the flow analysis code to keep track of the type of local variables. // // The flow code uses a BitVector to keep track of whether a variable has been assigned // or not. This is easy for fundamental types (int, char etc.) or reference types since @@ -1076,8 +1081,6 @@ namespace Mono.CSharp // public class TypeInfo { - public readonly TypeSpec Type; - // // Total number of bits a variable of this type consumes in the flow vector. // @@ -1097,7 +1100,7 @@ namespace Mono.CSharp // // If this is a struct. // - public readonly bool IsStruct; + public readonly bool IsStruct; // // If this is a struct, all fields which are structs theirselves. @@ -1106,6 +1109,8 @@ namespace Mono.CSharp readonly StructInfo struct_info; private static Dictionary type_hash; + + static readonly TypeInfo simple_type = new TypeInfo (1); static TypeInfo () { @@ -1118,34 +1123,11 @@ namespace Mono.CSharp StructInfo.field_type_hash = new Dictionary (); } - public static TypeInfo GetTypeInfo (TypeSpec type) + TypeInfo (int totalLength) { - TypeInfo info; - if (type_hash.TryGetValue (type, out info)) - return info; - - info = new TypeInfo (type); - type_hash.Add (type, info); - return info; + this.TotalLength = totalLength; } - - private TypeInfo (TypeSpec type) - { - this.Type = type; - - struct_info = StructInfo.GetStructInfo (type); - if (struct_info != null) { - Length = struct_info.Length; - TotalLength = struct_info.TotalLength; - SubStructInfo = struct_info.StructFields; - IsStruct = true; - } else { - Length = 0; - TotalLength = 1; - IsStruct = false; - } - } - + TypeInfo (StructInfo struct_info, int offset) { this.struct_info = struct_info; @@ -1153,10 +1135,9 @@ namespace Mono.CSharp this.Length = struct_info.Length; this.TotalLength = struct_info.TotalLength; this.SubStructInfo = struct_info.StructFields; - this.Type = struct_info.Type; this.IsStruct = true; } - + public int GetFieldIndex (string name) { if (struct_info == null) @@ -1165,7 +1146,7 @@ namespace Mono.CSharp return struct_info [name]; } - public TypeInfo GetSubStruct (string name) + public TypeInfo GetStructField (string name) { if (struct_info == null) return null; @@ -1173,6 +1154,26 @@ namespace Mono.CSharp return struct_info.GetStructField (name); } + public static TypeInfo GetTypeInfo (TypeSpec type) + { + if (!type.IsStruct) + return simple_type; + + TypeInfo info; + if (type_hash.TryGetValue (type, out info)) + return info; + + var struct_info = StructInfo.GetStructInfo (type); + if (struct_info != null) { + info = new TypeInfo (struct_info, 0); + } else { + info = simple_type; + } + + type_hash.Add (type, info); + return info; + } + // // A struct's constructor must always assign all fields. // This method checks whether it actually does so. @@ -1187,11 +1188,7 @@ namespace Mono.CSharp for (int i = 0; i < struct_info.Count; i++) { var field = struct_info.Fields [i]; - // Fixed size buffers are not subject to definite assignment checking - if (field is FixedFieldSpec) - continue; - - if (!branching.IsFieldAssigned (vi, field.Name)) { + if (!branching.IsStructFieldAssigned (vi, field.Name)) { if (field.MemberDefinition is Property.BackingField) { ec.Report.Error (843, loc, "An automatically implemented property `{0}' must be fully assigned before control leaves the constructor. Consider calling the default struct contructor from a constructor initializer", @@ -1210,76 +1207,46 @@ namespace Mono.CSharp public override string ToString () { - return String.Format ("TypeInfo ({0}:{1}:{2}:{3})", - Type, Offset, Length, TotalLength); + return String.Format ("TypeInfo ({0}:{1}:{2})", + Offset, Length, TotalLength); } - class StructInfo { - public readonly TypeSpec Type; - public readonly FieldSpec[] Fields; + class StructInfo + { + readonly List fields; public readonly TypeInfo[] StructFields; - public readonly int Count; - public readonly int CountPublic; - public readonly int CountNonPublic; public readonly int Length; public readonly int TotalLength; - public readonly bool HasStructFields; public static Dictionary field_type_hash; private Dictionary struct_field_hash; private Dictionary field_hash; - protected bool InTransit = false; + bool InTransit; - // Private constructor. To save memory usage, we only need to create one instance - // of this class per struct type. - private StructInfo (TypeSpec type) + // + // We only need one instance per type + // + StructInfo (TypeSpec type) { - this.Type = type; - field_type_hash.Add (type, this); - TypeContainer tc = type.MemberDefinition as TypeContainer; - - var public_fields = new List (); - var non_public_fields = new List (); - - if (tc != null) { - var fields = tc.Fields; - - if (fields != null) { - foreach (FieldBase field in fields) { - if ((field.ModFlags & Modifiers.STATIC) != 0) - continue; - if ((field.ModFlags & Modifiers.PUBLIC) != 0) - public_fields.Add (field.Spec); - else - non_public_fields.Add (field.Spec); - } - } - } - - CountPublic = public_fields.Count; - CountNonPublic = non_public_fields.Count; - Count = CountPublic + CountNonPublic; - - Fields = new FieldSpec[Count]; - public_fields.CopyTo (Fields, 0); - non_public_fields.CopyTo (Fields, CountPublic); + fields = MemberCache.GetAllFieldsForDefiniteAssignment (type); struct_field_hash = new Dictionary (); - field_hash = new Dictionary (); + field_hash = new Dictionary (fields.Count); - Length = 0; - StructFields = new TypeInfo [Count]; - StructInfo[] sinfo = new StructInfo [Count]; + StructFields = new TypeInfo[fields.Count]; + StructInfo[] sinfo = new StructInfo[fields.Count]; InTransit = true; - for (int i = 0; i < Count; i++) { - var field = Fields [i]; + for (int i = 0; i < fields.Count; i++) { + var field = fields [i]; + + if (field.MemberType.IsStruct) + sinfo [i] = GetStructInfo (field.MemberType); - sinfo [i] = GetStructInfo (field.MemberType); if (sinfo [i] == null) field_hash.Add (field.Name, ++Length); else if (sinfo [i].InTransit) { @@ -1291,21 +1258,32 @@ namespace Mono.CSharp InTransit = false; TotalLength = Length + 1; - for (int i = 0; i < Count; i++) { - var field = Fields [i]; + for (int i = 0; i < fields.Count; i++) { + var field = fields [i]; if (sinfo [i] == null) continue; field_hash.Add (field.Name, TotalLength); - HasStructFields = true; StructFields [i] = new TypeInfo (sinfo [i], TotalLength); struct_field_hash.Add (field.Name, StructFields [i]); TotalLength += sinfo [i].TotalLength; } } + public int Count { + get { + return fields.Count; + } + } + + public List Fields { + get { + return fields; + } + } + public int this [string name] { get { int val; @@ -1327,7 +1305,7 @@ namespace Mono.CSharp public static StructInfo GetStructInfo (TypeSpec type) { - if (!type.IsStruct || type.BuiltinType > 0) + if (type.BuiltinType > 0) return null; StructInfo info; @@ -1346,13 +1324,13 @@ namespace Mono.CSharp // it has been assigned or not, but for structs, we need this information for each of its fields. // public class VariableInfo { - public readonly string Name; - public readonly TypeInfo TypeInfo; + readonly string Name; + readonly TypeInfo TypeInfo; // // The bit offset of this variable in the flow vector. // - public readonly int Offset; + readonly int Offset; // // The number of bits this variable needs in the flow vector. @@ -1366,17 +1344,9 @@ namespace Mono.CSharp // public readonly bool IsParameter; - public readonly LocalVariable LocalInfo; - - readonly VariableInfo Parent; VariableInfo[] sub_info; - bool is_ever_assigned; - public bool IsEverAssigned { - get { return is_ever_assigned; } - } - - protected VariableInfo (string name, TypeSpec type, int offset) + VariableInfo (string name, TypeSpec type, int offset) { this.Name = name; this.Offset = offset; @@ -1387,16 +1357,14 @@ namespace Mono.CSharp Initialize (); } - protected VariableInfo (VariableInfo parent, TypeInfo type) + VariableInfo (VariableInfo parent, TypeInfo type) { this.Name = parent.Name; this.TypeInfo = type; this.Offset = parent.Offset + type.Offset; - this.Parent = parent; this.Length = type.TotalLength; this.IsParameter = parent.IsParameter; - this.LocalInfo = parent.LocalInfo; Initialize (); } @@ -1417,7 +1385,6 @@ namespace Mono.CSharp public VariableInfo (LocalVariable local_info, int offset) : this (local_info.Name, local_info.Type, offset) { - this.LocalInfo = local_info; this.IsParameter = false; } @@ -1429,20 +1396,7 @@ namespace Mono.CSharp public bool IsAssigned (ResolveContext ec) { - return !ec.DoFlowAnalysis || - (ec.OmitStructFlowAnalysis && TypeInfo.Type.IsStruct) || - ec.CurrentBranching.IsAssigned (this); - } - - public bool IsAssigned (ResolveContext ec, Location loc) - { - if (IsAssigned (ec)) - return true; - - ec.Report.Error (165, loc, - "Use of unassigned local variable `" + Name + "'"); - ec.CurrentBranching.SetAssigned (this); - return false; + return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this); } public bool IsAssigned (MyBitVector vector) @@ -1453,69 +1407,54 @@ namespace Mono.CSharp if (vector [Offset]) return true; - // FIXME: Fix SetFieldAssigned to set the whole range like SetAssigned below. Then, get rid of this stanza - for (VariableInfo parent = Parent; parent != null; parent = parent.Parent) { - if (vector [parent.Offset]) { - // 'parent' is assigned, but someone forgot to note that all its components are assigned too - parent.SetAssigned (vector); - return true; - } - } - - // Return unless this is a struct. + // Unless this is a struct if (!TypeInfo.IsStruct) return false; - // Ok, so each field must be assigned. - for (int i = 0; i < TypeInfo.Length; i++) { - if (!vector [Offset + i + 1]) + // + // Following case cannot be handled fully by SetStructFieldAssigned + // because we may encounter following case + // + // struct A { B b } + // struct B { int value; } + // + // setting a.b.value is propagated only to B's vector and not upwards to possible parents + // + // + // Each field must be assigned + // + for (int i = Offset + 1; i <= TypeInfo.Length + Offset; i++) { + if (!vector[i]) return false; } // Ok, now check all fields which are structs. for (int i = 0; i < sub_info.Length; i++) { - VariableInfo sinfo = sub_info [i]; + VariableInfo sinfo = sub_info[i]; if (sinfo == null) continue; if (!sinfo.IsAssigned (vector)) return false; } - + vector [Offset] = true; - is_ever_assigned = true; return true; } - public void SetAssigned (ResolveContext ec) - { - if (ec.DoFlowAnalysis) - ec.CurrentBranching.SetAssigned (this); - } + public bool IsEverAssigned { get; set; } - public void SetAssigned (MyBitVector vector) + public bool IsStructFieldAssigned (ResolveContext ec, string name) { - if (Length == 1) - vector [Offset] = true; - else - vector.SetRange (Offset, Length); - is_ever_assigned = true; + return !ec.DoFlowAnalysis || ec.CurrentBranching.IsStructFieldAssigned (this, name); } - public bool IsFieldAssigned (ResolveContext ec, string name, Location loc) + public bool IsFullyInitialized (BlockContext bc, Location loc) { - if (!ec.DoFlowAnalysis || - ec.OmitStructFlowAnalysis && TypeInfo.IsStruct || - ec.CurrentBranching.IsFieldAssigned (this, name)) - return true; - - ec.Report.Error (170, loc, - "Use of possibly unassigned field `" + name + "'"); - ec.CurrentBranching.SetFieldAssigned (this, name); - return false; + return TypeInfo.IsFullyInitialized (bc, this, loc); } - public bool IsFieldAssigned (MyBitVector vector, string field_name) + public bool IsStructFieldAssigned (MyBitVector vector, string field_name) { int field_idx = TypeInfo.GetFieldIndex (field_name); @@ -1525,26 +1464,65 @@ namespace Mono.CSharp return vector [Offset + field_idx]; } - public void SetFieldAssigned (ResolveContext ec, string name) + public void SetStructFieldAssigned (ResolveContext ec, string name) { if (ec.DoFlowAnalysis) ec.CurrentBranching.SetFieldAssigned (this, name); } - public void SetFieldAssigned (MyBitVector vector, string field_name) + public void SetAssigned (ResolveContext ec) + { + if (ec.DoFlowAnalysis) + ec.CurrentBranching.SetAssigned (this); + } + + public void SetAssigned (MyBitVector vector) + { + if (Length == 1) + vector[Offset] = true; + else + vector.SetRange (Offset, Length); + + IsEverAssigned = true; + } + + public void SetStructFieldAssigned (MyBitVector vector, string field_name) { + if (vector[Offset]) + return; + int field_idx = TypeInfo.GetFieldIndex (field_name); if (field_idx == 0) return; - vector [Offset + field_idx] = true; - is_ever_assigned = true; + var complex_field = TypeInfo.GetStructField (field_name); + if (complex_field != null) { + vector.SetRange (Offset + complex_field.Offset, complex_field.TotalLength); + } else { + vector[Offset + field_idx] = true; + } + + IsEverAssigned = true; + + // + // Each field must be assigned + // + for (int i = Offset + 1; i < TypeInfo.TotalLength + Offset; i++) { + if (!vector[i]) + return; + } + + // + // Set master struct flag to assigned when all tested struct + // fields have been assigned + // + vector[Offset] = true; } - public VariableInfo GetSubStruct (string name) + public VariableInfo GetStructFieldInfo (string fieldName) { - TypeInfo type = TypeInfo.GetSubStruct (name); + TypeInfo type = TypeInfo.GetStructField (fieldName); if (type == null) return null;