From 3e9d7d6e9cf8dc33eb29c497c350a1cd7df3a057 Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Thu, 5 Oct 2017 10:28:06 +0200 Subject: [PATCH] [mcs] Fixes codegen for pattern probing with value-type variables --- mcs/mcs/expression.cs | 79 +++++++++++++++++++--------- mcs/mcs/statement.cs | 2 + mcs/tests/test-pattern-10.cs | 31 +++++++++++ mcs/tests/test-pattern-11.cs | 15 ++++++ mcs/tests/test-pattern-12.cs | 38 ++++++++++++++ mcs/tests/ver-il-net_4_x.xml | 99 ++++++++++++++++++++++++++++++++++-- 6 files changed, 235 insertions(+), 29 deletions(-) create mode 100644 mcs/tests/test-pattern-10.cs create mode 100644 mcs/tests/test-pattern-11.cs create mode 100644 mcs/tests/test-pattern-12.cs diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 89207a3b54a..732ee3ee934 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -1676,8 +1676,6 @@ namespace Mono.CSharp void EmitLoad (EmitContext ec) { - Label no_value_label = new Label (); - if (expr_unwrap != null) { expr_unwrap.EmitCheck (ec); @@ -1685,44 +1683,76 @@ namespace Mono.CSharp return; ec.Emit (OpCodes.Dup); - no_value_label = ec.DefineLabel (); + var no_value_label = ec.DefineLabel (); ec.Emit (OpCodes.Brfalse_S, no_value_label); if (Variable.HoistedVariant != null) ec.EmitThis (); expr_unwrap.Emit (ec); - } else { - if (Variable?.HoistedVariant != null) - ec.EmitThis (); - expr.Emit (ec); + if (Variable.HoistedVariant != null) { + Variable.HoistedVariant.EmitAssignFromStack (ec); + } else { + // + // It's ok to have variable builder created out of order. It simplifies emit + // of statements like while (condition) { } + // + if (!Variable.Created) + Variable.CreateBuilder (ec); - // Only to make verifier happy - if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type)) - ec.Emit (OpCodes.Box, expr.Type); + Variable.EmitAssign (ec); + } - ec.Emit (OpCodes.Isinst, probe_type_expr); + ec.MarkLabel (no_value_label); + return; } + expr.Emit (ec); + + bool vtype_variable = Variable != null && (probe_type_expr.IsGenericParameter || TypeSpec.IsValueType (ProbeType.Type)); + LocalBuilder expr_copy = null; + + if (vtype_variable && !ExpressionAnalyzer.IsInexpensiveLoad (expr)) { + expr_copy = ec.GetTemporaryLocal (expr.Type); + ec.Emit (OpCodes.Stloc, expr_copy); + ec.Emit (OpCodes.Ldloc, expr_copy); + } else if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type)) { + // + // Only to make verifier happy + // + ec.Emit (OpCodes.Box, expr.Type); + } + + ec.Emit (OpCodes.Isinst, probe_type_expr); + if (Variable != null) { - bool value_on_stack; - if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) { - ec.Emit (OpCodes.Dup); + ec.Emit (OpCodes.Dup); + + var nonmatching_label = ec.DefineLabel (); + ec.Emit (OpCodes.Brfalse_S, nonmatching_label); + + if (vtype_variable) { + if (expr_copy != null) { + ec.Emit (OpCodes.Ldloc, expr_copy); + ec.FreeTemporaryLocal (expr_copy, expr.Type); + } else { + expr.Emit (ec); + } + ec.Emit (OpCodes.Unbox_Any, probe_type_expr); - value_on_stack = true; } else { - value_on_stack = false; + // Already on the stack } if (Variable.HoistedVariant != null) { - Variable.HoistedVariant.EmitAssignFromStack (ec); + var temp = new LocalTemporary (ProbeType.Type); + temp.Store (ec); + Variable.HoistedVariant.EmitAssign (ec, temp, false, false); + temp.Release (ec); - if (expr_unwrap != null) { - ec.MarkLabel (no_value_label); - } else if (!value_on_stack) { + if (!vtype_variable) Variable.HoistedVariant.Emit (ec); - } } else { // // It's ok to have variable builder created out of order. It simplifies emit @@ -1733,12 +1763,11 @@ namespace Mono.CSharp Variable.EmitAssign (ec); - if (expr_unwrap != null) { - ec.MarkLabel (no_value_label); - } else if (!value_on_stack) { + if (!vtype_variable) Variable.Emit (ec); - } } + + ec.MarkLabel (nonmatching_label); } } diff --git a/mcs/mcs/statement.cs b/mcs/mcs/statement.cs index 369343a5df7..58ba2795e4b 100644 --- a/mcs/mcs/statement.cs +++ b/mcs/mcs/statement.cs @@ -774,6 +774,8 @@ namespace Mono.CSharp { ec.Emit (OpCodes.Br, test); ec.MarkLabel (loop); + + Condition?.EmitPrepare (ec); Statement.Emit (ec); ec.MarkLabel (ec.LoopBegin); diff --git a/mcs/tests/test-pattern-10.cs b/mcs/tests/test-pattern-10.cs new file mode 100644 index 00000000000..967600e189c --- /dev/null +++ b/mcs/tests/test-pattern-10.cs @@ -0,0 +1,31 @@ +using System; + +class X +{ + public static int Main () + { + Test (null); + if (Test ((long) 0) != 1) + return 1; + + object o = "aa"; + if (o != null) { + if (o is long s) { + Console.WriteLine (s); + } + } else if (o is string s) { + Console.WriteLine (s); + } + + return 0; + } + + static int Test (object o) + { + if (o is long s) { + return 1; + } + + return 0; + } +} \ No newline at end of file diff --git a/mcs/tests/test-pattern-11.cs b/mcs/tests/test-pattern-11.cs new file mode 100644 index 00000000000..bc889512668 --- /dev/null +++ b/mcs/tests/test-pattern-11.cs @@ -0,0 +1,15 @@ +using System; + +class X +{ + public static int Main () + { + object o = null; + for (o = "abcd"; o is String s; o = null) { + Console.WriteLine (s); + } + + + return 0; + } +} \ No newline at end of file diff --git a/mcs/tests/test-pattern-12.cs b/mcs/tests/test-pattern-12.cs new file mode 100644 index 00000000000..19f39f190b4 --- /dev/null +++ b/mcs/tests/test-pattern-12.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; + +class X +{ + public static int Main () + { + foreach (var x in Test1 ("2")) + { + Console.WriteLine (x); + return 1; + } + + foreach (var x in Test2 (2)) + { + Console.WriteLine (x); + return 2; + } + + return 0; + } + + public static IEnumerable Test1 (object expr) + { + if (expr is short list) + { + yield return "list.Length"; + } + } + + public static IEnumerable Test2 (object expr) + { + if (expr is string list) + { + yield return "list.Length"; + } + } +} \ 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 636afd18a00..c2c98123305 100644 --- a/mcs/tests/ver-il-net_4_x.xml +++ b/mcs/tests/ver-il-net_4_x.xml @@ -72291,16 +72291,16 @@ - 118 + 124 7 - 24 + 32 - 39 + 42 @@ -72403,7 +72403,7 @@ - 124 + 129 14 @@ -72454,6 +72454,97 @@ + + + + 114 + + + 39 + + + 7 + + + + + + + 49 + + + 7 + + + + + + + 160 + + + 30 + + + 30 + + + 7 + + + + + 106 + + + 14 + + + 14 + + + 15 + + + 6 + + + 14 + + + 40 + + + 7 + + + + + 99 + + + 14 + + + 14 + + + 15 + + + 6 + + + 14 + + + 40 + + + 7 + + + -- 2.25.1