Llst内郚デバむス、パヌト3。JITの魔法、たたは仮想マシンを50倍高速化する方法

XKCD 303
前の蚘事で 、 humbugず私は、メ゜ッドの実行方法ずその内容によっお蚈算速床がどのように倉化するかを瀺したした。 これで、仮想マシンの内郚を芋お、これがどのように、なぜ起こるのかを理解できたす。

先ほど、 Smalltalk蚀語 、たたはLittle Smalltalkのマむクロ実装に粟通したした。 蚀語の構文、メモリ内のオブゞェクトを衚珟するための圢匏、および基本的な呜什のセットを理解したした。 これで、SmalltalkずLLVMの盞互䜜甚の問題に近づきたすこのため、䞀連の蚘事党䜓が考案されたした。

これで、JITコンパむラで䜕が行われるかを正確に理解するために必芁な知識ベヌスがすべお揃いたした。 この蚘事では、SmalltalkバむトコヌドがLLVM IRコヌドに倉換される方法、コヌドがコンパむルおよび実行される方法、およびプログラムによる解釈よりも高速に動䜜する理由を孊習したす。 最もせっかちな人は、数字ず忍び寄るラむンのあるシェルキャスト 1回ず2回 を芋るこずができたすスクロヌルの可胜性を忘れないでください。


はじめに


TRIZず垞識のありふれた考察の䞡方は、私たちに次のこずを教えおくれたす


これらの原則は人間関係をはるかに超えおおり、幅広い分野で応甚されおいたす。 コンピュヌタヌサむ゚ンスを含む。 倚くは、 キャッシュを䜿甚する利点を理解しおいたす。 怠zyなコンピュヌティングのこずを聞いた人もいたす。 しかし、無意味でむさがる官僚䞻矩の時代に盎面した反䟋で、誰もが出䌚いたした。

たた、JITコンパむラヌには、䞊蚘の考慮事項ず倚くの共通点がありたす。 私たちのプロゞェクトも䟋倖ではありたせん。 埓来の方法でコヌドが実行される方法ず、パフォヌマンスを改善するためにコヌドで䜕ができるかを確認したす。

仮想マシンず実際のプロセッサヌの違い


Smalltalk仮想マシンはスタック指向です。

  1. 操䜜を実行するず、オペランドがスタックにプッシュされたす。
  2. 実行された操䜜により、必芁な数のオペランドがスタックから削陀されたす。
  3. 結果はスタックの最䞊郚にプッシュバックされ、次の操䜜のオペランドずしお䜿甚できたす。

このアプロヌチの利点は、仮想マシンのコヌドがシンプルであり、䞀連の蚈算を簡単に実装できるこずです。 もちろん欠点もありたすが、その䞻な点は、倀を操䜜したり、スタックに倀を配眮したり、スタックから倀を削陀したりしお、マシンが倀に察しお䜕らかのアクションを実行できるようにするこずです。 自分で刀断する 前の蚘事  Collection>>sort:説明した䟋では、倀をスタックに繰り返しプッシュしおすぐに倀を抜出し、Arrayクラスのむンスタンスにコピヌしおから、オブゞェクトをスタックに再び配眮したす markArgumentsはこれを行いたす 

もちろん、これはすべお理由がありたす。 マシンの積み重ねられた構成により、耇雑な操䜜を導入するこずなく、アクションのシヌケンスを非垞に簡単に蚘録できたす。 たずえば、括匧を䜿甚しお算術匏を蚈算する堎合、スタックは䞭間倀の䞀時的なストレヌゞずしお䜿甚されたす。 倪叀から、工孊蚈算機はこれらの原則に埓っお、 逆ポヌランド蚘法を䜿甚しお蚭蚈されおきたした。

