This is the 28th day of my participation in Gwen Challenge

Programming languages are divided into compiled languages and interpreted languages.

  • Compiled languages are where the compiler converts code directly to machine code before it is run. The advantage is that you can compile once and then run the program again with the final result without having to translate it again.
  • Interpreted languages must want to have an interpreter, the interpreter will read the program code, executable program, while translation advantage is the code to run is dependent on the interpreter, is corresponding to different platform versions of the interpreter, so the code is to be able to direct cross-platform program is running, deficiency is every execution procedures must be translated, execution efficiency is lower than the compiled program.

JavaScript is an interpreted language, V8 is one of the most powerful JavaScript engines of all browsers, and it is the core of Chrome. Node.js is based on V8.

What are the stages through which THE V8 engine executes JS code?

  1. Parse phase: The V8 engine is responsible for converting JS code into an AST(abstract syntax tree).
  2. Ignition phase: The interpreter converts the AST to bytecode, and parsing the execution of the bytecode also provides the information needed to optimize compilation for the next phase.
  3. TurboFan stage: The compiler uses the information gathered in the previous stage to optimize bytecode into machine code that can be executed.
  4. Orinoco stage: Garbage collection stage, where memory space that is no longer used in the program is reclaimed.

The first three stages are the main ones.

Generate AST

Eslint and Babel are two tools involved in generating AST. The V8 engine uses the compiler (Parse) to Parse source code into AST.

Application scenarios

  • JS decomcompile, syntax parsing
  • Babel compiles ES6 syntax
  • Code highlighting
  • Keyword matching
  • Code compression

There are two stages in AST generation, one is lexical analysis, the other is grammatical analysis

  1. Lexical analysis: This stage breaks down the code into the smallest, non-detachable lexical units (tokens), such asvar a = 1;It’s usually broken down intovar,a,=,1,;These five lexical units, Spaces are ignored in JS.
  2. Parsing: This is the process of converting lexical units into a hierarchical nested tree of elements that represents the syntax structure of the program. This tree is called an abstract syntax tree.

See what it looks like when parsed into an abstract syntax tree.

var a = 1;
Copy the code

JSON format returned after conversion to AST abstract syntax tree

{
  "type": "Program"."start": 0."end": 10."body": [{"type": "VariableDeclaration"."start": 0."end": 10."declarations": [{"type": "VariableDeclarator"."start": 4."end": 9."id": {
            "type": "Identifier"."start": 4."end": 5."name": "a"
          },
          "init": {
            "type": "Literal"."start": 8."end": 9."value": 1."raw": "1"}}]."kind": "var"}]."sourceType": "module"
}
Copy the code
function sum (a,b) {
  return a + b;
}
Copy the code

JSON format returned after conversion to AST abstract syntax tree

{
  "type": "Program"."start": 0."end": 38."body": [{"type": "FunctionDeclaration"."start": 0."end": 38."id": {
        "type": "Identifier"."start": 9."end": 12."name": "sum"
      },
      "expression": false."generator": false."async": false."params": [{"type": "Identifier"."start": 14."end": 15."name": "a"
        },
        {
          "type": "Identifier"."start": 16."end": 17."name": "b"}]."body": {
        "type": "BlockStatement"."start": 19."end": 38."body": [{"type": "ReturnStatement"."start": 23."end": 36."argument": {
              "type": "BinaryExpression"."start": 30."end": 35."left": {
                "type": "Identifier"."start": 30."end": 31."name": "a"
              },
              "operator": "+"."right": {
                "type": "Identifier"."start": 34."end": 35."name": "b"}}}]}}],"sourceType": "module"
}
Copy the code

Babel, a common front-end utility, converts ES6 code into ES5 code for the browser to execute if the browser does not currently support ES6. The process is to parse ES6 code into an AST(abstract syntax tree), and then convert the abstract syntax tree of ES6 syntax into the abstract syntax tree of ES5 syntax. ESlint works in much the same way, converting source code into an abstract syntax tree and using the abstract syntax tree to monitor code specifications.

To make it easier to understand, here is an AST online conversion url, you can try it yourself

Generate bytecode

Converting the abstract syntax tree to bytecode is the Ignition phase, which is converting the AST to bytecode.

Previous versions of V8 directly converted the AST to machine code without the bytecode generation phase, but without the bytecode phase there were some problems. Direct conversions take up too much memory because the abstract syntax tree is all converted to machine code, which takes up much more memory than bytecode. In some cases, generating machine code is unnecessary to reduce the memory footprint.

So V8 later joined the process, reintroducing the Ignition interpreter to convert the abstract syntax tree to bytecode, and the memory footprint was significantly reduced. ** Further optimizations can also be made using a JIT compiler.

In fact, bytecode is a kind of code between AST and machine code, which needs to be converted into machine code before it can be executed. Bytecode can be understood as an abstraction of machine code. In addition to quickly generating unoptimized bytecode, the Ignition interpreter can also execute partial bytecode.

Generating machine code

After the Ignition interpreter processes, if a piece of code is found to have been executed multiple times, the generated bytecode and analysis data are passed to the Turbo compiler, which generates optimized machine code from the analysis data so that the code can be executed directly from the compiled machine code, which provides better performance.

The TurboFan compiler is a JIT optimized compiler. Because the V8 engine is multi-threaded, TurboFan’s compiler thread is not on the same thread as Ignition’s bytecode generation thread, so it can be used in conjunction with Ignition’s interpreter. Not influenced by the other side.

conclusion

Once the JavaScript source code comes in with the V8 engine, the JS is converted to the AST abstract syntax tree, the AST is converted to bytecode using the Ignition interpreter, and bytecode is converted to machine code using TurboFan (optimized machine code is generated if there is code that is used repeatedly, The machine code generated by the next execution. , and then the garbage is recycled.