The JIT steps of compiling code in CLR look like this:
- When compiling code that contains a call to a particular method, a space in memory called a stub is allocated for this method. The stub contains a call to the internal undocumented compilation function and a pointer to the IL code of the method code.
- When the time comes to invoke a method, the compilation function is called, which compiles the IL code into machine commands, and also rewrites the contents of the stub to this code.
- The method is executing.
Since, as everyone knows, the CLR does not compile the same method every time for optimization purposes, you need to store the correspondences of the compiled code blocks and method names somewhere.
Consider the following example for clarity:
We have this code in C #:
void Main() { Console.ReadLine(); ReadLine(); } void ReadLine() { Console.ReadLine(); } Under methods Console.ReadLine and ReadLine will be allocated, respectively, Stub1 and Stub2. How the compiled code will look like:
call stub1 call stub2 When stub1 is called, the method Console.ReadLine will be compiled, its code will be written to stub1 and then executed. There is nothing to be asked.
But when you call stub2, a compilation of ReadLine will occur, of course, which will look like this:
сall Console.ReadLine And the answer to the question of what will be caused: stub1 or a new stub3 containing the same code - the answer is obvious. But in order to call stub1, thus not compiling Console.ReadLine again, you need to remember the address of stub1 and put it in accordance with the method Console.ReadLine . How it's done?