ただし、最新のプロセッサアヌキテクチャの芳点から芋るず、Smalltalkは非垞に䞍䟿です。 ほずんどの操䜜はメモリを䜿甚しお実行されたす。 局所性の原則は維持されたせんオブゞェクトはすべお互いに遠く離れたヒヌプに散圚しおいたす。 新しいオブゞェクトが絶えず生成されおいるため、ガベヌゞコレクションが行われ、次の倧量のメモリがシャッフルされたす。 すべおのメモリ操䜜は間接的に凊理されたす。 最埌に、倚数の小さなメ゜ッドにより、レゞスタを適切に割り圓おるこずができなくなりたす。

倧衆の最新のプロセッサは登録されおいたす。 レゞスタはRAMよりもはるかに高速に動䜜するため、レゞスタを盎接操䜜するこずでより高いパフォヌマンスを期埅できたす。 倧量のデヌタキャッシュが存圚するず、メモリぞのアクセスのコストを倧幅に削枛できたすロヌカリティの原理に埓いたすが、以䞋に瀺すように、メモリ操䜜自䜓をレゞスタに移動するのではなく、メモリ操䜜自䜓の数を根本的に削枛するこずにより、䞻に成功を達成したす。

したがっお、プロセッサでSmalltalkコヌドを効率的に実行するには、スタックロゞックをレゞスタに倉換する方法を芋぀ける必芁がありたす。

コンパむラヌJIT倀スタック


LLVMの䞭間コヌド衚珟はSSA衚蚘を䜿甚したす。 この衚蚘では、慣れおいる圢匏の倉数はありたせん。 すべおの蚈算はグラフです。 各蚈算結果ノヌドに名前を割り圓おお、この名前を以降の蚈算で䜿甚できたす2぀のノヌドをリンクしたす。 さらに、指定された名前がその倀を倉曎できない堎合同じ名前ぞの倀の再割り圓おは蚱可されたせん。 名前は、それが発衚されたプログラムおよびデヌタ内のそのポむントのみを参照したす。 ただメモリを操䜜する必芁がある堎所では、alloca呜什が䜿甚されたす。これは、芁求されたサむズのメモリ領域ず、読み蟌みおよび曞き蟌みのロヌドおよびストア呜什をそれぞれ割り圓おたす。

前述の゜ヌト方法からleft倉数を初期化するのに必芁なSmalltalkバむトコヌドに再び泚目したしょう。
 "left <- List new" 0023 PushLiteral 4 0024 MarkArguments 1 0025 SendMessage new 0026 AssignTemporary 0 0027 DoSpecial popTop 

別の䟋、同じメ゜ッドからのブロックの開始
 0037 PushArgument 1 "criteria" 0038 PushTemporary 3 "x" 0039 PushTemporary 2 "mediane" 0040 MarkArguments 3 0041 SendMessage value:value: "  " 0042 DoSpecial branchIfFalse 52 

たた、どちらの堎合も、倚数の単玔なメモリ操䜜が実行されるこずは明らかです。 基本的なプッシュ呜什は、アセンブラヌ呜什のペアに倉換できたす。 スタックの最䞊郚のむンデックスをシフトするこずにより倉数のむンデックスを別の領域にシフトするこずにより、あるメモリ領域からポむンタをコピヌするだけですそしおオブゞェクト構造ぞのポむンタのみを䜿甚したす。

IRコヌドでの䞊蚘のアむデアの「正面」実装は、次のようになりたす。
 define void @pushValueToStack(%TContext* %context, i32 %index, %TObject* %value) { %stackPointer = getelementptr inbounds %TContext* %context, i32 0, i32 4 %stack = load %TObjectArray** %stackPointer %stackObject = bitcast %TObjectArray* %stack to %TObject* call %TObject** @setObjectField(%TObject* %stackObject, i32 %index, %TObject* %value) ret void } define %TObject** @setObjectField(%TObject* %object, i32 %index, %TObject* %value) { %fieldPointer = call %TObject** @getObjectFieldPtr(%TObject* %object, i32 %index) store %TObject* %value, %TObject** %fieldPointer ret %TObject** %fieldPointer } define %TObject** @getObjectFieldPtr(%TObject* %object, i32 %index) { %fields = getelementptr inbounds %TObject* %object, i32 0, i32 2 %fieldPointer = getelementptr inbounds [0 x %TObject*]* %fields, i32 0, i32 %index ret %TObject** %fieldPointer } 

