For JavaScript:
[ JS source] --(parser)--> [ AST ] --(Ignition bytecode generator)--> [ bytecode ]
[ bytecode ] --(Ignition bytecode interpreter)--> {execution}
As a given function gets increasingly hotter (as determined by certain counters/budgets embedded into it):
[ bytecode ] --(Sparkplug non-optimizing compiler)--> [ unoptimized machine code ] --> {execution}
[ bytecode ] --(Maglev fast optimizing compiler)--> [ mostly-optimized machine code ] --> {execution}
[ bytecode ] --(Turbofan thorough optimizing compiler)--> [ fully optimized machine code] --> {execution}
The fact that the compilers consume bytecode is just an internal optimization, they could alternatively start with the AST again, as bytecode and AST are similarly expressive. There are multiple reasons why it's convenient to make them consume bytecode:
- the bytecode is much more compact than the AST, so storing the AST until later optimization would cost a lot more memory
- re-parsing the source to re-generate the AST (if not storing it) would cost more CPU time
- when generating bytecode from the AST, we perform a few steps of desugaring, so it's convenient to not have to reimplement that logic elsewhere too
- to simplify things, Ignition and Sparkplug use the same stack frame layout, which means they have to stay very closely in sync, which is easier to achieve by making Sparkplug consume bytecode as input
I'm pointing this out because in my experience this is a detail that tends to confuse audiences, so it may be worth pointing out that it's just an internal detail, and not important for the overall concept.
For Wasm it's a similar principle, but only two compilers:
[ Wasm wire bytes] --(Liftoff single-pass compiler)--> [ unoptimized machine code ] --> {execution}
If a given function gets hot enough:
[ Wasm wire bytes ] --(Turbofan optimizing compiler)--> [ optimized machine code] --> {execution}
Comparing the above to the draft graph as currently posted on GitHub:
- Ignition does not produce machine code
- I'm not sure what the "Profile (C1 Compiler?)" box is supposed to be
- I'm not sure what the dotted arrows are supposed to mean
As a general tip, it may help to visually distinguish boxes that are transformers (e.g. "parser") from boxes that are data consumed and produced by these transformers (e.g. "AST").