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
200
1
Share
V8 internals for JavaScript developers
Google Experts Summit 2017
Mathias Bynens
September 04, 2017
More Decks by Mathias Bynens
See All by Mathias Bynens
V8 internals for JavaScript developers @ Fronteers 2018
mathiasbynens
3
530
V8 internals for JavaScript developers
mathiasbynens
2
1.1k
What’s new in ES2018?
mathiasbynens
2
160
Preventing timing attacks on the web @ Fronteers Jam 2016
mathiasbynens
4
280
Front-End Performance: The Dark Side @ ColdFront Conference 2016
mathiasbynens
1
520
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
1.2k
3.14 things I didn’t know about CSS @ CSS Day 2014
mathiasbynens
70
29k
Other Decks in Technology
See All in Technology
マルチモーダル非構造データとの闘い
shibuiwilliam
1
130
How to install a gem
indirect
0
2k
昔話で振り返るAWSの歩み ~S3誕生から20年、クラウドはどう進化したのか~
nrinetcom
PRO
0
130
15年メンテしてきたdotfilesから開発トレンドを振り返る 2011 - 2026
giginet
PRO
2
260
Oracle AI Database@AWS:サービス概要のご紹介
oracle4engineer
PRO
3
2.1k
「できない」のアウトプット 同人誌『精神を壊してからの』シリーズ出版を 通して得られたこと
comi190327
3
520
The essence of decision-making lies in primary data
kaminashi
0
220
Navigation APIと見るSvelteKitのWeb標準志向
yamanoku
2
140
開発チームとQAエンジニアの新しい協業モデル -年末調整開発チームで実践する【QAリード施策】-
kaomi_wombat
0
280
Sansanの認証基盤を支えるアーキテクチャとその振り返り
sansantech
PRO
1
140
開発チームとQAエンジニアの新しい協業モデル -年末調整開発チームで実践する【QAリード施策】-
qa
0
660
Microsoft Fabricで考える非構造データのAI活用
ryomaru0825
0
590
Featured
See All Featured
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.8k
Optimizing for Happiness
mojombo
378
71k
A Soul's Torment
seathinner
5
2.6k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
120
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.8k
GraphQLとの向き合い方2022年版
quramy
50
14k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
The Curious Case for Waylosing
cassininazir
0
280
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
620
4 Signs Your Business is Dying
shpigford
187
22k
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