[mcs] Clone labeled statements cache in probing mode. Fixes #16376
authorMarek Safar <marek.safar@gmail.com>
Wed, 11 Dec 2013 16:51:16 +0000 (17:51 +0100)
committerMarek Safar <marek.safar@gmail.com>
Wed, 11 Dec 2013 19:03:17 +0000 (20:03 +0100)
mcs/class/Mono.CSharp/Test/Evaluator/ExpressionsTest.cs
mcs/mcs/statement.cs

index 9732b655d2031f5b893cdcb96da04b6cce4b85b4..feb4294647f45a19f3ee62846f471a890bd8ed16 100644 (file)
@@ -130,6 +130,22 @@ namespace MonoTests.EvaluatorTest
                        Assert.AreEqual ("1+", sres, "The result should have been the input string, since we have a partial input");
                }
 
+               [Test]
+               public void GotoWithUnreachableStatement ()
+               {
+                       Evaluator.Run ("using System;");
+
+                       string code = "var x = new Action(() => {" +
+                       "Console.WriteLine(\"beforeGoto\");" +
+                       "goto L;" +
+               "L:" +
+                       "Console.WriteLine(\"afterGoto\");" +
+                       "});";
+
+                       Assert.IsTrue (Evaluator.Run (code), "#1");
+                       Assert.IsTrue (Evaluator.Run ("x();"), "#2");
+               }
+
 #if NET_4_0
                [Test]
                public void DynamicStatement ()
index 9f7b41e4e3cbcd03e5a28eceaa305d10e4fc007f..7090c4a7aefb05e22389c3728c0b2250e10bd39b 100644 (file)
@@ -2809,7 +2809,7 @@ namespace Mono.CSharp {
 
                public LabeledStatement LookupLabel (string name)
                {
-                       return ParametersBlock.TopBlock.GetLabel (name, this);
+                       return ParametersBlock.GetLabel (name, this);
                }
 
                public override Reachability MarkReachable (Reachability rc)
@@ -3480,6 +3480,7 @@ namespace Mono.CSharp {
                protected bool resolved;
                protected ToplevelBlock top_block;
                protected StateMachine state_machine;
+               protected Dictionary<string, object> labels;
 
                public ParametersBlock (Block parent, ParametersCompiled parameters, Location start, Flags flags = 0)
                        : base (parent, 0, start, start)
@@ -3608,6 +3609,46 @@ namespace Mono.CSharp {
                        }                                       
                }
 
+               protected override void CloneTo (CloneContext clonectx, Statement t)
+               {
+                       base.CloneTo (clonectx, t);
+
+                       var target = (ParametersBlock) t;
+
+                       //
+                       // Clone label statements as well as they contain block reference
+                       //
+                       var pb = this;
+                       while (true) {
+                               if (pb.labels != null) {
+                                       target.labels = new Dictionary<string, object> ();
+
+                                       foreach (var entry in pb.labels) {
+                                               var list = entry.Value as List<LabeledStatement>;
+
+                                               if (list != null) {
+                                                       var list_clone = new List<LabeledStatement> ();
+                                                       foreach (var lentry in list) {
+                                                               list_clone.Add (RemapLabeledStatement (lentry, lentry.Block, clonectx.RemapBlockCopy (lentry.Block)));
+                                                       }
+
+                                                       target.labels.Add (entry.Key, list_clone);
+                                               } else {
+                                                       var labeled = (LabeledStatement) entry.Value;
+                                                       target.labels.Add (entry.Key, RemapLabeledStatement (labeled, labeled.Block, clonectx.RemapBlockCopy (labeled.Block)));
+                                               }
+                                       }
+
+                                       break;
+                               }
+
+                               if (pb.Parent == null)
+                                       break;
+
+                               pb = pb.Parent.ParametersBlock;
+                       }
+               }
+
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
                        if (statements.Count == 1) {
@@ -3651,6 +3692,43 @@ namespace Mono.CSharp {
                        return res;
                }
 
+               public LabeledStatement GetLabel (string name, Block block)
+               {
+                       //
+                       // Cloned parameters blocks can have their own cloned version of top-level labels
+                       //
+                       if (labels == null) {
+                               if (Parent != null)
+                                       return Parent.ParametersBlock.GetLabel (name, block);
+
+                               return null;
+                       }
+
+                       object value;
+                       if (!labels.TryGetValue (name, out value)) {
+                               return null;
+                       }
+
+                       var label = value as LabeledStatement;
+                       Block b = block;
+                       if (label != null) {
+                               do {
+                                       if (label.Block == b)
+                                               return label;
+                                       b = b.Parent;
+                               } while (b != null);
+                       } else {
+                               List<LabeledStatement> list = (List<LabeledStatement>) value;
+                               for (int i = 0; i < list.Count; ++i) {
+                                       label = list[i];
+                                       if (label.Block == b)
+                                               return label;
+                               }
+                       }
+
+                       return null;
+               }
+
                public ParameterInfo GetParameterInfo (Parameter p)
                {
                        for (int i = 0; i < parameters.Count; ++i) {
@@ -3690,6 +3768,17 @@ namespace Mono.CSharp {
                        }
                }
 
+               static LabeledStatement RemapLabeledStatement (LabeledStatement stmt, Block src, Block dst)
+               {
+                       var src_stmts = src.Statements;
+                       for (int i = 0; i < src_stmts.Count; ++i) {
+                               if (src_stmts[i] == stmt)
+                                       return (LabeledStatement) dst.Statements[i];
+                       }
+
+                       throw new InternalErrorException ("Should never be reached");
+               }
+
                public override bool Resolve (BlockContext bc)
                {
                        // TODO: if ((flags & Flags.Resolved) != 0)
@@ -3825,7 +3914,6 @@ namespace Mono.CSharp {
                LocalVariable this_variable;
                CompilerContext compiler;
                Dictionary<string, object> names;
-               Dictionary<string, object> labels;
 
                List<ExplicitBlock> this_references;
 
@@ -4116,36 +4204,6 @@ namespace Mono.CSharp {
                        return false;
                }
 
-               public LabeledStatement GetLabel (string name, Block block)
-               {
-                       if (labels == null)
-                               return null;
-
-                       object value;
-                       if (!labels.TryGetValue (name, out value)) {
-                               return null;
-                       }
-
-                       var label = value as LabeledStatement;
-                       Block b = block;
-                       if (label != null) {
-                               do {
-                                       if (label.Block == b.Original)
-                                               return label;
-                                       b = b.Parent;
-                               } while (b != null);
-                       } 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;
-                               }
-                       }
-                               
-                       return null;
-               }
-
                // <summary>
                //   This is used by non-static `struct' constructors which do not have an
                //   initializer - in this case, the constructor must initialize all of the