📄 flowanalysis.cs
字号:
"a cycle in the structure layout", type, field.Name, sinfo [i].Type)); sinfo [i] = null; return; } } InTransit = false; TotalLength = Length + 1; for (int i = 0; i < Count; i++) { FieldInfo field = (FieldInfo) 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 this [string name] { get { if (field_hash.Contains (name)) return (int) field_hash [name]; else return 0; } } public TypeInfo GetStructField (string name) { return (TypeInfo) struct_field_hash [name]; } public static StructInfo GetStructInfo (Type type) { if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) || TypeManager.IsBuiltinType (type)) return null; StructInfo info = (StructInfo) field_type_hash [type]; if (info != null) return info; return new StructInfo (type); } public static StructInfo GetStructInfo (TypeContainer tc) { StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder]; if (info != null) return info; return new StructInfo (tc.TypeBuilder); } } } // <summary> // This is used by the flow analysis code to store information about a single local variable // or parameter. Depending on the variable's type, we need to allocate one or more elements // in the BitVector - if it's a fundamental or reference type, we just need to know whether // it has been assigned or not, but for structs, we need this information for each of its fields. // </summary> public class VariableInfo { public readonly string Name; public readonly TypeInfo TypeInfo; // <summary> // The bit offset of this variable in the flow vector. // </summary> public readonly int Offset; // <summary> // The number of bits this variable needs in the flow vector. // The first bit always specifies whether the variable as such has been assigned while // the remaining bits contain this information for each of a struct's fields. // </summary> public readonly int Length; // <summary> // If this is a parameter of local variable. // </summary> public readonly bool IsParameter; public readonly LocalInfo LocalInfo; public readonly int ParameterIndex; readonly VariableInfo Parent; VariableInfo[] sub_info; protected VariableInfo (string name, Type type, int offset) { this.Name = name; this.Offset = offset; this.TypeInfo = TypeInfo.GetTypeInfo (type); Length = TypeInfo.TotalLength; Initialize (); } protected 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; this.ParameterIndex = parent.ParameterIndex; Initialize (); } protected void Initialize () { TypeInfo[] sub_fields = TypeInfo.SubStructInfo; if (sub_fields != null) { sub_info = new VariableInfo [sub_fields.Length]; for (int i = 0; i < sub_fields.Length; i++) { if (sub_fields [i] != null) sub_info [i] = new VariableInfo (this, sub_fields [i]); } } else sub_info = new VariableInfo [0]; } public VariableInfo (LocalInfo local_info, int offset) : this (local_info.Name, local_info.VariableType, offset) { this.LocalInfo = local_info; this.IsParameter = false; } public VariableInfo (string name, Type type, int param_idx, int offset) : this (name, type, offset) { this.ParameterIndex = param_idx; this.IsParameter = true; } public bool IsAssigned (EmitContext ec) { return !ec.DoFlowAnalysis || ec.OmitStructFlowAnalysis && TypeInfo.IsStruct || ec.CurrentBranching.IsAssigned (this); } public bool IsAssigned (EmitContext ec, Location loc) { if (IsAssigned (ec)) return true; Report.Error (165, loc, "Use of unassigned local variable `" + Name + "'"); ec.CurrentBranching.SetAssigned (this); return false; } public bool IsAssigned (MyBitVector vector) { if (vector [Offset]) return true; for (VariableInfo parent = Parent; parent != null; parent = parent.Parent) if (vector [parent.Offset]) return true; // Return 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]) return false; } // Ok, now check all fields which are structs. for (int i = 0; i < sub_info.Length; i++) { VariableInfo sinfo = sub_info [i]; if (sinfo == null) continue; if (!sinfo.IsAssigned (vector)) return false; } vector [Offset] = true; return true; } public void SetAssigned (EmitContext ec) { if (ec.DoFlowAnalysis) ec.CurrentBranching.SetAssigned (this); } public void SetAssigned (MyBitVector vector) { vector [Offset] = true; } public bool IsFieldAssigned (EmitContext ec, string name, Location loc) { if (!ec.DoFlowAnalysis || ec.OmitStructFlowAnalysis && TypeInfo.IsStruct || ec.CurrentBranching.IsFieldAssigned (this, name)) return true; Report.Error (170, loc, "Use of possibly unassigned field `" + name + "'"); ec.CurrentBranching.SetFieldAssigned (this, name); return false; } public bool IsFieldAssigned (MyBitVector vector, string field_name) { int field_idx = TypeInfo.GetFieldIndex (field_name); if (field_idx == 0) return true; return vector [Offset + field_idx]; } public void SetFieldAssigned (EmitContext ec, string name) { if (ec.DoFlowAnalysis) ec.CurrentBranching.SetFieldAssigned (this, name); } public void SetFieldAssigned (MyBitVector vector, string field_name) { int field_idx = TypeInfo.GetFieldIndex (field_name); if (field_idx == 0) return; vector [Offset + field_idx] = true; } public VariableInfo GetSubStruct (string name) { TypeInfo type = TypeInfo.GetSubStruct (name); if (type == null) return null; return new VariableInfo (this, type); } public override string ToString () { return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})", Name, TypeInfo, Offset, Length, IsParameter); } } // <summary> // This is used by the flow code to hold the `layout' of the flow vector for // all locals and all parameters (ie. we create one instance of this class for the // locals and another one for the params). // </summary> public class VariableMap { // <summary> // The number of variables in the map. // </summary> public readonly int Count; // <summary> // Total length of the flow vector for this map. // <summary> public readonly int Length; VariableInfo[] map; public VariableMap (InternalParameters ip) { Count = ip != null ? ip.Count : 0; // Dont bother allocating anything! if (Count == 0) return; Length = 0; for (int i = 0; i < Count; i++) { Parameter.Modifier mod = ip.ParameterModifier (i); if ((mod & Parameter.Modifier.OUT) == 0) continue; // Dont allocate till we find an out var. if (map == null) map = new VariableInfo [Count]; map [i] = new VariableInfo (ip.ParameterName (i), TypeManager.GetElementType (ip.ParameterType (i)), i, Length); Length += map [i].Length; } } public VariableMap (LocalInfo[] locals) : this (null, locals) { } public VariableMap (VariableMap parent, LocalInfo[] locals) { int offset = 0, start = 0; if (parent != null && parent.map != null) { offset = parent.Length; start = parent.Count; } Count = locals.Length + start; if (Count == 0) return; map = new VariableInfo [Count]; Length = offset; if (parent != null && parent.map != null) { parent.map.CopyTo (map, 0); } for (int i = start; i < Count; i++) { LocalInfo li = locals [i-start]; if (li.VariableType == null) continue; map [i] = li.VariableInfo = new VariableInfo (li, Length); Length += map [i].Length; } } // <summary> // Returns the VariableInfo for variable @index or null if we don't need to // compute assignment info for this variable. // </summary> public VariableInfo this [int index] { get { if (map == null) return null; return map [index]; } } public override string ToString () { return String.Format ("VariableMap ({0}:{1})", Count, Length); } } // <summary> // This is a special bit vector which can inherit from another bit vector doing a // copy-on-write strategy. The inherited vector may have a smaller size than the // current one. // </summary> public class MyBitVector { public readonly int Count; public readonly MyBitVector InheritsFrom; bool is_dirty; BitArray vector; public MyBitVector (int Count) : this (null, Count) { } public MyBitVector (MyBitVector InheritsFrom, int Count) { this.InheritsFrom = InheritsFrom; this.Count = Count; } // <summary> // Checks whether this bit vector has been modified. After setting this to true, // we won't use the inherited vector anymore, but our own copy of it. // </summary> public bool IsDirty { get { return is_dirty; } set { if (!is_dirty) initialize_vector (); } } // <summary> // Get/set bit `index' in the bit vector. // </summary> public bool this [int index] { get { if (index > Count) throw new ArgumentOutOfRangeException (); // We're doing a "copy-on-write" strategy here; as long // as nobody writes to the array, we can use our parent's // copy instead of duplicating the vector. if (vector != null) return vector [index]; else if (InheritsFrom != null) { BitArray inherited = InheritsFrom.Vector; if (index < inherited.Count) return inherited [index]; else return false; } else return false; } set { if (index > Count) throw new ArgumentOutOfRangeException (); // Only copy the vector if we're actually modifying it. if (this [index] != value) { initialize_vector (); vector [index] = value; } } } // <summary> // If you explicitly convert the MyBitVector to a BitArray, you will get a deep // copy of the bit vector. // </summary> public static explicit operator BitArray (MyBitVector vector) { vector.initialize_vector (); return vector.Vector; } // <summary> // Performs an `or' operation on the bit vector. The `new_vector' may have a // different size than the current one. // </summary> public void Or (MyBitVector new_vector) { BitArray new_array = new_vector.Vector; initialize_vector (); int upper; if (vector.Count < new_array.Count) upper = vector.Count; else upper = new_array.Count; for (int i = 0; i < upper; i++) vector [i] = vector [i] | new_array [i]; } // <summary> // Perfonrms an `and' operation on the bit vector. The `new_vector' may have // a different size than the current one. // </summary> public void And (MyBitVector new_vector) { BitArray new_array; if (new_vector != null) new_array = new_vector.Vector; else new_array = new BitArray (Count, false); initialize_vector (); int lower, upper; if (vector.Count < new_array.Count) lower = upper = vector.Count; else { lower = new_array.Count; upper = vector.Count; } for (int i = 0; i < lower; i++) vector [i] = vector [i] & new_array [i]; for (int i = lower; i < upper; i++) vector [i] = false; } public static void And (ref MyBitVector target, MyBitVector vector) { if (target != null) target.And (vector); else target = vector.Clone (); } public static void Or (ref MyBitVector target, MyBitVector vector) { if (target != null) target.Or (vector); else target = vector.Clone (); } // <summary> // This does a deep copy of the bit vector. // </summary> public MyBitVector Clone () { MyBitVector retval = new MyBitVector (Count); retval.Vector = Vector; return retval; } BitArray Vector { get { if (vector != null) return vector; else if (!is_dirty && (InheritsFrom != null)) return InheritsFrom.Vector; initialize_vector (); return vector; } set { initialize_vector (); for (int i = 0; i < System.Math.Min (vector.Count, value.Count); i++) vector [i] = value [i]; } } void initialize_vector () { if (vector != null) return; vector = new BitArray (Count, false); if (InheritsFrom != null) Vector = InheritsFrom.Vector; is_dirty = true; } public override string ToString () { StringBuilder sb = new StringBuilder ("{"); BitArray vector = Vector; if (!IsDirty) sb.Append ("="); for (int i = 0; i < vector.Count; i++) { sb.Append (vector [i] ? "1" : "0"); } sb.Append ("}"); return sb.ToString (); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -