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 protected VariableMap param_map, local_map;
121 static int next_id = 0;
125 // The vector contains a BitArray with information about which local variables
126 // and parameters are already initialized at the current code position.
128 public class UsageVector {
130 // The type of this branching.
132 public readonly SiblingType Type;
135 // Start location of this branching.
137 public Location Location;
140 // This is only valid for SwitchSection, Try, Catch and Finally.
142 public readonly Block Block;
145 // The number of parameters in this block.
147 public readonly int CountParameters;
150 // The number of locals in this block.
152 public readonly int CountLocals;
155 // If not null, then we inherit our state from this vector and do a
156 // copy-on-write. If null, then we're the first sibling in a top-level
157 // block and inherit from the empty vector.
159 public readonly UsageVector InheritsFrom;
162 // This is used to construct a list of UsageVector's.
164 public UsageVector Next;
169 MyBitVector locals, parameters;
172 static int next_id = 0;
176 // Normally, you should not use any of these constructors.
178 public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc, int num_params, int num_locals)
183 this.InheritsFrom = parent;
184 this.CountParameters = num_params;
185 this.CountLocals = num_locals;
187 locals = num_locals == 0
189 : new MyBitVector (parent == null ? MyBitVector.Empty : parent.locals, num_locals);
191 parameters = num_params == 0
193 : new MyBitVector (parent == null ? MyBitVector.Empty : parent.parameters, num_params);
196 is_unreachable = parent.is_unreachable;
202 public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc)
203 : this (type, parent, block, loc, parent.CountParameters, parent.CountLocals)
206 private UsageVector (MyBitVector parameters, MyBitVector locals, bool is_unreachable, Block block, Location loc)
208 this.Type = SiblingType.Block;
212 this.is_unreachable = is_unreachable;
214 this.parameters = parameters;
215 this.locals = locals;
222 // This does a deep copy of the usage vector.
224 public UsageVector Clone ()
226 UsageVector retval = new UsageVector (Type, null, Block, Location, CountParameters, CountLocals);
228 retval.locals = locals.Clone ();
229 retval.parameters = parameters.Clone ();
230 retval.is_unreachable = is_unreachable;
235 public bool IsAssigned (VariableInfo var, bool ignoreReachability)
237 if (!ignoreReachability && !var.IsParameter && IsUnreachable)
240 return var.IsAssigned (var.IsParameter ? parameters : locals);
243 public void SetAssigned (VariableInfo var)
245 if (!var.IsParameter && IsUnreachable)
248 var.SetAssigned (var.IsParameter ? parameters : locals);
251 public bool IsFieldAssigned (VariableInfo var, string name)
253 if (!var.IsParameter && IsUnreachable)
256 return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name);
259 public void SetFieldAssigned (VariableInfo var, string name)
261 if (!var.IsParameter && IsUnreachable)
264 var.SetFieldAssigned (var.IsParameter ? parameters : locals, name);
267 public bool IsUnreachable {
268 get { return is_unreachable; }
271 public void ResetBarrier ()
273 is_unreachable = false;
278 is_unreachable = true;
281 public static UsageVector MergeSiblings (UsageVector sibling_list, Location loc)
283 if (sibling_list.Next == null)
286 MyBitVector locals = null;
287 MyBitVector parameters = null;
288 bool is_unreachable = sibling_list.is_unreachable;
290 if (!sibling_list.IsUnreachable) {
291 locals &= sibling_list.locals;
292 parameters &= sibling_list.parameters;
295 for (UsageVector child = sibling_list.Next; child != null; child = child.Next) {
296 is_unreachable &= child.is_unreachable;
298 if (!child.IsUnreachable) {
299 locals &= child.locals;
300 parameters &= child.parameters;
304 return new UsageVector (parameters, locals, is_unreachable, null, loc);
308 // Merges a child branching.
310 public UsageVector MergeChild (UsageVector child, bool overwrite)
312 Report.Debug (2, " MERGING CHILD EFFECTS", this, child, Type);
314 bool new_isunr = child.is_unreachable;
317 // We've now either reached the point after the branching or we will
318 // never get there since we always return or always throw an exception.
320 // If we can reach the point after the branching, mark all locals and
321 // parameters as initialized which have been initialized in all branches
322 // we need to look at (see above).
325 if ((Type == SiblingType.SwitchSection) && !new_isunr) {
326 Report.Error (163, Location,
327 "Control cannot fall through from one " +
328 "case label to another");
332 locals |= child.locals;
333 parameters |= child.parameters;
336 is_unreachable = new_isunr;
338 is_unreachable |= new_isunr;
343 public void MergeOrigins (UsageVector o_vectors)
345 Report.Debug (1, " MERGING BREAK ORIGINS", this);
347 if (o_vectors == null)
352 locals.SetAll (true);
353 if (parameters != null)
354 parameters.SetAll (true);
357 for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) {
358 Report.Debug (1, " MERGING BREAK ORIGIN", vector);
359 if (vector.IsUnreachable)
361 locals &= vector.locals;
362 parameters &= vector.parameters;
363 is_unreachable &= vector.is_unreachable;
366 Report.Debug (1, " MERGING BREAK ORIGINS DONE", this);
373 public override string ToString ()
375 return String.Format ("Vector ({0},{1},{2}-{3}-{4})", Type, id, is_unreachable, parameters, locals);
380 // Creates a new flow branching which is contained in `parent'.
381 // You should only pass non-null for the `block' argument if this block
382 // introduces any new variables - in this case, we need to create a new
383 // usage vector with a different size than our parent's one.
385 protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
386 Block block, Location loc)
396 param_map = Block.ParameterMap;
397 local_map = Block.LocalMap;
399 UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
400 vector = new UsageVector (
401 stype, parent_vector, Block, loc,
402 param_map.Length, local_map.Length);
404 param_map = Parent.param_map;
405 local_map = Parent.local_map;
406 vector = new UsageVector (
407 stype, Parent.CurrentUsageVector, null, loc);
413 public abstract UsageVector CurrentUsageVector {
418 // Creates a sibling of the current usage vector.
420 public virtual void CreateSibling (Block block, SiblingType type)
422 UsageVector vector = new UsageVector (
423 type, Parent.CurrentUsageVector, block, Location);
426 Report.Debug (1, " CREATED SIBLING", CurrentUsageVector);
429 public void CreateSibling ()
431 CreateSibling (null, SiblingType.Conditional);
434 protected abstract void AddSibling (UsageVector uv);
436 protected abstract UsageVector Merge ();
439 // Merge a child branching.
441 public UsageVector MergeChild (FlowBranching child)
443 bool overwrite = child.Type == BranchingType.Labeled ||
444 (child.Type == BranchingType.Block && child.Block.Implicit);
445 Report.Debug (2, " MERGING CHILD", this, child);
446 UsageVector result = CurrentUsageVector.MergeChild (child.Merge (), overwrite);
447 Report.Debug (2, " MERGING CHILD DONE", this, result);
451 public virtual bool InTryWithCatch ()
453 return Parent.InTryWithCatch ();
456 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
457 public virtual bool AddBreakOrigin (UsageVector vector, Location loc)
459 return Parent.AddBreakOrigin (vector, loc);
462 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
463 public virtual bool AddContinueOrigin (UsageVector vector, Location loc)
465 return Parent.AddContinueOrigin (vector, loc);
468 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
469 public virtual bool AddReturnOrigin (UsageVector vector, Location loc)
471 return Parent.AddReturnOrigin (vector, loc);
474 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
475 public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
477 return Parent.AddGotoOrigin (vector, goto_stmt);
480 public virtual void StealFinallyClauses (ref ArrayList list)
482 Parent.StealFinallyClauses (ref list);
485 public bool IsAssigned (VariableInfo vi)
487 return CurrentUsageVector.IsAssigned (vi, false);
490 public bool IsFieldAssigned (VariableInfo vi, string field_name)
492 return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
495 public void SetAssigned (VariableInfo vi)
497 CurrentUsageVector.SetAssigned (vi);
500 public void SetFieldAssigned (VariableInfo vi, string name)
502 CurrentUsageVector.SetFieldAssigned (vi, name);
505 public override string ToString ()
507 StringBuilder sb = new StringBuilder ();
508 sb.Append (GetType ());
516 sb.Append (Block.ID);
518 sb.Append (Block.StartLocation);
521 // sb.Append (Siblings.Length);
522 // sb.Append (" - ");
523 sb.Append (CurrentUsageVector);
525 return sb.ToString ();
529 get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
533 public class FlowBranchingBlock : FlowBranching
535 UsageVector sibling_list = null;
537 public FlowBranchingBlock (FlowBranching parent, BranchingType type,
538 SiblingType stype, Block block, Location loc)
539 : base (parent, type, stype, block, loc)
542 public override UsageVector CurrentUsageVector {
543 get { return sibling_list; }
546 protected override void AddSibling (UsageVector sibling)
548 sibling.Next = sibling_list;
549 sibling_list = sibling;
552 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
554 LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
556 return Parent.AddGotoOrigin (vector, goto_stmt);
559 goto_stmt.SetResolvedTarget (stmt);
560 stmt.AddUsageVector (vector);
564 protected override UsageVector Merge ()
566 Report.Debug (2, " MERGING SIBLINGS", Name);
567 UsageVector vector = UsageVector.MergeSiblings (sibling_list, Location);
568 Report.Debug (2, " MERGING SIBLINGS DONE", Name, vector);
573 public class FlowBranchingBreakable : FlowBranchingBlock
575 UsageVector break_origins;
577 public FlowBranchingBreakable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
578 : base (parent, type, stype, block, loc)
581 public override bool AddBreakOrigin (UsageVector vector, Location loc)
583 vector = vector.Clone ();
584 vector.Next = break_origins;
585 break_origins = vector;
589 protected override UsageVector Merge ()
591 UsageVector vector = base.Merge ();
592 vector.MergeOrigins (break_origins);
597 public class FlowBranchingContinuable : FlowBranchingBlock
599 UsageVector continue_origins;
601 public FlowBranchingContinuable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
602 : base (parent, type, stype, block, loc)
605 public override bool AddContinueOrigin (UsageVector vector, Location loc)
607 vector = vector.Clone ();
608 vector.Next = continue_origins;
609 continue_origins = vector;
613 protected override UsageVector Merge ()
615 UsageVector vector = base.Merge ();
616 vector.MergeOrigins (continue_origins);
621 public class FlowBranchingLabeled : FlowBranchingBlock
623 LabeledStatement stmt;
626 public FlowBranchingLabeled (FlowBranching parent, LabeledStatement stmt)
627 : base (parent, BranchingType.Labeled, SiblingType.Conditional, null, stmt.loc)
630 CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
631 actual = CurrentUsageVector.Clone ();
633 // stand-in for backward jumps
634 CurrentUsageVector.ResetBarrier ();
637 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
639 if (goto_stmt.Target != stmt.Name)
640 return Parent.AddGotoOrigin (vector, goto_stmt);
643 goto_stmt.SetResolvedTarget (stmt);
644 actual.MergeOrigins (vector.Clone ());
649 protected override UsageVector Merge ()
651 UsageVector vector = base.Merge ();
653 if (actual.IsUnreachable)
654 Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
656 actual.MergeChild (vector, false);
661 public class FlowBranchingToplevel : FlowBranchingBlock
663 UsageVector return_origins;
665 public FlowBranchingToplevel (FlowBranching parent, ToplevelBlock stmt)
666 : base (parent, BranchingType.Toplevel, SiblingType.Conditional, stmt, stmt.loc)
671 // Check whether all `out' parameters have been assigned.
673 void CheckOutParameters (UsageVector vector, Location loc)
675 if (vector.IsUnreachable)
677 for (int i = 0; i < param_map.Count; i++) {
678 VariableInfo var = param_map [i];
683 if (vector.IsAssigned (var, false))
686 Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
691 public override bool InTryWithCatch ()
696 public override bool AddBreakOrigin (UsageVector vector, Location loc)
698 Report.Error (139, loc, "No enclosing loop out of which to break or continue");
702 public override bool AddContinueOrigin (UsageVector vector, Location loc)
704 Report.Error (139, loc, "No enclosing loop out of which to break or continue");
708 public override bool AddReturnOrigin (UsageVector vector, Location loc)
710 vector = vector.Clone ();
711 vector.Location = loc;
712 vector.Next = return_origins;
713 return_origins = vector;
717 public override void StealFinallyClauses (ref ArrayList list)
722 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
724 string name = goto_stmt.Target;
725 LabeledStatement s = Block.LookupLabel (name);
727 throw new InternalErrorException ("Shouldn't get here");
729 if (Parent == null) {
730 Report.Error (159, goto_stmt.loc, "No such label `{0}' in this scope", name);
734 int errors = Report.Errors;
735 Parent.AddGotoOrigin (vector, goto_stmt);
736 if (errors == Report.Errors)
737 Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
741 protected override UsageVector Merge ()
743 for (UsageVector origin = return_origins; origin != null; origin = origin.Next)
744 CheckOutParameters (origin, origin.Location);
746 UsageVector vector = base.Merge ();
747 CheckOutParameters (vector, Block.loc);
748 // Note: we _do_not_ merge in the return origins
754 return Merge ().IsUnreachable;
758 public class FlowBranchingException : FlowBranching
760 ExceptionStatement stmt;
761 UsageVector current_vector;
762 UsageVector catch_vectors;
763 UsageVector finally_vector;
765 UsageVector break_origins;
766 UsageVector continue_origins;
767 UsageVector return_origins;
768 GotoOrigin goto_origins;
771 public GotoOrigin Next;
772 public Goto GotoStmt;
773 public UsageVector Vector;
775 public GotoOrigin (UsageVector vector, Goto goto_stmt, GotoOrigin next)
778 GotoStmt = goto_stmt;
785 public FlowBranchingException (FlowBranching parent,
786 ExceptionStatement stmt)
787 : base (parent, BranchingType.Exception, SiblingType.Try,
791 this.emit_finally = true;
794 protected override void AddSibling (UsageVector sibling)
796 switch (sibling.Type) {
797 case SiblingType.Try:
798 case SiblingType.Catch:
799 sibling.Next = catch_vectors;
800 catch_vectors = sibling;
802 case SiblingType.Finally:
803 finally_vector = sibling;
806 throw new InvalidOperationException ();
808 current_vector = sibling;
811 public override UsageVector CurrentUsageVector {
812 get { return current_vector; }
815 public override bool InTryWithCatch ()
817 if (finally_vector == null) {
819 if (t != null && t.HasCatch)
823 return base.InTryWithCatch ();
826 public override bool AddBreakOrigin (UsageVector vector, Location loc)
828 vector = vector.Clone ();
829 if (finally_vector != null) {
830 vector.MergeChild (finally_vector, false);
831 int errors = Report.Errors;
832 Parent.AddBreakOrigin (vector, loc);
833 if (errors == Report.Errors)
834 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
836 vector.Location = loc;
837 vector.Next = break_origins;
838 break_origins = vector;
843 public override bool AddContinueOrigin (UsageVector vector, Location loc)
845 vector = vector.Clone ();
846 if (finally_vector != null) {
847 vector.MergeChild (finally_vector, false);
848 int errors = Report.Errors;
849 Parent.AddContinueOrigin (vector, loc);
850 if (errors == Report.Errors)
851 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
853 vector.Location = loc;
854 vector.Next = continue_origins;
855 continue_origins = vector;
860 public override bool AddReturnOrigin (UsageVector vector, Location loc)
862 vector = vector.Clone ();
863 if (finally_vector != null) {
864 vector.MergeChild (finally_vector, false);
865 int errors = Report.Errors;
866 Parent.AddReturnOrigin (vector, loc);
867 if (errors == Report.Errors)
868 Report.Error (157, loc, "Control cannot leave the body of a finally clause");
870 vector.Location = loc;
871 vector.Next = return_origins;
872 return_origins = vector;
877 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
879 LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
881 throw new InternalErrorException ("Shouldn't get here");
883 vector = vector.Clone ();
884 if (finally_vector != null) {
885 vector.MergeChild (finally_vector, false);
886 int errors = Report.Errors;
887 Parent.AddGotoOrigin (vector, goto_stmt);
888 if (errors == Report.Errors)
889 Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
891 goto_origins = new GotoOrigin (vector, goto_stmt, goto_origins);
896 public override void StealFinallyClauses (ref ArrayList list)
899 list = new ArrayList ();
901 emit_finally = false;
902 base.StealFinallyClauses (ref list);
905 public bool EmitFinally {
906 get { return emit_finally; }
909 protected override UsageVector Merge ()
911 Report.Debug (2, " MERGING TRY/CATCH", Name);
912 UsageVector vector = UsageVector.MergeSiblings (catch_vectors, Location);
913 Report.Debug (2, " MERGING TRY/CATCH DONE", vector);
915 if (finally_vector != null)
916 vector.MergeChild (finally_vector, false);
918 for (UsageVector origin = break_origins; origin != null; origin = origin.Next) {
919 if (finally_vector != null)
920 origin.MergeChild (finally_vector, false);
921 Parent.AddBreakOrigin (origin, origin.Location);
924 for (UsageVector origin = continue_origins; origin != null; origin = origin.Next) {
925 if (finally_vector != null)
926 origin.MergeChild (finally_vector, false);
927 Parent.AddContinueOrigin (origin, origin.Location);
930 for (UsageVector origin = return_origins; origin != null; origin = origin.Next) {
931 if (finally_vector != null)
932 origin.MergeChild (finally_vector, false);
933 Parent.AddReturnOrigin (origin, origin.Location);
936 for (GotoOrigin origin = goto_origins; origin != null; origin = origin.Next) {
937 if (finally_vector != null)
938 origin.Vector.MergeChild (finally_vector, false);
939 Parent.AddGotoOrigin (origin.Vector, origin.GotoStmt);
947 // This is used by the flow analysis code to keep track of the type of local variables
950 // The flow code uses a BitVector to keep track of whether a variable has been assigned
951 // or not. This is easy for fundamental types (int, char etc.) or reference types since
952 // you can only assign the whole variable as such.
954 // For structs, we also need to keep track of all its fields. To do this, we allocate one
955 // bit for the struct itself (it's used if you assign/access the whole struct) followed by
956 // one bit for each of its fields.
958 // This class computes this `layout' for each type.
960 public class TypeInfo
962 public readonly Type Type;
965 // Total number of bits a variable of this type consumes in the flow vector.
967 public readonly int TotalLength;
970 // Number of bits the simple fields of a variable of this type consume
971 // in the flow vector.
973 public readonly int Length;
976 // This is only used by sub-structs.
978 public readonly int Offset;
981 // If this is a struct.
983 public readonly bool IsStruct;
986 // If this is a struct, all fields which are structs theirselves.
988 public TypeInfo[] SubStructInfo;
990 protected readonly StructInfo struct_info;
991 private static Hashtable type_hash = new Hashtable ();
993 public static TypeInfo GetTypeInfo (Type type)
995 TypeInfo info = (TypeInfo) type_hash [type];
999 info = new TypeInfo (type);
1000 type_hash.Add (type, info);
1004 public static TypeInfo GetTypeInfo (TypeContainer tc)
1006 TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
1010 info = new TypeInfo (tc);
1011 type_hash.Add (tc.TypeBuilder, info);
1015 private TypeInfo (Type type)
1019 struct_info = StructInfo.GetStructInfo (type);
1020 if (struct_info != null) {
1021 Length = struct_info.Length;
1022 TotalLength = struct_info.TotalLength;
1023 SubStructInfo = struct_info.StructFields;
1032 private TypeInfo (TypeContainer tc)
1034 this.Type = tc.TypeBuilder;
1036 struct_info = StructInfo.GetStructInfo (tc);
1037 if (struct_info != null) {
1038 Length = struct_info.Length;
1039 TotalLength = struct_info.TotalLength;
1040 SubStructInfo = struct_info.StructFields;
1049 protected TypeInfo (StructInfo struct_info, int offset)
1051 this.struct_info = struct_info;
1052 this.Offset = offset;
1053 this.Length = struct_info.Length;
1054 this.TotalLength = struct_info.TotalLength;
1055 this.SubStructInfo = struct_info.StructFields;
1056 this.Type = struct_info.Type;
1057 this.IsStruct = true;
1060 public int GetFieldIndex (string name)
1062 if (struct_info == null)
1065 return struct_info [name];
1068 public TypeInfo GetSubStruct (string name)
1070 if (struct_info == null)
1073 return struct_info.GetStructField (name);
1077 // A struct's constructor must always assign all fields.
1078 // This method checks whether it actually does so.
1080 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1082 if (struct_info == null)
1086 for (int i = 0; i < struct_info.Count; i++) {
1087 FieldInfo field = struct_info.Fields [i];
1089 if (!branching.IsFieldAssigned (vi, field.Name)) {
1090 Report.Error (171, loc,
1091 "Field `{0}' must be fully assigned before control leaves the constructor",
1092 TypeManager.GetFullNameSignature (field));
1100 public override string ToString ()
1102 return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1103 Type, Offset, Length, TotalLength);
1106 protected class StructInfo {
1107 public readonly Type Type;
1108 public readonly FieldInfo[] Fields;
1109 public readonly TypeInfo[] StructFields;
1110 public readonly int Count;
1111 public readonly int CountPublic;
1112 public readonly int CountNonPublic;
1113 public readonly int Length;
1114 public readonly int TotalLength;
1115 public readonly bool HasStructFields;
1117 private static Hashtable field_type_hash = new Hashtable ();
1118 private Hashtable struct_field_hash;
1119 private Hashtable field_hash;
1121 protected bool InTransit = false;
1123 // Private constructor. To save memory usage, we only need to create one instance
1124 // of this class per struct type.
1125 private StructInfo (Type type)
1129 field_type_hash.Add (type, this);
1131 if (type is TypeBuilder) {
1132 TypeContainer tc = TypeManager.LookupTypeContainer (type);
1134 ArrayList fields = null;
1138 ArrayList public_fields = new ArrayList ();
1139 ArrayList non_public_fields = new ArrayList ();
1141 if (fields != null) {
1142 foreach (FieldBase field in fields) {
1143 if ((field.ModFlags & Modifiers.STATIC) != 0)
1145 if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1146 public_fields.Add (field.FieldBuilder);
1148 non_public_fields.Add (field.FieldBuilder);
1152 CountPublic = public_fields.Count;
1153 CountNonPublic = non_public_fields.Count;
1154 Count = CountPublic + CountNonPublic;
1156 Fields = new FieldInfo [Count];
1157 public_fields.CopyTo (Fields, 0);
1158 non_public_fields.CopyTo (Fields, CountPublic);
1160 } else if (type is GenericTypeParameterBuilder) {
1161 CountPublic = CountNonPublic = Count = 0;
1163 Fields = new FieldInfo [0];
1166 FieldInfo[] public_fields = type.GetFields (
1167 BindingFlags.Instance|BindingFlags.Public);
1168 FieldInfo[] non_public_fields = type.GetFields (
1169 BindingFlags.Instance|BindingFlags.NonPublic);
1171 CountPublic = public_fields.Length;
1172 CountNonPublic = non_public_fields.Length;
1173 Count = CountPublic + CountNonPublic;
1175 Fields = new FieldInfo [Count];
1176 public_fields.CopyTo (Fields, 0);
1177 non_public_fields.CopyTo (Fields, CountPublic);
1180 struct_field_hash = new Hashtable ();
1181 field_hash = new Hashtable ();
1184 StructFields = new TypeInfo [Count];
1185 StructInfo[] sinfo = new StructInfo [Count];
1189 for (int i = 0; i < Count; i++) {
1190 FieldInfo field = (FieldInfo) Fields [i];
1192 sinfo [i] = GetStructInfo (field.FieldType);
1193 if (sinfo [i] == null)
1194 field_hash.Add (field.Name, ++Length);
1195 else if (sinfo [i].InTransit) {
1196 Report.Error (523, String.Format (
1197 "Struct member `{0}.{1}' of type `{2}' causes " +
1198 "a cycle in the structure layout",
1199 type, field.Name, sinfo [i].Type));
1207 TotalLength = Length + 1;
1208 for (int i = 0; i < Count; i++) {
1209 FieldInfo field = (FieldInfo) Fields [i];
1211 if (sinfo [i] == null)
1214 field_hash.Add (field.Name, TotalLength);
1216 HasStructFields = true;
1217 StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1218 struct_field_hash.Add (field.Name, StructFields [i]);
1219 TotalLength += sinfo [i].TotalLength;
1223 public int this [string name] {
1225 if (field_hash.Contains (name))
1226 return (int) field_hash [name];
1232 public TypeInfo GetStructField (string name)
1234 return (TypeInfo) struct_field_hash [name];
1237 public static StructInfo GetStructInfo (Type type)
1239 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1240 TypeManager.IsBuiltinType (type))
1243 StructInfo info = (StructInfo) field_type_hash [type];
1247 return new StructInfo (type);
1250 public static StructInfo GetStructInfo (TypeContainer tc)
1252 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1256 return new StructInfo (tc.TypeBuilder);
1262 // This is used by the flow analysis code to store information about a single local variable
1263 // or parameter. Depending on the variable's type, we need to allocate one or more elements
1264 // in the BitVector - if it's a fundamental or reference type, we just need to know whether
1265 // it has been assigned or not, but for structs, we need this information for each of its fields.
1267 public class VariableInfo {
1268 public readonly string Name;
1269 public readonly TypeInfo TypeInfo;
1272 // The bit offset of this variable in the flow vector.
1274 public readonly int Offset;
1277 // The number of bits this variable needs in the flow vector.
1278 // The first bit always specifies whether the variable as such has been assigned while
1279 // the remaining bits contain this information for each of a struct's fields.
1281 public readonly int Length;
1284 // If this is a parameter of local variable.
1286 public readonly bool IsParameter;
1288 public readonly LocalInfo LocalInfo;
1289 public readonly int ParameterIndex;
1291 readonly VariableInfo Parent;
1292 VariableInfo[] sub_info;
1294 protected VariableInfo (string name, Type type, int offset)
1297 this.Offset = offset;
1298 this.TypeInfo = TypeInfo.GetTypeInfo (type);
1300 Length = TypeInfo.TotalLength;
1305 protected VariableInfo (VariableInfo parent, TypeInfo type)
1307 this.Name = parent.Name;
1308 this.TypeInfo = type;
1309 this.Offset = parent.Offset + type.Offset;
1310 this.Parent = parent;
1311 this.Length = type.TotalLength;
1313 this.IsParameter = parent.IsParameter;
1314 this.LocalInfo = parent.LocalInfo;
1315 this.ParameterIndex = parent.ParameterIndex;
1320 protected void Initialize ()
1322 TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1323 if (sub_fields != null) {
1324 sub_info = new VariableInfo [sub_fields.Length];
1325 for (int i = 0; i < sub_fields.Length; i++) {
1326 if (sub_fields [i] != null)
1327 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1330 sub_info = new VariableInfo [0];
1333 public VariableInfo (LocalInfo local_info, int offset)
1334 : this (local_info.Name, local_info.VariableType, offset)
1336 this.LocalInfo = local_info;
1337 this.IsParameter = false;
1340 public VariableInfo (string name, Type type, int param_idx, int offset)
1341 : this (name, type, offset)
1343 this.ParameterIndex = param_idx;
1344 this.IsParameter = true;
1347 public bool IsAssigned (EmitContext ec)
1349 return !ec.DoFlowAnalysis ||
1350 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1351 ec.CurrentBranching.IsAssigned (this);
1354 public bool IsAssigned (EmitContext ec, Location loc)
1356 if (IsAssigned (ec))
1359 Report.Error (165, loc,
1360 "Use of unassigned local variable `" + Name + "'");
1361 ec.CurrentBranching.SetAssigned (this);
1365 public bool IsAssigned (MyBitVector vector)
1370 if (vector [Offset])
1373 for (VariableInfo parent = Parent; parent != null; parent = parent.Parent)
1374 if (vector [parent.Offset])
1377 // Return unless this is a struct.
1378 if (!TypeInfo.IsStruct)
1381 // Ok, so each field must be assigned.
1382 for (int i = 0; i < TypeInfo.Length; i++) {
1383 if (!vector [Offset + i + 1])
1387 // Ok, now check all fields which are structs.
1388 for (int i = 0; i < sub_info.Length; i++) {
1389 VariableInfo sinfo = sub_info [i];
1393 if (!sinfo.IsAssigned (vector))
1397 vector [Offset] = true;
1401 public void SetAssigned (EmitContext ec)
1403 if (ec.DoFlowAnalysis)
1404 ec.CurrentBranching.SetAssigned (this);
1407 public void SetAssigned (MyBitVector vector)
1409 vector [Offset] = true;
1412 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1414 if (!ec.DoFlowAnalysis ||
1415 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1416 ec.CurrentBranching.IsFieldAssigned (this, name))
1419 Report.Error (170, loc,
1420 "Use of possibly unassigned field `" + name + "'");
1421 ec.CurrentBranching.SetFieldAssigned (this, name);
1425 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1427 int field_idx = TypeInfo.GetFieldIndex (field_name);
1432 return vector [Offset + field_idx];
1435 public void SetFieldAssigned (EmitContext ec, string name)
1437 if (ec.DoFlowAnalysis)
1438 ec.CurrentBranching.SetFieldAssigned (this, name);
1441 public void SetFieldAssigned (MyBitVector vector, string field_name)
1443 int field_idx = TypeInfo.GetFieldIndex (field_name);
1448 vector [Offset + field_idx] = true;
1451 public VariableInfo GetSubStruct (string name)
1453 TypeInfo type = TypeInfo.GetSubStruct (name);
1458 return new VariableInfo (this, type);
1461 public override string ToString ()
1463 return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1464 Name, TypeInfo, Offset, Length, IsParameter);
1469 // This is used by the flow code to hold the `layout' of the flow vector for
1470 // all locals and all parameters (ie. we create one instance of this class for the
1471 // locals and another one for the params).
1473 public class VariableMap {
1475 // The number of variables in the map.
1477 public readonly int Count;
1480 // Total length of the flow vector for this map.
1482 public readonly int Length;
1486 public VariableMap (Parameters ip)
1488 Count = ip != null ? ip.Count : 0;
1490 // Dont bother allocating anything!
1496 for (int i = 0; i < Count; i++) {
1497 Parameter.Modifier mod = ip.ParameterModifier (i);
1499 if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
1502 // Dont allocate till we find an out var.
1504 map = new VariableInfo [Count];
1506 map [i] = new VariableInfo (ip.ParameterName (i),
1507 TypeManager.GetElementType (ip.ParameterType (i)), i, Length);
1509 Length += map [i].Length;
1513 public VariableMap (LocalInfo[] locals)
1514 : this (null, locals)
1517 public VariableMap (VariableMap parent, LocalInfo[] locals)
1519 int offset = 0, start = 0;
1520 if (parent != null && parent.map != null) {
1521 offset = parent.Length;
1522 start = parent.Count;
1525 Count = locals.Length + start;
1530 map = new VariableInfo [Count];
1533 if (parent != null && parent.map != null) {
1534 parent.map.CopyTo (map, 0);
1537 for (int i = start; i < Count; i++) {
1538 LocalInfo li = locals [i-start];
1540 if (li.VariableType == null)
1543 map [i] = li.VariableInfo = new VariableInfo (li, Length);
1544 Length += map [i].Length;
1549 // Returns the VariableInfo for variable @index or null if we don't need to
1550 // compute assignment info for this variable.
1552 public VariableInfo this [int index] {
1561 public override string ToString ()
1563 return String.Format ("VariableMap ({0}:{1})", Count, Length);
1568 // This is a special bit vector which can inherit from another bit vector doing a
1569 // copy-on-write strategy. The inherited vector may have a smaller size than the
1572 public class MyBitVector {
1573 public readonly int Count;
1574 public static readonly MyBitVector Empty = new MyBitVector ();
1576 // Invariant: vector != null => vector.Count == Count
1577 // Invariant: vector == null || shared == null
1578 // i.e., at most one of 'vector' and 'shared' can be non-null. They can both be null -- that means all-ones
1579 // The object in 'shared' cannot be modified, while 'vector' can be freely modified
1580 BitArray vector, shared;
1584 shared = new BitArray (0, false);
1587 public MyBitVector (MyBitVector InheritsFrom, int Count)
1589 if (InheritsFrom != null)
1590 shared = InheritsFrom.Shared;
1595 // Use this accessor to get a shareable copy of the underlying BitArray representation
1598 // Post-condition: vector == null
1599 if (shared == null) {
1608 // Get/set bit `index' in the bit vector.
1610 public bool this [int index] {
1613 throw new ArgumentOutOfRangeException ();
1616 return vector [index];
1619 if (index < shared.Count)
1620 return shared [index];
1625 // Only copy the vector if we're actually modifying it.
1626 if (this [index] != value) {
1628 initialize_vector ();
1629 vector [index] = value;
1635 // Performs an `or' operation on the bit vector. The `new_vector' may have a
1636 // different size than the current one.
1638 private MyBitVector Or (MyBitVector new_vector)
1640 if (Count == 0 || new_vector.Count == 0)
1643 BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1646 int n = new_vector.Count;
1648 for (int i = 0; i < n; ++i)
1656 if (Count == o.Count) {
1657 if (vector == null) {
1660 initialize_vector ();
1670 for (int i = 0; i < min; i++) {
1679 // Performs an `and' operation on the bit vector. The `new_vector' may have
1680 // a different size than the current one.
1682 private MyBitVector And (MyBitVector new_vector)
1687 BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1690 for (int i = new_vector.Count; i < Count; ++i)
1700 if (Count == o.Count) {
1701 if (vector == null) {
1702 if (shared == null) {
1703 shared = new_vector.Shared;
1706 initialize_vector ();
1716 for (int i = 0; i < min; i++) {
1721 for (int i = min; i < Count; i++)
1727 public static MyBitVector operator & (MyBitVector a, MyBitVector b)
1735 if (a.Count > b.Count)
1736 return a.Clone ().And (b);
1738 return b.Clone ().And (a);
1741 public static MyBitVector operator | (MyBitVector a, MyBitVector b)
1746 return new MyBitVector (null, b.Count);
1748 return new MyBitVector (null, a.Count);
1749 if (a.Count > b.Count)
1750 return a.Clone ().Or (b);
1752 return b.Clone ().Or (a);
1755 public MyBitVector Clone ()
1757 return Count == 0 ? Empty : new MyBitVector (this, Count);
1760 public void SetAll (bool value)
1762 // Don't clobber Empty
1765 shared = value ? null : Empty.Shared;
1769 void initialize_vector ()
1771 // Post-condition: vector != null
1772 if (shared == null) {
1773 vector = new BitArray (Count, true);
1777 vector = new BitArray (shared);
1778 if (Count != vector.Count)
1779 vector.Length = Count;
1783 StringBuilder Dump (StringBuilder sb)
1785 BitArray dump = vector == null ? shared : vector;
1787 return sb.Append ("/");
1790 for (int i = 0; i < dump.Count; i++)
1791 sb.Append (dump [i] ? "1" : "0");
1795 public override string ToString ()
1797 return Dump (new StringBuilder ("{")).Append ("}").ToString ();