The major JavaScript
engines of web browsers and nodeJS
have had just-in-time
pilers for years.
I was just watching a video on Compiler Explorer showing the assembly code output by many pilers for various CPUs.
This reminded me that I've been curious about the code generated by the JS engines' jits.
Do any of those engines have ways for us to see that low-level generated code?
(If this is out of place on SO please feel free to migrate it to the correct SE site.)
The major JavaScript
engines of web browsers and nodeJS
have had just-in-time
pilers for years.
I was just watching a video on Compiler Explorer showing the assembly code output by many pilers for various CPUs.
This reminded me that I've been curious about the code generated by the JS engines' jits.
Do any of those engines have ways for us to see that low-level generated code?
(If this is out of place on SO please feel free to migrate it to the correct SE site.)
Share Improve this question edited Dec 28, 2017 at 12:00 Mamun 69k9 gold badges51 silver badges62 bronze badges asked Dec 28, 2017 at 11:56 hippietrailhippietrail 17.1k21 gold badges109 silver badges179 bronze badges 1- 2 The video you were watching was probably Matt Godbolt's talk at CppCon2017: “What Has My Compiler Done for Me Lately? Unbolting the Compiler's Lid". It's good :) – Peter Cordes Commented Dec 29, 2017 at 2:27
2 Answers
Reset to default 7For V8, there is a flag --print-opt-code
, which prints generated optimized assembly code for each function that gets optimized. Note that functions only get optimized when they're "hot", not right away, so for a short "hello, world" style program the flag won't print anything. You can make functions "hot" by calling them a lot.
In older versions, there was a --print-code
flag for unoptimized code, but since the baseline (non-optimizing) piler has been replaced by an interpreter, there is no unoptimized code any more. You can print the generated bytecode with --print-bytecode
.
If you're using Chrome, you can specify flags to be passed to V8 by wrapping them in --js-flags, e.g. --js-flags="--print-opt-code"
.
One thing you can always do is interrupt your program while it's running, using a debugger.
If it's spending most of its time in JIT-piled code, then chances are the current instruction-pointer value (RIP) will be inside some JIT-piled machine code, which your debugger will disassemble for you. (Or at least the part after the current RIP: x86 machine code uses variable-length instructions, so there's no reliable way to go backwards. You might single-step until you reach a backwards branch to get to the top of a loop.)
But without any way to figure out which function name you're seeing JITed asm for, this is probably not very useful unless you only have one hot loop (e.g. in an artificial test / microbenchmark).
Having the JIT engine print the asm as it generates it (@jmrk's answer) is much more usable; I only mention this technique because it works without any support from the JIT engine, so it can work on anything.