Skip to content

Commit

Permalink
[mcs] Clone labeled statements cache in probing mode. Fixes #16376
Browse files Browse the repository at this point in the history
  • Loading branch information
marek-safar committed Dec 11, 2013
1 parent 42f7b0b commit f7f54fa
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 32 deletions.
16 changes: 16 additions & 0 deletions mcs/class/Mono.CSharp/Test/Evaluator/ExpressionsTest.cs
Expand Up @@ -130,6 +130,22 @@ public void PartialExpression ()
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 ()
Expand Down
122 changes: 90 additions & 32 deletions mcs/mcs/statement.cs
Expand Up @@ -2809,7 +2809,7 @@ public void AddStatement (Statement s)

public LabeledStatement LookupLabel (string name)
{
return ParametersBlock.TopBlock.GetLabel (name, this);
return ParametersBlock.GetLabel (name, this);
}

public override Reachability MarkReachable (Reachability rc)
Expand Down Expand Up @@ -3480,6 +3480,7 @@ public override void Emit (EmitContext ec)
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)
Expand Down Expand Up @@ -3608,6 +3609,46 @@ public virtual void CheckControlExit (FlowAnalysisContext fc, DefiniteAssignment
}
}

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) {
Expand Down Expand Up @@ -3651,6 +3692,43 @@ protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
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) {
Expand Down Expand Up @@ -3690,6 +3768,17 @@ protected void ProcessParameters ()
}
}

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)
Expand Down Expand Up @@ -3825,7 +3914,6 @@ public class ToplevelBlock : ParametersBlock
LocalVariable this_variable;
CompilerContext compiler;
Dictionary<string, object> names;
Dictionary<string, object> labels;

List<ExplicitBlock> this_references;

Expand Down Expand Up @@ -4116,36 +4204,6 @@ public bool GetLocalName (string name, Block block, ref INamedBlockVariable vari
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
Expand Down

0 comments on commit f7f54fa

Please sign in to comment.