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
0
110
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
2
440
V8 internals for JavaScript developers
mathiasbynens
1
690
What’s new in ES2018?
mathiasbynens
1
89
Preventing timing attacks on the web @ Fronteers Jam 2016
mathiasbynens
3
190
Front-End Performance: The Dark Side @ ColdFront Conference 2016
mathiasbynens
0
280
Hacking with Unicode in 2016
mathiasbynens
14
14k
Front-End Performance: The Dark Side @ Fronteers Spring Conference 2016
mathiasbynens
15
57k
3.14 things I didn’t know about CSS @ CSSConf.asia 2015
mathiasbynens
3
820
3.14 things I didn’t know about CSS @ CSS Day 2014
mathiasbynens
69
29k
Other Decks in Technology
See All in Technology
プロンプトエンジニアリングでがんばらない-Agentic Workflow へ-近藤憲児
kenjikondobai
6
1.2k
開発パフォーマンスを最大化するための開発体制
ham0215
7
1.1k
The AI Revolution Will Not Be Monopolized: Behind the scenes
inesmontani
PRO
1
150
Azure犬駆動開発の記録/GlobalAzureFukuoka2024_20240420
nina01
1
240
Babylon.jsと色々なものを組み合わせる:ブラウザのAPIやガジェットや2D描画ライブラリなど / Babylon.js 勉強会 vol.3
you
PRO
0
160
成長をサポートするピープルマネジメントのやり方
sioncojp
7
780
アクセス制御にまつわる改善 / Improving access control
itkq
0
590
Azure Container Apps + Bicep 〜 こんな感じで運用しています
kaz29
3
620
非同期推論システムによるコスト削減と信頼性向上
koki_nishihara
1
360
今年のRubyKaigiはProfiler Year🤘
osyoyu
0
320
Grafana x PagerDuty Better Together
jacopen
1
250
AOAI をきっかけに 社内の Azure 管理を見直した話
recruitengineers
PRO
1
440
Featured
See All Featured
10 Git Anti Patterns You Should be Aware of
lemiorhan
649
58k
Code Review Best Practice
trishagee
56
15k
For a Future-Friendly Web
brad_frost
172
9k
[RailsConf 2023] Rails as a piece of cake
palkan
27
4k
The Illustrated Children's Guide to Kubernetes
chrisshort
32
46k
How GitHub Uses GitHub to Build GitHub
holman
468
290k
What's new in Ruby 2.0
geeforr
337
31k
Scaling GitHub
holman
457
140k
A designer walks into a library…
pauljervisheath
201
23k
Robots, Beer and Maslow
schacon
PRO
155
7.9k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
41
4.4k
How to name files
jennybc
65
93k
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