I: Background
1. Storytelling
Everyone knows the so-called.NET Native AOT
That is, through the AOT compiler directly compiled C# code into machine code, we are also accustomed to use the C/C++ compilation process to analogize, are static compilation is essentially similar to this we use the tools from the macro level to take a look at the compilation process of AOT.
II: The C/C++ Compilation Process
Those of you who have compiled c code with gcc know that it can be compiled separately with the-E, -S, -c,-o
to show the various stages of compilation, ie:
- Preprocessing phase: landing define, include files and code.
- Compilation phase: converting C to assembly code.
- Assembly phase: assembly code to machine code.
- Linking phase: linking libc libraries and system libraries, generating executables.
Draw a diagram as follows:
In this world, although it is said that there is no difference between the lines, but the lines are not separated, and with this knowledge, the next step is totry and find sth with the help of a clue
The right number of the right number of the right number of the right number of the right number is enough.
III: AOT compilation process
The AOT compiler in .NET is called theNET, which is written in C# code and updated with .NET versions, such as mine here
C:\Users\Administrator\.nuget\packages\\8.0.8\tools\
。
The corresponding source code is in theD:\sources\runtime\src\coreclr\tools\aot
Down.
One more thing to note is that the code received is MSIL code, not C# code.MSIL
Where does it come from? Naturally, dotnet publish calls it first.Rolysn
Come prepared, draw a picture as follows:
Next is the official ilc phase.
1. Where is the pre-processing stage
This stage actually corresponds to the AOT'sDependency graph construction and optimization
, of course C# is more complex here and includes more things like:
- Build a dependency graph
- Secondary Processing of IL Code for Pinvoke, COM, Delegate
- GetHashCode and Equals generation for ValueType.
- Some metadata are provided for the limited support of reflections.
- Tree shaking optimization
All materials constructed for the dependency graph can be referred to theobj\Debug\net8.0\win-x64\native
folder of theExample_21_2.
。
If you are interested, you can focus on the code under this library and the DependencyAnalyzer class, the screenshots are as follows:
/// <summary>
/// Implement a dependency analysis framework. This works much like a Garbage Collector's mark algorithm
/// in that it finds a set of nodes from an initial root set.
///
/// However, in contrast to a typical GC in addition to simple edges from a node, there may also
/// be conditional edges where a node has a dependency if some other specific node exists in the
/// graph, and dynamic edges in which a node has a dependency if some other node exists in the graph,
/// but what that other node might be is not known until it may exist in the graph.
///
/// This analyzer also attempts to maintain a serialized state of why nodes are in the graph
/// with strings describing the reason a given node was added to the graph. The degree of logging
/// is configurable via the MarkStrategy
///
/// </summary>
public sealed class DependencyAnalyzer<MarkStrategy, DependencyContextType> : DependencyAnalyzerBase<DependencyContextType> where MarkStrategy : struct, IDependencyAnalysisMarkStrategy<DependencyContextType>
{
private MarkStrategy _marker = new MarkStrategy();
private IComparer<DependencyNodeCore<DependencyContextType>> _resultSorter;
private RandomInsertStack<DependencyNodeCore<DependencyContextType>> _markStack;
private List<DependencyNodeCore<DependencyContextType>> _rootNodes = new List<DependencyNodeCore<DependencyContextType>>();
}
It's kind of funny how the official notes say that this thing is like theGC Mark Algorithm
The look field is also adepth-first algorithm
。
Some of you may be curious about thisdependency tree
What it ends up looking like can be configured on csproj<IlcGenerateMapFile>true</IlcGenerateMapFile>
node, and then dotnet publish will generate aExample_21_2.
file, open it to see the type and method nodes.
2. Where is the compilation phase
The compilation phase of C is used to convert C code into assembly code, which in ILC is called theCode generation backend
, supports both on the landing program.
- RyuJIT
Yes, you read that right, it's the JIT compiler you're all too familiar with, and AOT uses it too. After all, it's so mature that it supports all the major operating system platforms, and the corresponding high-level encapsulation is in the library, screenshot below:
- LLVM
This is currently used to generate WebAssembly code, see:/dotnet/runtimelab/tree/feature/NativeAOT-LLVM
3. Where is the compilation phase?
In C this stage is mainly about putting.s
change into.o
The file, i.e., assembly code to machine code, if you apply it to the AOT, is the ObjectWriter class, which does the work of generating the final file.
4. Where is the linking phase?
After the obj has been generated, both C and C#different routes the same destination (idiom); fig. different means of achieve the same end
This is a call to merge the VCRuntime runtime and the system .lib libraries as a whole, which can be seen in the documentation, as shown in the screenshot below:
One small note in the diagram is that the obj does not yet have gc code, which is eventually merged in during the link phase.
III: How seeing is believing
To study these processes, two tools are offered here, one calledprefview
A new product calledprocmon
。
1. How to observe the compilation process
To know the answer to this question, it is easy to find a suitable tool to know, there is a Processes view in Prefview, you can use it to observe the start and stop of the process after the execution of the dotnet publish command, the screenshot is as follows:
It's obvious from the trigrams that it is: -> (Roslyn) -> ->
Haha, haha, does this flowchart deepen the understanding of the compilation process haha.
2. how to observe the generation of obj
To observe the generation of obj's, it is natural to monitor the reading and writing of files, yes, you can use Microsoft's Procmon utility with the following configuration:
Once that's done, the next step is to use dotnet publish to lure you out of the hole, thenlit. the whole nest overturns the eggs (idiom); fig. turn out in full force
The screenshot is below:
Next we double-click on this line to observeStack
tab, it's clear to see that it's theObjectWriter
The screenshot is below:
IV: Summary
Research on these things is still relatively troublesome, mainly the official github on the introduction of ilc is also relatively limited, more or need to study the source code, the art of specialization, as a debugger, more energy is still consumed in the market dump it.