current position:Home>Chrome V8

Chrome V8

2021-08-27 06:11:15 Avocado is my favorite

What is? V8

V8, Also known as virtual machines ( Can simulate the actual computer CPU、 Stack 、 Register, etc , It also has its own set of Command set system , about JavaScript Come on ,V8 It's the whole world , So don't worry about JavaScript Differences in the computer environment ), It's a by Google Open source for development Javascript engine , It is currently used in Chrome The browser and Node.js in , Its core function is to perform tasks that are easy to understand by humans JavaScript Code .

Its main core process is divided into compile and perform Two steps . First, you need to JavaScript The code is converted into low-level intermediate code or machine code that the machine can understand , Then execute the converted code and output the execution result .

Why should high-level code be compiled before execution

You can take CPU As a very small computing machine , We can use binary instructions and CPU To communicate . In order to be able to complete complex tasks , The engineer provided a lot of instructions , To realize various functions , It's machine language . Be careful ,CPU Only binary instructions can be recognized , That is to say Machine instructions . And what people can see is Assembly instruction .


1000100101011010  Machine instructions 
mov ax bx  Assembly instruction 
 Copy code 

Assembly language needs to consider the details of computer architecture , and JavaScript,C,Python These high-level languages , Then mask these differences . however , High level languages also need to be parsed , To be carried out . There are two main ways :

  1. Explain to perform
A piece of code
Intermediate code
The parser executes
Output results
  1. Compile implementation
A piece of code
Intermediate code
Machine code
Machine code execution
Output results

V8 How to execute a paragraph JavaScript Code ?

V8 It is a combination of compilation execution and interpretation execution , be called JIT(JUST IN TIME) technology . Explain that the startup speed of execution is fast , The execution speed of compilation execution is fast , Therefore, it combines the advantages of the two . The specific process is shown in the following figure :


  • Initialize the environment at startup : Stack space 、 Global execution context 、 Event loop system initialization
  • The source code is AST analysis , Generate related scopes at the same time , Store relevant variables in the scope
  • Generate intermediate code ( Bytecode )
  • Interpreter interpretation execution
  • If you find that a piece of code has been executed multiple times , Will be marked as hot code , Throw it to the compiler to compile it into binary optimization code for execution .
  • If the optimized code , Modified structure , Then anti optimization code is generated , The next execution is still left to the interpreter

V8 Debugging tools :D8

  • Print AST
pt --print-ast xxx.js
 Copy code 
  • View scope
pt --print-scopes xxx.js
 Copy code 
  • View the bytecode generated by the interpreter
pt --print-bytecode xxx.js
 Copy code 
  • View the optimized hotspot code
pt --trace-opt xxx.js
 Copy code 
  • Look at the anti optimization code
pt --trace-deopt xxx.js
 Copy code 

JavaScript design idea

Fast and slow attributes

as follows , Define an object :

let foo = {'10': 1,100: 'dds', 2: 'sda', 1: 'fdsf', 'ds': 'sda', '3': 'dfs'}
 Copy code 

Print object , You can see , The number is key The attribute of will be listed in the alphabet, and the attribute is key In front of , And the number is key The properties of are arranged in numerical order :

 screenshots 2021-08-21  Afternoon 4.34.14.png

among , The number is key The attribute of is called fast attribute , The letter is key Is called the slow property . The reason for this result is that in ECMAScript Specification , Defines that numeric attributes should be sorted in ascending order of index size , String properties are arranged in ascending order according to the order of creation time . Numeric attributes are called Sort properties , stay V8 Known as elements, The string attribute is called General properties , stay V8 Known as properties.

Because the search speed of linear structure is fast , The search speed of dictionary structure is slow , therefore ,10 General properties within are built into the object , Easy to find quickly , More than ten will still be put in properties in .

except elements and properties attribute ,V8 Also implemented for each object map Properties and __proto__ attribute .map It's a hidden class , Used to quickly find object properties in memory .


The function expression that is called immediately

The main differences between function expressions and function declarations are as follows :

  • Function expressions are used in expression statements function Of , The most typical expression is a=b This form , Because a function is also an object , We put var a = function(){} It's called a function expression
  • In a function expression , You can omit the function name , To create anonymous functions (anonymous functions)
  • A function expression can be used as a just in time call function ——IIFE

JavaScript There is a parenthesis operator in , You can put an expression in parentheses , Such as

 Copy code 

