In-depth understanding of the JIT compilation method of .NET

xiaoxiao2021-03-18  188

The CLR only performs the machine code of this unit. There are two ways to generate machine code: real-time compilation (JIT) and pre-compiled mode (generating native image). Here, I want to talk about JIT.

The CLR uses the type of method to route all method calls. The method of type is composed of multiple entrance items. Each entry is directed to a unique settler routine. When initialization, each stub routine contains a call to the JIT compiler of the CLR (it is disclosed by the internal PRESTUBWORKER program). After generating this machine code after the JIT compiler, it will rewrite the root routine, insert a JMP instruction to jump to the code just just the JIT compiler. The JIT compiler is compiled into the corresponding local machine code versions when you want to call a method. This will optimize the work set of the program.

For the following example:

// using system;

Public class bub {

Static int x;

Static void a () {x = 2;

Static void b () {x = 3;

Static void c () {x = 4;

Public static void f ()

{

c ();

b ();

a ();

}

}

Public Class Myclass

{

Public static void main ()

{

Bob.f ();

}

}

JIT debugging with the debugger.

First, look at the assembly display of each method:

Compilation of main () is displayed:

Push EBP

MOV EBP, ESP

// Call bob.f () method

Call dword ptr DS: [00975394H]

NOP

POP EBP

RET

[Note] 00975394H is Bob.f () corresponding to the memory address in the internal data structure in Corinfo_Class_Struct, the content in this address is the start address of the corresponding settlement routine.

F () assembly is displayed:

Push EBP

MOV EBP, ESP

// Call BOB.C () method

Call Dword Ptr DS: [00975390H]

// Call Bob.B () method

Call DWORD PTR DS: [0097538CH]

// Call Bob.a () method

Call dword Ptr DS: [00975388H]

NOP

POP EBP

RET

[Note] 00975390, 0097538C, 00975388 is bob.c (), bob.b (), bob.a () in Corinfo_Class_Struct The corresponding memory address in the internal data structure, the content in this address is the corresponding settlement routine Start address.

C () assembly shows:

Push EBP

MOV EBP, ESP

Add DWORD PTR DS: [0097539CH], 4

NOP

POP EBP

RET

[Note] 0097539C is the memory address of Bob.x.

B () assembly shows:

Push EBP

MOV EBP, ESP

Add DWORD PTR DS: [0097539CH], 3

NOP

POP EBP

RET

[Note] 0097539C is the memory address of Bob.x.

A () assembly is shown in:

Push EBP

MOV EBP, ESP

Add DWORD PTR DS: [0097539CH], 2

NOP

POP EBP

RET

[Note] 0097539C is the memory address of Bob.x.

Below, let's take a look at the debugging, the address is 00975394H, 00975390H, 0097538CH, 00975388H:

0x00975384 2B 85 BF 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 00 00 00 00 00 00 Green is Bob.f () in Corinfo_Class_Struct The memory address corresponding in the internal data structure;

Purple is bob.c () corresponding to the memory address corresponding in the internal data structure of Corinfo_Class_Struct;

Gray is bob.b () in Corinfo_Class_Struct The corresponding memory address in the internal data structure;

Yellow is bob.a () in Corinfo_Class_Struct The corresponding memory address in the internal data structure;

[Note] The red content is the value of bob.x! Do not believe? Then you see the changes in the value of the red in the next debugging process:

Before entering f ():

0x00975384 2B 85 BF 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

C () plus 4 changes to:

0x00975384 2B 85 BF 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 04 00 00 00 00 00 00 00 00

Plus 3 changes to:

0x00975384 2B 85 BF 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 07 00 00 00 00 00 00 00 00 00

Plus 2 changes to:

0x00975384 2B 85 BF 79 03 53 97 00 13 53 97 00 23 53 97 00

0x00975394 33 53 97 00 43 53 97 00 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Let's take a look at the contents of the root departure before calling bob.f ():

0x00975303 E8 D0 52 7D FF 04 00 10 00 50 00 c0 02 00 Fe

0x00975313 E8 C0 52 7D FF 05 00 10 00 6C 20 00 c0 03 00 fc

0x00975323 E8 B0 52 7D FF 06 00 10 00 88 20 00 c0 04 00 FA

0x00975333 E8 A0 52 7D FF 07 00 10 00 A4 20 00 c0 05 00 f8

The green is the content of the bob.f ().

The purple is the content of the bob.c () of the retrieval routine;

Gray is the content of the bob.b () of the retrieval routine;

Yellow is the content of the bob.a () of the root routine;

Let's take a look at the contents of the root departure after entering the bob.f () method:

0x00975303 E8 D0 52 7D FF 04 00 10 00 50 00 c0 02 00 Fe

0x00975313 E8 C0 52 7D FF 05 00 10 00 6C 20 00 c0 03 00 fc

0x00975323 E8 B0 52 7D FF 06 00 10 00 88 20 00 c0 04 00 FA

0x00975333 E9 40 AD 39 06 07 00 10 00 78 00 D1 06 05 00 F8

Obviously, only the contents of the bob.f () of the retrieval routines have changed. This shows that the JIT compiler is called. At the same time, the compiler converts F () CIL method body into machine code versions in address space. Replace the original content of the stub routine. After replacing, the first address of the F () method is the first address of 0x06d10078 (content at blue labels). Do you not believe? Well, let's take a look at the memory content of 0x06d10078: 0x06d10078 55 8b EC FF 15 90 53 97 00 FF 15 8c 53 97 00 ff

0x06D10088 15 88 53 97 00 00 00 00 00 00 00 00 00 00 00

You may wish to look back at the F () assembly display, here:

The purple is not a memory address corresponding to bob.c () in Corinfo_Class_Struct.

The gray is not a memory address corresponding to Bob.B () in Corinfo_Class_Struct, in the internal data structure;

Yellow is not a memory address corresponding to Bob.a () in Corinfo_Class_Struct, in the internal data structure;

Do not just correspond to F () assembly display:

// Call BOB.C () method

Call Dword Ptr DS: [00975390H]

// Call Bob.B () method

Call DWORD PTR DS: [0097538CH]

// Call Bob.a () method

Call dword Ptr DS: [00975388H]

you got it! Ok, the following is the same for C (), B (), and A () call is also the same. There is a memory display for the next debugging:

The next settlement routine:

Enter C () and turn to:

0x00975303 E8 D0 52 7D FF 04 00 10 00 50 00 c0 02 00 Fe

0x00975313 E8 C0 52 7D FF 05 00 10 00 6C 20 00 c0 03 00 fc

0x00975323 E9 78 AD 39 06 06 00 10 00 A0 00 D1 06 04 00 FA

0x00975333 E9 40 AD 39 06 07 00 10 00 78 00 D1 06 05 00 F8

Enter B () and turn to:

0x00975303 E8 D0 52 7D FF 04 00 10 00 50 00 c0 02 00 Fe

0x00975313 E9 A8 AD 39 06 05 00 10 00 c0 00 d1 06 03 00 fc

0x00975323 E9 78 AD 39 06 06 00 10 00 A0 00 D1 06 04 00 FA

0x00975333 E9 40 AD 39 06 07 00 10 00 78 00 D1 06 05 00 F8

Enter A () to become:

0x00975303 E9 D8 AD 39 06 04 00 10 00 D1 06 02 00 Fe

0x00975313 E9 A8 AD 39 06 05 00 10 00 c0 00 d1 06 03 00 fc

0x00975323 E9 78 AD 39 06 06 00 10 00 A0 00 D1 06 04 00 FA

0x00975333 E9 40 AD 39 06 07 00 10 00 78 00 D1 06 05 00 F8

Enter the content of the C () after the address is 0x06d100A0 (Bob.c () machine code version is as follows:

0x06D100A0 55 8B EC 83 05 9C 53 97 00 04 90 5D C3 00 00 00 00 00 00 00 00 00 00 00 00 00

Enter the content of the b () after the address is 0x06d100c0 (Bob.b () machine code version) is as follows: 0x06d100c0 55 8b EC 83 05 9C 53 97 00 03 90 5D C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03

Enter the content of the A () after the address is 0x06d100E0 (Bob.a () machine code version is as follows:

0x06D100E0 55 8b ec 83 05 9c 53 97 00 02 90 5d c3 00 00 00

转载请注明原文地址:https://www.9cbs.com/read-129764.html

New Post(0)