Dynamic compilation is the practice of delaying compilation of a program (translation from a source language to a target language; the latter usually being the instruction set of the underlying microprocessor) until the time that the program is loaded or run. Dynamic compilation can either be done at program load, or on demand as code is executed (or generated!).
In many instances, only the compiler back-end (target code generation and much but not all optimization) is so delayed; there is far less advantage to be gained by delaying things like parsing and semantic analysis. In such cases, an IntermediateForm? is generated by an ahead-of-time compiler (consisting of front-end stuff only); this intermediate form is converted to the target language by the dynamic back-end.
Examples:
Advantages of doing this:
- Allows programs to be deployed in a "higher-level" form, eliminating the need for specific ApplicationBinaryInterface?s.
- One notorious problem of C++ (and other languages which are typically ahead-of-time compiled) is the FragileBinaryInterfaceProblem, wherein libraries which ought to be source-compatible are not binary-compatible due to differences introduced by the compilation process. (The usual solution in C++ is to manually recompile everything; which may not be an option if its Grandma experiencing the resulting DllHell).
- Many code optimizations that are dangerous if performed earlier (inlining virtual functions, replacing HashTable lookups with computed offset computations) in the process are safe when done by a dynamic compiler. (CeePlusPlus does many of these optimizations anyway...)
- Another problem with explicit ABIs is that they are notoriously low-level; making efficient implementation of higher-level languages more difficult. (They are also often optimized for programs in static languages like C, not dynamic languages).
- The dynamic compiler can be "tuned" to the target, generating more efficient code. In addition, ABI requirements often result in code inefficiencies.
- The dynamic compiler can perform security/robustness audits on the code as part of the translation process, similar to the bytecode verification done by a JavaVirtualMachine. (Note that JVM bytecode verification is separate from the issue of DynamicCompilation; even VMs that don't do any JustInTimeCompilation still do bytecode verification).
- For HomoiconicLanguages, or other programming languages that allow generation of code on the fly (via an "eval" statement or something similar), DynamicCompilation is (in general) the only way to achieve the benefits of code compiled to the target microprocessor. Comprehensive ahead-of-time compilation of progamming languages with eval() is known to be undecideable--without DynamicCompilation, the choices left to the language designer are: a) interpret everything; or b) compile the static parts and interpret the dynamic parts (making the dynamic parts noticeably slower; which will often cause programmers to avoid the dynamic features).
Disadvantages:
- Application start time can be increased noticeably; compiling nontrivial programs cam take a considerable amount of time. Compilation, rather than being something that happens on the developer's machine, happens instead on the user's machine
- This can be offset by caching the resultant binaries--the program loader looks at the transitive closure of the application and its dependent libraries; if nothing has changed the cached compiled program can be used. Otherwise, the program loader automagically recompiles everything; thus most executions don't require a re-compilation.
- Even with caching; DynamicCompilation still takes a long time--many DynamicCompilers? only bother to perform trivial optimizations as a result. Many optimization algorithms are NpHard (or worse)--and are problematic to implement efficiently on ahead-of-time compilers (where the compile-time, while annoying, is less of an issue).
- Many claims about performance of DynamicCompilation are based on the mythical SufficientlySmartCompiler.
- Compilation of large programs can be memory-intensive; in many situations the target machine may have insufficient memory to handle the translation--which can result in thrashing or program failure. This is especially problematic in embedded systems.
- Some CPU architectures and OperatingSystems (or combinations thereof) take a dim view of user-modified code, and disallow user-writeable pages to be executed. The Intel x86 architecture doesn't have this property, though a NX (No eXecute) bit is being added to the page table in upcoming versions--but many other CPUs do have NX bits in the MemoryManagementUnit? (PowerPc for example) and many operating systems use this to enhance security (StackSmashing is impossible if user-writeable pages cannot be executed--it's primarily an x86 problem). In addition, many processors do not have automatically synchronized data and instruction caches, and manually syncing the caches many require execution of privileged instructions (the x86 is again an exception, owing to lots of self-modifying DOS programs that the architecture needed to maintain compatibility with). On such targets, DynamicCompilation can be even more expensive as the OperatingSystem needs to continuously get involved in order to load pages into the CodeSegment?.
See also
http://sunir.org/apps/vm.pl?DynamicCompilation
CategoryLinker