.NET9 Pre3 CLR的优化细节

文摘   科技   2024-04-15 14:48   湖北  

点击上方蓝字 江湖评谈设为关注




前言

上一篇:.NET9 Pre3 CLR的改进,讲了下.NET9 Pre3的CLR改进,第二个改进点即是内联。本篇详细看下,略有繁芜。

内联

Pre3里面,哪些代码可以内联优化呢?诸如以下这种:

typeof(T) == obj.GetType()typeof(T) == typeof(T)typeof(T) == nullobj1.GetType() == obj2.GetType()

比如其中的typeof,如果出现以下代码:

public static bool Callee<T>() => typeof(T) == typeof(int);

.NET9 Pre3之前呢?typeof函数它实际上是调用了System.Type.GetTypeFromHandle获取到类型,通过System.Type.op_Equality进行类型比较。则比较麻烦。

这里的优化是在JIT层面进行的,如果JIT检测到GetTypeFromHandle和op_Equality标记了Intrincis,则在JIT构建IR的时候,就把这个结果判断出来。

Importing BB01 (PC=000) of 'ConsoleApp3.Program:Callee[int]():ubyte'    [ 0]   0 (0x000) ldtoken    [ 1]   5 (0x005) call 0A00000EIn Compiler::impImportCall: opcode is call, kind=0, callRetType is ref, structSize is 0Named Intrinsic System.Type.GetTypeFromHandle: Recognized
[ 1] 10 (0x00a) ldtoken [ 2] 15 (0x00f) call 0A00000EIn Compiler::impImportCall: opcode is call, kind=0, callRetType is ref, structSize is 0Named Intrinsic System.Type.GetTypeFromHandle: Recognized
[ 2] 20 (0x014) call 0A00000FIn Compiler::impImportCall: opcode is call, kind=0, callRetType is ubyte, structSize is 0Named Intrinsic System.Type.op_Equality: RecognizedImporting Type.op_*Equality intrinsic
Folding call to Type:op_Equality to a simple compare via EQOptimizing compare of types-from-handles to instead compare handlesAsking runtime to compare 00007FF89EF9FC30 (System.Int32) and 00007FF89EF9FC30 (System.Int32) for equalityRuntime reports comparison is known at jit time: 0
[ 1] 25 (0x019) ret
STMT00000 ( 0x000[E-] ... ??? ) [000008] ----------- * RETURN int [000007] ----------- \--* CNS_INT int 1

上面很清晰的看到在JIT Compile的时候就已经判断出了返回的值是0(false)。JIT判断代码:

const bool typesAreEqual = (s == TypeCompareState::Must);const bool operatorIsEQ  = (oper == GT_EQ);const int  compareResult = operatorIsEQ ^ typesAreEqual ? 0 : 1;JITDUMP("Runtime reports comparison is known at jit time: %u\n", compareResult);GenTree* result = gtNewIconNode(compareResult);                return result;

减少IR的代码,即如果泛型T与int同类型,则返回true,否则false。而不需要等到JIT生成机器码的时候,生成繁杂的GetTypeFromHandle和op_Equality机器码。

push    rbpmov     rbp,rspmov     eax,1 //类型相同为1,不同为0pop     rbpret

未优化前的:

ConsoleApp3.dll!ConsoleApp3.Program.Callee<T>()://此处省略,便于观看00007FF8BCAE22C3 FF 15 07 2C F4 FF    call        qword ptr [System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)+08h (07FF8BCA24ED0h)]  00007FF8BCAE22C9 48 89 45 E8          mov         qword ptr [rbp-18h],rax  00007FF8BCAE22CD 48 B9 88 11 A5 BC F8 7F 00 00 mov         rcx,7FF8BCA51188h  00007FF8BCAE22D7 E8 24 14 AE 5F       call        00007FF91C5C3700  00007FF8BCAE22DC 48 89 45 E0          mov         qword ptr [rbp-20h],rax  00007FF8BCAE22E0 48 8B 4D E0          mov         rcx,qword ptr [rbp-20h]  00007FF8BCAE22E4 FF 15 E6 2B F4 FF    call        qword ptr [System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)+08h (07FF8BCA24ED0h)]  00007FF8BCAE22EA 48 89 45 D8          mov         qword ptr [rbp-28h],rax  00007FF8BCAE22EE 48 8B 4D E8          mov         rcx,qword ptr [rbp-18h]  00007FF8BCAE22F2 48 8B 55 D8          mov         rdx,qword ptr [rbp-28h]  00007FF8BCAE22F6 FF 15 84 3C F4 FF    call        qword ptr [System.Type.op_Equality(System.Type, System.Type)+08h (07FF8BCA25F80h)]  //此处省略,便于观看00007FF8BCAE230B C3                   ret

未优化前,即使是删除了部分代码,依然是比较繁杂。

代码

代码(注意观察需要在Debug模式下开启Debuggable特性,也可以C# Code Relase放到CLR里面),参考:.NET9极致性能CLR操控MSIL(分层编译)

可以加特性[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]或者dotnet build -c relase namespace ConsoleApp3{    public class Program    {        public static bool Test<T>() => Callee<T>();        public static bool Callee<T>() => typeof(T) == typeof(int);        static void Main(string[] args)        {            Test<int>();            Console.ReadLine();        }    }}

原理

  • 通过pMethod->GetMethodSignature().GetToken()获取方法Token

  • 获取到System.Runtime.CompilerServices.IntrinsicAttribute这个特性

  • 通过Token获取到CustomAttribute的IL表里面的Parent字段值,如果相等则表示Intrincis被设置了。此时就可以进行内联优化了。GetTypeFromHandle和op_Equality函数皆是如此。

往期精彩回顾

欢迎加入.NET9技术交流群


江湖评谈
记录,分享,自由。
 最新文章