diff options
author | Marek Safar <marek.safar@gmail.com> | 2017-02-23 14:29:13 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2017-02-23 14:30:42 +0300 |
commit | f1fa4ecd4d6adf617676bc8d1f257bdf53e05979 (patch) | |
tree | 9febd1b832527a4fc572142221f32e7ec20e1954 | |
parent | 421088dfcee556c01b407a61eee1895532dfe9a4 (diff) |
[mcs] Emit leave for redirected jumps out of rewritten finally exit scope. Fixes #52599
-rw-r--r-- | mcs/mcs/statement.cs | 58 | ||||
-rw-r--r-- | mcs/tests/test-async-91.cs | 38 | ||||
-rw-r--r-- | mcs/tests/ver-il-net_4_x.xml | 47 |
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+<TestFinallyWithReturn>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+<TestFinallyWithReturnNoValue>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+<TestFinallyWithGoto>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+<TestFinallyWithGotoAndReturn>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+<TestNestedReturn>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+<TestNestedGoto>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+<BreakTest>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+<ContinueTest>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+<Test>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+<Test>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"> |