C#编译器优化那点事 (2)

未优化

.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 74 (0x4a) .maxstack 1 IL_0000: nop .try { IL_0001: nop IL_0002: nop IL_0003: leave.s IL_001a } // end .try catch [System.Runtime]System.Exception { IL_0005: pop IL_0006: nop IL_0007: call valuetype [System.Runtime]System.DateTime [System.Runtime]System.DateTime::get_Now() IL_000c: box [System.Runtime]System.DateTime IL_0011: call void [System.Console]System.Console::WriteLine(object) IL_0016: nop IL_0017: nop IL_0018: leave.s IL_001a } // end handler IL_001a: nop .try { .try { IL_001b: nop IL_001c: nop IL_001d: leave.s IL_0034 } // end .try catch [System.Runtime]System.Exception { IL_001f: pop IL_0020: nop IL_0021: call valuetype [System.Runtime]System.DateTime [System.Runtime]System.DateTime::get_Now() IL_0026: box [System.Runtime]System.DateTime IL_002b: call void [System.Console]System.Console::WriteLine(object) IL_0030: nop IL_0031: nop IL_0032: leave.s IL_0034 } // end handler IL_0034: leave.s IL_0049 } // end .try finally { IL_0036: nop IL_0037: call valuetype [System.Runtime]System.DateTime [System.Runtime]System.DateTime::get_Now() IL_003c: box [System.Runtime]System.DateTime IL_0041: call void [System.Console]System.Console::WriteLine(object) IL_0046: nop IL_0047: nop IL_0048: endfinally } // end handler IL_0049: ret } // end of method Program::Main

优化开关开启:

.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 19 (0x13) .maxstack 1 .try { IL_0000: leave.s IL_0012 } // end .try finally { IL_0002: call valuetype [System.Runtime]System.DateTime [System.Runtime]System.DateTime::get_Now() IL_0007: box [System.Runtime]System.DateTime IL_000c: call void [System.Console]System.Console::WriteLine(object) IL_0011: endfinally } // end handler IL_0012: ret } // end of method Program::Main

很明显可以看到,空的try catch直接消失了,但是空的try catch finally代码是不会消失的,但是也不会直接调用finally内的代码(即还是会生成try代码段)。

分支简化 代码如下:

using System; using System.Threading.Tasks; namespace CompileOpt { class Program { static void Main(string[] args) { int x = 3; if (x == 3) goto LABEL1; else goto LABEL2; LABEL2: return; LABEL1: return; } } }

未优化的情况下:

.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 22 (0x16) .maxstack 2 .locals init (int32 V_0, bool V_1) IL_0000: nop IL_0001: ldc.i4.3 IL_0002: stloc.0 IL_0003: ldloc.0 IL_0004: ldc.i4.3 IL_0005: ceq IL_0007: stloc.1 IL_0008: ldloc.1 IL_0009: brfalse.s IL_000d IL_000b: br.s IL_0012 IL_000d: br.s IL_000f IL_000f: nop IL_0010: br.s IL_0015 IL_0012: nop IL_0013: br.s IL_0015 IL_0015: ret } // end of method Program::Main

优化:

.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 5 (0x5) .maxstack 8 IL_0000: ldc.i4.3 IL_0001: ldc.i4.3 IL_0002: pop IL_0003: pop IL_0004: ret } // end of method Program::Main

优化的情况下,一些分支会被简化,使得调用更加简洁。

跳转简化 代码如下:

using System; using System.Threading.Tasks; namespace CompileOpt { class Program { static void Main(string[] args) { goto LABEL1; LABEL2: Console.WriteLine("234"); Console.WriteLine("123"); return; LABEL1: goto LABEL2; } } }

未优化:

.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 32 (0x20) .maxstack 8 IL_0000: nop IL_0001: br.s IL_001c IL_0003: nop IL_0004: ldstr "234" IL_0009: call void [System.Console]System.Console::WriteLine(string) IL_000e: nop IL_000f: ldstr "123" IL_0014: call void [System.Console]System.Console::WriteLine(string) IL_0019: nop IL_001a: br.s IL_001f IL_001c: nop IL_001d: br.s IL_0003 IL_001f: ret } // end of method Program::Main

优化后:

.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 21 (0x15) .maxstack 8 IL_0000: ldstr "234" IL_0005: call void [System.Console]System.Console::WriteLine(string) IL_000a: ldstr "123" IL_000f: call void [System.Console]System.Console::WriteLine(string) IL_0014: ret } // end of method Program::Main

一些多层的标签跳转会得到简化,优化器就是人狠话不多。

临时变量消除 一些临时变量(中间变量)会被简化消除。代码如下:

using System; using System.Threading.Tasks; namespace CompileOpt { class Program { static void Main(string[] args) { for (int i = 0; i < 3; i++) { Console.WriteLine(i); } for (int i = 0; i < 3; i++) { Console.WriteLine(i + 1); } } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwjdp.html