How V8 Runs JavaScript

What is JavaScript?

Execution

Memory

What is JavaScript?

APIs

document.createElement DOM Standard
setTimeout HTML Standard
console.log Console Standard

Environments

Web Pages

Node

Web Worker

Service Worker

Chrome Extension

D8

JavaScript Engines

Chrome V8
Firefox SpiderMonkey
Edge Chakra
Safari JavaScriptCore (Nitro)
Node V8
Opera V8
Electron V8
Node-ChakraCore ChakraCore

Execution

Parsing

Compilation

var hi = "Hello"

Parsing

function sayHi(name){
    var message = "Hi " + name + "!"
    console.log(message)
}

sayHi("Sparkle")
$ node --trace_parse test.js 
$ node --trace_parse test.js

[parsing script: native harmony-regexp-exec.js - took 0.165 ms]
[parsing function: ImportNow - took 0.020 ms]
[parsing function: OverrideFunction - took 0.028 ms]
[parsing function: SetFunctionName - took 0.022 ms]
[parsing script: native harmony-species.js - took 0.052 ms]
[parsing function: get __proto__ - took 0.012 ms]
[parsing function: InstallGetter - took 0.020 ms]
[parsing script: native harmony-unicode-regexps.js - took 0.043 ms]
[parsing function: Import - took 0.008 ms]
[parsing script: native promise-extra.js - took 0.023 ms]
[parsing function: InstallFunctions - took 0.032 ms]
[parsing function: PostExperimentals - took 0.027 ms]
[parsing function:  - took 0.007 ms]
[parsing function:  - took 0.008 ms]
[parsing function:  - took 0.005 ms]
[parsing function: b.CreateDoubleResultArray - took 0.008 ms]
[parsing function: Float64Array - took 0.040 ms]
[parsing function: Float64ArrayConstructByLength - took 0.024 ms]
[parsing function: ToPositiveInteger - took 0.015 ms]
[parsing script: bootstrap_node.js - took 0.611 ms]
[parsing function: some - took 0.036 ms]
[parsing function: InnerArraySome - took 0.034 ms]
[parsing function:  - took 0.010 ms]
[parsing function: match - took 0.050 ms]
[parsing function: [Symbol.match] - took 0.050 ms]
[parsing function: get global - took 0.040 ms]
[parsing function: RegExpSubclassExec - took 0.034 ms]
[parsing function: exec - took 0.059 ms]
[parsing function: startup - took 0.160 ms]
[parsing function: NativeModule.require - took 0.028 ms]
[parsing function: NativeModule.getCached - took 0.008 ms]
[parsing function: NativeModule.exists - took 0.006 ms]
[parsing function: NativeModule - took 0.013 ms]
[parsing function: NativeModule.cache - took 0.008 ms]
[parsing function: NativeModule.compile - took 0.022 ms]
[parsing function: NativeModule.getSource - took 0.007 ms]
[parsing function: NativeModule.wrap - took 0.008 ms]
[parsing function: runInThisContext - took 0.011 ms]
[parsing script: events.js - took 0.428 ms]
[parsing function: defineProperty - took 0.036 ms]
[parsing function: setPrototypeOf - took 0.025 ms]
[parsing function: EventEmitter - took 0.009 ms]
[parsing function: EventEmitter.init - took 0.025 ms]
[parsing function: getPrototypeOf - took 0.041 ms]
[parsing function: setupProcessObject - took 0.023 ms]
[parsing function: setupProcessFatal - took 0.033 ms]
[parsing function: setupGlobalVariables - took 0.038 ms]
[parsing script: util.js - took 1.090 ms]
[parsing script: buffer.js - took 1.063 ms]
[parsing script: internal/util.js - took 0.172 ms]
[parsing function: createPool - took 0.013 ms]
[parsing function: createUnsafeBuffer - took 0.013 ms]
[parsing function: FastBuffer - took 0.009 ms]
[parsing function: Uint8Array - took 0.048 ms]
[parsing function: Uint8ArrayConstructByLength - took 0.035 ms]
[parsing function: exports.deprecate - took 0.011 ms]
[parsing function: exports._deprecate - took 0.031 ms]
[parsing function: forEach - took 0.032 ms]
[parsing function: InnerArrayForEach - took 0.044 ms]
[parsing function:  - took 0.038 ms]
[parsing function: setupGlobalTimeouts - took 0.019 ms]
[parsing script: timers.js - took 0.463 ms]
[parsing script: internal/linkedlist.js - took 0.056 ms]
[parsing script: assert.js - took 0.286 ms]
[parsing function: exports.inherits - took 0.022 ms]
[parsing function: exports.debuglog - took 0.053 ms]
[parsing function: toUpperCase - took 0.019 ms]
[parsing function: RegExp - took 0.032 ms]
[parsing function: IsRegExp - took 0.014 ms]
[parsing function: RegExpInitialize - took 0.014 ms]
[parsing function: test - took 0.015 ms]
[parsing function: ImmediateList - took 0.019 ms]
[parsing function: setupGlobalConsole - took 0.038 ms]
[parsing script: internal/process.js - took 0.217 ms]
[parsing function: setup_hrtime - took 0.042 ms]
[parsing function: Uint32Array - took 0.056 ms]
[parsing function: Uint32ArrayConstructByLength - took 0.042 ms]
[parsing function: setup_cpuUsage - took 0.056 ms]
[parsing function: setupConfig - took 0.052 ms]
[parsing function: split - took 0.048 ms]
[parsing function: join - took 0.021 ms]
[parsing function: InnerArrayJoin - took 0.020 ms]
[parsing function: Join - took 0.018 ms]
[parsing function: StackHas - took 0.015 ms]
[parsing function: StackPush - took 0.008 ms]
[parsing function: DoJoin - took 0.057 ms]
[parsing function: UseSparseVariant - took 0.018 ms]
[parsing function: StackPop - took 0.009 ms]
[parsing function: replace - took 0.047 ms]
[parsing function: [Symbol.replace] - took 0.096 ms]
[parsing function: get unicode - took 0.022 ms]
[parsing function: [Symbol.replace] - took 0.045 ms]
[parsing function: parse - took 0.021 ms]
[parsing function: InternalizeJSONProperty - took 0.042 ms]
[parsing function:  - took 0.012 ms]
[parsing function: CreateDataProperty - took 0.015 ms]
[parsing script: internal/process/warning.js - took 0.084 ms]
[parsing function: setupProcessWarnings - took 0.057 ms]
[parsing function: addListener - took 0.010 ms]
[parsing function: _addListener - took 0.058 ms]
[parsing script: internal/process/next_tick.js - took 0.133 ms]
[parsing function: setupNextTick - took 0.115 ms]
[parsing script: internal/process/promises.js - took 0.096 ms]
[parsing function: WeakMap - took 0.038 ms]
[parsing function: setupPromises - took 0.078 ms]
[parsing script: internal/process/stdio.js - took 0.141 ms]
[parsing function: setupStdio - took 0.096 ms]
[parsing function: setupKillAndExit - took 0.044 ms]
[parsing function: setupSignalHandlers - took 0.046 ms]
[parsing function: emit - took 0.072 ms]
[parsing function: emitTwo - took 0.023 ms]
[parsing function:  - took 0.031 ms]
[parsing function: isSignal - took 0.010 ms]
[parsing function: lazyConstants - took 0.010 ms]
[parsing function: setupChannel - took 0.023 ms]
[parsing function: setupRawDebug - took 0.017 ms]
[parsing script: path.js - took 2.163 ms]
[parsing function: resolve - took 0.045 ms]
[parsing function: assertPath - took 0.012 ms]
[parsing function: charCodeAt - took 0.023 ms]
[parsing function: normalizeStringPosix - took 0.066 ms]
[parsing function: slice - took 0.037 ms]
[parsing script: module.js - took 0.585 ms]
[parsing script: internal/module.js - took 0.088 ms]
[parsing script: vm.js - took 0.134 ms]
[parsing script: fs.js - took 2.119 ms]
[parsing function: Script.runInThisContext - took 0.018 ms]
[parsing script: stream.js - took 0.105 ms]
[parsing script: _stream_readable.js - took 0.747 ms]
[parsing script: internal/streams/BufferList.js - took 0.082 ms]
[parsing script: _stream_writable.js - took 0.416 ms]
[parsing script: _stream_duplex.js - took 0.061 ms]
[parsing script: _stream_transform.js - took 0.136 ms]
[parsing script: _stream_passthrough.js - took 0.042 ms]
[parsing function:  - took 0.015 ms]
[parsing function: Map - took 0.039 ms]
[parsing function: Module._initPaths - took 0.039 ms]
[parsing function: preloadModules - took 0.012 ms]
[parsing function: run - took 0.026 ms]
[parsing function: Module.runMain - took 0.011 ms]
[parsing function: Module._load - took 0.040 ms]
[parsing function: Module._resolveFilename - took 0.035 ms]
[parsing function: NativeModule.nonInternalExists - took 0.025 ms]
[parsing function: Module._resolveLookupPaths - took 0.099 ms]
[parsing function: debugs.(anonymous function) - took 0.004 ms]
[parsing function: Module._findPath - took 0.102 ms]
[parsing function: isAbsolute - took 0.022 ms]
[parsing function: stringify - took 0.100 ms]
[parsing function: stat - took 0.030 ms]
[parsing function: _makeLong - took 0.006 ms]
[parsing function: toRealPath - took 0.021 ms]
[parsing function: realpathSync - took 0.131 ms]
[parsing function: nullCheck - took 0.030 ms]
[parsing function: indexOf - took 0.033 ms]
[parsing function: toString - took 0.013 ms]
[parsing function: get - took 0.037 ms]
[parsing function: GetExistingHash - took 0.023 ms]
[parsing function: MapFindEntry - took 0.038 ms]
[parsing function: HashToEntry - took 0.010 ms]
[parsing function: start - took 0.019 ms]
[parsing function: fs.lstatSync - took 0.011 ms]
[parsing function: fs.Stats - took 0.039 ms]
[parsing function: fs.Stats.isSymbolicLink - took 0.018 ms]
[parsing function: fs.Stats._checkModeProperty - took 0.008 ms]
[parsing function: set - took 0.065 ms]
[parsing function: GetHash - took 0.017 ms]
[parsing function: encodeRealpathResult - took 0.030 ms]
[parsing function: Module - took 0.026 ms]
[parsing function: tryModuleLoad - took 0.026 ms]
[parsing function: Module.load - took 0.031 ms]
[parsing function: ok - took 0.019 ms]
[parsing function: dirname - took 0.030 ms]
[parsing function: Module._nodeModulePaths - took 0.055 ms]
[parsing function: extname - took 0.044 ms]
[parsing function: Module._extensions..js - took 0.013 ms]
[parsing function: fs.readFileSync - took 0.062 ms]
[parsing function: assertEncoding - took 0.012 ms]
[parsing function: Buffer.isEncoding - took 0.009 ms]
[parsing function: normalizeEncoding - took 0.025 ms]
[parsing function: isFd - took 0.007 ms]
[parsing function: fs.openSync - took 0.015 ms]
[parsing function: modeNum - took 0.070 ms]
[parsing function: stringToFlags - took 0.054 ms]
[parsing function: tryStatSync - took 0.022 ms]
[parsing function: fs.fstatSync - took 0.007 ms]
[parsing function: fs.Stats.isFile - took 0.007 ms]
[parsing function: tryCreateBuffer - took 0.027 ms]
[parsing function: Buffer.allocUnsafe - took 0.007 ms]