Because the expression stored between parentheses must be , So if you define a function in parentheses , that V8 I'll also think of this function as a function expression , When executed, it returns a function object .

    var a = 3
    return a + 3
 Copy code 

We add the calling bracket directly after the expression , It is called an immediate call function expression (IIFE).

    var a = 3
    return a + 3
 Copy code 

Because the function immediately calls the expression is also an expression , So in V8 Compile phase ,V8 Does not handle function expressions , The function object... Will not be created for this expression . One advantage of this is that it won't pollute the environment , Neither the function nor its internal variables will be accessed by other parts of the code .

Prototype inheritance

JavaScript Each object contains a hidden property __proto__, This is the prototype of the object .__proto__ The object pointed to is called the prototype object of the object . The following is the prototype chain , Used to find properties for objects , Look up the properties on the object one level at a time as follows .

Inheritance is that one object can access properties and methods in another object , stay JavaScript in , We implemented the inherited features through prototype and prototype chain .


The implementation of inheritance should be realized through the constructor . Each function object has an exposed prototype attribute , When you use this function as a constructor to create a new object , The prototype object of the newly created object points to the function prototype attribute .


Scope chain

Each function needs to find its own scope when executing , We call it function scope .V8 During the compilation phase of the function, a scope is created for the function , Variables defined in the function and declared functions will be thrown into the scope , In addition, the system will add another hidden variable this.

In the execution phase , If a variable, the function cannot be found in this scope , Will go to the scope where the function is defined to find , Not the scope in which it is called , This is it. Scope chain . because JavaScript Based on Lexical scope Of , The order of lexical scopes is Function definition Determined by the position of , The scope is determined when the function is declared , So the lexical scope is called Static scope . dynamic scope Just care where the function is called , The scope chain is based on the call stack rather than the location defined by the function .

Look at a question :