はい、動䜜し、ネむティブコヌドに倉換されるず、むンタヌプリタヌの同様の実装よりも高速になりたす。 ただし、このようなJIT VMの党䜓的なパフォヌマンスは驚くほど䜎くなりたす。 問題は、メモリ操䜜自䜓がなくなっおいないこずです。 単玔に䜎レベルのコヌドに移怍し、゜フトりェアVMの「ラッパヌ」を取り陀きたした。

仮想マシンを実際に高速化するには、提䟛されおいるLLVM機胜、぀たりSSAを豊富な最適化パスずずもに䜿甚する必芁がありたす。

pushおよびmarkArgument呜什の目的を思い出すず、ここのスタックは特定の倀匕数、リテラル、定数、たたは䞀時倉数を、察応するプッシュ呜什の䜍眮によっお決定される匕数の配列内の察応するセルに関連付けるためにのみ䜿甚されるこずが明らかになりたす。

SSA衚蚘により、スタックをバむパスしおこれを盎接行うこずができたす。 必芁なのは、匕数の配列に入れるために準備したオブゞェクトを「蚘憶」し、すぐに将来の䜿甚堎所にコピヌするこずです。 LIFOの原則に埓っお、保存されおいる倀にも順番にアクセスするため、スタックを䜿甚しおリンクを保存するのが劥圓です。 この倀スタックは存圚し、コンパむル時にのみ䜿甚されたす。 すでに生成された「正しい」コヌドが実行されたす。

この原則は非垞にうたく機胜するため、JITバヌゞョンのメ゜ッドは通垞のコンテキストスタックをたったく䜿甚したせん。 JITコヌドでコンテキストを䜜成するずきにも初期化されず、これは送信するメッセヌゞごずに 1぀の割り圓おを差し匕いたものです。

したがっお、最適化されたメッセヌゞ送信のために次のアルゎリズムを取埗したす。
  1. オブゞェクトをコンテキストスタックにプッシュする  push 代わりに、メモリから倉数に倀をロヌドし load 、コンパむラヌの倀スタックに眮きたす。
  2. markArgumentsステヌトメントを凊理し、匕数のオブゞェクトを䜜成しおから、倀スタックから芁玠を順次削陀し、䜜成された匕数の配列のスロットの行にそれらを栌玍したす。
  3. sendMessageハンドラヌスタブを呌び出したす 。

4぀のメモリ操䜜倀の読み蟌み 、スタックぞの倀の栌玍 、スタックからの倀の読み蟌み 、匕数配列のフィヌルドぞの栌玍の代わりに、2぀倀の読み蟌みず配列ぞの栌玍だけを残したこずがわかりたす。

LLVMに粟通しおいる人は、オプティマむザパスによっお倖郚の支揎なしでそのような空のメモリ操䜜が効果的に削陀されるこずに反察するかもしれたせん。 実際、最も単玔な堎合、これはそうです。 しかし、生成する必芁がある実際のコヌドは、はるかに耇雑に芋えたす。 これは䞻に、ガベヌゞコレクタヌの正しい動䜜を保蚌するために特別なマヌカヌず倀ぞの参照を远加する必芁があるためです。

メ゜ッドず機胜


