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;
19 public enum TriState : byte {
20 // Never < Sometimes < Always
27 // A new instance of this class is created every time a new block is resolved
28 // and if there's branching in the block's control flow.
30 public abstract class FlowBranching
33 // The type of a FlowBranching.
35 public enum BranchingType : byte {
36 // Normal (conditional or toplevel) block.
56 // The type of one sibling of a branching.
58 public enum SiblingType : byte {
67 public sealed class Reachability
69 TriState returns, breaks, throws, barrier;
71 public TriState Returns {
72 get { return returns; }
74 public TriState Breaks {
75 get { return breaks; }
77 public TriState Throws {
78 get { return throws; }
80 public TriState Barrier {
81 get { return barrier; }
84 Reachability (TriState returns, TriState breaks, TriState throws, TriState barrier)
86 this.returns = returns;
89 this.barrier = barrier;
92 public Reachability Clone ()
94 return new Reachability (returns, breaks, throws, barrier);
97 public static TriState TriState_Meet (TriState a, TriState b)
99 // (1) if both are Never, return Never
100 // (2) if both are Always, return Always
101 // (3) otherwise, return Sometimes
102 // note that (3) => (3') if both are Sometimes, return Sometimes
103 return a == b ? a : TriState.Sometimes;
106 public static TriState TriState_Max (TriState a, TriState b)
108 return ((byte) a > (byte) b) ? a : b;
111 public void Meet (Reachability b, bool do_break)
114 // `break' does not "break" in a Switch or a LoopBlock
116 bool a_breaks = do_break && AlwaysBreaks;
117 bool b_breaks = do_break && b.AlwaysBreaks;
119 bool a_has_barrier, b_has_barrier;
122 // This is the normal case: the code following a barrier
123 // cannot be reached.
125 a_has_barrier = AlwaysHasBarrier;
126 b_has_barrier = b.AlwaysHasBarrier;
129 // Special case for Switch and LoopBlocks: we can reach the
130 // code after the barrier via the `break'.
132 a_has_barrier = !AlwaysBreaks && AlwaysHasBarrier;
133 b_has_barrier = !b.AlwaysBreaks && b.AlwaysHasBarrier;
136 bool a_unreachable = a_breaks || AlwaysThrows || a_has_barrier;
137 bool b_unreachable = b_breaks || b.AlwaysThrows || b_has_barrier;
140 // Do all code paths always return ?
143 if (b.AlwaysReturns || b_unreachable)
144 returns = TriState.Always;
146 returns = TriState.Sometimes;
147 } else if (b.AlwaysReturns) {
148 if (AlwaysReturns || a_unreachable)
149 returns = TriState.Always;
151 returns = TriState.Sometimes;
152 } else if (!MayReturn) {
154 returns = TriState.Sometimes;
156 returns = TriState.Never;
157 } else if (!b.MayReturn) {
159 returns = TriState.Sometimes;
161 returns = TriState.Never;
164 breaks = TriState_Meet (breaks, b.breaks);
165 throws = TriState_Meet (throws, b.throws);
166 barrier = TriState_Meet (barrier, b.barrier);
168 if (a_unreachable && b_unreachable)
169 barrier = TriState.Always;
170 else if (a_unreachable || b_unreachable)
171 barrier = TriState.Sometimes;
173 barrier = TriState.Never;
176 public void Or (Reachability b)
178 returns = TriState_Max (returns, b.returns);
179 breaks = TriState_Max (breaks, b.breaks);
180 throws = TriState_Max (throws, b.throws);
181 barrier = TriState_Max (barrier, b.barrier);
184 public static Reachability Always ()
186 return new Reachability (
187 TriState.Never, TriState.Never,
188 TriState.Never, TriState.Never);
191 public TriState Reachable {
193 if ((returns == TriState.Always) ||
194 (breaks == TriState.Always) ||
195 (throws == TriState.Always) ||
196 (barrier == TriState.Always))
197 return TriState.Never;
198 else if ((returns == TriState.Never) &&
199 (breaks == TriState.Never) &&
200 (throws == TriState.Never) &&
201 (barrier == TriState.Never))
202 return TriState.Always;
204 return TriState.Sometimes;
208 public bool AlwaysBreaks {
209 get { return breaks == TriState.Always; }
212 public bool MayBreak {
213 get { return breaks != TriState.Never; }
216 public bool AlwaysReturns {
217 get { return returns == TriState.Always; }
220 public bool MayReturn {
221 get { return returns != TriState.Never; }
224 public bool AlwaysThrows {
225 get { return throws == TriState.Always; }
228 public bool MayThrow {
229 get { return throws != TriState.Never; }
232 public bool AlwaysHasBarrier {
233 get { return barrier == TriState.Always; }
236 public bool MayHaveBarrier {
237 get { return barrier != TriState.Never; }
240 public bool IsUnreachable {
241 get { return Reachable == TriState.Never; }
244 public void SetReturns ()
246 returns = TriState.Always;
249 public void SetReturnsSometimes ()
251 returns = TriState.Sometimes;
254 public void SetBreaks ()
256 breaks = TriState.Always;
259 public void ResetBreaks ()
261 breaks = TriState.Never;
264 public void SetThrows ()
266 throws = TriState.Always;
269 public void SetThrowsSometimes ()
271 throws = TriState.Sometimes;
274 public void SetBarrier ()
276 barrier = TriState.Always;
279 public void ResetBarrier ()
281 barrier = TriState.Never;
284 static string ShortName (TriState returns)
289 case TriState.Sometimes:
296 public override string ToString ()
298 return String.Format ("[{0}:{1}:{2}:{3}:{4}]",
299 ShortName (returns), ShortName (breaks),
300 ShortName (throws), ShortName (barrier),
301 ShortName (Reachable));
305 public static FlowBranching CreateBranching (FlowBranching parent, BranchingType type, Block block, Location loc)
308 case BranchingType.Exception:
309 throw new InvalidOperationException ();
311 case BranchingType.Switch:
312 return new FlowBranchingSwitch (parent, block, loc);
314 case BranchingType.SwitchSection:
315 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
317 case BranchingType.Block:
318 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
320 case BranchingType.Loop:
321 return new FlowBranchingLoop (parent, block, loc);
324 return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc);
329 // The type of this flow branching.
331 public readonly BranchingType Type;
334 // The block this branching is contained in. This may be null if it's not
335 // a top-level block and it doesn't declare any local variables.
337 public readonly Block Block;
340 // The parent of this branching or null if this is the top-block.
342 public readonly FlowBranching Parent;
345 // Start-Location of this flow branching.
347 public readonly Location Location;
350 // If this is an infinite loop.
352 public bool Infinite;
357 VariableMap param_map, local_map;
359 static int next_id = 0;
363 // The vector contains a BitArray with information about which local variables
364 // and parameters are already initialized at the current code position.
366 public class UsageVector {
368 // The type of this branching.
370 public readonly SiblingType Type;
373 // Start location of this branching.
375 public readonly Location Location;
378 // This is only valid for SwitchSection, Try, Catch and Finally.
380 public readonly Block Block;
383 // If this is true, then the usage vector has been modified and must be
384 // merged when we're done with this branching.
389 // The number of parameters in this block.
391 public readonly int CountParameters;
394 // The number of locals in this block.
396 public readonly int CountLocals;
399 // If not null, then we inherit our state from this vector and do a
400 // copy-on-write. If null, then we're the first sibling in a top-level
401 // block and inherit from the empty vector.
403 public readonly UsageVector InheritsFrom;
406 // This is used to construct a list of UsageVector's.
408 public UsageVector Next;
413 MyBitVector locals, parameters;
414 Reachability reachability;
416 static int next_id = 0;
420 // Normally, you should not use any of these constructors.
422 public UsageVector (SiblingType type, UsageVector parent,
423 Block block, Location loc,
424 int num_params, int num_locals)
429 this.InheritsFrom = parent;
430 this.CountParameters = num_params;
431 this.CountLocals = num_locals;
433 if (parent != null) {
435 locals = new MyBitVector (parent.locals, CountLocals);
438 parameters = new MyBitVector (parent.parameters, num_params);
440 reachability = parent.Reachability.Clone ();
443 locals = new MyBitVector (null, CountLocals);
446 parameters = new MyBitVector (null, num_params);
448 reachability = Reachability.Always ();
454 public UsageVector (SiblingType type, UsageVector parent,
455 Block block, Location loc)
456 : this (type, parent, block, loc,
457 parent.CountParameters, parent.CountLocals)
460 public UsageVector (MyBitVector parameters, MyBitVector locals,
461 Reachability reachability, Block block,
464 this.Type = SiblingType.Block;
468 this.reachability = reachability;
469 this.parameters = parameters;
470 this.locals = locals;
476 // This does a deep copy of the usage vector.
478 public UsageVector Clone ()
480 UsageVector retval = new UsageVector (
481 Type, null, Block, Location,
482 CountParameters, CountLocals);
484 if (retval.locals != null)
485 retval.locals = locals.Clone ();
487 if (parameters != null)
488 retval.parameters = parameters.Clone ();
490 retval.reachability = reachability.Clone ();
495 public bool IsAssigned (VariableInfo var, bool ignoreReachability)
497 if (!ignoreReachability && !var.IsParameter && Reachability.IsUnreachable)
500 return var.IsAssigned (var.IsParameter ? parameters : locals);
503 public void SetAssigned (VariableInfo var)
505 if (!var.IsParameter && Reachability.IsUnreachable)
509 var.SetAssigned (var.IsParameter ? parameters : locals);
512 public bool IsFieldAssigned (VariableInfo var, string name)
514 if (!var.IsParameter && Reachability.IsUnreachable)
517 return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name);
520 public void SetFieldAssigned (VariableInfo var, string name)
522 if (!var.IsParameter && Reachability.IsUnreachable)
526 var.SetFieldAssigned (var.IsParameter ? parameters : locals, name);
529 public Reachability Reachability {
530 get { return reachability; }
533 public void Return ()
535 if (!reachability.IsUnreachable) {
537 reachability.SetReturns ();
543 if (!reachability.IsUnreachable) {
545 reachability.SetBreaks ();
551 if (!reachability.IsUnreachable) {
553 reachability.SetThrows ();
559 if (!reachability.IsUnreachable) {
561 reachability.SetBarrier ();
566 // Merges a child branching.
568 public UsageVector MergeChild (UsageVector child, bool implicit_block)
570 Report.Debug (2, " MERGING CHILD EFFECTS", this, child, IsDirty, reachability, Type);
572 Reachability new_r = child.Reachability;
575 // We've now either reached the point after the branching or we will
576 // never get there since we always return or always throw an exception.
578 // If we can reach the point after the branching, mark all locals and
579 // parameters as initialized which have been initialized in all branches
580 // we need to look at (see above).
583 if ((Type == SiblingType.SwitchSection) && !new_r.IsUnreachable) {
584 Report.Error (163, Location,
585 "Control cannot fall through from one " +
586 "case label to another");
590 if (locals != null && child.LocalVector != null)
591 locals.Or (child.LocalVector);
593 if (child.ParameterVector != null)
594 parameters.Or (child.ParameterVector);
597 reachability = new_r.Clone ();
599 reachability.Or (new_r);
606 protected static void MergeFinally (UsageVector f_origins,
607 MyBitVector f_params)
609 for (UsageVector vector = f_origins; vector != null; vector = vector.Next) {
610 MyBitVector temp_params = f_params.Clone ();
611 temp_params.Or (vector.Parameters);
615 public void MergeFinally (UsageVector f_vector,
616 UsageVector f_origins)
618 if (parameters != null) {
619 if (f_vector != null) {
620 MergeFinally (f_origins, f_vector.Parameters);
621 MyBitVector.Or (ref parameters, f_vector.ParameterVector);
623 MergeFinally (f_origins, parameters);
626 if (f_vector != null && f_vector.LocalVector != null)
627 MyBitVector.Or (ref locals, f_vector.LocalVector);
631 // Tells control flow analysis that the current code position may be reached with
632 // a forward jump from any of the origins listed in `origin_vectors' which is a
633 // list of UsageVectors.
635 // This is used when resolving forward gotos - in the following example, the
636 // variable `a' is uninitialized in line 8 becase this line may be reached via
637 // the goto in line 4:
647 // 8 Console.WriteLine (a);
650 public void MergeJumpOrigins (UsageVector o_vectors)
652 Report.Debug (1, " MERGING JUMP ORIGINS", this);
654 reachability = Reachability.Always ();
656 if (o_vectors == null) {
657 reachability.SetBarrier ();
663 for (UsageVector vector = o_vectors; vector != null;
664 vector = vector.Next) {
665 Report.Debug (1, " MERGING JUMP ORIGIN", vector,
666 first, locals, vector.Locals);
669 if (locals != null && vector.Locals != null)
670 locals.Or (vector.locals);
672 if (parameters != null)
673 parameters.Or (vector.parameters);
677 locals.And (vector.locals);
678 if (parameters != null)
679 parameters.And (vector.parameters);
682 reachability.Meet (vector.Reachability, true);
684 Report.Debug (1, " MERGING JUMP ORIGIN #1", vector);
687 Report.Debug (1, " MERGING JUMP ORIGINS DONE", this);
691 // This is used at the beginning of a finally block if there were
692 // any return statements in the try block or one of the catch blocks.
694 public void MergeFinallyOrigins (UsageVector f_origins)
696 Report.Debug (1, " MERGING FINALLY ORIGIN", this);
698 reachability = Reachability.Always ();
700 for (UsageVector vector = f_origins; vector != null; vector = vector.Next) {
701 Report.Debug (1, " MERGING FINALLY ORIGIN", vector);
703 if (parameters != null)
704 parameters.And (vector.parameters);
706 reachability.Meet (vector.Reachability, true);
709 Report.Debug (1, " MERGING FINALLY ORIGIN DONE", this);
712 public void MergeBreakOrigins (FlowBranching branching, UsageVector o_vectors)
714 Report.Debug (1, " MERGING BREAK ORIGINS", this);
716 if (o_vectors == null)
719 bool first = branching.Infinite;
721 for (UsageVector vector = o_vectors; vector != null;
722 vector = vector.Next) {
723 Report.Debug (1, " MERGING BREAK ORIGIN", vector, first);
726 if (locals != null && vector.Locals != null)
727 locals.Or (vector.locals);
729 if (parameters != null)
730 parameters.Or (vector.parameters);
733 if (locals != null && vector.Locals != null)
734 locals.And (vector.locals);
735 if (parameters != null)
736 parameters.And (vector.parameters);
739 reachability.Meet (vector.Reachability, false);
742 Report.Debug (1, " MERGING BREAK ORIGINS DONE", this);
745 public void CheckOutParameters (FlowBranching branching)
747 if (parameters != null)
748 branching.CheckOutParameters (parameters, branching.Location);
752 // Performs an `or' operation on the locals and the parameters.
754 public void Or (UsageVector new_vector)
757 locals.Or (new_vector.locals);
758 if (parameters != null)
759 parameters.Or (new_vector.parameters);
763 // Performs an `and' operation on the locals.
765 public void AndLocals (UsageVector new_vector)
768 locals.And (new_vector.locals);
771 public bool HasParameters {
772 get { return parameters != null; }
775 public bool HasLocals {
776 get { return locals != null; }
780 // Returns a deep copy of the parameters.
782 public MyBitVector Parameters {
783 get { return parameters == null ? null : parameters.Clone (); }
787 // Returns a deep copy of the locals.
789 public MyBitVector Locals {
790 get { return locals == null ? null : locals.Clone (); }
793 public MyBitVector ParameterVector {
794 get { return parameters; }
797 public MyBitVector LocalVector {
798 get { return locals; }
805 public override string ToString ()
807 StringBuilder sb = new StringBuilder ();
809 sb.Append ("Vector (");
816 sb.Append (reachability);
817 if (parameters != null) {
819 sb.Append (parameters);
825 return sb.ToString ();
830 // Creates a new flow branching which is contained in `parent'.
831 // You should only pass non-null for the `block' argument if this block
832 // introduces any new variables - in this case, we need to create a new
833 // usage vector with a different size than our parent's one.
835 protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
836 Block block, Location loc)
846 param_map = Block.ParameterMap;
847 local_map = Block.LocalMap;
849 UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
850 vector = new UsageVector (
851 stype, parent_vector, Block, loc,
852 param_map.Length, local_map.Length);
854 param_map = Parent.param_map;
855 local_map = Parent.local_map;
856 vector = new UsageVector (
857 stype, Parent.CurrentUsageVector, null, loc);
863 public abstract UsageVector CurrentUsageVector {
868 // Creates a sibling of the current usage vector.
870 public virtual void CreateSibling (Block block, SiblingType type)
872 UsageVector vector = new UsageVector (
873 type, Parent.CurrentUsageVector, block, Location);
876 Report.Debug (1, " CREATED SIBLING", CurrentUsageVector);
879 public void CreateSibling ()
881 CreateSibling (null, SiblingType.Conditional);
884 protected abstract void AddSibling (UsageVector uv);
886 public virtual LabeledStatement LookupLabel (string name, Location loc)
889 return Parent.LookupLabel (name, loc);
893 "No such label `" + name + "' in this scope");
897 public abstract void Label (UsageVector origin_vectors);
900 // Check whether all `out' parameters have been assigned.
902 public void CheckOutParameters (MyBitVector parameters, Location loc)
904 for (int i = 0; i < param_map.Count; i++) {
905 VariableInfo var = param_map [i];
910 if (var.IsAssigned (parameters))
913 Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method",
918 protected UsageVector Merge (UsageVector sibling_list)
920 if (sibling_list.Next == null)
923 MyBitVector locals = null;
924 MyBitVector parameters = null;
926 Reachability reachability = null;
928 Report.Debug (2, " MERGING SIBLINGS", this, Name);
930 for (UsageVector child = sibling_list; child != null; child = child.Next) {
931 bool do_break = (Type != BranchingType.Switch) &&
932 (Type != BranchingType.Loop);
934 Report.Debug (2, " MERGING SIBLING ", child,
935 child.ParameterVector, child.LocalVector,
936 reachability, child.Reachability, do_break);
938 if (reachability == null)
939 reachability = child.Reachability.Clone ();
941 reachability.Meet (child.Reachability, do_break);
943 // A local variable is initialized after a flow branching if it
944 // has been initialized in all its branches which do neither
945 // always return or always throw an exception.
947 // If a branch may return, but does not always return, then we
948 // can treat it like a never-returning branch here: control will
949 // only reach the code position after the branching if we did not
952 // It's important to distinguish between always and sometimes
953 // returning branches here:
956 // 2 if (something) {
960 // 6 Console.WriteLine (a);
962 // The if block in lines 3-4 always returns, so we must not look
963 // at the initialization of `a' in line 4 - thus it'll still be
964 // uninitialized in line 6.
966 // On the other hand, the following is allowed:
973 // 6 Console.WriteLine (a);
975 // Here, `a' is initialized in line 3 and we must not look at
976 // line 5 since it always returns.
978 bool do_break_2 = (child.Type != SiblingType.Block) &&
979 (child.Type != SiblingType.SwitchSection);
980 bool always_throws = (child.Type != SiblingType.Try) &&
981 child.Reachability.AlwaysThrows;
982 bool unreachable = always_throws ||
983 (do_break_2 && child.Reachability.AlwaysBreaks) ||
984 child.Reachability.AlwaysReturns ||
985 child.Reachability.AlwaysHasBarrier;
987 Report.Debug (2, " MERGING SIBLING #1", reachability,
988 Type, child.Type, child.Reachability.IsUnreachable,
989 do_break_2, always_throws, unreachable);
991 if (!unreachable && (child.LocalVector != null))
992 MyBitVector.And (ref locals, child.LocalVector);
994 // An `out' parameter must be assigned in all branches which do
995 // not always throw an exception.
996 if ((child.ParameterVector != null) && !child.Reachability.AlwaysThrows)
997 MyBitVector.And (ref parameters, child.ParameterVector);
999 Report.Debug (2, " MERGING SIBLING #2", parameters, locals);
1002 if (reachability == null)
1003 throw new InternalErrorException ("Cannot happen: the loop above runs at least twice");
1005 Report.Debug (2, " MERGING SIBLINGS DONE", parameters, locals,
1006 reachability, Infinite);
1008 return new UsageVector (
1009 parameters, locals, reachability, null, Location);
1012 protected abstract UsageVector Merge ();
1015 // Merge a child branching.
1017 public UsageVector MergeChild (FlowBranching child)
1019 bool implicit_block = child.Type == BranchingType.Block && child.Block.Implicit;
1020 Report.Debug (2, " MERGING CHILD", this, child);
1021 UsageVector result = CurrentUsageVector.MergeChild (child.Merge (), implicit_block);
1022 Report.Debug (2, " MERGING CHILD DONE", this, result);
1027 // Does the toplevel merging.
1029 public Reachability MergeTopBlock ()
1031 if ((Type != BranchingType.Block) || (Block == null))
1032 throw new NotSupportedException ();
1034 UsageVector result = Merge ();
1036 Report.Debug (4, "MERGE TOP BLOCK", Location, result);
1038 if ((result.Reachability.Throws != TriState.Always) &&
1039 (result.Reachability.Barrier != TriState.Always))
1040 CheckOutParameters (result.Parameters, Location);
1042 return result.Reachability;
1046 // Checks whether we're in a `try' block.
1048 public virtual bool InTryOrCatch (bool is_return)
1050 if (Block != null && Block.IsDestructor)
1052 if (!is_return && (Type == BranchingType.Loop || Type == BranchingType.Switch))
1054 return Parent != null && Parent.InTryOrCatch (is_return);
1057 public virtual bool InTryWithCatch ()
1059 return Parent != null && Parent.InTryWithCatch ();
1062 public virtual bool InLoop ()
1064 return Parent != null && Parent.InLoop ();
1067 public virtual bool InSwitch ()
1069 return Parent != null && Parent.InSwitch ();
1072 public virtual bool BreakCrossesTryCatchBoundary ()
1074 return Parent != null && Parent.BreakCrossesTryCatchBoundary ();
1077 public virtual void AddFinallyVector (UsageVector vector)
1080 Parent.AddFinallyVector (vector);
1081 else if ((Block == null) || !Block.IsDestructor)
1082 throw new NotSupportedException ();
1085 public virtual void AddBreakVector (UsageVector vector)
1088 Parent.AddBreakVector (vector);
1089 else if ((Block == null) || !Block.IsDestructor)
1090 throw new NotSupportedException ();
1093 public virtual void StealFinallyClauses (ref ArrayList list)
1096 Parent.StealFinallyClauses (ref list);
1099 public bool IsAssigned (VariableInfo vi)
1101 return CurrentUsageVector.IsAssigned (vi, false);
1104 public bool IsFieldAssigned (VariableInfo vi, string field_name)
1106 return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
1109 public void SetAssigned (VariableInfo vi)
1111 CurrentUsageVector.SetAssigned (vi);
1114 public void SetFieldAssigned (VariableInfo vi, string name)
1116 CurrentUsageVector.SetFieldAssigned (vi, name);
1119 public override string ToString ()
1121 StringBuilder sb = new StringBuilder ();
1122 sb.Append (GetType ());
1128 if (Block != null) {
1130 sb.Append (Block.ID);
1132 sb.Append (Block.StartLocation);
1135 // sb.Append (Siblings.Length);
1136 // sb.Append (" - ");
1137 sb.Append (CurrentUsageVector);
1139 return sb.ToString ();
1142 public string Name {
1143 get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
1147 public class FlowBranchingBlock : FlowBranching
1149 UsageVector sibling_list = null;
1151 public FlowBranchingBlock (FlowBranching parent, BranchingType type,
1152 SiblingType stype, Block block, Location loc)
1153 : base (parent, type, stype, block, loc)
1156 public override UsageVector CurrentUsageVector {
1157 get { return sibling_list; }
1160 protected override void AddSibling (UsageVector sibling)
1162 sibling.Next = sibling_list;
1163 sibling_list = sibling;
1166 public override LabeledStatement LookupLabel (string name, Location loc)
1169 return base.LookupLabel (name, loc);
1171 LabeledStatement s = Block.LookupLabel (name);
1175 return base.LookupLabel (name, loc);
1178 public override void Label (UsageVector origin_vectors)
1180 if (!CurrentUsageVector.Reachability.IsUnreachable) {
1181 UsageVector vector = CurrentUsageVector.Clone ();
1182 vector.Next = origin_vectors;
1183 origin_vectors = vector;
1186 CurrentUsageVector.MergeJumpOrigins (origin_vectors);
1189 protected override UsageVector Merge ()
1191 return Merge (sibling_list);
1195 public class FlowBranchingLoop : FlowBranchingBlock
1197 UsageVector break_origins;
1199 public FlowBranchingLoop (FlowBranching parent, Block block, Location loc)
1200 : base (parent, BranchingType.Loop, SiblingType.Conditional, block, loc)
1203 public override void AddBreakVector (UsageVector vector)
1205 vector = vector.Clone ();
1206 vector.Next = break_origins;
1207 break_origins = vector;
1210 public override bool InLoop ()
1215 public override bool BreakCrossesTryCatchBoundary ()
1220 protected override UsageVector Merge ()
1222 UsageVector vector = base.Merge ();
1224 vector.MergeBreakOrigins (this, break_origins);
1226 Reachability r = vector.Reachability;
1230 } else if (Infinite) {
1233 // If we're an infinite loop and do not break,
1234 // the code after the loop can never be reached.
1235 // However, if we may return from the loop,
1236 // then we do always return (or stay in the
1242 // swallow up the 'break'
1249 public class FlowBranchingSwitch : FlowBranchingBlock
1251 UsageVector break_origins;
1253 public FlowBranchingSwitch (FlowBranching parent, Block block, Location loc)
1254 : base (parent, BranchingType.Switch, SiblingType.SwitchSection, block, loc)
1257 public override void AddBreakVector (UsageVector vector)
1259 vector = vector.Clone ();
1260 vector.Next = break_origins;
1261 break_origins = vector;
1264 public override bool InSwitch ()
1269 public override bool BreakCrossesTryCatchBoundary ()
1274 protected override UsageVector Merge ()
1276 UsageVector vector = base.Merge ();
1278 vector.MergeBreakOrigins (this, break_origins);
1280 Reachability r = vector.Reachability;
1282 if (r.MayBreak || r.MayReturn)
1291 public class FlowBranchingException : FlowBranching
1293 ExceptionStatement stmt;
1294 UsageVector current_vector;
1295 UsageVector catch_vectors;
1296 UsageVector finally_vector;
1297 UsageVector finally_origins;
1300 public FlowBranchingException (FlowBranching parent,
1301 ExceptionStatement stmt)
1302 : base (parent, BranchingType.Exception, SiblingType.Try,
1306 this.emit_finally = true;
1309 protected override void AddSibling (UsageVector sibling)
1311 if (sibling.Type == SiblingType.Try) {
1312 sibling.Next = catch_vectors;
1313 catch_vectors = sibling;
1314 } else if (sibling.Type == SiblingType.Catch) {
1315 sibling.Next = catch_vectors;
1316 catch_vectors = sibling;
1317 } else if (sibling.Type == SiblingType.Finally) {
1318 sibling.MergeFinallyOrigins (finally_origins);
1319 finally_vector = sibling;
1321 throw new InvalidOperationException ();
1323 current_vector = sibling;
1326 public override UsageVector CurrentUsageVector {
1327 get { return current_vector; }
1330 public override bool InTryOrCatch (bool is_return)
1332 return finally_vector == null;
1335 public override bool InTryWithCatch ()
1337 if (finally_vector == null) {
1338 Try t = stmt as Try;
1339 if (t != null && t.HasCatch)
1343 return base.InTryWithCatch ();
1346 public override bool BreakCrossesTryCatchBoundary ()
1351 public override void AddFinallyVector (UsageVector vector)
1353 vector = vector.Clone ();
1354 vector.Next = finally_origins;
1355 finally_origins = vector;
1358 public override void StealFinallyClauses (ref ArrayList list)
1361 list = new ArrayList ();
1363 emit_finally = false;
1364 base.StealFinallyClauses (ref list);
1367 public bool EmitFinally {
1368 get { return emit_finally; }
1371 public override LabeledStatement LookupLabel (string name, Location loc)
1373 if (current_vector.Block == null)
1374 return base.LookupLabel (name, loc);
1376 LabeledStatement s = current_vector.Block.LookupLabel (name);
1380 if (finally_vector != null) {
1381 Report.Error (157, loc,
1382 "Control cannot leave the body of a finally clause");
1386 return base.LookupLabel (name, loc);
1389 public override void Label (UsageVector origin_vectors)
1391 CurrentUsageVector.MergeJumpOrigins (origin_vectors);
1394 protected override UsageVector Merge ()
1396 UsageVector vector = Merge (catch_vectors);
1398 vector.MergeFinally (finally_vector, finally_origins);
1405 // This is used by the flow analysis code to keep track of the type of local variables
1408 // The flow code uses a BitVector to keep track of whether a variable has been assigned
1409 // or not. This is easy for fundamental types (int, char etc.) or reference types since
1410 // you can only assign the whole variable as such.
1412 // For structs, we also need to keep track of all its fields. To do this, we allocate one
1413 // bit for the struct itself (it's used if you assign/access the whole struct) followed by
1414 // one bit for each of its fields.
1416 // This class computes this `layout' for each type.
1418 public class TypeInfo
1420 public readonly Type Type;
1423 // Total number of bits a variable of this type consumes in the flow vector.
1425 public readonly int TotalLength;
1428 // Number of bits the simple fields of a variable of this type consume
1429 // in the flow vector.
1431 public readonly int Length;
1434 // This is only used by sub-structs.
1436 public readonly int Offset;
1439 // If this is a struct.
1441 public readonly bool IsStruct;
1444 // If this is a struct, all fields which are structs theirselves.
1446 public TypeInfo[] SubStructInfo;
1448 protected readonly StructInfo struct_info;
1449 private static Hashtable type_hash = new Hashtable ();
1451 public static TypeInfo GetTypeInfo (Type type)
1453 TypeInfo info = (TypeInfo) type_hash [type];
1457 info = new TypeInfo (type);
1458 type_hash.Add (type, info);
1462 public static TypeInfo GetTypeInfo (TypeContainer tc)
1464 TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
1468 info = new TypeInfo (tc);
1469 type_hash.Add (tc.TypeBuilder, info);
1473 private TypeInfo (Type type)
1477 struct_info = StructInfo.GetStructInfo (type);
1478 if (struct_info != null) {
1479 Length = struct_info.Length;
1480 TotalLength = struct_info.TotalLength;
1481 SubStructInfo = struct_info.StructFields;
1490 private TypeInfo (TypeContainer tc)
1492 this.Type = tc.TypeBuilder;
1494 struct_info = StructInfo.GetStructInfo (tc);
1495 if (struct_info != null) {
1496 Length = struct_info.Length;
1497 TotalLength = struct_info.TotalLength;
1498 SubStructInfo = struct_info.StructFields;
1507 protected TypeInfo (StructInfo struct_info, int offset)
1509 this.struct_info = struct_info;
1510 this.Offset = offset;
1511 this.Length = struct_info.Length;
1512 this.TotalLength = struct_info.TotalLength;
1513 this.SubStructInfo = struct_info.StructFields;
1514 this.Type = struct_info.Type;
1515 this.IsStruct = true;
1518 public int GetFieldIndex (string name)
1520 if (struct_info == null)
1523 return struct_info [name];
1526 public TypeInfo GetSubStruct (string name)
1528 if (struct_info == null)
1531 return struct_info.GetStructField (name);
1535 // A struct's constructor must always assign all fields.
1536 // This method checks whether it actually does so.
1538 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1540 if (struct_info == null)
1544 for (int i = 0; i < struct_info.Count; i++) {
1545 FieldInfo field = struct_info.Fields [i];
1547 if (!branching.IsFieldAssigned (vi, field.Name)) {
1548 Report.Error (171, loc,
1549 "Field `{0}' must be fully assigned before control leaves the constructor",
1550 TypeManager.GetFullNameSignature (field));
1558 public override string ToString ()
1560 return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1561 Type, Offset, Length, TotalLength);
1564 protected class StructInfo {
1565 public readonly Type Type;
1566 public readonly FieldInfo[] Fields;
1567 public readonly TypeInfo[] StructFields;
1568 public readonly int Count;
1569 public readonly int CountPublic;
1570 public readonly int CountNonPublic;
1571 public readonly int Length;
1572 public readonly int TotalLength;
1573 public readonly bool HasStructFields;
1575 private static Hashtable field_type_hash = new Hashtable ();
1576 private Hashtable struct_field_hash;
1577 private Hashtable field_hash;
1579 protected bool InTransit = false;
1581 // Private constructor. To save memory usage, we only need to create one instance
1582 // of this class per struct type.
1583 private StructInfo (Type type)
1587 field_type_hash.Add (type, this);
1589 if (type is TypeBuilder) {
1590 TypeContainer tc = TypeManager.LookupTypeContainer (type);
1592 ArrayList fields = null;
1596 ArrayList public_fields = new ArrayList ();
1597 ArrayList non_public_fields = new ArrayList ();
1599 if (fields != null) {
1600 foreach (FieldMember field in fields) {
1601 if ((field.ModFlags & Modifiers.STATIC) != 0)
1603 if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1604 public_fields.Add (field.FieldBuilder);
1606 non_public_fields.Add (field.FieldBuilder);
1610 CountPublic = public_fields.Count;
1611 CountNonPublic = non_public_fields.Count;
1612 Count = CountPublic + CountNonPublic;
1614 Fields = new FieldInfo [Count];
1615 public_fields.CopyTo (Fields, 0);
1616 non_public_fields.CopyTo (Fields, CountPublic);
1617 } else if (type is GenericTypeParameterBuilder) {
1618 CountPublic = CountNonPublic = Count = 0;
1620 Fields = new FieldInfo [0];
1622 FieldInfo[] public_fields = type.GetFields (
1623 BindingFlags.Instance|BindingFlags.Public);
1624 FieldInfo[] non_public_fields = type.GetFields (
1625 BindingFlags.Instance|BindingFlags.NonPublic);
1627 CountPublic = public_fields.Length;
1628 CountNonPublic = non_public_fields.Length;
1629 Count = CountPublic + CountNonPublic;
1631 Fields = new FieldInfo [Count];
1632 public_fields.CopyTo (Fields, 0);
1633 non_public_fields.CopyTo (Fields, CountPublic);
1636 struct_field_hash = new Hashtable ();
1637 field_hash = new Hashtable ();
1640 StructFields = new TypeInfo [Count];
1641 StructInfo[] sinfo = new StructInfo [Count];
1645 for (int i = 0; i < Count; i++) {
1646 FieldInfo field = (FieldInfo) Fields [i];
1648 sinfo [i] = GetStructInfo (field.FieldType);
1649 if (sinfo [i] == null)
1650 field_hash.Add (field.Name, ++Length);
1651 else if (sinfo [i].InTransit) {
1652 Report.Error (523, String.Format (
1653 "Struct member `{0}.{1}' of type `{2}' causes " +
1654 "a cycle in the structure layout",
1655 type, field.Name, sinfo [i].Type));
1663 TotalLength = Length + 1;
1664 for (int i = 0; i < Count; i++) {
1665 FieldInfo field = (FieldInfo) Fields [i];
1667 if (sinfo [i] == null)
1670 field_hash.Add (field.Name, TotalLength);
1672 HasStructFields = true;
1673 StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1674 struct_field_hash.Add (field.Name, StructFields [i]);
1675 TotalLength += sinfo [i].TotalLength;
1679 public int this [string name] {
1681 if (field_hash.Contains (name))
1682 return (int) field_hash [name];
1688 public TypeInfo GetStructField (string name)
1690 return (TypeInfo) struct_field_hash [name];
1693 public static StructInfo GetStructInfo (Type type)
1695 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1696 TypeManager.IsBuiltinType (type))
1699 StructInfo info = (StructInfo) field_type_hash [type];
1703 return new StructInfo (type);
1706 public static StructInfo GetStructInfo (TypeContainer tc)
1708 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1712 return new StructInfo (tc.TypeBuilder);
1718 // This is used by the flow analysis code to store information about a single local variable
1719 // or parameter. Depending on the variable's type, we need to allocate one or more elements
1720 // in the BitVector - if it's a fundamental or reference type, we just need to know whether
1721 // it has been assigned or not, but for structs, we need this information for each of its fields.
1723 public class VariableInfo {
1724 public readonly string Name;
1725 public readonly TypeInfo TypeInfo;
1728 // The bit offset of this variable in the flow vector.
1730 public readonly int Offset;
1733 // The number of bits this variable needs in the flow vector.
1734 // The first bit always specifies whether the variable as such has been assigned while
1735 // the remaining bits contain this information for each of a struct's fields.
1737 public readonly int Length;
1740 // If this is a parameter of local variable.
1742 public readonly bool IsParameter;
1744 public readonly LocalInfo LocalInfo;
1745 public readonly int ParameterIndex;
1747 readonly VariableInfo Parent;
1748 VariableInfo[] sub_info;
1750 protected VariableInfo (string name, Type type, int offset)
1753 this.Offset = offset;
1754 this.TypeInfo = TypeInfo.GetTypeInfo (type);
1756 Length = TypeInfo.TotalLength;
1761 protected VariableInfo (VariableInfo parent, TypeInfo type)
1763 this.Name = parent.Name;
1764 this.TypeInfo = type;
1765 this.Offset = parent.Offset + type.Offset;
1766 this.Parent = parent;
1767 this.Length = type.TotalLength;
1769 this.IsParameter = parent.IsParameter;
1770 this.LocalInfo = parent.LocalInfo;
1771 this.ParameterIndex = parent.ParameterIndex;
1776 protected void Initialize ()
1778 TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1779 if (sub_fields != null) {
1780 sub_info = new VariableInfo [sub_fields.Length];
1781 for (int i = 0; i < sub_fields.Length; i++) {
1782 if (sub_fields [i] != null)
1783 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1786 sub_info = new VariableInfo [0];
1789 public VariableInfo (LocalInfo local_info, int offset)
1790 : this (local_info.Name, local_info.VariableType, offset)
1792 this.LocalInfo = local_info;
1793 this.IsParameter = false;
1796 public VariableInfo (string name, Type type, int param_idx, int offset)
1797 : this (name, type, offset)
1799 this.ParameterIndex = param_idx;
1800 this.IsParameter = true;
1803 public bool IsAssigned (EmitContext ec)
1805 return !ec.DoFlowAnalysis ||
1806 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1807 ec.CurrentBranching.IsAssigned (this);
1810 public bool IsAssigned (EmitContext ec, Location loc)
1812 if (IsAssigned (ec))
1815 Report.Error (165, loc,
1816 "Use of unassigned local variable `" + Name + "'");
1817 ec.CurrentBranching.SetAssigned (this);
1821 public bool IsAssigned (MyBitVector vector)
1823 if (vector [Offset])
1826 for (VariableInfo parent = Parent; parent != null; parent = parent.Parent)
1827 if (vector [parent.Offset])
1830 // Return unless this is a struct.
1831 if (!TypeInfo.IsStruct)
1834 // Ok, so each field must be assigned.
1835 for (int i = 0; i < TypeInfo.Length; i++) {
1836 if (!vector [Offset + i + 1])
1840 // Ok, now check all fields which are structs.
1841 for (int i = 0; i < sub_info.Length; i++) {
1842 VariableInfo sinfo = sub_info [i];
1846 if (!sinfo.IsAssigned (vector))
1850 vector [Offset] = true;
1854 public void SetAssigned (EmitContext ec)
1856 if (ec.DoFlowAnalysis)
1857 ec.CurrentBranching.SetAssigned (this);
1860 public void SetAssigned (MyBitVector vector)
1862 vector [Offset] = true;
1865 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1867 if (!ec.DoFlowAnalysis ||
1868 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1869 ec.CurrentBranching.IsFieldAssigned (this, name))
1872 Report.Error (170, loc,
1873 "Use of possibly unassigned field `" + name + "'");
1874 ec.CurrentBranching.SetFieldAssigned (this, name);
1878 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1880 int field_idx = TypeInfo.GetFieldIndex (field_name);
1885 return vector [Offset + field_idx];
1888 public void SetFieldAssigned (EmitContext ec, string name)
1890 if (ec.DoFlowAnalysis)
1891 ec.CurrentBranching.SetFieldAssigned (this, name);
1894 public void SetFieldAssigned (MyBitVector vector, string field_name)
1896 int field_idx = TypeInfo.GetFieldIndex (field_name);
1901 vector [Offset + field_idx] = true;
1904 public VariableInfo GetSubStruct (string name)
1906 TypeInfo type = TypeInfo.GetSubStruct (name);
1911 return new VariableInfo (this, type);
1914 public override string ToString ()
1916 return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1917 Name, TypeInfo, Offset, Length, IsParameter);
1922 // This is used by the flow code to hold the `layout' of the flow vector for
1923 // all locals and all parameters (ie. we create one instance of this class for the
1924 // locals and another one for the params).
1926 public class VariableMap {
1928 // The number of variables in the map.
1930 public readonly int Count;
1933 // Total length of the flow vector for this map.
1935 public readonly int Length;
1939 public VariableMap (Parameters ip)
1941 Count = ip != null ? ip.Count : 0;
1943 // Dont bother allocating anything!
1949 for (int i = 0; i < Count; i++) {
1950 Parameter.Modifier mod = ip.ParameterModifier (i);
1952 if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
1955 // Dont allocate till we find an out var.
1957 map = new VariableInfo [Count];
1959 map [i] = new VariableInfo (ip.ParameterName (i),
1960 TypeManager.GetElementType (ip.ParameterType (i)), i, Length);
1962 Length += map [i].Length;
1966 public VariableMap (LocalInfo[] locals)
1967 : this (null, locals)
1970 public VariableMap (VariableMap parent, LocalInfo[] locals)
1972 int offset = 0, start = 0;
1973 if (parent != null && parent.map != null) {
1974 offset = parent.Length;
1975 start = parent.Count;
1978 Count = locals.Length + start;
1983 map = new VariableInfo [Count];
1986 if (parent != null && parent.map != null) {
1987 parent.map.CopyTo (map, 0);
1990 for (int i = start; i < Count; i++) {
1991 LocalInfo li = locals [i-start];
1993 if (li.VariableType == null)
1996 map [i] = li.VariableInfo = new VariableInfo (li, Length);
1997 Length += map [i].Length;
2002 // Returns the VariableInfo for variable @index or null if we don't need to
2003 // compute assignment info for this variable.
2005 public VariableInfo this [int index] {
2014 public override string ToString ()
2016 return String.Format ("VariableMap ({0}:{1})", Count, Length);
2021 // This is a special bit vector which can inherit from another bit vector doing a
2022 // copy-on-write strategy. The inherited vector may have a smaller size than the
2025 public class MyBitVector {
2026 public readonly int Count;
2027 public readonly MyBitVector InheritsFrom;
2032 public MyBitVector (int Count)
2033 : this (null, Count)
2036 public MyBitVector (MyBitVector InheritsFrom, int Count)
2038 this.InheritsFrom = InheritsFrom;
2043 // Checks whether this bit vector has been modified. After setting this to true,
2044 // we won't use the inherited vector anymore, but our own copy of it.
2046 public bool IsDirty {
2047 get { return is_dirty; }
2051 initialize_vector ();
2056 // Get/set bit `index' in the bit vector.
2058 public bool this [int index]
2062 throw new ArgumentOutOfRangeException ();
2064 // We're doing a "copy-on-write" strategy here; as long
2065 // as nobody writes to the array, we can use our parent's
2066 // copy instead of duplicating the vector.
2069 return vector [index];
2070 else if (InheritsFrom != null) {
2071 BitArray inherited = InheritsFrom.Vector;
2073 if (index < inherited.Count)
2074 return inherited [index];
2083 throw new ArgumentOutOfRangeException ();
2085 // Only copy the vector if we're actually modifying it.
2087 if (this [index] != value) {
2088 initialize_vector ();
2090 vector [index] = value;
2096 // If you explicitly convert the MyBitVector to a BitArray, you will get a deep
2097 // copy of the bit vector.
2099 public static explicit operator BitArray (MyBitVector vector)
2101 vector.initialize_vector ();
2102 return vector.Vector;
2106 // Performs an `or' operation on the bit vector. The `new_vector' may have a
2107 // different size than the current one.
2109 public void Or (MyBitVector new_vector)
2111 // Treat null 'new_vector' as all false, just like the And() below
2112 if (new_vector == null)
2114 BitArray new_array = new_vector.Vector;
2116 initialize_vector ();
2119 if (vector.Count < new_array.Count)
2120 upper = vector.Count;
2122 upper = new_array.Count;
2124 for (int i = 0; i < upper; i++)
2125 vector [i] = vector [i] | new_array [i];
2129 // Perfonrms an `and' operation on the bit vector. The `new_vector' may have
2130 // a different size than the current one.
2132 public void And (MyBitVector new_vector)
2136 if (new_vector != null)
2137 new_array = new_vector.Vector;
2139 new_array = new BitArray (Count, false);
2141 initialize_vector ();
2144 if (vector.Count < new_array.Count)
2145 lower = upper = vector.Count;
2147 lower = new_array.Count;
2148 upper = vector.Count;
2151 for (int i = 0; i < lower; i++)
2152 vector [i] = vector [i] & new_array [i];
2154 for (int i = lower; i < upper; i++)
2158 public static void And (ref MyBitVector target, MyBitVector vector)
2161 target.And (vector);
2163 target = vector.Clone ();
2166 public static void Or (ref MyBitVector target, MyBitVector vector)
2171 target = vector.Clone ();
2175 // This does a deep copy of the bit vector.
2177 public MyBitVector Clone ()
2179 MyBitVector retval = new MyBitVector (Count);
2181 retval.Vector = Vector;
2190 else if (!is_dirty && (InheritsFrom != null))
2191 return InheritsFrom.Vector;
2193 initialize_vector ();
2199 initialize_vector ();
2201 for (int i = 0; i < System.Math.Min (vector.Count, value.Count); i++)
2202 vector [i] = value [i];
2206 void initialize_vector ()
2211 vector = new BitArray (Count, false);
2212 if (InheritsFrom != null)
2213 Vector = InheritsFrom.Vector;
2218 public override string ToString ()
2220 StringBuilder sb = new StringBuilder ("{");
2222 BitArray vector = Vector;
2225 for (int i = 0; i < vector.Count; i++) {
2226 sb.Append (vector [i] ? "1" : "0");
2230 return sb.ToString ();