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

  • 811