First, let's understand the difference between a compiled language and an interpreted one. In both cases, the goal is to take a human-readable language and translate it into machine language. Keep in mind that these are simplified, general distinctions. There are more nuanced differences, even within distinctions themselves. It's worth noting that a compiler can be written for any language.
Before being executed, a compiled language goes through a preliminary step - a "build" step. All of the code is translated at once and then it can be run on the target machine. For this reason, a compiled program can only be run on the machine it was compiled for - the translation for MacOS ≠ the one for Windows. Although this seems like a downside, compiled languages often result in a faster program and a lot of trivial bugs can be caught at compile time as opposed to run time. A few examples of compiled languages are Java, C, and C++.
Please note that these explanations are very simplified. I highly recommend further reading if you want to learn more about what happens under the hood (sources listed below).
JIT stands for just-in-time compilation. In a similar vein as being interpreted line-by-line on the fly, the code is compiled as the program is running, rather than going through a full compilation step before being executed. To go further, as opposed to the all source code being translated & optimized into the target's machine code, JIT compilation goes through several steps to optimize the code as needed, resulting in programs that are fast to start and retain optimization as they run. Code is first simply interpreted and, during execution, "warm" segments that are run several times are sent to a base compiler and "hot" segments that are run a significant number of times are sent to an optimized compiler.
First, the source JS code goes through a parsing step that creates an Abstract-Syntax-Tree (AST) representation of the code. The AST is then interpreted into unoptimized bytecode (Ignition's responsibility) and executed. This allows programs to get up and running quickly. The bytecode is then selectively optimized by Turbofan based on feedback from Ignition. The specifics of how the optimizations are made can be difficult to explain succinctly. However, as with all optimization, at the heart it aims to reduce unnecessary repeated actions and generally improve efficiency of tasks.
- Interpreted vs. Compiled Languages
- Crash Course in JIT Compilers
- An Introduction to Speculative Optimization in V8
Again, a lot of this explanation simplified for sake of brevity. Let me know if there are any concepts that could benefit from being more in-depth!