動䜜するず、仮想マシンはむメヌゞから各メ゜ッドのJITバヌゞョンを䜜成したす。 メ゜ッドず機胜的に同等ですが、ネむティブプロセッサの呜什で既に実装されおいたす。 JIT関数は、ただ送信されおいないメッセヌゞを最初に送信したずきに䜜成されたす。 たずえば、メッセヌゞList>>sort: firstを送信するず、メッセヌゞハンドラが芋぀かりたす。これはCollection>>sort:メ゜ッドです Listクラスにはsort:メ゜ッドはありたせんが、 Collectionから継承されるため。 その埌、仮想マシンは同じ名前のJIT関数を芋぀けようずしたすが、芋぀けられたせん。 JITコンパむラが呌び出され、 Collection>>sort:メ゜ッドの本䜓を通じお、同等の関数が䜜成されたす。 次に、この関数は、通垞のメッセヌゞ甚ず同じパラメヌタヌで呌び出されたす。 次回送信するず、コンパむラは呌び出されず、メ゜ッドの既存のバヌゞョンが䜿甚されたす。

メッセヌゞを送信する


前回の蚘事で思い出したように、仮想マシンにメッセヌゞを送信するには、次のものが必芁です。

  1. スタックから倀を削陀し、匕数の配列を䜜成したす markArgumentsの個別のステップずしお実行されたす 。
  2. メッセヌゞを凊理する階局内のメ゜ッドを芋぀けたす。
  3. コンテキストオブゞェクトを䜜成し、フィヌルドに入力したす。
  4. 新しいコンテキストの実行に切り替えたす。

この段階では、仮想マシンにはオブゞェクトのタむプに関する情報がないため、宛先メ゜ッドの怜玢手順に圱響を䞎えるこずはできたせん。 具䜓的には、この情報は呌び出し時にのみ利甚可胜であり、オブゞェクトの将来のタむプを予枬するために䜿甚するこずはできたせん。 したがっお、メッセヌゞ怜玢゚ンゞンは同じたたで、モゞュヌルに登録されおいるsendMessage()システム関数を䜿甚しお呌び出されたす。 この機胜を䜿甚するず、JITコヌドから゜フトりェアVMにアクセスし、メッセヌゞ宛先を芋぀けるように䟝頌できたす。 次に、制埡は芋぀かったメ゜ッドのJITバヌゞョンに転送されたす。

゜フトりェアVMは、他のメモリがないため、ヒヌプ䞊にのみすべおのオブゞェクトを䜜成したす。 JIT VMの堎合、いく぀かのオブゞェクトをスタックに配眮するこずにより、メモリのオヌバヌヘッドを倧幅に削枛できたす。 そのようなオブゞェクトは次のずおりです。


これらのオブゞェクトの存続期間はメ゜ッド自䜓の実行時間よりも短くないため垞にアクティブなコンテキストからリンクされおいるため、スタックに配眮できたす。 メ゜ッドを終了するず、スタックは前のフレヌムに折りたたたれ、䜿甚䞭のメモリが自動的に解攟されたす。 厳密に蚀えば、スタックずヒヌプのメモリ割り圓おの速床はほが同じです。 そこずそこの䞡方で、割り圓おられたメモリのサむズにポむンタを移動し、結果の倀を返すだけです。 しかし、倧量の堎合、これはガベヌゞコレクションの必芁性に぀ながり、すでにかなりの時間がかかりたす。 これが頻繁に発生するほど、スタックオプションはより効率的に機胜したす。

統蚈


JITコンパむラの理想的な最終結果は、次のように衚すこずができたす。


RBIを達成する方法の䞻な問題は、呌び出しごずのオブゞェクトのタむプの䞍確実性です。 既に知っおいるCollection >> sortメ゜ッドをもう䞀床考えおみたしょう。

 sort: criteria | left right mediane | (self size < 32) ifTrue: [ ^ self insertSort: criteria ]. mediane <- self popFirst. left <- List new. right <- List new. self do: [ :x | (criteria value: x value: mediane) ifTrue: [ left add: x ] ifFalse: [ right add: x ] ]. left <- left sort: criteria. right <- right sort: criteria. right add: mediane. ^ left appendList: right 


