.Net 7 新编译器ILC简析(二)

楔子

它主要是生成Native Code,跟CLR调用RyuJIT的即时编译有所不同。

初始化

ILC的初始化自然是核心的.Net 类库System.Private.CoreLib.dll。注意这个DLL跟CLR的System.Private.CoreLib.dll不太一样。另外就是初始化ILC所依赖的库文件,比如TypeRef此类。.

R2RH

R2RH的全称是:ReadyToRunHeader。这个东西是贯穿整个ILC编译器的核心,在初始化加载全局栈_markStack的时候,它是第一个被Push到这个栈里面的。后面陆续Push:
GCStaticsRegion
ThreadStaticsRegion
EagerCctorTable
TypeManagerIndirection
DispatchMapTable
FrozenSegmentRegion
InterfaceDispatchCellSection
ModuleInitializerList
以上八大类型,除了InterfaceDispatchCellSection,又会被陆续加入到R2RH的_items项。

到整个需要被写入目标文件的全局栈Count数目为0x50十进制的80个。在这80个项里面会被筛选和循环,所有项里面依赖的函数项,包括虚函数,静态函数,以及非静态函数等,和其它一些编译需要用到的节点Node。
此次结果为:0x0000d7d8项。

并行编译

ILC相对于CLR调用JIT的一个最大好处就是同时启动并行函数编译,实质上就是对于多个函数进行一次性并行编译,而非一次性编译一个函数。其实非常简单,主要用到的函数就是:Parallel.ForEach

 Parallel.ForEach(
                methodsToCompile,
                new ParallelOptions { MaxDegreeOfParallelism = _parallelism },
                CompileSingleMethod);

在提取一部分依赖的项和函数进行编译之后,会继续遍历剩余的项以及函数进行编译。直至以上所有完成为止。

Write

写入是写入目标文件,因为不同的平台有不同的目标文件格式,比如windows的.Obj,Linux .O,MacOs Mach-O等。所以会通过ObjWriter封装调用LLVM写入不同的平台目标文件。

步骤

Source Code ->Roslyn(DLL)->ILC->RyuJit(native code)->ObjWriter(Obj)->链接(可执行文件)。

结尾

如有疏漏,请不吝赐教。
作者:江湖评谈(公众号同名)