[parsing function: assertSize - took 0.023 ms]
[parsing function: isNaN - took 0.024 ms]
[parsing function: get buffer - took 0.013 ms]
[parsing function: get byteOffset - took 0.009 ms]
[parsing function: Uint8ArrayConstructByArrayBuffer - took 0.069 ms]
[parsing function: alignPool - took 0.011 ms]
[parsing function: tryReadSync - took 0.019 ms]
[parsing function: fs.readSync - took 0.051 ms]
[parsing function: fs.closeSync - took 0.008 ms]
[parsing function: Buffer.toString - took 0.017 ms]
[parsing function: slowToString - took 0.054 ms]
[parsing function: stripBOM - took 0.012 ms]
[parsing function: Module._compile - took 0.084 ms]
[parsing function: exports.runInThisContext - took 0.031 ms]
[parsing script: /Users/mattzeunert/test.js - took 0.019 ms]
[parsing function: makeRequireFunction - took 0.037 ms]
[parsing function: sayHi - took 0.022 ms]
[parsing function: get - took 0.013 ms]
[parsing script: console.js - took 0.333 ms]
[parsing function: getStdout - took 0.108 ms]
[parsing function: createWritableStdioStream - took 0.098 ms]
[parsing script: tty.js - took 0.131 ms]
[parsing script: net.js - took 1.197 ms]
[parsing script: internal/net.js - took 0.032 ms]
[parsing function: protoGetter - took 0.021 ms]
[parsing function: WriteStream - took 0.040 ms]
[parsing function: Socket - took 0.083 ms]
[parsing function: Duplex - took 0.035 ms]
[parsing function: Readable - took 0.018 ms]
[parsing function: ReadableState - took 0.077 ms]
[parsing function: BufferList - took 0.010 ms]
[parsing function: Stream - took 0.013 ms]
[parsing function: EventHandlers - took 0.005 ms]
[parsing function: Writable - took 0.032 ms]
[parsing function: WritableState - took 0.066 ms]
[parsing function: CorkedRequest - took 0.029 ms]
[parsing function: once - took 0.018 ms]
[parsing function: _onceWrap - took 0.021 ms]
[parsing function: Readable.on - took 0.032 ms]
[parsing function: initSocketHandle - took 0.020 ms]
[parsing function: getStderr - took 0.031 ms]
[parsing function: $getMaxListeners - took 0.014 ms]
[parsing function: get - took 0.006 ms]
[parsing function: Console - took 0.052 ms]
[parsing function: Console.log - took 0.016 ms]
[parsing function: Console.warn - took 0.012 ms]
[parsing function: Console.dir - took 0.016 ms]
[parsing function: Console.time - took 0.009 ms]
[parsing function: Console.timeEnd - took 0.025 ms]
[parsing function: trace - took 0.018 ms]
[parsing function: Console.assert - took 0.014 ms]
[parsing function: installInspectorConsoleIfNeeded - took 0.036 ms]
[parsing function: exports.format - took 0.073 ms]
[parsing function: Socket.write - took 0.020 ms]
[parsing function: Writable.write - took 0.031 ms]
[parsing function: validChunk - took 0.029 ms]
[parsing function: writeOrBuffer - took 0.038 ms]
[parsing function: decodeChunk - took 0.015 ms]
[parsing function: doWrite - took 0.020 ms]
[parsing function: Socket._write - took 0.008 ms]
[parsing function: Socket._writeGeneric - took 0.063 ms]
[parsing function: _unrefTimer - took 0.012 ms]
[parsing function: exports._unrefActive - took 0.007 ms]
[parsing function: insert - took 0.028 ms]
[parsing function: createWriteReq - took 0.027 ms]
Hi Sparkle!
[parsing function: WritableState.onwrite - took 0.008 ms]
[parsing function: onwrite - took 0.026 ms]
[parsing function: onwriteStateUpdate - took 0.011 ms]
[parsing function: needFinish - took 0.010 ms]
[parsing function: nextTick - took 0.026 ms]
[parsing function: TickObject - took 0.011 ms]
[parsing function: _tickCallback - took 0.027 ms]
[parsing function: _combinedTickCallback - took 0.020 ms]
[parsing function: afterWrite - took 0.013 ms]
[parsing function: onwriteDrain - took 0.011 ms]
[parsing function: nop - took 0.003 ms]
[parsing function: finishMaybe - took 0.016 ms]
[parsing function: tickDone - took 0.017 ms]
[parsing function: emitPendingUnhandledRejections - took 0.034 ms]
$ d8 --trace-parse test.js 

