Does the JVM or CLR use registers to run JIT code?

I understand that the JVM and CLR were created as stack-based virtual machines. When JIT compiles bytecode into native code, does it also convert stack / load primitives to registers on the X86 platform?

If so, it looks like the bytecode is stack-based or case-based, not a big deal. JIT questions.

+4
source share
3 answers

I think you are mixing two different concepts.

At a minimum for Java, the JVM acts like a virtual machine - it is an idealized computer with a relatively high level of assembler (bytecode), which is based on a stack of calls with stack frames. When compiling Java into bytecode, the Java program turns into an (essentially) build program to control this machine.

When Java is actually running on this system, the job of implementing the JVM is to accurately simulate the execution of this machine on a stack basis using any hardware that is actually available. Usually this means that a huge number of stack operations will be implemented using registers when possible, and possibly using other specialized equipment that is not in the Java virtual machine description. The actual information about how this is done is implementation-specific - some implementations can compile it to machine code that does almost everything in the register, while a simpler implementation can simply be compiled into memory operations. For several months I was working on the implementation of the JVM for JavaScript, and in this case we โ€œcompiledโ€ the code to JS functions, which, in turn, were passed to the JS browser implementation.

The reason for this difference is that Java was designed to easily load and paste (think of applets). In this case, security and portability issues are important. The bytecode had to be checked in some way automatically to exclude certain types of malicious code (for example, buffer overflows). In the same way, whatever format was used, it had to be high enough so that it could be run on various platforms (handheld devices, supercomputers, PCs, etc.). The choice of stack-based JVMs allowed both of these problems to be met simultaneously. This is a high enough level that you can check bytecode to rule out many type errors or read / write uninitialized memory, at a low enough level that the JVM can use tricks, such as compiling to code using registers.

If you are interested in what your particular JVM will do with a specific piece of code, you should take a look at the documentation. Most JVMs have some way to provide you with information on how they execute code. If your question is: โ€œWhy not just bytecode manipulate case-basedโ€, the reason is twofold:

  • The bytecode has an analogue of registers - each frame of the stack has an additional allocated space for storing temporary values โ€‹โ€‹and
  • There is not such reliable register support as is present in x86 or MIPS, because JVM code must be easily executed on several hardware, and hard coding in a number of registers can complicate the situation.

Hope this helps!

+5
source

Cannot use registers on x86 core. The processor does not have instructions, for example, add two local variables. One of them must be loaded into the register. You can then add the value in register to the value in the variable. And save the result back to the stack variable.

The optimization possibilities are obvious from this sequence. For example, not saving it, but storing the result in the register and using it later, saving both the storage and the load. Regarding the work of the optimizer, he is looking for ways to make the best use of the available registers.

+1
source

The only way to know for sure is to study the JIT-compiled output, but it can be said that the use of registers is one of the most striking optimizations of the JIT compiler. I find it difficult for most programmers to write faster code than the JIT compiler.

The JIT compiler is capable of a lot and probably uses registers as much as appropriate. Things like the inlining method encourage the use of registers, and many imperative program codes can be more easily expressed in a case-based architecture, so it makes sense to use registers for the JIT compiler.

0
source

All Articles