Slide 1

Slide 1 text

@mathias V8 internals for JavaScript developers @mathias // @v8js

Slide 2

Slide 2 text

Write modern, idiomatic JavaScript, and let the JavaScript engine worry about making it fast.

Slide 3

Slide 3 text

@mathias JavaScript source code

Slide 4

Slide 4 text

@mathias parser JavaScript source code

Slide 5

Slide 5 text

@mathias parser Abstract Syntax Tree JavaScript source code

Slide 6

Slide 6 text

@mathias parser Abstract Syntax Tree interpreter JavaScript source code

Slide 7

Slide 7 text

@mathias parser Abstract Syntax Tree interpreter bytecode JavaScript source code

Slide 8

Slide 8 text

@mathias optimizing compiler parser Abstract Syntax Tree interpreter bytecode JavaScript source code optimize + profiling data

Slide 9

Slide 9 text

@mathias optimized code optimizing compiler parser Abstract Syntax Tree interpreter bytecode JavaScript source code optimize + profiling data

Slide 10

Slide 10 text

@mathias optimized code optimizing compiler parser Abstract Syntax Tree interpreter bytecode JavaScript source code deoptimize optimize + profiling data

Slide 11

Slide 11 text

@mathias optimized code optimizing compiler parser Abstract Syntax Tree interpreter bytecode JavaScript source code deoptimize optimize + profiling data

Slide 12

Slide 12 text

@mathias optimized code optimizing compiler parser Abstract Syntax Tree interpreter bytecode JavaScript source code deoptimize optimize + profiling data

Slide 13

Slide 13 text

@mathias optimized code optimizing compiler parser Abstract Syntax Tree interpreter bytecode JavaScript source code deoptimize optimize + profiling data

Slide 14

Slide 14 text

@mathias optimized code optimizing compiler parser Abstract Syntax Tree interpreter bytecode JavaScript source code deoptimize optimize + profiling data optimized code optimizing compiler !"❤$%&'()"!

Slide 15

Slide 15 text

@mathias Elements kinds in V8

Slide 16

Slide 16 text