test.js:3: ReferenceError: console is not defined
    console.log(message)
    ^
ReferenceError: console is not defined
    at sayHi (test.js:3:5)
    at test.js:6:1
function sayHi(name){
    var message = "Hi " + name + "!"
    console.log(message)
}

sayHi("Sparkle")
$ d8 --trace-parse test.js

[parsing script: native datetime-format-...js - took 3.453 ms]
[parsing function: ImportNow - took 0.025 ms]
[parsing function: InstallFunctions - took 0.035 ms]
[parsing function: SetFunctionName - took 0.020 ms]
[parsing script: native icu-case-mapping.js - took 0.029 ms]
[parsing function: OverrideFunction - took 0.311 ms]
[parsing function: PostExperimentals - took 0.024 ms]
[parsing script: test.js - took 1.248 ms]
[parsing function: sayHi - took 0.012 ms]
Hi Sparkle!
function sayHi(name){
    var message = "Hi " + name + "!"
    print(message)
}

sayHi("Sparkle")
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!

sayHi pre-parse

sayHi full parse

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!
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!

Create React App Bundle:
24ms => 18ms

press Shift 6 times to see all experiments

Compilation

Baseline Compiler

Optimizing Compiler

Full-codegen

Crankshaft / Turbofan

$ d8 --trace_opt test.js

