Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
V8 internals for JavaScript developers
Search
Mathias Bynens
September 04, 2017
Technology
1
160
V8 internals for JavaScript developers
Google Experts Summit 2017
Mathias Bynens
September 04, 2017
Tweet
Share
More Decks by Mathias Bynens
See All by Mathias Bynens
V8 internals for JavaScript developers @ Fronteers 2018
mathiasbynens
3
490
V8 internals for JavaScript developers
mathiasbynens
2
870
What’s new in ES2018?
mathiasbynens
2
130
Preventing timing attacks on the web @ Fronteers Jam 2016
mathiasbynens
4
240
Front-End Performance: The Dark Side @ ColdFront Conference 2016
mathiasbynens
1
410
Hacking with Unicode in 2016
mathiasbynens
15
15k
Front-End Performance: The Dark Side @ Fronteers Spring Conference 2016
mathiasbynens
16
57k
3.14 things I didn’t know about CSS @ CSSConf.asia 2015
mathiasbynens
4
1k
3.14 things I didn’t know about CSS @ CSS Day 2014
mathiasbynens
70
29k
Other Decks in Technology
See All in Technology
為什麼我們需要 Observability?
marcustung
0
200
技術書典18結果報告
mutsumix
2
190
kintone開発組織のDevOpsへの移り変わりと実践
ueokande
1
170
組織とセキュリティ文化と、自分の一歩
maimyyym
3
1.2k
会社員しながら本を書いてきた知見の共有
sat
PRO
3
700
面接を通過するためにやってて良かったこと3選
sansantech
PRO
0
140
Javaアプリケーションの配布とパッケージング / Distribution and packaging of Java applications
hogelog
1
410
データプレーンプログラミングとは? DPU&スイッチASICの開発経験から語る
ebiken
PRO
1
270
CSSDay, Amsterdam
brucel
0
160
コードの考古学 〜労務システムから発掘した成長の糧〜
kenta_smarthr
1
1.3k
Eight Engineering Unit 紹介資料
sansan33
PRO
0
3.2k
Java で学ぶ 代数的データ型
ysknsid25
1
920
Featured
See All Featured
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
750
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
5.8k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.2k
Making the Leap to Tech Lead
cromwellryan
134
9.3k
Visualization
eitanlees
146
16k
Raft: Consensus for Rubyists
vanstee
137
7k
Testing 201, or: Great Expectations
jmmastey
42
7.5k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
32
2.3k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
15
890
Transcript
None
V8 internals for JavaScript developers @mathias
Elements kinds in V8
const array = [1, 2, 3];
const array = [1, 2, 3]; // elements kind: PACKED_SMI_ELEMENTS
const array = [1, 2, 3]; // elements kind: PACKED_SMI_ELEMENTS
array.push(4.56);
const array = [1, 2, 3]; // elements kind: PACKED_SMI_ELEMENTS
array.push(4.56); // elements kind: PACKED_DOUBLE_ELEMENTS
const array = [1, 2, 3]; // elements kind: PACKED_SMI_ELEMENTS
array.push(4.56); // elements kind: PACKED_DOUBLE_ELEMENTS array.push('x');
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
Smi Doubles Regular elements Elements kinds
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
array.length; // 5 index 0 1 2 3 4 value
1 2 3 4.56 'x'
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
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
array[8]; // → ??? index 0 1 2 3 4
5 6 7 8 9 value 1 2 3 4.56 'x' 1
array[8]; // → ??? ❌ index 0 1 2 3
4 5 6 7 8 9 value 1 2 3 4.56 'x' 1
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
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
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
index 0 1 2 3 4 5 6 7 8
9 value 1 2 3 4.56 'x' 1 array[8]; // → ??? ❌ 8 >= 0 && 8 < array.length; // bounds check // → true ❌ hasOwnProperty(array, '8'); // → false ❌
array[8]; // → ??? ❌ 8 >= 0 && 8
< array.length; // bounds check // → true ❌ hasOwnProperty(array, '8'); // → false ❌ hasOwnProperty(Array.prototype, '8'); // → false
array[8]; // → ??? ❌ 8 >= 0 && 8
< array.length; // bounds check // → true ❌ hasOwnProperty(array, '8'); // → false ❌ hasOwnProperty(Array.prototype, '8'); // → false ❌
array[8]; // → ??? ❌ 8 >= 0 && 8
< array.length; // bounds check // → true ❌ hasOwnProperty(array, '8'); // → false ❌ hasOwnProperty(Array.prototype, '8'); // → false ❌ hasOwnProperty(Object.prototype, '8'); // → false
array[8]; // → ??? ❌ 8 >= 0 && 8
< array.length; // bounds check // → true ❌ hasOwnProperty(array, '8'); // → false ❌ hasOwnProperty(Array.prototype, '8'); // → false ❌ hasOwnProperty(Object.prototype, '8'); // → false ✅
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 ✅
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 ✅
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 ✅
array[0]; // → ???
array[0]; // → ??? ❌
array[0]; // → ??? ❌ 0 >= 0 && 0
< array.length; // bounds check // → true
array[0]; // → ??? ❌ 0 >= 0 && 0
< array.length; // bounds check // → true ❌
array[0]; // → ??? ❌ 0 >= 0 && 0
< array.length; // bounds check // → true ❌ hasOwnProperty(array, '0'); // → true
array[0]; // → ??? ❌ 0 >= 0 && 0
< array.length; // bounds check // → true ❌ hasOwnProperty(array, '0'); // → true ✅
array[0]; // → 1 ✅ 0 >= 0 && 0
< array.length; // bounds check // → true hasOwnProperty(array, '0'); // → true ✅
PACKED > HOLEY
PACKED > HOLEY
Smi Doubles Regular elements Elements kinds
Smi, packed Doubles, packed Regular elements, packed Smi, holey Doubles,
holey Regular elements, holey
lattice
PACKED_SMI_ELEMENTS HOLEY_SMI_ELEMENTS PACKED_DOUBLE_ELEMENTS HOLEY_DOUBLE_ELEMENTS PACKED_ELEMENTS HOLEY_ELEMENTS
const array = new Array(3);
const array = new Array(3); index 0 1 2 value
const array = new Array(3); // HOLEY_SMI_ELEMENTS index 0 1
2 value
const array = new Array(3); // HOLEY_SMI_ELEMENTS array[0] = 'a';
index 0 1 2 value 'a'
const array = new Array(3); // HOLEY_SMI_ELEMENTS array[0] = 'a';
// HOLEY_ELEMENTS index 0 1 2 value 'a'
const array = new Array(3); // HOLEY_SMI_ELEMENTS array[0] = 'a';
// HOLEY_ELEMENTS array[1] = 'b'; index 0 1 2 value 'a' 'b'
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' now packed!
const array = new Array(3); // HOLEY_SMI_ELEMENTS array[0] = 'a';
// HOLEY_ELEMENTS array[1] = 'b'; array[2] = 'c'; // HOLEY_ELEMENTS (still!) now packed! but it’s too late index 0 1 2 value 'a' 'b' 'c'
const array = ['a', 'b', 'c']; // elements kind: PACKED_ELEMENTS
const array = ['a', 'b', 'c']; // elements kind: PACKED_ELEMENTS
// … array.push(someValue); array.push(someOtherValue);
Avoid holes! #ProTip Avoid holes
for (let i = 0, item; (item = items[i]) !=
null; i++) { doSomething(item); }
for (let i = 0, item; (item = items[i]) !=
null; i++) { doSomething(item); }
for (let i = 0, item; (item = items[i]) !=
null; i++) { doSomething(item); } for (let index = 0; index < items.length; index++) { doSomething(item); }
for (const item of items) { doSomething(item); }
Avoid holes! #ProTip Avoid out-of-bounds reads
[3, 2, 1, +0]; // PACKED_SMI_ELEMENTS
[3, 2, 1, +0]; // PACKED_SMI_ELEMENTS [3, 2, 1, -0];
// PACKED_DOUBLE_ELEMENTS
[3, 2, 1, +0]; // PACKED_SMI_ELEMENTS [3, 2, 1, -0];
// PACKED_DOUBLE_ELEMENTS [3, 2, 1, NaN, Infinity]; // PACKED_DOUBLE_ELEMENTS
Avoid holes! #ProTip Avoid elements kind transitions
const arrayLike = {}; arrayLike[0] = 'a'; arrayLike[1] = 'b';
arrayLike[2] = 'c'; arrayLike.length = 3;
Array.prototype.forEach.call(arrayLike, (value, index) => { console.log(`${ index }: ${ value
}`); }); // This logs '0: a', then '1: b', and finally '2: c'.
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'.
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'.
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'.
Avoid holes! #ProTip Prefer arrays over array-like objects
$
$ rlwrap ~/projects/v8/out.gn/x64.debug/d8
$ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax
$ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax V8 version 6.2.0 (candidate) d8>
$ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax V8 version 6.2.0 (candidate) d8> const
array = [1, 2, 3];
$ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax V8 version 6.2.0 (candidate) d8> const
array = [1, 2, 3]; %DebugPrint(array);
$ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax V8 version 6.2.0 (candidate) d8> const
array = [1, 2, 3]; %DebugPrint(array); DebugPrint: 0x313389e0e551: [JSArray] - map = 0x3133e0582889 [FastProperties] - prototype = 0x313360387f81 - elements = 0x313389e0e4c9 <FixedArray[3]> [PACKED_SMI_ELEMENTS (COW)] - length = 3 - properties = 0x3133dae02241 <FixedArray[0]> { #length: 0x31336c242839 <AccessorInfo> (const accessor descriptor) } …
$ rlwrap ~/projects/v8/out.gn/x64.debug/d8 --allow-natives-syntax V8 version 6.2.0 (candidate) d8> const
array = [1, 2, 3]; %DebugPrint(array); DebugPrint: 0x313389e0e551: [JSArray] - map = 0x3133e0582889 [FastProperties] - prototype = 0x313360387f81 - elements = 0x313389e0e4c9 <FixedArray[3]> [PACKED_SMI_ELEMENTS (COW)] - length = 3 - properties = 0x3133dae02241 <FixedArray[0]> { #length: 0x31336c242839 <AccessorInfo> (const accessor descriptor) } …
None
Avoid holes. — J.K. Rowling
Avoid holes. Avoid out-of-bounds reads. — ancient Chinese proverb
Avoid holes. Avoid out-of-bounds reads. Avoid elements kind transitions. —
Justin Bieber
Avoid holes. Avoid out-of-bounds reads. Avoid elements kind transitions. Prefer
arrays over array-like objects. — Albert Einstein
Avoid holes. Avoid out-of-bounds reads. Avoid elements kind transitions. Prefer
arrays over array-like objects. Eat your vegetables. — this slide, just now
Thank you! @mathias