Resolve switch block without fake sections blocks. Fixes #10781
authorMarek Safar <marek.safar@gmail.com>
Wed, 13 Mar 2013 11:02:18 +0000 (12:02 +0100)
committerMarek Safar <marek.safar@gmail.com>
Wed, 13 Mar 2013 11:08:13 +0000 (12:08 +0100)
mcs/mcs/cs-parser.jay
mcs/mcs/flowanalysis.cs
mcs/mcs/statement.cs
mcs/mcs/visit.cs
mcs/tests/test-49.cs
mcs/tests/test-debug-11-ref.xml
mcs/tests/ver-il-net_4_5.xml

index a6f764fda7a395c4dfec7131eff87bacdf5f0aed..be0fcc57bea4deac29d1c1542573525b6563a6b4 100644 (file)
@@ -5374,7 +5374,7 @@ switch_statement
          }
          opt_switch_sections CLOSE_BRACE
          {
-               $$ = new Switch ((Expression) $3, (ExplicitBlock) current_block.Explicit, (List<SwitchSection>) $7, GetLocation ($1));  
+               $$ = new Switch ((Expression) $3, (ExplicitBlock) current_block.Explicit, GetLocation ($1));    
                end_block (GetLocation ($8));
                lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4));
          }
@@ -5382,7 +5382,7 @@ switch_statement
          {
                Error_SyntaxError (yyToken);
          
-               $$ = new Switch ((Expression) $3, null, null, GetLocation ($1));        
+               $$ = new Switch ((Expression) $3, null, GetLocation ($1));      
                lbag.AddStatement ($$, GetLocation ($2));
          }
        ;
@@ -5391,58 +5391,33 @@ opt_switch_sections
        : /* empty */           
       {
                report.Warning (1522, 1, current_block.StartLocation, "Empty switch block"); 
-               $$ = new List<SwitchSection> ();
          }
        | switch_sections
        ;
 
 switch_sections
        : switch_section 
-         {
-               var sections = new List<SwitchSection> (4);
-
-               sections.Add ((SwitchSection) $1);
-               $$ = sections;
-         }
        | switch_sections switch_section
-         {
-               var sections = (List<SwitchSection>) $1;
-
-               sections.Add ((SwitchSection) $2);
-               $$ = sections;
-         }
        | error
          {
                Error_SyntaxError (yyToken);
-               $$ = new List<SwitchSection> ();
          } 
        ;
 
 switch_section
-       : switch_labels
-         {
-               current_block = current_block.CreateSwitchBlock (lexer.Location);
-         }
-         statement_list 
-         {
-               $$ = new SwitchSection ((List<SwitchLabel>) $1, current_block);
-         }
+       : switch_labels statement_list 
        ;
 
 switch_labels
        : switch_label 
          {
-               var labels = new List<SwitchLabel> (2);
-
-               labels.Add ((SwitchLabel) $1);
-               $$ = labels;
+               var label = (SwitchLabel) $1;
+               label.SectionStart = true;
+               current_block.AddStatement (label);
          }
        | switch_labels switch_label 
          {
-               var labels = (List<SwitchLabel>) ($1);
-               labels.Add ((SwitchLabel) $2);
-
-               $$ = labels;
+               current_block.AddStatement ((Statement) $2);
          }
        ;
 
index f6d6db60e93144dd0baecb234b9441d43e2a623b..e71051994e0e07af7d8519fb2fa50c28471bdcd7 100644 (file)
@@ -394,7 +394,7 @@ namespace Mono.CSharp
                // <summary>
                //   Creates a sibling of the current usage vector.
                // </summary>
