[mcs] Makes flow analysis of goto/goto case significantly faster. Fixes #24511
authorMarek Safar <marek.safar@gmail.com>
Tue, 18 Nov 2014 09:27:17 +0000 (10:27 +0100)
committerMarek Safar <marek.safar@gmail.com>
Tue, 18 Nov 2014 09:28:55 +0000 (10:28 +0100)
mcs/errors/cs0165-50.cs [new file with mode: 0644]
mcs/mcs/context.cs
mcs/mcs/expression.cs
mcs/mcs/flowanalysis.cs
mcs/mcs/statement.cs

diff --git a/mcs/errors/cs0165-50.cs b/mcs/errors/cs0165-50.cs
new file mode 100644 (file)
index 0000000..1695000
--- /dev/null
@@ -0,0 +1,23 @@
+// CS0165: Use of unassigned local variable `u'
+// Line: 15
+
+class X
+{
+       public static void Main ()
+       {
+               int i = 0;
+               int u;
+               switch (i) {
+                       case 1:
+                               A1:
+                               goto case 2;
+                       case 2:
+                               i = u;
+                               goto case 3;
+                       case 3:
+                               goto case 4;
+                       case 4:
+                               goto A1;
+               }
+       }
+}
\ No newline at end of file
index 230aa12576413949820af1dd5bbfca51e28e997c..b41d8c472771ec04e567e305606099e003cf6e63 100644 (file)
@@ -464,7 +464,7 @@ namespace Mono.CSharp
 
                public DefiniteAssignmentBitSet DefiniteAssignmentOnFalse { get; set; }
 
-               public List<LabeledStatement> LabelStack { get; set; }
+               Dictionary<Statement, List<DefiniteAssignmentBitSet>> LabelStack { get; set; }
 
                public ParametersBlock ParametersBlock { get; set; }
 
@@ -480,12 +480,48 @@ namespace Mono.CSharp
 
                public bool UnreachableReported { get; set; }
 
+               public bool AddReachedLabel (Statement label)
+               {
+                       List<DefiniteAssignmentBitSet> das;
+                       if (LabelStack == null) {
+                               LabelStack = new Dictionary<Statement, List<DefiniteAssignmentBitSet>> ();
+                               das = null;
+                       } else {
+                               LabelStack.TryGetValue (label, out das);
+                       }
+
+                       if (das == null) {
+                               das = new List<DefiniteAssignmentBitSet> ();
+                               das.Add (new DefiniteAssignmentBitSet (DefiniteAssignment));
+                               LabelStack.Add (label, das);
+                               return false;
+                       }
+
+                       foreach (var existing in das) {
+                               if (DefiniteAssignmentBitSet.AreEqual (existing, DefiniteAssignment))
+                                       return true;
+                       }
+
+                       if (DefiniteAssignment == DefiniteAssignmentBitSet.Empty)
+                               das.Add (DefiniteAssignment);
+                       else
+                               das.Add (new DefiniteAssignmentBitSet (DefiniteAssignment));
+
+                       return false;
+               }
+
                public DefiniteAssignmentBitSet BranchDefiniteAssignment ()
                {
-                       var dat = DefiniteAssignment;
-                       if (dat != DefiniteAssignmentBitSet.Empty)
-                               DefiniteAssignment = new DefiniteAssignmentBitSet (dat);
-                       return dat;
+                       return BranchDefiniteAssignment (DefiniteAssignment);
+               }
+
+               public DefiniteAssignmentBitSet BranchDefiniteAssignment (DefiniteAssignmentBitSet da)
+               {
+                       if (da != DefiniteAssignmentBitSet.Empty) {
+                               DefiniteAssignment = new DefiniteAssignmentBitSet (da);
+                       }
+
+                       return da;
                }
 
                public void BranchConditionalAccessDefiniteAssignment ()
index 6699377f8df408e355b889789f3a2ffce55cdd2d..4a5cddb992f723927ef1fd460f625272b4f9dc56 100644 (file)
@@ -6271,11 +6271,11 @@ namespace Mono.CSharp
                        var expr_true = fc.DefiniteAssignmentOnTrue;
                        var expr_false = fc.DefiniteAssignmentOnFalse;
 
