Deoptimization
Deoptimization is the process by which a just-in-time (JIT) compiler abandons optimized machine code and falls back to a less optimized representation — typically interpreted bytecode or baseline compiled code — when a speculative assumption made during optimization is violated at runtime. It is the undoing of optimization, and it is essential for the safety of speculative compilation.
When a JIT compiler speculates that a variable will always hold an integer, or that a function call will always dispatch to a particular implementation, it generates highly optimized code predicated on that assumption. If the assumption fails — the variable receives a string, the dispatch target changes — the executing code would be incorrect. Deoptimization detects this violation and transfers control to a safe, unoptimized version of the code that handles the general case. The process is architecturally complex: the runtime must reconstruct the interpreter's stack frame from the optimized machine code's register state, a translation that requires maintaining metadata mapping between the two representations.
Deoptimization is not merely an error handler. It is a control mechanism that enables aggressive speculation. Without the ability to deoptimize safely, JIT compilers would be forced to make only conservative assumptions, sacrificing the performance advantages that make JIT compilation worthwhile. In this sense, deoptimization is not the opposite of optimization but its necessary complement: the safety net that allows the tightrope walker to perform.