var a = []
for (let i=0; i < 10; i++) {
    a[i] = function(){
 Copy code 

let Defined i Will run for In the block level scope of , Execute the loop once at a time , Create a block level scope . In this block-level scope , Another function is defined , This function references an external variable i, There's a closure , because a Not destroyed , So... In all block level scopes i Will not be destroyed . Because every in a closure i The values are different , So you can print out the corresponding i Value 3. however , If you put variables i Statement of , from let Switch to var, here i Is a variable in the global scope , Because there is only one global scope , therefore i The value of is always changing . The final printed result will be 10.

Type conversion

The process is as follows :

  • First, check whether there is... In the object valueOf Method , If there is and the original data type is returned , Then use this value for cast
  • If valueOf No original type returned , Then use it without toString Return value of method
  • If valueOf and toString Neither method returns the basic data type , May be an error .
let foo = {'10': 1,100: 'dds', 2: 'sda', 1: 'fdsf', 'ds': 'sda', '3': 'dfs'}
foo.valueOf() //  Return the value of the object itself 
foo.toString() //  return [object Object]
foo + 2 //  Return results :[object Object]2
//  If you change foo Of valueOf Method 
foo.valueOf = function(){return '100'}
foo + 2 //  Return results :1002
foo.valueOf = function(){return 100}
foo + 2 //  Return results :102
 Copy code 

Compilation pipeline

Runtime environment

In execution JavaScript Before code ,V8 The runtime environment for the code is ready , This environment includes Heap space and stack space 、 Global execution context 、 Global scope 、 Built in built-in functions 、 Extension functions and objects provided by the host environment , And the message circulation system .


What is the host environment

To execute V8 Need a hosting environment , It could be a browser 、Nodejs Or other custom development environment , These hosting environments provide V8 perform JavaScript Basic functional components required for . The following figure shows the host environment and V8 Functional diagram of :


Heap space and stack space

stay Chrome Just open a rendering process , The rendering process initializes V8, Also initialize stack space . Stack space is used to manage JavaScript Of a function call . Didn't call a function , Just push the function onto the stack , Function encountered during execution , Just press it into the stack , After execution, the function is out of the stack , Until all function calls are completed , The stack is emptied .

Stack space is a continuous space , The address of each element in the stack is fixed , Therefore, the search efficiency of stack space is very high , But it is usually difficult to allocate a large continuous space in memory , therefore V8 The size of stack space is limited , If the function call is too deep , The stack may overflow .

Heap space is a tree storage structure , Discrete data used to store reference types . Heap space can hold a lot of data , But the reading speed will be slow .

function add (x, y) {
    return x + y
function main () {
    let num1 = 2
    let num2 = 3
    let num3 = add(num1, num2)
    let data = {
        sum: num3
    return data
 Copy code 

Let me explain , The execution process of the above code :

  1. establish main Stack frame pointer of function
  2. In the stack num1 initialization num1 = 2
  3. In the stack num2 initialization num2 = 3
  4. preservation main Stack top pointer of function
  5. establish add Stack frame pointer of function
  6. In the stack x initialization x = 2
  7. In the stack y initialization y = 2
  8. take x,y The added value is stored in a register
  9. The destruction add function
  10. resurrection main Stack top pointer of function
  11. In the stack num3 initialization num3 = In register add The return value of the function
  12. Create a new object in heap space , Return the object address assigned to data
  13. Write the return value to the register
  14. The destruction main function

Here's the picture , It means a stack :

 screenshots 2021-08-22  Afternoon 6.13.46.png

 screenshots 2021-08-22  Afternoon 6.19.43.png

 screenshots 2021-08-22  Afternoon 6.20.25.png

The following figure shows the relationship between register and bytecode stack :

  • Use an area of memory to store bytecode
  • Use general purpose registers r0,r1... These registers are used to store some intermediate data
  • PC The register is used to point to the next bytecode to be executed
  • Stack top register to point to the top of the stack
  • The accumulator is a very special register , Used to save intermediate results . such as : function return End execution of current function , And pass control back to the caller , The returned value is the value in the accumulator .


Global execution context

There are three main parts in the execution context , The variable environment 、 Lexical Environment and this keyword . For example, in a browser environment , The global execution context contains window object , There is also a point window Of this keyword , There are others web api function ,setTimeoutXMLHttpRequest etc. . In the Lexical Environment , It contains let、const And other variables .

Construct an event loop system

For event loop systems , Because all tasks run on the main thread , In the browser page ,V8 Will share the main thread with the page , Shared message queue , So if a function executes too long , It will affect the interactive performance of the page .

Machine code :CPU How to operate binary code

Look at a piece of code :

int main() {
    int x = 1;
    int y = 2;
    int z = x + y;
    return z;

 Copy code 

The above code will be compiled by the compiler assembly code , And binary code . image.png Here's the picture , Stack storage is Continuous space , Through the pointer and register, the function on and off the stack is realized : image.png

Lazy parsing

The so-called inert interpretation means , During parsing, the parser , If you encounter a function declaration , Then the code inside the function will be skipped , It does not generate AST And bytecode , Only one function object is generated . The function object contains name, and code attribute .name It's the name of the function ,code Is the source code of the function .

function foo(a, b) {
    var d = 100
    var f = 10
    return d + f + a + b
var a = 1
var c = 4
foo(1, 5)
 Copy code 

image.png The final generation is the number of abstract syntax of the top-level code : image.png

When you meet Closure When the condition of , At the stage of executing the function , Although it does not parse and execute its internal functions , However, the pre parser still needs to determine whether its internal functions refer to its variables .

The pre parser will judge the syntax error , And check whether the external variables referenced inside the function . If you reference an external variable , The pre parser copies the variables in the stack to the heap , The next time the function is executed , Directly use references in the heap , This solves the problem that closure external variables cannot be destroyed .

Hidden class

stay V8 in , Hidden classes are also called map, Each object has one map attribute , Its value points to the hidden class in memory . Hidden classes describe the property layout of objects , It mainly includes the attribute name and the offset corresponding to each attribute .

var point = {x=200,y=400}
 Copy code 

image.png With map after , When you use again point.x Access properties x when ,V8 Will inquire about point Of map in x Attribute relative to point The offset of the object , And then point The starting position of the object plus the offset , Got it. x The location of the value of the property in memory , It eliminates a more complex search process .

It should be noted that :

  • Objects with the same structure and different values can share the same hidden class
  • If the object structure changes , Hidden classes need to be recreated , This will affect V8 Efficiency of execution

therefore , When writing code , Pay attention to the following points :

  1. When initializing objects with literals , To ensure that the order of attributes is consistent . because key The initialization sequence is different , It will also lead to different structures .
  2. Try to use literals to initialize complete object properties at one time , Don't add... One by one .
  3. Avoid using delete Method to delete a property .
// bad
var point = {x=200,y=400}
var point2 = {y=200,x=400}
// bad
var x = {}
x.a = 1
x.b = 2
 Copy code 

Event loop system

Garbage collection mechanism

copyright notice
author[Avocado is my favorite],Please bring the original link to reprint, thank you.

Random recommended