Code Generation
The v8 bytecode

V8 JavaScript Engine

The most popular JavaScript interpreter is called V8, and it's used in Node.js and the Chrome browser. V8 is really good at turning JavaScript into fast-running code. It also uses JIT compilation. Other web browsers have their own interpreters, like Firefox's SpiderMonkey (opens in a new tab)

V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++. It implements ECMAScript and WebAssembly, and runs on Windows, macOS, and Linux systems that use x64, IA-32, or ARM processors. V8 can be embedded into any C++ application.

/images/v8/v8-compiler-stages.webp

You can use d8 (opens in a new tab) a developer shell of Chrome V8.

  v8 brew install v8
  v8 pwd -P
/Users/casianorodriguezleon/campus-virtual/2324/learning/javascript-learning/v8
  v8 cat test.js
console.log('Hello world!');
  v8 d8 test.js
Hello world!
  v8 d8
V8 version 12.1.285.24
d8> load('test.js')
Hello world!
undefined

When we use the option --printbytecode we can see the bytecode generated by the V8 engine.

  v8 d8 --print-bytecode test.js 
[generated bytecode for function:  (0x20b200199ba5 <SharedFunctionInfo>)]
Bytecode length: 19
Parameter count 1
Register count 4
Frame size 32
         0x2f2400002150 @    0 : 21 00 00          LdaGlobal [0], [0]
         0x2f2400002153 @    3 : c4                Star2
         0x2f2400002154 @    4 : 2d f7 01 02       GetNamedProperty r2, [1], [2]
         0x2f2400002158 @    8 : c5                Star1
         0x2f2400002159 @    9 : 13 02             LdaConstant [2]
         0x2f240000215b @   11 : c3                Star3
         0x2f240000215c @   12 : 5e f8 f7 f6 04    CallProperty1 r1, r2, r3, [4]
         0x2f2400002161 @   17 : c6                Star0
         0x2f2400002162 @   18 : ab                Return
Constant pool (size = 3)
Handler Table (size = 0)
Source Position Table (size = 0)
Hello world!

You can find the full list of bytecodes here (opens in a new tab). V8 has hundreds of bytecodes ranging from simple operations like Add and Sub to complex operations like LdaNamedProperty.

Each bytecode can use registers and accumulator as operands.

The accumulator is a regular register like any other register, but the difference is that the read/write of the accumulator is implicit.

When executing the bytecodes,

  1. V8 keeps monitoring the codes and looking for opportunities to optimize them.
  2. When some frequently used bytecodes are detected, V8 marks them as hot.
  3. Hot codes are then converted to machine codes of the current architecture (ARM, X64, S397 , ...) and consumed by the CPU. Machine codes take a longer time to compile, although it is much faster in terms of execution.
  4. If a hot code is changed, V8 de-optimizes the machine codes and reverts to the original bytecodes.

How the JavaScript engine works!! Source to byte code JS V8 engine explained










node.js bytecode

To view the bytecode generated by the V8 engine (which Node.js uses under the hood), you can use the --print-bytecode flag. This flag instructs V8 to output the bytecode of the JavaScript code being executed.

Here is an example of how to use it:

  1. First, ensure you have a recent version of Node.js installed, as this flag may not be available in older versions.
  2. Run your JavaScript file with the --print-bytecode flag.
node --print-bytecode your_script.js

For example, if you have a file named example.js, you would run:

node --print-bytecode example.js

This will output a lot of detailed information about the bytecode that V8 generates for your script, which is useful for deep performance analysis and understanding how your JavaScript code is being executed at a lower level.

  • This flag is primarily intended for developers working on V8 or those deeply interested in the internals of JavaScript engines.
  • The output can be quite verbose and technical, requiring a good understanding of V8 internals to interpret effectively.

If you are working on performance tuning or understanding how V8 compiles your JavaScript, the --print-bytecode flag can be a valuable tool. However, for more general debugging and profiling, Node.js offers other tools and flags that might be more user-friendly, such as the Node.js inspector or the built-in --prof flag for generating performance profiles.

v8 Resources

References