䜿甚される倉数のタむプはどうですか 実行コンテキストず呌び出しコヌドがなければ、明確なこずは蚀えたせん。 これは、Smalltalkの長所ず短所の䞡方です。 このコヌドは、䞋䜍クラスに関係なく同等に効率的に機胜するため、匷力です。 リストず配列の䞡方を等しく゜ヌトしたす。 コンパむル段階で最適化を行うこずができず、オブゞェクト型の知識に䟝存しおいるため、匱い。

最適に近い結果を埗るこずができるトリッキヌなプランがありたす。 そしお、圌の名前はコヌル統蚈です。 プログラムが実行されるず、sendMessageハンドラヌが呌び出されたす。このハンドラヌは、メむンの䜜業に加えお、メッセヌゞの送信に関䞎するクラスの統蚈も補充したす。

プログラムの過皋でクラス階局が倉化しないず仮定しお、条件の代わりに盎接呌び出しを挿入できたす。 残念なこずに、ここでの厳しい珟実には驚きがありたす。 たずえば、統蚈を収集するず、次の結果が埗られたした。10回の連続した呌び出しから、倉数がクラスStringこずが10回刀明したした。 しかし、これは次回にそうなるずいう意味ではありたせん。 オブゞェクトのコレクションを歩くず、さたざたなクラスに出䌚えたす。 最埌に、 Stringむンスタンスを返すために䜿甚されたメ゜ッドでさえ、単に星が圢成されたためにパラメヌタが蚭定されたため、突然nilを返すこずがありたした。

したがっお、呌び出しの統蚈情報を持っおいる堎合でも、倉数の型が既知のいずれかであるこずが刀明した堎合、この段階でできるこずは盎接呌び出しを挿入するこずです。 実際には、これは、パッチャヌがオブゞェクトのクラスをチェックし、察応する関数に制埡を移すスむッチブロックを挿入するずいう事実に぀ながりたす。

型掚論


将来的には、Hindley-Milnerアルゎリズムず远加のヒュヌリスティックを䜿甚しお、完党な型掚論を行う予定です。 次に、倉数の型が完党に掚枬された堎所で、チェックなしで盎接呌び出しを行うこずができたす。 これは、呌び出したコヌドに呌び出されたメ゜ッドを完党にむンラむン化するパフォヌマンスず機胜に非垞によく圱響したす。

たずえば、䞊蚘のCollection>>sort:メ゜ッドを芋るず、泚意深い読者は、倉数leftずright垞にListクラスのむンスタンスによっお初期化されるこずに気付くかもしれたせん。 仮想マシンは、次の考慮事項からこれを理解できたす。

  1. left倉数は、 List new匏の結果に初期化されたす。
  2. 匏List newはパラメヌタヌを䜿甚せず、固定アクションオブゞェクト List を持ちたす。
  3. Listオブゞェクトぞの#newメッセヌゞの送信は、 List>>newによっお凊理されたす
  4. List>>newメ゜ッドは、匏super new結果を返したす
  5. 珟圚のコンテキストでは、 List super 、぀たりCollection
  6. Collectionオブゞェクトぞの#newメッセヌゞの送信は、 Object>>newによっお凊理されたす
  7. Object>>newメ゜ッドには、既知のクラス公理のオブゞェクトを垞に返すプリミティブ7が含たれたす。

さらに、匏は逆の順序で折りたたたれ、「 leftの倉数はListクラスのオブゞェクトによっお初期化されたす」ずいうステヌトメントに぀ながりたす。

倉数のクラスleftずrightを知っおいれば、メ゜ッドの残りの郚分も最適化できたす。 操䜜#add: #sort: 、および#appendList:は、远加の条件なしで盎接メ゜ッド呌び出しを䜿甚しおコンパむルされたす。

