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
Source to Binary - journey of V8 javascript engine
Search
Taketoshi Aono(青野健利 a.k.a brn)
November 25, 2017
Programming
13
13k
Source to Binary - journey of V8 javascript engine
V8 javascript engineについて
パーサー、AST、Ignition/TurboFan、最適化周り等
Taketoshi Aono(青野健利 a.k.a brn)
November 25, 2017
Tweet
Share
More Decks by Taketoshi Aono(青野健利 a.k.a brn)
See All by Taketoshi Aono(青野健利 a.k.a brn)
document.write再考
brn
6
2.9k
Parsing Javascript
brn
12
9k
JSON & Object Tips
brn
1
410
CA 1Day Youth Bootcamp for Frontend LT
brn
0
820
Modern TypeScript
brn
2
750
javascript - behind the scene
brn
3
690
tc39 proposals
brn
0
790
プロダクト開発とTypeScript
brn
8
2.8k
React-Springでリッチなアニメーション
brn
1
620
Other Decks in Programming
See All in Programming
わたしの星のままで一番星になる ~ 出産を機にSIerからEC事業会社に転職した話 ~
kimura_m_29
0
180
The Efficiency Paradox and How to Save Yourself and the World
hollycummins
1
440
As an Engineers, let's build the CRM system via LINE Official Account 2.0
clonn
1
670
Keeping it Ruby: Why Your Product Needs a Ruby SDK - RubyWorld 2024
envek
0
180
LLM Supervised Fine-tuningの理論と実践
datanalyticslabo
3
890
採用事例の少ないSvelteを選んだ理由と それを正解にするためにやっていること
oekazuma
2
1k
return文におけるstd::moveについて
onihusube
1
610
KMP와 kotlinx.rpc로 서버와 클라이언트 동기화
kwakeuijin
0
130
ゆるやかにgolangci-lintのルールを強くする / Kyoto.go #56
utgwkk
1
350
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
610
「Chatwork」Android版アプリを 支える単体テストの現在
okuzawats
0
180
Fibonacci Function Gallery - Part 1
philipschwarz
PRO
0
200
Featured
See All Featured
XXLCSS - How to scale CSS and keep your sanity
sugarenia
247
1.3M
Bash Introduction
62gerente
608
210k
Six Lessons from altMBA
skipperchong
27
3.5k
How to train your dragon (web standard)
notwaldorf
88
5.7k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
26
1.9k
The Pragmatic Product Professional
lauravandoore
32
6.3k
GitHub's CSS Performance
jonrohan
1030
460k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
Thoughts on Productivity
jonyablonski
67
4.4k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
Transcript
None
Name @brn (ꫬꅿ⨳ⵃ) Occupation ؿٗٝزؒٝسؒٝآص،٥ط؎ذ؍ـؒٝآص، Company Cyberagent ،سذؙأةآؔ AI Messenger
Blog http://abcdef.gets.b6n.ch/ Twitter https://twitter.com/brn227 GitHub https://github.com/brn
Agenda • What is V8? • Execution flow of V8
• Parsing • Abstract Syntax Tree • Ignition – BytecodeInterpreter • CodeStubAssembler • Builtins / Runtime • Optimization / Hidden Class / Inline Caching • TurboFan / Deoptimization
What is V8? V8הכGoogle爡ָ㹋鄲׃javascriptؒٝآٝדծ Google Chrome/Node.JSךjavascriptؒٝآٝח䱰欽ׁגְתׅկ
Execution Flow
Source AST Bytecode Graph Assembly first time hot code
Parsing
Basic parsing V8כا٦أ؝٦سػ٦أ׃גASTח㢌䳔ׅ ASTהכAbstractSyntaxTreeך殛獥 䬄韋圓俑加הㄎל Parsing
if (x) { x = 100 }
IF CONDITION THEN BLOCK EXPRESSION STATEMENT ASSIGN VAR PROXY (X)
LITERAL (100) if (x) { x = 100
Problems
Parsing all functions - Slow ׅץגך؝٦س剑ⴱחػ٦أׅךכ֮ת״׃ֻזְ ׃ػ٦أ׃؝٦سָ㹋遤ׁזֽל䠐ָזְ Parsing
Split parsing phase ػ٦أ鹼䒀׃ג遤ֲחծػ٦أ✳媮ꥡחⴓֽ Parsing
PreParsing ✲חׅץגךꟼ侧ךٖ؎،ؐز ػ٦أ׃גֶֻ Parsing
function x(a, b) { return a + b; } FUNCTION(X)
parameter-count: 2 start-position: 1 end-position: 34 use-super-property: false …
// when x is called x() FUNCTION NAME (x) RETURN
LITERAL(1)
Lazy Parsing V8כ㹋ꥷח״ןׁתדػ٦أ鹼䒀ׅ ꟼ侧כㄎן⳿ׁגⴱג؝ٝػ؎ׁٕ Parsing
More About https://docs.google.com/presentation/d/1b- ALt6W01nIxutFVFmXMOyd_6ou_6qqP6S0Prmb1iDs/present? slide=id.p Parsing
Abstract Syntax Tree
AST Rewriting Parserח״ג欰䧭ׁAST㢌䕎ׅ ְֻאַ稱➜ AbstractSyntaxTree
Subsclass constructor return 竰䪫׃ؙٓأך؝ٝأزؙٓة㢌䕎ׅ 崢欰ؙٓأך؝ٝأزؙٓةד䒭return׃גְ儗כծ 3갪怴皾㶨ח㢌䳔׃גծ 䒭ך穠卓ָundefined㜥さחכthis䨱ׅկ AbstractSyntaxTree
constructor() {! super();! return expr! }! ! constructor() {! super();!
var tmp;! return (temp = expr) === undefined?! this: temp;! }!
for (let/const/var in/of e) for-in/ofךⴱ劍⻉דconst/let⢪ֲחծⰋ⡤ـٗحؙד㔲 㢌侧㹑鎉ׅկ AbstractSyntaxTree
for (const key of e) {! ...! }!
{! var temp;! for (temp of e) {! const x
= temp;! ...! }! let x! }!
Spread operator doהfor-ofח縧ֹ䳔ִגⳢ椚 AbstractSyntaxTree
const x = [1,2,3];! const y = [...x];!
do {! $R = [];! for ($i of x)! %AppendElement($R,
$i);! $R! }!
Ecmascript? – Binary AST ➙תד鋅״ֲחASTך؟؎ؤכ穠圓㣐ְֹךדծ 㖇簭ׅ䲿周 Parsing
Ignition
Bytecode Interpreter V8כ欰䧭׃AST1~4byteךBytecodeח㢌䳔׃גַ㹋遤ׅ Ignition
How does it work? ♧אך،ُؗيٖ٦ة٦⪒ִٖآأةك٦أד⹛⡲ׅ؎ٝ ة٦فٔة Ignition
Pseudo javascript code Javascriptד圓鸡垷⦺ׅהֿך״ֲחז Ignition
const Bytecodes = [0,1,2,3,4,5];! let index = 0;! function dispatch(next)
{BytecodeHandlers[next] ();}! const BytecodeHandlers = [! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! ]! dispatch(Bytecodes[index++]);!
How to create bytecode? BytecodeכASTַAstVisitorⵃ欽׃ג欰䧭ׁ AstVisitorכVistorػة٦ٝⵃ欽׃ؙٓأדծ AST帾ׁ⮚⯓䱱稊׃זָ㼎䘔ׅ؝٦ٕغحؙꟼ侧ㄎן⳿ ׅ Ignition
BytecodeArray 欰䧭ׁBytecodeכBytecodeArrayח呓秛ׁ BytecodeArrayכꟼ侧⽃⡘ד㶷㖈ׅ Ignition
Dispatch Table Stub(Machine Code) BytecodeArray Dispatch Tableから対応するHandlerを取り出して実行 0 1 3
4 5 6 7 8 5 6 1
InterpreterEntryTrampoline 剑穄涸ח欰䧭ׁBytecodeכInterpreterEntrynTrampolineה ㄎלBuiltin؝٦سַ㹋遤ׁ InterpreterEntryTrampolineכAssemblyח؝ٝػ؎ׁٕծ 鸐䌢ךCךꟼ侧הㄎן⳿ׁ Ignition
InterpreterEntryTrampoline(Assembly) Script::Run Call as C function Ignition DispatchTable Dispatch First
bytecode
Ignition Handler ⯓玎亻⡂؝٦سד爙׃BytecodeHandlersכV8דכ Ignition Handlerהㄎלגְ Ignition HandlerכCodeStubAssemblerהְֲDSLד鎸鶢ׁג ְ Iginition
CodeStub Assember
What is CodeStubAssmber? CodeStubAssembler(CSA)כ؝٦س欰䧭ؚٓؿ欰䧭ח䬄韋⻉׃ V8ⰻ鿇ךDSL 㹋遤✮㹀Node穈甧גֽדծCodeGeneratorח״גぐ ،٦ؗذؙثٍぢֽך؝٦سָ欰䧭ׁծ،إٝـٔ鎉铂 ְְ倜ח剅ֻ䗳銲ָזְ CodeStubAssembler
IGNITION_HANDLER(JumpIfToBooleanFalse, InterpreterAssembler) {! Node* value = GetAccumulator();! // Accumulatorの値を取得! Node*
relative_jump = BytecodeOperandUImmWord(0);! // 引数のoperandを取得! Label if_true(this), if_false(this);! BranchIfToBooleanIsTrue(value, &if_true, &if_false);! // valueがtrueならif_true、falseならif_false! Bind(&if_true);! Dispatch();! Bind(&if_false);! // operandのbytecodeまでjump! Jump(relative_jump);! }!
Graph based DSL ֿךCodeStubAssemblerךֶַ־ד㹋ꥷך،٦ؗذؙثٍぢֽ ך،إٝـٓ擾濼׃גְזֻג֮ח؝٦س鷄⸇ֿׅ הָ㺁僒חזծ ת〳铣䚍ꬊ䌢ח넝ֻזגְ CodeStubAssembler
Dispatch Table 00 01 02 04 08 0f 10 10
Node Node Node Operator Operator IGNITION_HANDLER Stub (Mahine Code Fragment) グラフからコードを生成 生成したコードを、 DispatchTableの対応する バイトコードのインデックスへ 登録 Assemble
Assembler 㹋ꥷחぐ،٦ؗذؙثٍぢֽך؝٦س⳿⸂ׅ X64ぢֽךjmpص٦ٌصحؙ׳הֽ鋖ְג״ֲ CodeStubAssembler
void Assembler::jmp(! Handle<Code> target,! RelocInfo::Mode rmode! ) {! EnsureSpace ensure_space(this);!
// 1110 1001 #32-bit disp.! // ここでメモリ上にアセンブラを書き出す! emit(0xE9);! emit_code_target(target, rmode);! }!
Where to use BuiltinsכAssemblerؙٓأⵃ欽׃גぐ،٦ؗذؙثٍ嫣ך Stubָ鎸鶢ׁגְ ♧鿇CSA⢪ֲ皘䨽֮(*-gen.cc) Ignition HandlerכקרⰋגָCSAד鎸鶢ׁגְ CodeStubAssembler
Builtins & Runtime
Builtins BuiltinsכV8ך饯⹛儗ח؝ٝػ؎ׁٕ،إٝـٓך؝٦س晙 ꟼ侧ך״ֲחCallBuiltin穗歋דㄎן⳿ׁ Stubהㄎל 㹋遤儗ך剑黝⻉כ遤זְ Builtins & Runtime
Runtime RuntimeכBuiltinsװך➭ך،إٝـٓ؝٦سַㄎן⳿ֿׅ הָדֹC++ך؝٦س Javascriptך⚅歲ַC++ך⚅歲אזּ؝٦س晙 ずֻׄ㹋遤儗ך剑黝⻉כ遤זְ Builtins & Runtime
Hidden Class
What is Hidden Class? Javascriptחכ㘗ָזְךדؔـآؙؑز鋉㹀ׅךָ搀ְկ ךծV8כؔـآؙؑزך圓鸡荈⡤㘗ך״ֲח䪔גְկ ֿHidden Classהㄎע Hidden Class
• Hidden Class const point1 = {x: 0, y: 0};!
const point2 = {x: 0, y: 0};! Map FixedArray [ {x: {offset: 0}}, {y: {offset: 1}} ]
Map הִJavascript♳דכⴽךؔـآؙؑزד֮גծ ずׄ圓鸡䭯גְלずׄHidden ClassⰟ剣ׅ ׃גֿךؔـآؙؑزך酅ח֮圓鸡Mapהㄎע Hidden Class
const pointA = {x: 0, y: 0};! const pointB =
{x: 0, y: 0};! // pointA.Map === pointB.Map;! ! const pointC = {y: 0, x: 0};! // pointA.Map !== pointC.Map! ! const point3D = {x: 0, y: 0, z: 0};! // point3D.Map !== pointA.Map!
class PointA {! constructor() {! this.x = 0;! this.y =
0;! }! }! const pointAInstance = new PointA();! ! class PointB {! constructor() {! this.y = 0;! this.x = 0;! }! }! const pointBInstance = new PointB();! // PointAInstance.Map !== PointBInstance.Map!
Layout Mapؔـآؙؑزכַז⿑㺘חفٗػذ؍ךoffsetثؑحؙ ׅծٔذٕٓךⴱ劍⻉갫٥فٗػذ؍ךⴱ劍⻉갫٥فٗػ ذ؍ך侧ָ麩ֲהⴽךMapָⶴ䔲ג Hidden Class
Map Transition ׃ַ׃فٗػذ؍ך㟓幾ָ걼籕ח饯ֿJavascriptדծ嫣㔐Map 欰䧭ׅה؝أزָ搀鋔דֹזְךדכ V8כفٗػذ؍ך㟓幾ָ֮㜥さחכMapⰟ剣׃זָծ 㟓ִ鿇ⴓךך倜׃ְMap欰䧭ׅ ֿMap Transitionהㄎע Hidden Class
function Point(x, y) { this.x = x; this.y = y;
} Map FixedArray [ {x: {offset: 0}}, {y: {offset: 1}}, ] var x = new Point(1, 1); x.z = 1; Map FixedArray [ {z: {offset: 2}} ] transition {z: transi>on(address)}
What's Happening? Hidden Classָ֮ה⡦ָ㴍׃ְַהְֲהծ ؔـآؙؑزךفٗػذ؍،ؙإأװ㘗ךثؑحؙ״넝鸞חծ ״㸜Ⰻח遤ִ״ֲחז Hidden Class
Inline Caching
What is Inline Caching فٗػذ؍،ؙإأך넝鸞⻉ךח麓ך،ؙإأٍؗح ءُ׃גֶֻ Inline Caching
function x(obj) {! return obj.x + obj.y;! }! ! x({x:
0, y: 0});! x({x: 1, y: 1});! x({x: 2, y: 2});!
Search Property ؔـآؙؑزַفٗػذ؍䱱ׅחכծ HashMapװFixedArrayַفٗػذ؍ٗ٦سׅ ׃ַ׃嫣㔐遤ֲךכꬊ䌢ח鹼ְ Inline Caching
Reduce Property Access ֿך⢽דכxהyפך،ؙإأָずׄMap䭯אؔـآؙؑزח㼎 ׃ג⡦䏝㹋遤ׁגְ ׅדחobjכ{x, y}ךMapהַגְךד֮לծ 䔲搫ًٌٖٔ؎،ؐزַגְךדծ湫䱸offset䭷㹀׃ ג،ؙإأ׃קֲָ傍ְ Inline
Caching
Cache זךדծ暴㹀ךMapך،ؙإأ鎸䥉׃גֶֻ ֮فٗػذ؍פ،ؙإأ׃㜥さծךMapؔـآؙؑز鎸 䥉ֿׅהד2㔐湡⟃꣬ךفٗػذ؍،ؙإأָ넝鸞⻉ׁ Inline Caching
x({x: 0, y: 0});! // uninitialized! x({x: 1, y: 1});!
// stub_call! x({x: 2, y: 2});! // found ic! x({x: 1, y: 1, z: 1})! // load ic miss! x({x: 1, y: 1, foo() {}});! // load ic miss!
Cache Miss ׃ծMapָ㢌⻉׃㜥さחכ䔲搫CacheךMissؼحزָ饯ֹ ךדծתفٗػذ؍ٗ٦س׃ג倜ח鎸䥉׃湫ׅ ׃ׅץג鎸ꐮׅךכ♶〳腉זךדծ4אתדMapؔـ آؙؑز鎸ꐮׅ Inline Cache
Cahce State ٍؗحءُך朐䡾כ⟃♴ך״ֲח鼂獳ׅ PreMonomorphic Monomorphic Polymorphic Megamorphic Inline Caching
Pre Monomorphic ؝٦س♳ך鿪さד劢ⴱ劍ַוֲַⴻ㹀ׅח㶷㖈ׅךדծ ֮ת䠐כזְ Inline Caching
Monomorphic ⽃♧ךMapפך،ؙإأ׃ַ㶷㖈׃זְ朐䡾 椚䟝涸ז朐䡾ה鎉ִ Inline Caching
Polymorphic MapָFixedArrayח呓秛ׁגֶ醱侧ךMapַ嗚稊׃ג فٗػذ؍،ؙإأ㹋遤ׅ ٍؗحءُ荈⡤כׁגְךדת넝鸞 Inline Caching
Megamorphic ֮תחMissָ㢳ְךדծMapך鎸ꐮ⨡姺׃朐䡾 איחStubַGetPropertyㄎן⳿׃גفٗػذ؍《䖤ׅ 剑鹼ְ朐䡾 Inline Caching
Optimization
Hot or Small 䌢ח؝٦س剑黝⻉ׅךכꬊ䌢ח搀꼽 ⟃♴ך勴⟝ח䔲גכת؝٦س剑黝⻉ׅ • (ꟼ侧ךغ؎ز؝٦سꞿ/ 1200) + 2ך㔐侧ꟼ侧ָㄎן⳿ׁ
גְ • ꟼ侧ָ㼭ְׁ(غ؎ز؝٦سךꞿָׁ90劢弫) Optimization
Optimization Budget غ؎ز؝٦س㹋遤⚥חぐꟼ侧חכ剑黝⻉✮皾ָⶴ䮶גֶծ ך⦼ָ0ⴖה؝٦س剑黝⻉⦪酡הז Optimization
For loop ٕ٦فדכJumpLoopהְֲغ؎ز؝٦سָ⳿⸂ׁ ֿךJumpLoopך⚥ד䨱⯓ך،سٖأ⦼ךoffsetꅾח׃גծ ⯓玎ך✮皾ַ⦼䒷ֹծָ0ⶴٕ٦فⰻך剑黝⻉ ָ涪欰ׅ Optimization
function id(v) {return v;}! function x(v) {! for (var i
= 0; i < 10000; i++) {! id(v + i);! }! }! x(1);!
0x1bb9e5e2935e LdaSmi.Wide [1000] 0x1bb9e5e2937e JumpLoop [32], [0] (0x1bb9e5e2935e @ 4)
Bytecode length = 100 if (budget –= 100 < 0) { OptimizeAndOSR(); }
OSR - OnStackReplacement ؝ٝػ؎ׁٕגغ؎ز؝٦سַ堣唒铂ח㢌䳔ׁ؝٦سכծ ٕ٦فך鷿⚥ד굲ן⯓ָ剅ֹ䳔ִג倜ז堣唒铂ך؝٦سָ 㹋遤ׁ Optimization
For function ꟼ侧ך㜥さכReturnغ؎ز؝٦سָ䗳׆欰䧭ׁ ֿדInterruptָ遤ג✮皾ךثؑحָؙ涪欰ׅ Optimization
function x() {! const x = 1 + 1;! }!
x();!
0x3d22953a917a StackCheck 0x3d22953a9180 Return Bytecode length 30 if (budget -=
30 < 0) { OptimizeConcurrent(); }
Concurrent Compilation ꟼ侧剑黝⻉ׅ㜥さכծ⚛؝ٝػ؎ָٕꬊず劍ח遤 ך如㔐⟃꣬ךꟼ侧ㄎן⳿׃ָ䗳׆剑黝⻉ׁגְֽד כזְ Optimization
CompilationQueue CompilationJob CompilationJob CompilationJob Hot Function Bytecode Called Hot Function(Queued)
Bytecode Called Hot Function(Queued) Bytecode Called Optimized Function Assembly Called
const x = x => x;! const y = ()
=> {! for (let i = 0; i < 1000; i++) {! x(i);! }! ! for (let i = 0; i < 1000; i++) {! x(i);! }! };! y();!
0x13b567fa924e LdaSmi.Wide [1000] 0x13b567fa9268 JumpLoop [26], [0] (0x13b567fa924e @ 4)
Bytecode length 26 budget –= 26 0x13b567fa926e LdaSmi.Wide [1000] 0x13b567fa9288 JumpLoop [26], [0] (0x13b567fa926e @ 36) Bytecode length 26 budget –= 26 0x13b567fa928c Return budget –= all_bytecode_length
Budget for function הִٕ٦فָⴓⶴׁגְגⰋ⡤ך✮皾Returnד鎘皾ׅ ךד㉏겗זֻ剑黝⻉ָ遤 Optimization
TurboFan
What is TurboFan? TurboFanהכV8ך剑黝⻉أةحؙךֿה V8כBytecodeַ剑黝⻉؝ٝػ؎ٕ遤ֲ㜥さחծ ♧傉IR欰䧭ׅ ֿךGraph欰䧭ה剑黝⻉遤ֲךָTurboFan TurboFan
Bytecode IR TurboFan Optimization & CodeGeneration
IR 䬄韋涸ז㹋遤ـٗحؙ Control Flow Graph TurboFan
#22:Branch[None](#21:SpeculativeNumberLessThan, #9:Loop) #28:IfTrue(#22:Branch) #30:JSStackCheck(#11:Phi, #32:FrameState, #21:SpeculativeNumberLessThan, #28:IfTrue) #33:JSLoadGlobal[0x2f3e1c607881 <String[1]: a>,
1] (#11:Phi, #34:FrameState, #30:JSStackCheck, #30:JSStackCheck) #2:HeapConstant[0x2f3e1c6022e1 <undefined>]() #39:FrameState #36:StateValues[sparse:^^](#12:Phi, #33:JSLoadGlobal) #37:FrameState#35:Checkpoint(#37:FrameState, #33:JSLoadGlobal, #33:JSLoadGlobal) #38:JSCall[2, 15256, NULL_OR_UNDEFINED] (#33:JSLoadGlobal, #2:HeapConstant, #11:Phi, #39:FrameState, #35:Checkpoint, #33:JSLoadGlobal) #9:Loop(#0:Start, #38:JSCall)
Optimization TurboFanכGraphח㼎׃ג剑黝⻉遤ֲ TurboFan
inline ꟼ侧ㄎן⳿׃ךInline⻉ trimming ⵋ麦׃זְNodeךꤐ type 㘗䱿锷 typed-lowering 㘗ח㛇בְג䒭װㄏ⟀״知⽃זⳢ椚ח縧ֹ䳔ִ loop-peeling ٕ٦فⰻךⳢ椚㢩ח⳿ׅկ
loop-exit-elimination LoopExitꤐ load-elimination 搀꼽ז⦼ך铣⳿׃װcheckꤐ simplified-lowering ״Ⱗ⡤涸ז⦼דㄏ⟀ءٝفٕח㢌䳔ׅ generic-lowering JSفٖؿ؍حؙأך➰ֻㄏ⟀״ءٝفٕזㄎן⳿׃װ stubךㄎן⳿׃ח㢌䳔ׅ dead-code-elimination
ⵋ麦♶腉؝٦سךꤐ
Code generation 剑穄涸חInstructionSelectorהְֲؙٓأָregisterךⶴ➰遤 ְծ ֿךؚٓؿַCodeGeneratorָ堣唒铂欰䧭׃ג PC(ProgramCounter)ח،إٝـٔ剅ֹ⳿׃גְֻ Optimization
Deoptimization
What is Deoptimization? Deoptimization(膴剑黝⻉)הכ剑黝⻉׃Assembly؝٦سח✮劍 ׇט⦼ָ床㜥さחծⱄ䏝؝ٝػ؎ٕ׃湫ׅ堣腉 㼰זְח馉׃ֿהכזְ Deoptimizationָ涪欰ׅ⢽然钠׃ג״ֲ Deoptimization
const id = x => x;! const test = obj
=> {! for (let i = 0; i < 100000; i++) {! id(obj.x);! }! };! ! test({x: 1});! test({x: 1, y: 1});!
Wrong Map ➙ך⢽דכ剑ⴱח{x}ךMapח㼎׃ג剑黝⻉ׁAssembly⳿ ⸂׃ָծ ✳㔐湡ךㄎן⳿׃ָ{x,y}ךMapחծⱄ؝ٝػ؎ٕ⡭ ⭑זֻׁג׃ת ׳הֽAssembly鋖ְג״ֲ Deoptimization
0x451eb30464c 8c 48b9f1c7d830391e0000 REX.W movq rcx, 0x1e3930d8c7f1 0x451eb304656 96 483bca
REX.W cmpq rcx,rdx 0x451eb304659 99 0f8591000000 jnz 0x451eb3046f0 ;; Check Map!! ... 0x451eb3046f0 130 e81ff9cfff call 0x451eb004014 ;; deoptimization bailout 2
Bailout ֿך״ֲח⳿⸂ׁ؝٦سחMap然钠ׅ؝٦سろתג ְ Deoptimizationָ遤ה؝٦سכBytecode㹋遤ח䨱ָծ ֿBailoutהㄎע Deoptimization
Summary ⟃♳ָV8ָJS㹋遤ׅ䊨玎ד֮ 儗ך鿪さ♳GCכ満ְ V8ך؝٦سٔ٦ر؍ؚٝך䪮遭瘝כתـؚٗח剅ֻ✮㹀 http://abcdef.gets.b6n.ch/ ׀幠耮ָ֮הֲ׀ְׂת׃