-                       fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
+                       fc.BranchDefiniteAssignment (expr_true);
                        true_expr.FlowAnalysis (fc);
                        var true_fc = fc.DefiniteAssignment;
 
-                       fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
+                       fc.BranchDefiniteAssignment (expr_false);
                        false_expr.FlowAnalysis (fc);
 
                        fc.DefiniteAssignment &= true_fc;
index a28434d6bc27bd40c6d3ba4da44060c0b1643848..183250cde8bf01f673318052672c0e1b67efa68d 100644 (file)
@@ -669,7 +669,7 @@ namespace Mono.CSharp
                                large_bits[index >> 5] |= (1 << (index & 31));
                }
 
-               static bool AreEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
+               public static bool AreEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
                {
                        if (a.large_bits == null)
                                return (a.bits & ~copy_on_write_flag) == (b.bits & ~copy_on_write_flag);
index 00d61eba2b764a6a5a53607bae1860b887ed2303..9f9f01845b009369d38278ed6a64ad3958954577 100644 (file)
@@ -1408,15 +1408,10 @@ namespace Mono.CSharp {
 
                protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
                {
-                       if (fc.LabelStack == null) {
-                               fc.LabelStack = new List<LabeledStatement> ();
-                       } else if (fc.LabelStack.Contains (label)) {
+                       if (fc.AddReachedLabel (label))
                                return true;
-                       }
 
-                       fc.LabelStack.Add (label);
                        label.Block.ScanGotoJump (label, fc);
-                       fc.LabelStack.Remove (label);
                        return true;
                }
 
@@ -2966,6 +2961,7 @@ namespace Mono.CSharp {
                bool DoFlowAnalysis (FlowAnalysisContext fc, int startIndex)
                {
                        bool end_unreachable = !reachable;
+                       bool goto_flow_analysis = startIndex != 0;
                        for (; startIndex < statements.Count; ++startIndex) {
                                var s = statements[startIndex];
 
@@ -2989,10 +2985,14 @@ namespace Mono.CSharp {
                                // this for flow-analysis only to carry variable info correctly.
                                //
                                if (end_unreachable) {
+                                       bool after_goto_case = goto_flow_analysis && s is GotoCase;
+
                                        for (++startIndex; startIndex < statements.Count; ++startIndex) {
                                                s = statements[startIndex];
                                                if (s is SwitchLabel) {
-                                                       s.FlowAnalysis (fc);
+                                                       if (!after_goto_case)
+                                                               s.FlowAnalysis (fc);
+
                                                        break;
                                                }
 
@@ -3001,7 +3001,20 @@ namespace Mono.CSharp {
                                                        statements [startIndex] = RewriteUnreachableStatement (s);
                                                }
                                        }
+
+                                       //
+                                       // Idea is to stop after goto case because goto case will always have at least same
+                                       // variable assigned as switch case label. This saves a lot for complex goto case tests
+                                       //
+                                       if (after_goto_case)
+                                               break;
+
+                                       continue;
                                }
+
+                               var lb = s as LabeledStatement;
+                               if (lb != null && fc.AddReachedLabel (lb))
+                                       break;
                        }
 
                        //
@@ -3025,7 +3038,7 @@ namespace Mono.CSharp {
                        // L:
                        //      v = 1;
 
-                       if (s is BlockVariable)
+                       if (s is BlockVariable || s is EmptyStatement)
                                return s;
 
                        return new EmptyStatement (s.loc);
@@ -4494,7 +4507,7 @@ namespace Mono.CSharp {
                        if (!SectionStart)
                                return false;
 
-                       fc.DefiniteAssignment = new DefiniteAssignmentBitSet (fc.SwitchInitialDefinitiveAssignment);
+                       fc.BranchDefiniteAssignment (fc.SwitchInitialDefinitiveAssignment);
                        return false;
                }
 
@@ -7193,7 +7206,7 @@ namespace Mono.CSharp {
                        DefiniteAssignmentBitSet try_fc = res ? null : fc.DefiniteAssignment;
 
                        foreach (var c in clauses) {
-                               fc.DefiniteAssignment = new DefiniteAssignmentBitSet (start_fc);
+                               fc.BranchDefiniteAssignment (start_fc);
                                if (!c.FlowAnalysis (fc)) {
                                        if (try_fc == null)
                                                try_fc = fc.DefiniteAssignment;