-               public virtual void CreateSibling (Block block, SiblingType type)
+               public void CreateSibling (Block block, SiblingType type)
                {
                        UsageVector vector = new UsageVector (
                                type, Parent.CurrentUsageVector, block, Location);
index 396aa326acaeef123e9cf5975451af2664d8347b..401b6a877fe3cda21a72f5330e403c37fb473dc1 100644 (file)
@@ -1171,7 +1171,7 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       if (!ec.Switch.GotDefault) {
+                       if (ec.Switch.DefaultLabel == null) {
                                FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
                                return false;
                        }
@@ -1181,7 +1181,7 @@ namespace Mono.CSharp {
 
                protected override void DoEmit (EmitContext ec)
                {
-                       ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel);
+                       ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel.GetILLabel (ec));
                }
                
                public override object Accept (StructuralVisitor visitor)
@@ -2146,14 +2146,6 @@ namespace Mono.CSharp {
 
                #endregion
 
-               public Block CreateSwitchBlock (Location start)
-               {
-                       // FIXME: Only explicit block should be created
-                       var new_block = new Block (this, start, start);
-                       new_block.IsCompilerGenerated = true;
-                       return new_block;
-               }
-
                public void SetEndLocation (Location loc)
                {
                        EndLocation = loc;
@@ -2287,7 +2279,7 @@ namespace Mono.CSharp {
                                        if (s is EmptyStatement)
                                                continue;
 
-                                       if (!ec.UnreachableReported && !(s is LabeledStatement)) {
+                                       if (!ec.UnreachableReported && !(s is LabeledStatement) && !(s is SwitchLabel)) {
                                                ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
                                                ec.UnreachableReported = true;
                                        }
@@ -2309,7 +2301,7 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
-                               if (unreachable && !(s is LabeledStatement) && !(s is Block))
+                               if (unreachable && !(s is LabeledStatement) && !(s is SwitchLabel) && !(s is Block))
                                        statements [ix] = new EmptyStatement (s.loc);
 
                                unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
@@ -3258,18 +3250,19 @@ namespace Mono.CSharp {
                        //
                        // A collision checking between local names
                        //
+                       var variable_block = li.Block.Explicit;
                        for (int i = 0; i < existing_list.Count; ++i) {
                                existing = existing_list[i];
                                Block b = existing.Block.Explicit;
 
                                // Collision at same level
-                               if (li.Block.Explicit == b) {
+                               if (variable_block == b) {
                                        li.Block.Error_AlreadyDeclared (name, li);
                                        break;
                                }
 
                                // Collision with parent
-                               Block parent = li.Block.Explicit;
+                               Block parent = variable_block;
                                while ((parent = parent.Parent) != null) {
                                        if (parent == b) {
                                                li.Block.Error_AlreadyDeclared (name, li, "parent or current");
@@ -3278,10 +3271,10 @@ namespace Mono.CSharp {
                                        }
                                }
 
-                               if (!ignoreChildrenBlocks) {
+                               if (!ignoreChildrenBlocks && variable_block.Parent != b.Parent) {
                                        // Collision with children
                                        while ((b = b.Parent) != null) {
-                                               if (li.Block.Explicit == b) {
+                                               if (variable_block == b) {
                                                        li.Block.Error_AlreadyDeclared (name, li, "child");
                                                        i = existing_list.Count;
                                                        break;
@@ -3458,20 +3451,12 @@ namespace Mono.CSharp {
                        if (label != null) {
                                if (label.Block == b.Original)
                                        return label;
-
-                               // TODO: Temporary workaround for the switch block implicit label block
-                               if (label.Block.IsCompilerGenerated && (label.Block.Parent == b.Original || label.Block == b.Original.Parent))
-                                       return label;
                        } else {
                                List<LabeledStatement> list = (List<LabeledStatement>) value;
                                for (int i = 0; i < list.Count; ++i) {
                                        label = list[i];
                                        if (label.Block == b.Original)
                                                return label;
-
-                                       // TODO: Temporary workaround for the switch block implicit label block
-                                       if (label.Block.IsCompilerGenerated && (label.Block.Parent == b.Original || label.Block == b.Original.Parent))
-                                               return label;
                                }
                        }
                                
@@ -3553,10 +3538,10 @@ namespace Mono.CSharp {
                }
        }
        
-       public class SwitchLabel {
+       public class SwitchLabel : Statement
+       {
                Expression label;
                Constant converted;
-               readonly Location loc;
 
                Label? il_label;
 
@@ -3596,6 +3581,8 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool SectionStart { get; set; }
+
                public Label GetILLabel (EmitContext ec)
                {
                        if (il_label == null){
@@ -3605,6 +3592,18 @@ namespace Mono.CSharp {
                        return il_label.Value;
                }
 
+               protected override void DoEmit (EmitContext ec)
+               {
+                       ec.MarkLabel (GetILLabel (ec));
+               }
+
+               public override bool Resolve (BlockContext bc)
+               {
+                       bc.CurrentBranching.CurrentUsageVector.ResetBarrier ();
+
+                       return base.Resolve (bc);
+               }
+
                //
                // Resolves the expression, reduces it to a literal if possible
                // and then converts it to the requested type.
@@ -3643,36 +3642,19 @@ namespace Mono.CSharp {
                        ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
                }
 
-               public SwitchLabel Clone (CloneContext clonectx)
-               {
-                       if (label == null)
-                               return this;
-
-                       return new SwitchLabel (label.Clone (clonectx), loc);
-               }
-       }
-
-       public class SwitchSection {
-               public readonly List<SwitchLabel> Labels;
-               public readonly Block Block;
-               
-               public SwitchSection (List<SwitchLabel> labels, Block block)
+               protected override void CloneTo (CloneContext clonectx, Statement target)
                {
-                       Labels = labels;
-                       Block = block;
+                       var t = (SwitchLabel) target;
+                       if (label != null)
+                               t.label = label.Clone (clonectx);
                }
 
-               public SwitchSection Clone (CloneContext clonectx)
+               public override object Accept (StructuralVisitor visitor)
                {
-                       var cloned_labels = new List<SwitchLabel> ();
-
-                       foreach (SwitchLabel sl in Labels)
-                               cloned_labels.Add (sl.Clone (clonectx));
-                       
-                       return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
+                       return visitor.Visit (this);
                }
        }
-       
+
        public class Switch : Statement
        {
                // structure used to hold blocks of keys while calculating table switch
@@ -3725,33 +3707,26 @@ namespace Mono.CSharp {
                        }
                }
 
-               sealed class LabelMarker : Statement
+               sealed class DispatchStatement : Statement
                {
-                       readonly Switch s;
-                       readonly List<SwitchLabel> labels;
+                       readonly Switch body;
 
-                       public LabelMarker (Switch s, List<SwitchLabel> labels)
+                       public DispatchStatement (Switch body)
                        {
-                               this.s = s;
-                               this.labels = labels;
+                               this.body = body;
                        }
 
                        protected override void CloneTo (CloneContext clonectx, Statement target)
                        {
+                               throw new NotImplementedException ();
                        }
 
                        protected override void DoEmit (EmitContext ec)
                        {
-                               foreach (var l in labels) {
-                                       if (l.IsDefault)
-                                               ec.MarkLabel (s.DefaultLabel);
-                                       else
-                                               ec.MarkLabel (l.GetILLabel (ec));
-                               }
+                               body.EmitDispatch (ec);
                        }
                }
 
-               public List<SwitchSection> Sections;
                public Expression Expr;
 
                //
@@ -3759,25 +3734,19 @@ namespace Mono.CSharp {
                //
                Dictionary<long, SwitchLabel> labels;
                Dictionary<string, SwitchLabel> string_labels;
+               List<SwitchLabel> case_labels;
 
                /// <summary>
                ///   The governing switch type
                /// </summary>
                public TypeSpec SwitchType;
 
-               //
-               // Computed
-               //
-               Label default_target;
-               Label null_target;
                Expression new_expr;
-               bool is_constant;
 
-               SwitchSection constant_section;
-               SwitchSection default_section;
-               SwitchLabel null_section;
+               SwitchLabel case_null;
+               SwitchLabel case_default;
 
-               Statement simple_stmt;
+               Label defaultLabel, nullLabel;
                VariableReference value;
                ExpressionStatement string_dictionary;
                FieldExpr switch_cache_field;
@@ -3788,11 +3757,10 @@ namespace Mono.CSharp {
                //
                Nullable.Unwrap unwrap;
 
-               public Switch (Expression e, ExplicitBlock block, List<SwitchSection> sects, Location l)
+               public Switch (Expression e, ExplicitBlock block, Location l)
                {
                        Expr = e;
                        this.block = block;
-                       Sections = sects;
                        loc = l;
                }
 
@@ -3802,15 +3770,9 @@ namespace Mono.CSharp {
                        }
                }
 
-               public Label DefaultLabel {
+               public SwitchLabel DefaultLabel {
                        get {
-                               return default_target;
-                       }
-               }
-
-               public bool GotDefault {
-                       get {
-                               return default_section != null;
+                               return case_default;
                        }
                }
 
@@ -3900,54 +3862,80 @@ namespace Mono.CSharp {
                // It also returns a hashtable with the keys that we will later
                // use to compute the switch tables
                //
-               bool CheckSwitch (ResolveContext ec)
+               bool ResolveLabels (ResolveContext ec, Constant value)
                {
                        bool error = false;
-                       if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String)
-                               string_labels = new Dictionary<string, SwitchLabel> (Sections.Count + 1);
-                       else
-                               labels = new Dictionary<long, SwitchLabel> (Sections.Count + 1);
-                               
-                       foreach (SwitchSection ss in Sections){
-                               foreach (SwitchLabel sl in ss.Labels){
-                                       if (sl.IsDefault){
-                                               if (default_section != null){
-                                                       sl.Error_AlreadyOccurs (ec, SwitchType, default_section.Labels [0]);
-                                                       error = true;
-                                               }
-                                               default_section = ss;
-                                               continue;
-                                       }
+                       if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
+                               string_labels = new Dictionary<string, SwitchLabel> ();
+                       } else {
+                               labels = new Dictionary<long, SwitchLabel> ();
+                       }
 
-                                       if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
+                       case_labels = new List<SwitchLabel> ();
+                       int default_label_index = -1;
+                       bool constant_label_found = false;
+
+                       for (int i = 0; i < block.Statements.Count; ++i) {
+                               var s = block.Statements[i];
+
+                               var sl = s as SwitchLabel;
+                               if (sl == null) {
+                                       continue;
+                               }
+
+                               case_labels.Add (sl);
+
+                               if (sl.IsDefault) {
+                                       if (case_default != null) {
+                                               sl.Error_AlreadyOccurs (ec, SwitchType, case_default);
                                                error = true;
-                                               continue;
                                        }
-                                       
-                                       try {
-                                               if (string_labels != null) {
-                                                       string s = sl.Converted.GetValue () as string;
-                                                       if (s == null)
-                                                               null_section = sl;
-                                                       else
-                                                               string_labels.Add (s, sl);
+
+                                       default_label_index = i;
+                                       case_default = sl;
+                                       continue;
+                               }
+
+                               if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
+                                       error = true;
+                                       continue;
+                               }
+
+                               try {
+                                       if (string_labels != null) {
+                                               string string_value = sl.Converted.GetValue () as string;
+                                               if (string_value == null)
+                                                       case_null = sl;
+                                               else
+                                                       string_labels.Add (string_value, sl);
+                                       } else {
+                                               if (sl.Converted is NullLiteral) {
+                                                       case_null = sl;
                                                } else {
-                                                       if (sl.Converted is NullLiteral) {
-                                                               null_section = sl;
-                                                       } else {
-                                                               labels.Add (sl.Converted.GetValueAsLong (), sl);
-                                                       }
+                                                       labels.Add (sl.Converted.GetValueAsLong (), sl);
                                                }
-                                       } catch (ArgumentException) {
-                                               if (string_labels != null)
-                                                       sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
-                                               else
-                                                       sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
-
-                                               error = true;
                                        }
+                               } catch (ArgumentException) {
+                                       if (string_labels != null)
+                                               sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
+                                       else
+                                               sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
+
+                                       error = true;
+                               }
+
+                               if (value != null) {
+                                       var constant_label = constant_label_found ? null : FindLabel (value);
+                                       if (constant_label == null || constant_label != sl)
+                                               block.Statements[i] = new EmptyStatement (s.loc);
+                                       else
+                                               constant_label_found = true;
                                }
                        }
+
+                       if (value != null && constant_label_found && default_label_index >= 0)
+                               block.Statements[default_label_index] = new EmptyStatement (case_default.loc);
+
                        return !error;
                }
                
@@ -3960,8 +3948,6 @@ namespace Mono.CSharp {
                //
                void EmitTableSwitch (EmitContext ec, Expression val)
                {
-                       Label lbl_default = default_target;
-
                        if (labels != null && labels.Count > 0) {
                                List<LabelsRange> ranges;
                                if (string_labels != null) {
@@ -3994,17 +3980,21 @@ namespace Mono.CSharp {
                                        ranges.Sort ();
                                }
 
+                               Label lbl_default = defaultLabel;
                                TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
 
                                for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
                                        LabelsRange kb = ranges[range_index];
-                                       lbl_default = (range_index == 0) ? default_target : ec.DefineLabel ();
+                                       lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
 
                                        // Optimize small ranges using simple equality check
                                        if (kb.Range <= 2) {
                                                foreach (var key in kb.label_values) {
                                                        SwitchLabel sl = labels[key];
-                                                       if (sl.Converted.IsDefaultValue) {
+                                                       if (sl == case_default || sl == case_null)
+                                                               continue;
+
+                                                       if (sl.Converted.IsZeroInteger) {
                                                                val.EmitBranchable (ec, sl.GetILLabel (ec), false);
                                                        } else {
                                                                val.Emit (ec);
@@ -4075,35 +4065,8 @@ namespace Mono.CSharp {
                                if (ranges.Count > 0)
                                        ec.Emit (OpCodes.Br, lbl_default);
                        }
-
-                       // now emit the code for the sections
-                       bool found_default = false;
-
-                       foreach (SwitchSection ss in Sections) {
-                               foreach (SwitchLabel sl in ss.Labels) {
-                                       if (sl.IsDefault) {
-                                               ec.MarkLabel (lbl_default);
-                                               found_default = true;
-                                               if (null_section == null)
-                                                       ec.MarkLabel (null_target);
-                                       } else if (sl.Converted.IsNull) {
-                                               ec.MarkLabel (null_target);
-                                       }
-
-                                       ec.MarkLabel (sl.GetILLabel (ec));
-                               }
-
-                               ss.Block.Emit (ec);
-                       }
-                       
-                       if (!found_default) {
-                               ec.MarkLabel (lbl_default);
-                               if (null_section == null) {
-                                       ec.MarkLabel (null_target);
-                               }
-                       }
                }
-
+               
                SwitchLabel FindLabel (Constant value)
                {
                        SwitchLabel sl = null;
@@ -4111,16 +4074,16 @@ namespace Mono.CSharp {
                        if (string_labels != null) {
                                string s = value.GetValue () as string;
                                if (s == null) {
-                                       if (null_section != null)
-                                               sl = null_section;
-                                       else if (default_section != null)
-                                               sl = default_section.Labels[0];
+                                       if (case_null != null)
+                                               sl = case_null;
+                                       else if (case_default != null)
+                                               sl = case_default;
                                } else {
                                        string_labels.TryGetValue (s, out sl);
                                }
                        } else {
                                if (value is NullLiteral) {
-                                       sl = null_section;
+                                       sl = case_null;
                                } else {
                                        labels.TryGetValue (value.GetValueAsLong (), out sl);
                                }
@@ -4129,18 +4092,6 @@ namespace Mono.CSharp {
                        return sl;
                }
 
-               SwitchSection FindSection (SwitchLabel label)
-               {
-                       foreach (SwitchSection ss in Sections){
-                               foreach (SwitchLabel sl in ss.Labels){
-                                       if (label == sl)
-                                               return ss;
-                               }
-                       }
-
-                       return null;
-               }
-
                public override bool Resolve (BlockContext ec)
                {
                        Expr = Expr.Resolve (ec);
@@ -4172,64 +4123,45 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       if (!CheckSwitch (ec))
-                               return false;
+                       if (block.Statements.Count == 0)
+                               return true;
 
-                       Switch old_switch = ec.Switch;
-                       ec.Switch = this;
-                       ec.Switch.SwitchType = SwitchType;
+                       var constant = new_expr as Constant;
 
-                       ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
+                       if (!ResolveLabels (ec, constant))
+                               return false;
 
-                       var constant = new_expr as Constant;
-                       if (constant != null) {
-                               is_constant = true;
-                               SwitchLabel label = FindLabel (constant);
-                               if (label != null)
-                                       constant_section = FindSection (label);
-
-                               if (constant_section == null)
-                                       constant_section = default_section;
-                       } else {
+                       //
+                       // Don't need extra variable for constant switch or switch with
+                       // only default case
+                       //
+                       if (constant == null && (case_labels.Count - (case_default != null ? 1 : 0)) != 0) {
                                //
                                // Store switch expression for comparison purposes
                                //
                                value = new_expr as VariableReference;
                                if (value == null) {
                                        // Create temporary variable inside switch scope
-                                       var block = ec.CurrentBlock;
+                                       var current_block = ec.CurrentBlock;
                                        ec.CurrentBlock = Block;
                                        value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
                                        value.Resolve (ec);
-                                       ec.CurrentBlock = block;
+                                       ec.CurrentBlock = current_block;
                                }
                        }
 
-                       bool first = true;
-                       bool ok = true;
-                       foreach (SwitchSection ss in Sections){
-                               if (!first)
-                                       ec.CurrentBranching.CreateSibling (
-                                               null, FlowBranching.SiblingType.SwitchSection);
-                               else
-                                       first = false;
+                       Switch old_switch = ec.Switch;
+                       ec.Switch = this;
+                       ec.Switch.SwitchType = SwitchType;
 
-                               if (is_constant && (ss != constant_section)) {
-                                       // If we're a constant switch, we're only emitting
-                                       // one single section - mark all the others as
-                                       // unreachable.
-                                       ec.CurrentBranching.CurrentUsageVector.Goto ();
-                                       if (!ss.Block.ResolveUnreachable (ec, true)) {
-                                               ok = false;
-                                       }
-                               } else {
-                                       if (!ss.Block.Resolve (ec))
-                                               ok = false;
-                               }
-                       }
+                       ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
 
-                       if (default_section == null)
-                               ec.CurrentBranching.CreateSibling (null, FlowBranching.SiblingType.SwitchSection);
+                       ec.CurrentBranching.CurrentUsageVector.Goto ();
+
+                       var ok = block.Resolve (ec);
+
+                       if (case_default == null)
+                               ec.CurrentBranching.CurrentUsageVector.ResetBarrier ();
 
                        ec.EndFlowBranching ();
                        ec.Switch = old_switch;
@@ -4237,17 +4169,16 @@ namespace Mono.CSharp {
                        if (!ok)
                                return false;
 
-                       if (!is_constant) {
-                               if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
-                                       if (string_labels.Count < 7)
-                                               ResolveSimpleSwitch (ec);
-                                       else
-                                               ResolveStringSwitchMap (ec);
-                               } else if (labels.Count < 3 && !IsNullable) {
-                                       ResolveSimpleSwitch (ec);
-                               }
+                       if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
+                               ResolveStringSwitchMap (ec);
                        }
 
+                       //
+                       // Needed to emit anonymous storey initialization before
+                       // any generated switch dispatch
+                       //
+                       block.AddScopeStatement (new DispatchStatement (this));
+
                        return true;
                }
 
@@ -4262,45 +4193,6 @@ namespace Mono.CSharp {
                        return sl;
                }
 
-               //
-               // Prepares switch using simple if/else comparison for small label count (4 + optional default)
-               //
-               void ResolveSimpleSwitch (BlockContext bc)
-               {
-                       simple_stmt = default_section != null ? default_section.Block : null;
-
-                       for (int i = Sections.Count - 1; i >= 0; --i) {
-                               var s = Sections[i];
-
-                               if (s == default_section) {
-                                       s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
-                                       continue;
-                               }
-
-                               s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
-
-                               Expression cond = null;
-                               for (int ci = 0; ci < s.Labels.Count; ++ci) {
-                                       var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted);
-
-                                       if (ci > 0) {
-                                               cond = new Binary (Binary.Operator.LogicalOr, cond, e);
-                                       } else {
-                                               cond = e;
-                                       }
-                               }
-
-                               //
-                               // Compiler generated, hide from symbol file
-                               //
-                               simple_stmt = new If (cond, s.Block, simple_stmt, Location.Null);
-                       }
-
-                       // It's null for empty switch
-                       if (simple_stmt != null)
-                               simple_stmt.Resolve (bc);
-               }
-
                //
                // Converts string switch into string hashtable
                //
@@ -4328,37 +4220,28 @@ namespace Mono.CSharp {
                        ctype.AddField (field);
 
                        var init = new List<Expression> ();
-                       int counter = 0;
+                       int counter = -1;
                        labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
                        string value = null;
-                       foreach (SwitchSection section in Sections) {
-                               bool contains_label = false;
-                               foreach (SwitchLabel sl in section.Labels) {
-                                       if (sl.IsDefault || sl.Converted.IsNull)
-                                               continue;
 
-                                       if (!contains_label) {
-                                               labels.Add (counter, sl);
-                                               contains_label = true;
-                                       }
+                       foreach (SwitchLabel sl in case_labels) {
 
-                                       value = (string) sl.Converted.GetValue ();
-                                       var init_args = new List<Expression> (2);
-                                       init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
+                               if (sl.SectionStart)
+                                       labels.Add (++counter, sl);
 
-                                       sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
-                                       init_args.Add (sl.Converted);
+                               if (sl == case_default || sl == case_null)
+                                       continue;
 
-                                       init.Add (new CollectionElementInitializer (init_args, loc));
-                               }
+                               value = (string) sl.Converted.GetValue ();
+                               var init_args = new List<Expression> (2);
+                               init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
 
-                               //
-                               // Don't add empty sections
-                               //
-                               if (contains_label)
-                                       ++counter;
-                       }
+                               sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
+                               init_args.Add (sl.Converted);
 
+                               init.Add (new CollectionElementInitializer (init_args, loc));
+                       }
+       
                        Arguments args = new Arguments (1);
                        args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
                        Expression initializer = new NewInitialize (string_dictionary_type, args,
@@ -4375,7 +4258,7 @@ namespace Mono.CSharp {
                        //
                        // Skip initialization when value is null
                        //
-                       value.EmitBranchable (ec, null_target, false);
+                       value.EmitBranchable (ec, nullLabel, false);
 
                        //
                        // Check if string dictionary is initialized and initialize
@@ -4401,7 +4284,7 @@ namespace Mono.CSharp {
                                //
                                // A value was not found, go to default case
                                //
-                               get_item.EmitBranchable (ec, default_target, false);
+                               get_item.EmitBranchable (ec, defaultLabel, false);
                        } else {
                                Arguments get_value_args = new Arguments (1);
                                get_value_args.Add (new Argument (value));
@@ -4412,7 +4295,7 @@ namespace Mono.CSharp {
 
                                LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
                                get_item_object.EmitAssign (ec, get_item, true, false);
-                               ec.Emit (OpCodes.Brfalse, default_target);
+                               ec.Emit (OpCodes.Brfalse, defaultLabel);
 
                                ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
                                        new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
@@ -4425,49 +4308,104 @@ namespace Mono.CSharp {
                        string_switch_variable.Release (ec);
                }
 
-               protected override void DoEmit (EmitContext ec)
+               //
+               // Emits switch using simple if/else comparison for small label count (4 + optional default)
+               //
+               void EmitShortSwitch (EmitContext ec)
                {
-                       // Workaround broken flow-analysis
-                       block.HasUnreachableClosingBrace = true;
+                       MethodSpec equal_method = null;
+                       if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
+                               equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
+                       }
+
+                       if (equal_method != null) {
+                               value.EmitBranchable (ec, nullLabel, false);
+                       }
+
+                       for (int i = 0; i < case_labels.Count; ++i) {
+                               var label = case_labels [i];
+                               if (label == case_default || label == case_null)
+                                       continue;
+
+                               var constant = label.Converted;
+
+                               if (equal_method != null) {
+                                       value.Emit (ec);
+                                       constant.Emit (ec);
+
+                                       var call = new CallEmitter ();
+                                       call.EmitPredefined (ec, equal_method, new Arguments (0));
+                                       ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
+                                       continue;
+                               }
+
+                               if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
+                                       value.EmitBranchable (ec, label.GetILLabel (ec), false);
+                                       continue;
+                               }
+
+                               value.Emit (ec);
+                               constant.Emit (ec);
+                               ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
+                       }
+
+                       ec.Emit (OpCodes.Br, defaultLabel);
+               }
+
+               void EmitDispatch (EmitContext ec)
+               {
+                       if (value == null) {
+                               //
+                               // Constant switch, we already done the work
+                               //
+                               return;
+                       }
 
                        //
-                       // Needed to emit anonymous storey initialization
-                       // Otherwise it does not contain any statements for now
+                       // Mark sequence point explicitly to switch
                        //
-                       block.Emit (ec);
-
-                       default_target = ec.DefineLabel ();
-                       null_target = ec.DefineLabel ();
+                       ec.Mark (block.StartLocation);
+                       block.IsCompilerGenerated = true;
 
-                       if (IsNullable) {
-                               unwrap.EmitCheck (ec);
-                               ec.Emit (OpCodes.Brfalse, null_target);
-                               value.EmitAssign (ec, new_expr, false, false);
-                       } else if (new_expr != value && !is_constant) {
-                               value.EmitAssign (ec, new_expr, false, false);
+                       if (string_dictionary != null) {
+                               DoEmitStringSwitch (ec);
+                       } else if (case_labels.Count < 4 || string_labels != null) {
+                               EmitShortSwitch (ec);
+                       } else {
+                               EmitTableSwitch (ec, value);
                        }
+               }
+
+               protected override void DoEmit (EmitContext ec)
+               {
+                       // Workaround broken flow-analysis
+                       block.HasUnreachableClosingBrace = true;
 
                        //
                        // Setup the codegen context
                        //
                        Label old_end = ec.LoopEnd;
                        Switch old_switch = ec.Switch;
-                       
+
                        ec.LoopEnd = ec.DefineLabel ();
                        ec.Switch = this;
 
-                       // Emit Code.
-                       if (is_constant) {
-                               if (constant_section != null)
-                                       constant_section.Block.Emit (ec);
-                       } else if (string_dictionary != null) {
-                               DoEmitStringSwitch (ec);
-                       } else if (simple_stmt != null) {
-                               simple_stmt.Emit (ec);
-                       } else {
-                               EmitTableSwitch (ec, value);
+                       defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
+                       nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
+
+                       if (value != null) {
+                               ec.Mark (loc);
+                               if (IsNullable) {
+                                       unwrap.EmitCheck (ec);
+                                       ec.Emit (OpCodes.Brfalse, nullLabel);
+                                       value.EmitAssign (ec, new_expr, false, false);
+                               } else if (new_expr != value) {
+                                       value.EmitAssign (ec, new_expr, false, false);
+                               }
                        }
 
+                       block.Emit (ec);
+
                        // Restore context state. 
                        ec.MarkLabel (ec.LoopEnd);
 
@@ -4483,10 +4421,7 @@ namespace Mono.CSharp {
                        Switch target = (Switch) t;
 
                        target.Expr = Expr.Clone (clonectx);
-                       target.Sections = new List<SwitchSection> ();
-                       foreach (SwitchSection ss in Sections){
-                               target.Sections.Add (ss.Clone (clonectx));
-                       }
+                       target.block = (ExplicitBlock) block.Clone (clonectx);
                }
                
                public override object Accept (StructuralVisitor visitor)
index f7ea686a46bf866445d13fa9d2784c5baf82a496..3af9db9a8c293e3044af275e65abb02d6d7496c3 100644 (file)
@@ -212,6 +212,11 @@ namespace Mono.CSharp
                        return null;
                }
 
+               public virtual object Visit (SwitchLabel switchLabel)
+               {
+                       return null;
+               }
+
                public virtual object Visit (GotoDefault gotoDefault)
                {
                        return null;
index c9aabd35775024f8e8bef667faa29a0d7a5efb37..9800ffd3d61399cbed524df4108aae3f89d538d0 100644 (file)
@@ -579,6 +579,76 @@ class X {
                switch (a) {
                }
        }
+
+       static int LongStringSwitch (string s)
+       {
+               switch (s)
+               {
+                       case "System":
+                       case "System.Core":
+                       case "System.Data":
+                       case "System.Data.DataSetExtensions":
+                       case "System.Data.Linq":
+                       case "System.Data.OracleClient":
+                       case "System.Data.Services":
+                       case "System.Data.Services.Client":
+                       case "System.IdentityModel":
+                       case "System.IdentityModel.Selectors":
+                       case "System.Runtime.Remoting":
+                       case "System.Runtime.Serialization":
+                       case "System.ServiceModel":
+                       case "System.Transactions":
+                       case "System.Windows.Forms":
+                       case "System.Xml":
+                       case "System.Xml.Linq":
+                               return 1;
+
+                       case "System.Configuration":
+                       case "System.Configuration.Install":
+                       case "System.Design":
+                       case "System.DirectoryServices":
+                       case "System.Drawing":
+                       case "System.Drawing.Design":
+                       case "System.EnterpriseServices":
+                       case "System.Management":
+                       case "System.Messaging":
+                       case "System.Runtime.Serialization.Formatters.Soap":
+                       case "System.Security":
+                       case "System.ServiceProcess":
+                       case "System.Web":
+                       case "System.Web.Mobile":
+                       case "System.Web.Services":
+                               return 2;
+
+                       case "System.ComponentModel.DataAnnotations":
+                       case "System.ServiceModel.Web":
+                       case "System.Web.Abstractions":
+                       case "System.Web.Extensions":
+                       case "System.Web.Extensions.Design":
+                       case "System.Web.DynamicData":
+                       case "System.Web.Routing":
+                               return 3;
+               }
+
+               return 10;
+       }
+
+       static bool SwitchSingleSection (string scheme)
+       {
+               switch (scheme) {
+               case "http":
+               case "https":
+               case "file":
+               case "ftp":
+               case "nntp":
+               case "gopher":
+               case "mailto":
+               case "news":
+                       return true;
+               default:
+                       return false;
+               }
+       }
        
        public static int Main ()
        {
@@ -720,6 +790,20 @@ class X {
                if (tests2 ("two") != 3)
                        return 73;
 
+               if (LongStringSwitch ("System.Management") != 2)
+                       return 80;              
+               if (LongStringSwitch (null) != 10)
+                       return 81;
+               if (LongStringSwitch (".") != 10)
+                       return 82;
+
+               if (!SwitchSingleSection ("file"))
+                       return 90;
+               if (SwitchSingleSection (null))
+                       return 91;
+               if (SwitchSingleSection ("-=-"))
+                       return 92;
+
                test_1597 ();
                
                Console.WriteLine ("All tests pass");
index 9a6c2dcacd76c246516db009c97e51e62450fd68..2a1b635dcce1d15a83b8caf462414bfcace990a5 100644 (file)
       <sequencepoints>
         <entry il="0x0" row="68" col="2" file_ref="1" hidden="false" />
         <entry il="0x1" row="70" col="3" file_ref="1" hidden="false" />
-        <entry il="0x23" row="72" col="5" file_ref="1" hidden="false" />
-        <entry il="0x28" row="74" col="4" file_ref="1" hidden="false" />
-        <entry il="0x29" row="75" col="5" file_ref="1" hidden="false" />
-        <entry il="0x2e" row="78" col="5" file_ref="1" hidden="false" />
-        <entry il="0x33" row="81" col="5" file_ref="1" hidden="false" />
-        <entry il="0x38" row="83" col="5" file_ref="1" hidden="false" />
-        <entry il="0x3d" row="85" col="2" file_ref="1" hidden="false" />
+        <entry il="0x22" row="72" col="5" file_ref="1" hidden="false" />
+        <entry il="0x27" row="74" col="4" file_ref="1" hidden="false" />
+        <entry il="0x28" row="75" col="5" file_ref="1" hidden="false" />
+        <entry il="0x2d" row="78" col="5" file_ref="1" hidden="false" />
+        <entry il="0x32" row="81" col="5" file_ref="1" hidden="false" />
+        <entry il="0x37" row="83" col="5" file_ref="1" hidden="false" />
+        <entry il="0x3c" row="85" col="2" file_ref="1" hidden="false" />
       </sequencepoints>
       <locals />
       <scopes>
-        <entry index="0" start="0x2" end="0x2" />
-        <entry index="1" start="0x29" end="0x2e" />
+        <entry index="0" start="0x22" end="0x3c" />
+        <entry index="1" start="0x28" end="0x2d" />
       </scopes>
     </method>
     <method token="0x600000b">
       <sequencepoints>
         <entry il="0x0" row="88" col="2" file_ref="1" hidden="false" />
-        <entry il="0x1" row="90" col="3" file_ref="1" hidden="false" />
-        <entry il="0x29" row="92" col="5" file_ref="1" hidden="false" />
-        <entry il="0x2e" row="94" col="4" file_ref="1" hidden="false" />
-        <entry il="0x2f" row="95" col="5" file_ref="1" hidden="false" />
-        <entry il="0x34" row="98" col="5" file_ref="1" hidden="false" />
-        <entry il="0x39" row="100" col="2" file_ref="1" hidden="false" />
+        <entry il="0x1" row="89" col="3" file_ref="1" hidden="false" />
+        <entry il="0x15" row="90" col="3" file_ref="1" hidden="false" />
+        <entry il="0x28" row="92" col="5" file_ref="1" hidden="false" />
+        <entry il="0x2d" row="94" col="4" file_ref="1" hidden="false" />
+        <entry il="0x2e" row="95" col="5" file_ref="1" hidden="false" />
+        <entry il="0x33" row="98" col="5" file_ref="1" hidden="false" />
+        <entry il="0x38" row="100" col="2" file_ref="1" hidden="false" />
       </sequencepoints>
       <locals />
       <scopes>
-        <entry index="0" start="0x2" end="0x2" />
-        <entry index="1" start="0x2f" end="0x34" />
+        <entry index="0" start="0x28" end="0x38" />
+        <entry index="1" start="0x2e" end="0x33" />
       </scopes>
     </method>
     <method token="0x600000c">
       <sequencepoints>
         <entry il="0x0" row="103" col="2" file_ref="1" hidden="false" />
         <entry il="0x1" row="105" col="3" file_ref="1" hidden="false" />
-        <entry il="0xb0" row="107" col="5" file_ref="1" hidden="false" />
-        <entry il="0xb5" row="109" col="4" file_ref="1" hidden="false" />
-        <entry il="0xb6" row="110" col="5" file_ref="1" hidden="false" />
-        <entry il="0xbb" row="114" col="5" file_ref="1" hidden="false" />
-        <entry il="0xc0" row="116" col="5" file_ref="1" hidden="false" />
-        <entry il="0xc5" row="120" col="5" file_ref="1" hidden="false" />
-        <entry il="0xca" row="122" col="5" file_ref="1" hidden="false" />
-        <entry il="0xcf" row="124" col="2" file_ref="1" hidden="false" />
+        <entry il="0xb3" row="107" col="5" file_ref="1" hidden="false" />
+        <entry il="0xb8" row="109" col="4" file_ref="1" hidden="false" />
+        <entry il="0xb9" row="110" col="5" file_ref="1" hidden="false" />
+        <entry il="0xbe" row="114" col="5" file_ref="1" hidden="false" />
+        <entry il="0xc3" row="116" col="5" file_ref="1" hidden="false" />
+        <entry il="0xc8" row="120" col="5" file_ref="1" hidden="false" />
+        <entry il="0xcd" row="122" col="5" file_ref="1" hidden="false" />
+        <entry il="0xd2" row="124" col="2" file_ref="1" hidden="false" />
       </sequencepoints>
       <locals />
       <scopes>
-        <entry index="0" start="0x2" end="0x2" />
-        <entry index="1" start="0xb6" end="0xbb" />
+        <entry index="0" start="0xb3" end="0xd2" />
+        <entry index="1" start="0xb9" end="0xbe" />
       </scopes>
     </method>
     <method token="0x600000d">
       <sequencepoints>
         <entry il="0x0" row="127" col="2" file_ref="1" hidden="false" />
         <entry il="0x1" row="129" col="3" file_ref="1" hidden="false" />
-        <entry il="0x12" row="131" col="5" file_ref="1" hidden="false" />
-        <entry il="0x2c" row="133" col="5" file_ref="1" hidden="false" />
+        <entry il="0x2c" row="131" col="5" file_ref="1" hidden="false" />
+        <entry il="0x31" row="133" col="5" file_ref="1" hidden="false" />
         <entry il="0x36" row="135" col="5" file_ref="1" hidden="false" />
         <entry il="0x3b" row="137" col="2" file_ref="1" hidden="false" />
       </sequencepoints>
       <locals />
       <scopes>
-        <entry index="0" start="0x2" end="0x2" />
+        <entry index="0" start="0x2c" end="0x3b" />
       </scopes>
     </method>
     <method token="0x600000e">
index ab4aca730e063b1d154cc5c4975792dcdb6a5df7..61ff83c029da9abebbb1a570815941d8073d3365 100644 (file)
     </type>\r
     <type name="X">\r
       <method name="Int32 Beer(Nullable`1)" attrs="145">\r
-        <size>73</size>\r
+        <size>72</size>\r
       </method>\r
       <method name="Int64 PubToLong(IrishPub)" attrs="145">\r
         <size>20</size>\r
       </method>\r
       <method name="Int32 Test(Nullable`1)" attrs="145">\r
-        <size>72</size>\r
+        <size>62</size>\r
       </method>\r
       <method name="Int32 TestWithNull(Nullable`1)" attrs="145">\r
-        <size>79</size>\r
+        <size>78</size>\r
       </method>\r
       <method name="Nullable`1 Foo(Boolean)" attrs="145">\r
         <size>37</size>\r
       </method>\r
       <method name="Int32 Test(Boolean)" attrs="145">\r
-        <size>71</size>\r
+        <size>72</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
         <size>247</size>\r
   <test name="gtest-270.cs">\r
     <type name="X">\r
       <method name="Int32 Test(Nullable`1)" attrs="145">\r
-        <size>63</size>\r
+        <size>62</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
         <size>60</size>\r
   <test name="gtest-335.cs">\r
     <type name="TestClass">\r
       <method name="Boolean Test_1()" attrs="150">\r
-        <size>57</size>\r
+        <size>56</size>\r
       </method>\r
       <method name="Boolean Test_2()" attrs="150">\r
-        <size>67</size>\r
+        <size>66</size>\r
       </method>\r
       <method name="Boolean Test_3()" attrs="150">\r
-        <size>60</size>\r
+        <size>59</size>\r
       </method>\r
       <method name="Boolean Test_4()" attrs="150">\r
-        <size>38</size>\r
+        <size>18</size>\r
       </method>\r
       <method name="Boolean Test_5()" attrs="150">\r
-        <size>82</size>\r
+        <size>81</size>\r
       </method>\r
       <method name="Int32 Test_6()" attrs="145">\r
-        <size>72</size>\r
+        <size>71</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
         <size>123</size>\r
   <test name="test-152.cs">\r
     <type name="X">\r
       <method name="Int32 Main()" attrs="150">\r
-        <size>112</size>\r
+        <size>115</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
         <size>29</size>\r
       </method>\r
       <method name="Int64 test11(Int32)" attrs="150">\r
-        <size>61</size>\r
+        <size>55</size>\r
       </method>\r
       <method name="Void test12(Single ByRef)" attrs="150">\r
         <size>24</size>\r
         <size>36</size>\r
       </method>\r
       <method name="Int64 test14(Int32, Single ByRef)" attrs="150">\r
-        <size>78</size>\r
+        <size>77</size>\r
       </method>\r
       <method name="Int32 test15(Int32, Single ByRef)" attrs="150">\r
         <size>41</size>\r
         <size>44</size>\r
       </method>\r
       <method name="Int64 test24(Int32)" attrs="145">\r
-        <size>85</size>\r
+        <size>89</size>\r
       </method>\r
       <method name="Int64 test25(Int32)" attrs="145">\r
         <size>48</size>\r
         <size>41</size>\r
       </method>\r
       <method name="System.String test31(Int32)" attrs="134">\r
-        <size>95</size>\r
+        <size>94</size>\r
       </method>\r
       <method name="Void test32()" attrs="134">\r
         <size>15</size>\r
         <size>26</size>\r
       </method>\r
       <method name="Void test35(Int32, Boolean)" attrs="150">\r
-        <size>36</size>\r
+        <size>35</size>\r
       </method>\r
       <method name="Void test36()" attrs="150">\r
         <size>46</size>\r
       </method>\r
       <method name="Void test37()" attrs="150">\r
-        <size>31</size>\r
+        <size>39</size>\r
       </method>\r
       <method name="Int32 test38()" attrs="150">\r
         <size>10</size>\r
   <test name="test-193.cs">\r
     <type name="A">\r
       <method name="Int32 Test(Int32)" attrs="145">\r
-        <size>94</size>\r
+        <size>93</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
         <size>15</size>\r
   <test name="test-234.cs">\r
     <type name="T">\r
       <method name="Void Main()" attrs="150">\r
-        <size>701</size>\r
+        <size>700</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
   <test name="test-308.cs">\r
     <type name="Program">\r
       <method name="Void Main(System.String[])" attrs="150">\r
-        <size>35</size>\r
+        <size>39</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
     </type>\r
     <type name="X">\r
       <method name="Void Main()" attrs="150">\r
-        <size>52</size>\r
+        <size>51</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
   <test name="test-368.cs">\r
     <type name="X">\r
       <method name="Void Main()" attrs="150">\r
-        <size>26</size>\r
+        <size>30</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
   <test name="test-370.cs">\r
     <type name="Test.Application">\r
       <method name="Int32 ParseType(System.String)" attrs="145">\r
-        <size>126</size>\r
+        <size>152</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
         <size>72</size>\r
   <test name="test-385.cs">\r
     <type name="Test">\r
       <method name="Int32 Main()" attrs="150">\r
-        <size>57</size>\r
+        <size>56</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
   <test name="test-438.cs">\r
     <type name="Program">\r
       <method name="Void Main(System.String[])" attrs="150">\r
-        <size>35</size>\r
+        <size>39</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
   <test name="test-49.cs">\r
     <type name="X">\r
       <method name="Int32 s(Byte)" attrs="145">\r
-        <size>3469</size>\r
+        <size>3468</size>\r
       </method>\r
       <method name="Int32 test(Int32)" attrs="145">\r
-        <size>92</size>\r
+        <size>91</size>\r
       </method>\r
       <method name="Int32 tests(System.String)" attrs="145">\r
-        <size>137</size>\r
+        <size>135</size>\r
       </method>\r
       <method name="Int32 tests2(System.String)" attrs="145">\r
-        <size>53</size>\r
+        <size>63</size>\r
       </method>\r
       <method name="Int32 testn(System.String)" attrs="145">\r
-        <size>34</size>\r
+        <size>44</size>\r
       </method>\r
       <method name="Int32 testm(System.String)" attrs="145">\r
-        <size>35</size>\r
+        <size>45</size>\r
       </method>\r
       <method name="Int32 testo(System.String)" attrs="145">\r
-        <size>59</size>\r
+        <size>52</size>\r
       </method>\r
       <method name="Int32 testp(System.String)" attrs="145">\r
-        <size>90</size>\r
+        <size>83</size>\r
       </method>\r
       <method name="Int32 test_def(System.String)" attrs="145">\r
-        <size>78</size>\r
+        <size>88</size>\r
       </method>\r
       <method name="Int32 test_coverage(Int32)" attrs="145">\r
-        <size>25</size>\r
+        <size>29</size>\r
       </method>\r
       <method name="Int32 test_goto(Int32)" attrs="145">\r
-        <size>56</size>\r
+        <size>55</size>\r
       </method>\r
       <method name="Int32 test_memberaccess(System.String)" attrs="145">\r
-        <size>34</size>\r
+        <size>44</size>\r
       </method>\r
       <method name="Int32 test_string_multiple_targets(System.String)" attrs="145">\r
         <size>106</size>\r
       </method>\r
       <method name="Int32 test_casts(Int32)" attrs="145">\r
-        <size>24</size>\r
+        <size>28</size>\r
       </method>\r
       <method name="Int32 testSwitchEnumLong(TestEnum)" attrs="150">\r
-        <size>73</size>\r
+        <size>72</size>\r
       </method>\r
       <method name="Int32 test_long_enum_switch()" attrs="145">\r
         <size>94</size>\r
       </method>\r
       <method name="Int32 tests_default(System.String)" attrs="145">\r
-        <size>34</size>\r
+        <size>76</size>\r
       </method>\r
       <method name="Int32 tests_default_2(System.String)" attrs="145">\r
-        <size>98</size>\r
+        <size>93</size>\r
       </method>\r
       <method name="Void test_76590(System.String)" attrs="145">\r
-        <size>72</size>\r
+        <size>60</size>\r
       </method>\r
       <method name="Void test_77964()" attrs="145">\r
-        <size>37</size>\r
+        <size>36</size>\r
       </method>\r
       <method name="Boolean bug_78860()" attrs="145">\r
-        <size>91</size>\r
+        <size>84</size>\r
       </method>\r
       <method name="Void test_1597()" attrs="145">\r
         <size>9</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
-        <size>1390</size>\r
+        <size>1525</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
       </method>\r
+      <method name="Int32 LongStringSwitch(System.String)" attrs="145">\r
+        <size>571</size>\r
+      </method>\r
+      <method name="Boolean SwitchSingleSection(System.String)" attrs="145">\r
+        <size>171</size>\r
+      </method>\r
     </type>\r
   </test>\r
   <test name="test-490.cs">\r
   <test name="test-499.cs">\r
     <type name="A">\r
       <method name="Int32 switch1(UInt64)" attrs="145">\r
-        <size>123</size>\r
+        <size>122</size>\r
       </method>\r
       <method name="Int32 switch2(SByte)" attrs="145">\r
-        <size>45</size>\r
+        <size>42</size>\r
       </method>\r
       <method name="Int32 switch3(Int64)" attrs="145">\r
-        <size>46</size>\r
+        <size>45</size>\r
       </method>\r
       <method name="Int32 switch4(UInt64)" attrs="145">\r
-        <size>51</size>\r
+        <size>50</size>\r
       </method>\r
       <method name="Int32 switch5(UInt64)" attrs="145">\r
-        <size>36</size>\r
+        <size>35</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
         <size>154</size>\r
   <test name="test-544.cs">\r
     <type name="X">\r
       <method name="Void Main()" attrs="150">\r
-        <size>34</size>\r
+        <size>33</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
   <test name="test-591.cs">\r
     <type name="C1">\r
       <method name="Void Foo(System.String)" attrs="145">\r
-        <size>20</size>\r
+        <size>18</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
         <size>46</size>\r
       </method>\r
       <method name="Void foo(Int32)" attrs="129">\r
-        <size>36</size>\r
+        <size>40</size>\r
       </method>\r
       <method name="Void XXXA()" attrs="145">\r
         <size>7</size>\r
     </type>\r
     <type name="C">\r
       <method name="Void Main()" attrs="150">\r
-        <size>19</size>\r
+        <size>8</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
   <test name="test-664.cs">\r
     <type name="C">\r
       <method name="Boolean Test(System.String)" attrs="145">\r
-        <size>160</size>\r
+        <size>159</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
         <size>72</size>\r
         <size>10</size>\r
       </method>\r
       <method name="Void Foo(ItemSlot)" attrs="129">\r
-        <size>22</size>\r
+        <size>26</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
         <size>10</size>\r
     </type>\r
     <type name="B">\r
       <method name="Int32 Main()" attrs="150">\r
-        <size>216</size>\r
+        <size>217</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
         <size>14</size>\r
       </method>\r
       <method name="Int32 Main()" attrs="150">\r
-        <size>223</size>\r
+        <size>224</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
   <test name="test-854.cs">\r
     <type name="Test">\r
       <method name="Int32 Main()" attrs="150">\r
-        <size>70</size>\r
+        <size>69</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
         <size>54</size>\r
       </method>\r
       <method name="Void &lt;Main&gt;m__7(E)" attrs="145">\r
-        <size>41</size>\r
+        <size>35</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
     </type>\r
     <type name="Test+&lt;Switch&gt;c__AnonStorey8`1[T]">\r
       <method name="T &lt;&gt;m__8()" attrs="131">\r
-        <size>44</size>\r
+        <size>16</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
         <size>36</size>\r
       </method>\r
       <method name="Void &lt;Main&gt;m__0()" attrs="145">\r
-        <size>84</size>\r
+        <size>89</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
         <size>113</size>\r
       </method>\r
       <method name="Int32 &lt;Main&gt;m__0(Int32)" attrs="145">\r
-        <size>57</size>\r
+        <size>51</size>\r
       </method>\r
       <method name="Int32 &lt;Main&gt;m__1(Int32)" attrs="145">\r
-        <size>42</size>\r
+        <size>46</size>\r
       </method>\r
       <method name="Int32 &lt;Main&gt;m__2(Int32)" attrs="145">\r
-        <size>38</size>\r
+        <size>42</size>\r
       </method>\r
       <method name="Void .ctor()" attrs="6278">\r
         <size>7</size>\r
         <size>11</size>\r
       </method>\r
       <method name="Program+D Get(Int32)" attrs="145">\r
-        <size>145</size>\r
+        <size>146</size>\r
       </method>\r
       <method name="Int32 Run(Int32)" attrs="145">\r
         <size>20</size>\r
     </type>\r
     <type name="Tester+&lt;SwitchTest_1&gt;c__async0">\r
       <method name="Void MoveNext()" attrs="486">\r
-        <size>346</size>\r
+        <size>336</size>\r
       </method>\r
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">\r
         <size>13</size>\r
         <size>30</size>\r
       </method>\r
       <method name="Void Switch_1(Int32)" attrs="129">\r
-        <size>62</size>\r
+        <size>61</size>\r
       </method>\r
       <method name="Void Switch_2(Nullable`1)" attrs="129">\r
-        <size>58</size>\r
+        <size>57</size>\r
       </method>\r
       <method name="Void Switch_3(System.String)" attrs="129">\r
-        <size>208</size>\r
+        <size>211</size>\r
       </method>\r
       <method name="Void Switch_4(System.String)" attrs="129">\r
         <size>60</size>\r