Home > Article > Backend Development > CLR (common language runtime) and IL (intermediate code) in C#
CLR in the .net platform
The first thing to note is that the .NET platform is not the same thing as C#. It is the platform on which programs such as C# and VB.net run.
CLR is the common language runtime and an important part of the .NET Framework. It provides services such as memory management, thread management, and exception handling, and is also responsible for implementing strict type safety checks on the code to ensure the correctness of the code.
In fact, many features in C# such as type safety (Type Checker), garbage collection (Garbage Collector), exception handling (Exception Manager), backward compatibility (COM Marshaler), etc. are provided by the CLR .
What is IL
.NET Framework is a virtual running platform built on the Windows platform. You can imagine replacing the bottom layer Windows with other operating systems, such as Linux, the same It is possible to use .NET language that complies with CLS (Common Language Specification, Common Language Specification). This is actually the function that Mono plans to achieve. Therefore, in theory, C# is a cross-platform language.
Another thing that makes C# more like Java is that it is also a language (in a special sense). Like Java, the program code written in C# is first compiled into a special character by the C# compiler. Section code, (Microsoft Intermediate Language, MSIL, Microsoft) intermediate language, is compiled into machine code by a specific compiler (JIT compiler, Just In tIME, JITer) at runtime for execution by the operating system.
IL is an intermediate language. The compilers of various high-level languages (such as C#, VB, F#) on the .NET platform will convert their respective text expressions into IL. Various text forms were finally unified into the expression of IL
After CLR loads IL, when each method is executed for the first time, JIT will be used to compile the IL code into machine code. Machine code and assembly actually have a one-to-one correspondence. It can be understood like this: Assembly is the textual representation of machine code and provides some "mnemonics" that are convenient for people to remember.
For the same IL, JIT will generate different machine codes for different CPU architectures (such as x86/IA64, etc.).
C# code and its corresponding IL intermediate code
//hidebysig指令表示如果当前类为父类,用该指令标记的方法将不会被子类继承 //cil managed表明方法体中的代码是IL代码,且是托管代码,即运行在CLR运行库上的代码 .method private hidebysig static void Main(string[] args)cil managed { .entrypoint //该指令代表该函数程序的入口函数。每一个托管应用程序都有且只有一个入口函数,CLR加载程序时,首先从.entrypoint函数开始执行。 .maxstack 2 //执行构造函数时,评估堆栈可容纳数据项的最大个数。评估堆栈是保存方法中所需要变量的值的一个内存区域,该区域在方法执行结束时会被清空, 或者存储一个返回值。 .locals init ( [0] int32 num, [1] int32 num2, [2] int32 num3) //表示定义int类型的变量,变量名分别为num,num2,num3。存储在调用栈。 L_0000: nop //No operation的意思,即没有任何操作。 L_0001: ldc.i4.1 //将“1”压入评估栈,此时“1”处于评估栈的栈顶。 L_0002: stloc.0 //此指令表示把值从评估栈中弹出,并赋值给调用栈的第0个变量num。 L_0003: ldc.i4.2 L_0004: stloc.1 L_0005: ldc.i4.3 L_0006: stloc.2 //从.locals init到L_0006,相当于C#代码的为i,j,k赋值。 L_0007: ldloc.0 //取调用栈中位置为0的元素压入评估栈(取i的值)。 L_0008: ldloc.1 //取调用栈中位置为1的元素压入评估栈(取j的值)。 L_0009: add //做加法操作 L_000a: ldloc.2 //取调用栈中位置为2的元素压入评估栈(取k的值)。 L_000b: add //做加法操作 L_000c: call void [mscorlib]System.Console::WriteLine(int32) //调用输出方法 L_0011: nop //No Operation L_0012: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey() //调用ReadKey方法 L_0017: pop //把评估栈的内容清空 L_0018: ret //return 标记返回值 } //Main方法结束
Through the above code, we can summarize: .maxstack: The variables in the code need to be in Occupies several positions in the call stack (Call Stack); .locals int(...): Define variable initialization and put it in the call stack (Call Stack); nop: No Operation, no operation; ldstr: Load String, put the characters The string is pushed into the Evaluation Stack;
ldc.i4.1: Push the value 2 into the Evaluation Stack in the form of a 4-byte length integer; stloc: Pop the value in the evaluation stack (Evaluation) and assign it to the call stack (Call Stack); ldloc: Take out (Copy) the value at the specified position in the call stack (Call Stack) and push it into the evaluation stack (Evaluation Stack); call: Call the specified method. This instruction is generally used to call static methods; callvir is generally used to call instance methods; ret: return, mark return.
Let’s look at another example
namespace TestConsole { class Program { [MethodImpl(MethodImplOptions.NoInlining)] private static void SomeMethod() { Console.WriteLine("Hello World!"); } static void Main(string[] args) { Console.WriteLine("Before JITed."); Console.ReadLine(); SomeMethod(); Console.WriteLine("After JITed"); Console.ReadLine(); } } }
The corresponding main method IL code:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint .maxstack 8 // 分配字符串"Before JITed" L_0000: ldstr "Before JITed." // 调用Console.WriteLine方法 L_0005: call void [mscorlib]System.Console::WriteLine(string) // 调用Console.ReadLine方法 L_000a: call string [mscorlib]System.Console::ReadLine() L_000f: pop // 调用Program.SomeMethod方法 L_0010: call void TestConsole.Program::SomeMethod() // 分配字符串"After JITed" L_0015: ldstr "After JITed" // 调用Console.WriteLine方法 L_001a: call void [mscorlib]System.Console::WriteLine(string) // 调用Console.ReadLine方法 L_001f: call string [mscorlib]System.Console::ReadLine() L_0024: pop L_0025: ret }
The above is the CLR (common language runtime) and IL (intermediate code) content, please pay attention to the PHP Chinese website (www.php.cn) for more related content!