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
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.SwitchSection:
82 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
84 case BranchingType.Block:
85 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
87 case BranchingType.Loop:
88 return new FlowBranchingBreakable (parent, type, SiblingType.Conditional, block, loc);
90 case BranchingType.Embedded:
91 return new FlowBranchingContinuable (parent, type, SiblingType.Conditional, block, 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 parameters in this block.
145 public readonly int CountParameters;
148 // The number of locals in this block.
150 public readonly int CountLocals;
153 // If not null, then we inherit our state from this vector and do a
154 // copy-on-write. If null, then we're the first sibling in a top-level
155 // block and inherit from the empty vector.
157 public readonly UsageVector InheritsFrom;
160 // This is used to construct a list of UsageVector's.
162 public UsageVector Next;
167 MyBitVector locals, parameters;
170 static int next_id = 0;
174 // Normally, you should not use any of these constructors.
176 public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc, int num_params, int num_locals)
181 this.InheritsFrom = parent;
182 this.CountParameters = num_params;
183 this.CountLocals = num_locals;
185 locals = num_locals == 0
187 : new MyBitVector (parent == null ? MyBitVector.Empty : parent.locals, num_locals);
189 parameters = num_params == 0
191 : new MyBitVector (parent == null ? MyBitVector.Empty : parent.parameters, num_params);
194 is_unreachable = parent.is_unreachable;
200 public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc)
201 : this (type, parent, block, loc, parent.CountParameters, parent.CountLocals)
204 private UsageVector (MyBitVector parameters, MyBitVector locals, bool is_unreachable, Block block, Location loc)
206 this.Type = SiblingType.Block;
210 this.is_unreachable = is_unreachable;
212 this.parameters = parameters;
213 this.locals = locals;
220 // This does a deep copy of the usage vector.
222 public UsageVector Clone ()
224 UsageVector retval = new UsageVector (Type, null, Block, Location, CountParameters, CountLocals);
226 retval.locals = locals.Clone ();
227 retval.parameters = parameters.Clone ();
228 retval.is_unreachable = is_unreachable;
233 public bool IsAssigned (VariableInfo var, bool ignoreReachability)
235 if (!ignoreReachability && !var.IsParameter && IsUnreachable)
238 return var.IsAssigned (var.IsParameter ? parameters : locals);
241 public void SetAssigned (VariableInfo var)
243 if (!var.IsParameter && IsUnreachable)
246 var.SetAssigned (var.IsParameter ? parameters : locals);
249 public bool IsFieldAssigned (VariableInfo var, string name)
251 if (!var.IsParameter && IsUnreachable)
254 return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name);
257 public void SetFieldAssigned (VariableInfo var, string name)
259 if (!var.IsParameter && IsUnreachable)
262 var.SetFieldAssigned (var.IsParameter ? parameters : locals, name);
265 public bool IsUnreachable {
266 get { return is_unreachable; }
269 public void ResetBarrier ()
271 is_unreachable = false;
276 is_unreachable = true;
279 public static UsageVector MergeSiblings (UsageVector sibling_list, Location loc)
281 if (sibling_list.Next == null)
284 MyBitVector locals = null;
285 MyBitVector parameters = null;
286 bool is_unreachable = sibling_list.is_unreachable;
288 if (!sibling_list.IsUnreachable) {
289 locals &= sibling_list.locals;
290 parameters &= sibling_list.parameters;
293 for (UsageVector child = sibling_list.Next; child != null; child = child.Next) {
294 is_unreachable &= child.is_unreachable;
296 if (!child.IsUnreachable) {
297 locals &= child.locals;
298 parameters &= child.parameters;
302 return new UsageVector (parameters, locals, is_unreachable, null, loc);
306 // Merges a child branching.
308 public UsageVector MergeChild (UsageVector child, bool overwrite)
310 Report.Debug (2, " MERGING CHILD EFFECTS", this, child, Type);
312 bool new_isunr = child.is_unreachable;
315 // We've now either reached the point after the branching or we will
316 // never get there since we always return or always throw an exception.
318 // If we can reach the point after the branching, mark all locals and
319 // parameters as initialized which have been initialized in all branches
320 // we need to look at (see above).
323 if ((Type == SiblingType.SwitchSection) && !new_isunr) {
324 Report.Error (163, Location,
325 "Control cannot fall through from one " +
326 "case label to another");
330 locals |= child.locals;
331 parameters |= child.parameters;
334 is_unreachable = new_isunr;
336 is_unreachable |= new_isunr;
341 public void MergeOrigins (UsageVector o_vectors)
343 Report.Debug (1, " MERGING BREAK ORIGINS", this);
345 if (o_vectors == null)
350 locals.SetAll (true);
351 if (parameters != null)
352 parameters.SetAll (true);
355 for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) {
356 Report.Debug (1, " MERGING BREAK ORIGIN", vector);
357 if (vector.IsUnreachable)
359 locals &= vector.locals;
360 parameters &= vector.parameters;
361 is_unreachable &= vector.is_unreachable;
364 Report.Debug (1, " MERGING BREAK ORIGINS DONE", this);
371 public override string ToString ()
373 return String.Format ("Vector ({0},{1},{2}-{3}-{4})", Type, id, is_unreachable, parameters, locals);
378 // Creates a new flow branching which is contained in `parent'.
379 // You should only pass non-null for the `block' argument if this block
380 // introduces any new variables - in this case, we need to create a new
381 // usage vector with a different size than our parent's one.
383 protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
384 Block block, Location loc)
394 UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
395 vector = new UsageVector (
396 stype, parent_vector, Block, loc, Block.Toplevel.ParameterMap.Length, Block.AssignableSlots);
398 vector = new UsageVector (
399 stype, Parent.CurrentUsageVector, null, loc);
405 public abstract UsageVector CurrentUsageVector {
410 // Creates a sibling of the current usage vector.
412 public virtual void CreateSibling (Block block, SiblingType type)
414 UsageVector vector = new UsageVector (
415 type, Parent.CurrentUsageVector, block, Location);
418 Report.Debug (1, " CREATED SIBLING", CurrentUsageVector);
421 public void CreateSibling ()
423 CreateSibling (null, SiblingType.Conditional);
426 protected abstract void AddSibling (UsageVector uv);
428 protected abstract UsageVector Merge ();
431 // Merge a child branching.
433 public UsageVector MergeChild (FlowBranching child)
435 bool overwrite = child.Type == BranchingType.Labeled ||
436 (child.Type == BranchingType.Block && child.Block != null && child.Block.Implicit);
437 Report.Debug (2, " MERGING CHILD", this, child);
438 UsageVector result = CurrentUsageVector.MergeChild (child.Merge (), overwrite);
439 Report.Debug (2, " MERGING CHILD DONE", this, result);
443 public virtual bool InTryWithCatch ()
445 return Parent.InTryWithCatch ();
448 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
449 public virtual bool AddBreakOrigin (UsageVector vector, Location loc)
451 return Parent.AddBreakOrigin (vector, loc);
454 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
455 public virtual bool AddContinueOrigin (UsageVector vector, Location loc)
457 return Parent.AddContinueOrigin (vector, loc);
460 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
461 public virtual bool AddReturnOrigin (UsageVector vector, Location loc)
463 return Parent.AddReturnOrigin (vector, loc);
466 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
467 public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
469 return Parent.AddGotoOrigin (vector, goto_stmt);
472 public virtual void StealFinallyClauses (ref ArrayList list)
474 Parent.StealFinallyClauses (ref list);
477 public bool IsAssigned (VariableInfo vi)
479 return CurrentUsageVector.IsAssigned (vi, false);
482 public bool IsFieldAssigned (VariableInfo vi, string field_name)
484 return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
487 public void SetAssigned (VariableInfo vi)
489 CurrentUsageVector.SetAssigned (vi);
492 public void SetFieldAssigned (VariableInfo vi, string name)
494 CurrentUsageVector.SetFieldAssigned (vi, name);
497 public override string ToString ()
499 StringBuilder sb = new StringBuilder ();
500 sb.Append (GetType ());
508 sb.Append (Block.ID);
510 sb.Append (Block.StartLocation);
513 // sb.Append (Siblings.Length);
514 // sb.Append (" - ");
515 sb.Append (CurrentUsageVector);
517 return sb.ToString ();
521 get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
525 public class FlowBranchingBlock : FlowBranching
527 UsageVector sibling_list = null;
529 public FlowBranchingBlock (FlowBranching parent, BranchingType type,
530 SiblingType stype, Block block, Location loc)
531 : base (parent, type, stype, block, loc)
534 public override UsageVector CurrentUsageVector {
535 get { return sibling_list; }
538 protected override void AddSibling (UsageVector sibling)
540 sibling.Next = sibling_list;
541 sibling_list = sibling;
544 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
546 LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
548 return Parent.AddGotoOrigin (vector, goto_stmt);
551 goto_stmt.SetResolvedTarget (stmt);
552 stmt.AddUsageVector (vector);
556 public static void Error_UnknownLabel (Location loc, string label)
558 Report.Error(159, loc, "The label `{0}:' could not be found within the scope of the goto statement",
562 protected override UsageVector Merge ()
564 Report.Debug (2, " MERGING SIBLINGS", Name);
565 UsageVector vector = UsageVector.MergeSiblings (sibling_list, Location);
566 Report.Debug (2, " MERGING SIBLINGS DONE", Name, vector);
571 public class FlowBranchingBreakable : FlowBranchingBlock
573 UsageVector break_origins;
575 public FlowBranchingBreakable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
576 : base (parent, type, stype, block, loc)
579 public override bool AddBreakOrigin (UsageVector vector, Location loc)
581 vector = vector.Clone ();
582 vector.Next = break_origins;
583 break_origins = vector;
587 protected override UsageVector Merge ()
589 UsageVector vector = base.Merge ();
590 vector.MergeOrigins (break_origins);
595 public class FlowBranchingContinuable : FlowBranchingBlock
597 UsageVector continue_origins;
599 public FlowBranchingContinuable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
600 : base (parent, type, stype, block, loc)
603 public override bool AddContinueOrigin (UsageVector vector, Location loc)
605 vector = vector.Clone ();
606 vector.Next = continue_origins;
607 continue_origins = vector;
611 protected override UsageVector Merge ()
613 UsageVector vector = base.Merge ();
614 vector.MergeOrigins (continue_origins);
619 public class FlowBranchingLabeled : FlowBranchingBlock
621 LabeledStatement stmt;
624 public FlowBranchingLabeled (FlowBranching parent, LabeledStatement stmt)
625 : base (parent, BranchingType.Labeled, SiblingType.Conditional, null, stmt.loc)
628 CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
629 actual = CurrentUsageVector.Clone ();
631 // stand-in for backward jumps
632 CurrentUsageVector.ResetBarrier ();
635 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
637 if (goto_stmt.Target != stmt.Name)
638 return Parent.AddGotoOrigin (vector, goto_stmt);
641 goto_stmt.SetResolvedTarget (stmt);
642 actual.MergeOrigins (vector.Clone ());
647 protected override UsageVector Merge ()
649 UsageVector vector = base.Merge ();
651 if (actual.IsUnreachable)
652 Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
654 actual.MergeChild (vector, false);
659 public class FlowBranchingToplevel : FlowBranchingBlock
661 UsageVector return_origins;
663 public FlowBranchingToplevel (FlowBranching parent, ToplevelBlock stmt)
664 : base (parent, BranchingType.Toplevel, SiblingType.Conditional, stmt, stmt.loc)
669 // Check whether all `out' parameters have been assigned.
671 void CheckOutParameters (UsageVector vector, Location loc)
673 if (vector.IsUnreachable)
675 VariableMap param_map = Block.Toplevel.ParameterMap;
676 for (int i = 0; i < param_map.Count; i++) {
677 VariableInfo var = param_map [i];
682 if (vector.IsAssigned (var, false))
685 Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
690 public override bool InTryWithCatch ()
695 public override bool AddBreakOrigin (UsageVector vector, Location loc)
697 Report.Error (139, loc, "No enclosing loop out of which to break or continue");
701 public override bool AddContinueOrigin (UsageVector vector, Location loc)
703 Report.Error (139, loc, "No enclosing loop out of which to break or continue");
707 public override bool AddReturnOrigin (UsageVector vector, Location loc)
709 vector = vector.Clone ();
710 vector.Location = loc;
711 vector.Next = return_origins;
712 return_origins = vector;
716 public override void StealFinallyClauses (ref ArrayList list)
721 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
723 string name = goto_stmt.Target;
724 LabeledStatement s = Block.LookupLabel (name);
726 throw new InternalErrorException ("Shouldn't get here");
728 if (Parent == null) {
729 Error_UnknownLabel (goto_stmt.loc, name);
733 int errors = Report.Errors;
734 Parent.AddGotoOrigin (vector, goto_stmt);
735 if (errors == Report.Errors)
736 Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
740 protected override UsageVector Merge ()
742 for (UsageVector origin = return_origins; origin != null; origin = origin.Next)
743 CheckOutParameters (origin, origin.Location);
745 UsageVector vector = base.Merge ();
746 CheckOutParameters (vector, Block.loc);
747 // Note: we _do_not_ merge in the return origins
753 return Merge ().IsUnreachable;
757 public class FlowBranchingException : FlowBranching
759 ExceptionStatement stmt;
760 UsageVector current_vector;
761 UsageVector catch_vectors;
762 UsageVector finally_vector;
764 UsageVector break_origins;
765 UsageVector continue_origins;
766 UsageVector return_origins;
767 GotoOrigin goto_origins;
770 public GotoOrigin Next;
771 public Goto GotoStmt;
772 public UsageVector Vector;
774 public GotoOrigin (UsageVector vector, Goto goto_stmt, GotoOrigin next)
777 GotoStmt = goto_stmt;
784 public FlowBranchingException (FlowBranching parent,
785 ExceptionStatement stmt)
786 : base (parent, BranchingType.Exception, SiblingType.Try,
790 this.emit_finally = true;
793 protected override void AddSibling (UsageVector sibling)
795 switch (sibling.Type) {
796 case SiblingType.Try:
797 case SiblingType.Catch:
798 sibling.Next = catch_vectors;
799 catch_vectors = sibling;
801 case SiblingType.Finally:
802 finally_vector = sibling;
805 throw new InvalidOperationException ();
807 current_vector = sibling;
810 public override UsageVector CurrentUsageVector {
811 get { return current_vector; }
814 public override bool InTryWithCatch ()
816 if (finally_vector == null) {
818 if (t != null && t.HasCatch)
822 return base.InTryWithCatch ();
825 public override bool AddBreakOrigin (UsageVector vector, Location loc)
827 vector = vector.Clone ();
828 if (finally_vector != null) {
829 vector.MergeChild (finally_vector, false);
830 int errors = Report.Errors;
831 Parent.AddBreakOrigin (vector, loc);
832 if (errors == Report.Errors)
833 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
835 vector.Location = loc;
836 vector.Next = break_origins;
837 break_origins = vector;
842 public override bool AddContinueOrigin (UsageVector vector, Location loc)
844 vector = vector.Clone ();
845 if (finally_vector != null) {
846 vector.MergeChild (finally_vector, false);
847 int errors = Report.Errors;
848 Parent.AddContinueOrigin (vector, loc);
849 if (errors == Report.Errors)
850 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
852 vector.Location = loc;
853 vector.Next = continue_origins;
854 continue_origins = vector;
859 public override bool AddReturnOrigin (UsageVector vector, Location loc)
861 vector = vector.Clone ();
862 if (finally_vector != null) {
863 vector.MergeChild (finally_vector, false);
864 int errors = Report.Errors;
865 Parent.AddReturnOrigin (vector, loc);
866 if (errors == Report.Errors)
867 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
869 vector.Location = loc;
870 vector.Next = return_origins;
871 return_origins = vector;
876 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
878 LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
880 throw new InternalErrorException ("Shouldn't get here");
882 vector = vector.Clone ();
883 if (finally_vector != null) {
884 vector.MergeChild (finally_vector, false);
885 int errors = Report.Errors;
886 Parent.AddGotoOrigin (vector, goto_stmt);
887 if (errors == Report.Errors)
888 Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
890 goto_origins = new GotoOrigin (vector, goto_stmt, goto_origins);
895 public override void StealFinallyClauses (ref ArrayList list)
898 list = new ArrayList ();
900 emit_finally = false;
901 base.StealFinallyClauses (ref list);
904 public bool EmitFinally {
905 get { return emit_finally; }
908 protected override UsageVector Merge ()
910 Report.Debug (2, " MERGING TRY/CATCH", Name);
911 UsageVector vector = UsageVector.MergeSiblings (catch_vectors, Location);
912 Report.Debug (2, " MERGING TRY/CATCH DONE", vector);
914 if (finally_vector != null)
915 vector.MergeChild (finally_vector, false);
917 for (UsageVector origin = break_origins; origin != null; origin = origin.Next) {
918 if (finally_vector != null)
919 origin.MergeChild (finally_vector, false);
920 Parent.AddBreakOrigin (origin, origin.Location);
923 for (UsageVector origin = continue_origins; origin != null; origin = origin.Next) {
924 if (finally_vector != null)
925 origin.MergeChild (finally_vector, false);
926 Parent.AddContinueOrigin (origin, origin.Location);
929 for (UsageVector origin = return_origins; origin != null; origin = origin.Next) {
930 if (finally_vector != null)
931 origin.MergeChild (finally_vector, false);
932 Parent.AddReturnOrigin (origin, origin.Location);
935 for (GotoOrigin origin = goto_origins; origin != null; origin = origin.Next) {
936 if (finally_vector != null)
937 origin.Vector.MergeChild (finally_vector, false);
938 Parent.AddGotoOrigin (origin.Vector, origin.GotoStmt);
946 // This is used by the flow analysis code to keep track of the type of local variables
949 // The flow code uses a BitVector to keep track of whether a variable has been assigned
950 // or not. This is easy for fundamental types (int, char etc.) or reference types since
951 // you can only assign the whole variable as such.
953 // For structs, we also need to keep track of all its fields. To do this, we allocate one
954 // bit for the struct itself (it's used if you assign/access the whole struct) followed by
955 // one bit for each of its fields.
957 // This class computes this `layout' for each type.
959 public class TypeInfo
961 public readonly Type Type;
964 // Total number of bits a variable of this type consumes in the flow vector.
966 public readonly int TotalLength;
969 // Number of bits the simple fields of a variable of this type consume
970 // in the flow vector.
972 public readonly int Length;
975 // This is only used by sub-structs.
977 public readonly int Offset;
980 // If this is a struct.
982 public readonly bool IsStruct;
985 // If this is a struct, all fields which are structs theirselves.
987 public TypeInfo[] SubStructInfo;
989 protected readonly StructInfo struct_info;
990 private static Hashtable type_hash = new Hashtable ();
992 public static TypeInfo GetTypeInfo (Type type)
994 TypeInfo info = (TypeInfo) type_hash [type];
998 info = new TypeInfo (type);
999 type_hash.Add (type, info);
1003 public static TypeInfo GetTypeInfo (TypeContainer tc)
1005 TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
1009 info = new TypeInfo (tc);
1010 type_hash.Add (tc.TypeBuilder, info);
1014 private TypeInfo (Type type)
1018 struct_info = StructInfo.GetStructInfo (type);
1019 if (struct_info != null) {
1020 Length = struct_info.Length;
1021 TotalLength = struct_info.TotalLength;
1022 SubStructInfo = struct_info.StructFields;
1031 private TypeInfo (TypeContainer tc)
1033 this.Type = tc.TypeBuilder;
1035 struct_info = StructInfo.GetStructInfo (tc);
1036 if (struct_info != null) {
1037 Length = struct_info.Length;
1038 TotalLength = struct_info.TotalLength;
1039 SubStructInfo = struct_info.StructFields;
1048 protected TypeInfo (StructInfo struct_info, int offset)
1050 this.struct_info = struct_info;
1051 this.Offset = offset;
1052 this.Length = struct_info.Length;
1053 this.TotalLength = struct_info.TotalLength;
1054 this.SubStructInfo = struct_info.StructFields;
1055 this.Type = struct_info.Type;
1056 this.IsStruct = true;
1059 public int GetFieldIndex (string name)
1061 if (struct_info == null)
1064 return struct_info [name];
1067 public TypeInfo GetSubStruct (string name)
1069 if (struct_info == null)
1072 return struct_info.GetStructField (name);
1076 // A struct's constructor must always assign all fields.
1077 // This method checks whether it actually does so.
1079 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1081 if (struct_info == null)
1085 for (int i = 0; i < struct_info.Count; i++) {
1086 FieldInfo field = struct_info.Fields [i];
1088 if (!branching.IsFieldAssigned (vi, field.Name)) {
1089 Report.Error (171, loc,
1090 "Field `{0}' must be fully assigned before control leaves the constructor",
1091 TypeManager.GetFullNameSignature (field));
1099 public override string ToString ()
1101 return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1102 Type, Offset, Length, TotalLength);
1105 protected class StructInfo {
1106 public readonly Type Type;
1107 public readonly FieldInfo[] Fields;
1108 public readonly TypeInfo[] StructFields;
1109 public readonly int Count;
1110 public readonly int CountPublic;
1111 public readonly int CountNonPublic;
1112 public readonly int Length;
1113 public readonly int TotalLength;
1114 public readonly bool HasStructFields;
1116 private static Hashtable field_type_hash = new Hashtable ();
1117 private Hashtable struct_field_hash;
1118 private Hashtable field_hash;
1120 protected bool InTransit = false;
1122 // Private constructor. To save memory usage, we only need to create one instance
1123 // of this class per struct type.
1124 private StructInfo (Type type)
1128 field_type_hash.Add (type, this);
1130 if (type is TypeBuilder) {
1131 TypeContainer tc = TypeManager.LookupTypeContainer (type);
1133 ArrayList fields = null;
1137 ArrayList public_fields = new ArrayList ();
1138 ArrayList non_public_fields = new ArrayList ();
1140 if (fields != null) {
1141 foreach (FieldBase field in fields) {
1142 if ((field.ModFlags & Modifiers.STATIC) != 0)
1144 if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1145 public_fields.Add (field.FieldBuilder);
1147 non_public_fields.Add (field.FieldBuilder);
1151 CountPublic = public_fields.Count;
1152 CountNonPublic = non_public_fields.Count;
1153 Count = CountPublic + CountNonPublic;
1155 Fields = new FieldInfo [Count];
1156 public_fields.CopyTo (Fields, 0);
1157 non_public_fields.CopyTo (Fields, CountPublic);
1159 } else if (type is GenericTypeParameterBuilder) {
1160 CountPublic = CountNonPublic = Count = 0;
1162 Fields = new FieldInfo [0];
1165 FieldInfo[] public_fields = type.GetFields (
1166 BindingFlags.Instance|BindingFlags.Public);
1167 FieldInfo[] non_public_fields = type.GetFields (
1168 BindingFlags.Instance|BindingFlags.NonPublic);
1170 CountPublic = public_fields.Length;
1171 CountNonPublic = non_public_fields.Length;
1172 Count = CountPublic + CountNonPublic;
1174 Fields = new FieldInfo [Count];
1175 public_fields.CopyTo (Fields, 0);
1176 non_public_fields.CopyTo (Fields, CountPublic);
1179 struct_field_hash = new Hashtable ();
1180 field_hash = new Hashtable ();
1183 StructFields = new TypeInfo [Count];
1184 StructInfo[] sinfo = new StructInfo [Count];
1188 for (int i = 0; i < Count; i++) {
1189 FieldInfo field = (FieldInfo) Fields [i];
1191 sinfo [i] = GetStructInfo (field.FieldType);
1192 if (sinfo [i] == null)
1193 field_hash.Add (field.Name, ++Length);
1194 else if (sinfo [i].InTransit) {
1195 Report.Error (523, String.Format (
1196 "Struct member `{0}.{1}' of type `{2}' causes " +
1197 "a cycle in the structure layout",
1198 type, field.Name, sinfo [i].Type));
1206 TotalLength = Length + 1;
1207 for (int i = 0; i < Count; i++) {
1208 FieldInfo field = (FieldInfo) Fields [i];
1210 if (sinfo [i] == null)
1213 field_hash.Add (field.Name, TotalLength);
1215 HasStructFields = true;
1216 StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1217 struct_field_hash.Add (field.Name, StructFields [i]);
1218 TotalLength += sinfo [i].TotalLength;
1222 public int this [string name] {
1224 if (field_hash.Contains (name))
1225 return (int) field_hash [name];
1231 public TypeInfo GetStructField (string name)
1233 return (TypeInfo) struct_field_hash [name];
1236 public static StructInfo GetStructInfo (Type type)
1238 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1239 TypeManager.IsBuiltinType (type))
1242 StructInfo info = (StructInfo) field_type_hash [type];
1246 return new StructInfo (type);
1249 public static StructInfo GetStructInfo (TypeContainer tc)
1251 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1255 return new StructInfo (tc.TypeBuilder);
1261 // This is used by the flow analysis code to store information about a single local variable
1262 // or parameter. Depending on the variable's type, we need to allocate one or more elements
1263 // in the BitVector - if it's a fundamental or reference type, we just need to know whether
1264 // it has been assigned or not, but for structs, we need this information for each of its fields.
1266 public class VariableInfo {
1267 public readonly string Name;
1268 public readonly TypeInfo TypeInfo;
1271 // The bit offset of this variable in the flow vector.
1273 public readonly int Offset;
1276 // The number of bits this variable needs in the flow vector.
1277 // The first bit always specifies whether the variable as such has been assigned while
1278 // the remaining bits contain this information for each of a struct's fields.
1280 public readonly int Length;
1283 // If this is a parameter of local variable.
1285 public readonly bool IsParameter;
1287 public readonly LocalInfo LocalInfo;
1288 public readonly int ParameterIndex;
1290 readonly VariableInfo Parent;
1291 VariableInfo[] sub_info;
1293 protected VariableInfo (string name, Type type, int offset)
1296 this.Offset = offset;
1297 this.TypeInfo = TypeInfo.GetTypeInfo (type);
1299 Length = TypeInfo.TotalLength;
1304 protected VariableInfo (VariableInfo parent, TypeInfo type)
1306 this.Name = parent.Name;
1307 this.TypeInfo = type;
1308 this.Offset = parent.Offset + type.Offset;
1309 this.Parent = parent;
1310 this.Length = type.TotalLength;
1312 this.IsParameter = parent.IsParameter;
1313 this.LocalInfo = parent.LocalInfo;
1314 this.ParameterIndex = parent.ParameterIndex;
1319 protected void Initialize ()
1321 TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1322 if (sub_fields != null) {
1323 sub_info = new VariableInfo [sub_fields.Length];
1324 for (int i = 0; i < sub_fields.Length; i++) {
1325 if (sub_fields [i] != null)
1326 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1329 sub_info = new VariableInfo [0];
1332 public VariableInfo (LocalInfo local_info, int offset)
1333 : this (local_info.Name, local_info.VariableType, offset)
1335 this.LocalInfo = local_info;
1336 this.IsParameter = false;
1339 public VariableInfo (string name, Type type, int param_idx, int offset)
1340 : this (name, type, offset)
1342 this.ParameterIndex = param_idx;
1343 this.IsParameter = true;
1346 public bool IsAssigned (EmitContext ec)
1348 return !ec.DoFlowAnalysis ||
1349 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1350 ec.CurrentBranching.IsAssigned (this);
1353 public bool IsAssigned (EmitContext ec, Location loc)
1355 if (IsAssigned (ec))
1358 Report.Error (165, loc,
1359 "Use of unassigned local variable `" + Name + "'");
1360 ec.CurrentBranching.SetAssigned (this);
1364 public bool IsAssigned (MyBitVector vector)
1369 if (vector [Offset])
1372 for (VariableInfo parent = Parent; parent != null; parent = parent.Parent)
1373 if (vector [parent.Offset])
1376 // Return unless this is a struct.
1377 if (!TypeInfo.IsStruct)
1380 // Ok, so each field must be assigned.
1381 for (int i = 0; i < TypeInfo.Length; i++) {
1382 if (!vector [Offset + i + 1])
1386 // Ok, now check all fields which are structs.
1387 for (int i = 0; i < sub_info.Length; i++) {
1388 VariableInfo sinfo = sub_info [i];
1392 if (!sinfo.IsAssigned (vector))
1396 vector [Offset] = true;
1400 public void SetAssigned (EmitContext ec)
1402 if (ec.DoFlowAnalysis)
1403 ec.CurrentBranching.SetAssigned (this);
1406 public void SetAssigned (MyBitVector vector)
1408 vector [Offset] = true;
1411 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1413 if (!ec.DoFlowAnalysis ||
1414 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1415 ec.CurrentBranching.IsFieldAssigned (this, name))
1418 Report.Error (170, loc,
1419 "Use of possibly unassigned field `" + name + "'");
1420 ec.CurrentBranching.SetFieldAssigned (this, name);
1424 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1426 int field_idx = TypeInfo.GetFieldIndex (field_name);
1431 return vector [Offset + field_idx];
1434 public void SetFieldAssigned (EmitContext ec, string name)
1436 if (ec.DoFlowAnalysis)
1437 ec.CurrentBranching.SetFieldAssigned (this, name);
1440 public void SetFieldAssigned (MyBitVector vector, string field_name)
1442 int field_idx = TypeInfo.GetFieldIndex (field_name);
1447 vector [Offset + field_idx] = true;
1450 public VariableInfo GetSubStruct (string name)
1452 TypeInfo type = TypeInfo.GetSubStruct (name);
1457 return new VariableInfo (this, type);
1460 public override string ToString ()
1462 return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1463 Name, TypeInfo, Offset, Length, IsParameter);
1468 // This is used by the flow code to hold the `layout' of the flow vector for
1469 // all locals and all parameters (ie. we create one instance of this class for the
1470 // locals and another one for the params).
1472 public class VariableMap {
1474 // The number of variables in the map.
1476 public readonly int Count;
1479 // Total length of the flow vector for this map.
1481 public readonly int Length;
1485 public VariableMap (Parameters ip)
1487 Count = ip != null ? ip.Count : 0;
1489 // Dont bother allocating anything!
1495 for (int i = 0; i < Count; i++) {
1496 Parameter.Modifier mod = ip.ParameterModifier (i);
1498 if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
1501 // Dont allocate till we find an out var.
1503 map = new VariableInfo [Count];
1505 map [i] = new VariableInfo (ip.ParameterName (i),
1506 TypeManager.GetElementType (ip.ParameterType (i)), i, Length);
1508 Length += map [i].Length;
1513 // Returns the VariableInfo for variable @index or null if we don't need to
1514 // compute assignment info for this variable.
1516 public VariableInfo this [int index] {
1525 public override string ToString ()
1527 return String.Format ("VariableMap ({0}:{1})", Count, Length);
1532 // This is a special bit vector which can inherit from another bit vector doing a
1533 // copy-on-write strategy. The inherited vector may have a smaller size than the
1536 public class MyBitVector {
1537 public readonly int Count;
1538 public static readonly MyBitVector Empty = new MyBitVector ();
1540 // Invariant: vector != null => vector.Count == Count
1541 // Invariant: vector == null || shared == null
1542 // i.e., at most one of 'vector' and 'shared' can be non-null. They can both be null -- that means all-ones
1543 // The object in 'shared' cannot be modified, while 'vector' can be freely modified
1544 BitArray vector, shared;
1548 shared = new BitArray (0, false);
1551 public MyBitVector (MyBitVector InheritsFrom, int Count)
1553 if (InheritsFrom != null)
1554 shared = InheritsFrom.Shared;
1559 // Use this accessor to get a shareable copy of the underlying BitArray representation
1562 // Post-condition: vector == null
1563 if (shared == null) {
1572 // Get/set bit `index' in the bit vector.
1574 public bool this [int index] {
1577 throw new ArgumentOutOfRangeException ();
1580 return vector [index];
1583 if (index < shared.Count)
1584 return shared [index];
1589 // Only copy the vector if we're actually modifying it.
1590 if (this [index] != value) {
1592 initialize_vector ();
1593 vector [index] = value;
1599 // Performs an `or' operation on the bit vector. The `new_vector' may have a
1600 // different size than the current one.
1602 private MyBitVector Or (MyBitVector new_vector)
1604 if (Count == 0 || new_vector.Count == 0)
1607 BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1610 int n = new_vector.Count;
1612 for (int i = 0; i < n; ++i)
1620 if (Count == o.Count) {
1621 if (vector == null) {
1624 initialize_vector ();
1634 for (int i = 0; i < min; i++) {
1643 // Performs an `and' operation on the bit vector. The `new_vector' may have
1644 // a different size than the current one.
1646 private MyBitVector And (MyBitVector new_vector)
1651 BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1654 for (int i = new_vector.Count; i < Count; ++i)
1664 if (Count == o.Count) {
1665 if (vector == null) {
1666 if (shared == null) {
1667 shared = new_vector.Shared;
1670 initialize_vector ();
1680 for (int i = 0; i < min; i++) {
1685 for (int i = min; i < Count; i++)
1691 public static MyBitVector operator & (MyBitVector a, MyBitVector b)
1699 if (a.Count > b.Count)
1700 return a.Clone ().And (b);
1702 return b.Clone ().And (a);
1705 public static MyBitVector operator | (MyBitVector a, MyBitVector b)
1710 return new MyBitVector (null, b.Count);
1712 return new MyBitVector (null, a.Count);
1713 if (a.Count > b.Count)
1714 return a.Clone ().Or (b);
1716 return b.Clone ().Or (a);
1719 public MyBitVector Clone ()
1721 return Count == 0 ? Empty : new MyBitVector (this, Count);
1724 public void SetAll (bool value)
1726 // Don't clobber Empty
1729 shared = value ? null : Empty.Shared;
1733 void initialize_vector ()
1735 // Post-condition: vector != null
1736 if (shared == null) {
1737 vector = new BitArray (Count, true);
1741 vector = new BitArray (shared);
1742 if (Count != vector.Count)
1743 vector.Length = Count;
1747 StringBuilder Dump (StringBuilder sb)
1749 BitArray dump = vector == null ? shared : vector;
1751 return sb.Append ("/");
1754 for (int i = 0; i < dump.Count; i++)
1755 sb.Append (dump [i] ? "1" : "0");
1759 public override string ToString ()
1761 return Dump (new StringBuilder ("{")).Append ("}").ToString ();