@mathias const object = { // ‚* foo: true, // ‚* // ‚* // ‚* // ‚* }; // ‚*

Slide 17

Slide 17 text

@mathias const object = { // ‚* 'foo': true, // ‚* // ‚* // ‚* // ‚* }; // ‚*

Slide 18

Slide 18 text

@mathias const object = { // ‚* 'foo': true, // ‚* '#fronteers': true, // ‚* // ‚* // ‚* }; // ‚*

Slide 19

Slide 19 text

@mathias const object = { // ‚* 'foo': true, // ‚* '#fronteers': true, // ‚* 'Iñtërnâtiônàlizætiøn‚*': true, // ‚* }; // ‚*

Slide 20

Slide 20 text

@mathias const object = { // ‚* 'foo': true, // ‚* '#fronteers': true, // ‚* 'Iñtërnâtiônàlizætiøn‚*': true, '123': true, // ‚* }; // ‚*

Slide 21

Slide 21 text

@mathias Elements kinds in V8

Slide 22

Slide 22 text

@mathias const array = [1, 2, 3];


Slide 23

Slide 23 text

@mathias const array = [1, 2, 3];
 // elements kind: PACKED_SMI_ELEMENTS


Slide 24

Slide 24 text

@mathias const array = [1, 2, 3];
 // elements kind: PACKED_SMI_ELEMENTS
 array.push(4.56);


Slide 25

Slide 25 text

@mathias const array = [1, 2, 3];
 // elements kind: PACKED_SMI_ELEMENTS
 array.push(4.56);
 // elements kind: PACKED_DOUBLE_ELEMENTS

Slide 26

Slide 26 text

@mathias const array = [1, 2, 3];
 // elements kind: PACKED_SMI_ELEMENTS
 array.push(4.56);
 // elements kind: PACKED_DOUBLE_ELEMENTS
 array.push('x');


Slide 27

Slide 27 text

@mathias const array = [1, 2, 3];
 // elements kind: PACKED_SMI_ELEMENTS
 array.push(4.56);
 // elements kind: PACKED_DOUBLE_ELEMENTS
 array.push('x');
 // elements kind: PACKED_ELEMENTS

Slide 28

Slide 28 text

@mathias Smi Doubles Regular elements Elements kinds

Slide 29

Slide 29 text

@mathias const array = [1, 2, 3];
 // elements kind: PACKED_SMI_ELEMENTS
 array.push(4.56);
 // elements kind: PACKED_DOUBLE_ELEMENTS
 array.push('x');
 // elements kind: PACKED_ELEMENTS

Slide 30

Slide 30 text

@mathias array.length; // 5
 index 0 1 2 3 4 value 1 2 3 4.56 'x'

Slide 31

Slide 31 text

@mathias array.length; // 5
 array[9] = 1; // array[5] until array[8] are now holes
 index 0 1 2 3 4 5 6 7 8 9 value 1 2 3 4.56 'x' 1

Slide 32

Slide 32 text

@mathias array.length; // 5
 array[9] = 1; // array[5] until array[8] are now holes
 // elements kind: HOLEY_ELEMENTS index 0 1 2 3 4 5 6 7 8 9 value 1 2 3 4.56 'x' 1

Slide 33

Slide 33 text

@mathias array[8];
 // " ??? index 0 1 2 3 4 5 6 7 8 9 value 1 2 3 4.56 'x' 1

Slide 34

Slide 34 text

@mathias array[8];
 // " ??? ❌ index 0 1 2 3 4 5 6 7 8 9 value 1 2 3 4.56 'x' 1

Slide 35

Slide 35 text

@mathias array[8];
 // " ??? ❌
 8 >= 0 && 8 < array.length; // bounds check // " true index 0 1 2 3 4 5 6 7 8 9 value 1 2 3 4.56 'x' 1

Slide 36

Slide 36 text

@mathias array[8];
 // " ??? ❌
 8 >= 0 && 8 < array.length; // bounds check // " true ❌ index 0 1 2 3 4 5 6 7 8 9 value 1 2 3 4.56 'x' 1

Slide 37

Slide 37 text

@mathias array[8];
 // " ??? ❌
 8 >= 0 && 8 < array.length; // bounds check // " true ❌ hasOwnProperty(array, '8');
 // " false index 0 1 2 3 4 5 6 7 8 9 value 1 2 3 4.56 'x' 1

Slide 38

Slide 38 text

@mathias array[8];
 // " ??? ❌
 8 >= 0 && 8 < array.length; // bounds check // " true ❌ hasOwnProperty(array, '8');
 // " false ❌ index 0 1 2 3 4 5 6 7 8 9 value 1 2 3 4.56 'x' 1

Slide 39

Slide 39 text

@mathias array[8];
 // " ??? ❌
 8 >= 0 && 8 < array.length; // bounds check // " true ❌ hasOwnProperty(array, '8');
 // " false ❌ hasOwnProperty(Array.prototype, '8');
 // " false

Slide 40

Slide 40 text

@mathias array[8];
 // " ??? ❌
 8 >= 0 && 8 < array.length; // bounds check // " true ❌ hasOwnProperty(array, '8');
 // " false ❌ hasOwnProperty(Array.prototype, '8'); // " false ❌

Slide 41

Slide 41 text

@mathias array[8];
 // " ??? ❌
 8 >= 0 && 8 < array.length; // bounds check // " true ❌ hasOwnProperty(array, '8');
 // " false ❌ hasOwnProperty(Array.prototype, '8'); // " false ❌ hasOwnProperty(Object.prototype, '8'); // " false

Slide 42

Slide 42 text

@mathias array[8];
 // " ??? ❌
 8 >= 0 && 8 < array.length; // bounds check // " true ❌ hasOwnProperty(array, '8');
 // " false ❌ hasOwnProperty(Array.prototype, '8'); // " false ❌ hasOwnProperty(Object.prototype, '8'); // " false ✅

Slide 43

Slide 43 text

@mathias array[8];
 // " undefined ✅
 8 >= 0 && 8 < array.length; // bounds check // " true hasOwnProperty(array, '8');
 // " false hasOwnProperty(Array.prototype, '8'); // " false hasOwnProperty(Object.prototype, '8'); // " false ✅

Slide 44

Slide 44 text

@mathias packedArray[8];
 // " undefined ✅
 8 >= 0 && 8 < packedArray.length; // bounds check // " true ✅ hasOwnProperty(packedArray, '8');
 // " true ✅ hasOwnProperty(Array.prototype, '8'); // " false ✅ hasOwnProperty(Object.prototype, '8'); // " false ✅

Slide 45

Slide 45 text

@mathias packedArray[8];
 // " undefined ✅
 8 >= 0 && 8 < packedArray.length; // bounds check // " true ✅ hasOwnProperty(packedArray, '8');
 // " true ✅ hasOwnProperty(Array.prototype, '8'); // " false ✅ hasOwnProperty(Object.prototype, '8'); // " false ✅

Slide 46

Slide 46 text

@mathias array[0];
 // " ???


Slide 47

Slide 47 text

@mathias array[0];
 // " ??? ❌

Slide 48

Slide 48 text

@mathias array[0];
 // " ??? ❌ 0 >= 0 && 0 < array.length; // bounds check // " true

Slide 49

Slide 49 text

@mathias array[0];
 // " ??? ❌ 0 >= 0 && 0 < array.length; // bounds check // " true ❌

Slide 50

Slide 50 text

@mathias array[0];
 // " ??? ❌ 0 >= 0 && 0 < array.length; // bounds check // " true ❌
 hasOwnProperty(array, '0');
 // " true

Slide 51

Slide 51 text

@mathias array[0];
 // " ??? ❌ 0 >= 0 && 0 < array.length; // bounds check // " true ❌
 hasOwnProperty(array, '0');
 // " true ✅

Slide 52

Slide 52 text

@mathias array[0];
 // " 1 ✅ 0 >= 0 && 0 < array.length; // bounds check // " true
 hasOwnProperty(array, '0');
 // " true ✅

Slide 53

Slide 53 text

@mathias PACKED > HOLEY

Slide 54

Slide 54 text

@mathias PACKED > HOLEY -. /0

Slide 55

Slide 55 text

@mathias Smi Doubles Regular elements Elements kinds

Slide 56

Slide 56 text

@mathias Smi, packed Doubles, packed Regular elements, packed Smi, holey Doubles, holey Regular elements, holey

Slide 57

Slide 57 text

lattice

Slide 58

Slide 58 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS

Slide 59

Slide 59 text

@mathias Array.prototype.forEach PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Chrome 59

Slide 60

Slide 60 text

@mathias Array.prototype.forEach PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Chrome 61

Slide 61

Slide 61 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array.prototype.forEach Chrome 64

Slide 62

Slide 62 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array.prototype.map Chrome 64

Slide 63

Slide 63 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array.prototype.filter Chrome 64

Slide 64

Slide 64 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array.prototype.some Chrome 64

Slide 65

Slide 65 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array.prototype.every Chrome 64

Slide 66

Slide 66 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array.prototype.reduce Chrome 64

Slide 67

Slide 67 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array.prototype.reduceRight Chrome 64

Slide 68

Slide 68 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array#{find,findIndex} 1 Chrome 64

Slide 69

Slide 69 text

@mathias

Slide 70

Slide 70 text

@mathias PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS Array#{find,findIndex} Chrome 70

Slide 71

Slide 71 text

@mathias const array = new Array(3);


Slide 72

Slide 72 text

@mathias const array = new Array(3);
 index 0 1 2 value

Slide 73

Slide 73 text

@mathias const array = new Array(3);
 // HOLEY_SMI_ELEMENTS
 index 0 1 2 value

Slide 74

Slide 74 text

@mathias const array = new Array(3);
 // HOLEY_SMI_ELEMENTS
 array[0] = 'a';
 index 0 1 2 value 'a'

Slide 75

Slide 75 text

@mathias const array = new Array(3);
 // HOLEY_SMI_ELEMENTS
 array[0] = 'a';
 // HOLEY_ELEMENTS index 0 1 2 value 'a'

Slide 76

Slide 76 text

@mathias const array = new Array(3);
 // HOLEY_SMI_ELEMENTS
 array[0] = 'a';
 // HOLEY_ELEMENTS array[1] = 'b';
 index 0 1 2 value 'a' 'b'

Slide 77

Slide 77 text

@mathias const array = new Array(3);
 // HOLEY_SMI_ELEMENTS
 array[0] = 'a';
 // HOLEY_ELEMENTS array[1] = 'b';
 array[2] = 'c';
 index 0 1 2 value 'a' 'b' 'c' 2 now packed! 2

Slide 78

Slide 78 text

@mathias const array = new Array(3);
 // HOLEY_SMI_ELEMENTS
 array[0] = 'a';
 // HOLEY_ELEMENTS array[1] = 'b';
 array[2] = 'c';
 // HOLEY_ELEMENTS (still!) 2 now packed! 2 but it’s too late 3 index 0 1 2 value 'a' 'b' 'c'

Slide 79

Slide 79 text

@mathias const array = ['a', 'b', 'c'];
 // elements kind: PACKED_ELEMENTS


Slide 80

Slide 80 text

@mathias const array = ['a', 'b', 'c'];
 // elements kind: PACKED_ELEMENTS
 
 // …
 array.push(someValue);
 array.push(someOtherValue);

Slide 81

Slide 81 text

@mathias Avoid holes! #ProTip Avoid holes

Slide 82

Slide 82 text

@mathias for (let i = 0, item; (item = items[i]) != null; i++) {
 doSomething(item);
 }

Slide 83

Slide 83 text

@mathias for (let i = 0, item; (item = items[i]) != null; i++) {
 doSomething(item);
 }

Slide 84

Slide 84 text

@mathias for (let i = 0, item; (item = items[i]) != null; i++) {
 doSomething(item);
 } 
 for (let index = 0; index < items.length; index++) {
 const item = items[index]; doSomething(item);
 }

Slide 85

Slide 85 text

@mathias for (const item of items) {
 doSomething(item);
 }

Slide 86

Slide 86 text

@mathias items.forEach((item) => {
 doSomething(item);
 });

Slide 87

Slide 87 text

@mathias Avoid holes! #ProTip Avoid out-of-bounds reads

Slide 88

Slide 88 text

@mathias +0 === -0; // " true

Slide 89

Slide 89 text

@mathias +0 === -0; // " true Object.is(+0, -0); // " false

Slide 90

Slide 90 text

@mathias [3, 2, 1, +0];
 // PACKED_SMI_ELEMENTS


Slide 91

Slide 91 text

@mathias [3, 2, 1, +0];
 // PACKED_SMI_ELEMENTS
 [3, 2, 1, -0];
 // PACKED_DOUBLE_ELEMENTS


Slide 92

Slide 92 text

@mathias [3, 2, 1, +0];
 // PACKED_SMI_ELEMENTS
 [3, 2, 1, -0];
 // PACKED_DOUBLE_ELEMENTS
 [3, 2, 1, NaN, Infinity];
 // PACKED_DOUBLE_ELEMENTS

Slide 93

Slide 93 text

@mathias Avoid holes! #ProTip Avoid elements kind transitions

Slide 94

Slide 94 text

@mathias const arrayLike = {};
 arrayLike[0] = 'a';
 arrayLike[1] = 'b';
 arrayLike[2] = 'c';
 arrayLike.length = 3;

Slide 95

Slide 95 text

@mathias Array.prototype.forEach.call(arrayLike, (value, index) => {
 console.log(`${ index }: ${ value }`);
 });
 // This logs '0: a', then '1: b', and finally '2: c'.

Slide 96

Slide 96 text

@mathias const actualArray = Array.prototype.slice.call(arrayLike, 0);
 actualArray.forEach((value, index) => {
 console.log(`${ index }: ${ value }`);
 });
 // This logs '0: a', then '1: b', and finally '2: c'.

Slide 97

Slide 97 text

@mathias const logArgs = function() {
 Array.prototype.forEach.call(arguments, (value, index) => {
 console.log(`${ index }: ${ value }`);
 });
 };
 logArgs('a', 'b', 'c');
 // This logs '0: a', then '1: b', and finally '2: c'.

Slide 98

Slide 98 text

@mathias const logArgs = (...args) => {
 args.forEach((value, index) => {
 console.log(`${ index }: ${ value }`);
 });
 };
 logArgs('a', 'b', 'c');
 // This logs '0: a', then '1: b', and finally '2: c'.

Slide 99

Slide 99 text

@mathias Avoid holes! #ProTip Prefer arrays over array-like objects

Slide 100

Slide 100 text

@mathias $


Slide 101

Slide 101 text

@mathias $ rlwrap ~/projects/v8/out/x64.debug/d8


Slide 102

Slide 102 text

@mathias $ rlwrap ~/projects/v8/out/x64.debug/d8 --allow-natives-syntax


Slide 103

Slide 103 text

@mathias $ rlwrap ~/projects/v8/out/x64.debug/d8 --allow-natives-syntax
 V8 version 7.1.255 (candidate)
 d8>

Slide 104

Slide 104 text

@mathias $ rlwrap ~/projects/v8/out/x64.debug/d8 --allow-natives-syntax
 V8 version 7.1.255 (candidate)
 d8> const array = [1, 2,, 3];

Slide 105

Slide 105 text

@mathias $ rlwrap ~/projects/v8/out/x64.debug/d8 --allow-natives-syntax
 V8 version 7.1.255 (candidate)
 d8> const array = [1, 2,, 3]; %DebugPrint(array);


Slide 106

Slide 106 text

@mathias $ rlwrap ~/projects/v8/out/x64.debug/d8 --allow-natives-syntax
 V8 version 7.1.255 (candidate)
 d8> const array = [1, 2,, 3]; %DebugPrint(array);
 DebugPrint: 0x313389e0e551: [JSArray]
 - map = 0x3133e0582889 [FastProperties]
 - prototype = 0x313360387f81
 - elements = 0x313389e0e4c9 [HOLEY_SMI_ELEMENTS (COW)]
 - length = 4
 - properties = 0x3133dae02241 {
 #length: 0x31336c242839 (const accessor descriptor)
 }
 …

Slide 107

Slide 107 text

@mathias $ rlwrap ~/projects/v8/out/x64.debug/d8 --allow-natives-syntax
 V8 version 7.1.255 (candidate)
 d8> const array = [1, 2,, 3]; %DebugPrint(array);
 DebugPrint: 0x313389e0e551: [JSArray]
 - map = 0x3133e0582889 [FastProperties]
 - prototype = 0x313360387f81
 - elements = 0x313389e0e4c9 [HOLEY_SMI_ELEMENTS (COW)]
 - length = 4
 - properties = 0x3133dae02241 {
 #length: 0x31336c242839 (const accessor descriptor)
 }
 …

Slide 108

Slide 108 text

@mathias $ rlwrap ~/projects/v8/out/x64.debug/d8 --allow-natives-syntax
 V8 version 7.1.255 (candidate)
 d8> const array = [1, 2,, 3]; %DebugPrint(array);
 DebugPrint: 0x313389e0e551: [JSArray]
 - map = 0x3133e0582889 [FastProperties]
 - prototype = 0x313360387f81
 - elements = 0x313389e0e4c9 [HOLEY_SMI_ELEMENTS (COW)]
 - length = 4
 - properties = 0x3133dae02241 {
 #length: 0x31336c242839 (const accessor descriptor)
 }
 … 4

Slide 109

Slide 109 text

No content

Slide 110

Slide 110 text

Avoid holes. — J.K. Rowling

Slide 111

Slide 111 text

Avoid holes. Avoid out-of-bounds reads. — ancient Chinese proverb

Slide 112

Slide 112 text

Avoid holes. Avoid out-of-bounds reads. Avoid elements kind transitions. — Justin Bieber

Slide 113

Slide 113 text

Avoid holes. Avoid out-of-bounds reads. Avoid elements kind transitions. Prefer arrays over array-like objects. — Albert Einstein

Slide 114

Slide 114 text

Avoid holes. Avoid out-of-bounds reads. Avoid elements kind transitions. Prefer arrays over array-like objects. Eat your vegetables. — this slide, just now

Slide 115

Slide 115 text

@mathias One more thing…

Slide 116

Slide 116 text

@mathias const array = [
 someValue,
 someOtherValue,
 theLastValue
 ];

Slide 117

Slide 117 text

@mathias const array = [
 someValue,
 someOtherValue,
 /* more values */,
 theLastValue
 ];

Slide 118

Slide 118 text

@mathias const array = new Array(9001);
 // …
 array[0] = someValue;
 array[1] = someOtherValue;
 // …
 array[9000] = theLastValue;

Slide 119

Slide 119 text

@mathias const array = new Array(9001);
 // " an array with 9001 holes :'(

Slide 120

Slide 120 text

@mathias new Array(n) + allows engines to preallocate space for n elements + optimizes array creation - creates a holey array - slower array operations (compared to packed arrays)

Slide 121

Slide 121 text

@mathias const array = [];
 // …
 array.push(someValue);
 array.push(someOtherValue);
 // …
 array.push(theLastValue);

Slide 122

Slide 122 text

@mathias + creates a packed array (never has any holes in it) + optimizes array operations - engines need to reallocate space as the array grows - slower array creation array = []; array.push(x);

Slide 123

Slide 123 text

Use new Array(n) to optimize the creation of the array by pre-allocating the correct number of elements.

Slide 124

Slide 124 text

Avoid new Array(n) to optimize operations on the array by avoiding holeyness.

Slide 125

Slide 125 text

Write modern, idiomatic JavaScript, and let the JavaScript engine worry about making it fast.

Slide 126

Slide 126 text

mths.be/v8ek

Slide 127

Slide 127 text

Thank you! @mathias // @v8js mths.be/v8ek