Just-in-time compilation
From Wikipedia, the free encyclopedia
This article needs additional citations for verification. Please help improve this article by adding reliable references (ideally, using inline citations). Unsourced material may be challenged and removed. (November 2007) |
In computing, just-in-time compilation (JIT), also known as dynamic translation, is a technique for improving the runtime performance of a computer program. JIT builds upon two earlier ideas in run-time environments: bytecode compilation and dynamic compilation. It converts code at runtime prior to executing it natively, for example bytecode into native machine code. The performance improvement over interpreters originates from caching the results of translating blocks of code, and not simply reevaluating each line or operand each time it is met (see Interpreted language). It also has advantages over statically compiling the code at development time, as it can recompile the code if this is found to be advantageous, and may be able to enforce security guarantees. Thus JIT can combine some of the advantages of interpretation and static (ahead-of-time) compilation.
Several modern runtime environments, such as Microsoft's .NET Framework and most implementations of Java, rely on JIT compilation for high-speed code execution.
Contents |
[edit] Overview
In a bytecode-compiled system, source code is translated to an intermediate representation known as bytecode. Bytecode is not the machine code for any particular computer, and may be portable among computer architectures. The bytecode may then be interpreted by, or run on, a virtual machine. A just-in-time compiler can be used as a way to speed up execution of bytecode. At the time the bytecode is run, the just-in-time compiler will compile some or all of it to native machine code for better performance. This can be done per-file, per-function or even on any arbitrary code fragment; the code can be compiled when it is about to be executed (hence the name "just-in-time").
In contrast, a traditional interpreted virtual machine will simply interpret the bytecode, generally with much lower performance. Some interpreters even interpret source code, without the step of first compiling to bytecode, with even worse performance. Statically compiled code or native code is compiled prior to deployment. A dynamic compilation environment is one in which the compiler can be used during execution. For instance, most Common Lisp systems have a compile function which can compile new functions created during the run. This provides many of the advantages of JIT, but the programmer, rather than the runtime, is in control of what parts of the code are compiled. This can also compile dynamically generated code, which can, in many scenarios, provide substantial performance advantages over statically compiled code, as well as over most JIT systems.
A common goal of using JIT techniques is to reach or surpass the performance of static compilation, while maintaining the advantages of bytecode interpretation: Much of the "heavy lifting" of parsing the original source code and performing basic optimization is often handled at compile time, prior to deployment: compilation from bytecode to machine code is much faster than compiling from source. The deployed bytecode is portable, unlike native code. Since the runtime has control over the compilation, like interpreted bytecode, it can run in a secure sandbox. Compilers from bytecode to machine code are easier to write, because the portable bytecode compiler has already done much of the work.
JIT code generally offers far better performance than interpreters. In addition, it can in some or many cases offer better performance than static compilation, as many optimizations are only feasible at run-time:
- The compilation can be optimized to the targeted CPU and the operating system model where the application runs. For example JIT can choose SSE2 CPU instructions when it detects that the CPU supports them. With a static compiler one must write two versions of the code, possibly using inline assembly.
- The system is able to collect statistics about how the program is actually running in the environment it is in, and it can rearrange and recompile for optimum performance. However, some static compilers can also take profile information as input.
- The system can do global code optimizations (e.g. inlining of library functions) without losing the advantages of dynamic linking and without the overheads inherent to static compilers and linkers. Specifically, when doing global inline substitutions, a static compiler must insert run-time checks and ensure that a virtual call would occur if the actual class of the object overrides the inlined method.
- Although this is possible with statically compiled garbage collected languages, a bytecode system can more easily rearrange memory for better cache utilization.
However, JIT typically causes a slight delay in initial execution of an application, due to the time taken to compile the bytecode. Sometimes this delay is called "startup time delay". In general, the more optimization JIT performs, the better code it will generate. However, users will experience a longer delay. A JIT compiler therefore has to make a trade-off between the compilation time and the quality of the code it hopes to generate.
One possible optimization, used by Sun's HotSpot Java Virtual Machine, is to combine interpretation and JIT compilation. The application code is initially interpreted, but the JVM monitors which sequences of bytecode are frequently executed and translates them to machine code for direct execution on the hardware. For bytecode which is executed only a few times, this saves the compilation time and reduces the initial latency; for frequently executed bytecode, JIT compilation is used to run at high speed, after an initial phase of slow interpretation. Additionally, since a program spends most time executing a minority of its code, the saved compilation time is big. Finally, during the initial code interpretation, execution statistics can be collected before compilation, which helps to perform better optimization.[1]
Also, Sun's Java Virtual Machine has two major modes -- client and server. In client mode, minimal compilation and optimization is performed, to reduce startup time. In server mode, extensive compilation and optimization is performed, to maximize performance once the application is running by sacrificing startup time.
"Native Image Generator" (Ngen.exe) by Microsoft is another approach at reducing the initial delay. Ngen pre-compiles (or pre-jits) bytecode in a Common Intermediate Language image into machine native code. As a result, no runtime compilation is needed. .NET framework 2.0 shipped with Visual Studio 2005 runs Ngen.exe on all of the Microsoft library DLLs right after the installation. Pre-jitting provides a way to improve the startup time. However, the quality of code it generates might not be as good as the one that is jitted, for many of the same reasons why statically compiled code cannot be as good as JIT compiled code in the extreme case.
There also exist Java implementations that combine an AOT (ahead-of-time) compiler with either a JIT compiler (Excelsior JET) or interpreter (GNU Compiler for Java.)
[edit] History
Dynamic translation was pioneered by the commercial Smalltalk implementation currently known as VisualWorks, in the early 1980s.
Sun's Self language improved these techniques extensively and was at one point the fastest Smalltalk system in the world; achieving up to half the speed of optimized C[2] but with a fully object-oriented language.
Self was abandoned by Sun, but the research went into the Java language, and currently it is used by most implementations of the Java virtual machine, as HotSpot builds on, and extensively uses, this research base.
The HP project Dynamo was an experimental JIT compiler where the bytecode format and the machine code format were of the same type; the system turned HPA-8000 machine code into HPA-8000 machine code. Counterintuitively, this resulted in speed ups, in some cases of 30% since doing this permitted optimisations at the machine code level. For example inlining code for better cache usage and optimizations of calls to dynamic libraries and many other run-time optimizations which conventional compilers are not able to attempt.[3]
[edit] See also
- AOT compiler
- Code generation (compiler)
- Binary translation
- HotSpot
- Java performance
- Common Language Runtime
- Crusoe, a microprocessor that essentially performs just-in-time compilation from x86 code to microcode within the microprocessor
- rewriting
- GNU lightning
- Open CIL JIT
- Works records system, online interactive spreadsheet utilizing JIT compilation in 1974
- libJIT, a library by Rhys Weatherley, Klaus Treichel, Aleksey Demakov, and Kirill Kononenko for development of Just-In-Time compilers (JIT) in Virtual Machine runtimes
[edit] Notes
- ^ The Java HotSpot Performance Engine Architecture
- ^ http://research.sun.com/jtech/pubs/97-pep.ps
- ^ Ars Technica on HP's Dynamo
[edit] References
- L. Peter Deutsch and Allan M. Schiffman, "Efficient Implementation of the Smalltalk-80 System", 11th Annual Symposium on Principles of Programming Languages, Jan 1984, pp. 297-302
- Free Online Dictionary of Computing entry
- John Aycock, "A brief history of just-in-time", ACM Computing Surveys, 35,2, 2003, pp. 97-113
- Matthew Arnold, Stephen Fink, David Grove, Michael Hind, and Peter F. Sweeney, "A Survey of Adaptive Optimization in Virtual Machines", Proceedings of the IEEE, 92(2), February 2005, Pages 449-466.
[edit] External links
- .Net Framework Just In Time Compiler
- GNU lightning — A library that generates assembly language code at run-time
- libJIT — A library by Rhys Weatherley, Klaus Treichel, Aleksey Demakov, and Kirill Kononenko for development of Just-In-Time compilers (JIT) in Virtual Machine runtimes
- SoftWire — A library by Nicolas Capens that generates assembly language code at run-time
- AsmJit — Complete x86/x64 jit assembler library for C++ language by Petr Kobalíček
- [1] An earlier implementation of JIT in 1974 at ICI for spreadsheets