実際、型の完党な掚論は私たちにずっお望たしいですが、必須ではありたせん。 倉数の型は呌び出しごずに倉わらないこずを知るだけで十分です。 そしお、最初にメッセヌゞを送信したずきの状態を正確に調べたす。 党䜓ずしお、プログラム実行䞭の型チェックを排陀し、コヌド量を削枛し、オプティマむザヌの手を離すこずができたす。

線集


この時点たで読んだこずがあるが 、 LLVMが䜕であるかに぀いおほずんど知らない人のために、Habréの倚くの非垞に良い投皿、たたはLLVMずLLVM蚀語リファレンスマニュアル ぞのHackerの玹介を読むこずをお勧めしたす。 もちろん、英語で。

そのため、LLVMは呜什のチェヌンの圢匏で蚘述されたIR衚珟を入力で受け取りたす。 呜什は、 基本ブロックず呌ばれる゚ンティティに線成されたす 。 このようなナニットの特城は、1぀の入力ず1぀の出力しかないこずです。 これは、䜜業の䟿宜䞊、意図的に行われたす。 制埡を転送する呜什を陀き、呜什はブロック内に配眮できたす。 ぀たり、条件付きゞャンプ、リタヌン、スロヌ、およびキャッチ呜什をブロックの途䞭に眮くこずはできたせん䟋倖をスロヌしない堎合、関数呌び出しは蚱可されたす。 それでもこれが必芁な堎合、この堎所のブロックは2぀に分割されるため、問題の呜什LLVM甚語ではタヌミネヌタヌず呌ばれたす は前半の末尟にありたす。 したがっお、機胜党䜓は䞀連の基本ブロックずそれらの間の遷移で構成されたす遷移呜什自䜓はアドレスではなく、制埡を転送するブロックの識別子で動䜜したす。

私たちのタスクは、メ゜ッドのバむトコヌドを読み取り、それをIRコヌドで再䜜成し、遷移ロゞックを保持し、最終的に機胜的に同等なものを取埗するこずです。 もちろん、これは単語ごずにバむトコヌドから操䜜を繰り返す必芁があるずいう意味ではありたせんが、正確性を確保する必芁がありたす。

最初の問題は、メ゜ッドのバむトコヌドが1぀の配列にたずめお曞き蟌たれるこずです。 圓然、基本的なブロックはなく、すべおの遷移アドレスは、配列の先頭からのオフセットシステムに蚘録されたす。 したがっお、最初に必芁なこずは、遷移呜什のオフセットずベヌスブロック間の察応を構築するこずです。 これは、バむトコヌドを事前に枡すこずで行われたす MethodCompiler.cppのscanForBranchesメ゜ッド

メ゜ッドの将来のブロックの「魚」を手にし、指瀺を「詰め蟌む」こずから始めたす。 スタッフィング自䜓は順番に行われたす。 メ゜ッドの最初から、Smalltalk呜什を察応するIRコヌドの操䜜に倉換したす。 プッシュ呜什は盎接゚ンコヌドされないこずを思い出しおください。代わりに、必芁な保留䞭のアクションを説明するTDeferredValue構造䜓 TStackValueも参照 を倀スタックに配眮したす。 次に、コヌドでスタックからそのような倀を削陀する操䜜に出くわすず、保留䞭のアクションを実行し、既に䜿甚可胜な実際の名前を取埗したす。 倧半の堎合、アクションは数呜什だけ延期されるため、コヌド内の操䜜の実際の䜍眮は倉わりたせん。 実際、䞭間倀たたはコンテキストスタックの䜿甚を必芁ずせずに、コヌド内の2぀の堎所の論理バむンディングがありたす。 珟圚のコヌドの倀の転送がどのように正確に実装されるかは、LLVMによっおすでに決定されおいたす。

たずえば、バむトコヌドで次の堎合
 "left <- List new" 0023 PushLiteral 4 0024 MarkArguments 1 0025 SendMessage new 0026 AssignTemporary 0 0027 DoSpecial popTop 

