2 // flowanalyis.cs: The control flow analysis code
5 // Martin Baulig (martin@ximian.com)
6 // Raja R Harinath (rharinath@novell.com)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Diagnostics;
21 // A new instance of this class is created every time a new block is resolved
22 // and if there's branching in the block's control flow.
24 public abstract class FlowBranching
27 // The type of a FlowBranching.
29 public enum BranchingType : byte {
30 // Normal (conditional or toplevel) block.
39 // The statement embedded inside a loop
42 // part of a block headed by a jump target
48 // TryFinally, Using, Lock, CollectionForeach
54 // The toplevel block of a function
59 // The type of one sibling of a branching.
61 public enum SiblingType : byte {
70 public static FlowBranching CreateBranching (FlowBranching parent, BranchingType type, Block block, Location loc)
73 case BranchingType.Exception:
74 case BranchingType.Labeled:
75 case BranchingType.Toplevel:
76 throw new InvalidOperationException ();
78 case BranchingType.Switch:
79 return new FlowBranchingBreakable (parent, type, SiblingType.SwitchSection, block, loc);
81 case BranchingType.Block:
82 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
84 case BranchingType.Loop:
85 return new FlowBranchingBreakable (parent, type, SiblingType.Conditional, block, loc);
87 case BranchingType.Embedded:
88 return new FlowBranchingContinuable (parent, type, SiblingType.Conditional, block, loc);
90 case BranchingType.TryCatch:
91 return new FlowBranchingTryCatch (parent, loc);
94 return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc);
99 // The type of this flow branching.
101 public readonly BranchingType Type;
104 // The block this branching is contained in. This may be null if it's not
105 // a top-level block and it doesn't declare any local variables.
107 public readonly Block Block;
110 // The parent of this branching or null if this is the top-block.
112 public readonly FlowBranching Parent;
115 // Start-Location of this flow branching.
117 public readonly Location Location;
119 static int next_id = 0;
123 // The vector contains a BitArray with information about which local variables
124 // and parameters are already initialized at the current code position.
126 public class UsageVector {
128 // The type of this branching.
130 public readonly SiblingType Type;
133 // Start location of this branching.
135 public Location Location;
138 // This is only valid for SwitchSection, Try, Catch and Finally.
140 public readonly Block Block;
143 // The number of locals in this block.
145 public readonly int CountLocals;
148 // If not null, then we inherit our state from this vector and do a
149 // copy-on-write. If null, then we're the first sibling in a top-level
150 // block and inherit from the empty vector.
152 public readonly UsageVector InheritsFrom;
155 // This is used to construct a list of UsageVector's.
157 public UsageVector Next;
165 static int next_id = 0;
169 // Normally, you should not use any of these constructors.
171 public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc, int num_locals)
176 this.InheritsFrom = parent;
177 this.CountLocals = num_locals;
179 locals = num_locals == 0
181 : new MyBitVector (parent == null ? MyBitVector.Empty : parent.locals, num_locals);
184 is_unreachable = parent.is_unreachable;
190 public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc)
191 : this (type, parent, block, loc, parent.CountLocals)
194 private UsageVector (MyBitVector locals, bool is_unreachable, Block block, Location loc)
196 this.Type = SiblingType.Block;
200 this.is_unreachable = is_unreachable;
202 this.locals = locals;
209 // This does a deep copy of the usage vector.
211 public UsageVector Clone ()
213 UsageVector retval = new UsageVector (Type, null, Block, Location, CountLocals);
215 retval.locals = locals.Clone ();
216 retval.is_unreachable = is_unreachable;
221 public bool IsAssigned (VariableInfo var, bool ignoreReachability)
223 if (!ignoreReachability && !var.IsParameter && IsUnreachable)
226 return var.IsAssigned (locals);
229 public void SetAssigned (VariableInfo var)
231 if (!var.IsParameter && IsUnreachable)
234 var.SetAssigned (locals);
237 public bool IsFieldAssigned (VariableInfo var, string name)
239 if (!var.IsParameter && IsUnreachable)
242 return var.IsFieldAssigned (locals, name);
245 public void SetFieldAssigned (VariableInfo var, string name)
247 if (!var.IsParameter && IsUnreachable)
250 var.SetFieldAssigned (locals, name);
253 public bool IsUnreachable {
254 get { return is_unreachable; }
257 public void ResetBarrier ()
259 is_unreachable = false;
264 is_unreachable = true;
267 public static UsageVector MergeSiblings (UsageVector sibling_list, Location loc)
269 if (sibling_list.Next == null)
272 MyBitVector locals = null;
273 bool is_unreachable = sibling_list.is_unreachable;
275 if (!sibling_list.IsUnreachable)
276 locals &= sibling_list.locals;
278 for (UsageVector child = sibling_list.Next; child != null; child = child.Next) {
279 is_unreachable &= child.is_unreachable;
281 if (!child.IsUnreachable)
282 locals &= child.locals;
285 return new UsageVector (locals, is_unreachable, null, loc);
289 // Merges a child branching.
291 public UsageVector MergeChild (UsageVector child, bool overwrite)
293 Report.Debug (2, " MERGING CHILD EFFECTS", this, child, Type);
295 bool new_isunr = child.is_unreachable;
298 // We've now either reached the point after the branching or we will
299 // never get there since we always return or always throw an exception.
301 // If we can reach the point after the branching, mark all locals and
302 // parameters as initialized which have been initialized in all branches
303 // we need to look at (see above).
306 if ((Type == SiblingType.SwitchSection) && !new_isunr) {
307 Report.Error (163, Location,
308 "Control cannot fall through from one " +
309 "case label to another");
313 locals |= child.locals;
316 is_unreachable = new_isunr;
318 is_unreachable |= new_isunr;
323 public void MergeOrigins (UsageVector o_vectors)
325 Report.Debug (1, " MERGING BREAK ORIGINS", this);
327 if (o_vectors == null)
330 if (IsUnreachable && locals != null)
331 locals.SetAll (true);
333 for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) {
334 Report.Debug (1, " MERGING BREAK ORIGIN", vector);
335 if (vector.IsUnreachable)
337 locals &= vector.locals;
338 is_unreachable &= vector.is_unreachable;
341 Report.Debug (1, " MERGING BREAK ORIGINS DONE", this);
348 public override string ToString ()
350 return String.Format ("Vector ({0},{1},{2}-{3})", Type, id, is_unreachable, locals);
355 // Creates a new flow branching which is contained in `parent'.
356 // You should only pass non-null for the `block' argument if this block
357 // introduces any new variables - in this case, we need to create a new
358 // usage vector with a different size than our parent's one.
360 protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
361 Block block, Location loc)
371 UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
372 vector = new UsageVector (stype, parent_vector, Block, loc, Block.AssignableSlots);
374 vector = new UsageVector (stype, Parent.CurrentUsageVector, null, loc);
380 public abstract UsageVector CurrentUsageVector {
385 // Creates a sibling of the current usage vector.
387 public virtual void CreateSibling (Block block, SiblingType type)
389 UsageVector vector = new UsageVector (
390 type, Parent.CurrentUsageVector, block, Location);
393 Report.Debug (1, " CREATED SIBLING", CurrentUsageVector);
396 public void CreateSibling ()
398 CreateSibling (null, SiblingType.Conditional);
401 protected abstract void AddSibling (UsageVector uv);
403 protected abstract UsageVector Merge ();
406 // Merge a child branching.
408 public UsageVector MergeChild (FlowBranching child)
410 bool overwrite = false;
412 switch (child.Type) {
413 case BranchingType.Labeled:
416 case BranchingType.Block:
417 if (child.Block != null && child.Block != child.Block.Explicit)
422 Report.Debug (2, " MERGING CHILD", this, child);
423 UsageVector result = CurrentUsageVector.MergeChild (child.Merge (), overwrite);
424 Report.Debug (2, " MERGING CHILD DONE", this, result);
428 public virtual bool InTryWithCatch ()
430 return Parent.InTryWithCatch ();
433 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
434 public virtual bool AddBreakOrigin (UsageVector vector, Location loc)
436 return Parent.AddBreakOrigin (vector, loc);
439 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
440 public virtual bool AddContinueOrigin (UsageVector vector, Location loc)
442 return Parent.AddContinueOrigin (vector, loc);
445 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
446 public virtual bool AddReturnOrigin (UsageVector vector, Location loc)
448 return Parent.AddReturnOrigin (vector, loc);
451 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
452 public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
454 return Parent.AddGotoOrigin (vector, goto_stmt);
457 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
458 public virtual bool StealFinallyClauses (ref ArrayList list)
460 return Parent.StealFinallyClauses (ref list);
463 public bool IsAssigned (VariableInfo vi)
465 return CurrentUsageVector.IsAssigned (vi, false);
468 public bool IsFieldAssigned (VariableInfo vi, string field_name)
470 return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
473 public void SetAssigned (VariableInfo vi)
475 CurrentUsageVector.SetAssigned (vi);
478 public void SetFieldAssigned (VariableInfo vi, string name)
480 CurrentUsageVector.SetFieldAssigned (vi, name);
483 public override string ToString ()
485 StringBuilder sb = new StringBuilder ();
486 sb.Append (GetType ());
494 sb.Append (Block.ID);
496 sb.Append (Block.StartLocation);
499 // sb.Append (Siblings.Length);
500 // sb.Append (" - ");
501 sb.Append (CurrentUsageVector);
503 return sb.ToString ();
507 get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
511 public class FlowBranchingBlock : FlowBranching
513 UsageVector sibling_list = null;
515 public FlowBranchingBlock (FlowBranching parent, BranchingType type,
516 SiblingType stype, Block block, Location loc)
517 : base (parent, type, stype, block, loc)
520 public override UsageVector CurrentUsageVector {
521 get { return sibling_list; }
524 protected override void AddSibling (UsageVector sibling)
526 if (sibling.Type == SiblingType.Block && sibling_list != null)
527 throw new InternalErrorException ("Blocks don't have sibling flow paths");
528 sibling.Next = sibling_list;
529 sibling_list = sibling;
532 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
534 LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
536 return Parent.AddGotoOrigin (vector, goto_stmt);
539 goto_stmt.SetResolvedTarget (stmt);
540 stmt.AddUsageVector (vector);
544 public static void Error_UnknownLabel (Location loc, string label)
546 Report.Error(159, loc, "The label `{0}:' could not be found within the scope of the goto statement",
550 protected override UsageVector Merge ()
552 Report.Debug (2, " MERGING SIBLINGS", Name);
553 UsageVector vector = UsageVector.MergeSiblings (sibling_list, Location);
554 Report.Debug (2, " MERGING SIBLINGS DONE", Name, vector);
559 public class FlowBranchingBreakable : FlowBranchingBlock
561 UsageVector break_origins;
563 public FlowBranchingBreakable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
564 : base (parent, type, stype, block, loc)
567 public override bool AddBreakOrigin (UsageVector vector, Location loc)
569 vector = vector.Clone ();
570 vector.Next = break_origins;
571 break_origins = vector;
575 protected override UsageVector Merge ()
577 UsageVector vector = base.Merge ();
578 vector.MergeOrigins (break_origins);
583 public class FlowBranchingContinuable : FlowBranchingBlock
585 UsageVector continue_origins;
587 public FlowBranchingContinuable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
588 : base (parent, type, stype, block, loc)
591 public override bool AddContinueOrigin (UsageVector vector, Location loc)
593 vector = vector.Clone ();
594 vector.Next = continue_origins;
595 continue_origins = vector;
599 protected override UsageVector Merge ()
601 UsageVector vector = base.Merge ();
602 vector.MergeOrigins (continue_origins);
607 public class FlowBranchingLabeled : FlowBranchingBlock
609 LabeledStatement stmt;
612 public FlowBranchingLabeled (FlowBranching parent, LabeledStatement stmt)
613 : base (parent, BranchingType.Labeled, SiblingType.Conditional, null, stmt.loc)
616 CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
617 actual = CurrentUsageVector.Clone ();
619 // stand-in for backward jumps
620 CurrentUsageVector.ResetBarrier ();
623 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
625 if (goto_stmt.Target != stmt.Name)
626 return Parent.AddGotoOrigin (vector, goto_stmt);
629 goto_stmt.SetResolvedTarget (stmt);
630 actual.MergeOrigins (vector.Clone ());
635 protected override UsageVector Merge ()
637 UsageVector vector = base.Merge ();
639 if (actual.IsUnreachable)
640 Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
642 actual.MergeChild (vector, false);
647 public class FlowBranchingToplevel : FlowBranchingBlock
649 UsageVector return_origins;
651 public FlowBranchingToplevel (FlowBranching parent, ToplevelBlock stmt)
652 : base (parent, BranchingType.Toplevel, SiblingType.Conditional, stmt, stmt.loc)
656 public override bool InTryWithCatch ()
661 public override bool AddBreakOrigin (UsageVector vector, Location loc)
663 Report.Error (139, loc, "No enclosing loop out of which to break or continue");
667 public override bool AddContinueOrigin (UsageVector vector, Location loc)
669 Report.Error (139, loc, "No enclosing loop out of which to break or continue");
673 public override bool AddReturnOrigin (UsageVector vector, Location loc)
675 vector = vector.Clone ();
676 vector.Location = loc;
677 vector.Next = return_origins;
678 return_origins = vector;
682 public override bool StealFinallyClauses (ref ArrayList list)
687 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
689 string name = goto_stmt.Target;
690 LabeledStatement s = Block.LookupLabel (name);
692 throw new InternalErrorException ("Shouldn't get here");
694 if (Parent == null) {
695 Error_UnknownLabel (goto_stmt.loc, name);
699 int errors = Report.Errors;
700 Parent.AddGotoOrigin (vector, goto_stmt);
701 if (errors == Report.Errors)
702 Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
706 protected override UsageVector Merge ()
708 for (UsageVector origin = return_origins; origin != null; origin = origin.Next)
709 Block.Toplevel.CheckOutParameters (origin, origin.Location);
711 UsageVector vector = base.Merge ();
712 Block.Toplevel.CheckOutParameters (vector, Block.loc);
713 // Note: we _do_not_ merge in the return origins
719 return Merge ().IsUnreachable;
723 public class FlowBranchingTryCatch : FlowBranchingBlock
725 public FlowBranchingTryCatch (FlowBranching parent, Location loc)
726 : base (parent, BranchingType.Block, SiblingType.Try, null, loc)
730 public override bool InTryWithCatch ()
735 public override bool AddBreakOrigin (UsageVector vector, Location loc)
737 Parent.AddBreakOrigin (vector, loc);
741 public override bool AddContinueOrigin (UsageVector vector, Location loc)
743 Parent.AddContinueOrigin (vector, loc);
747 public override bool AddReturnOrigin (UsageVector vector, Location loc)
749 Parent.AddReturnOrigin (vector, loc);
753 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
755 Parent.AddGotoOrigin (vector, goto_stmt);
759 public override bool StealFinallyClauses (ref ArrayList list)
761 Parent.StealFinallyClauses (ref list);
766 public class FlowBranchingException : FlowBranching
768 ExceptionStatement stmt;
769 UsageVector current_vector;
770 UsageVector try_vector;
771 UsageVector finally_vector;
773 UsageVector break_origins;
774 UsageVector continue_origins;
775 UsageVector return_origins;
776 GotoOrigin goto_origins;
779 public GotoOrigin Next;
780 public Goto GotoStmt;
781 public UsageVector Vector;
783 public GotoOrigin (UsageVector vector, Goto goto_stmt, GotoOrigin next)
786 GotoStmt = goto_stmt;
793 public FlowBranchingException (FlowBranching parent,
794 ExceptionStatement stmt)
795 : base (parent, BranchingType.Exception, SiblingType.Try,
799 this.emit_finally = true;
802 protected override void AddSibling (UsageVector sibling)
804 switch (sibling.Type) {
805 case SiblingType.Try:
806 try_vector = sibling;
808 case SiblingType.Finally:
809 finally_vector = sibling;
812 throw new InvalidOperationException ();
814 current_vector = sibling;
817 public override UsageVector CurrentUsageVector {
818 get { return current_vector; }
821 public override bool AddBreakOrigin (UsageVector vector, Location loc)
823 vector = vector.Clone ();
824 if (finally_vector != null) {
825 int errors = Report.Errors;
826 Parent.AddBreakOrigin (vector, loc);
827 if (errors == Report.Errors)
828 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
830 vector.Location = loc;
831 vector.Next = break_origins;
832 break_origins = vector;
837 public override bool AddContinueOrigin (UsageVector vector, Location loc)
839 vector = vector.Clone ();
840 if (finally_vector != null) {
841 int errors = Report.Errors;
842 Parent.AddContinueOrigin (vector, loc);
843 if (errors == Report.Errors)
844 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
846 vector.Location = loc;
847 vector.Next = continue_origins;
848 continue_origins = vector;
853 public override bool AddReturnOrigin (UsageVector vector, Location loc)
855 vector = vector.Clone ();
856 if (finally_vector != null) {
857 int errors = Report.Errors;
858 Parent.AddReturnOrigin (vector, loc);
859 if (errors == Report.Errors)
860 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
862 vector.Location = loc;
863 vector.Next = return_origins;
864 return_origins = vector;
869 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
871 LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
873 throw new InternalErrorException ("Shouldn't get here");
875 vector = vector.Clone ();
876 if (finally_vector != null) {
877 int errors = Report.Errors;
878 Parent.AddGotoOrigin (vector, goto_stmt);
879 if (errors == Report.Errors)
880 Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
882 goto_origins = new GotoOrigin (vector, goto_stmt, goto_origins);
887 public override bool StealFinallyClauses (ref ArrayList list)
890 list = new ArrayList ();
892 emit_finally = false;
893 base.StealFinallyClauses (ref list);
897 public bool EmitFinally {
898 get { return emit_finally; }
901 protected override UsageVector Merge ()
903 UsageVector vector = try_vector.Clone ();
905 if (finally_vector != null)
906 vector.MergeChild (finally_vector, false);
908 for (UsageVector origin = break_origins; origin != null; origin = origin.Next) {
909 if (finally_vector != null)
910 origin.MergeChild (finally_vector, false);
911 Parent.AddBreakOrigin (origin, origin.Location);
914 for (UsageVector origin = continue_origins; origin != null; origin = origin.Next) {
915 if (finally_vector != null)
916 origin.MergeChild (finally_vector, false);
917 Parent.AddContinueOrigin (origin, origin.Location);
920 for (UsageVector origin = return_origins; origin != null; origin = origin.Next) {
921 if (finally_vector != null)
922 origin.MergeChild (finally_vector, false);
923 Parent.AddReturnOrigin (origin, origin.Location);
926 for (GotoOrigin origin = goto_origins; origin != null; origin = origin.Next) {
927 if (finally_vector != null)
928 origin.Vector.MergeChild (finally_vector, false);
929 Parent.AddGotoOrigin (origin.Vector, origin.GotoStmt);
937 // This is used by the flow analysis code to keep track of the type of local variables
940 // The flow code uses a BitVector to keep track of whether a variable has been assigned
941 // or not. This is easy for fundamental types (int, char etc.) or reference types since
942 // you can only assign the whole variable as such.
944 // For structs, we also need to keep track of all its fields. To do this, we allocate one
945 // bit for the struct itself (it's used if you assign/access the whole struct) followed by
946 // one bit for each of its fields.
948 // This class computes this `layout' for each type.
950 public class TypeInfo
952 public readonly Type Type;
955 // Total number of bits a variable of this type consumes in the flow vector.
957 public readonly int TotalLength;
960 // Number of bits the simple fields of a variable of this type consume
961 // in the flow vector.
963 public readonly int Length;
966 // This is only used by sub-structs.
968 public readonly int Offset;
971 // If this is a struct.
973 public readonly bool IsStruct;
976 // If this is a struct, all fields which are structs theirselves.
978 public TypeInfo[] SubStructInfo;
980 protected readonly StructInfo struct_info;
981 private static Hashtable type_hash = new Hashtable ();
983 public static TypeInfo GetTypeInfo (Type type)
985 TypeInfo info = (TypeInfo) type_hash [type];
989 info = new TypeInfo (type);
990 type_hash.Add (type, info);
994 public static TypeInfo GetTypeInfo (TypeContainer tc)
996 TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
1000 info = new TypeInfo (tc);
1001 type_hash.Add (tc.TypeBuilder, info);
1005 private TypeInfo (Type type)
1009 struct_info = StructInfo.GetStructInfo (type);
1010 if (struct_info != null) {
1011 Length = struct_info.Length;
1012 TotalLength = struct_info.TotalLength;
1013 SubStructInfo = struct_info.StructFields;
1022 private TypeInfo (TypeContainer tc)
1024 this.Type = tc.TypeBuilder;
1026 struct_info = StructInfo.GetStructInfo (tc);
1027 if (struct_info != null) {
1028 Length = struct_info.Length;
1029 TotalLength = struct_info.TotalLength;
1030 SubStructInfo = struct_info.StructFields;
1039 protected TypeInfo (StructInfo struct_info, int offset)
1041 this.struct_info = struct_info;
1042 this.Offset = offset;
1043 this.Length = struct_info.Length;
1044 this.TotalLength = struct_info.TotalLength;
1045 this.SubStructInfo = struct_info.StructFields;
1046 this.Type = struct_info.Type;
1047 this.IsStruct = true;
1050 public int GetFieldIndex (string name)
1052 if (struct_info == null)
1055 return struct_info [name];
1058 public TypeInfo GetSubStruct (string name)
1060 if (struct_info == null)
1063 return struct_info.GetStructField (name);
1067 // A struct's constructor must always assign all fields.
1068 // This method checks whether it actually does so.
1070 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1072 if (struct_info == null)
1076 for (int i = 0; i < struct_info.Count; i++) {
1077 FieldInfo field = struct_info.Fields [i];
1079 if (!branching.IsFieldAssigned (vi, field.Name)) {
1080 Report.Error (171, loc,
1081 "Field `{0}' must be fully assigned before control leaves the constructor",
1082 TypeManager.GetFullNameSignature (field));
1090 public override string ToString ()
1092 return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1093 Type, Offset, Length, TotalLength);
1096 protected class StructInfo {
1097 public readonly Type Type;
1098 public readonly FieldInfo[] Fields;
1099 public readonly TypeInfo[] StructFields;
1100 public readonly int Count;
1101 public readonly int CountPublic;
1102 public readonly int CountNonPublic;
1103 public readonly int Length;
1104 public readonly int TotalLength;
1105 public readonly bool HasStructFields;
1107 private static Hashtable field_type_hash = new Hashtable ();
1108 private Hashtable struct_field_hash;
1109 private Hashtable field_hash;
1111 protected bool InTransit = false;
1113 // Private constructor. To save memory usage, we only need to create one instance
1114 // of this class per struct type.
1115 private StructInfo (Type type)
1119 field_type_hash.Add (type, this);
1121 if (type is TypeBuilder) {
1122 TypeContainer tc = TypeManager.LookupTypeContainer (type);
1124 ArrayList fields = null;
1128 ArrayList public_fields = new ArrayList ();
1129 ArrayList non_public_fields = new ArrayList ();
1131 if (fields != null) {
1132 foreach (FieldBase field in fields) {
1133 if ((field.ModFlags & Modifiers.STATIC) != 0)
1135 if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1136 public_fields.Add (field.FieldBuilder);
1138 non_public_fields.Add (field.FieldBuilder);
1142 CountPublic = public_fields.Count;
1143 CountNonPublic = non_public_fields.Count;
1144 Count = CountPublic + CountNonPublic;
1146 Fields = new FieldInfo [Count];
1147 public_fields.CopyTo (Fields, 0);
1148 non_public_fields.CopyTo (Fields, CountPublic);
1150 } else if (type is GenericTypeParameterBuilder) {
1151 CountPublic = CountNonPublic = Count = 0;
1153 Fields = new FieldInfo [0];
1156 FieldInfo[] public_fields = type.GetFields (
1157 BindingFlags.Instance|BindingFlags.Public);
1158 FieldInfo[] non_public_fields = type.GetFields (
1159 BindingFlags.Instance|BindingFlags.NonPublic);
1161 CountPublic = public_fields.Length;
1162 CountNonPublic = non_public_fields.Length;
1163 Count = CountPublic + CountNonPublic;
1165 Fields = new FieldInfo [Count];
1166 public_fields.CopyTo (Fields, 0);
1167 non_public_fields.CopyTo (Fields, CountPublic);
1170 struct_field_hash = new Hashtable ();
1171 field_hash = new Hashtable ();
1174 StructFields = new TypeInfo [Count];
1175 StructInfo[] sinfo = new StructInfo [Count];
1179 for (int i = 0; i < Count; i++) {
1180 FieldInfo field = (FieldInfo) Fields [i];
1182 sinfo [i] = GetStructInfo (field.FieldType);
1183 if (sinfo [i] == null)
1184 field_hash.Add (field.Name, ++Length);
1185 else if (sinfo [i].InTransit) {
1186 Report.Error (523, String.Format (
1187 "Struct member `{0}.{1}' of type `{2}' causes " +
1188 "a cycle in the structure layout",
1189 type, field.Name, sinfo [i].Type));
1197 TotalLength = Length + 1;
1198 for (int i = 0; i < Count; i++) {
1199 FieldInfo field = (FieldInfo) Fields [i];
1201 if (sinfo [i] == null)
1204 field_hash.Add (field.Name, TotalLength);
1206 HasStructFields = true;
1207 StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1208 struct_field_hash.Add (field.Name, StructFields [i]);
1209 TotalLength += sinfo [i].TotalLength;
1213 public int this [string name] {
1215 if (field_hash.Contains (name))
1216 return (int) field_hash [name];
1222 public TypeInfo GetStructField (string name)
1224 return (TypeInfo) struct_field_hash [name];
1227 public static StructInfo GetStructInfo (Type type)
1229 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1230 TypeManager.IsBuiltinType (type))
1233 StructInfo info = (StructInfo) field_type_hash [type];
1237 return new StructInfo (type);
1240 public static StructInfo GetStructInfo (TypeContainer tc)
1242 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1246 return new StructInfo (tc.TypeBuilder);
1252 // This is used by the flow analysis code to store information about a single local variable
1253 // or parameter. Depending on the variable's type, we need to allocate one or more elements
1254 // in the BitVector - if it's a fundamental or reference type, we just need to know whether
1255 // it has been assigned or not, but for structs, we need this information for each of its fields.
1257 public class VariableInfo {
1258 public readonly string Name;
1259 public readonly TypeInfo TypeInfo;
1262 // The bit offset of this variable in the flow vector.
1264 public readonly int Offset;
1267 // The number of bits this variable needs in the flow vector.
1268 // The first bit always specifies whether the variable as such has been assigned while
1269 // the remaining bits contain this information for each of a struct's fields.
1271 public readonly int Length;
1274 // If this is a parameter of local variable.
1276 public readonly bool IsParameter;
1278 public readonly LocalInfo LocalInfo;
1280 readonly VariableInfo Parent;
1281 VariableInfo[] sub_info;
1283 protected VariableInfo (string name, Type type, int offset)
1286 this.Offset = offset;
1287 this.TypeInfo = TypeInfo.GetTypeInfo (type);
1289 Length = TypeInfo.TotalLength;
1294 protected VariableInfo (VariableInfo parent, TypeInfo type)
1296 this.Name = parent.Name;
1297 this.TypeInfo = type;
1298 this.Offset = parent.Offset + type.Offset;
1299 this.Parent = parent;
1300 this.Length = type.TotalLength;
1302 this.IsParameter = parent.IsParameter;
1303 this.LocalInfo = parent.LocalInfo;
1308 protected void Initialize ()
1310 TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1311 if (sub_fields != null) {
1312 sub_info = new VariableInfo [sub_fields.Length];
1313 for (int i = 0; i < sub_fields.Length; i++) {
1314 if (sub_fields [i] != null)
1315 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1318 sub_info = new VariableInfo [0];
1321 public VariableInfo (LocalInfo local_info, int offset)
1322 : this (local_info.Name, local_info.VariableType, offset)
1324 this.LocalInfo = local_info;
1325 this.IsParameter = false;
1328 public VariableInfo (Parameters ip, int i, int offset)
1329 : this (ip.ParameterName (i), TypeManager.GetElementType (ip.ParameterType (i)), offset)
1331 this.IsParameter = true;
1334 public bool IsAssigned (EmitContext ec)
1336 return !ec.DoFlowAnalysis ||
1337 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1338 ec.CurrentBranching.IsAssigned (this);
1341 public bool IsAssigned (EmitContext ec, Location loc)
1343 if (IsAssigned (ec))
1346 Report.Error (165, loc,
1347 "Use of unassigned local variable `" + Name + "'");
1348 ec.CurrentBranching.SetAssigned (this);
1352 public bool IsAssigned (MyBitVector vector)
1357 if (vector [Offset])
1360 // FIXME: Fix SetFieldAssigned to set the whole range like SetAssigned below. Then, get rid of this stanza
1361 for (VariableInfo parent = Parent; parent != null; parent = parent.Parent) {
1362 if (vector [parent.Offset]) {
1363 // 'parent' is assigned, but someone forgot to note that all its components are assigned too
1364 parent.SetAssigned (vector);
1369 // Return unless this is a struct.
1370 if (!TypeInfo.IsStruct)
1373 // Ok, so each field must be assigned.
1374 for (int i = 0; i < TypeInfo.Length; i++) {
1375 if (!vector [Offset + i + 1])
1379 // Ok, now check all fields which are structs.
1380 for (int i = 0; i < sub_info.Length; i++) {
1381 VariableInfo sinfo = sub_info [i];
1385 if (!sinfo.IsAssigned (vector))
1389 vector [Offset] = true;
1393 public void SetAssigned (EmitContext ec)
1395 if (ec.DoFlowAnalysis)
1396 ec.CurrentBranching.SetAssigned (this);
1399 public void SetAssigned (MyBitVector vector)
1402 vector [Offset] = true;
1404 vector.SetRange (Offset, Length);
1407 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1409 if (!ec.DoFlowAnalysis ||
1410 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1411 ec.CurrentBranching.IsFieldAssigned (this, name))
1414 Report.Error (170, loc,
1415 "Use of possibly unassigned field `" + name + "'");
1416 ec.CurrentBranching.SetFieldAssigned (this, name);
1420 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1422 int field_idx = TypeInfo.GetFieldIndex (field_name);
1427 return vector [Offset + field_idx];
1430 public void SetFieldAssigned (EmitContext ec, string name)
1432 if (ec.DoFlowAnalysis)
1433 ec.CurrentBranching.SetFieldAssigned (this, name);
1436 public void SetFieldAssigned (MyBitVector vector, string field_name)
1438 int field_idx = TypeInfo.GetFieldIndex (field_name);
1443 vector [Offset + field_idx] = true;
1446 public VariableInfo GetSubStruct (string name)
1448 TypeInfo type = TypeInfo.GetSubStruct (name);
1453 return new VariableInfo (this, type);
1456 public override string ToString ()
1458 return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1459 Name, TypeInfo, Offset, Length, IsParameter);
1464 // This is a special bit vector which can inherit from another bit vector doing a
1465 // copy-on-write strategy. The inherited vector may have a smaller size than the
1468 public class MyBitVector {
1469 public readonly int Count;
1470 public static readonly MyBitVector Empty = new MyBitVector ();
1472 // Invariant: vector != null => vector.Count == Count
1473 // Invariant: vector == null || shared == null
1474 // i.e., at most one of 'vector' and 'shared' can be non-null. They can both be null -- that means all-ones
1475 // The object in 'shared' cannot be modified, while 'vector' can be freely modified
1476 BitArray vector, shared;
1480 shared = new BitArray (0, false);
1483 public MyBitVector (MyBitVector InheritsFrom, int Count)
1485 if (InheritsFrom != null)
1486 shared = InheritsFrom.Shared;
1491 // Use this accessor to get a shareable copy of the underlying BitArray representation
1494 // Post-condition: vector == null
1495 if (shared == null) {
1504 // Get/set bit `index' in the bit vector.
1506 public bool this [int index] {
1509 throw new ArgumentOutOfRangeException ();
1512 return vector [index];
1515 if (index < shared.Count)
1516 return shared [index];
1521 // Only copy the vector if we're actually modifying it.
1522 if (this [index] != value) {
1524 initialize_vector ();
1525 vector [index] = value;
1531 // Performs an `or' operation on the bit vector. The `new_vector' may have a
1532 // different size than the current one.
1534 private MyBitVector Or (MyBitVector new_vector)
1536 if (Count == 0 || new_vector.Count == 0)
1539 BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1542 int n = new_vector.Count;
1544 for (int i = 0; i < n; ++i)
1552 if (Count == o.Count) {
1553 if (vector == null) {
1556 initialize_vector ();
1566 for (int i = 0; i < min; i++) {
1575 // Performs an `and' operation on the bit vector. The `new_vector' may have
1576 // a different size than the current one.
1578 private MyBitVector And (MyBitVector new_vector)
1583 BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1586 for (int i = new_vector.Count; i < Count; ++i)
1596 if (Count == o.Count) {
1597 if (vector == null) {
1598 if (shared == null) {
1599 shared = new_vector.Shared;
1602 initialize_vector ();
1612 for (int i = 0; i < min; i++) {
1617 for (int i = min; i < Count; i++)
1623 public static MyBitVector operator & (MyBitVector a, MyBitVector b)
1631 if (a.Count > b.Count)
1632 return a.Clone ().And (b);
1634 return b.Clone ().And (a);
1637 public static MyBitVector operator | (MyBitVector a, MyBitVector b)
1642 return new MyBitVector (null, b.Count);
1644 return new MyBitVector (null, a.Count);
1645 if (a.Count > b.Count)
1646 return a.Clone ().Or (b);
1648 return b.Clone ().Or (a);
1651 public MyBitVector Clone ()
1653 return Count == 0 ? Empty : new MyBitVector (this, Count);
1656 public void SetRange (int offset, int length)
1658 if (offset > Count || offset + length > Count)
1659 throw new ArgumentOutOfRangeException ();
1661 if (shared == null && vector == null)
1665 if (shared != null) {
1666 if (offset + length <= shared.Count) {
1667 for (; i < length; ++i)
1668 if (!shared [i+offset])
1673 initialize_vector ();
1675 for (; i < length; ++i)
1676 vector [i+offset] = true;
1680 public void SetAll (bool value)
1682 // Don't clobber Empty
1685 shared = value ? null : Empty.Shared;
1689 void initialize_vector ()
1691 // Post-condition: vector != null
1692 if (shared == null) {
1693 vector = new BitArray (Count, true);
1697 vector = new BitArray (shared);
1698 if (Count != vector.Count)
1699 vector.Length = Count;
1703 StringBuilder Dump (StringBuilder sb)
1705 BitArray dump = vector == null ? shared : vector;
1707 return sb.Append ("/");
1710 for (int i = 0; i < dump.Count; i++)
1711 sb.Append (dump [i] ? "1" : "0");
1715 public override string ToString ()
1717 return Dump (new StringBuilder ("{")).Append ("}").ToString ();