5
votes

I recently learned that JIT compilers are used to compile platform independant code to native code. JVM and the .net runtime environments use this, for better performance and significant reduce in compiling time. My question is that why not the ordinary compilers that compile directly into native code (like c compilers) also be made as JIT? Is there a restriction or a specification for the usage if JIT compilers?

4

4 Answers

4
votes

JIT has advantages and disadvantages. JIT can be very useful if you deploy your software to a lot of different PCs because the JIT compiler can detect how to optimize the code for each specific platform.

The problem is that JIT adds another step that must be taken before the software can be executed first: first it has to be compiled to IL and then it is compiled to machine code, this means an extra performance overhead. However, this conversion from IL to machine code only has to be done the first time the software is run, so each subsequent call will be much faster.

So basically (as a rule of thumb) you can say: if the software is a long-running process it's often good to use JIT, if the software has a short life-time it's better to use native code.

3
votes

Modern javascript implementations also do JIT, as do some PHP, Python, and Ruby implementations (at least). The trick with JIT, though, is that they are a relatively recent developement, and part of what makes them work is that you rely on a framework or runtime of some type that lives on the end-user machine that is capable of making the correct optimizations for that machine and instance of the application.

For languages that want to be close to the "bare metal" of your computer, relying on that extra abstraction layer does not always make sense.

2
votes

there are a couple reasons I can think of:

  • precompiled binaries can use high levels of optimization that takes days in order achieve the best performance, you wouldn't want that in a JIT compiler

  • the initial JIT compile can take longer than direct interpretation with unnoticeable differences on subsequent runs for the common cases

  • JIT compiling can hog user resources that are needed for other run time processes (I don't see many 3d JIT-compiled games)

  • precompiled interpreters, if written efficiently, can achieve close enough speeds while allowing instant user modification to the source without performance degradation

This is starting to change for commercial software with the divergence of the x86 instruction set and increasingly widespread use of arm, mips, etc... in consumer devices along with different operating systems. When you add in the ability for a JIT compiler to use native code on the video card (which also vary widely) it becomes less and less reasonable to try to distribute a compiled version optimized for every unique combination. At some point a reasonable JIT compiler that can access all of the cpu as well as the gpu will outperform a compiled equivalent that is limited to (for example) a subset of x86.

One thing that is often asked is if you could just distribute the bytecode... almost, but not quite. It works for java because it was designed-to-be-virtual and thus does not need to worry about endianness and other hardware issues that a libc does, or the custom assembly language bits for each architecture (all that gets implemented in the virtual machine) To really gain a strong footing, one would need to implement a basic libc designed for JIT (maybe based on musl libc due to its simplified code and permissive license)

0
votes

Optimizing ahead of time compilers, like most C compilers (e.g. GCC) may produce better machine code than a JIT compiler. But ahead of time compilers usually need much more time (than JIT) to optimize. For instance, gcc -O3 is doing a lot of expansive optimizations that most JIT JVM cannot afford. Hence, gcc -O3 often produces very efficient machine code (much better than whan a JVM could do).

However, in some cases, the JIT technology may give better code, because it is able to take into account some dynamic properties unknown to the ahead of time compiler. For example, a JIT compiler can take into account that on some particular call site the argument of the call has usually one given class (and that class depends upon the call site, and is dynamically learned).