...この郚分をコンパむルするずき、アクションのシヌケンスは次のようになりたす。

  1. 「スタックに4番目のリテラルを眮く」遅延操䜜を䜜成したす。
  2. markArgumentsステヌトメントでは、スタックから倀を取埗する必芁がありたす。 これにより、保留䞭の操䜜が実行されたす。名前lit0䜜成し、 lit0リテラルの配列から4番目の芁玠を読み取る操䜜をlit0たす。 この名前は、珟圚のベヌスナニットの倀のスタックに配眮したす。
  3. 1぀の芁玠の配列を䜜成し、それをargs0ずいう名前でargs0たす。 . , , ( lit0 ). , : args0[0] = lit0 .
  4. sendMessage, args0 . ( , ).
  5. temp0, . temp0 .
  6. ( popTop ).


䞀芋怖いですが、実際には、これらすべおがほんの数個のアセンブラヌ呜什でたずめられたす。特に、匕数の配列を䜜成するずき、必芁なメモリ操䜜のみを残したした。リテラルを読み取り、配列に曞き蟌み、メッセヌゞを送信し、結果を䞀時倉数に曞き蟌みたす。

同じ操䜜セットの゜フトりェアVMは、スタックを操䜜するずきにメモリの読み取りず曞き蟌みを繰り返し実行する必芁がありたす。倀をコンテキストスタックにプッシュしおすぐに倀を取埗し、匕数の配列に曞き蟌みたす。圌女は再び䜜成された匕数の配列ぞのポむンタをスタックに眮き、それをスタックから匕き出し、メッセヌゞを送信するずきにそれを䜿甚したす。その結果は数秒間だけスタックに眮かれたす。最新のプロセッサず倧胆なデヌタキャッシュでも。

私たちの囜では、匕数の配列でさえヒヌプ䞊に䜜成されたせんが、ストリヌムぞの呌び出しの実際のスタックに配眮されたす。したがっお、配列の割り圓おず充填は迅速に行われたす。最も重芁なこずは、IRで動䜜するLLVMは、盎接芋られないが適切ず考えるあらゆる皮類の最適化を自由に実行できるこずです。

たずえば、同じtemp倀が連続しお2回䜿甚される堎合がありたす。次に、倀を再読み取りする代わりに、LLVMは以前の名前を䜿甚できたすこれが結果に圱響しない堎合。そしお、そのような些现な事柄がたくさんありたす。

...コンパむラ倀スタックをロヌカルで䜿甚するオプションを怜蚎したした。ただし、移行操䜜が開始されるず、事態はさらに耇雑になりたす。

すべおのプッシュ操䜜珟圚の基本単䜍の倀のロヌカルスタックで実行されたす。スタック操䜜は非ロヌカルにするこずができたす。この堎合、倀は遷移階局の䞊䜍のブロックから削陀されたす。たずえば、2぀の基本ブロックXずYがありたす。ブロックXは操䜜pushTemporary 0ずbranch , Y. , Y markArguments 1 , . , Y . , Y X, . .

Y X 1 ..X n , φ- , SSA. X i , , . , .

, MethodCompiler::TJitContext::popValue() JITCompilation.txt .


, , « ». , , . Collection>>sort: , . , , .

, . , , . , .

, . , 10% , , — . , :

branch , Y. , Y markArguments 1 , . , Y . , Y X, . .

Y X 1 ..X n , φ- , SSA. X i , , . , .

, MethodCompiler::TJitContext::popValue() JITCompilation.txt .


, , « ». , , . Collection>>sort: , . , , .

, . , , . , .

, . , 10% , , — . , :

branch , Y. , Y markArguments 1 , . , Y . , Y X, . .

Y X 1 ..X n , φ- , SSA. X i , , . , .

, MethodCompiler::TJitContext::popValue() JITCompilation.txt .


, , « ». , , . Collection>>sort: , . , , .

, . , , . , .

, . , 10% , , — . , :

Source: https://habr.com/ru/post/J197474/


All Articles