From 644941d25be795b6f4acd936057c76021cecf784 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 11 May 2018 01:08:54 +0200 Subject: [PATCH] Fix C# 1.0 switch on string transform and add tests --- .../ILPrettyTestRunner.cs | 12 + .../TestCases/ILPretty/CS1xSwitch_Debug.cs | 412 +++++ .../TestCases/ILPretty/CS1xSwitch_Debug.il | 1425 +++++++++++++++++ .../TestCases/ILPretty/CS1xSwitch_Release.cs | 412 +++++ .../TestCases/ILPretty/CS1xSwitch_Release.il | 1325 +++++++++++++++ .../CSharp/CSharpDecompiler.cs | 7 +- .../IL/Transforms/SwitchOnStringTransform.cs | 290 +++- 7 files changed, 3837 insertions(+), 46 deletions(-) create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.cs create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.il create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.cs create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.il diff --git a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs index 6abcf5620..30defe919 100644 --- a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs @@ -94,6 +94,18 @@ namespace ICSharpCode.Decompiler.Tests Run(settings: new DecompilerSettings { RemoveDeadCode = true }); } + [Test] + public void CS1xSwitch_Debug() + { + Run(); + } + + [Test] + public void CS1xSwitch_Release() + { + Run(); + } + [Test, Ignore("?")] public void FSharpLoops_Debug() { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.cs new file mode 100644 index 000000000..d927e3fd0 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.cs @@ -0,0 +1,412 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections; +using System.Reflection; + +namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty +{ + public class Switch + { + public class SetProperty + { + public readonly PropertyInfo Property; + private int _set; + + public int Set { + get { + return _set; + } + + set { + _set = value; + } + } + + public SetProperty(PropertyInfo property) + { + Property = property; + } + } + + public enum State + { + False, + True, + Null + } + + public static string SparseIntegerSwitch(int i) + { + Console.WriteLine("SparseIntegerSwitch: " + i); + switch (i) { + case -10000000: + return "-10 mln"; + case -100: + return "-hundred"; + case -1: + return "-1"; + case 0: + return "0"; + case 1: + return "1"; + case 2: + return "2"; + case 4: + return "4"; + case 100: + return "hundred"; + case 10000: + return "ten thousand"; + case 10001: + return "ten thousand and one"; + case int.MaxValue: + return "int.MaxValue"; + default: + return "something else"; + } + } + + public static void SwitchOverInt(int i) + { + switch (i) { + case 0: + Console.WriteLine("zero"); + break; + case 5: + Console.WriteLine("five"); + break; + case 10: + Console.WriteLine("ten"); + break; + case 15: + Console.WriteLine("fifteen"); + break; + case 20: + Console.WriteLine("twenty"); + break; + case 25: + Console.WriteLine("twenty-five"); + break; + case 30: + Console.WriteLine("thirty"); + break; + } + } + + public static string ShortSwitchOverString(string text) + { + Console.WriteLine("ShortSwitchOverString: " + text); + switch (text) { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case "Third case": + return "Text3"; + default: + return "Default"; + } + } + + public static string ShortSwitchOverStringWithNullCase(string text) + { + Console.WriteLine("ShortSwitchOverStringWithNullCase: " + text); + switch (text) { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case null: + return "null"; + default: + return "Default"; + } + } + + public static string SwitchOverString1(string text) + { + Console.WriteLine("SwitchOverString1: " + text); + switch (text) { + case "First case": + return "Text1"; + case "Second case": + case "2nd case": + return "Text2"; + case "Third case": + return "Text3"; + case "Fourth case": + return "Text4"; + case "Fifth case": + return "Text5"; + case "Sixth case": + return "Text6"; + case null: + return null; + default: + return "Default"; + } + } + + public static string SwitchOverString2() + { + Console.WriteLine("SwitchOverString2:"); + switch (Environment.UserName) { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case "Third case": + return "Text3"; + case "Fourth case": + return "Text4"; + case "Fifth case": + return "Text5"; + case "Sixth case": + return "Text6"; + case "Seventh case": + return "Text7"; + case "Eighth case": + return "Text8"; + case "Ninth case": + return "Text9"; + case "Tenth case": + return "Text10"; + case "Eleventh case": + return "Text11"; + default: + return "Default"; + } + } + + public static string TwoDifferentSwitchBlocksInTryFinally() + { + try { + Console.WriteLine("TwoDifferentSwitchBlocks:"); + switch (Environment.UserName) { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case "Third case": + return "Text3"; + case "Fourth case": + return "Text4"; + case "Fifth case": + return "Text5"; + case "Sixth case": + return "Text6"; + case "Seventh case": + return "Text7"; + case "Eighth case": + return "Text8"; + case "Ninth case": + return "Text9"; + case "Tenth case": + return "Text10"; + case "Eleventh case": + return "Text11"; + default: + return "Default"; + } + } finally { + Console.WriteLine("Second switch:"); + switch (Console.ReadLine()) { + case "12": + Console.WriteLine("Te43234xt1"); + break; + case "13": + Console.WriteLine("Te223443xt2"); + break; + case "14": + Console.WriteLine("Te234xt3"); + break; + case "15": + Console.WriteLine("Tex243t4"); + break; + case "16": + Console.WriteLine("Tex243t5"); + break; + case "17": + Console.WriteLine("Text2346"); + break; + case "18": + Console.WriteLine("Text234234"); + break; + case "19 case": + Console.WriteLine("Text8234"); + break; + case "20 case": + Console.WriteLine("Text923423"); + break; + case "21 case": + Console.WriteLine("Text10"); + break; + case "22 case": + Console.WriteLine("Text1134123"); + break; + default: + Console.WriteLine("Defa234234ult"); + break; + } + } + } + + public static string SwitchOverBool(bool b) + { + Console.WriteLine("SwitchOverBool: " + b.ToString()); + switch (b) { + case true: + return bool.TrueString; + case false: + return bool.FalseString; + default: + return null; + } + } + + public static void SwitchInLoop(int i) + { + Console.WriteLine("SwitchInLoop: " + i); + while (true) { + switch (i) { + case 1: + Console.WriteLine("one"); + break; + case 2: + Console.WriteLine("two"); + break; + //case 3: + // Console.WriteLine("three"); + // continue; + case 4: + Console.WriteLine("four"); + return; + default: + Console.WriteLine("default"); + Console.WriteLine("more code"); + return; + } + i++; + } + } + + public static void SwitchWithGoto(int i) + { + Console.WriteLine("SwitchWithGoto: " + i); + switch (i) { + case 1: + Console.WriteLine("one"); + goto default; + case 2: + Console.WriteLine("two"); + goto case 3; + case 3: + Console.WriteLine("three"); + break; + case 4: + Console.WriteLine("four"); + return; + default: + Console.WriteLine("default"); + break; + } + Console.WriteLine("End of method"); + } + + private static SetProperty[] GetProperties() + { + return new SetProperty[0]; + } + + public static void SwitchOnStringInForLoop() + { + ArrayList arrayList = new ArrayList(); + ArrayList arrayList2 = new ArrayList(); + SetProperty[] properties = GetProperties(); + for (int i = 0; i < properties.Length; i++) { + Console.WriteLine("In for-loop"); + SetProperty setProperty = properties[i]; + switch (setProperty.Property.Name) { + case "Name1": + setProperty.Set = 1; + arrayList.Add(setProperty); + break; + case "Name2": + setProperty.Set = 2; + arrayList.Add(setProperty); + break; + case "Name3": + setProperty.Set = 3; + arrayList.Add(setProperty); + break; + case "Name4": + setProperty.Set = 4; + arrayList.Add(setProperty); + break; + case "Name5": + case "Name6": + arrayList.Add(setProperty); + break; + default: + arrayList2.Add(setProperty); + break; + } + } + } + + public static void SwitchWithComplexCondition(string[] args) + { + switch ((args.Length == 0) ? "dummy" : args[0]) { + case "a": + Console.WriteLine("a"); + break; + case "b": + Console.WriteLine("b"); + break; + case "c": + Console.WriteLine("c"); + break; + case "d": + Console.WriteLine("d"); + break; + } + Console.WriteLine("end"); + } + + public static void SwitchWithArray(string[] args) + { + switch (args[0]) { + case "a": + Console.WriteLine("a"); + break; + case "b": + Console.WriteLine("b"); + break; + case "c": + Console.WriteLine("c"); + break; + case "d": + Console.WriteLine("d"); + break; + } + Console.WriteLine("end"); + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.il b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.il new file mode 100644 index 000000000..86c960186 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Debug.il @@ -0,0 +1,1425 @@ + +// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0 +// Copyright (c) Microsoft Corporation. All rights reserved. + + + +// Metadata version: v1.1.4322 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 1:0:5000:0 +} +.assembly CS1xSwitch_Debug +{ + + // --- The following custom attribute is added automatically, do not uncomment ------- + // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool, + // bool) = ( 01 00 00 01 00 00 ) + + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module CS1xSwitch_Debug.dll +// MVID: {3797A9DC-06AE-42B7-994E-BDC70F8FF69B} +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY +// Image base: 0x07560000 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch + extends [mscorlib]System.Object +{ + .class auto ansi nested public beforefieldinit SetProperty + extends [mscorlib]System.Object + { + .field public initonly class [mscorlib]System.Reflection.PropertyInfo Property + .field private int32 _set + .method public hidebysig specialname + instance int32 get_Set() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::_set + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method SetProperty::get_Set + + .method public hidebysig specialname + instance void set_Set(int32 'value') cil managed + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::_set + IL_0007: ret + } // end of method SetProperty::set_Set + + .method public hidebysig specialname rtspecialname + instance void .ctor(class [mscorlib]System.Reflection.PropertyInfo 'property') cil managed + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld class [mscorlib]System.Reflection.PropertyInfo ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::Property + IL_000d: ret + } // end of method SetProperty::.ctor + + .property instance int32 Set() + { + .get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::get_Set() + .set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + } // end of property SetProperty::Set + } // end of class SetProperty + + .class auto ansi sealed nested public State + extends [mscorlib]System.Enum + { + .field public specialname rtspecialname int32 value__ + .field public static literal valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State False = int32(0x00000000) + .field public static literal valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State True = int32(0x00000001) + .field public static literal valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State Null = int32(0x00000002) + } // end of class State + + .method public hidebysig static string + SparseIntegerSwitch(int32 i) cil managed + { + // Code size 207 (0xcf) + .maxstack 2 + .locals init (string V_0, + int32 V_1) + IL_0000: ldstr "SparseIntegerSwitch: " + IL_0005: ldarg.0 + IL_0006: box [mscorlib]System.Int32 + IL_000b: call string [mscorlib]System.String::Concat(object, + object) + IL_0010: call void [mscorlib]System.Console::WriteLine(string) + IL_0015: ldarg.0 + IL_0016: stloc.1 + IL_0017: ldloc.1 + IL_0018: ldc.i4.4 + IL_0019: bgt.s IL_004a + + IL_001b: ldloc.1 + IL_001c: ldc.i4 0xff676980 + IL_0021: beq.s IL_006d + + IL_0023: ldloc.1 + IL_0024: ldc.i4.s -100 + IL_0026: beq.s IL_0075 + + IL_0028: ldloc.1 + IL_0029: ldc.i4.m1 + IL_002a: sub + IL_002b: switch ( + IL_007d, + IL_0085, + IL_008d, + IL_0095, + IL_00c5, + IL_009d) + IL_0048: br.s IL_00c5 + + IL_004a: ldloc.1 + IL_004b: ldc.i4.s 100 + IL_004d: beq.s IL_00a5 + + IL_004f: ldloc.1 + IL_0050: ldc.i4 0x2710 + IL_0055: sub + IL_0056: switch ( + IL_00ad, + IL_00b5) + IL_0063: ldloc.1 + IL_0064: ldc.i4 0x7fffffff + IL_0069: beq.s IL_00bd + + IL_006b: br.s IL_00c5 + + IL_006d: ldstr "-10 mln" + IL_0072: stloc.0 + IL_0073: br.s IL_00cd + + IL_0075: ldstr "-hundred" + IL_007a: stloc.0 + IL_007b: br.s IL_00cd + + IL_007d: ldstr "-1" + IL_0082: stloc.0 + IL_0083: br.s IL_00cd + + IL_0085: ldstr "0" + IL_008a: stloc.0 + IL_008b: br.s IL_00cd + + IL_008d: ldstr "1" + IL_0092: stloc.0 + IL_0093: br.s IL_00cd + + IL_0095: ldstr "2" + IL_009a: stloc.0 + IL_009b: br.s IL_00cd + + IL_009d: ldstr "4" + IL_00a2: stloc.0 + IL_00a3: br.s IL_00cd + + IL_00a5: ldstr "hundred" + IL_00aa: stloc.0 + IL_00ab: br.s IL_00cd + + IL_00ad: ldstr "ten thousand" + IL_00b2: stloc.0 + IL_00b3: br.s IL_00cd + + IL_00b5: ldstr "ten thousand and one" + IL_00ba: stloc.0 + IL_00bb: br.s IL_00cd + + IL_00bd: ldstr "int.MaxValue" + IL_00c2: stloc.0 + IL_00c3: br.s IL_00cd + + IL_00c5: ldstr "something else" + IL_00ca: stloc.0 + IL_00cb: br.s IL_00cd + + IL_00cd: ldloc.0 + IL_00ce: ret + } // end of method Switch::SparseIntegerSwitch + + .method public hidebysig static void SwitchOverInt(int32 i) cil managed + { + // Code size 136 (0x88) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.s 10 + IL_0005: bgt.s IL_0016 + + IL_0007: ldloc.0 + IL_0008: ldc.i4.0 + IL_0009: beq.s IL_0033 + + IL_000b: ldloc.0 + IL_000c: ldc.i4.5 + IL_000d: beq.s IL_003f + + IL_000f: ldloc.0 + IL_0010: ldc.i4.s 10 + IL_0012: beq.s IL_004b + + IL_0014: br.s IL_0087 + + IL_0016: ldloc.0 + IL_0017: ldc.i4.s 20 + IL_0019: bgt.s IL_0027 + + IL_001b: ldloc.0 + IL_001c: ldc.i4.s 15 + IL_001e: beq.s IL_0057 + + IL_0020: ldloc.0 + IL_0021: ldc.i4.s 20 + IL_0023: beq.s IL_0063 + + IL_0025: br.s IL_0087 + + IL_0027: ldloc.0 + IL_0028: ldc.i4.s 25 + IL_002a: beq.s IL_006f + + IL_002c: ldloc.0 + IL_002d: ldc.i4.s 30 + IL_002f: beq.s IL_007b + + IL_0031: br.s IL_0087 + + IL_0033: ldstr "zero" + IL_0038: call void [mscorlib]System.Console::WriteLine(string) + IL_003d: br.s IL_0087 + + IL_003f: ldstr "five" + IL_0044: call void [mscorlib]System.Console::WriteLine(string) + IL_0049: br.s IL_0087 + + IL_004b: ldstr "ten" + IL_0050: call void [mscorlib]System.Console::WriteLine(string) + IL_0055: br.s IL_0087 + + IL_0057: ldstr "fifteen" + IL_005c: call void [mscorlib]System.Console::WriteLine(string) + IL_0061: br.s IL_0087 + + IL_0063: ldstr "twenty" + IL_0068: call void [mscorlib]System.Console::WriteLine(string) + IL_006d: br.s IL_0087 + + IL_006f: ldstr "twenty-five" + IL_0074: call void [mscorlib]System.Console::WriteLine(string) + IL_0079: br.s IL_0087 + + IL_007b: ldstr "thirty" + IL_0080: call void [mscorlib]System.Console::WriteLine(string) + IL_0085: br.s IL_0087 + + IL_0087: ret + } // end of method Switch::SwitchOverInt + + .method public hidebysig static string + ShortSwitchOverString(string text) cil managed + { + // Code size 105 (0x69) + .maxstack 3 + .locals init (string V_0, + string V_1) + IL_0000: ldstr "ShortSwitchOverString: " + IL_0005: ldarg.0 + IL_0006: call string [mscorlib]System.String::Concat(string, + string) + IL_000b: call void [mscorlib]System.Console::WriteLine(string) + IL_0010: ldstr "First case" + IL_0015: ldstr "Second case" + IL_001a: ldstr "Third case" + IL_001f: leave.s IL_0021 + + IL_0021: ldarg.0 + IL_0022: dup + IL_0023: stloc.1 + IL_0024: brfalse.s IL_005f + + IL_0026: ldloc.1 + IL_0027: call string [mscorlib]System.String::IsInterned(string) + IL_002c: stloc.1 + IL_002d: ldloc.1 + IL_002e: ldstr "First case" + IL_0033: beq.s IL_0047 + + IL_0035: ldloc.1 + IL_0036: ldstr "Second case" + IL_003b: beq.s IL_004f + + IL_003d: ldloc.1 + IL_003e: ldstr "Third case" + IL_0043: beq.s IL_0057 + + IL_0045: br.s IL_005f + + IL_0047: ldstr "Text1" + IL_004c: stloc.0 + IL_004d: br.s IL_0067 + + IL_004f: ldstr "Text2" + IL_0054: stloc.0 + IL_0055: br.s IL_0067 + + IL_0057: ldstr "Text3" + IL_005c: stloc.0 + IL_005d: br.s IL_0067 + + IL_005f: ldstr "Default" + IL_0064: stloc.0 + IL_0065: br.s IL_0067 + + IL_0067: ldloc.0 + IL_0068: ret + } // end of method Switch::ShortSwitchOverString + + .method public hidebysig static string + ShortSwitchOverStringWithNullCase(string text) cil managed + { + // Code size 92 (0x5c) + .maxstack 2 + .locals init (string V_0, + string V_1) + IL_0000: ldstr "ShortSwitchOverStringWithNullCase: " + IL_0005: ldarg.0 + IL_0006: call string [mscorlib]System.String::Concat(string, + string) + IL_000b: call void [mscorlib]System.Console::WriteLine(string) + IL_0010: ldstr "First case" + IL_0015: ldstr "Second case" + IL_001a: leave.s IL_001c + + IL_001c: ldarg.0 + IL_001d: dup + IL_001e: stloc.1 + IL_001f: brfalse.s IL_004a + + IL_0021: ldloc.1 + IL_0022: call string [mscorlib]System.String::IsInterned(string) + IL_0027: stloc.1 + IL_0028: ldloc.1 + IL_0029: ldstr "First case" + IL_002e: beq.s IL_003a + + IL_0030: ldloc.1 + IL_0031: ldstr "Second case" + IL_0036: beq.s IL_0042 + + IL_0038: br.s IL_0052 + + IL_003a: ldstr "Text1" + IL_003f: stloc.0 + IL_0040: br.s IL_005a + + IL_0042: ldstr "Text2" + IL_0047: stloc.0 + IL_0048: br.s IL_005a + + IL_004a: ldstr "null" + IL_004f: stloc.0 + IL_0050: br.s IL_005a + + IL_0052: ldstr "Default" + IL_0057: stloc.0 + IL_0058: br.s IL_005a + + IL_005a: ldloc.0 + IL_005b: ret + } // end of method Switch::ShortSwitchOverStringWithNullCase + + .method public hidebysig static string + SwitchOverString1(string text) cil managed + { + // Code size 185 (0xb9) + .maxstack 7 + .locals init (string V_0, + string V_1) + IL_0000: ldstr "SwitchOverString1: " + IL_0005: ldarg.0 + IL_0006: call string [mscorlib]System.String::Concat(string, + string) + IL_000b: call void [mscorlib]System.Console::WriteLine(string) + IL_0010: ldstr "First case" + IL_0015: ldstr "Second case" + IL_001a: ldstr "2nd case" + IL_001f: ldstr "Third case" + IL_0024: ldstr "Fourth case" + IL_0029: ldstr "Fifth case" + IL_002e: ldstr "Sixth case" + IL_0033: leave.s IL_0035 + + IL_0035: ldarg.0 + IL_0036: dup + IL_0037: stloc.1 + IL_0038: brfalse.s IL_00ab + + IL_003a: ldloc.1 + IL_003b: call string [mscorlib]System.String::IsInterned(string) + IL_0040: stloc.1 + IL_0041: ldloc.1 + IL_0042: ldstr "First case" + IL_0047: beq.s IL_007b + + IL_0049: ldloc.1 + IL_004a: ldstr "Second case" + IL_004f: beq.s IL_0083 + + IL_0051: ldloc.1 + IL_0052: ldstr "2nd case" + IL_0057: beq.s IL_0083 + + IL_0059: ldloc.1 + IL_005a: ldstr "Third case" + IL_005f: beq.s IL_008b + + IL_0061: ldloc.1 + IL_0062: ldstr "Fourth case" + IL_0067: beq.s IL_0093 + + IL_0069: ldloc.1 + IL_006a: ldstr "Fifth case" + IL_006f: beq.s IL_009b + + IL_0071: ldloc.1 + IL_0072: ldstr "Sixth case" + IL_0077: beq.s IL_00a3 + + IL_0079: br.s IL_00af + + IL_007b: ldstr "Text1" + IL_0080: stloc.0 + IL_0081: br.s IL_00b7 + + IL_0083: ldstr "Text2" + IL_0088: stloc.0 + IL_0089: br.s IL_00b7 + + IL_008b: ldstr "Text3" + IL_0090: stloc.0 + IL_0091: br.s IL_00b7 + + IL_0093: ldstr "Text4" + IL_0098: stloc.0 + IL_0099: br.s IL_00b7 + + IL_009b: ldstr "Text5" + IL_00a0: stloc.0 + IL_00a1: br.s IL_00b7 + + IL_00a3: ldstr "Text6" + IL_00a8: stloc.0 + IL_00a9: br.s IL_00b7 + + IL_00ab: ldnull + IL_00ac: stloc.0 + IL_00ad: br.s IL_00b7 + + IL_00af: ldstr "Default" + IL_00b4: stloc.0 + IL_00b5: br.s IL_00b7 + + IL_00b7: ldloc.0 + IL_00b8: ret + } // end of method Switch::SwitchOverString1 + + .method public hidebysig static string + SwitchOverString2() cil managed + { + // Code size 418 (0x1a2) + .maxstack 4 + .locals init (string V_0, + object V_1) + IL_0000: volatile. + IL_0002: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000006-1' + IL_0007: brtrue IL_00dc + + IL_000c: ldc.i4.s 24 + IL_000e: ldc.r4 0.5 + IL_0013: newobj instance void [mscorlib]System.Collections.Hashtable::.ctor(int32, + float32) + IL_0018: dup + IL_0019: ldstr "First case" + IL_001e: ldc.i4.0 + IL_001f: box [mscorlib]System.Int32 + IL_0024: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0029: dup + IL_002a: ldstr "Second case" + IL_002f: ldc.i4.1 + IL_0030: box [mscorlib]System.Int32 + IL_0035: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_003a: dup + IL_003b: ldstr "Third case" + IL_0040: ldc.i4.2 + IL_0041: box [mscorlib]System.Int32 + IL_0046: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_004b: dup + IL_004c: ldstr "Fourth case" + IL_0051: ldc.i4.3 + IL_0052: box [mscorlib]System.Int32 + IL_0057: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_005c: dup + IL_005d: ldstr "Fifth case" + IL_0062: ldc.i4.4 + IL_0063: box [mscorlib]System.Int32 + IL_0068: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_006d: dup + IL_006e: ldstr "Sixth case" + IL_0073: ldc.i4.5 + IL_0074: box [mscorlib]System.Int32 + IL_0079: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_007e: dup + IL_007f: ldstr "Seventh case" + IL_0084: ldc.i4.6 + IL_0085: box [mscorlib]System.Int32 + IL_008a: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_008f: dup + IL_0090: ldstr "Eighth case" + IL_0095: ldc.i4.7 + IL_0096: box [mscorlib]System.Int32 + IL_009b: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00a0: dup + IL_00a1: ldstr "Ninth case" + IL_00a6: ldc.i4.8 + IL_00a7: box [mscorlib]System.Int32 + IL_00ac: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00b1: dup + IL_00b2: ldstr "Tenth case" + IL_00b7: ldc.i4.s 9 + IL_00b9: box [mscorlib]System.Int32 + IL_00be: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00c3: dup + IL_00c4: ldstr "Eleventh case" + IL_00c9: ldc.i4.s 10 + IL_00cb: box [mscorlib]System.Int32 + IL_00d0: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00d5: volatile. + IL_00d7: stsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000006-1' + IL_00dc: ldstr "SwitchOverString2:" + IL_00e1: call void [mscorlib]System.Console::WriteLine(string) + IL_00e6: call string [mscorlib]System.Environment::get_UserName() + IL_00eb: dup + IL_00ec: stloc.1 + IL_00ed: brfalse IL_0198 + + IL_00f2: volatile. + IL_00f4: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000006-1' + IL_00f9: ldloc.1 + IL_00fa: call instance object [mscorlib]System.Collections.Hashtable::get_Item(object) + IL_00ff: dup + IL_0100: stloc.1 + IL_0101: brfalse IL_0198 + + IL_0106: ldloc.1 + IL_0107: unbox [mscorlib]System.Int32 + IL_010c: ldind.i4 + IL_010d: switch ( + IL_0140, + IL_0148, + IL_0150, + IL_0158, + IL_0160, + IL_0168, + IL_0170, + IL_0178, + IL_0180, + IL_0188, + IL_0190) + IL_013e: br.s IL_0198 + + IL_0140: ldstr "Text1" + IL_0145: stloc.0 + IL_0146: br.s IL_01a0 + + IL_0148: ldstr "Text2" + IL_014d: stloc.0 + IL_014e: br.s IL_01a0 + + IL_0150: ldstr "Text3" + IL_0155: stloc.0 + IL_0156: br.s IL_01a0 + + IL_0158: ldstr "Text4" + IL_015d: stloc.0 + IL_015e: br.s IL_01a0 + + IL_0160: ldstr "Text5" + IL_0165: stloc.0 + IL_0166: br.s IL_01a0 + + IL_0168: ldstr "Text6" + IL_016d: stloc.0 + IL_016e: br.s IL_01a0 + + IL_0170: ldstr "Text7" + IL_0175: stloc.0 + IL_0176: br.s IL_01a0 + + IL_0178: ldstr "Text8" + IL_017d: stloc.0 + IL_017e: br.s IL_01a0 + + IL_0180: ldstr "Text9" + IL_0185: stloc.0 + IL_0186: br.s IL_01a0 + + IL_0188: ldstr "Text10" + IL_018d: stloc.0 + IL_018e: br.s IL_01a0 + + IL_0190: ldstr "Text11" + IL_0195: stloc.0 + IL_0196: br.s IL_01a0 + + IL_0198: ldstr "Default" + IL_019d: stloc.0 + IL_019e: br.s IL_01a0 + + IL_01a0: ldloc.0 + IL_01a1: ret + } // end of method Switch::SwitchOverString2 + + .method public hidebysig static string + TwoDifferentSwitchBlocksInTryFinally() cil managed + { + // Code size 925 (0x39d) + .maxstack 4 + .locals init (string V_0, + object V_1) + IL_0000: volatile. + IL_0002: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-1' + IL_0007: brtrue IL_01b8 + + IL_000c: ldc.i4.s 24 + IL_000e: ldc.r4 0.5 + IL_0013: newobj instance void [mscorlib]System.Collections.Hashtable::.ctor(int32, + float32) + IL_0018: dup + IL_0019: ldstr "12" + IL_001e: ldc.i4.0 + IL_001f: box [mscorlib]System.Int32 + IL_0024: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0029: dup + IL_002a: ldstr "13" + IL_002f: ldc.i4.1 + IL_0030: box [mscorlib]System.Int32 + IL_0035: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_003a: dup + IL_003b: ldstr "14" + IL_0040: ldc.i4.2 + IL_0041: box [mscorlib]System.Int32 + IL_0046: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_004b: dup + IL_004c: ldstr "15" + IL_0051: ldc.i4.3 + IL_0052: box [mscorlib]System.Int32 + IL_0057: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_005c: dup + IL_005d: ldstr "16" + IL_0062: ldc.i4.4 + IL_0063: box [mscorlib]System.Int32 + IL_0068: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_006d: dup + IL_006e: ldstr "17" + IL_0073: ldc.i4.5 + IL_0074: box [mscorlib]System.Int32 + IL_0079: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_007e: dup + IL_007f: ldstr "18" + IL_0084: ldc.i4.6 + IL_0085: box [mscorlib]System.Int32 + IL_008a: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_008f: dup + IL_0090: ldstr "19 case" + IL_0095: ldc.i4.7 + IL_0096: box [mscorlib]System.Int32 + IL_009b: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00a0: dup + IL_00a1: ldstr "20 case" + IL_00a6: ldc.i4.8 + IL_00a7: box [mscorlib]System.Int32 + IL_00ac: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00b1: dup + IL_00b2: ldstr "21 case" + IL_00b7: ldc.i4.s 9 + IL_00b9: box [mscorlib]System.Int32 + IL_00be: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00c3: dup + IL_00c4: ldstr "22 case" + IL_00c9: ldc.i4.s 10 + IL_00cb: box [mscorlib]System.Int32 + IL_00d0: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00d5: volatile. + IL_00d7: stsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-1' + IL_00dc: volatile. + IL_00de: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-2' + IL_00e3: brtrue IL_01b8 + + IL_00e8: ldc.i4.s 24 + IL_00ea: ldc.r4 0.5 + IL_00ef: newobj instance void [mscorlib]System.Collections.Hashtable::.ctor(int32, + float32) + IL_00f4: dup + IL_00f5: ldstr "First case" + IL_00fa: ldc.i4.0 + IL_00fb: box [mscorlib]System.Int32 + IL_0100: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0105: dup + IL_0106: ldstr "Second case" + IL_010b: ldc.i4.1 + IL_010c: box [mscorlib]System.Int32 + IL_0111: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0116: dup + IL_0117: ldstr "Third case" + IL_011c: ldc.i4.2 + IL_011d: box [mscorlib]System.Int32 + IL_0122: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0127: dup + IL_0128: ldstr "Fourth case" + IL_012d: ldc.i4.3 + IL_012e: box [mscorlib]System.Int32 + IL_0133: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0138: dup + IL_0139: ldstr "Fifth case" + IL_013e: ldc.i4.4 + IL_013f: box [mscorlib]System.Int32 + IL_0144: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0149: dup + IL_014a: ldstr "Sixth case" + IL_014f: ldc.i4.5 + IL_0150: box [mscorlib]System.Int32 + IL_0155: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_015a: dup + IL_015b: ldstr "Seventh case" + IL_0160: ldc.i4.6 + IL_0161: box [mscorlib]System.Int32 + IL_0166: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_016b: dup + IL_016c: ldstr "Eighth case" + IL_0171: ldc.i4.7 + IL_0172: box [mscorlib]System.Int32 + IL_0177: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_017c: dup + IL_017d: ldstr "Ninth case" + IL_0182: ldc.i4.8 + IL_0183: box [mscorlib]System.Int32 + IL_0188: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_018d: dup + IL_018e: ldstr "Tenth case" + IL_0193: ldc.i4.s 9 + IL_0195: box [mscorlib]System.Int32 + IL_019a: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_019f: dup + IL_01a0: ldstr "Eleventh case" + IL_01a5: ldc.i4.s 10 + IL_01a7: box [mscorlib]System.Int32 + IL_01ac: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_01b1: volatile. + IL_01b3: stsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-2' + .try + { + IL_01b8: ldstr "TwoDifferentSwitchBlocks:" + IL_01bd: call void [mscorlib]System.Console::WriteLine(string) + IL_01c2: call string [mscorlib]System.Environment::get_UserName() + IL_01c7: dup + IL_01c8: stloc.1 + IL_01c9: brfalse IL_0295 + + IL_01ce: volatile. + IL_01d0: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-2' + IL_01d5: ldloc.1 + IL_01d6: call instance object [mscorlib]System.Collections.Hashtable::get_Item(object) + IL_01db: dup + IL_01dc: stloc.1 + IL_01dd: brfalse IL_0295 + + IL_01e2: ldloc.1 + IL_01e3: unbox [mscorlib]System.Int32 + IL_01e8: ldind.i4 + IL_01e9: switch ( + IL_021c, + IL_0227, + IL_0232, + IL_023d, + IL_0248, + IL_0253, + IL_025e, + IL_0269, + IL_0274, + IL_027f, + IL_028a) + IL_021a: br.s IL_0295 + + IL_021c: ldstr "Text1" + IL_0221: stloc.0 + IL_0222: leave IL_039b + + IL_0227: ldstr "Text2" + IL_022c: stloc.0 + IL_022d: leave IL_039b + + IL_0232: ldstr "Text3" + IL_0237: stloc.0 + IL_0238: leave IL_039b + + IL_023d: ldstr "Text4" + IL_0242: stloc.0 + IL_0243: leave IL_039b + + IL_0248: ldstr "Text5" + IL_024d: stloc.0 + IL_024e: leave IL_039b + + IL_0253: ldstr "Text6" + IL_0258: stloc.0 + IL_0259: leave IL_039b + + IL_025e: ldstr "Text7" + IL_0263: stloc.0 + IL_0264: leave IL_039b + + IL_0269: ldstr "Text8" + IL_026e: stloc.0 + IL_026f: leave IL_039b + + IL_0274: ldstr "Text9" + IL_0279: stloc.0 + IL_027a: leave IL_039b + + IL_027f: ldstr "Text10" + IL_0284: stloc.0 + IL_0285: leave IL_039b + + IL_028a: ldstr "Text11" + IL_028f: stloc.0 + IL_0290: leave IL_039b + + IL_0295: ldstr "Default" + IL_029a: stloc.0 + IL_029b: leave IL_039b + + } // end .try + finally + { + IL_02a0: ldstr "Second switch:" + IL_02a5: call void [mscorlib]System.Console::WriteLine(string) + IL_02aa: call string [mscorlib]System.Console::ReadLine() + IL_02af: dup + IL_02b0: stloc.1 + IL_02b1: brfalse IL_038e + + IL_02b6: volatile. + IL_02b8: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-1' + IL_02bd: ldloc.1 + IL_02be: call instance object [mscorlib]System.Collections.Hashtable::get_Item(object) + IL_02c3: dup + IL_02c4: stloc.1 + IL_02c5: brfalse IL_038e + + IL_02ca: ldloc.1 + IL_02cb: unbox [mscorlib]System.Int32 + IL_02d0: ldind.i4 + IL_02d1: switch ( + IL_0307, + IL_0316, + IL_0322, + IL_032e, + IL_033a, + IL_0346, + IL_0352, + IL_035e, + IL_036a, + IL_0376, + IL_0382) + IL_0302: br IL_038e + + IL_0307: ldstr "Te43234xt1" + IL_030c: call void [mscorlib]System.Console::WriteLine(string) + IL_0311: br IL_039a + + IL_0316: ldstr "Te223443xt2" + IL_031b: call void [mscorlib]System.Console::WriteLine(string) + IL_0320: br.s IL_039a + + IL_0322: ldstr "Te234xt3" + IL_0327: call void [mscorlib]System.Console::WriteLine(string) + IL_032c: br.s IL_039a + + IL_032e: ldstr "Tex243t4" + IL_0333: call void [mscorlib]System.Console::WriteLine(string) + IL_0338: br.s IL_039a + + IL_033a: ldstr "Tex243t5" + IL_033f: call void [mscorlib]System.Console::WriteLine(string) + IL_0344: br.s IL_039a + + IL_0346: ldstr "Text2346" + IL_034b: call void [mscorlib]System.Console::WriteLine(string) + IL_0350: br.s IL_039a + + IL_0352: ldstr "Text234234" + IL_0357: call void [mscorlib]System.Console::WriteLine(string) + IL_035c: br.s IL_039a + + IL_035e: ldstr "Text8234" + IL_0363: call void [mscorlib]System.Console::WriteLine(string) + IL_0368: br.s IL_039a + + IL_036a: ldstr "Text923423" + IL_036f: call void [mscorlib]System.Console::WriteLine(string) + IL_0374: br.s IL_039a + + IL_0376: ldstr "Text10" + IL_037b: call void [mscorlib]System.Console::WriteLine(string) + IL_0380: br.s IL_039a + + IL_0382: ldstr "Text1134123" + IL_0387: call void [mscorlib]System.Console::WriteLine(string) + IL_038c: br.s IL_039a + + IL_038e: ldstr "Defa234234ult" + IL_0393: call void [mscorlib]System.Console::WriteLine(string) + IL_0398: br.s IL_039a + + IL_039a: endfinally + } // end handler + IL_039b: ldloc.0 + IL_039c: ret + } // end of method Switch::TwoDifferentSwitchBlocksInTryFinally + + .method public hidebysig static string + SwitchOverBool(bool b) cil managed + { + // Code size 62 (0x3e) + .maxstack 2 + .locals init (string V_0, + bool V_1) + IL_0000: ldstr "SwitchOverBool: " + IL_0005: ldarga.s b + IL_0007: call instance string [mscorlib]System.Boolean::ToString() + IL_000c: call string [mscorlib]System.String::Concat(string, + string) + IL_0011: call void [mscorlib]System.Console::WriteLine(string) + IL_0016: ldarg.0 + IL_0017: stloc.1 + IL_0018: ldloc.1 + IL_0019: switch ( + IL_0030, + IL_0028) + IL_0026: br.s IL_0038 + + IL_0028: ldsfld string [mscorlib]System.Boolean::TrueString + IL_002d: stloc.0 + IL_002e: br.s IL_003c + + IL_0030: ldsfld string [mscorlib]System.Boolean::FalseString + IL_0035: stloc.0 + IL_0036: br.s IL_003c + + IL_0038: ldnull + IL_0039: stloc.0 + IL_003a: br.s IL_003c + + IL_003c: ldloc.0 + IL_003d: ret + } // end of method Switch::SwitchOverBool + + .method public hidebysig static void SwitchInLoop(int32 i) cil managed + { + // Code size 117 (0x75) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldstr "SwitchInLoop: " + IL_0005: ldarg.0 + IL_0006: box [mscorlib]System.Int32 + IL_000b: call string [mscorlib]System.String::Concat(object, + object) + IL_0010: call void [mscorlib]System.Console::WriteLine(string) + IL_0015: br.s IL_0072 + + IL_0017: ldarg.0 + IL_0018: stloc.0 + IL_0019: ldloc.0 + IL_001a: ldc.i4.1 + IL_001b: sub + IL_001c: switch ( + IL_0033, + IL_003f, + IL_0057, + IL_004b) + IL_0031: br.s IL_0057 + + IL_0033: ldstr "one" + IL_0038: call void [mscorlib]System.Console::WriteLine(string) + IL_003d: br.s IL_006d + + IL_003f: ldstr "two" + IL_0044: call void [mscorlib]System.Console::WriteLine(string) + IL_0049: br.s IL_006d + + IL_004b: ldstr "four" + IL_0050: call void [mscorlib]System.Console::WriteLine(string) + IL_0055: br.s IL_0074 + + IL_0057: ldstr "default" + IL_005c: call void [mscorlib]System.Console::WriteLine(string) + IL_0061: ldstr "more code" + IL_0066: call void [mscorlib]System.Console::WriteLine(string) + IL_006b: br.s IL_0074 + + IL_006d: ldarg.0 + IL_006e: ldc.i4.1 + IL_006f: add + IL_0070: starg.s i + IL_0072: br.s IL_0017 + + IL_0074: ret + } // end of method Switch::SwitchInLoop + + .method public hidebysig static void SwitchWithGoto(int32 i) cil managed + { + // Code size 120 (0x78) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldstr "SwitchWithGoto: " + IL_0005: ldarg.0 + IL_0006: box [mscorlib]System.Int32 + IL_000b: call string [mscorlib]System.String::Concat(object, + object) + IL_0010: call void [mscorlib]System.Console::WriteLine(string) + IL_0015: ldarg.0 + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: ldc.i4.1 + IL_0019: sub + IL_001a: switch ( + IL_0031, + IL_003d, + IL_0049, + IL_0055) + IL_002f: br.s IL_0061 + + IL_0031: ldstr "one" + IL_0036: call void [mscorlib]System.Console::WriteLine(string) + IL_003b: br.s IL_0061 + + IL_003d: ldstr "two" + IL_0042: call void [mscorlib]System.Console::WriteLine(string) + IL_0047: br.s IL_0049 + + IL_0049: ldstr "three" + IL_004e: call void [mscorlib]System.Console::WriteLine(string) + IL_0053: br.s IL_006d + + IL_0055: ldstr "four" + IL_005a: call void [mscorlib]System.Console::WriteLine(string) + IL_005f: br.s IL_0077 + + IL_0061: ldstr "default" + IL_0066: call void [mscorlib]System.Console::WriteLine(string) + IL_006b: br.s IL_006d + + IL_006d: ldstr "End of method" + IL_0072: call void [mscorlib]System.Console::WriteLine(string) + IL_0077: ret + } // end of method Switch::SwitchWithGoto + + .method private hidebysig static class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty[] + GetProperties() cil managed + { + // Code size 11 (0xb) + .maxstack 1 + .locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty[] V_0) + IL_0000: ldc.i4.0 + IL_0001: newarr ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty + IL_0006: stloc.0 + IL_0007: br.s IL_0009 + + IL_0009: ldloc.0 + IL_000a: ret + } // end of method Switch::GetProperties + + .method public hidebysig static void SwitchOnStringInForLoop() cil managed + { + // Code size 269 (0x10d) + .maxstack 6 + .locals init (class [mscorlib]System.Collections.ArrayList V_0, + class [mscorlib]System.Collections.ArrayList V_1, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty[] V_2, + int32 V_3, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty V_4, + string V_5) + IL_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor() + IL_0005: stloc.0 + IL_0006: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor() + IL_000b: stloc.1 + IL_000c: call class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty[] ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch::GetProperties() + IL_0011: stloc.2 + IL_0012: ldc.i4.0 + IL_0013: stloc.3 + IL_0014: br IL_0103 + + IL_0019: ldstr "In for-loop" + IL_001e: call void [mscorlib]System.Console::WriteLine(string) + IL_0023: ldloc.2 + IL_0024: ldloc.3 + IL_0025: ldelem.ref + IL_0026: stloc.s V_4 + IL_0028: ldstr "Name1" + IL_002d: ldstr "Name2" + IL_0032: ldstr "Name3" + IL_0037: ldstr "Name4" + IL_003c: ldstr "Name5" + IL_0041: ldstr "Name6" + IL_0046: leave.s IL_0048 + + IL_0048: ldloc.s V_4 + IL_004a: ldfld class [mscorlib]System.Reflection.PropertyInfo ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::Property + IL_004f: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() + IL_0054: dup + IL_0055: stloc.s V_5 + IL_0057: brfalse IL_00f4 + + IL_005c: ldloc.s V_5 + IL_005e: call string [mscorlib]System.String::IsInterned(string) + IL_0063: stloc.s V_5 + IL_0065: ldloc.s V_5 + IL_0067: ldstr "Name1" + IL_006c: beq.s IL_009d + + IL_006e: ldloc.s V_5 + IL_0070: ldstr "Name2" + IL_0075: beq.s IL_00b0 + + IL_0077: ldloc.s V_5 + IL_0079: ldstr "Name3" + IL_007e: beq.s IL_00c3 + + IL_0080: ldloc.s V_5 + IL_0082: ldstr "Name4" + IL_0087: beq.s IL_00d6 + + IL_0089: ldloc.s V_5 + IL_008b: ldstr "Name5" + IL_0090: beq.s IL_00e9 + + IL_0092: ldloc.s V_5 + IL_0094: ldstr "Name6" + IL_0099: beq.s IL_00e9 + + IL_009b: br.s IL_00f4 + + IL_009d: ldloc.s V_4 + IL_009f: ldc.i4.1 + IL_00a0: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + IL_00a5: ldloc.0 + IL_00a6: ldloc.s V_4 + IL_00a8: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00ad: pop + IL_00ae: br.s IL_00ff + + IL_00b0: ldloc.s V_4 + IL_00b2: ldc.i4.2 + IL_00b3: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + IL_00b8: ldloc.0 + IL_00b9: ldloc.s V_4 + IL_00bb: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00c0: pop + IL_00c1: br.s IL_00ff + + IL_00c3: ldloc.s V_4 + IL_00c5: ldc.i4.3 + IL_00c6: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + IL_00cb: ldloc.0 + IL_00cc: ldloc.s V_4 + IL_00ce: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00d3: pop + IL_00d4: br.s IL_00ff + + IL_00d6: ldloc.s V_4 + IL_00d8: ldc.i4.4 + IL_00d9: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + IL_00de: ldloc.0 + IL_00df: ldloc.s V_4 + IL_00e1: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00e6: pop + IL_00e7: br.s IL_00ff + + IL_00e9: ldloc.0 + IL_00ea: ldloc.s V_4 + IL_00ec: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00f1: pop + IL_00f2: br.s IL_00ff + + IL_00f4: ldloc.1 + IL_00f5: ldloc.s V_4 + IL_00f7: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00fc: pop + IL_00fd: br.s IL_00ff + + IL_00ff: ldloc.3 + IL_0100: ldc.i4.1 + IL_0101: add + IL_0102: stloc.3 + IL_0103: ldloc.3 + IL_0104: ldloc.2 + IL_0105: ldlen + IL_0106: conv.i4 + IL_0107: blt IL_0019 + + IL_010c: ret + } // end of method Switch::SwitchOnStringInForLoop + + .method public hidebysig static void SwitchWithComplexCondition(string[] args) cil managed + { + // Code size 141 (0x8d) + .maxstack 4 + .locals init (string V_0) + IL_0000: ldstr "a" + IL_0005: ldstr "b" + IL_000a: ldstr "c" + IL_000f: ldstr "d" + IL_0014: leave.s IL_0016 + + IL_0016: ldarg.0 + IL_0017: ldlen + IL_0018: conv.i4 + IL_0019: brfalse.s IL_0020 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.0 + IL_001d: ldelem.ref + IL_001e: br.s IL_0025 + + IL_0020: ldstr "dummy" + IL_0025: dup + IL_0026: stloc.0 + IL_0027: brfalse.s IL_0082 + + IL_0029: ldloc.0 + IL_002a: call string [mscorlib]System.String::IsInterned(string) + IL_002f: stloc.0 + IL_0030: ldloc.0 + IL_0031: ldstr "a" + IL_0036: beq.s IL_0052 + + IL_0038: ldloc.0 + IL_0039: ldstr "b" + IL_003e: beq.s IL_005e + + IL_0040: ldloc.0 + IL_0041: ldstr "c" + IL_0046: beq.s IL_006a + + IL_0048: ldloc.0 + IL_0049: ldstr "d" + IL_004e: beq.s IL_0076 + + IL_0050: br.s IL_0082 + + IL_0052: ldstr "a" + IL_0057: call void [mscorlib]System.Console::WriteLine(string) + IL_005c: br.s IL_0082 + + IL_005e: ldstr "b" + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: br.s IL_0082 + + IL_006a: ldstr "c" + IL_006f: call void [mscorlib]System.Console::WriteLine(string) + IL_0074: br.s IL_0082 + + IL_0076: ldstr "d" + IL_007b: call void [mscorlib]System.Console::WriteLine(string) + IL_0080: br.s IL_0082 + + IL_0082: ldstr "end" + IL_0087: call void [mscorlib]System.Console::WriteLine(string) + IL_008c: ret + } // end of method Switch::SwitchWithComplexCondition + + .method public hidebysig static void SwitchWithArray(string[] args) cil managed + { + // Code size 129 (0x81) + .maxstack 4 + .locals init (string V_0) + IL_0000: ldstr "a" + IL_0005: ldstr "b" + IL_000a: ldstr "c" + IL_000f: ldstr "d" + IL_0014: leave.s IL_0016 + + IL_0016: ldarg.0 + IL_0017: ldc.i4.0 + IL_0018: ldelem.ref + IL_0019: dup + IL_001a: stloc.0 + IL_001b: brfalse.s IL_0076 + + IL_001d: ldloc.0 + IL_001e: call string [mscorlib]System.String::IsInterned(string) + IL_0023: stloc.0 + IL_0024: ldloc.0 + IL_0025: ldstr "a" + IL_002a: beq.s IL_0046 + + IL_002c: ldloc.0 + IL_002d: ldstr "b" + IL_0032: beq.s IL_0052 + + IL_0034: ldloc.0 + IL_0035: ldstr "c" + IL_003a: beq.s IL_005e + + IL_003c: ldloc.0 + IL_003d: ldstr "d" + IL_0042: beq.s IL_006a + + IL_0044: br.s IL_0076 + + IL_0046: ldstr "a" + IL_004b: call void [mscorlib]System.Console::WriteLine(string) + IL_0050: br.s IL_0076 + + IL_0052: ldstr "b" + IL_0057: call void [mscorlib]System.Console::WriteLine(string) + IL_005c: br.s IL_0076 + + IL_005e: ldstr "c" + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: br.s IL_0076 + + IL_006a: ldstr "d" + IL_006f: call void [mscorlib]System.Console::WriteLine(string) + IL_0074: br.s IL_0076 + + IL_0076: ldstr "end" + IL_007b: call void [mscorlib]System.Console::WriteLine(string) + IL_0080: ret + } // end of method Switch::SwitchWithArray + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Switch::.ctor + +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch + +.class private auto ansi '' + extends [mscorlib]System.Object +{ + .field static assembly class [mscorlib]System.Collections.Hashtable '$$method0x6000006-1' + .field static assembly class [mscorlib]System.Collections.Hashtable '$$method0x6000007-1' + .field static assembly class [mscorlib]System.Collections.Hashtable '$$method0x6000007-2' +} // end of class '' + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file C:\Users\Siegfried\Projects\ILSpy master\ICSharpCode.Decompiler.Tests\TestCases\ILPretty\CS1xSwitch_Debug.res diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.cs new file mode 100644 index 000000000..d927e3fd0 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.cs @@ -0,0 +1,412 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections; +using System.Reflection; + +namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty +{ + public class Switch + { + public class SetProperty + { + public readonly PropertyInfo Property; + private int _set; + + public int Set { + get { + return _set; + } + + set { + _set = value; + } + } + + public SetProperty(PropertyInfo property) + { + Property = property; + } + } + + public enum State + { + False, + True, + Null + } + + public static string SparseIntegerSwitch(int i) + { + Console.WriteLine("SparseIntegerSwitch: " + i); + switch (i) { + case -10000000: + return "-10 mln"; + case -100: + return "-hundred"; + case -1: + return "-1"; + case 0: + return "0"; + case 1: + return "1"; + case 2: + return "2"; + case 4: + return "4"; + case 100: + return "hundred"; + case 10000: + return "ten thousand"; + case 10001: + return "ten thousand and one"; + case int.MaxValue: + return "int.MaxValue"; + default: + return "something else"; + } + } + + public static void SwitchOverInt(int i) + { + switch (i) { + case 0: + Console.WriteLine("zero"); + break; + case 5: + Console.WriteLine("five"); + break; + case 10: + Console.WriteLine("ten"); + break; + case 15: + Console.WriteLine("fifteen"); + break; + case 20: + Console.WriteLine("twenty"); + break; + case 25: + Console.WriteLine("twenty-five"); + break; + case 30: + Console.WriteLine("thirty"); + break; + } + } + + public static string ShortSwitchOverString(string text) + { + Console.WriteLine("ShortSwitchOverString: " + text); + switch (text) { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case "Third case": + return "Text3"; + default: + return "Default"; + } + } + + public static string ShortSwitchOverStringWithNullCase(string text) + { + Console.WriteLine("ShortSwitchOverStringWithNullCase: " + text); + switch (text) { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case null: + return "null"; + default: + return "Default"; + } + } + + public static string SwitchOverString1(string text) + { + Console.WriteLine("SwitchOverString1: " + text); + switch (text) { + case "First case": + return "Text1"; + case "Second case": + case "2nd case": + return "Text2"; + case "Third case": + return "Text3"; + case "Fourth case": + return "Text4"; + case "Fifth case": + return "Text5"; + case "Sixth case": + return "Text6"; + case null: + return null; + default: + return "Default"; + } + } + + public static string SwitchOverString2() + { + Console.WriteLine("SwitchOverString2:"); + switch (Environment.UserName) { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case "Third case": + return "Text3"; + case "Fourth case": + return "Text4"; + case "Fifth case": + return "Text5"; + case "Sixth case": + return "Text6"; + case "Seventh case": + return "Text7"; + case "Eighth case": + return "Text8"; + case "Ninth case": + return "Text9"; + case "Tenth case": + return "Text10"; + case "Eleventh case": + return "Text11"; + default: + return "Default"; + } + } + + public static string TwoDifferentSwitchBlocksInTryFinally() + { + try { + Console.WriteLine("TwoDifferentSwitchBlocks:"); + switch (Environment.UserName) { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case "Third case": + return "Text3"; + case "Fourth case": + return "Text4"; + case "Fifth case": + return "Text5"; + case "Sixth case": + return "Text6"; + case "Seventh case": + return "Text7"; + case "Eighth case": + return "Text8"; + case "Ninth case": + return "Text9"; + case "Tenth case": + return "Text10"; + case "Eleventh case": + return "Text11"; + default: + return "Default"; + } + } finally { + Console.WriteLine("Second switch:"); + switch (Console.ReadLine()) { + case "12": + Console.WriteLine("Te43234xt1"); + break; + case "13": + Console.WriteLine("Te223443xt2"); + break; + case "14": + Console.WriteLine("Te234xt3"); + break; + case "15": + Console.WriteLine("Tex243t4"); + break; + case "16": + Console.WriteLine("Tex243t5"); + break; + case "17": + Console.WriteLine("Text2346"); + break; + case "18": + Console.WriteLine("Text234234"); + break; + case "19 case": + Console.WriteLine("Text8234"); + break; + case "20 case": + Console.WriteLine("Text923423"); + break; + case "21 case": + Console.WriteLine("Text10"); + break; + case "22 case": + Console.WriteLine("Text1134123"); + break; + default: + Console.WriteLine("Defa234234ult"); + break; + } + } + } + + public static string SwitchOverBool(bool b) + { + Console.WriteLine("SwitchOverBool: " + b.ToString()); + switch (b) { + case true: + return bool.TrueString; + case false: + return bool.FalseString; + default: + return null; + } + } + + public static void SwitchInLoop(int i) + { + Console.WriteLine("SwitchInLoop: " + i); + while (true) { + switch (i) { + case 1: + Console.WriteLine("one"); + break; + case 2: + Console.WriteLine("two"); + break; + //case 3: + // Console.WriteLine("three"); + // continue; + case 4: + Console.WriteLine("four"); + return; + default: + Console.WriteLine("default"); + Console.WriteLine("more code"); + return; + } + i++; + } + } + + public static void SwitchWithGoto(int i) + { + Console.WriteLine("SwitchWithGoto: " + i); + switch (i) { + case 1: + Console.WriteLine("one"); + goto default; + case 2: + Console.WriteLine("two"); + goto case 3; + case 3: + Console.WriteLine("three"); + break; + case 4: + Console.WriteLine("four"); + return; + default: + Console.WriteLine("default"); + break; + } + Console.WriteLine("End of method"); + } + + private static SetProperty[] GetProperties() + { + return new SetProperty[0]; + } + + public static void SwitchOnStringInForLoop() + { + ArrayList arrayList = new ArrayList(); + ArrayList arrayList2 = new ArrayList(); + SetProperty[] properties = GetProperties(); + for (int i = 0; i < properties.Length; i++) { + Console.WriteLine("In for-loop"); + SetProperty setProperty = properties[i]; + switch (setProperty.Property.Name) { + case "Name1": + setProperty.Set = 1; + arrayList.Add(setProperty); + break; + case "Name2": + setProperty.Set = 2; + arrayList.Add(setProperty); + break; + case "Name3": + setProperty.Set = 3; + arrayList.Add(setProperty); + break; + case "Name4": + setProperty.Set = 4; + arrayList.Add(setProperty); + break; + case "Name5": + case "Name6": + arrayList.Add(setProperty); + break; + default: + arrayList2.Add(setProperty); + break; + } + } + } + + public static void SwitchWithComplexCondition(string[] args) + { + switch ((args.Length == 0) ? "dummy" : args[0]) { + case "a": + Console.WriteLine("a"); + break; + case "b": + Console.WriteLine("b"); + break; + case "c": + Console.WriteLine("c"); + break; + case "d": + Console.WriteLine("d"); + break; + } + Console.WriteLine("end"); + } + + public static void SwitchWithArray(string[] args) + { + switch (args[0]) { + case "a": + Console.WriteLine("a"); + break; + case "b": + Console.WriteLine("b"); + break; + case "c": + Console.WriteLine("c"); + break; + case "d": + Console.WriteLine("d"); + break; + } + Console.WriteLine("end"); + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.il b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.il new file mode 100644 index 000000000..32bd71dee --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/CS1xSwitch_Release.il @@ -0,0 +1,1325 @@ + +// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0 +// Copyright (c) Microsoft Corporation. All rights reserved. + + + +// Metadata version: v1.1.4322 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 1:0:5000:0 +} +.assembly CS1xSwitch_Release +{ + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module CS1xSwitch_Release.dll +// MVID: {E26201E5-5EC1-412E-BE6D-AE48AFAE6535} +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY +// Image base: 0x07560000 + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch + extends [mscorlib]System.Object +{ + .class auto ansi nested public beforefieldinit SetProperty + extends [mscorlib]System.Object + { + .field public initonly class [mscorlib]System.Reflection.PropertyInfo Property + .field private int32 _set + .method public hidebysig specialname + instance int32 get_Set() cil managed + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::_set + IL_0006: ret + } // end of method SetProperty::get_Set + + .method public hidebysig specialname + instance void set_Set(int32 'value') cil managed + { + // Code size 8 (0x8) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::_set + IL_0007: ret + } // end of method SetProperty::set_Set + + .method public hidebysig specialname rtspecialname + instance void .ctor(class [mscorlib]System.Reflection.PropertyInfo 'property') cil managed + { + // Code size 14 (0xe) + .maxstack 2 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld class [mscorlib]System.Reflection.PropertyInfo ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::Property + IL_000d: ret + } // end of method SetProperty::.ctor + + .property instance int32 Set() + { + .get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::get_Set() + .set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + } // end of property SetProperty::Set + } // end of class SetProperty + + .class auto ansi sealed nested public State + extends [mscorlib]System.Enum + { + .field public specialname rtspecialname int32 value__ + .field public static literal valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State False = int32(0x00000000) + .field public static literal valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State True = int32(0x00000001) + .field public static literal valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/State Null = int32(0x00000002) + } // end of class State + + .method public hidebysig static string + SparseIntegerSwitch(int32 i) cil managed + { + // Code size 181 (0xb5) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldstr "SparseIntegerSwitch: " + IL_0005: ldarg.0 + IL_0006: box [mscorlib]System.Int32 + IL_000b: call string [mscorlib]System.String::Concat(object, + object) + IL_0010: call void [mscorlib]System.Console::WriteLine(string) + IL_0015: ldarg.0 + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: ldc.i4.4 + IL_0019: bgt.s IL_004a + + IL_001b: ldloc.0 + IL_001c: ldc.i4 0xff676980 + IL_0021: beq.s IL_006d + + IL_0023: ldloc.0 + IL_0024: ldc.i4.s -100 + IL_0026: beq.s IL_0073 + + IL_0028: ldloc.0 + IL_0029: ldc.i4.m1 + IL_002a: sub + IL_002b: switch ( + IL_0079, + IL_007f, + IL_0085, + IL_008b, + IL_00af, + IL_0091) + IL_0048: br.s IL_00af + + IL_004a: ldloc.0 + IL_004b: ldc.i4.s 100 + IL_004d: beq.s IL_0097 + + IL_004f: ldloc.0 + IL_0050: ldc.i4 0x2710 + IL_0055: sub + IL_0056: switch ( + IL_009d, + IL_00a3) + IL_0063: ldloc.0 + IL_0064: ldc.i4 0x7fffffff + IL_0069: beq.s IL_00a9 + + IL_006b: br.s IL_00af + + IL_006d: ldstr "-10 mln" + IL_0072: ret + + IL_0073: ldstr "-hundred" + IL_0078: ret + + IL_0079: ldstr "-1" + IL_007e: ret + + IL_007f: ldstr "0" + IL_0084: ret + + IL_0085: ldstr "1" + IL_008a: ret + + IL_008b: ldstr "2" + IL_0090: ret + + IL_0091: ldstr "4" + IL_0096: ret + + IL_0097: ldstr "hundred" + IL_009c: ret + + IL_009d: ldstr "ten thousand" + IL_00a2: ret + + IL_00a3: ldstr "ten thousand and one" + IL_00a8: ret + + IL_00a9: ldstr "int.MaxValue" + IL_00ae: ret + + IL_00af: ldstr "something else" + IL_00b4: ret + } // end of method Switch::SparseIntegerSwitch + + .method public hidebysig static void SwitchOverInt(int32 i) cil managed + { + // Code size 125 (0x7d) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.s 10 + IL_0005: bgt.s IL_0015 + + IL_0007: ldloc.0 + IL_0008: ldc.i4.0 + IL_0009: beq.s IL_0030 + + IL_000b: ldloc.0 + IL_000c: ldc.i4.5 + IL_000d: beq.s IL_003b + + IL_000f: ldloc.0 + IL_0010: ldc.i4.s 10 + IL_0012: beq.s IL_0046 + + IL_0014: ret + + IL_0015: ldloc.0 + IL_0016: ldc.i4.s 20 + IL_0018: bgt.s IL_0025 + + IL_001a: ldloc.0 + IL_001b: ldc.i4.s 15 + IL_001d: beq.s IL_0051 + + IL_001f: ldloc.0 + IL_0020: ldc.i4.s 20 + IL_0022: beq.s IL_005c + + IL_0024: ret + + IL_0025: ldloc.0 + IL_0026: ldc.i4.s 25 + IL_0028: beq.s IL_0067 + + IL_002a: ldloc.0 + IL_002b: ldc.i4.s 30 + IL_002d: beq.s IL_0072 + + IL_002f: ret + + IL_0030: ldstr "zero" + IL_0035: call void [mscorlib]System.Console::WriteLine(string) + IL_003a: ret + + IL_003b: ldstr "five" + IL_0040: call void [mscorlib]System.Console::WriteLine(string) + IL_0045: ret + + IL_0046: ldstr "ten" + IL_004b: call void [mscorlib]System.Console::WriteLine(string) + IL_0050: ret + + IL_0051: ldstr "fifteen" + IL_0056: call void [mscorlib]System.Console::WriteLine(string) + IL_005b: ret + + IL_005c: ldstr "twenty" + IL_0061: call void [mscorlib]System.Console::WriteLine(string) + IL_0066: ret + + IL_0067: ldstr "twenty-five" + IL_006c: call void [mscorlib]System.Console::WriteLine(string) + IL_0071: ret + + IL_0072: ldstr "thirty" + IL_0077: call void [mscorlib]System.Console::WriteLine(string) + IL_007c: ret + } // end of method Switch::SwitchOverInt + + .method public hidebysig static string + ShortSwitchOverString(string text) cil managed + { + // Code size 95 (0x5f) + .maxstack 3 + .locals init (string V_0) + IL_0000: ldstr "ShortSwitchOverString: " + IL_0005: ldarg.0 + IL_0006: call string [mscorlib]System.String::Concat(string, + string) + IL_000b: call void [mscorlib]System.Console::WriteLine(string) + IL_0010: ldstr "First case" + IL_0015: ldstr "Second case" + IL_001a: ldstr "Third case" + IL_001f: leave.s IL_0021 + + IL_0021: ldarg.0 + IL_0022: dup + IL_0023: stloc.0 + IL_0024: brfalse.s IL_0059 + + IL_0026: ldloc.0 + IL_0027: call string [mscorlib]System.String::IsInterned(string) + IL_002c: stloc.0 + IL_002d: ldloc.0 + IL_002e: ldstr "First case" + IL_0033: beq.s IL_0047 + + IL_0035: ldloc.0 + IL_0036: ldstr "Second case" + IL_003b: beq.s IL_004d + + IL_003d: ldloc.0 + IL_003e: ldstr "Third case" + IL_0043: beq.s IL_0053 + + IL_0045: br.s IL_0059 + + IL_0047: ldstr "Text1" + IL_004c: ret + + IL_004d: ldstr "Text2" + IL_0052: ret + + IL_0053: ldstr "Text3" + IL_0058: ret + + IL_0059: ldstr "Default" + IL_005e: ret + } // end of method Switch::ShortSwitchOverString + + .method public hidebysig static string + ShortSwitchOverStringWithNullCase(string text) cil managed + { + // Code size 82 (0x52) + .maxstack 2 + .locals init (string V_0) + IL_0000: ldstr "ShortSwitchOverStringWithNullCase: " + IL_0005: ldarg.0 + IL_0006: call string [mscorlib]System.String::Concat(string, + string) + IL_000b: call void [mscorlib]System.Console::WriteLine(string) + IL_0010: ldstr "First case" + IL_0015: ldstr "Second case" + IL_001a: leave.s IL_001c + + IL_001c: ldarg.0 + IL_001d: dup + IL_001e: stloc.0 + IL_001f: brfalse.s IL_0046 + + IL_0021: ldloc.0 + IL_0022: call string [mscorlib]System.String::IsInterned(string) + IL_0027: stloc.0 + IL_0028: ldloc.0 + IL_0029: ldstr "First case" + IL_002e: beq.s IL_003a + + IL_0030: ldloc.0 + IL_0031: ldstr "Second case" + IL_0036: beq.s IL_0040 + + IL_0038: br.s IL_004c + + IL_003a: ldstr "Text1" + IL_003f: ret + + IL_0040: ldstr "Text2" + IL_0045: ret + + IL_0046: ldstr "null" + IL_004b: ret + + IL_004c: ldstr "Default" + IL_0051: ret + } // end of method Switch::ShortSwitchOverStringWithNullCase + + .method public hidebysig static string + SwitchOverString1(string text) cil managed + { + // Code size 167 (0xa7) + .maxstack 7 + .locals init (string V_0) + IL_0000: ldstr "SwitchOverString1: " + IL_0005: ldarg.0 + IL_0006: call string [mscorlib]System.String::Concat(string, + string) + IL_000b: call void [mscorlib]System.Console::WriteLine(string) + IL_0010: ldstr "First case" + IL_0015: ldstr "Second case" + IL_001a: ldstr "2nd case" + IL_001f: ldstr "Third case" + IL_0024: ldstr "Fourth case" + IL_0029: ldstr "Fifth case" + IL_002e: ldstr "Sixth case" + IL_0033: leave.s IL_0035 + + IL_0035: ldarg.0 + IL_0036: dup + IL_0037: stloc.0 + IL_0038: brfalse.s IL_009f + + IL_003a: ldloc.0 + IL_003b: call string [mscorlib]System.String::IsInterned(string) + IL_0040: stloc.0 + IL_0041: ldloc.0 + IL_0042: ldstr "First case" + IL_0047: beq.s IL_007b + + IL_0049: ldloc.0 + IL_004a: ldstr "Second case" + IL_004f: beq.s IL_0081 + + IL_0051: ldloc.0 + IL_0052: ldstr "2nd case" + IL_0057: beq.s IL_0081 + + IL_0059: ldloc.0 + IL_005a: ldstr "Third case" + IL_005f: beq.s IL_0087 + + IL_0061: ldloc.0 + IL_0062: ldstr "Fourth case" + IL_0067: beq.s IL_008d + + IL_0069: ldloc.0 + IL_006a: ldstr "Fifth case" + IL_006f: beq.s IL_0093 + + IL_0071: ldloc.0 + IL_0072: ldstr "Sixth case" + IL_0077: beq.s IL_0099 + + IL_0079: br.s IL_00a1 + + IL_007b: ldstr "Text1" + IL_0080: ret + + IL_0081: ldstr "Text2" + IL_0086: ret + + IL_0087: ldstr "Text3" + IL_008c: ret + + IL_008d: ldstr "Text4" + IL_0092: ret + + IL_0093: ldstr "Text5" + IL_0098: ret + + IL_0099: ldstr "Text6" + IL_009e: ret + + IL_009f: ldnull + IL_00a0: ret + + IL_00a1: ldstr "Default" + IL_00a6: ret + } // end of method Switch::SwitchOverString1 + + .method public hidebysig static string + SwitchOverString2() cil managed + { + // Code size 389 (0x185) + .maxstack 4 + .locals init (object V_0) + IL_0000: volatile. + IL_0002: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000006-1' + IL_0007: brtrue IL_00dc + + IL_000c: ldc.i4.s 24 + IL_000e: ldc.r4 0.5 + IL_0013: newobj instance void [mscorlib]System.Collections.Hashtable::.ctor(int32, + float32) + IL_0018: dup + IL_0019: ldstr "First case" + IL_001e: ldc.i4.0 + IL_001f: box [mscorlib]System.Int32 + IL_0024: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0029: dup + IL_002a: ldstr "Second case" + IL_002f: ldc.i4.1 + IL_0030: box [mscorlib]System.Int32 + IL_0035: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_003a: dup + IL_003b: ldstr "Third case" + IL_0040: ldc.i4.2 + IL_0041: box [mscorlib]System.Int32 + IL_0046: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_004b: dup + IL_004c: ldstr "Fourth case" + IL_0051: ldc.i4.3 + IL_0052: box [mscorlib]System.Int32 + IL_0057: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_005c: dup + IL_005d: ldstr "Fifth case" + IL_0062: ldc.i4.4 + IL_0063: box [mscorlib]System.Int32 + IL_0068: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_006d: dup + IL_006e: ldstr "Sixth case" + IL_0073: ldc.i4.5 + IL_0074: box [mscorlib]System.Int32 + IL_0079: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_007e: dup + IL_007f: ldstr "Seventh case" + IL_0084: ldc.i4.6 + IL_0085: box [mscorlib]System.Int32 + IL_008a: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_008f: dup + IL_0090: ldstr "Eighth case" + IL_0095: ldc.i4.7 + IL_0096: box [mscorlib]System.Int32 + IL_009b: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00a0: dup + IL_00a1: ldstr "Ninth case" + IL_00a6: ldc.i4.8 + IL_00a7: box [mscorlib]System.Int32 + IL_00ac: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00b1: dup + IL_00b2: ldstr "Tenth case" + IL_00b7: ldc.i4.s 9 + IL_00b9: box [mscorlib]System.Int32 + IL_00be: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00c3: dup + IL_00c4: ldstr "Eleventh case" + IL_00c9: ldc.i4.s 10 + IL_00cb: box [mscorlib]System.Int32 + IL_00d0: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00d5: volatile. + IL_00d7: stsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000006-1' + IL_00dc: ldstr "SwitchOverString2:" + IL_00e1: call void [mscorlib]System.Console::WriteLine(string) + IL_00e6: call string [mscorlib]System.Environment::get_UserName() + IL_00eb: dup + IL_00ec: stloc.0 + IL_00ed: brfalse IL_017f + + IL_00f2: volatile. + IL_00f4: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000006-1' + IL_00f9: ldloc.0 + IL_00fa: call instance object [mscorlib]System.Collections.Hashtable::get_Item(object) + IL_00ff: dup + IL_0100: stloc.0 + IL_0101: brfalse.s IL_017f + + IL_0103: ldloc.0 + IL_0104: unbox [mscorlib]System.Int32 + IL_0109: ldind.i4 + IL_010a: switch ( + IL_013d, + IL_0143, + IL_0149, + IL_014f, + IL_0155, + IL_015b, + IL_0161, + IL_0167, + IL_016d, + IL_0173, + IL_0179) + IL_013b: br.s IL_017f + + IL_013d: ldstr "Text1" + IL_0142: ret + + IL_0143: ldstr "Text2" + IL_0148: ret + + IL_0149: ldstr "Text3" + IL_014e: ret + + IL_014f: ldstr "Text4" + IL_0154: ret + + IL_0155: ldstr "Text5" + IL_015a: ret + + IL_015b: ldstr "Text6" + IL_0160: ret + + IL_0161: ldstr "Text7" + IL_0166: ret + + IL_0167: ldstr "Text8" + IL_016c: ret + + IL_016d: ldstr "Text9" + IL_0172: ret + + IL_0173: ldstr "Text10" + IL_0178: ret + + IL_0179: ldstr "Text11" + IL_017e: ret + + IL_017f: ldstr "Default" + IL_0184: ret + } // end of method Switch::SwitchOverString2 + + .method public hidebysig static string + TwoDifferentSwitchBlocksInTryFinally() cil managed + { + // Code size 923 (0x39b) + .maxstack 4 + .locals init (string V_0, + object V_1) + IL_0000: volatile. + IL_0002: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-1' + IL_0007: brtrue IL_01b8 + + IL_000c: ldc.i4.s 24 + IL_000e: ldc.r4 0.5 + IL_0013: newobj instance void [mscorlib]System.Collections.Hashtable::.ctor(int32, + float32) + IL_0018: dup + IL_0019: ldstr "12" + IL_001e: ldc.i4.0 + IL_001f: box [mscorlib]System.Int32 + IL_0024: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0029: dup + IL_002a: ldstr "13" + IL_002f: ldc.i4.1 + IL_0030: box [mscorlib]System.Int32 + IL_0035: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_003a: dup + IL_003b: ldstr "14" + IL_0040: ldc.i4.2 + IL_0041: box [mscorlib]System.Int32 + IL_0046: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_004b: dup + IL_004c: ldstr "15" + IL_0051: ldc.i4.3 + IL_0052: box [mscorlib]System.Int32 + IL_0057: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_005c: dup + IL_005d: ldstr "16" + IL_0062: ldc.i4.4 + IL_0063: box [mscorlib]System.Int32 + IL_0068: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_006d: dup + IL_006e: ldstr "17" + IL_0073: ldc.i4.5 + IL_0074: box [mscorlib]System.Int32 + IL_0079: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_007e: dup + IL_007f: ldstr "18" + IL_0084: ldc.i4.6 + IL_0085: box [mscorlib]System.Int32 + IL_008a: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_008f: dup + IL_0090: ldstr "19 case" + IL_0095: ldc.i4.7 + IL_0096: box [mscorlib]System.Int32 + IL_009b: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00a0: dup + IL_00a1: ldstr "20 case" + IL_00a6: ldc.i4.8 + IL_00a7: box [mscorlib]System.Int32 + IL_00ac: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00b1: dup + IL_00b2: ldstr "21 case" + IL_00b7: ldc.i4.s 9 + IL_00b9: box [mscorlib]System.Int32 + IL_00be: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00c3: dup + IL_00c4: ldstr "22 case" + IL_00c9: ldc.i4.s 10 + IL_00cb: box [mscorlib]System.Int32 + IL_00d0: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_00d5: volatile. + IL_00d7: stsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-1' + IL_00dc: volatile. + IL_00de: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-2' + IL_00e3: brtrue IL_01b8 + + IL_00e8: ldc.i4.s 24 + IL_00ea: ldc.r4 0.5 + IL_00ef: newobj instance void [mscorlib]System.Collections.Hashtable::.ctor(int32, + float32) + IL_00f4: dup + IL_00f5: ldstr "First case" + IL_00fa: ldc.i4.0 + IL_00fb: box [mscorlib]System.Int32 + IL_0100: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0105: dup + IL_0106: ldstr "Second case" + IL_010b: ldc.i4.1 + IL_010c: box [mscorlib]System.Int32 + IL_0111: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0116: dup + IL_0117: ldstr "Third case" + IL_011c: ldc.i4.2 + IL_011d: box [mscorlib]System.Int32 + IL_0122: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0127: dup + IL_0128: ldstr "Fourth case" + IL_012d: ldc.i4.3 + IL_012e: box [mscorlib]System.Int32 + IL_0133: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0138: dup + IL_0139: ldstr "Fifth case" + IL_013e: ldc.i4.4 + IL_013f: box [mscorlib]System.Int32 + IL_0144: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_0149: dup + IL_014a: ldstr "Sixth case" + IL_014f: ldc.i4.5 + IL_0150: box [mscorlib]System.Int32 + IL_0155: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_015a: dup + IL_015b: ldstr "Seventh case" + IL_0160: ldc.i4.6 + IL_0161: box [mscorlib]System.Int32 + IL_0166: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_016b: dup + IL_016c: ldstr "Eighth case" + IL_0171: ldc.i4.7 + IL_0172: box [mscorlib]System.Int32 + IL_0177: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_017c: dup + IL_017d: ldstr "Ninth case" + IL_0182: ldc.i4.8 + IL_0183: box [mscorlib]System.Int32 + IL_0188: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_018d: dup + IL_018e: ldstr "Tenth case" + IL_0193: ldc.i4.s 9 + IL_0195: box [mscorlib]System.Int32 + IL_019a: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_019f: dup + IL_01a0: ldstr "Eleventh case" + IL_01a5: ldc.i4.s 10 + IL_01a7: box [mscorlib]System.Int32 + IL_01ac: call instance void [mscorlib]System.Collections.Hashtable::Add(object, + object) + IL_01b1: volatile. + IL_01b3: stsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-2' + .try + { + IL_01b8: ldstr "TwoDifferentSwitchBlocks:" + IL_01bd: call void [mscorlib]System.Console::WriteLine(string) + IL_01c2: call string [mscorlib]System.Environment::get_UserName() + IL_01c7: dup + IL_01c8: stloc.1 + IL_01c9: brfalse IL_0295 + + IL_01ce: volatile. + IL_01d0: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-2' + IL_01d5: ldloc.1 + IL_01d6: call instance object [mscorlib]System.Collections.Hashtable::get_Item(object) + IL_01db: dup + IL_01dc: stloc.1 + IL_01dd: brfalse IL_0295 + + IL_01e2: ldloc.1 + IL_01e3: unbox [mscorlib]System.Int32 + IL_01e8: ldind.i4 + IL_01e9: switch ( + IL_021c, + IL_0227, + IL_0232, + IL_023d, + IL_0248, + IL_0253, + IL_025e, + IL_0269, + IL_0274, + IL_027f, + IL_028a) + IL_021a: br.s IL_0295 + + IL_021c: ldstr "Text1" + IL_0221: stloc.0 + IL_0222: leave IL_0399 + + IL_0227: ldstr "Text2" + IL_022c: stloc.0 + IL_022d: leave IL_0399 + + IL_0232: ldstr "Text3" + IL_0237: stloc.0 + IL_0238: leave IL_0399 + + IL_023d: ldstr "Text4" + IL_0242: stloc.0 + IL_0243: leave IL_0399 + + IL_0248: ldstr "Text5" + IL_024d: stloc.0 + IL_024e: leave IL_0399 + + IL_0253: ldstr "Text6" + IL_0258: stloc.0 + IL_0259: leave IL_0399 + + IL_025e: ldstr "Text7" + IL_0263: stloc.0 + IL_0264: leave IL_0399 + + IL_0269: ldstr "Text8" + IL_026e: stloc.0 + IL_026f: leave IL_0399 + + IL_0274: ldstr "Text9" + IL_0279: stloc.0 + IL_027a: leave IL_0399 + + IL_027f: ldstr "Text10" + IL_0284: stloc.0 + IL_0285: leave IL_0399 + + IL_028a: ldstr "Text11" + IL_028f: stloc.0 + IL_0290: leave IL_0399 + + IL_0295: ldstr "Default" + IL_029a: stloc.0 + IL_029b: leave IL_0399 + + } // end .try + finally + { + IL_02a0: ldstr "Second switch:" + IL_02a5: call void [mscorlib]System.Console::WriteLine(string) + IL_02aa: call string [mscorlib]System.Console::ReadLine() + IL_02af: dup + IL_02b0: stloc.1 + IL_02b1: brfalse IL_038e + + IL_02b6: volatile. + IL_02b8: ldsfld class [mscorlib]System.Collections.Hashtable ''::'$$method0x6000007-1' + IL_02bd: ldloc.1 + IL_02be: call instance object [mscorlib]System.Collections.Hashtable::get_Item(object) + IL_02c3: dup + IL_02c4: stloc.1 + IL_02c5: brfalse IL_038e + + IL_02ca: ldloc.1 + IL_02cb: unbox [mscorlib]System.Int32 + IL_02d0: ldind.i4 + IL_02d1: switch ( + IL_0307, + IL_0316, + IL_0322, + IL_032e, + IL_033a, + IL_0346, + IL_0352, + IL_035e, + IL_036a, + IL_0376, + IL_0382) + IL_0302: br IL_038e + + IL_0307: ldstr "Te43234xt1" + IL_030c: call void [mscorlib]System.Console::WriteLine(string) + IL_0311: br IL_0398 + + IL_0316: ldstr "Te223443xt2" + IL_031b: call void [mscorlib]System.Console::WriteLine(string) + IL_0320: br.s IL_0398 + + IL_0322: ldstr "Te234xt3" + IL_0327: call void [mscorlib]System.Console::WriteLine(string) + IL_032c: br.s IL_0398 + + IL_032e: ldstr "Tex243t4" + IL_0333: call void [mscorlib]System.Console::WriteLine(string) + IL_0338: br.s IL_0398 + + IL_033a: ldstr "Tex243t5" + IL_033f: call void [mscorlib]System.Console::WriteLine(string) + IL_0344: br.s IL_0398 + + IL_0346: ldstr "Text2346" + IL_034b: call void [mscorlib]System.Console::WriteLine(string) + IL_0350: br.s IL_0398 + + IL_0352: ldstr "Text234234" + IL_0357: call void [mscorlib]System.Console::WriteLine(string) + IL_035c: br.s IL_0398 + + IL_035e: ldstr "Text8234" + IL_0363: call void [mscorlib]System.Console::WriteLine(string) + IL_0368: br.s IL_0398 + + IL_036a: ldstr "Text923423" + IL_036f: call void [mscorlib]System.Console::WriteLine(string) + IL_0374: br.s IL_0398 + + IL_0376: ldstr "Text10" + IL_037b: call void [mscorlib]System.Console::WriteLine(string) + IL_0380: br.s IL_0398 + + IL_0382: ldstr "Text1134123" + IL_0387: call void [mscorlib]System.Console::WriteLine(string) + IL_038c: br.s IL_0398 + + IL_038e: ldstr "Defa234234ult" + IL_0393: call void [mscorlib]System.Console::WriteLine(string) + IL_0398: endfinally + } // end handler + IL_0399: ldloc.0 + IL_039a: ret + } // end of method Switch::TwoDifferentSwitchBlocksInTryFinally + + .method public hidebysig static string + SwitchOverBool(bool b) cil managed + { + // Code size 54 (0x36) + .maxstack 2 + .locals init (bool V_0) + IL_0000: ldstr "SwitchOverBool: " + IL_0005: ldarga.s b + IL_0007: call instance string [mscorlib]System.Boolean::ToString() + IL_000c: call string [mscorlib]System.String::Concat(string, + string) + IL_0011: call void [mscorlib]System.Console::WriteLine(string) + IL_0016: ldarg.0 + IL_0017: stloc.0 + IL_0018: ldloc.0 + IL_0019: switch ( + IL_002e, + IL_0028) + IL_0026: br.s IL_0034 + + IL_0028: ldsfld string [mscorlib]System.Boolean::TrueString + IL_002d: ret + + IL_002e: ldsfld string [mscorlib]System.Boolean::FalseString + IL_0033: ret + + IL_0034: ldnull + IL_0035: ret + } // end of method Switch::SwitchOverBool + + .method public hidebysig static void SwitchInLoop(int32 i) cil managed + { + // Code size 112 (0x70) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldstr "SwitchInLoop: " + IL_0005: ldarg.0 + IL_0006: box [mscorlib]System.Int32 + IL_000b: call string [mscorlib]System.String::Concat(object, + object) + IL_0010: call void [mscorlib]System.Console::WriteLine(string) + IL_0015: ldarg.0 + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: ldc.i4.1 + IL_0019: sub + IL_001a: switch ( + IL_0031, + IL_003d, + IL_0054, + IL_0049) + IL_002f: br.s IL_0054 + + IL_0031: ldstr "one" + IL_0036: call void [mscorlib]System.Console::WriteLine(string) + IL_003b: br.s IL_0069 + + IL_003d: ldstr "two" + IL_0042: call void [mscorlib]System.Console::WriteLine(string) + IL_0047: br.s IL_0069 + + IL_0049: ldstr "four" + IL_004e: call void [mscorlib]System.Console::WriteLine(string) + IL_0053: ret + + IL_0054: ldstr "default" + IL_0059: call void [mscorlib]System.Console::WriteLine(string) + IL_005e: ldstr "more code" + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: ret + + IL_0069: ldarg.0 + IL_006a: ldc.i4.1 + IL_006b: add + IL_006c: starg.s i + IL_006e: br.s IL_0015 + } // end of method Switch::SwitchInLoop + + .method public hidebysig static void SwitchWithGoto(int32 i) cil managed + { + // Code size 115 (0x73) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldstr "SwitchWithGoto: " + IL_0005: ldarg.0 + IL_0006: box [mscorlib]System.Int32 + IL_000b: call string [mscorlib]System.String::Concat(object, + object) + IL_0010: call void [mscorlib]System.Console::WriteLine(string) + IL_0015: ldarg.0 + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: ldc.i4.1 + IL_0019: sub + IL_001a: switch ( + IL_0031, + IL_003d, + IL_0047, + IL_0053) + IL_002f: br.s IL_005e + + IL_0031: ldstr "one" + IL_0036: call void [mscorlib]System.Console::WriteLine(string) + IL_003b: br.s IL_005e + + IL_003d: ldstr "two" + IL_0042: call void [mscorlib]System.Console::WriteLine(string) + IL_0047: ldstr "three" + IL_004c: call void [mscorlib]System.Console::WriteLine(string) + IL_0051: br.s IL_0068 + + IL_0053: ldstr "four" + IL_0058: call void [mscorlib]System.Console::WriteLine(string) + IL_005d: ret + + IL_005e: ldstr "default" + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: ldstr "End of method" + IL_006d: call void [mscorlib]System.Console::WriteLine(string) + IL_0072: ret + } // end of method Switch::SwitchWithGoto + + .method private hidebysig static class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty[] + GetProperties() cil managed + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldc.i4.0 + IL_0001: newarr ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty + IL_0006: ret + } // end of method Switch::GetProperties + + .method public hidebysig static void SwitchOnStringInForLoop() cil managed + { + // Code size 267 (0x10b) + .maxstack 6 + .locals init (class [mscorlib]System.Collections.ArrayList V_0, + class [mscorlib]System.Collections.ArrayList V_1, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty[] V_2, + int32 V_3, + class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty V_4, + string V_5) + IL_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor() + IL_0005: stloc.0 + IL_0006: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor() + IL_000b: stloc.1 + IL_000c: call class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty[] ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch::GetProperties() + IL_0011: stloc.2 + IL_0012: ldc.i4.0 + IL_0013: stloc.3 + IL_0014: br IL_0101 + + IL_0019: ldstr "In for-loop" + IL_001e: call void [mscorlib]System.Console::WriteLine(string) + IL_0023: ldloc.2 + IL_0024: ldloc.3 + IL_0025: ldelem.ref + IL_0026: stloc.s V_4 + IL_0028: ldstr "Name1" + IL_002d: ldstr "Name2" + IL_0032: ldstr "Name3" + IL_0037: ldstr "Name4" + IL_003c: ldstr "Name5" + IL_0041: ldstr "Name6" + IL_0046: leave.s IL_0048 + + IL_0048: ldloc.s V_4 + IL_004a: ldfld class [mscorlib]System.Reflection.PropertyInfo ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::Property + IL_004f: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() + IL_0054: dup + IL_0055: stloc.s V_5 + IL_0057: brfalse IL_00f4 + + IL_005c: ldloc.s V_5 + IL_005e: call string [mscorlib]System.String::IsInterned(string) + IL_0063: stloc.s V_5 + IL_0065: ldloc.s V_5 + IL_0067: ldstr "Name1" + IL_006c: beq.s IL_009d + + IL_006e: ldloc.s V_5 + IL_0070: ldstr "Name2" + IL_0075: beq.s IL_00b0 + + IL_0077: ldloc.s V_5 + IL_0079: ldstr "Name3" + IL_007e: beq.s IL_00c3 + + IL_0080: ldloc.s V_5 + IL_0082: ldstr "Name4" + IL_0087: beq.s IL_00d6 + + IL_0089: ldloc.s V_5 + IL_008b: ldstr "Name5" + IL_0090: beq.s IL_00e9 + + IL_0092: ldloc.s V_5 + IL_0094: ldstr "Name6" + IL_0099: beq.s IL_00e9 + + IL_009b: br.s IL_00f4 + + IL_009d: ldloc.s V_4 + IL_009f: ldc.i4.1 + IL_00a0: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + IL_00a5: ldloc.0 + IL_00a6: ldloc.s V_4 + IL_00a8: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00ad: pop + IL_00ae: br.s IL_00fd + + IL_00b0: ldloc.s V_4 + IL_00b2: ldc.i4.2 + IL_00b3: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + IL_00b8: ldloc.0 + IL_00b9: ldloc.s V_4 + IL_00bb: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00c0: pop + IL_00c1: br.s IL_00fd + + IL_00c3: ldloc.s V_4 + IL_00c5: ldc.i4.3 + IL_00c6: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + IL_00cb: ldloc.0 + IL_00cc: ldloc.s V_4 + IL_00ce: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00d3: pop + IL_00d4: br.s IL_00fd + + IL_00d6: ldloc.s V_4 + IL_00d8: ldc.i4.4 + IL_00d9: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch/SetProperty::set_Set(int32) + IL_00de: ldloc.0 + IL_00df: ldloc.s V_4 + IL_00e1: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00e6: pop + IL_00e7: br.s IL_00fd + + IL_00e9: ldloc.0 + IL_00ea: ldloc.s V_4 + IL_00ec: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00f1: pop + IL_00f2: br.s IL_00fd + + IL_00f4: ldloc.1 + IL_00f5: ldloc.s V_4 + IL_00f7: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object) + IL_00fc: pop + IL_00fd: ldloc.3 + IL_00fe: ldc.i4.1 + IL_00ff: add + IL_0100: stloc.3 + IL_0101: ldloc.3 + IL_0102: ldloc.2 + IL_0103: ldlen + IL_0104: conv.i4 + IL_0105: blt IL_0019 + + IL_010a: ret + } // end of method Switch::SwitchOnStringInForLoop + + .method public hidebysig static void SwitchWithComplexCondition(string[] args) cil managed + { + // Code size 139 (0x8b) + .maxstack 4 + .locals init (string V_0) + IL_0000: ldstr "a" + IL_0005: ldstr "b" + IL_000a: ldstr "c" + IL_000f: ldstr "d" + IL_0014: leave.s IL_0016 + + IL_0016: ldarg.0 + IL_0017: ldlen + IL_0018: conv.i4 + IL_0019: brfalse.s IL_0020 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.0 + IL_001d: ldelem.ref + IL_001e: br.s IL_0025 + + IL_0020: ldstr "dummy" + IL_0025: dup + IL_0026: stloc.0 + IL_0027: brfalse.s IL_0080 + + IL_0029: ldloc.0 + IL_002a: call string [mscorlib]System.String::IsInterned(string) + IL_002f: stloc.0 + IL_0030: ldloc.0 + IL_0031: ldstr "a" + IL_0036: beq.s IL_0052 + + IL_0038: ldloc.0 + IL_0039: ldstr "b" + IL_003e: beq.s IL_005e + + IL_0040: ldloc.0 + IL_0041: ldstr "c" + IL_0046: beq.s IL_006a + + IL_0048: ldloc.0 + IL_0049: ldstr "d" + IL_004e: beq.s IL_0076 + + IL_0050: br.s IL_0080 + + IL_0052: ldstr "a" + IL_0057: call void [mscorlib]System.Console::WriteLine(string) + IL_005c: br.s IL_0080 + + IL_005e: ldstr "b" + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: br.s IL_0080 + + IL_006a: ldstr "c" + IL_006f: call void [mscorlib]System.Console::WriteLine(string) + IL_0074: br.s IL_0080 + + IL_0076: ldstr "d" + IL_007b: call void [mscorlib]System.Console::WriteLine(string) + IL_0080: ldstr "end" + IL_0085: call void [mscorlib]System.Console::WriteLine(string) + IL_008a: ret + } // end of method Switch::SwitchWithComplexCondition + + .method public hidebysig static void SwitchWithArray(string[] args) cil managed + { + // Code size 127 (0x7f) + .maxstack 4 + .locals init (string V_0) + IL_0000: ldstr "a" + IL_0005: ldstr "b" + IL_000a: ldstr "c" + IL_000f: ldstr "d" + IL_0014: leave.s IL_0016 + + IL_0016: ldarg.0 + IL_0017: ldc.i4.0 + IL_0018: ldelem.ref + IL_0019: dup + IL_001a: stloc.0 + IL_001b: brfalse.s IL_0074 + + IL_001d: ldloc.0 + IL_001e: call string [mscorlib]System.String::IsInterned(string) + IL_0023: stloc.0 + IL_0024: ldloc.0 + IL_0025: ldstr "a" + IL_002a: beq.s IL_0046 + + IL_002c: ldloc.0 + IL_002d: ldstr "b" + IL_0032: beq.s IL_0052 + + IL_0034: ldloc.0 + IL_0035: ldstr "c" + IL_003a: beq.s IL_005e + + IL_003c: ldloc.0 + IL_003d: ldstr "d" + IL_0042: beq.s IL_006a + + IL_0044: br.s IL_0074 + + IL_0046: ldstr "a" + IL_004b: call void [mscorlib]System.Console::WriteLine(string) + IL_0050: br.s IL_0074 + + IL_0052: ldstr "b" + IL_0057: call void [mscorlib]System.Console::WriteLine(string) + IL_005c: br.s IL_0074 + + IL_005e: ldstr "c" + IL_0063: call void [mscorlib]System.Console::WriteLine(string) + IL_0068: br.s IL_0074 + + IL_006a: ldstr "d" + IL_006f: call void [mscorlib]System.Console::WriteLine(string) + IL_0074: ldstr "end" + IL_0079: call void [mscorlib]System.Console::WriteLine(string) + IL_007e: ret + } // end of method Switch::SwitchWithArray + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Switch::.ctor + +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Switch + +.class private auto ansi '' + extends [mscorlib]System.Object +{ + .field static assembly class [mscorlib]System.Collections.Hashtable '$$method0x6000006-1' + .field static assembly class [mscorlib]System.Collections.Hashtable '$$method0x6000007-1' + .field static assembly class [mscorlib]System.Collections.Hashtable '$$method0x6000007-2' +} // end of class '' + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file C:\Users\Siegfried\Projects\ILSpy master\ICSharpCode.Decompiler.Tests\TestCases\ILPretty\CS1xSwitch_Release.res diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 452089f2e..5f2d2553e 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -229,6 +229,8 @@ namespace ICSharpCode.Decompiler.CSharp if (settings.AnonymousTypes && type.IsAnonymousType()) return true; } + if (settings.ArrayInitializers && settings.SwitchStatementOnString && type.Name.StartsWith("", StringComparison.Ordinal)) + return true; } FieldDefinition field = member as FieldDefinition; @@ -244,12 +246,15 @@ namespace ICSharpCode.Decompiler.CSharp // event-fields are not [CompilerGenerated] if (settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name)) return true; - // HACK : only hide fields starting with '__StaticArrayInit' if (settings.ArrayInitializers && field.DeclaringType.Name.StartsWith("", StringComparison.Ordinal)) { + // hide fields starting with '__StaticArrayInit' if (field.Name.StartsWith("__StaticArrayInit", StringComparison.Ordinal)) return true; if (field.FieldType.Name.StartsWith("__StaticArrayInit", StringComparison.Ordinal)) return true; + // hide fields starting with '$$method' + if (field.Name.StartsWith("$$method", StringComparison.Ordinal)) + return true; } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs index 7668accde..03ff10994 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs @@ -25,6 +25,8 @@ using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.IL.Transforms { + using HashtableInitializer = Dictionary Labels, IfInstruction JumpToNext, Block ContainingBlock, Block Previous, Block Next, bool Transformed)>; + /// /// Detects switch-on-string patterns employed by the C# compiler and transforms them to an ILAst-switch-instruction. /// @@ -35,6 +37,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (!context.Settings.SwitchStatementOnString) return; + BlockContainer body = (BlockContainer)function.Body; + var hashtableInitializers = ScanHashtableInitializerBlocks(body.EntryPoint); + HashSet changedContainers = new HashSet(); foreach (var block in function.Descendants.OfType()) { @@ -44,7 +49,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms changed = true; continue; } - if (MatchLegacySwitchOnStringWithHashtable(block.Instructions, ref i)) { + if (SimplifyCSharp1CascadingIfStatements(block.Instructions, ref i)) { + changed = true; + continue; + } + if (MatchLegacySwitchOnStringWithHashtable(block, hashtableInitializers, ref i)) { changed = true; continue; } @@ -63,10 +72,83 @@ namespace ICSharpCode.Decompiler.IL.Transforms changedContainers.Add(container); } + var omittedBlocks = new Dictionary(); + + // Remove all transformed hashtable initializers from the entrypoint. + foreach (var item in hashtableInitializers) { + var (labels, jumpToNext, containingBlock, previous, next, transformed) = item.Value; + if (!transformed) continue; + if (!omittedBlocks.TryGetValue(previous, out var actual)) + actual = previous; + if (jumpToNext != null) { + actual.Instructions.SecondToLastOrDefault().ReplaceWith(jumpToNext); + } + actual.Instructions.LastOrDefault().ReplaceWith(new Branch(next)); + omittedBlocks.Add(containingBlock, previous); + changedContainers.Add(body); + } + + // If all initializer where removed, remove the initial null check as well. + if (hashtableInitializers.Count > 0 && omittedBlocks.Count == hashtableInitializers.Count && body.EntryPoint.Instructions.Count == 2) { + if (body.EntryPoint.Instructions[0] is IfInstruction ifInst + && ifInst.TrueInst.MatchBranch(out var beginOfMethod) && body.EntryPoint.Instructions[1].MatchBranch(beginOfMethod)) { + body.EntryPoint.Instructions.RemoveAt(0); + } + } + foreach (var container in changedContainers) container.SortBlocks(deleteUnreachableBlocks: true); } + HashtableInitializer ScanHashtableInitializerBlocks(Block entryPoint) + { + var hashtables = new HashtableInitializer(); + if (entryPoint.Instructions.Count != 2) + return hashtables; + // match first block: checking compiler-generated Hashtable for null + // if (comp(volatile.ldobj System.Collections.Hashtable(ldsflda $$method0x600003f-1) != ldnull)) br switchHeadBlock + // br tableInitBlock + if (!(entryPoint.Instructions[0].MatchIfInstruction(out var condition, out var branchToSwitchHead))) + return hashtables; + if (!entryPoint.Instructions[1].MatchBranch(out var tableInitBlock)) + return hashtables; + if (!(condition.MatchCompNotEquals(out var left, out var right) && right.MatchLdNull() && + MatchDictionaryFieldLoad(left, IsNonGenericHashtable, out var dictField, out var dictionaryType))) + return hashtables; + if (!branchToSwitchHead.MatchBranch(out var switchHead)) + return hashtables; + // match second block: initialization of compiler-generated Hashtable + // stloc table(newobj Hashtable..ctor(ldc.i4 capacity, ldc.f loadFactor)) + // call Add(ldloc table, ldstr value, box System.Int32(ldc.i4 index)) + // ... more calls to Add ... + // volatile.stobj System.Collections.Hashtable(ldsflda $$method0x600003f - 1, ldloc table) + // br switchHeadBlock + if (tableInitBlock.IncomingEdgeCount != 1 || tableInitBlock.Instructions.Count < 3) + return hashtables; + Block previousBlock = entryPoint; + while (tableInitBlock != null) { + if (!ExtractStringValuesFromInitBlock(tableInitBlock, out var stringValues, out var blockAfterThisInitBlock, dictionaryType, dictField, true)) + break; + var nextHashtableInitHead = tableInitBlock.Instructions.SecondToLastOrDefault() as IfInstruction; + hashtables.Add(dictField, (stringValues, nextHashtableInitHead, tableInitBlock, previousBlock, blockAfterThisInitBlock, false)); + previousBlock = tableInitBlock; + // if there is another IfInstruction before the end of the block, it might be a jump to the next hashtable init block. + // if (comp(volatile.ldobj System.Collections.Hashtable(ldsflda $$method0x600003f-2) != ldnull)) br switchHeadBlock + if (nextHashtableInitHead != null) { + if (!(nextHashtableInitHead.Condition.MatchCompNotEquals(out left, out right) && right.MatchLdNull() && + MatchDictionaryFieldLoad(left, IsNonGenericHashtable, out var nextDictField, out _))) + break; + if (!nextHashtableInitHead.TrueInst.MatchBranch(switchHead)) + break; + tableInitBlock = blockAfterThisInitBlock; + dictField = nextDictField; + } else { + break; + } + } + return hashtables; + } + bool SimplifyCascadingIfStatements(InstructionCollection instructions, ref int i) { if (i < 1) return false; @@ -98,8 +180,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms var otherSwitchValueVar = switchValueVar; switchValueVar = stloc.Variable; if (i >= 2 && instructions[i - 2].MatchStLoc(otherSwitchValueVar, out switchValue) - && otherSwitchValueVar.IsSingleDefinition && otherSwitchValueVar.LoadCount == 2) - { + && otherSwitchValueVar.IsSingleDefinition && otherSwitchValueVar.LoadCount == 2) { extraLoad = true; } else { switchValue = new LdLoc(otherSwitchValueVar); @@ -148,6 +229,91 @@ namespace ICSharpCode.Decompiler.IL.Transforms return true; } + bool SimplifyCSharp1CascadingIfStatements(InstructionCollection instructions, ref int i) + { + if (i < 1) return false; + // match first block: + // stloc switchValueVar(ldloc temp) + // if (comp(ldloc temp == ldnull)) br defaultBlock + // br isInternedBlock + if (!(instructions[i].MatchIfInstruction(out var condition, out var defaultBlockJump))) + return false; + if (!instructions[i + 1].MatchBranch(out var isInternedBlock)) + return false; + if (!defaultBlockJump.MatchBranch(out var defaultOrNullBlock)) + return false; + if (!(condition.MatchCompEqualsNull(out var tempLoad) && tempLoad.MatchLdLoc(out var temp))) + return false; + if (!(temp.Kind == VariableKind.StackSlot && temp.LoadCount == 2)) + return false; + if (!(instructions[i - 1].MatchStLoc(out var switchValueVar, out var switchValue) && switchValue.MatchLdLoc(temp))) + return false; + // match isInternedBlock: + // stloc switchValueVarCopy(call IsInterned(ldloc switchValueVar)) + // if (comp(ldloc switchValueVarCopy == ldstr "case1")) br caseBlock1 + // br caseHeader2 + if (isInternedBlock.IncomingEdgeCount != 1 || isInternedBlock.Instructions.Count != 3) + return false; + if (!(isInternedBlock.Instructions[0].MatchStLoc(out var switchValueVarCopy, out var arg) && IsIsInternedCall(arg as Call, out arg) && arg.MatchLdLoc(switchValueVar))) + return false; + switchValueVar = switchValueVarCopy; + int conditionOffset = 1; + Block currentCaseBlock = isInternedBlock; + List<(string, Block)> values = new List<(string, Block)>(); + + // each case starts with: + // if (comp(ldloc switchValueVar == ldstr "case label")) br caseBlock + // br currentCaseBlock + + while (currentCaseBlock.Instructions[conditionOffset].MatchIfInstruction(out condition, out var caseBlockJump)) { + if (currentCaseBlock.Instructions.Count != conditionOffset + 2) + break; + if (!condition.MatchCompEquals(out var left, out var right)) + break; + if (!left.MatchLdLoc(switchValueVar)) + break; + if (!right.MatchLdStr(out string value)) + break; + if (!caseBlockJump.MatchBranch(out var caseBlock)) + break; + if (!currentCaseBlock.Instructions[conditionOffset + 1].MatchBranch(out currentCaseBlock)) + break; + conditionOffset = 0; + values.Add((value, caseBlock)); + } + + // switch contains case null: + if (currentCaseBlock != defaultOrNullBlock) { + values.Add((null, defaultOrNullBlock)); + } + + var sections = new List(values.SelectWithIndex((index, b) => new SwitchSection { Labels = new LongSet(index), Body = new Branch(b.Item2) })); + sections.Add(new SwitchSection { Labels = new LongSet(new LongInterval(0, sections.Count)).Invert(), Body = new Branch(currentCaseBlock) }); + var stringToInt = new StringToInt(switchValue, values.SelectArray(item => item.Item1)); + var inst = new SwitchInstruction(stringToInt); + inst.Sections.AddRange(sections); + + instructions[i].ReplaceWith(inst); + instructions.RemoveAt(i + 1); + instructions.RemoveAt(i - 1); + + return true; + } + + bool IsIsInternedCall(Call call, out ILInstruction argument) + { + if (call != null + && call.Method.DeclaringType.IsKnownType(KnownTypeCode.String) + && call.Method.IsStatic + && call.Method.Name == "IsInterned" + && call.Arguments.Count == 1) { + argument = call.Arguments[0]; + return true; + } + argument = null; + return false; + } + /// /// Each case consists of two blocks: /// 1. block: @@ -235,7 +401,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms // br switchHeadBlock if (dictInitBlock.IncomingEdgeCount != 1 || dictInitBlock.Instructions.Count < 3) return false; - if (!ExtractStringValuesFromInitBlock(dictInitBlock, out var stringValues, tryGetValueBlock, dictionaryType, dictField)) + if (!ExtractStringValuesFromInitBlock(dictInitBlock, out var stringValues, out var blockAfterInit, dictionaryType, dictField, false)) + return false; + if (tryGetValueBlock != blockAfterInit) return false; // match fourth block: TryGetValue on compiler-generated Dictionary // if (logic.not(call TryGetValue(volatile.ldobj System.Collections.Generic.Dictionary`2[[System.String],[System.Int32]](ldsflda $$method0x600000c-1), ldloc switchValueVar, ldloca switchIndexVar))) br defaultBlock @@ -382,9 +550,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// /// Matches and extracts values from Add-call sequences. /// - bool ExtractStringValuesFromInitBlock(Block block, out List<(string, int)> values, Block targetBlock, IType dictionaryType, IField dictionaryField) + bool ExtractStringValuesFromInitBlock(Block block, out List<(string, int)> values, out Block blockAfterInit, IType dictionaryType, IField dictionaryField, bool isHashtablePattern) { values = null; + blockAfterInit = null; // stloc dictVar(newobj Dictionary..ctor(ldc.i4 valuesLength)) // -or- // stloc dictVar(newobj Hashtable..ctor(ldc.i4 capacity, ldc.f4 loadFactor)) @@ -414,7 +583,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms dictType.Equals(dictionaryType) && loadField.MatchLdsFlda(out var dictField) && dictField.Equals(dictionaryField) && dictVarLoad.MatchLdLoc(dictVar))) return false; - return block.Instructions[i + 2].MatchBranch(targetBlock); + if (isHashtablePattern && block.Instructions[i + 2] is IfInstruction) { + return block.Instructions[i + 3].MatchBranch(out blockAfterInit); + } + return block.Instructions[i + 2].MatchBranch(out blockAfterInit); } /// @@ -454,48 +626,26 @@ namespace ICSharpCode.Decompiler.IL.Transforms return true; } - bool MatchLegacySwitchOnStringWithHashtable(InstructionCollection instructions, ref int i) + bool MatchLegacySwitchOnStringWithHashtable(Block block, HashtableInitializer hashtableInitializers, ref int i) { - // match first block: checking compiler-generated Hashtable for null - // if (comp(volatile.ldobj System.Collections.Hashtable(ldsflda $$method0x600003f-1) != ldnull)) br switchHeadBlock - // br tableInitBlock - if (!(instructions[i].MatchIfInstruction(out var condition, out var branchToSwitchHead) && i + 1 < instructions.Count)) - return false; - if (!instructions[i + 1].MatchBranch(out var tableInitBlock) || tableInitBlock.IncomingEdgeCount != 1) - return false; - if (!(condition.MatchCompNotEquals(out var left, out var right) && right.MatchLdNull() && - MatchDictionaryFieldLoad(left, IsNonGenericHashtable, out var dictField, out var dictionaryType))) - return false; - if (!branchToSwitchHead.MatchBranch(out var switchHead)) - return false; - // match second block: initialization of compiler-generated Hashtable - // stloc table(newobj Hashtable..ctor(ldc.i4 capacity, ldc.f loadFactor)) - // call Add(ldloc table, ldstr value, box System.Int32(ldc.i4 index)) - // ... more calls to Add ... - // volatile.stobj System.Collections.Hashtable(ldsflda $$method0x600003f - 1, ldloc table) - // br switchHeadBlock - if (tableInitBlock.IncomingEdgeCount != 1 || tableInitBlock.Instructions.Count < 3) - return false; - if (!ExtractStringValuesFromInitBlock(tableInitBlock, out var stringValues, switchHead, dictionaryType, dictField)) - return false; - // match third block: checking switch-value for null + // match first block: checking switch-value for null // stloc tmp(ldloc switch-value) // stloc switchVariable(ldloc tmp) // if (comp(ldloc tmp == ldnull)) br nullCaseBlock - // br getItemBlock - if (switchHead.Instructions.Count != 4 || switchHead.IncomingEdgeCount != 2) + // br getItemBloc + if (block.Instructions.Count != i + 4) return false; - if (!switchHead.Instructions[0].MatchStLoc(out var tmp, out var switchValue)) + if (!block.Instructions[i].MatchStLoc(out var tmp, out var switchValue)) return false; - if (!switchHead.Instructions[1].MatchStLoc(out var switchVariable, out var tmpLoad) || !tmpLoad.MatchLdLoc(tmp)) + if (!block.Instructions[i + 1].MatchStLoc(out var switchVariable, out var tmpLoad) || !tmpLoad.MatchLdLoc(tmp)) return false; - if (!switchHead.Instructions[2].MatchIfInstruction(out condition, out var nullCaseBlockBranch)) + if (!block.Instructions[i + 2].MatchIfInstruction(out var condition, out var nullCaseBlockBranch)) return false; - if (!switchHead.Instructions[3].MatchBranch(out var getItemBlock) || !nullCaseBlockBranch.MatchBranch(out var nullCaseBlock)) + if (!block.Instructions[i + 3].MatchBranch(out var getItemBlock) || !(nullCaseBlockBranch.MatchBranch(out var nullCaseBlock) || nullCaseBlockBranch is Leave)) return false; - if (!(condition.MatchCompEquals(out left, out right) && right.MatchLdNull() && left.MatchLdLoc(tmp))) + if (!(condition.MatchCompEquals(out var left, out var right) && right.MatchLdNull() && left.MatchLdLoc(tmp))) return false; - // match fourth block: get_Item on compiler-generated Hashtable + // match second block: get_Item on compiler-generated Hashtable // stloc tmp2(call get_Item(volatile.ldobj System.Collections.Hashtable(ldsflda $$method0x600003f - 1), ldloc switchVariable)) // stloc switchVariable(ldloc tmp2) // if (comp(ldloc tmp2 == ldnull)) br defaultCaseBlock @@ -510,14 +660,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; if (!getItemBlock.Instructions[2].MatchIfInstruction(out condition, out var defaultBlockBranch)) return false; - if (!getItemBlock.Instructions[3].MatchBranch(out var switchBlock) || !defaultBlockBranch.MatchBranch(out var defaultBlock)) + if (!getItemBlock.Instructions[3].MatchBranch(out var switchBlock) || !(defaultBlockBranch.MatchBranch(out var defaultBlock) || defaultBlockBranch is Leave)) return false; if (!(condition.MatchCompEquals(out left, out right) && right.MatchLdNull() && left.MatchLdLoc(tmp2))) return false; - if (!(getItemCall.Arguments.Count == 2 && MatchDictionaryFieldLoad(getItemCall.Arguments[0], IsStringToIntDictionary, out var dictField2, out _) && dictField2.Equals(dictField)) && - getItemCall.Arguments[1].MatchLdLoc(switchVariable2)) + if (!(getItemCall.Arguments.Count == 2 && MatchDictionaryFieldLoad(getItemCall.Arguments[0], IsNonGenericHashtable, out var dictField, out _) && getItemCall.Arguments[1].MatchLdLoc(switchVariable))) return false; - // match fifth block: switch-instruction block + // Check if there is a hashtable init block at the beginning of the method + if (!hashtableInitializers.TryGetValue(dictField, out var info)) + return false; + var stringValues = info.Labels; + // match third block: switch-instruction block // switch (ldobj System.Int32(unbox System.Int32(ldloc switchVariable))) { // case [0..1): br caseBlock1 // ... more cases ... @@ -530,7 +683,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms return false; var sections = new List(switchInst.Sections); // switch contains case null: - if (nullCaseBlock != defaultBlock) { + if (!(nullCaseBlockBranch is Leave) && nullCaseBlock != defaultBlock) { if (!AddNullSection(sections, stringValues, nullCaseBlock)) { return false; } @@ -538,8 +691,55 @@ namespace ICSharpCode.Decompiler.IL.Transforms var stringToInt = new StringToInt(switchValue, stringValues); var inst = new SwitchInstruction(stringToInt); inst.Sections.AddRange(sections); - instructions[i + 1].ReplaceWith(inst); - instructions.RemoveAt(i); + block.Instructions[i].ReplaceWith(inst); + block.Instructions.RemoveRange(i + 1, 3); + info.Transformed = true; + hashtableInitializers[dictField] = info; + return true; + } + + bool FindHashtableInitBlock(Block entryPoint, out List<(string, int)> stringValues, out IField dictField, out Block blockAfterThisInitBlock, out ILInstruction thisSwitchInitJumpInst, out ILInstruction nextSwitchInitJumpInst) + { + stringValues = null; + dictField = null; + blockAfterThisInitBlock = null; + nextSwitchInitJumpInst = null; + thisSwitchInitJumpInst = null; + if (entryPoint.Instructions.Count != 2) + return false; + // match first block: checking compiler-generated Hashtable for null + // if (comp(volatile.ldobj System.Collections.Hashtable(ldsflda $$method0x600003f-1) != ldnull)) br switchHeadBlock + // br tableInitBlock + if (!(entryPoint.Instructions[0].MatchIfInstruction(out var condition, out var branchToSwitchHead))) + return false; + if (!entryPoint.Instructions[1].MatchBranch(out var tableInitBlock)) + return false; + if (!(condition.MatchCompNotEquals(out var left, out var right) && right.MatchLdNull() && + MatchDictionaryFieldLoad(left, IsNonGenericHashtable, out dictField, out var dictionaryType))) + return false; + if (!branchToSwitchHead.MatchBranch(out var switchHead)) + return false; + thisSwitchInitJumpInst = entryPoint.Instructions[0]; + // match second block: initialization of compiler-generated Hashtable + // stloc table(newobj Hashtable..ctor(ldc.i4 capacity, ldc.f loadFactor)) + // call Add(ldloc table, ldstr value, box System.Int32(ldc.i4 index)) + // ... more calls to Add ... + // volatile.stobj System.Collections.Hashtable(ldsflda $$method0x600003f - 1, ldloc table) + // br switchHeadBlock + if (tableInitBlock.IncomingEdgeCount != 1 || tableInitBlock.Instructions.Count < 3) + return false; + if (!ExtractStringValuesFromInitBlock(tableInitBlock, out stringValues, out blockAfterThisInitBlock, dictionaryType, dictField, true)) + return false; + // if there is another IfInstruction before the end of the block, it might be a jump to the next hashtable init block. + // if (comp(volatile.ldobj System.Collections.Hashtable(ldsflda $$method0x600003f-2) != ldnull)) br switchHeadBlock + if (tableInitBlock.Instructions.SecondToLastOrDefault() is IfInstruction nextHashtableInitHead) { + if (!(nextHashtableInitHead.Condition.MatchCompNotEquals(out left, out right) && right.MatchLdNull() && + MatchDictionaryFieldLoad(left, IsNonGenericHashtable, out var nextSwitchInitField, out _))) + return false; + if (!nextHashtableInitHead.TrueInst.MatchBranch(switchHead)) + return false; + nextSwitchInitJumpInst = nextHashtableInitHead; + } return true; }