Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2017-02-23 14:29:13 +0300
committerMarek Safar <marek.safar@gmail.com>2017-02-23 14:30:42 +0300
commitf1fa4ecd4d6adf617676bc8d1f257bdf53e05979 (patch)
tree9febd1b832527a4fc572142221f32e7ec20e1954
parent421088dfcee556c01b407a61eee1895532dfe9a4 (diff)
[mcs] Emit leave for redirected jumps out of rewritten finally exit scope. Fixes #52599
-rw-r--r--mcs/mcs/statement.cs58
-rw-r--r--mcs/tests/test-async-91.cs38
-rw-r--r--mcs/tests/ver-il-net_4_x.xml47
3 files changed, 117 insertions, 26 deletions
diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs
index fbb060f5296..4f67eb3240f 100644
--- a/mcs/mcs/statement.cs
+++ b/mcs/mcs/statement.cs
@@ -1301,7 +1301,7 @@ namespace Mono.CSharp {
// Special case hoisted return value (happens in try/finally scenario)
//
if (ec.TryFinallyUnwind != null) {
- exit_label = TryFinally.EmitRedirectedReturn (ec, async_body);
+ exit_label = TryFinally.EmitRedirectedReturn (ec, async_body, unwind_protect);
}
var async_return = (IAssignMethod)storey.HoistedReturnValue;
@@ -1311,7 +1311,7 @@ namespace Mono.CSharp {
expr.Emit (ec);
if (ec.TryFinallyUnwind != null)
- exit_label = TryFinally.EmitRedirectedReturn (ec, async_body);
+ exit_label = TryFinally.EmitRedirectedReturn (ec, async_body, unwind_protect);
}
ec.Emit (OpCodes.Leave, exit_label);
@@ -1460,7 +1460,7 @@ namespace Mono.CSharp {
if (ec.TryFinallyUnwind != null && IsLeavingFinally (label.Block)) {
var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
- l = TryFinally.EmitRedirectedJump (ec, async_body, l, label.Block);
+ l = TryFinally.EmitRedirectedJump (ec, async_body, l, label.Block, unwind_protect);
}
ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
@@ -1867,7 +1867,7 @@ namespace Mono.CSharp {
if (ec.TryFinallyUnwind != null) {
var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
- l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block);
+ l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block, unwind_protect);
}
ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
@@ -1915,7 +1915,7 @@ namespace Mono.CSharp {
if (ec.TryFinallyUnwind != null) {
var async_body = (AsyncInitializer) ec.CurrentAnonymousMethod;
- l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block);
+ l = TryFinally.EmitRedirectedJump (ec, async_body, l, enclosing_loop.Statement as Block, unwind_protect);
}
ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
@@ -6997,7 +6997,7 @@ namespace Mono.CSharp {
{
ExplicitBlock fini;
List<DefiniteAssignmentBitSet> try_exit_dat;
- List<Label> redirected_jumps;
+ List<Tuple<Label, bool>> redirected_jumps;
Label? start_fin_label;
public TryFinally (Statement stmt, ExplicitBlock fini, Location loc)
@@ -7123,7 +7123,7 @@ namespace Mono.CSharp {
return false;
}
- public static Label EmitRedirectedJump (EmitContext ec, AsyncInitializer initializer, Label label, Block labelBlock)
+ public static Label EmitRedirectedJump (EmitContext ec, AsyncInitializer initializer, Label label, Block labelBlock, bool unwindProtect)
{
int idx;
if (labelBlock != null) {
@@ -7143,7 +7143,7 @@ namespace Mono.CSharp {
if (labelBlock != null && !fin.IsParentBlock (labelBlock))
break;
- fin.EmitRedirectedExit (ec, label, initializer, set_return_state);
+ fin.EmitRedirectedExit (ec, label, initializer, set_return_state, unwindProtect);
set_return_state = false;
if (fin.start_fin_label == null) {
@@ -7156,26 +7156,26 @@ namespace Mono.CSharp {
return label;
}
- public static Label EmitRedirectedReturn (EmitContext ec, AsyncInitializer initializer)
+ public static Label EmitRedirectedReturn (EmitContext ec, AsyncInitializer initializer, bool unwindProtect)
{
- return EmitRedirectedJump (ec, initializer, initializer.BodyEnd, null);
+ return EmitRedirectedJump (ec, initializer, initializer.BodyEnd, null, unwindProtect);
}
- void EmitRedirectedExit (EmitContext ec, Label label, AsyncInitializer initializer, bool setReturnState)
+ void EmitRedirectedExit (EmitContext ec, Label label, AsyncInitializer initializer, bool setReturnState, bool unwindProtect)
{
if (redirected_jumps == null) {
- redirected_jumps = new List<Label> ();
+ redirected_jumps = new List<Tuple<Label, bool>> ();
// Add fallthrough label
- redirected_jumps.Add (ec.DefineLabel ());
+ redirected_jumps.Add (Tuple.Create (ec.DefineLabel (), false));
if (setReturnState)
initializer.HoistedReturnState = ec.GetTemporaryField (ec.Module.Compiler.BuiltinTypes.Int, true);
}
- int index = redirected_jumps.IndexOf (label);
+ int index = redirected_jumps.FindIndex (l => l.Item1 == label);
if (index < 0) {
- redirected_jumps.Add (label);
+ redirected_jumps.Add (Tuple.Create (label, unwindProtect));
index = redirected_jumps.Count - 1;
}
@@ -7199,10 +7199,34 @@ namespace Mono.CSharp {
var initializer = (AsyncInitializer)ec.CurrentAnonymousMethod;
initializer.HoistedReturnState.EmitLoad (ec);
- ec.Emit (OpCodes.Switch, redirected_jumps.ToArray ());
+
+ var jumps_table = new Label [redirected_jumps.Count];
+ List<Tuple<Label, Label>> leave_redirect = null;
+ for (int i = 0; i < jumps_table.Length; ++i) {
+ var val = redirected_jumps [i];
+
+ if (val.Item2) {
+ if (leave_redirect == null)
+ leave_redirect = new List<Tuple<Label, Label>> ();
+ var label = ec.DefineLabel ();
+ leave_redirect.Add (Tuple.Create (label, val.Item1));
+ jumps_table [i] = label;
+ } else {
+ jumps_table [i] = val.Item1;
+ }
+ }
+
+ ec.Emit (OpCodes.Switch, jumps_table);
+
+ if (leave_redirect != null) {
+ foreach (var entry in leave_redirect) {
+ ec.MarkLabel (entry.Item1);
+ ec.Emit (OpCodes.Leave, entry.Item2);
+ }
+ }
// Mark fallthrough label
- ec.MarkLabel (redirected_jumps [0]);
+ ec.MarkLabel (jumps_table [0]);
}
protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
diff --git a/mcs/tests/test-async-91.cs b/mcs/tests/test-async-91.cs
new file mode 100644
index 00000000000..405da3c3f92
--- /dev/null
+++ b/mcs/tests/test-async-91.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Threading.Tasks;
+
+class C : IDisposable
+{
+ public void Dispose ()
+ {
+ Console.WriteLine ("Disposed");
+ TestClass.Passed++;
+ }
+}
+
+public class TestClass
+{
+ public static int Passed;
+
+ public static async Task Test ()
+ {
+ using (var device_resource = new C ()) {
+ try {
+ Console.WriteLine ("aa");
+ return;
+ } finally {
+ await Task.Delay (0);
+ }
+ }
+ }
+
+ public static int Main()
+ {
+ Test ().Wait ();
+ if (Passed != 1)
+ return 1;
+
+ Console.WriteLine ("PASSED");
+ return 0;
+ }
+} \ No newline at end of file
diff --git a/mcs/tests/ver-il-net_4_x.xml b/mcs/tests/ver-il-net_4_x.xml
index 97e730296b7..58af2896f16 100644
--- a/mcs/tests/ver-il-net_4_x.xml
+++ b/mcs/tests/ver-il-net_4_x.xml
@@ -65761,7 +65761,7 @@
</type>
<type name="Test+&lt;TestFinallyWithReturn&gt;c__async1">
<method name="Void MoveNext()" attrs="486">
- <size>377</size>
+ <size>382</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -65769,7 +65769,7 @@
</type>
<type name="Test+&lt;TestFinallyWithReturnNoValue&gt;c__async2">
<method name="Void MoveNext()" attrs="486">
- <size>347</size>
+ <size>352</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -65777,7 +65777,7 @@
</type>
<type name="Test+&lt;TestFinallyWithGoto&gt;c__async3">
<method name="Void MoveNext()" attrs="486">
- <size>370</size>
+ <size>375</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -65785,7 +65785,7 @@
</type>
<type name="Test+&lt;TestFinallyWithGotoAndReturn&gt;c__async4">
<method name="Void MoveNext()" attrs="486">
- <size>407</size>
+ <size>417</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -65820,7 +65820,7 @@
</type>
<type name="Test+&lt;TestNestedReturn&gt;c__async1">
<method name="Void MoveNext()" attrs="486">
- <size>845</size>
+ <size>855</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -65828,7 +65828,7 @@
</type>
<type name="Test+&lt;TestNestedGoto&gt;c__async2">
<method name="Void MoveNext()" attrs="486">
- <size>848</size>
+ <size>858</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -65884,7 +65884,7 @@
</type>
<type name="Test+&lt;BreakTest&gt;c__async1">
<method name="Void MoveNext()" attrs="486">
- <size>898</size>
+ <size>903</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -65892,7 +65892,7 @@
</type>
<type name="Test+&lt;ContinueTest&gt;c__async2">
<method name="Void MoveNext()" attrs="486">
- <size>898</size>
+ <size>903</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -66269,7 +66269,7 @@
</type>
<type name="X+&lt;Test&gt;c__async0">
<method name="Void MoveNext()" attrs="486">
- <size>269</size>
+ <size>274</size>
</method>
<method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
<size>13</size>
@@ -66612,6 +66612,35 @@
</method>
</type>
</test>
+ <test name="test-async-91.cs">
+ <type name="C">
+ <method name="Void Dispose()" attrs="486">
+ <size>24</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="TestClass">
+ <method name="System.Threading.Tasks.Task Test()" attrs="150">
+ <size>33</size>
+ </method>
+ <method name="Int32 Main()" attrs="150">
+ <size>48</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="TestClass+&lt;Test&gt;c__async0">
+ <method name="Void MoveNext()" attrs="486">
+ <size>309</size>
+ </method>
+ <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">
+ <size>13</size>
+ </method>
+ </type>
+ </test>
<test name="test-cls-00.cs">
<type name="CLSCLass_6">
<method name="Void add_Disposed(Delegate)" attrs="2182">