How V8 Runs JavaScript
What's a JavaScript Engine?
APIs
document.createElement | DOM Standard |
setTimeout | HTML Standard |
console.log | Console Standard |
=> Built into browser
JavaScript Engines
Chrome | V8 |
Firefox | SpiderMonkey |
Edge | Chakra |
Safari | JavaScriptCore (Nitro) |
Node | V8 |
Opera | V8 |
Electron | V8 |
Node-ChakraCore | ChakraCore |
Execution Pipeline
Memory
var hi = "Hello"
Parsing
function sayHi(name){
var message = "Hi " + name + "!"
print(message)
}
function add(a, b){
return a + b
}
sayHi("Sparkle")
$ d8 --trace-parse test.js
[parsing script: test.js - took 0.651 ms]
[parsing function: sayHi - took 0.009 ms]
Hi Sparkle!
sayHi pre-parse
sayHi full parse
function sayHi(name){
var message = "Hi " + name + "!"
print(message)
}
sayHi("Sparkle")
$ d8 --trace-parse test.js
[parsing script: test.js - took 1.248 ms]
[parsing function: sayHi - took 0.012 ms]
Hi Sparkle!
var constants = (function(){
return {pi: 3.14}
})()
$ d8 --trace-parse test.js
[parsing script: test.js - took 0.024 ms]
var sayHi = (function sayHi(name){
var message = "Hi " + name + "!"
print(message)
})
sayHi("Sparkle")
$ d8 --trace-parse test.js
[parsing script: test.js - took 0.019 ms]
Hi Sparkle!
press Shift 6 times to see all experiments
Execution
Interpreter
Compiler
Ignition
Turbofan
$ d8 --trace_opt test.js
...
[marking 0x3830902c839 <JSFunction add (sfi = 0x3830902c489)>
for optimized recompilation, reason: small function,
ICs with typeinfo: 2/2 (100%), generic ICs: 0/2 (0%)]
[compiling method 0x3830902c839 <JSFunction add
(sfi = 0x3830902c489)> using TurboFan]
...
[optimizing 0x3830902c839 <JSFunction add (sfi = 0x3830902c489)>
[completed optimizing 0x3830902c839 <JSFunction add ...>]
function add(a, b, c){
return a + b + c
}
for (var i=0; i< 100000; i++){
add(i, 1, 2)
}
$ d8 --trace_opt --trace_deopt test.js
...
[optimizing 0x25c3063ac879 <JSFunction add (sfi =
0x25c3063ac489)> - took 1.146, 0.359, 0.014 ms]
[completed optimizing 0x25c3063ac879
<JSFunction add (sfi = 0x25c3063ac489)>]
[deoptimizing (DEOPT eager): begin 0x25c3063ac879
<JSFunction add (sfi = 0x25c3063ac489)> (opt #0) @3,
FP to SP delta: 16, caller sp: 0x7fff559a1fc8]
function add(a, b, c){
return a + b + c
}
for (var i=0; i< 100000; i++){
add(i, 1, 2)
}
add(1, 2, "a")
Objects and Properties
person.age
age = person.age
age = [objAddress + offset]
age = [0x674836362 + 2]
Person |
---|
[0] firstName |
[1] lastName |
[2] age |
[3] location |
Hidden Classes
var p1 = new Person("John", "William", "Green")
var p2 = new Person("Mary", "Lisa", "Smith")
Hidden Classes
var p1 = new Person("John", "William", "Green")
var p2 = new Person("Mary", "Lisa", "Smith")
p2.location = "London"
function getName(person){
return person.firstName + person.lastName
}
var p1 = new Person("John", "William", "Green")
var p2 = new Person("Mary", "Lisa", "Smith")
for (var i=0;i<10000;i++){ getName(p1) }
for (var i=0;i<10000;i++){ getName(p2) }
var p1 = new Person("John", "William", "Green")
var p2 = new Person("Mary", "Lisa", "Smith")
p2.location = "London"
for (var i=0;i<10000;i++){ getName(p1) }
for (var i=0;i<10000;i++){ getName(p2) }
$ d8 --trace_deopt test.js
[deoptimizing (DEOPT eager): begin 0x52f9ab45 <JS Function getName (SharedFunctionInfo 0x52f9a829)> (opt #0) @2, FP to SP delta: 12, caller sp: 0xbff65004]
...
[deoptimizing (eager): end 0x52f9ab45 <JS Function getName (SharedFunctionInfo 0x52f9a829)> @2 => node=4, pc=0x3ad0756f, caller sp=0xbff65004, state=NO_REGISTERS, took 0.104 ms]
[removing optimized code for: getName]
var p1 = new Person("John", "William", "Green")
p1.location = null
var p2 = new Person("Mary", "Lisa", "Smith")
p2.location = "London"
for (var i=0;i<10000;i++){ getName(p1) }
for (var i=0;i<10000;i++){ getName(p2) }
$ d8 --trace_deopt test.js
No output :)
Objects of the same type should have the same properties
Memory
var p1 = new Person("John", "William", "Green")
var p2 = new Person("Mary", "Lisa", "Smith")
1
2
3
4
5
5 * (64 / 8) = 40
var p = [];
for (var i=0; i<100000;i++){
p.push(new Person("a", "b", "c"))
}
p1.location = "London"
p1.otherProp = "sth"
Extra Properties
p1[0] = "zero"
p1[1] = "one"
Numbered Properties
Map |
extraProperties |
elements |
firstName |
middleName |
lastName |
location |
otherProp |
Person Object
0 |
1 |
1
2
3
4
5
6
6 * (64/8) = 48
delete p2.middleName
Arrays
var arr = []
for (var i=0; i< 1000000;i++){
arr.push(Math.random())
}
9.7MB ≈ 8MB
0.2 | 1.8 | 1.4 | |
0x8789 | 0x37b2 | 0xae72 |
"abc"
(reference)
0xc79d
(reference) | (reference) | (reference) | |
0x127b | 0x7a55 | 0x98ee |
"abc"
(reference)
0xc79d
{ num: 0.2 }
{ num: 1.8 }
{ num: 1.4 }
arr.push("abc")
arr.push("abc")
25.7MB ≈ 24MB
Keep Types Consistent
Learn More
V8 Wiki - Design Elements
V8 Behind the Scenes and a Tale of TurboFan
JavaScript Start-up Performance
Slides
Copy of How V8 Runs JavaScript - Strikingly Tech
By Matt Zeunert
Copy of How V8 Runs JavaScript - Strikingly Tech
- 888