88cecf4fea82a69c3a58fabb98e55668c583e777
[mono.git] / mcs / mcs / flowanalysis.cs
1 //
2 // flowanalyis.cs: The control flow analysis code
3 //
4 // Author:
5 //   Martin Baulig (martin@ximian.com)
6 //   Raja R Harinath (rharinath@novell.com)
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc.
9 //
10
11 using System;
12 using System.Text;
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Diagnostics;
17
18 namespace Mono.CSharp
19 {
20         // <summary>
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.
23         // </summary>
24         public abstract class FlowBranching
25         {
26                 // <summary>
27                 //   The type of a FlowBranching.
28                 // </summary>
29                 public enum BranchingType : byte {
30                         // Normal (conditional or toplevel) block.
31                         Block,
32
33                         // Conditional.
34                         Conditional,
35
36                         // A loop block.
37                         Loop,
38
39                         // The statement embedded inside a loop
40                         Embedded,
41
42                         // part of a block headed by a jump target
43                         Labeled,
44
45                         // TryCatch block.
46                         TryCatch,
47
48                         // TryFinally, Using, Lock, CollectionForeach
49                         Exception,
50
51                         // Switch block.
52                         Switch,
53
54                         // The toplevel block of a function
55                         Toplevel,
56
57                         // An iterator block
58                         Iterator
59                 }
60
61                 // <summary>
62                 //   The type of one sibling of a branching.
63                 // </summary>
64                 public enum SiblingType : byte {
65                         Block,
66                         Conditional,
67                         SwitchSection,
68                         Try,
69                         Catch,
70                         Finally
71                 }
72
73                 public static FlowBranching CreateBranching (FlowBranching parent, BranchingType type, Block block, Location loc)
74                 {
75                         switch (type) {
76                         case BranchingType.Exception:
77                         case BranchingType.Labeled:
78                         case BranchingType.Toplevel:
79                         case BranchingType.TryCatch:
80                                 throw new InvalidOperationException ();
81
82                         case BranchingType.Switch:
83                                 return new FlowBranchingBreakable (parent, type, SiblingType.SwitchSection, block, loc);
84
85                         case BranchingType.Block:
86                                 return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc);
87
88                         case BranchingType.Loop:
89                                 return new FlowBranchingBreakable (parent, type, SiblingType.Conditional, block, loc);
90
91                         case BranchingType.Embedded:
92                                 return new FlowBranchingContinuable (parent, type, SiblingType.Conditional, block, loc);
93
94                         default:
95                                 return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc);
96                         }
97                 }
98
99                 // <summary>
100                 //   The type of this flow branching.
101                 // </summary>
102                 public readonly BranchingType Type;
103
104                 // <summary>
105                 //   The block this branching is contained in.  This may be null if it's not
106                 //   a top-level block and it doesn't declare any local variables.
107                 // </summary>
108                 public readonly Block Block;
109
110                 // <summary>
111                 //   The parent of this branching or null if this is the top-block.
112                 // </summary>
113                 public readonly FlowBranching Parent;
114
115                 // <summary>
116                 //   Start-Location of this flow branching.
117                 // </summary>
118                 public readonly Location Location;
119
120                 static int next_id = 0;
121                 int id;
122
123                 // <summary>
124                 //   The vector contains a BitArray with information about which local variables
125                 //   and parameters are already initialized at the current code position.
126                 // </summary>
127                 public class UsageVector {
128                         // <summary>
129                         //   The type of this branching.
130                         // </summary>
131                         public readonly SiblingType Type;
132
133                         // <summary>
134                         //   Start location of this branching.
135                         // </summary>
136                         public Location Location;
137
138                         // <summary>
139                         //   This is only valid for SwitchSection, Try, Catch and Finally.
140                         // </summary>
141                         public readonly Block Block;
142
143                         // <summary>
144                         //   The number of locals in this block.
145                         // </summary>
146                         public readonly int CountLocals;
147
148                         // <summary>
149                         //   If not null, then we inherit our state from this vector and do a
150                         //   copy-on-write.  If null, then we're the first sibling in a top-level
151                         //   block and inherit from the empty vector.
152                         // </summary>
153                         public readonly UsageVector InheritsFrom;
154
155                         // <summary>
156                         //   This is used to construct a list of UsageVector's.
157                         // </summary>
158                         public UsageVector Next;
159
160                         //
161                         // Private.
162                         //
163                         MyBitVector locals;
164                         bool is_unreachable;
165
166                         static int next_id = 0;
167                         int id;
168
169                         //
170                         // Normally, you should not use any of these constructors.
171                         //
172                         public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc, int num_locals)
173                         {
174                                 this.Type = type;
175                                 this.Block = block;
176                                 this.Location = loc;
177                                 this.InheritsFrom = parent;
178                                 this.CountLocals = num_locals;
179
180                                 locals = num_locals == 0 
181                                         ? MyBitVector.Empty
182                                         : new MyBitVector (parent == null ? MyBitVector.Empty : parent.locals, num_locals);
183
184                                 if (parent != null)
185                                         is_unreachable = parent.is_unreachable;
186
187                                 id = ++next_id;
188
189                         }
190
191                         public UsageVector (SiblingType type, UsageVector parent, Block block, Location loc)
192                                 : this (type, parent, block, loc, parent.CountLocals)
193                         { }
194
195                         private UsageVector (MyBitVector locals, bool is_unreachable, Block block, Location loc)
196                         {
197                                 this.Type = SiblingType.Block;
198                                 this.Location = loc;
199                                 this.Block = block;
200
201                                 this.is_unreachable = is_unreachable;
202
203                                 this.locals = locals;
204
205                                 id = ++next_id;
206
207                         }
208
209                         // <summary>
210                         //   This does a deep copy of the usage vector.
211                         // </summary>
212                         public UsageVector Clone ()
213                         {
214                                 UsageVector retval = new UsageVector (Type, null, Block, Location, CountLocals);
215
216                                 retval.locals = locals.Clone ();
217                                 retval.is_unreachable = is_unreachable;
218
219                                 return retval;
220                         }
221
222                         public bool IsAssigned (VariableInfo var, bool ignoreReachability)
223                         {
224                                 if (!ignoreReachability && !var.IsParameter && IsUnreachable)
225                                         return true;
226
227                                 return var.IsAssigned (locals);
228                         }
229
230                         public void SetAssigned (VariableInfo var)
231                         {
232                                 if (!var.IsParameter && IsUnreachable)
233                                         return;
234
235                                 var.SetAssigned (locals);
236                         }
237
238                         public bool IsFieldAssigned (VariableInfo var, string name)
239                         {
240                                 if (!var.IsParameter && IsUnreachable)
241                                         return true;
242
243                                 return var.IsFieldAssigned (locals, name);
244                         }
245
246                         public void SetFieldAssigned (VariableInfo var, string name)
247                         {
248                                 if (!var.IsParameter && IsUnreachable)
249                                         return;
250
251                                 var.SetFieldAssigned (locals, name);
252                         }
253
254                         public bool IsUnreachable {
255                                 get { return is_unreachable; }
256                         }
257
258                         public void ResetBarrier ()
259                         {
260                                 is_unreachable = false;
261                         }
262
263                         public void Goto ()
264                         {
265                                 is_unreachable = true;
266                         }
267
268                         public static UsageVector MergeSiblings (UsageVector sibling_list, Location loc)
269                         {
270                                 if (sibling_list.Next == null)
271                                         return sibling_list;
272
273                                 MyBitVector locals = null;
274                                 bool is_unreachable = sibling_list.is_unreachable;
275
276                                 if (!sibling_list.IsUnreachable)
277                                         locals &= sibling_list.locals;
278
279                                 for (UsageVector child = sibling_list.Next; child != null; child = child.Next) {
280                                         is_unreachable &= child.is_unreachable;
281
282                                         if (!child.IsUnreachable)
283                                                 locals &= child.locals;
284                                 }
285
286                                 return new UsageVector (locals, is_unreachable, null, loc);
287                         }
288
289                         // <summary>
290                         //   Merges a child branching.
291                         // </summary>
292                         public UsageVector MergeChild (UsageVector child, bool overwrite)
293                         {
294                                 Report.Debug (2, "    MERGING CHILD EFFECTS", this, child, Type);
295
296                                 bool new_isunr = child.is_unreachable;
297
298                                 //
299                                 // We've now either reached the point after the branching or we will
300                                 // never get there since we always return or always throw an exception.
301                                 //
302                                 // If we can reach the point after the branching, mark all locals and
303                                 // parameters as initialized which have been initialized in all branches
304                                 // we need to look at (see above).
305                                 //
306
307                                 if ((Type == SiblingType.SwitchSection) && !new_isunr) {
308                                         Report.Error (163, Location,
309                                                       "Control cannot fall through from one " +
310                                                       "case label to another");
311                                         return child;
312                                 }
313
314                                 locals |= child.locals;
315
316                                 if (overwrite)
317                                         is_unreachable = new_isunr;
318                                 else
319                                         is_unreachable |= new_isunr;
320
321                                 return child;
322                         }
323
324                         public void MergeOrigins (UsageVector o_vectors)
325                         {
326                                 Report.Debug (1, "  MERGING BREAK ORIGINS", this);
327
328                                 if (o_vectors == null)
329                                         return;
330
331                                 if (IsUnreachable && locals != null)
332                                         locals.SetAll (true);
333
334                                 for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) {
335                                         Report.Debug (1, "    MERGING BREAK ORIGIN", vector);
336                                         if (vector.IsUnreachable)
337                                                 continue;
338                                         locals &= vector.locals;
339                                         is_unreachable &= vector.is_unreachable;
340                                 }
341
342                                 Report.Debug (1, "  MERGING BREAK ORIGINS DONE", this);
343                         }
344
345                         //
346                         // Debugging stuff.
347                         //
348
349                         public override string ToString ()
350                         {
351                                 return String.Format ("Vector ({0},{1},{2}-{3})", Type, id, is_unreachable, locals);
352                         }
353                 }
354
355                 // <summary>
356                 //   Creates a new flow branching which is contained in `parent'.
357                 //   You should only pass non-null for the `block' argument if this block
358                 //   introduces any new variables - in this case, we need to create a new
359                 //   usage vector with a different size than our parent's one.
360                 // </summary>
361                 protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype,
362                                          Block block, Location loc)
363                 {
364                         Parent = parent;
365                         Block = block;
366                         Location = loc;
367                         Type = type;
368                         id = ++next_id;
369
370                         UsageVector vector;
371                         if (Block != null) {
372                                 UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null;
373                                 vector = new UsageVector (stype, parent_vector, Block, loc, Block.AssignableSlots);
374                         } else {
375                                 vector = new UsageVector (stype, Parent.CurrentUsageVector, null, loc);
376                         }
377
378                         AddSibling (vector);
379                 }
380
381                 public abstract UsageVector CurrentUsageVector {
382                         get;
383                 }                               
384
385                 // <summary>
386                 //   Creates a sibling of the current usage vector.
387                 // </summary>
388                 public virtual void CreateSibling (Block block, SiblingType type)
389                 {
390                         UsageVector vector = new UsageVector (
391                                 type, Parent.CurrentUsageVector, block, Location);
392                         AddSibling (vector);
393
394                         Report.Debug (1, "  CREATED SIBLING", CurrentUsageVector);
395                 }
396
397                 public void CreateSibling ()
398                 {
399                         CreateSibling (null, SiblingType.Conditional);
400                 }
401
402                 protected abstract void AddSibling (UsageVector uv);
403
404                 protected abstract UsageVector Merge ();
405
406                 public UsageVector MergeChild (FlowBranching child)
407                 {
408                         return CurrentUsageVector.MergeChild (child.Merge (), true);
409                 }
410
411                 public virtual bool CheckRethrow (Location loc)
412                 {
413                         return Parent.CheckRethrow (loc);
414                 }
415
416                 public virtual bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
417                 {
418                         return Parent.AddResumePoint (stmt, loc, out pc);
419                 }
420
421                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
422                 public virtual bool AddBreakOrigin (UsageVector vector, Location loc)
423                 {
424                         return Parent.AddBreakOrigin (vector, loc);
425                 }
426
427                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
428                 public virtual bool AddContinueOrigin (UsageVector vector, Location loc)
429                 {
430                         return Parent.AddContinueOrigin (vector, loc);
431                 }
432
433                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
434                 public virtual bool AddReturnOrigin (UsageVector vector, ExitStatement stmt)
435                 {
436                         return Parent.AddReturnOrigin (vector, stmt);
437                 }
438
439                 // returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
440                 public virtual bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
441                 {
442                         return Parent.AddGotoOrigin (vector, goto_stmt);
443                 }
444
445                 public bool IsAssigned (VariableInfo vi)
446                 {
447                         return CurrentUsageVector.IsAssigned (vi, false);
448                 }
449
450                 public bool IsFieldAssigned (VariableInfo vi, string field_name)
451                 {
452                         return CurrentUsageVector.IsAssigned (vi, false) || CurrentUsageVector.IsFieldAssigned (vi, field_name);
453                 }
454
455                 public void SetAssigned (VariableInfo vi)
456                 {
457                         CurrentUsageVector.SetAssigned (vi);
458                 }
459
460                 public void SetFieldAssigned (VariableInfo vi, string name)
461                 {
462                         CurrentUsageVector.SetFieldAssigned (vi, name);
463                 }
464
465                 public override string ToString ()
466                 {
467                         StringBuilder sb = new StringBuilder ();
468                         sb.Append (GetType ());
469                         sb.Append (" (");
470
471                         sb.Append (id);
472                         sb.Append (",");
473                         sb.Append (Type);
474                         if (Block != null) {
475                                 sb.Append (" - ");
476                                 sb.Append (Block.ID);
477                                 sb.Append (" - ");
478                                 sb.Append (Block.StartLocation);
479                         }
480                         sb.Append (" - ");
481                         // sb.Append (Siblings.Length);
482                         // sb.Append (" - ");
483                         sb.Append (CurrentUsageVector);
484                         sb.Append (")");
485                         return sb.ToString ();
486                 }
487
488                 public string Name {
489                         get { return String.Format ("{0} ({1}:{2}:{3})", GetType (), id, Type, Location); }
490                 }
491         }
492
493         public class FlowBranchingBlock : FlowBranching
494         {
495                 UsageVector sibling_list = null;
496
497                 public FlowBranchingBlock (FlowBranching parent, BranchingType type,
498                                            SiblingType stype, Block block, Location loc)
499                         : base (parent, type, stype, block, loc)
500                 { }
501
502                 public override UsageVector CurrentUsageVector {
503                         get { return sibling_list; }
504                 }
505
506                 protected override void AddSibling (UsageVector sibling)
507                 {
508                         if (sibling_list != null && sibling_list.Type == SiblingType.Block)
509                                 throw new InternalErrorException ("Blocks don't have sibling flow paths");
510                         sibling.Next = sibling_list;
511                         sibling_list = sibling;
512                 }
513
514                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
515                 {
516                         LabeledStatement stmt = Block == null ? null : Block.LookupLabel (goto_stmt.Target);
517                         if (stmt == null)
518                                 return Parent.AddGotoOrigin (vector, goto_stmt);
519
520                         // forward jump
521                         goto_stmt.SetResolvedTarget (stmt);
522                         stmt.AddUsageVector (vector);
523                         return false;
524                 }
525                 
526                 public static void Error_UnknownLabel (Location loc, string label)
527                 {
528                         Report.Error(159, loc, "The label `{0}:' could not be found within the scope of the goto statement",
529                                 label);
530                 }
531
532                 protected override UsageVector Merge ()
533                 {
534                         Report.Debug (2, "  MERGING SIBLINGS", Name);
535                         UsageVector vector = UsageVector.MergeSiblings (sibling_list, Location);
536                         Report.Debug (2, "  MERGING SIBLINGS DONE", Name, vector);
537                         return vector;
538                 }
539         }
540
541         public class FlowBranchingBreakable : FlowBranchingBlock
542         {
543                 UsageVector break_origins;
544
545                 public FlowBranchingBreakable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
546                         : base (parent, type, stype, block, loc)
547                 { }
548
549                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
550                 {
551                         vector = vector.Clone ();
552                         vector.Next = break_origins;
553                         break_origins = vector;
554                         return false;
555                 }
556
557                 protected override UsageVector Merge ()
558                 {
559                         UsageVector vector = base.Merge ();
560                         vector.MergeOrigins (break_origins);
561                         return vector;
562                 }
563         }
564
565         public class FlowBranchingContinuable : FlowBranchingBlock
566         {
567                 UsageVector continue_origins;
568
569                 public FlowBranchingContinuable (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc)
570                         : base (parent, type, stype, block, loc)
571                 { }
572
573                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
574                 {
575                         vector = vector.Clone ();
576                         vector.Next = continue_origins;
577                         continue_origins = vector;
578                         return false;
579                 }
580
581                 protected override UsageVector Merge ()
582                 {
583                         UsageVector vector = base.Merge ();
584                         vector.MergeOrigins (continue_origins);
585                         return vector;
586                 }
587         }
588
589         public class FlowBranchingLabeled : FlowBranchingBlock
590         {
591                 LabeledStatement stmt;
592                 UsageVector actual;
593
594                 public FlowBranchingLabeled (FlowBranching parent, LabeledStatement stmt)
595                         : base (parent, BranchingType.Labeled, SiblingType.Conditional, null, stmt.loc)
596                 {
597                         this.stmt = stmt;
598                         CurrentUsageVector.MergeOrigins (stmt.JumpOrigins);
599                         actual = CurrentUsageVector.Clone ();
600
601                         // stand-in for backward jumps
602                         CurrentUsageVector.ResetBarrier ();
603                 }
604
605                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
606                 {
607                         if (goto_stmt.Target != stmt.Name)
608                                 return Parent.AddGotoOrigin (vector, goto_stmt);
609
610                         // backward jump
611                         goto_stmt.SetResolvedTarget (stmt);
612                         actual.MergeOrigins (vector.Clone ());
613
614                         return false;
615                 }
616
617                 protected override UsageVector Merge ()
618                 {
619                         UsageVector vector = base.Merge ();
620
621                         if (actual.IsUnreachable)
622                                 Report.Warning (162, 2, stmt.loc, "Unreachable code detected");
623
624                         actual.MergeChild (vector, false);
625                         return actual;
626                 }
627         }
628
629         public class FlowBranchingIterator : FlowBranchingBlock
630         {
631                 Iterator iterator;
632                 public FlowBranchingIterator (FlowBranching parent, Iterator iterator)
633                         : base (parent, BranchingType.Iterator, SiblingType.Block, null, iterator.Location)
634                 {
635                         this.iterator = iterator;
636                 }
637
638                 public override bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
639                 {
640                         pc = iterator.AddResumePoint (stmt, loc);
641                         return false;
642                 }
643         }
644
645         public class FlowBranchingToplevel : FlowBranchingBlock
646         {
647                 UsageVector return_origins;
648
649                 public FlowBranchingToplevel (FlowBranching parent, ToplevelBlock stmt)
650                         : base (parent, BranchingType.Toplevel, SiblingType.Conditional, stmt, stmt.loc)
651                 {
652                 }
653
654                 public override bool CheckRethrow (Location loc)
655                 {
656                         Report.Error (156, loc, "A throw statement with no arguments is not allowed outside of a catch clause");
657                         return false;
658                 }
659
660                 public override bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
661                 {
662                         pc = -1;
663                         Report.Error (-6, loc, "Internal Error: A yield in a non-iterator");
664                         return false;
665                 }
666
667                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
668                 {
669                         Report.Error (139, loc, "No enclosing loop out of which to break or continue");
670                         return false;
671                 }
672
673                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
674                 {
675                         Report.Error (139, loc, "No enclosing loop out of which to break or continue");
676                         return false;
677                 }
678
679                 public override bool AddReturnOrigin (UsageVector vector, ExitStatement stmt)
680                 {
681                         vector = vector.Clone ();
682                         vector.Location = stmt.loc;
683                         vector.Next = return_origins;
684                         return_origins = vector;
685                         return false;
686                 }
687
688                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
689                 {
690                         string name = goto_stmt.Target;
691                         LabeledStatement s = Block.LookupLabel (name);
692                         if (s != null)
693                                 throw new InternalErrorException ("Shouldn't get here");
694
695                         if (Parent == null) {
696                                 Error_UnknownLabel (goto_stmt.loc, name);
697                                 return false;
698                         }
699
700                         int errors = Report.Errors;
701                         Parent.AddGotoOrigin (vector, goto_stmt);
702                         if (errors == Report.Errors)
703                                 Report.Error (1632, goto_stmt.loc, "Control cannot leave the body of an anonymous method");
704                         return false;
705                 }
706
707                 protected override UsageVector Merge ()
708                 {
709                         for (UsageVector origin = return_origins; origin != null; origin = origin.Next)
710                                 Block.Toplevel.CheckOutParameters (origin, origin.Location);
711
712                         UsageVector vector = base.Merge ();
713                         Block.Toplevel.CheckOutParameters (vector, Block.loc);
714                         // Note: we _do_not_ merge in the return origins
715                         return vector;
716                 }
717
718                 public bool End ()
719                 {
720                         return Merge ().IsUnreachable;
721                 }
722         }
723
724         public class FlowBranchingTryCatch : FlowBranchingBlock
725         {
726                 TryCatch stmt;
727                 public FlowBranchingTryCatch (FlowBranching parent, TryCatch stmt)
728                         : base (parent, BranchingType.Block, SiblingType.Try, null, stmt.loc)
729                 {
730                         this.stmt = stmt;
731                 }
732
733                 public override bool CheckRethrow (Location loc)
734                 {
735                         return CurrentUsageVector.Next != null || Parent.CheckRethrow (loc);
736                 }
737
738                 public override bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
739                 {
740                         int errors = Report.Errors;
741                         Parent.AddResumePoint (stmt, loc, out pc);
742                         if (errors == Report.Errors) {
743                                 if (CurrentUsageVector.Next == null)
744                                         Report.Error (1626, loc, "Cannot yield a value in the body of a try block with a catch clause");
745                                 else
746                                         Report.Error (1631, loc, "Cannot yield a value in the body of a catch clause");
747                         }
748                         return true;
749                 }
750
751                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
752                 {
753                         Parent.AddBreakOrigin (vector, loc);
754                         stmt.SomeCodeFollows ();
755                         return true;
756                 }
757
758                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
759                 {
760                         Parent.AddContinueOrigin (vector, loc);
761                         stmt.SomeCodeFollows ();
762                         return true;
763                 }
764
765                 public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
766                 {
767                         Parent.AddReturnOrigin (vector, exit_stmt);
768                         stmt.SomeCodeFollows ();
769                         return true;
770                 }
771
772                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
773                 {
774                         Parent.AddGotoOrigin (vector, goto_stmt);
775                         return true;
776                 }
777         }
778
779         public class FlowBranchingException : FlowBranching
780         {
781                 ExceptionStatement stmt;
782                 UsageVector current_vector;
783                 UsageVector try_vector;
784                 UsageVector finally_vector;
785
786                 abstract class SavedOrigin {
787                         public SavedOrigin Next;
788                         public UsageVector Vector;
789
790                         public SavedOrigin (SavedOrigin next, UsageVector vector)
791                         {
792                                 Next = next;
793                                 Vector = vector.Clone ();
794                         }
795
796                         protected abstract void DoPropagateFinally (FlowBranching parent);
797                         public void PropagateFinally (UsageVector finally_vector, FlowBranching parent)
798                         {
799                                 if (finally_vector != null)
800                                         Vector.MergeChild (finally_vector, false);
801                                 DoPropagateFinally (parent);
802                         }
803                 }
804
805                 class BreakOrigin : SavedOrigin {
806                         Location Loc;
807                         public BreakOrigin (SavedOrigin next, UsageVector vector, Location loc)
808                                 : base (next, vector)
809                         {
810                                 Loc = loc;
811                         }
812
813                         protected override void DoPropagateFinally (FlowBranching parent)
814                         {
815                                 parent.AddBreakOrigin (Vector, Loc);
816                         }
817                 }
818
819                 class ContinueOrigin : SavedOrigin {
820                         Location Loc;
821                         public ContinueOrigin (SavedOrigin next, UsageVector vector, Location loc)
822                                 : base (next, vector)
823                         {
824                                 Loc = loc;
825                         }
826
827                         protected override void DoPropagateFinally (FlowBranching parent)
828                         {
829                                 parent.AddContinueOrigin (Vector, Loc);
830                         }
831                 }
832
833                 class ReturnOrigin : SavedOrigin {
834                         public ExitStatement Stmt;
835
836                         public ReturnOrigin (SavedOrigin next, UsageVector vector, ExitStatement stmt)
837                                 : base (next, vector)
838                         {
839                                 Stmt = stmt;
840                         }
841
842                         protected override void DoPropagateFinally (FlowBranching parent)
843                         {
844                                 parent.AddReturnOrigin (Vector, Stmt);
845                         }
846                 }
847
848                 class GotoOrigin : SavedOrigin {
849                         public Goto Stmt;
850
851                         public GotoOrigin (SavedOrigin next, UsageVector vector, Goto stmt)
852                                 : base (next, vector)
853                         {
854                                 Stmt = stmt;
855                         }
856
857                         protected override void DoPropagateFinally (FlowBranching parent)
858                         {
859                                 parent.AddGotoOrigin (Vector, Stmt);
860                         }
861                 }
862
863                 SavedOrigin saved_origins;
864
865                 public FlowBranchingException (FlowBranching parent,
866                                                ExceptionStatement stmt)
867                         : base (parent, BranchingType.Exception, SiblingType.Try,
868                                 null, stmt.loc)
869                 {
870                         this.stmt = stmt;
871                 }
872
873                 protected override void AddSibling (UsageVector sibling)
874                 {
875                         switch (sibling.Type) {
876                         case SiblingType.Try:
877                                 try_vector = sibling;
878                                 break;
879                         case SiblingType.Finally:
880                                 finally_vector = sibling;
881                                 break;
882                         default:
883                                 throw new InvalidOperationException ();
884                         }
885                         current_vector = sibling;
886                 }
887
888                 public override UsageVector CurrentUsageVector {
889                         get { return current_vector; }
890                 }
891
892                 public override bool CheckRethrow (Location loc)
893                 {
894                         if (!Parent.CheckRethrow (loc))
895                                 return false;
896                         if (finally_vector == null)
897                                 return true;
898                         Report.Error (724, loc, "A throw statement with no arguments is not allowed inside of a finally clause nested inside of the innermost catch clause");
899                         return false;
900                 }
901
902                 public override bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
903                 {
904                         int errors = Report.Errors;
905                         Parent.AddResumePoint (this.stmt, loc, out pc);
906                         if (errors == Report.Errors) {
907                                 if (finally_vector == null)
908                                         this.stmt.AddResumePoint (stmt, loc, pc);
909                                 else
910                                         Report.Error (1625, loc, "Cannot yield in the body of a finally clause");
911                         }
912                         return true;
913                 }
914
915                 public override bool AddBreakOrigin (UsageVector vector, Location loc)
916                 {
917                         if (finally_vector != null) {
918                                 int errors = Report.Errors;
919                                 Parent.AddBreakOrigin (vector, loc);
920                                 if (errors == Report.Errors)
921                                         Report.Error (157, loc, "Control cannot leave the body of a finally clause");
922                         } else {
923                                 saved_origins = new BreakOrigin (saved_origins, vector, loc);
924                         }
925
926                         // either the loop test or a back jump will follow code
927                         stmt.SomeCodeFollows ();
928                         return true;
929                 }
930
931                 public override bool AddContinueOrigin (UsageVector vector, Location loc)
932                 {
933                         if (finally_vector != null) {
934                                 int errors = Report.Errors;
935                                 Parent.AddContinueOrigin (vector, loc);
936                                 if (errors == Report.Errors)
937                                         Report.Error (157, loc, "Control cannot leave the body of a finally clause");
938                         } else {
939                                 saved_origins = new ContinueOrigin (saved_origins, vector, loc);
940                         }
941
942                         // either the loop test or a back jump will follow code
943                         stmt.SomeCodeFollows ();
944                         return true;
945                 }
946
947                 public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
948                 {
949                         if (finally_vector != null) {
950                                 int errors = Report.Errors;
951                                 Parent.AddReturnOrigin (vector, exit_stmt);
952                                 if (errors == Report.Errors)
953                                         exit_stmt.Error_FinallyClause ();
954                         } else {
955                                 saved_origins = new ReturnOrigin (saved_origins, vector, exit_stmt);
956                         }
957
958                         // sets ec.NeedReturnLabel()
959                         stmt.SomeCodeFollows ();
960                         return true;
961                 }
962
963                 public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
964                 {
965                         LabeledStatement s = current_vector.Block == null ? null : current_vector.Block.LookupLabel (goto_stmt.Target);
966                         if (s != null)
967                                 throw new InternalErrorException ("Shouldn't get here");
968
969                         if (finally_vector != null) {
970                                 int errors = Report.Errors;
971                                 Parent.AddGotoOrigin (vector, goto_stmt);
972                                 if (errors == Report.Errors)
973                                         Report.Error (157, goto_stmt.loc, "Control cannot leave the body of a finally clause");
974                         } else {
975                                 saved_origins = new GotoOrigin (saved_origins, vector, goto_stmt);
976                         }
977                         return true;
978                 }
979
980                 protected override UsageVector Merge ()
981                 {
982                         UsageVector vector = try_vector.Clone ();
983
984                         if (finally_vector != null)
985                                 vector.MergeChild (finally_vector, false);
986
987                         for (SavedOrigin origin = saved_origins; origin != null; origin = origin.Next)
988                                 origin.PropagateFinally (finally_vector, Parent);
989
990                         return vector;
991                 }
992         }
993
994         // <summary>
995         //   This is used by the flow analysis code to keep track of the type of local variables
996         //   and variables.
997         //
998         //   The flow code uses a BitVector to keep track of whether a variable has been assigned
999         //   or not.  This is easy for fundamental types (int, char etc.) or reference types since
1000         //   you can only assign the whole variable as such.
1001         //
1002         //   For structs, we also need to keep track of all its fields.  To do this, we allocate one
1003         //   bit for the struct itself (it's used if you assign/access the whole struct) followed by
1004         //   one bit for each of its fields.
1005         //
1006         //   This class computes this `layout' for each type.
1007         // </summary>
1008         public class TypeInfo
1009         {
1010                 public readonly Type Type;
1011
1012                 // <summary>
1013                 //   Total number of bits a variable of this type consumes in the flow vector.
1014                 // </summary>
1015                 public readonly int TotalLength;
1016
1017                 // <summary>
1018                 //   Number of bits the simple fields of a variable of this type consume
1019                 //   in the flow vector.
1020                 // </summary>
1021                 public readonly int Length;
1022
1023                 // <summary>
1024                 //   This is only used by sub-structs.
1025                 // </summary>
1026                 public readonly int Offset;
1027
1028                 // <summary>
1029                 //   If this is a struct.
1030                 // </summary>
1031                 public readonly bool IsStruct;       
1032
1033                 // <summary>
1034                 //   If this is a struct, all fields which are structs theirselves.
1035                 // </summary>
1036                 public TypeInfo[] SubStructInfo;
1037
1038                 protected readonly StructInfo struct_info;
1039                 private static Hashtable type_hash = new Hashtable ();
1040
1041                 public static TypeInfo GetTypeInfo (Type type)
1042                 {
1043                         TypeInfo info = (TypeInfo) type_hash [type];
1044                         if (info != null)
1045                                 return info;
1046
1047                         info = new TypeInfo (type);
1048                         type_hash.Add (type, info);
1049                         return info;
1050                 }
1051
1052                 public static TypeInfo GetTypeInfo (TypeContainer tc)
1053                 {
1054                         TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
1055                         if (info != null)
1056                                 return info;
1057
1058                         info = new TypeInfo (tc);
1059                         type_hash.Add (tc.TypeBuilder, info);
1060                         return info;
1061                 }
1062
1063                 private TypeInfo (Type type)
1064                 {
1065                         this.Type = type;
1066
1067                         struct_info = StructInfo.GetStructInfo (type);
1068                         if (struct_info != null) {
1069                                 Length = struct_info.Length;
1070                                 TotalLength = struct_info.TotalLength;
1071                                 SubStructInfo = struct_info.StructFields;
1072                                 IsStruct = true;
1073                         } else {
1074                                 Length = 0;
1075                                 TotalLength = 1;
1076                                 IsStruct = false;
1077                         }
1078                 }
1079
1080                 private TypeInfo (TypeContainer tc)
1081                 {
1082                         this.Type = tc.TypeBuilder;
1083
1084                         struct_info = StructInfo.GetStructInfo (tc);
1085                         if (struct_info != null) {
1086                                 Length = struct_info.Length;
1087                                 TotalLength = struct_info.TotalLength;
1088                                 SubStructInfo = struct_info.StructFields;
1089                                 IsStruct = true;
1090                         } else {
1091                                 Length = 0;
1092                                 TotalLength = 1;
1093                                 IsStruct = false;
1094                         }
1095                 }
1096
1097                 protected TypeInfo (StructInfo struct_info, int offset)
1098                 {
1099                         this.struct_info = struct_info;
1100                         this.Offset = offset;
1101                         this.Length = struct_info.Length;
1102                         this.TotalLength = struct_info.TotalLength;
1103                         this.SubStructInfo = struct_info.StructFields;
1104                         this.Type = struct_info.Type;
1105                         this.IsStruct = true;
1106                 }
1107
1108                 public int GetFieldIndex (string name)
1109                 {
1110                         if (struct_info == null)
1111                                 return 0;
1112
1113                         return struct_info [name];
1114                 }
1115
1116                 public TypeInfo GetSubStruct (string name)
1117                 {
1118                         if (struct_info == null)
1119                                 return null;
1120
1121                         return struct_info.GetStructField (name);
1122                 }
1123
1124                 // <summary>
1125                 //   A struct's constructor must always assign all fields.
1126                 //   This method checks whether it actually does so.
1127                 // </summary>
1128                 public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
1129                 {
1130                         if (struct_info == null)
1131                                 return true;
1132
1133                         bool ok = true;
1134                         for (int i = 0; i < struct_info.Count; i++) {
1135                                 FieldInfo field = struct_info.Fields [i];
1136
1137                                 if (!branching.IsFieldAssigned (vi, field.Name)) {
1138                                         Report.Error (171, loc,
1139                                                 "Field `{0}' must be fully assigned before control leaves the constructor",
1140                                                 TypeManager.GetFullNameSignature (field));
1141                                         ok = false;
1142                                 }
1143                         }
1144
1145                         return ok;
1146                 }
1147
1148                 public override string ToString ()
1149                 {
1150                         return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
1151                                               Type, Offset, Length, TotalLength);
1152                 }
1153
1154                 protected class StructInfo {
1155                         public readonly Type Type;
1156                         public readonly FieldInfo[] Fields;
1157                         public readonly TypeInfo[] StructFields;
1158                         public readonly int Count;
1159                         public readonly int CountPublic;
1160                         public readonly int CountNonPublic;
1161                         public readonly int Length;
1162                         public readonly int TotalLength;
1163                         public readonly bool HasStructFields;
1164
1165                         private static Hashtable field_type_hash = new Hashtable ();
1166                         private Hashtable struct_field_hash;
1167                         private Hashtable field_hash;
1168
1169                         protected bool InTransit = false;
1170
1171                         // Private constructor.  To save memory usage, we only need to create one instance
1172                         // of this class per struct type.
1173                         private StructInfo (Type type)
1174                         {
1175                                 this.Type = type;
1176
1177                                 field_type_hash.Add (type, this);
1178
1179                                 if (type is TypeBuilder) {
1180                                         TypeContainer tc = TypeManager.LookupTypeContainer (type);
1181
1182                                         ArrayList fields = null;
1183                                         if (tc != null)
1184                                                 fields = tc.Fields;
1185
1186                                         ArrayList public_fields = new ArrayList ();
1187                                         ArrayList non_public_fields = new ArrayList ();
1188
1189                                         if (fields != null) {
1190                                                 foreach (FieldBase field in fields) {
1191                                                         if ((field.ModFlags & Modifiers.STATIC) != 0)
1192                                                                 continue;
1193                                                         if ((field.ModFlags & Modifiers.PUBLIC) != 0)
1194                                                                 public_fields.Add (field.FieldBuilder);
1195                                                         else
1196                                                                 non_public_fields.Add (field.FieldBuilder);
1197                                                 }
1198                                         }
1199
1200                                         CountPublic = public_fields.Count;
1201                                         CountNonPublic = non_public_fields.Count;
1202                                         Count = CountPublic + CountNonPublic;
1203
1204                                         Fields = new FieldInfo [Count];
1205                                         public_fields.CopyTo (Fields, 0);
1206                                         non_public_fields.CopyTo (Fields, CountPublic);
1207 #if GMCS_SOURCE
1208                                 } else if (type is GenericTypeParameterBuilder) {
1209                                         CountPublic = CountNonPublic = Count = 0;
1210
1211                                         Fields = new FieldInfo [0];
1212 #endif
1213                                 } else {
1214                                         FieldInfo[] public_fields = type.GetFields (
1215                                                 BindingFlags.Instance|BindingFlags.Public);
1216                                         FieldInfo[] non_public_fields = type.GetFields (
1217                                                 BindingFlags.Instance|BindingFlags.NonPublic);
1218
1219                                         CountPublic = public_fields.Length;
1220                                         CountNonPublic = non_public_fields.Length;
1221                                         Count = CountPublic + CountNonPublic;
1222
1223                                         Fields = new FieldInfo [Count];
1224                                         public_fields.CopyTo (Fields, 0);
1225                                         non_public_fields.CopyTo (Fields, CountPublic);
1226                                 }
1227
1228                                 struct_field_hash = new Hashtable ();
1229                                 field_hash = new Hashtable ();
1230
1231                                 Length = 0;
1232                                 StructFields = new TypeInfo [Count];
1233                                 StructInfo[] sinfo = new StructInfo [Count];
1234
1235                                 InTransit = true;
1236
1237                                 for (int i = 0; i < Count; i++) {
1238                                         FieldInfo field = (FieldInfo) Fields [i];
1239
1240                                         sinfo [i] = GetStructInfo (field.FieldType);
1241                                         if (sinfo [i] == null)
1242                                                 field_hash.Add (field.Name, ++Length);
1243                                         else if (sinfo [i].InTransit) {
1244                                                 Report.Error (523, String.Format (
1245                                                                       "Struct member `{0}.{1}' of type `{2}' causes " +
1246                                                                       "a cycle in the structure layout",
1247                                                                       type, field.Name, sinfo [i].Type));
1248                                                 sinfo [i] = null;
1249                                                 return;
1250                                         }
1251                                 }
1252
1253                                 InTransit = false;
1254
1255                                 TotalLength = Length + 1;
1256                                 for (int i = 0; i < Count; i++) {
1257                                         FieldInfo field = (FieldInfo) Fields [i];
1258
1259                                         if (sinfo [i] == null)
1260                                                 continue;
1261
1262                                         field_hash.Add (field.Name, TotalLength);
1263
1264                                         HasStructFields = true;
1265                                         StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
1266                                         struct_field_hash.Add (field.Name, StructFields [i]);
1267                                         TotalLength += sinfo [i].TotalLength;
1268                                 }
1269                         }
1270
1271                         public int this [string name] {
1272                                 get {
1273                                         if (field_hash.Contains (name))
1274                                                 return (int) field_hash [name];
1275                                         else
1276                                                 return 0;
1277                                 }
1278                         }
1279
1280                         public TypeInfo GetStructField (string name)
1281                         {
1282                                 return (TypeInfo) struct_field_hash [name];
1283                         }
1284
1285                         public static StructInfo GetStructInfo (Type type)
1286                         {
1287                                 if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
1288                                     TypeManager.IsBuiltinType (type))
1289                                         return null;
1290
1291                                 StructInfo info = (StructInfo) field_type_hash [type];
1292                                 if (info != null)
1293                                         return info;
1294
1295                                 return new StructInfo (type);
1296                         }
1297
1298                         public static StructInfo GetStructInfo (TypeContainer tc)
1299                         {
1300                                 StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
1301                                 if (info != null)
1302                                         return info;
1303
1304                                 return new StructInfo (tc.TypeBuilder);
1305                         }
1306                 }
1307         }
1308
1309         // <summary>
1310         //   This is used by the flow analysis code to store information about a single local variable
1311         //   or parameter.  Depending on the variable's type, we need to allocate one or more elements
1312         //   in the BitVector - if it's a fundamental or reference type, we just need to know whether
1313         //   it has been assigned or not, but for structs, we need this information for each of its fields.
1314         // </summary>
1315         public class VariableInfo {
1316                 public readonly string Name;
1317                 public readonly TypeInfo TypeInfo;
1318
1319                 // <summary>
1320                 //   The bit offset of this variable in the flow vector.
1321                 // </summary>
1322                 public readonly int Offset;
1323
1324                 // <summary>
1325                 //   The number of bits this variable needs in the flow vector.
1326                 //   The first bit always specifies whether the variable as such has been assigned while
1327                 //   the remaining bits contain this information for each of a struct's fields.
1328                 // </summary>
1329                 public readonly int Length;
1330
1331                 // <summary>
1332                 //   If this is a parameter of local variable.
1333                 // </summary>
1334                 public readonly bool IsParameter;
1335
1336                 public readonly LocalInfo LocalInfo;
1337
1338                 readonly VariableInfo Parent;
1339                 VariableInfo[] sub_info;
1340
1341                 bool is_ever_assigned;
1342                 public bool IsEverAssigned {
1343                         get { return is_ever_assigned; }
1344                 }
1345
1346                 protected VariableInfo (string name, Type type, int offset)
1347                 {
1348                         this.Name = name;
1349                         this.Offset = offset;
1350                         this.TypeInfo = TypeInfo.GetTypeInfo (type);
1351
1352                         Length = TypeInfo.TotalLength;
1353
1354                         Initialize ();
1355                 }
1356
1357                 protected VariableInfo (VariableInfo parent, TypeInfo type)
1358                 {
1359                         this.Name = parent.Name;
1360                         this.TypeInfo = type;
1361                         this.Offset = parent.Offset + type.Offset;
1362                         this.Parent = parent;
1363                         this.Length = type.TotalLength;
1364
1365                         this.IsParameter = parent.IsParameter;
1366                         this.LocalInfo = parent.LocalInfo;
1367
1368                         Initialize ();
1369                 }
1370
1371                 protected void Initialize ()
1372                 {
1373                         TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
1374                         if (sub_fields != null) {
1375                                 sub_info = new VariableInfo [sub_fields.Length];
1376                                 for (int i = 0; i < sub_fields.Length; i++) {
1377                                         if (sub_fields [i] != null)
1378                                                 sub_info [i] = new VariableInfo (this, sub_fields [i]);
1379                                 }
1380                         } else
1381                                 sub_info = new VariableInfo [0];
1382                 }
1383
1384                 public VariableInfo (LocalInfo local_info, int offset)
1385                         : this (local_info.Name, local_info.VariableType, offset)
1386                 {
1387                         this.LocalInfo = local_info;
1388                         this.IsParameter = false;
1389                 }
1390
1391                 public VariableInfo (Parameters ip, int i, int offset)
1392                         : this (ip.ParameterName (i), TypeManager.GetElementType (ip.ParameterType (i)), offset)
1393                 {
1394                         this.IsParameter = true;
1395                 }
1396
1397                 public bool IsAssigned (EmitContext ec)
1398                 {
1399                         return !ec.DoFlowAnalysis ||
1400                                 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1401                                 ec.CurrentBranching.IsAssigned (this);
1402                 }
1403
1404                 public bool IsAssigned (EmitContext ec, Location loc)
1405                 {
1406                         if (IsAssigned (ec))
1407                                 return true;
1408
1409                         Report.Error (165, loc,
1410                                       "Use of unassigned local variable `" + Name + "'");
1411                         ec.CurrentBranching.SetAssigned (this);
1412                         return false;
1413                 }
1414
1415                 public bool IsAssigned (MyBitVector vector)
1416                 {
1417                         if (vector == null)
1418                                 return true;
1419
1420                         if (vector [Offset])
1421                                 return true;
1422
1423                         // FIXME: Fix SetFieldAssigned to set the whole range like SetAssigned below. Then, get rid of this stanza
1424                         for (VariableInfo parent = Parent; parent != null; parent = parent.Parent) {
1425                                 if (vector [parent.Offset]) {
1426                                         // 'parent' is assigned, but someone forgot to note that all its components are assigned too
1427                                         parent.SetAssigned (vector);
1428                                         return true;
1429                                 }
1430                         }
1431
1432                         // Return unless this is a struct.
1433                         if (!TypeInfo.IsStruct)
1434                                 return false;
1435
1436                         // Ok, so each field must be assigned.
1437                         for (int i = 0; i < TypeInfo.Length; i++) {
1438                                 if (!vector [Offset + i + 1])
1439                                         return false;
1440                         }
1441
1442                         // Ok, now check all fields which are structs.
1443                         for (int i = 0; i < sub_info.Length; i++) {
1444                                 VariableInfo sinfo = sub_info [i];
1445                                 if (sinfo == null)
1446                                         continue;
1447
1448                                 if (!sinfo.IsAssigned (vector))
1449                                         return false;
1450                         }
1451
1452                         vector [Offset] = true;
1453                         is_ever_assigned = true;
1454                         return true;
1455                 }
1456
1457                 public void SetAssigned (EmitContext ec)
1458                 {
1459                         if (ec.DoFlowAnalysis)
1460                                 ec.CurrentBranching.SetAssigned (this);
1461                 }
1462
1463                 public void SetAssigned (MyBitVector vector)
1464                 {
1465                         if (Length == 1)
1466                                 vector [Offset] = true;
1467                         else
1468                                 vector.SetRange (Offset, Length);
1469                         is_ever_assigned = true;
1470                 }
1471
1472                 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
1473                 {
1474                         if (!ec.DoFlowAnalysis ||
1475                                 ec.OmitStructFlowAnalysis && TypeInfo.IsStruct ||
1476                                 ec.CurrentBranching.IsFieldAssigned (this, name))
1477                                 return true;
1478
1479                         Report.Error (170, loc,
1480                                       "Use of possibly unassigned field `" + name + "'");
1481                         ec.CurrentBranching.SetFieldAssigned (this, name);
1482                         return false;
1483                 }
1484
1485                 public bool IsFieldAssigned (MyBitVector vector, string field_name)
1486                 {
1487                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1488
1489                         if (field_idx == 0)
1490                                 return true;
1491
1492                         return vector [Offset + field_idx];
1493                 }
1494
1495                 public void SetFieldAssigned (EmitContext ec, string name)
1496                 {
1497                         if (ec.DoFlowAnalysis)
1498                                 ec.CurrentBranching.SetFieldAssigned (this, name);
1499                 }
1500
1501                 public void SetFieldAssigned (MyBitVector vector, string field_name)
1502                 {
1503                         int field_idx = TypeInfo.GetFieldIndex (field_name);
1504
1505                         if (field_idx == 0)
1506                                 return;
1507
1508                         vector [Offset + field_idx] = true;
1509                         is_ever_assigned = true;
1510                 }
1511
1512                 public VariableInfo GetSubStruct (string name)
1513                 {
1514                         TypeInfo type = TypeInfo.GetSubStruct (name);
1515
1516                         if (type == null)
1517                                 return null;
1518
1519                         return new VariableInfo (this, type);
1520                 }
1521
1522                 public override string ToString ()
1523                 {
1524                         return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
1525                                               Name, TypeInfo, Offset, Length, IsParameter);
1526                 }
1527         }
1528
1529         // <summary>
1530         //   This is a special bit vector which can inherit from another bit vector doing a
1531         //   copy-on-write strategy.  The inherited vector may have a smaller size than the
1532         //   current one.
1533         // </summary>
1534         public class MyBitVector {
1535                 public readonly int Count;
1536                 public static readonly MyBitVector Empty = new MyBitVector ();
1537
1538                 // Invariant: vector != null => vector.Count == Count
1539                 // Invariant: vector == null || shared == null
1540                 //            i.e., at most one of 'vector' and 'shared' can be non-null.  They can both be null -- that means all-ones
1541                 // The object in 'shared' cannot be modified, while 'vector' can be freely modified
1542                 BitArray vector, shared;
1543
1544                 MyBitVector ()
1545                 {
1546                         shared = new BitArray (0, false);
1547                 }
1548
1549                 public MyBitVector (MyBitVector InheritsFrom, int Count)
1550                 {
1551                         if (InheritsFrom != null)
1552                                 shared = InheritsFrom.Shared;
1553
1554                         this.Count = Count;
1555                 }
1556
1557                 // Use this accessor to get a shareable copy of the underlying BitArray representation
1558                 BitArray Shared {
1559                         get {
1560                                 // Post-condition: vector == null
1561                                 if (shared == null) {
1562                                         shared = vector;
1563                                         vector = null;
1564                                 }
1565                                 return shared;
1566                         }
1567                 }
1568
1569                 // <summary>
1570                 //   Get/set bit `index' in the bit vector.
1571                 // </summary>
1572                 public bool this [int index] {
1573                         get {
1574                                 if (index >= Count)
1575                                         throw new ArgumentOutOfRangeException ();
1576
1577                                 if (vector != null)
1578                                         return vector [index];
1579                                 if (shared == null)
1580                                         return true;
1581                                 if (index < shared.Count)
1582                                         return shared [index];
1583                                 return false;
1584                         }
1585
1586                         set {
1587                                 // Only copy the vector if we're actually modifying it.
1588                                 if (this [index] != value) {
1589                                         if (vector == null)
1590                                                 initialize_vector ();
1591                                         vector [index] = value;
1592                                 }
1593                         }
1594                 }
1595
1596                 // <summary>
1597                 //   Performs an `or' operation on the bit vector.  The `new_vector' may have a
1598                 //   different size than the current one.
1599                 // </summary>
1600                 private MyBitVector Or (MyBitVector new_vector)
1601                 {
1602                         if (Count == 0 || new_vector.Count == 0)
1603                                 return this;
1604
1605                         BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1606
1607                         if (o == null) {
1608                                 int n = new_vector.Count;
1609                                 if (n < Count) {
1610                                         for (int i = 0; i < n; ++i)
1611                                                 this [i] = true;
1612                                 } else {
1613                                         SetAll (true);
1614                                 }
1615                                 return this;
1616                         }
1617
1618                         if (Count == o.Count) {
1619                                 if (vector == null) {
1620                                         if (shared == null)
1621                                                 return this;
1622                                         initialize_vector ();
1623                                 }
1624                                 vector.Or (o);
1625                                 return this;
1626                         }
1627
1628                         int min = o.Count;
1629                         if (Count < min)
1630                                 min = Count;
1631
1632                         for (int i = 0; i < min; i++) {
1633                                 if (o [i])
1634                                         this [i] = true;
1635                         }
1636
1637                         return this;
1638                 }
1639
1640                 // <summary>
1641                 //   Performs an `and' operation on the bit vector.  The `new_vector' may have
1642                 //   a different size than the current one.
1643                 // </summary>
1644                 private MyBitVector And (MyBitVector new_vector)
1645                 {
1646                         if (Count == 0)
1647                                 return this;
1648
1649                         BitArray o = new_vector.vector != null ? new_vector.vector : new_vector.shared;
1650
1651                         if (o == null) {
1652                                 for (int i = new_vector.Count; i < Count; ++i)
1653                                         this [i] = false;
1654                                 return this;
1655                         }
1656
1657                         if (o.Count == 0) {
1658                                 SetAll (false);
1659                                 return this;
1660                         }
1661
1662                         if (Count == o.Count) {
1663                                 if (vector == null) {
1664                                         if (shared == null) {
1665                                                 shared = new_vector.Shared;
1666                                                 return this;
1667                                         }
1668                                         initialize_vector ();
1669                                 }
1670                                 vector.And (o);
1671                                 return this;
1672                         }
1673
1674                         int min = o.Count;
1675                         if (Count < min)
1676                                 min = Count;
1677
1678                         for (int i = 0; i < min; i++) {
1679                                 if (! o [i])
1680                                         this [i] = false;
1681                         }
1682
1683                         for (int i = min; i < Count; i++)
1684                                 this [i] = false;
1685
1686                         return this;
1687                 }
1688
1689                 public static MyBitVector operator & (MyBitVector a, MyBitVector b)
1690                 {
1691                         if (a == b)
1692                                 return a;
1693                         if (a == null)
1694                                 return b.Clone ();
1695                         if (b == null)
1696                                 return a.Clone ();
1697                         if (a.Count > b.Count)
1698                                 return a.Clone ().And (b);
1699                         else
1700                                 return b.Clone ().And (a);                                      
1701                 }
1702
1703                 public static MyBitVector operator | (MyBitVector a, MyBitVector b)
1704                 {
1705                         if (a == b)
1706                                 return a;
1707                         if (a == null)
1708                                 return new MyBitVector (null, b.Count);
1709                         if (b == null)
1710                                 return new MyBitVector (null, a.Count);
1711                         if (a.Count > b.Count)
1712                                 return a.Clone ().Or (b);
1713                         else
1714                                 return b.Clone ().Or (a);
1715                 }
1716
1717                 public MyBitVector Clone ()
1718                 {
1719                         return Count == 0 ? Empty : new MyBitVector (this, Count);
1720                 }
1721
1722                 public void SetRange (int offset, int length)
1723                 {
1724                         if (offset > Count || offset + length > Count)
1725                                 throw new ArgumentOutOfRangeException ();
1726
1727                         if (shared == null && vector == null)
1728                                 return;
1729
1730                         int i = 0;
1731                         if (shared != null) {
1732                                 if (offset + length <= shared.Count) {
1733                                         for (; i < length; ++i)
1734                                                 if (!shared [i+offset])
1735                                                     break;
1736                                         if (i == length)
1737                                                 return;
1738                                 }
1739                                 initialize_vector ();
1740                         }
1741                         for (; i < length; ++i)
1742                                 vector [i+offset] = true;
1743
1744                 }
1745
1746                 public void SetAll (bool value)
1747                 {
1748                         // Don't clobber Empty
1749                         if (Count == 0)
1750                                 return;
1751                         shared = value ? null : Empty.Shared;
1752                         vector = null;
1753                 }
1754
1755                 void initialize_vector ()
1756                 {
1757                         // Post-condition: vector != null
1758                         if (shared == null) {
1759                                 vector = new BitArray (Count, true);
1760                                 return;
1761                         }
1762
1763                         vector = new BitArray (shared);
1764                         if (Count != vector.Count)
1765                                 vector.Length = Count;
1766                         shared = null;
1767                 }
1768
1769                 StringBuilder Dump (StringBuilder sb)
1770                 {
1771                         BitArray dump = vector == null ? shared : vector;
1772                         if (dump == null)
1773                                 return sb.Append ("/");
1774                         if (dump == shared)
1775                                 sb.Append ("=");
1776                         for (int i = 0; i < dump.Count; i++)
1777                                 sb.Append (dump [i] ? "1" : "0");
1778                         return sb;
1779                 }
1780
1781                 public override string ToString ()
1782                 {
1783                         return Dump (new StringBuilder ("{")).Append ("}").ToString ();
1784                 }
1785         }
1786 }