An Introduction to Turbofan
V8's Optimizer
What is Turbofan?
All JavaScript code is JIT compiled, meaning it is first converted into bytecode before being executed as machine instructions. In V8, the interpreter responsible for this bytecode is called Ignition, and as such we can refer to the intermediate bytecode as ignition bytecode.
One of the benefits of JIT compiling the javascript involves the collection of feedback from the Ignition interpreter. Often-executed functions get optimized to be faster and more efficient - this is the job of Turbofan.
Speculative Optimizations
The optimizations made by Turbofan are based off assumptions (hence speculative) - it will attempt to optimize the code for whatever object types and logic flows it expects to meet.
For example, let's say we're programming a game. In this game, you are a soldier, and your job is to hold off the invading aliens. Holding them off by force, the kill() function is regularly called on aliens. Turbofan recognises this, and generates optimized code for running the kill() function. With such a large number of calls to the function, the optimization is massively helpful. Go Turbofan!
But, once again, this optimization is speculative - the original code generated by Turbofan is optimized for running kill() on aliens. Let's say that the player ends up being overwhelmed, and kill() is called on the player themselves. Suddenly, turbofan's speculation is incorrect - the optimized code is incredibly quick, but only for aliens! The type passed to kill() here is a Player, so this optimization cannot be used. Turbofan has to destroy this optimzation and generate some ignition bytecode instead in a process called deoptimization.
Deoptimization has a huge performance cost, and is very desirable to avoid. As a result, Turbofan will optimize the code once again, if kill() continues to be called on both aliens and players. Turbofan will speculatively optimize the code to handle both alien and player objects, clawing back the performance benefits - maybe not entirely, but far better than generating ignition bytecode every time.
This is important, as Turbofan will keep track of a wide variety of things, most notably possible types for variables. For example, take the following code:
if (flag == true) {
x = 4;
} else {
x = 5;
}The type of x is then what Turbofan would denote Range(4,5) - it can be either 4, or 5, but nothing else. The typer decides this through static analysis.
But this means that, from now on, any checks regarding the value of x can be elimnated. For example, take this:
Under normal JavaScript execution, the interpreter would perform an out-of-bounds check on x to make sure that it is accessing an element of arr that actually exists. Now that the typer has decided that x is either 4 or 5, however, it will remove this check for speed - there will never be an out-of-bounds!
Mis-speculation bugs, occasionally called "typer bugs", involve finding ways to trick the typer into being incorrect about the possible values a variable can take.
Sea of Nodes
TODO
Turbolizer
TODO
Last updated
Was this helpful?