[marking 0x2b71a8bd <JS Function add (SharedFunctionInfo 0x2b71a6d9)> for optimized recompilation, reason: small function, ICs with typeinfo: 1/1 (100%), generic ICs: 0/1 (0%)]

[compiling method 0x2b71a8bd <JS Function add
(SharedFunctionInfo 0x2b71a6d9)> using Crankshaft]
[optimizing 0x2b71a8bd <JS Function add (SharedFunctionInfo 0x2b71a6d9)> - took 0.085, 0.112, 0.044 ms] [completed optimizing 0x2b71a8bd <JS Function add (SharedFunctionInfo 0x2b71a6d9)>]
function add(a,b){
    return a + b;
}

for (var i=0; i< 10000; i++){
    add(i, 1);
}
$ d8 --trace_opt --trace_deopt test.js

...
[optimizing 0x4761a8d5 <JS Function add (SharedFunctionInfo 0x4761a6d9)> - took 0.087, 0.105, 0.054 ms]
...
[deoptimizing (DEOPT eager): begin 0x4761a8d5 <JS Function add (SharedFunctionInfo 0x4761a6d9)> (opt #0) @2, FP to SP delta: 12, caller sp: 0xbffa1044]
...
[removing optimized code for: add]
function add(a,b){
    return a + b
}

for (var i=0; i< 10000; i++){
    add(i, 1)
}

add(i, "a")
function addInteger(a,b){
    return a + b;
}
function addString(a,b){
    return a + b;
}
console.time("Integer")
for (var i=0; i< 10000000; i++){
    addInteger(i, 1);
}
console.timeEnd("Integer")

console.time("String")
for (var i=0; i< 10000000; i++){
    addString(i, "a");
}
console.timeEnd("String")

$ node test.js 

Integer: 11.545ms
String: 792.009ms

$ node test.js

Integer: 10.061ms
String: 1031.975ms

add

addInteger/addString

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 :)

Assign All Properties In The Constructor

Bailouts

function doSth(){
    debugger;
    // code here isn't optimized
}
function debuggerFunction(){
    debugger
}

function doSth(){
    debuggerFunction()
    // code here is optimized
}
function sum(){
    var args = toArray(arguments)
    return args.reduce((sum, val) => sum + val, 0)
}
sum(1,2,3) // 6

"Bad value context for arguments value"

function sum(){
    var args = toArray(arguments)
    return args.reduce((sum, val) => sum + val, 0)
}
sum(1,2,3) // 6
function sum(){
    var sum = 0
    for (var i=0; i<arguments.length; i++){
        sum += arguments[i]
    }
    return sum
}

Baseline Compiler

Optimizing Compiler

Full-codegen

Crankshaft / Turbofan

Interpreter

Ignition

</Execution>

Memory

var p1 = new Person("John", "William", "Green")
var p2 = new Person("Mary", "Lisa", "Smith")

Objects

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 

Strings

Keep things uniform and predictable

Learn More

V8 Wiki - Design Elements

Breaking the JavaScript Speed Limit with V8

JavaScript Start-up Performance

 

Performance Profiling for V8

 

 

Garbage Collection?

Getting Garbage Collection For Free

Twitter: @mattzeunert

Thank You

Slides

How V8 runs JavaScript

By Matt Zeunert

How V8 runs JavaScript

  • 1,591