2 // flowanalyis.cs: The control flow analysis code
5 // Martin Baulig (martin@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc.
12 using System.Collections;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Diagnostics;
20 // A new instance of this class is created every time a new block is resolved
21 // and if there's branching in the block's control flow.
23 public abstract class FlowBranching
26 // The type of a FlowBranching.
28 public enum BranchingType {
29 // Normal (conditional or toplevel) block.
49 // The type of one sibling of a branching.
51 public enum SiblingType {
61 // This is used in the control flow analysis code to specify whether the
62 // current code block may return to its enclosing block before reaching
65 public enum FlowReturns {
68 // It can never return.
71 // This means that the block contains a conditional return statement
75 // The code always returns, ie. there's an unconditional return / break
80 public sealed class Reachability
82 FlowReturns returns, breaks, throws, barrier, reachable;
84 public FlowReturns Returns {
85 get { return returns; }
87 public FlowReturns Breaks {
88 get { return breaks; }
90 public FlowReturns Throws {
91 get { return throws; }
93 public FlowReturns Barrier {
94 get { return barrier; }
96 public FlowReturns Reachable {
97 get { return reachable; }
100 public Reachability (FlowReturns returns, FlowReturns breaks,
101 FlowReturns throws, FlowReturns barrier)
103 this.returns = returns;
104 this.breaks = breaks;
105 this.throws = throws;
106 this.barrier = barrier;
111 public Reachability Clone ()
113 Reachability cloned = new Reachability (returns, breaks, throws, barrier);
114 cloned.reachable = reachable;
118 public static void And (ref Reachability a, Reachability b, bool do_break)
125 Report.Debug (4, "AND REACHABILITY", a, b, do_break);
128 // `break' does not "break" in a Switch or a LoopBlock
130 bool a_breaks = do_break && a.AlwaysBreaks;
131 bool b_breaks = do_break && b.AlwaysBreaks;
133 bool a_has_barrier, b_has_barrier;
136 // This is the normal case: the code following a barrier
137 // cannot be reached.
139 a_has_barrier = a.AlwaysHasBarrier;
140 b_has_barrier = b.AlwaysHasBarrier;
143 // Special case for Switch and LoopBlocks: we can reach the
144 // code after the barrier via the `break'.
146 a_has_barrier = !a.AlwaysBreaks && a.AlwaysHasBarrier;
147 b_has_barrier = !b.AlwaysBreaks && b.AlwaysHasBarrier;
150 bool a_unreachable = a_breaks || a.AlwaysThrows || a_has_barrier;
151 bool b_unreachable = b_breaks || b.AlwaysThrows || b_has_barrier;
154 // Do all code paths always return ?
156 if (a.AlwaysReturns) {
157 if (b.AlwaysReturns || b_unreachable)
158 a.returns = FlowReturns.Always;
160 a.returns = FlowReturns.Sometimes;
161 } else if (b.AlwaysReturns) {
162 if (a.AlwaysReturns || a_unreachable)
163 a.returns = FlowReturns.Always;
165 a.returns = FlowReturns.Sometimes;
166 } else if (!a.MayReturn) {
168 a.returns = FlowReturns.Sometimes;
170 a.returns = FlowReturns.Never;
171 } else if (!b.MayReturn) {
173 a.returns = FlowReturns.Sometimes;
175 a.returns = FlowReturns.Never;
178 a.breaks = AndFlowReturns (a.breaks, b.breaks);
179 a.throws = AndFlowReturns (a.throws, b.throws);
180 a.barrier = AndFlowReturns (a.barrier, b.barrier);
182 a.reachable = AndFlowReturns (a.reachable, b.reachable);
185 public static Reachability Never ()
187 return new Reachability (
188 FlowReturns.Never, FlowReturns.Never,
189 FlowReturns.Never, FlowReturns.Never);
194 if ((returns == FlowReturns.Always) || (breaks == FlowReturns.Always) ||
195 (throws == FlowReturns.Always) || (barrier == FlowReturns.Always))
196 reachable = FlowReturns.Never;
197 else if ((returns == FlowReturns.Never) && (breaks == FlowReturns.Never) &&
198 (throws == FlowReturns.Never) && (barrier == FlowReturns.Never))
199 reachable = FlowReturns.Always;
201 reachable = FlowReturns.Sometimes;
204 public bool AlwaysBreaks {
205 get { return breaks == FlowReturns.Always; }
208 public bool MayBreak {
209 get { return breaks != FlowReturns.Never; }
212 public bool AlwaysReturns {
213 get { return returns == FlowReturns.Always; }
216 public bool MayReturn {
217 get { return returns != FlowReturns.Never; }
220 public bool AlwaysThrows {
221 get { return throws == FlowReturns.Always; }
224 public bool MayThrow {
225 get { return throws != FlowReturns.Never; }
228 public bool AlwaysHasBarrier {
229 get { return barrier == FlowReturns.Always; }
232 public bool MayHaveBarrier {
233 get { return barrier != FlowReturns.Never; }
236 public bool IsUnreachable {
237 get { return reachable == FlowReturns.Never; }
240 public void SetReturns ()
242 returns = FlowReturns.Always;
246 public void SetReturnsSometimes ()
248 returns = FlowReturns.Sometimes;
252 public void SetBreaks ()
254 breaks = FlowReturns.Always;
258 public void ResetBreaks ()
260 breaks = FlowReturns.Never;
264 public void SetThrows ()
266 throws = FlowReturns.Always;
270 public void SetBarrier ()
272 barrier = FlowReturns.Always;
276 static string ShortName (FlowReturns returns)
279 case FlowReturns.Never:
281 case FlowReturns.Sometimes:
288 public override string ToString ()
290 return String.Format ("[{0}:{1}:{2}:{3}:{4}]",
291 ShortName (returns), ShortName (breaks),
292 ShortName (throws), ShortName (barrier),
293 ShortName (reachable));
297 public static FlowBranching CreateBranching (FlowBranching parent, BranchingType type, Block block, Location loc)
300 case BranchingType.Exception:
301 return new FlowBranchingException (parent, type, block, loc);
303 case BranchingType.Switch:
304 return new FlowBranchingBlock (parent, type, SiblingType.SwitchSection, block, loc);
306 case BranchingType.SwitchSection:
307 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
309 case BranchingType.Block:
310 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
313 return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc);
318 // The type of this flow branching.
320 public readonly BranchingType Type;
323 // The block this branching is contained in. This may be null if it's not
324 // a top-level block and it doesn't declare any local variables.
326 public readonly Block Block;
329 // The parent of this branching or null if this is the top-block.
331 public readonly FlowBranching Parent;
334 // Start-Location of this flow branching.
336 public readonly Location Location;
339 // If this is an infinite loop.
341 public bool Infinite;
346 VariableMap param_map, local_map;
348 static int next_id = 0;
352 // Performs an `And' operation on the FlowReturns status
353 // (for instance, a block only returns Always if all its siblings
356 public static FlowReturns AndFlowReturns (FlowReturns a, FlowReturns b)
358 if (a == FlowReturns.Undefined)
362 case FlowReturns.Never:
363 if (b == FlowReturns.Never)
364 return FlowReturns.Never;
366 return FlowReturns.Sometimes;
368 case FlowReturns.Sometimes:
369 return FlowReturns.Sometimes;
371 case FlowReturns.Always:
372 if (b == FlowReturns.Always)
373 return FlowReturns.Always;
375 return FlowReturns.Sometimes;
378 throw new ArgumentException ();
385 // The vector contains a BitArray with information about which local variables
386 // and parameters are already initialized at the current code position.
388 public class UsageVector {
390 // The type of this branching.
392 public readonly SiblingType Type;
395 // Start location of this branching.
397 public readonly Location Location;
400 // If this is true, then the usage vector has been modified and must be
401 // merged when we're done with this branching.
406 // The number of parameters in this block.
408 public readonly int CountParameters;
411 // The number of locals in this block.
413 public readonly int CountLocals;
416 // If not null, then we inherit our state from this vector and do a
417 // copy-on-write. If null, then we're the first sibling in a top-level
418 // block and inherit from the empty vector.
420 public readonly UsageVector InheritsFrom;
423 // This is used to construct a list of UsageVector's.
425 public UsageVector Next;
430 MyBitVector locals, parameters;
431 Reachability reachability;
434 static int next_id = 0;
438 // Normally, you should not use any of these constructors.
440 public UsageVector (SiblingType type, UsageVector parent, Location loc, int num_params, int num_locals)
444 this.InheritsFrom = parent;
445 this.CountParameters = num_params;
446 this.CountLocals = num_locals;
448 if (parent != null) {
449 locals = new MyBitVector (parent.locals, CountLocals);
451 parameters = new MyBitVector (parent.parameters, num_params);
453 reachability = parent.Reachability.Clone ();
455 locals = new MyBitVector (null, CountLocals);
457 parameters = new MyBitVector (null, num_params);
459 reachability = Reachability.Never ();
465 public UsageVector (SiblingType type, UsageVector parent, Location loc)
466 : this (type, parent, loc, parent.CountParameters, parent.CountLocals)
469 public UsageVector (MyBitVector parameters, MyBitVector locals,
470 Reachability reachability, Location loc)
472 this.Type = SiblingType.Block;
475 this.reachability = reachability;
476 this.parameters = parameters;
477 this.locals = locals;
483 // This does a deep copy of the usage vector.
485 public UsageVector Clone ()
487 UsageVector retval = new UsageVector (Type, null, Location, CountParameters, CountLocals);
489 retval.locals = locals.Clone ();
490 if (parameters != null)
491 retval.parameters = parameters.Clone ();
492 retval.reachability = reachability.Clone ();
497 public bool IsAssigned (VariableInfo var)
499 if (!var.IsParameter && Reachability.AlwaysBreaks)
502 return var.IsAssigned (var.IsParameter ? parameters : locals);
505 public void SetAssigned (VariableInfo var)
507 if (!var.IsParameter && Reachability.AlwaysBreaks)
511 var.SetAssigned (var.IsParameter ? parameters : locals);
514 public bool IsFieldAssigned (VariableInfo var, string name)
516 if (!var.IsParameter && Reachability.AlwaysBreaks)
519 return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name);
522 public void SetFieldAssigned (VariableInfo var, string name)
524 if (!var.IsParameter && Reachability.AlwaysBreaks)
528 var.SetFieldAssigned (var.IsParameter ? parameters : locals, name);
531 public Reachability Reachability {
537 public void Return ()
539 if (!reachability.IsUnreachable) {
541 reachability.SetReturns ();
547 if (!reachability.IsUnreachable) {
549 reachability.SetBreaks ();
555 if (!reachability.IsUnreachable) {
557 reachability.SetThrows ();
563 if (!reachability.IsUnreachable) {
565 reachability.SetBarrier ();
570 // Merges a child branching.
572 public void MergeResult (MyBitVector new_params, MyBitVector new_locals,
573 Reachability new_reachability)
575 Report.Debug (2, " MERGING RESULT", this, IsDirty,
576 new_params, new_locals, new_reachability, Type);
578 reachability = new_reachability;
581 // We've now either reached the point after the branching or we will
582 // never get there since we always return or always throw an exception.
584 // If we can reach the point after the branching, mark all locals and
585 // parameters as initialized which have been initialized in all branches
586 // we need to look at (see above).
589 if ((Type == SiblingType.SwitchSection) && !reachability.IsUnreachable) {
590 Report.Error (163, Location,
591 "Control cannot fall through from one " +
592 "case label to another");
596 if (new_locals != null)
597 locals.Or (new_locals);
599 if (new_params != null)
600 parameters.Or (new_params);
602 Report.Debug (2, " MERGING RESULT DONE", this);
607 protected void MergeFinally (FlowBranching branching, UsageVector f_origins,
608 MyBitVector f_params)
610 for (UsageVector vector = f_origins; vector != null; vector = vector.Next) {
611 MyBitVector temp_params = f_params.Clone ();
612 temp_params.Or (vector.Parameters);
614 branching.CheckOutParameters (temp_params, branching.Location);
618 public void MergeFinally (FlowBranching branching, UsageVector f_vector,
619 UsageVector f_origins)
621 if (parameters != null) {
622 if (f_vector != null) {
623 MergeFinally (branching, f_origins, f_vector.Parameters);
624 MyBitVector.Or (ref parameters, f_vector.ParameterVector);
626 MergeFinally (branching, f_origins, parameters);
629 if (f_vector != null)
630 MyBitVector.Or (ref locals, f_vector.LocalVector);
634 // Tells control flow analysis that the current code position may be reached with
635 // a forward jump from any of the origins listed in `origin_vectors' which is a
636 // list of UsageVectors.
638 // This is used when resolving forward gotos - in the following example, the
639 // variable `a' is uninitialized in line 8 becase this line may be reached via
640 // the goto in line 4:
650 // 8 Console.WriteLine (a);
653 public void MergeJumpOrigins (ICollection origin_vectors)
655 Report.Debug (1, " MERGING JUMP ORIGIN", this);
657 reachability = Reachability.Never ();
659 if (origin_vectors == null)
662 foreach (UsageVector vector in origin_vectors) {
663 Report.Debug (1, " MERGING JUMP ORIGIN", vector);
665 locals.And (vector.locals);
666 if (parameters != null)
667 parameters.And (vector.parameters);
669 Reachability.And (ref reachability, vector.Reachability, true);
672 Report.Debug (1, " MERGING JUMP ORIGIN DONE", this);
676 // This is used at the beginning of a finally block if there were
677 // any return statements in the try block or one of the catch blocks.
679 public void MergeFinallyOrigins (ICollection finally_vectors)
681 Report.Debug (1, " MERGING FINALLY ORIGIN", this);
684 RealBreaks = FlowReturns.Never;
687 foreach (UsageVector vector in finally_vectors) {
688 Report.Debug (1, " MERGING FINALLY ORIGIN", vector);
690 if (parameters != null)
691 parameters.And (vector.parameters);
694 RealBreaks = AndFlowReturns (Breaks, vector.Breaks);
700 Report.Debug (1, " MERGING FINALLY ORIGIN DONE", this);
703 public void CheckOutParameters (FlowBranching branching)
705 if (parameters != null)
706 branching.CheckOutParameters (parameters, branching.Location);
710 // Performs an `or' operation on the locals and the parameters.
712 public void Or (UsageVector new_vector)
715 locals.Or (new_vector.locals);
716 if (parameters != null)
717 parameters.Or (new_vector.parameters);
721 // Performs an `and' operation on the locals.
723 public void AndLocals (UsageVector new_vector)
726 locals.And (new_vector.locals);
729 public bool HasParameters {
731 return parameters != null;
735 public bool HasLocals {
737 return locals != null;
742 // Returns a deep copy of the parameters.
744 public MyBitVector Parameters {
746 if (parameters != null)
747 return parameters.Clone ();
754 // Returns a deep copy of the locals.
756 public MyBitVector Locals {
758 return locals.Clone ();
762 public MyBitVector ParameterVector {
768 public MyBitVector LocalVector {
778 public override string ToString ()
780 StringBuilder sb = new StringBuilder ();
782 sb.Append ("Vector (");
787 sb.Append (reachability);
788 if (parameters != null) {
790 sb.Append (parameters);
796 return sb.ToString ();
801 // Creates a new flow branching which is contained in `parent'.
802 // You should only pass non-null for the `block' argument if this block
803 // introduces any new variables - in this case, we need to create a new
804 // usage vector with a different size than our parent's one.
806 protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
807 Block block, Location loc)
817 param_map = Block.ParameterMap;
818 local_map = Block.LocalMap;
820 UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
821 vector = new UsageVector (stype, parent_vector, loc, param_map.Length, local_map.Length);
823 param_map = Parent.param_map;
824 local_map = Parent.local_map;
825 vector = new UsageVector (stype, Parent.CurrentUsageVector, loc);
831 public abstract UsageVector CurrentUsageVector {
836 // Creates a sibling of the current usage vector.
838 public virtual void CreateSibling (SiblingType type)
840 AddSibling (new UsageVector (type, Parent.CurrentUsageVector, Location));
842 Report.Debug (1, " CREATED SIBLING", CurrentUsageVector);
845 protected abstract void AddSibling (UsageVector uv);
847 public abstract void Label (ArrayList origin_vectors);
850 // Check whether all `out' parameters have been assigned.
852 public void CheckOutParameters (MyBitVector parameters, Location loc)
854 for (int i = 0; i < param_map.Count; i++) {
855 VariableInfo var = param_map [i];
860 if (var.IsAssigned (parameters))
863 Report.Error (177, loc, "The out parameter `" +
864 param_map.VariableNames [i] + "' must be " +
865 "assigned before control leave the current method.");
869 protected UsageVector Merge (UsageVector sibling_list)
871 MyBitVector locals = null;
872 MyBitVector parameters = null;
874 Reachability reachability = null;
876 Report.Debug (2, " MERGING CHILDREN", Name);
878 for (UsageVector child = sibling_list; child != null; child = child.Next) {
879 bool do_break = (Type != BranchingType.Switch) &&
880 (Type != BranchingType.LoopBlock);
882 Report.Debug (2, " MERGING CHILD ", child,
883 child.Locals, child.Parameters,
884 reachability, child.Reachability, do_break);
886 Reachability.And (ref reachability, child.Reachability, do_break);
888 // A local variable is initialized after a flow branching if it
889 // has been initialized in all its branches which do neither
890 // always return or always throw an exception.
892 // If a branch may return, but does not always return, then we
893 // can treat it like a never-returning branch here: control will
894 // only reach the code position after the branching if we did not
897 // It's important to distinguish between always and sometimes
898 // returning branches here:
901 // 2 if (something) {
905 // 6 Console.WriteLine (a);
907 // The if block in lines 3-4 always returns, so we must not look
908 // at the initialization of `a' in line 4 - thus it'll still be
909 // uninitialized in line 6.
911 // On the other hand, the following is allowed:
918 // 6 Console.WriteLine (a);
920 // Here, `a' is initialized in line 3 and we must not look at
921 // line 5 since it always returns.
923 bool do_break_2 = (child.Type != SiblingType.Block) &&
924 (child.Type != SiblingType.SwitchSection);
925 bool unreachable = (do_break_2 && child.Reachability.AlwaysBreaks) ||
926 child.Reachability.AlwaysThrows ||
927 child.Reachability.AlwaysReturns ||
928 child.Reachability.AlwaysHasBarrier;
930 Report.Debug (2, " MERGING CHILD #1", reachability,
931 Type, child.Type, child.Reachability.IsUnreachable,
932 do_break_2, unreachable);
935 MyBitVector.And (ref locals, child.LocalVector);
937 // An `out' parameter must be assigned in all branches which do
938 // not always throw an exception.
939 if ((child.Type != SiblingType.Catch) &&
940 (child.ParameterVector != null) && !child.Reachability.AlwaysThrows)
941 MyBitVector.And (ref parameters, child.ParameterVector);
944 if (reachability == null)
945 reachability = Reachability.Never ();
947 Report.Debug (2, " MERGING CHILDREN #1 ", Type, reachability,
948 Infinite, reachability.MayBreak);
950 if (Type == BranchingType.LoopBlock) {
951 bool may_leave_loop = reachability.MayBreak;
952 reachability.ResetBreaks ();
954 if (Infinite && !may_leave_loop) {
955 if (reachability.Returns == FlowReturns.Sometimes) {
956 // If we're an infinite loop and do not break, the code
957 // after the loop can never be reached. However, if we
958 // may return from the loop, then we do always return
959 // (or stay in the loop forever).
960 reachability.SetReturns ();
963 reachability.SetBarrier ();
965 if (reachability.Returns == FlowReturns.Always) {
966 // We're either finite or we may leave the loop.
967 reachability.SetReturnsSometimes ();
970 } else if (Type == BranchingType.Switch)
971 reachability.ResetBreaks ();
973 Report.Debug (2, " MERGING CHILDREN DONE", parameters, locals,
974 reachability, Infinite);
976 return new UsageVector (parameters, locals, reachability, Location);
979 protected abstract UsageVector Merge ();
982 // Merge a child branching.
984 public Reachability MergeChild (FlowBranching child)
986 UsageVector result = child.Merge ();
988 CurrentUsageVector.MergeResult (
989 result.ParameterVector, result.LocalVector, result.Reachability);
991 Report.Debug (4, " MERGE CHILD", Location, child, CurrentUsageVector,
992 result.Reachability);
994 return result.Reachability;
998 // Does the toplevel merging.
1000 public Reachability MergeTopBlock ()
1002 if ((Type != BranchingType.Block) || (Block == null))
1003 throw new NotSupportedException ();
1005 UsageVector vector = new UsageVector (
1006 SiblingType.Conditional, null, Location, param_map.Length, local_map.Length);
1008 UsageVector result = Merge ();
1009 vector.MergeResult (result.ParameterVector, result.LocalVector,
1010 result.Reachability);
1012 Report.Debug (4, "MERGE TOP BLOCK", Location, vector, result.Reachability);
1014 if (vector.Reachability.Throws != FlowReturns.Always)
1015 CheckOutParameters (vector.Parameters, Location);
1017 return result.Reachability;
1020 public virtual bool InTryBlock ()
1023 return Parent.InTryBlock ();
1028 public virtual void AddFinallyVector (UsageVector vector)
1031 Parent.AddFinallyVector (vector);
1033 throw new NotSupportedException ();
1036 public bool IsAssigned (VariableInfo vi)
1038 return CurrentUsageVector.IsAssigned (vi);
1041 public bool IsFieldAssigned (VariableInfo vi, string field_name)
1043 if (CurrentUsageVector.IsAssigned (vi))
1046 return CurrentUsageVector.IsFieldAssigned (vi, field_name);
1049 public void SetAssigned (VariableInfo vi)
1051 CurrentUsageVector.SetAssigned (vi);
1054 public void SetFieldAssigned (VariableInfo vi, string name)
1056 CurrentUsageVector.SetFieldAssigned (vi, name);
1059 public override string ToString ()
1061 StringBuilder sb = new StringBuilder ();
1062 sb.Append (GetType ());
1068 if (Block != null) {
1070 sb.Append (Block.ID);
1072 sb.Append (Block.StartLocation);
1075 // sb.Append (Siblings.Length);
1076 // sb.Append (" - ");
1077 sb.Append (CurrentUsageVector);
1079 return sb.ToString ();
1082 public string Name {
1084 return String.Format ("{0} ({1}:{2}:{3})",
1085 GetType (), id, Type, Location);
1090 public class FlowBranchingBlock : FlowBranching
1092 UsageVector sibling_list = null;
1094 public FlowBranchingBlock (FlowBranching parent, BranchingType type, SiblingType stype,
1095 Block block, Location loc)
1096 : base (parent, type, stype, block, loc)
1099 public override UsageVector CurrentUsageVector {
1100 get { return sibling_list; }
1103 protected override void AddSibling (UsageVector sibling)
1105 sibling.Next = sibling_list;
1106 sibling_list = sibling;
1109 public override void Label (ArrayList origin_vectors)
1111 CurrentUsageVector.MergeJumpOrigins (origin_vectors);
1114 protected override UsageVector Merge ()
1116 return Merge (sibling_list);
1120 public class FlowBranchingException : FlowBranching
1122 UsageVector current_vector;
1123 UsageVector try_vector;
1124 UsageVector catch_vectors;
1125 UsageVector finally_vector;
1126 UsageVector finally_origins;
1128 public FlowBranchingException (FlowBranching parent, BranchingType type, Block block, Location loc)
1129 : base (parent, type, SiblingType.Try, block, loc)
1132 protected override void AddSibling (UsageVector sibling)
1134 if (sibling.Type == SiblingType.Try) {
1135 try_vector = sibling;
1136 sibling.Next = catch_vectors;
1137 catch_vectors = sibling;
1138 } else if (sibling.Type == SiblingType.Catch) {
1139 sibling.Next = catch_vectors;
1140 catch_vectors = sibling;
1141 } else if (sibling.Type == SiblingType.Finally) {
1142 // sibling.MergeFinallyOrigins (finally_vectors);
1143 finally_vector = sibling;
1145 throw new InvalidOperationException ();
1147 current_vector = sibling;
1150 public override UsageVector CurrentUsageVector {
1151 get { return current_vector; }
1154 public override bool InTryBlock ()
1159 public override void AddFinallyVector (UsageVector vector)
1161 vector = vector.Clone ();
1162 vector.Next = finally_origins;
1163 finally_origins = vector;
1166 public override void Label (ArrayList origin_vectors)
1168 CurrentUsageVector.MergeJumpOrigins (origin_vectors);
1171 protected override UsageVector Merge ()
1173 UsageVector vector = Merge (catch_vectors);
1175 vector.MergeFinally (this, finally_vector, finally_origins);
1182 // This is used by the flow analysis code to keep track of the type of local variables
1185 // The flow code uses a BitVector to keep track of whether a variable has been assigned
1186 // or not. This is easy for fundamental types (int, char etc.) or reference types since
1187 // you can only assign the whole variable as such.
1189 // For structs, we also need to keep track of all its fields. To do this, we allocate one
1190 // bit for the struct itself (it's used if you assign/access the whole struct) followed by
1191 // one bit for each of its fields.
1193 // This class computes this `layout' for each type.
1195 public class TypeInfo
1197 public readonly Type Type;
1200 // Total number of bits a variable of this type consumes in the flow vector.
1202 public readonly int TotalLength;
1205 // Number of bits the simple fields of a variable of this type consume
1206 // in the flow vector.
1208 public readonly int Length;
1211 // This is only used by sub-structs.
1213 public readonly int Offset;
1216 // If this is a struct.
1218 public readonly bool IsStruct;
1221 // If this is a struct, all fields which are structs theirselves.
1223 public TypeInfo[] SubStructInfo;
1225 protected readonly StructInfo struct_info;
1226 private static Hashtable type_hash = new Hashtable ();
1228 public static TypeInfo GetTypeInfo (Type type)
1230 TypeInfo info = (TypeInfo) type_hash [type];
1234 info = new TypeInfo (type);
1235 type_hash.Add (type, info);
1239 public static TypeInfo GetTypeInfo (TypeContainer tc)
1241 TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
1245 info = new TypeInfo (tc);
1246 type_hash.Add (tc.TypeBuilder, info);
1250 private TypeInfo (Type type)
1254 struct_info = StructInfo.GetStructInfo (type);
1255 if (struct_info != null) {
1256 Length = struct_info.Length;
1257 TotalLength = struct_info.TotalLength;
1258 SubStructInfo = struct_info.StructFields;
1267 private TypeInfo (TypeContainer tc)
1269 this.Type = tc.TypeBuilder;
1271 struct_info = StructInfo.GetStructInfo (tc);
1272 if (struct_info != null) {
1273 Length = struct_info.Length;
1274 TotalLength = struct_info.TotalLength;
1275 SubStructInfo = struct_info.StructFields;
1284 protected TypeInfo (StructInfo struct_info, int offset)
1286 this.struct_info = struct_info;
1287 this.Offset = offset;
1288 this.Length = struct_info.Length;
1289 this.TotalLength = struct_info.TotalLength;
1290 this.SubStructInfo = struct_info.StructFields;
1291 this.Type = struct_info.Type;
1292 this.IsStruct = true;
1295 public int GetFieldIndex (string name)
1297 if (struct_info == null)
1300 return struct_info [name];
1303 public TypeInfo GetSubStruct (string name)
1305 if (struct_info == null)
1308 return struct_info.GetStructField (name);
1312 // A struct's constructor must always assign all fields.
1313 // This method checks whether it actually does so.
1315 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1317 if (struct_info == null)
1321 for (int i = 0; i < struct_info.Count; i++) {
1322 FieldInfo field = struct_info.Fields [i];
1324 if (!branching.IsFieldAssigned (vi, field.Name)) {
1325 Report.Error (171, loc,
1326 "Field `" + TypeManager.CSharpName (Type) +
1327 "." + field.Name + "' must be fully initialized " +
1328 "before control leaves the constructor");
1336 public override string ToString ()
1338 return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1339 Type, Offset, Length, TotalLength);
1342 protected class StructInfo {
1343 public readonly Type Type;
1344 public readonly FieldInfo[] Fields;
1345 public readonly TypeInfo[] StructFields;
1346 public readonly int Count;
1347 public readonly int CountPublic;
1348 public readonly int CountNonPublic;
1349 public readonly int Length;
1350 public readonly int TotalLength;
1351 public readonly bool HasStructFields;
1353 private static Hashtable field_type_hash = new Hashtable ();
1354 private Hashtable struct_field_hash;
1355 private Hashtable field_hash;
1357 protected bool InTransit = false;
1359 // Private constructor. To save memory usage, we only need to create one instance
1360 // of this class per struct type.
1361 private StructInfo (Type type)
1365 field_type_hash.Add (type, this);
1367 if (type is TypeBuilder) {
1368 TypeContainer tc = TypeManager.LookupTypeContainer (type);
1370 ArrayList fields = tc.Fields;
1372 ArrayList public_fields = new ArrayList ();
1373 ArrayList non_public_fields = new ArrayList ();
1375 if (fields != null) {
1376 foreach (Field field in fields) {
1377 if ((field.ModFlags & Modifiers.STATIC) != 0)
1379 if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1380 public_fields.Add (field.FieldBuilder);
1382 non_public_fields.Add (field.FieldBuilder);
1386 CountPublic = public_fields.Count;
1387 CountNonPublic = non_public_fields.Count;
1388 Count = CountPublic + CountNonPublic;
1390 Fields = new FieldInfo [Count];
1391 public_fields.CopyTo (Fields, 0);
1392 non_public_fields.CopyTo (Fields, CountPublic);
1394 FieldInfo[] public_fields = type.GetFields (
1395 BindingFlags.Instance|BindingFlags.Public);
1396 FieldInfo[] non_public_fields = type.GetFields (
1397 BindingFlags.Instance|BindingFlags.NonPublic);
1399 CountPublic = public_fields.Length;
1400 CountNonPublic = non_public_fields.Length;
1401 Count = CountPublic + CountNonPublic;
1403 Fields = new FieldInfo [Count];
1404 public_fields.CopyTo (Fields, 0);
1405 non_public_fields.CopyTo (Fields, CountPublic);
1408 struct_field_hash = new Hashtable ();
1409 field_hash = new Hashtable ();
1412 StructFields = new TypeInfo [Count];
1413 StructInfo[] sinfo = new StructInfo [Count];
1417 for (int i = 0; i < Count; i++) {
1418 FieldInfo field = (FieldInfo) Fields [i];
1420 sinfo [i] = GetStructInfo (field.FieldType);
1421 if (sinfo [i] == null)
1422 field_hash.Add (field.Name, ++Length);
1423 else if (sinfo [i].InTransit) {
1424 Report.Error (523, String.Format (
1425 "Struct member '{0}.{1}' of type '{2}' causes " +
1426 "a cycle in the structure layout",
1427 type, field.Name, sinfo [i].Type));
1435 TotalLength = Length + 1;
1436 for (int i = 0; i < Count; i++) {
1437 FieldInfo field = (FieldInfo) Fields [i];
1439 if (sinfo [i] == null)
1442 field_hash.Add (field.Name, TotalLength);
1444 HasStructFields = true;
1445 StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1446 struct_field_hash.Add (field.Name, StructFields [i]);
1447 TotalLength += sinfo [i].TotalLength;
1451 public int this [string name] {
1453 if (field_hash.Contains (name))
1454 return (int) field_hash [name];
1460 public TypeInfo GetStructField (string name)
1462 return (TypeInfo) struct_field_hash [name];
1465 public static StructInfo GetStructInfo (Type type)
1467 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1468 TypeManager.IsBuiltinType (type))
1471 StructInfo info = (StructInfo) field_type_hash [type];
1475 return new StructInfo (type);
1478 public static StructInfo GetStructInfo (TypeContainer tc)
1480 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1484 return new StructInfo (tc.TypeBuilder);
1490 // This is used by the flow analysis code to store information about a single local variable
1491 // or parameter. Depending on the variable's type, we need to allocate one or more elements
1492 // in the BitVector - if it's a fundamental or reference type, we just need to know whether
1493 // it has been assigned or not, but for structs, we need this information for each of its fields.
1495 public class VariableInfo {
1496 public readonly string Name;
1497 public readonly TypeInfo TypeInfo;
1500 // The bit offset of this variable in the flow vector.
1502 public readonly int Offset;
1505 // The number of bits this variable needs in the flow vector.
1506 // The first bit always specifies whether the variable as such has been assigned while
1507 // the remaining bits contain this information for each of a struct's fields.
1509 public readonly int Length;
1512 // If this is a parameter of local variable.
1514 public readonly bool IsParameter;
1516 public readonly LocalInfo LocalInfo;
1517 public readonly int ParameterIndex;
1519 readonly VariableInfo Parent;
1520 VariableInfo[] sub_info;
1522 protected VariableInfo (string name, Type type, int offset)
1525 this.Offset = offset;
1526 this.TypeInfo = TypeInfo.GetTypeInfo (type);
1528 Length = TypeInfo.TotalLength;
1533 protected VariableInfo (VariableInfo parent, TypeInfo type)
1535 this.Name = parent.Name;
1536 this.TypeInfo = type;
1537 this.Offset = parent.Offset + type.Offset;
1538 this.Parent = parent;
1539 this.Length = type.TotalLength;
1541 this.IsParameter = parent.IsParameter;
1542 this.LocalInfo = parent.LocalInfo;
1543 this.ParameterIndex = parent.ParameterIndex;
1548 protected void Initialize ()
1550 TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1551 if (sub_fields != null) {
1552 sub_info = new VariableInfo [sub_fields.Length];
1553 for (int i = 0; i < sub_fields.Length; i++) {
1554 if (sub_fields [i] != null)
1555 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1558 sub_info = new VariableInfo [0];
1561 public VariableInfo (LocalInfo local_info, int offset)
1562 : this (local_info.Name, local_info.VariableType, offset)
1564 this.LocalInfo = local_info;
1565 this.IsParameter = false;
1568 public VariableInfo (string name, Type type, int param_idx, int offset)
1569 : this (name, type, offset)
1571 this.ParameterIndex = param_idx;
1572 this.IsParameter = true;
1575 public bool IsAssigned (EmitContext ec)
1577 return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this);
1580 public bool IsAssigned (EmitContext ec, Location loc)
1582 if (IsAssigned (ec))
1585 Report.Error (165, loc,
1586 "Use of unassigned local variable `" + Name + "'");
1587 ec.CurrentBranching.SetAssigned (this);
1591 public bool IsAssigned (MyBitVector vector)
1593 if (vector [Offset])
1596 for (VariableInfo parent = Parent; parent != null; parent = parent.Parent)
1597 if (vector [parent.Offset])
1600 // Return unless this is a struct.
1601 if (!TypeInfo.IsStruct)
1604 // Ok, so each field must be assigned.
1605 for (int i = 0; i < TypeInfo.Length; i++) {
1606 if (!vector [Offset + i + 1])
1610 // Ok, now check all fields which are structs.
1611 for (int i = 0; i < sub_info.Length; i++) {
1612 VariableInfo sinfo = sub_info [i];
1616 if (!sinfo.IsAssigned (vector))
1620 vector [Offset] = true;
1624 public void SetAssigned (EmitContext ec)
1626 if (ec.DoFlowAnalysis)
1627 ec.CurrentBranching.SetAssigned (this);
1630 public void SetAssigned (MyBitVector vector)
1632 vector [Offset] = true;
1635 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1637 if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsFieldAssigned (this, name))
1640 Report.Error (170, loc,
1641 "Use of possibly unassigned field `" + name + "'");
1642 ec.CurrentBranching.SetFieldAssigned (this, name);
1646 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1648 int field_idx = TypeInfo.GetFieldIndex (field_name);
1653 return vector [Offset + field_idx];
1656 public void SetFieldAssigned (EmitContext ec, string name)
1658 if (ec.DoFlowAnalysis)
1659 ec.CurrentBranching.SetFieldAssigned (this, name);
1662 public void SetFieldAssigned (MyBitVector vector, string field_name)
1664 int field_idx = TypeInfo.GetFieldIndex (field_name);
1669 vector [Offset + field_idx] = true;
1672 public VariableInfo GetSubStruct (string name)
1674 TypeInfo type = TypeInfo.GetSubStruct (name);
1679 return new VariableInfo (this, type);
1682 public override string ToString ()
1684 return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1685 Name, TypeInfo, Offset, Length, IsParameter);
1690 // This is used by the flow code to hold the `layout' of the flow vector for
1691 // all locals and all parameters (ie. we create one instance of this class for the
1692 // locals and another one for the params).
1694 public class VariableMap {
1696 // The number of variables in the map.
1698 public readonly int Count;
1701 // Total length of the flow vector for this map.
1703 public readonly int Length;
1706 // Type and name of all the variables.
1707 // Note that this is null for variables for which we do not need to compute
1710 public readonly Type[] VariableTypes;
1711 public readonly string[] VariableNames;
1715 public VariableMap (InternalParameters ip)
1717 Count = ip != null ? ip.Count : 0;
1718 map = new VariableInfo [Count];
1719 VariableNames = new string [Count];
1720 VariableTypes = new Type [Count];
1723 for (int i = 0; i < Count; i++) {
1724 Parameter.Modifier mod = ip.ParameterModifier (i);
1726 if ((mod & Parameter.Modifier.OUT) == 0)
1729 VariableNames [i] = ip.ParameterName (i);
1730 VariableTypes [i] = TypeManager.GetElementType (ip.ParameterType (i));
1732 map [i] = new VariableInfo (VariableNames [i], VariableTypes [i], i, Length);
1733 Length += map [i].Length;
1737 public VariableMap (LocalInfo[] locals)
1738 : this (null, locals)
1741 public VariableMap (VariableMap parent, LocalInfo[] locals)
1743 int offset = 0, start = 0;
1744 if (parent != null) {
1745 offset = parent.Length;
1746 start = parent.Count;
1749 Count = locals.Length + start;
1750 map = new VariableInfo [Count];
1751 VariableNames = new string [Count];
1752 VariableTypes = new Type [Count];
1755 if (parent != null) {
1756 parent.map.CopyTo (map, 0);
1757 parent.VariableNames.CopyTo (VariableNames, 0);
1758 parent.VariableTypes.CopyTo (VariableTypes, 0);
1761 for (int i = start; i < Count; i++) {
1762 LocalInfo li = locals [i-start];
1764 if (li.VariableType == null)
1767 VariableNames [i] = li.Name;
1768 VariableTypes [i] = li.VariableType;
1770 map [i] = li.VariableInfo = new VariableInfo (li, Length);
1771 Length += map [i].Length;
1776 // Returns the VariableInfo for variable @index or null if we don't need to
1777 // compute assignment info for this variable.
1779 public VariableInfo this [int index] {
1785 public override string ToString ()
1787 return String.Format ("VariableMap ({0}:{1})", Count, Length);
1792 // This is a special bit vector which can inherit from another bit vector doing a
1793 // copy-on-write strategy. The inherited vector may have a smaller size than the
1796 public class MyBitVector {
1797 public readonly int Count;
1798 public readonly MyBitVector InheritsFrom;
1803 public MyBitVector (int Count)
1804 : this (null, Count)
1807 public MyBitVector (MyBitVector InheritsFrom, int Count)
1809 this.InheritsFrom = InheritsFrom;
1814 // Checks whether this bit vector has been modified. After setting this to true,
1815 // we won't use the inherited vector anymore, but our own copy of it.
1817 public bool IsDirty {
1824 initialize_vector ();
1829 // Get/set bit `index' in the bit vector.
1831 public bool this [int index]
1835 throw new ArgumentOutOfRangeException ();
1837 // We're doing a "copy-on-write" strategy here; as long
1838 // as nobody writes to the array, we can use our parent's
1839 // copy instead of duplicating the vector.
1842 return vector [index];
1843 else if (InheritsFrom != null) {
1844 BitArray inherited = InheritsFrom.Vector;
1846 if (index < inherited.Count)
1847 return inherited [index];
1856 throw new ArgumentOutOfRangeException ();
1858 // Only copy the vector if we're actually modifying it.
1860 if (this [index] != value) {
1861 initialize_vector ();
1863 vector [index] = value;
1869 // If you explicitly convert the MyBitVector to a BitArray, you will get a deep
1870 // copy of the bit vector.
1872 public static explicit operator BitArray (MyBitVector vector)
1874 vector.initialize_vector ();
1875 return vector.Vector;
1879 // Performs an `or' operation on the bit vector. The `new_vector' may have a
1880 // different size than the current one.
1882 public void Or (MyBitVector new_vector)
1884 BitArray new_array = new_vector.Vector;
1886 initialize_vector ();
1889 if (vector.Count < new_array.Count)
1890 upper = vector.Count;
1892 upper = new_array.Count;
1894 for (int i = 0; i < upper; i++)
1895 vector [i] = vector [i] | new_array [i];
1899 // Perfonrms an `and' operation on the bit vector. The `new_vector' may have
1900 // a different size than the current one.
1902 public void And (MyBitVector new_vector)
1904 BitArray new_array = new_vector.Vector;
1906 initialize_vector ();
1909 if (vector.Count < new_array.Count)
1910 lower = upper = vector.Count;
1912 lower = new_array.Count;
1913 upper = vector.Count;
1916 for (int i = 0; i < lower; i++)
1917 vector [i] = vector [i] & new_array [i];
1919 for (int i = lower; i < upper; i++)
1923 public static void And (ref MyBitVector target, MyBitVector vector)
1926 target.And (vector);
1928 target = vector.Clone ();
1931 public static void Or (ref MyBitVector target, MyBitVector vector)
1936 target = vector.Clone ();
1940 // This does a deep copy of the bit vector.
1942 public MyBitVector Clone ()
1944 MyBitVector retval = new MyBitVector (Count);
1946 retval.Vector = Vector;
1955 else if (!is_dirty && (InheritsFrom != null))
1956 return InheritsFrom.Vector;
1958 initialize_vector ();
1964 initialize_vector ();
1966 for (int i = 0; i < System.Math.Min (vector.Count, value.Count); i++)
1967 vector [i] = value [i];
1971 void initialize_vector ()
1976 vector = new BitArray (Count, false);
1977 if (InheritsFrom != null)
1978 Vector = InheritsFrom.Vector;
1983 public override string ToString ()
1985 StringBuilder sb = new StringBuilder ("{");
1987 BitArray vector = Vector;
1990 for (int i = 0; i < vector.Count; i++) {
1991 sb.Append (vector [i] ? "1" : "0");
1995 return sb.ToString ();