Are you a programmer? Learn how a JIT compiler works

What is compiling?

Unless we are programming in binary, or in a very very low-level language, such as assembler, machines do not understand the lines of code that we write. And the higher level the language we use, the more natural it will be for us, but the more complex it will be for the machine. And that is why, to convert our high-level language into machine language we need compile the code.

Compiling the code is the process by which we convert our high-level lines of code to machine language. For this it is necessary to have, on the one hand, with the plain text file with all the code, and on the other with a program, the compiler, which is responsible for converting each of the lines of code into binary or the corresponding low-level language.

Compile program scheme

Thanks to the use of these compilers, programming is very simple, and the same code can be used, with some adjustments, on several different types of machines. Also, because these programs are optimized to work on specific architectures, they tend to offer good overall performance. However, not all benefits. A compiled program will only work on the machine for which the compiler is designed, for example an x64 CPU or ARM processor. It is also necessary to compile the same program several times depending on the operating systems (Windows, macOS, Linux, Android, iOS, etc.) where we are going to run it.

Differences with the interpreter

The interpreters They are born precisely in order to solve the two problems that we have just seen in the compilers. These are programs that run between our original code and our machine and are responsible for interpreting each of the instructions depending on the machine or operating system where we are executing it.

These interpreters are placed at the same point where the compilers would begin to translate the code. Thus, they eliminate all operating system or platform limitations, being able to use the same code for everything.

Of course, we cannot think that an interpreter is perfect. The first thing to keep in mind is that these are not valid for all types of programming languages. The interpreters can work, for example, with Python or JavaScript, but they would not be workable in other languages, such as C ++. Also, having to interpret the code at the same time that it is executed implies a considerable loss of performance by having to translate and handle each instruction as if it were a separate compiler.

And this is where the JIT compilers come into play.

What is a Just-In-Time Compiler

While a normal compiler is responsible for compiling all the code when we are going to execute the program, convert the code to binary and generate the executable, the JIT compiler optimizes this work. compiling only the code of each function when necessary.

In this way, when we are going to execute a program, the Just-In-Time, or JIT, compiler will only compile the functions that are going to be used at that moment, saving the result in a cache. As we use the program, when we come across a new function that has not yet been compiled, it is compiled again. But, when we find a function that has already been used, instead of compiling it again, it is searched in the cache, saving a significant amount of time.

Some examples of use of JIT compilers are as follows:

  • Java: The Java virtual machine, JVM, uses Just-In-Time.
  • .NET Framework – Microsoft’s programming environment.
  • C #: CLR (Common Language Runtime).
  • Android: when used with DVM (Dalvik Virtual Machine) or ART (Android RunTime).
  • Emulators: These compilers are also used in console and other PC emulators. This is how machine code is translated from one CPU architecture to another.

Compile JIT Java

This type of compiler has superior performance than interpretersInstead of interpreting all the code, they compile what they need as they need it. However, having to compile the code at runtime does have an impact, to a greater or lesser extent, on performance compared to using a standard compiler that generates the binary and allows us to execute it directly on the machine. And the bigger the program we are trying to run, the greater the performance impact. This causes some very large programs to take up to a minute to execute the first few functions.

To reduce this impact there are some pre-compilers, As the Native Image Generator (Ngen) from Microsoft, who are responsible for eliminating the runtime and making the JIT compiler workable out of the box.

Also, as the Just-In-Time compilation primarily uses executable data, protect it from possible exploits it is a very important challenge for developers. Memory must be watched closely and protected with advanced security techniques, such as isolation, to avoid taking unnecessary risks.

Optimize the JIT (Just-In-Time) compiler

Depending on the type of compiler that we use, it is possible to find different levels of code optimization. For example, in the case of OpenJ9 (Eclipse JIT compiler for Java code), it is possible to choose the level of code optimization we want. The higher the optimization of the Just-In-Time compiler, the faster the code will execute on our computer, of course, at the cost of a much higher use of RAM and CPU.

In addition, these compilers are designed to analyze and trace the functions of a program and detect which ones are the most repeated. Thus, certain optimizations are applied to them, and which ones are called the least, leaving them a bit in the background to avoid unnecessary use of resources.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *