ボンネットの䞋のV8

Yandex.Money Andrei MelikhovdevSchachtコミュニティの゚ディタヌ/トランスレヌタヌのリヌド開発者は、V8゚ンゞンを䟋ずしお䜿甚し、プログラムがマシンコヌドに倉わる前にどのような段階を経お、新しいコンパむラヌが本圓に必芁なのかを説明したす。







この資料は、6月2〜3日にサンクトペテルブルクで開催されたHolyJS 2017䌚議での著者の報告に基づいお䜜成されたした。 PDFでのプレれンテヌションは、 このリンクで芋぀けるこずができたす。



映画「The Last Dragon Slayer」は数ヶ月前に公開されたした。 そこで、䞻人公がドラゎンを殺すず、䞖界の魔法が消えたす。 JavaScriptの䞖界には魔法の堎所がないので、今日は敵になりたい、ドラゎンを殺したい。 動䜜するすべおが明瀺的に機胜したす。 どのように機胜するかを理解するために、どのように機胜するかを理解する必芁がありたす。



私はあなたず私の情熱を共有したいず思いたす。 ある時点で、V8の内郚でどのように機胜するのかわからないこずに気付きたした。 私は文孊を読み始め、䞻に英語のレポヌトを芋お、蓄積された知識を䜓系化し、それをあなたに届けたいず思いたす。



私たちの蚀語は解釈たたはコンパむルされおいたすか



誰もが違いを知っおいるこずを願っおいたすが、繰り返したす。 コンパむルされた蚀語それらの゜ヌスコヌドは、コンパむラによっおマシンコヌドに倉換され、ファむルに曞き蟌たれたす。 実行前にコンパむルを䜿甚したす。 利点は䜕ですか 再コンパむルする必芁はありたせん。コンパむル察象のシステムで可胜な限り自動化されおいたす。 欠点は䜕ですか オペレヌティングシステムが倉曎されおおり、゜ヌスがない堎合は、プログラムが倱われたす。

解釈された蚀語-むンタヌプリタヌプログラムによっお゜ヌスコヌドが実行されたずき。 利点は、クロスプラットフォヌムを簡単に実珟できるこずです。 ゜ヌスコヌドをそのたた提䟛したす。このシステムにむンタヌプリタヌがあれば、コヌドは機胜したす。 もちろん、JavaScriptは解釈されたす。



歎史に浞っおください。 Chromeは2008幎に発売されたす。 Googleはその幎に新しいV8゚ンゞンを導入したした。 2009幎に、Node.jsはV8ずioを提䟛するlibUVラむブラリで構成される同じ゚ンゞンで導入されたした。 ファむルぞのアクセス、いく぀かのネットワヌクなど。 䞀般に、私たちにずっお非垞に重芁な2぀のこずはV8゚ンゞンに基づいおいたす。 それが䜕で構成されるかを芋おみたしょう。







2008幎、゚ンゞンは内郚が非垞にシンプルになりたした。 たあ、比范的単玔です-そのレむアりトは単玔でした。 ゜ヌスコヌドはパヌサヌからパヌサヌからコンパむラヌに送られ、出力では半最適化されたコヌドが埗られたした。 最適化が適切ではなかったため、半最適化されたした。 おそらくそれらの幎には、オプティマむザが内郚で最適化するこずを期埅できなかったため、より良いJavaScriptを蚘述する必芁がありたした。



このスキヌムのパヌサヌは䜕ですか



゜ヌスコヌドを抜象構文ツリヌたたはASTに倉換するには、パヌサヌが必芁です。 ASTは、すべおの頂点が挔算子であり、すべおの葉がオペランドであるツリヌです。







数匏の䟋を芋おみたしょう。 このようなツリヌがあり、すべおの頂点は挔算子であり、分岐はオペランドです。 それに぀いお良いこずは、埌でそれからマシンコヌドを生成するこずが非垞に簡単であるこずです。 アセンブラヌで働いた人は、ほずんどの堎合、呜什は䜕をするか、䜕をするかで構成されおいるこずを知っおいたす。







そしお、ここで、珟圚のポむントに挔算子かオペランドかを確認できたす。 挔算子の堎合、そのオペランドを調べおコマンドを組み立おたす。







たずえば、配列があり、むンデックス1で配列から芁玠を芁求するず、JavaScriptで䜕が起こりたすか 挔算子が「キヌでプロパティをロヌドする」抜象構文ツリヌが衚瀺されたす。オペランドは、このプロパティをロヌドするオブゞェクトずキヌです。



なぜjavascriptコンパむラで



私が蚀ったように、私たちの蚀語は解釈されたすが、そのスキヌムにはコンパむラがありたす。 なんで 実際には、2皮類のコンパむラがありたす。 実行前にコンパむルする事前凊理コンパむラず、実行時にコンパむルするJITコンパむラがありたす。 たた、JITコンパむルにより、優れた加速が埗られたす。 これは䜕のためですか 比范しおみたしょう。







同じコヌドがありたす。 1぀はPascal、もう1぀はJavaScriptです。 パスカルは玠晎らしい蚀語です。 JavaScriptを䜿甚せずにプログラミングを孊習する必芁があるず思いたす。 プログラミングの方法を孊びたい人がいる堎合は、PascalたたはCを芋せおください。



違いは䜕ですか Pascalはコンパむルず解釈の䞡方が可胜で、JavaScriptには解釈が必芁です。 最も重芁な違いは静的型付けです。







Pascalで曞くずき、必芁な倉数を指定しおから、その型を曞くからです。 コンパむラヌは、最適化された適切なコヌドを簡単に構築できたす。 メモリ内の倉数にどのようにアクセスしたすか 䜏所があり、シフトがありたす。 たずえば、敎数32の堎合、このアドレスで32をメモリにシフトし、デヌタを取埗したす。



JavaScriptでは、いいえ、型は垞に実行時に倉曎されたす。コンパむラヌは、このコヌドが最初に実行されるずきに、このコヌドが最初に実行されたずきに、型に関する情報を収集したす。 そしお、同じ機胜を2回目に実行するずき、どのタむプがあったかを想定しお、前回受け取ったデヌタに基づいお最適化をすでに行うこずができたす。 倉数がすべお明確な堎合、倉数は倀によっお決定されたすが、オブゞェクトに぀いおはどうでしょうか



結局のずころ、JavaScriptがあり、プロトタむプモデルがあり、オブゞェクトのクラスはありたせん。 実際にはありたすが、それらは芋えたせん。 これらは、いわゆる隠しクラスです。 それらはコンパむラヌにのみ衚瀺されたす。



隠しクラスはどのように䜜成されたすか







ポむントがありたす-これはコンストラクタヌであり、オブゞェクトが䜜成されたす。 たず、ポむント自䜓のみを含む非衚瀺のクラスが䜜成されたす。







次に、このオブゞェクトxのプロパティを蚭定し、非衚瀺クラスがあったずいう事実から、xを含む次の非衚瀺クラスが䜜成されたす。







次に、yを蚭定し、それに応じお、xずyを含む別の非衚瀺クラスを取埗したす。







そこで、3぀の隠されたクラスを取埗したした。 その埌、同じコンストラクタヌを䜿甚しお2番目のオブゞェクトを䜜成するず、同じこずが起こりたす。 すでに非衚瀺のクラスがあり、それらを䜜成する必芁はもうありたせん。マップするだけです。 そのため、埌でこれら2぀のオブゞェクトの構造が同䞀であるこずがわかりたす。 そしお、あなたは圌らず仕事をしおいるように芋えたす。







しかし、埌でp2オブゞェクトにプロパティを远加するずどうなりたすか 新しい非衚瀺クラスが䜜成されたす。 p1ずp2はもはや類䌌しおいたせん。 なぜこれが重芁なのですか コンパむラがポむントルヌプを反埩凊理し、p1ず同じものがすべお揃うず、ツむスト、ツむスト、ツむスト、p2にぶ぀かり、別の隠されたクラスがあるため、コンパむラは最適化解陀になりたす。圌は期埅したものを受け取りたせんでした。







これはいわゆるカモタむピングです。 アヒルタむピングずは䜕ですか 衚珟はアメリカのスラングから来たした。䜕かがアヒルのように歩き、カチカチがアヒルのようであれば、それはアヒルです。 すなわち p1ずp2の構造が同䞀である堎合、それらは同じクラスに属したす。 しかし、p2を構造に远加する必芁がありたす。これらのアヒルはそれぞれ異なる方法でカチカチ音を立おたす。これらは異なるクラスです。



そしお、オブゞェクトがどのクラスに属しおいるか、どのような倉数、このデヌタをどこで䜿甚し、どのように保存するかに関するデヌタを取埗したした。 このために、むンラむンキャッシュシステムが䜿甚されたす。







この郚分のむンラむンキャッシュの䜜成方法を芋おみたしょう。 最初に、コヌドを分析するず、そのような呌び出しで補足されたす。 これは単なる初期化です。 むンラむンキャッシュの皮類はただわかりたせん。



ここで、ここで初期化するず蚀うこずができたす。this.primesの読み蟌みは次のずおりです。







䞻なダりンロヌドは次のずおりです。







そしお、操䜜BinaryOperation-これはバむナリであるこずを意味するのではなく、単項挔算ではなくバむナリであるこずを意味したす。 巊右のパヌツがある操䜜。







実行時に䜕が起こりたすか



コヌドが到着するず、すべおコンパむラ内に既にあるコヌドに眮き換えられ、コンパむラは型情報を持っおいる堎合にこの特定のケヌスでうたく機胜する方法を知っおいたす。 ぀たり、ここでは、オブゞェクトから玠数を取埗する方法を知っおいるコヌドを呌び出す代わりに䜿甚されたす。







ここでは、SMI配列から芁玠を取埗する方法を知っおいるコヌドに眮き換えられたす。







2぀のSMIの陀算の剰䜙を蚈算する方法を知っおいるコヌドを次に瀺したす。







すでに最適化されおいたす。 そのため、コンパむラヌはほが動䜜し、そのような郚分で飜和したした。





もちろん、これによりオヌバヌヘッドが発生したすが、パフォヌマンスも向䞊したす。



私たちはむンタヌネットを開発し、JavaScriptの数が増加し、より倚くの生産性が必芁になり、Googleは新しいクランクシャフトコンパむラを䜜成するこずで察応したした。







叀いコンパむラはFullCodegenずしお知られるようになりたした。これは、完党なコヌドベヌスで動䜜し、すべおのJavaScriptずそのコンパむル方法を知っおいるためです。 そしお、最適化されおいないコヌドを生成したす。 圌が䜕床か呌び出される関数に出くわした堎合、圌はそれが熱くなったず信じおおり、Crankshaftコンパむラヌがそれを最適化できるこずを知っおいたす。 そしお、圌は型に関する知識を䞎え、この機胜は新しいクランクシャフトコンパむラで最適化できるこずを瀺したした。 次に、新しいコンパむラは抜象構文ツリヌを取埗したす。 叀いASTコンパむラからではなく、戻っおASTを芁求するこずが重芁です。 そしお、型を知っお最適化を行い、最埌に最適化されたコヌドを取埗したす。



圌が最適化を行えない堎合、圌は非最適化に陥りたす。 これはい぀起こりたすか たずえば、隠しクラスサむクルでスピンした埌、予期せぬ䜕かが発生し、最適化が解陀されるなど、前に蚀ったずおりです。 たたは、たずえば、倚くの人々は、巊偎に䜕かがあるずきにチェックを行うこずを奜みたす。たずえば、長さを取埗したす。 文字列があるかどうかを確認し、その長さを取埗したす。 なぜこれが悪いのですか 行がない堎合、巊偎にブヌル倀が衚瀺され、出力はブヌル倀になり、その前に数倀が衚瀺されるためです。 この堎合、最適化が解陀されたす。 たたは、圌はコヌドに䌚ったが、それを最適化するこずはできたせん。







䟋ずしお同じコヌドを䜿甚したす。 ここでは、むンラむンキャッシュでいっぱいのコヌドがありたした。新しいコンパむラヌではすべおむンラむンです。







圌はそれをすべおむンラむンに挿入したす。 さらに、このコンパむラは投機的最適化コンパむラです。 圌は䜕を掚枬しおいたすか 圌は型の知識を掚枬しおいたす。 圌は、このタむプで10回呌び出した堎合、このタむプは継続するず想定しおいたす。 圌が期埅するタむプが来るようなチェックがどこにでもあり、圌が期埅しおいなかったタむプが来るずき、圌は非最適化に陥りたす。 これらの改善によりパフォヌマンスは倧幅に向䞊したしたが、V8゚ンゞンに関係するチヌムは埐々にすべおをれロから始める必芁があるこずに気付きたした。 なんで 最初のバヌゞョンを䜜成するずきに゜フトりェアを開発する方法はありたすが、2番目のバヌゞョンを最初から䜜成するのは、䜜成方法を理解しおいるためです。 そしお、圌らは新しいコンパむラヌ-2014幎のタヌボファンを䜜成したした。







゜ヌスコヌドがあり、これはパヌサヌに、次にFullCodegenコンパむラヌに分類されたす。 それで、違いはありたせんでした。 出力では、最適化されおいないコヌドを取埗したす。 あらゆる皮類の最適化を行うこずができる堎合、CrankshaftずTurbofanの2぀のコンパむラヌに進みたす。 FullCodegenは、Turbofanコンパむラヌが特定のものを最適化できるかどうかを刀断し、可胜な堎合は送信し、できない堎合は叀いコンパむラヌに送信したす。 そこで、ES6から新しいデザむンを埐々に远加し始めたした。 asm.jsを最適化するこずから始めたした。



なぜ新しいコンパむラが必芁なのですか



  1. 基本的なパフォヌマンスを改善する

  2. パフォヌマンスを予枬可胜にしたす。

  3. ゜ヌスコヌドの耇雑さを軜枛



「基本的なパフォヌマンスを向䞊させる」ずはどういう意味ですか



叀いコンパむラは、匷力なデスクトップがあった時代に曞かれたした。 そしお、オクタン、合成などのテストでテストされ、ピヌク性胜がテストされたした。 最近、Google I / Oカンファレンスがあり、V8の開発を管理しおいるマネヌゞャヌは、コンパむラが実際に動䜜するものに察応しないため、基本的にオクタンを攟棄したず述べたした。 そしお、これは私たちが非垞に良いピヌクパフォヌマンスを持っおいるずいう事実に぀ながりたしたが、基本的なもの、すなわち コヌド内の事柄は最適化されおおらず、うたく機胜するコヌドがそのような事柄に出くわすず、パフォヌマンスが倧幅に䜎䞋したした。 そしお、そのような操䜜はたくさんありたすが、そのうちのいく぀かを以䞋に瀺したすforEach、map、reduce。 それらは、チェックを詰めたプレヌンなJSで曞かれおいたす。 頻繁に䜿甚するこずをお勧めしたす。



バむンドの遅い動䜜-内郚的に実装されおおり、完党に恐ろしいこずが刀明したした。 倚くのフレヌムワヌクが独自のバむンド実装を䜜成したした。 倚くの堎合、人々は私が座っお膝の䞊にバむンドを曞いたず蚀っお、驚くほど速く動䜜したす。 try {} catche{}そしお最埌にを含む関数は非垞に遅いです。







倚くの堎合、パフォヌマンスが䜎䞋しないように、䜿甚しない方が良いタブレットがありたした。 実際、コンパむラが正垞に動䜜しおいないため、コヌドは遅くなりたす。 たた、タヌボファンの出珟により、すべおがすでに最適化されおいるため、それを忘れるこずができたす。 たた、非垞に重芁です非同期関数のパフォヌマンスが改善されたした。







したがっお、誰もが最近リリヌスされた新しいノヌドのリリヌスを埅っおいたす;そこでは非同期/埅機のパフォヌマンスが重芁です。 私たちの蚀語は最初は非同期であり、コヌルバックのみをうたく䜿甚できたした。 たた、promiseを䜿甚しお蚘述しおいる人は、サヌドパヌティの実装がネむティブの実装よりも高速であるこずを知っおいたす。



次の課題は、パフォヌマンスを予枬可胜にするこずでした。 このような状況がありたしたjsPerfで正垞に実行されたコヌドは、動䜜䞭のコヌドに貌り付けられたずきにたったく異なるパフォヌマンスを瀺したした。 しかし、コヌドが圓初の期埅どおりに生産的に機胜するこずを保蚌できなかった堎合もありたす。







たずえば、mymaxを呌び出す非垞に単玔なコヌドがあり、それをチェックするずキヌtrace-optおよびtrace-deoptを䜿甚しお、どの関数が最適化され、どの関数が最適化されなかったかを瀺したす。







これをノヌドで実行するか、V8がブラりザヌずは別に動䜜する特別な環境であるD8で実行できたす。 最適化が無効になっおいるこずがわかりたす。 怜蚌のために䜕床も実行されたためです。 問題は䜕ですか 匕数の擬䌌配列が倧きすぎるこずがわかり、内郚では、この配列のサむズのチェックが行われたこずがわかりたした。 さらに、このチェックは、Benedikt MeurerTurbofanのリヌド開発者が蚀ったように、䜕の意味もありたせんでしたが、長幎にわたっおコピヌペヌストで凊理されおいたした。



そしお、なぜ長さが制限されおいるのですか 結局のずころ、スタックのサむズはチェックされず、䜕もチェックされたせんでした。 これは、排陀する必芁がある予期しない動䜜です。







別の䟋ずしお、ここでは2぀のコヌルバックを呌び出すディスパッチャヌがありたす。 たた、圌を呌び出すず、圌が最適化されおいないこずがわかりたす。 ここで問題は䜕ですか その1぀の関数は厳密であり、2番目の関数は厳密ではありたせん。 たた、叀いコンパむラでは異なる隠しクラスを取埗したす。 すなわち 圌はそれらを異なるず考えおいたす。 たた、この堎合、圌は最適化を解陀したす。 このコヌドず以前のコヌドの䞡方は、原則ずしお正しく蚘述されおいたすが、最適化されおいたせん。 これは予想倖です。







たた、Twitterでそのような䟋があり、いく぀かのケヌスではchromeのforルヌプがreduceよりも遅く動䜜するこずが刀明したした。 reduceの方が遅いこずはわかっおいたすが。 問題は、予期せずにfor内でletが䜿甚されおいたこずが刀明したした。 その時点で最新バヌゞョンをむンストヌルしたしたが、結果はすでに良奜です-修正枈み。







次のポむントは、耇雑さを軜枛するこずでした。 ここにはバヌゞョンV8 3.24.9があり、4぀のアヌキテクチャをサポヌトしおいたした。







V8は9぀のアヌキテクチャをサポヌトするようになりたした







そしお、コヌドは䜕幎も蓄積されおきたした。 JS、アセンブラヌ、Cで郚分的に曞かれおいたため、チヌムに来た開発者はこのように感じたした。







䞖界の倉化に察応できるように、コヌドは簡単に倉曎できる必芁がありたす。 たた、タヌボファンの導入により、アヌキテクチャ固有のコヌドの量が枛少したした。







2013幎から2017幎にかけお、アヌキテクチャ固有のコヌドよりも29少なくなりたした。 これは、新しいタヌボファンコヌド生成アヌキテクチャの登堎によるものです。







圌らはそれをデヌタ駆動型、぀たり 制埡フロヌグラフがあり、そこに䜕が起こるかに぀いおのデヌタず知識が含たれおいたす。 そしお、それは䞀般的なコマンドセレクタヌに分類され、レゞスタの予玄があり、次に異なるアヌキテクチャのコヌド生成がありたす。 すなわち 開発者は、特定のアヌキテクチャ向けにすべおがどのように蚘述されおいるかを知る必芁はなくなりたしたが、より䞀般的なコヌドを䜜成できたす。 そういうわけで、コヌドはよく改善されたしたが、むンタヌプリタヌ蚀語甚のコンパむラヌを曞いおから数幎埌には、むンタヌプリタヌが必芁であるこずがわかりたした。



その理由は䜕ですか その理由は、Steve Jobsの手にかかっおいたす。







もちろん、これはiPhone自䜓ではなく、iPhoneを生み出したスマヌトフォンであり、むンタヌネットぞの䟿利なアクセスを可胜にしたした。 そしおこれは、モバむルデバむス䞊のナヌザヌの数がデスクトップ䞊の数を超えたずいう事実に぀ながりたした。







そしお圓初、コンパむラはモバむルデバむス甚ではなく、匷力なデスクトップ甚に蚭蚈されおいたした。







これは、1MB JavaScriptの初期分析タむムラむンです。 そしお最近、VKontakteがクラむアントレンダリングではなくサヌバヌレンダリングを行う理由に぀いお質問がありたした。 JS分析に費やされる時間は、モバむルデバむスでは2〜5倍長くなる可胜性があるためです。 そしお、我々はトップ゚ンドのデバむスに぀いお話しおいる、そしお人々はしばしば完党に異なるもので行く。



もう1぀の問題倚くの䞭囜のデバむスには512 MBのメモリがあり、V8メモリの割り圓お方法を芋るず、別の問題がありたす。







メモリは、オブゞェクトコヌドが䜿甚するものずコヌドオブゞェクトコンパむラが䜿甚するものです-たずえば、むンラむンキャッシュをそこに栌玍するに分かれおいたす。 内郚䜿甚をサポヌトするために、メモリの30が仮想マシンによっお占有されおいるこずがわかりたした。 , .



- , 2016 Android Ignition.







, , Turbofan, , - . -.







-, JavaScript , .



- , – . - assembler, . , .



, .







, .



, . accumulator ( , , ) smi integer 100.







, a2 ( 150) (100). accumulator 50.







, r0. d.







. b, accumulator, a0 , , 105.







. , .



, , inline caches. – Data-driven IC, . – , – .







. - , , , - . , , , . inline caches, , , . , , , . .



.







Turbofan. , FullCodegen JS, Crankshaft — JS, Turbofan JS JS. , , , , , . .







, ( , ES6 , ). , , . すなわち , hidden class – , , . hidden class, , , .



V8 JIT-. JIT- — . JIT- , , , . , , - . , . a+b – . , number+number string+string, . JIT-.



, (, ). – . Turbofan , , .



– . , . , , , . . - , . - . .



. , . , ( , , ).



.





github.com/v8/v8/wiki/TurboFan


http://benediktmeurer.de/

http://mrale.ph/

http://darksi.de/

https://medium.com/@amel_true






JS , , , HolyJS :






All Articles