QEMU.js: WASM を備えた本栌的なバヌゞョンになりたした

か぀お、私は楜しみのために決めたした プロセスの可逆性を蚌明する そしお、マシンコヌドから JavaScript (より正確には Asm.js) を生成する方法を孊びたす。 QEMU が実隓に遞ばれ、しばらくしお Habr に関する蚘事が曞かれたした。 コメントでは、WebAssembly でプロゞェクトを䜜り盎すこず、さらには自分自身を蟞めるこずさえアドバむスされたした。 ほずんど終わった 私はどういうわけかこのプロゞェクトを望んでいたせんでした...䜜業は進行しおいたしたが、非垞にゆっくりずしおいたした、そしお今、最近その蚘事に掲茉されたした コメント 「それで、すべおはどのように終わったのですか」ずいうトピックに぀いお私の詳しい回答に察しお、「蚘事っぜいですね」ずいう声が聞こえおきたした。 たあ、できれば蚘事にしたす。 もしかしたら誰かがそれを圹に立぀ず思うかもしれたせん。 ここから読者は、QEMU コヌド生成バック゚ンドの蚭蚈に関するいく぀かの事実ず、Web アプリケヌション甚の Just-in-Time コンパむラヌの䜜成方法に぀いお孊びたす。

タスク

QEMU を JavaScript に「どういうわけか」移怍する方法をすでに孊んでいたため、今回はそれを賢明に実行し、叀い間違いを繰り返さないこずにしたした。

゚ラヌその XNUMX: ポむント リリヌスからの分岐

私の最初の間違いは、アップストリヌムのバヌゞョン 2.4.1 から自分のバヌゞョンをフォヌクしたこずでした。 それから、これは良いアむデアのように思えたした。ポむント リリヌスが存圚する堎合、それはおそらく単玔な 2.4 よりも安定しおおり、ブランチはさらに安定しおいたす。 master。 たた、かなりの量の独自のバグを远加する予定だったので、他の人のバグはたったく必芁ありたせんでした。 おそらくそのようになったのでしょう。 しかし問題は、QEMU は立ち止たっおおらず、ある時点で、生成されたコヌドを 10% 最適化するこずさえ発衚したこずです。 ここで䜙談が必芁になりたす。QEMU.js のシングルスレッドの性質ず、元の QEMU がマルチスレッドの䞍圚を意味するものではないずいう事実 (぀たり、耇数の無関係なコヌド パスを同時に操䜜する機胜) のためです。 「すべおのカヌネルを䜿甚する」だけではありたせん) が重芁であり、スレッドの䞻芁な機胜を倖郚から呌び出せるようにする必芁がありたした。 このため、合䜵䞭に圓然の問題がいく぀か発生したした。 ただし、ブランチからの倉曎の䞀郚は、 masterコヌドをマヌゞしようずしたしたが、これもポむントリリヌス (したがっお私のブランチ) で厳遞されたものであり、おそらく利䟿性は向䞊しなかったでしょう。

䞀般的に、プロトタむプを砎棄し、パヌツごずに分解し、より新しいものに基づいお新しいバヌゞョンをれロから構築するこずが䟝然ずしお意味があるず刀断したした。 master.

間違いその XNUMX: TLP 手法

本質的に、これは間違いではありたせん。䞀般的に、「どこにどのように移動するか」ず䞀般的に「そこに到着できるか」の䞡方に぀いお完党に誀解された状態でプロゞェクトを䜜成するこずの特城にすぎたせん。 このような状況では 䞍噚甚なプログラミング それは正圓な遞択肢でしたが、圓然のこずながら、䞍必芁にそれを繰り返したくありたせんでした。 今回は、それを賢明に実行したかったのです。アトミックなコミット、意識的なコヌド倉曎 (りィキクォヌトによるず、リヌナス・トヌバルズがか぀お誰かに぀いお蚀ったように、「コンパむルされるたで (譊告付きで) ランダムな文字を䞊べる」こずはしたせんでした) などです。

間違いそのXNUMX浅瀬を知らずに氎に入っおしたった

私はただこの問題を完党に取り陀いたわけではありたせんが、今では抵抗の最も少ない道を歩むのではなく、「倧人ずしお」それを行うこずに決めたした。぀たり、TCG バック゚ンドをれロから䜜成するこずです。埌で「はい、これはもちろんゆっくりですが、すべおを制埡するこずはできたせん。TCI はそのように曞かれおいたす...」ず蚀わなければなりたせん。 さらに、これは最初は明癜な解決策のように思えたした。 バむナリコヌドを生成したす。 圌らが蚀うように、「ゲンは集たった」уもちろん、コヌドはバむナリですが、制埡を単玔に枡すこずはできたせん。コンパむルのためにブラりザに明瀺的にプッシュする必芁がありたす。その結果、JS ワヌルドから特定のオブゞェクトが生成されたすが、これにはただ必芁がありたす。どこかに救われる。 ただし、私の理解する限り、通垞の RISC アヌキテクチャでは、再生成されたコヌドの呜什キャッシュを明瀺的にリセットする必芁があるのが䞀般的な状況です。これが必芁でない堎合は、いずれにせよ、それに近い状態です。 さらに、前回の詊みから、制埡は倉換ブロックの途䞭には移されないようであるこずがわかりたした。そのため、オフセットから解釈されたバむトコヌドは実際には必芁なく、単に TB 䞊の関数からバむトコヌドを生成するこずができたす。 。

圌らはやっお来お蹎った

XNUMX 月にコヌドの曞き盎しを始めたしたが、魔法のようなキックが気づかぬうちに忍び寄っおきたした。通垞、GitHub からの手玙は、Issue や Pull Request ぞの応答に関する通知ずしお届きたすが、ここでは、 突然 スレッド内での蚀及 qemu バック゚ンドずしおの Binaryen 「圌はあんなこずをしたから、もしかしたら䜕か蚀うかもしれない」ずいう文脈で。 Emscripten の関連ラむブラリを䜿甚するこずに぀いお話しおいたした。 バむナリヌ WASM JIT を䜜成したす。 さお、私はそこで Apache 2.0 ラむセンスを持っおいるず蚀いたしたが、QEMU 党䜓は GPLv2 の䞋で配垃されおおり、互換性はあたり高くありたせん。 突然、ラむセンスを取埗できるこずが刀明したした。 䜕ずか盎しおください (わかりたせん。倉曎するかもしれたせん。デュアル ラむセンスかもしれたせん。あるいは他のものかもしれたせん...)。 もちろん、これは私を喜ばせたした。なぜなら、その時たでに私はすでに泚意深く芋おいたからです バむナリ圢匏 WebAssembly、なんだか悲しくお理解䞍胜でした。 遷移グラフを含む基本ブロックを読み蟌み、バむトコヌドを生成し、必芁に応じおそれをむンタヌプリタヌ自䜓で実行するラむブラリもありたした。

それからさらにありたした 手玙 QEMU メヌリング リストにありたすが、これは「そもそも誰が必芁ずするのか?」ずいう質問に関するものです。 そしおそれは 突然、それが必芁であるこずがわかりたした。 倚かれ少なかれ迅速に動䜜する堎合は、少なくずも次のような䜿甚の可胜性をたずめるこずができたす。

  • むンストヌルをたったく行わずに教育的なものを起動する
  • 噂によるず、オンザフラむでコヌドを生成する暩利を持぀唯䞀のアプリケヌションは JS ゚ンゞンです (これは本圓ですか?)
  • ミニ OS のデモンストレヌション - XNUMX 枚のフロッピヌ、内蔵、あらゆる皮類のファヌムりェアなど...

ブラりザのランタむム機胜

すでに述べたように、QEMU はマルチスレッドに関連付けられおいたすが、ブラりザヌにはマルチスレッドがありたせん。 そうですね...最初はたったく存圚したせんでしたが、その埌 WebWorkers が登堎したした。私が理解しおいる限り、これはメッセヌゞ パッシングに基づいたマルチスレッドです。 共有倉数なし。 圓然のこずながら、共有メモリ モデルに基づいお既存のコヌドを移怍する堎合、これにより重倧な問題が発生したす。 その埌、䞖論の圧力を受けお、それはたた次の名の䞋で実行されたした。 SharedArrayBuffers。 それは埐々に導入され、さたざたなブラりザでのリリヌスを祝い、次に新幎を祝い、そしおメルトダりンを祝いたした... その埌、圌らは時間の枬定を粗くするか粗くするかずいう結論に達したしたが、共有メモリずカりンタヌをむンクリメントするスレッド、すべお同じです それはかなり正確にうたくいきたす。 そこで、共有メモリによるマルチスレッドを無効にしたした。 その埌、再び有効にしたようですが、最初の実隓で明らかになったように、それなしの生掻も存圚したす。そうであれば、マルチスレッドに䟝存せずにそれを実行しようずしたす。

XNUMX 番目の特城は、スタックを䜿甚した䜎レベルの操䜜が䞍可胜であるこずです。珟圚のコンテキストを単玔に取埗しお保存し、新しいスタックで新しいコンテキストに切り替えるこずはできたせん。 コヌル スタックは JS 仮想マシンによっお管理されたす。 以前のフロヌを完党に手動で管理するこずにしたのに、䜕が問題なのでしょうか? 実際、QEMU のブロック I/O はコルヌチンを通じお実装されおおり、ここで䜎レベルのスタック操䜜が圹に立ちたす。 幞いなこずに、Emscipten には非同期操䜜のメカニズムがすでに XNUMX ぀含たれおいたす。 非同期化 О 通蚳者。 XNUMX ぀目は、生成された JavaScript コヌドが倧幅に肥倧化しおも機胜するため、サポヌトされなくなりたした。 XNUMX 番目は珟圚の「正しい方法」で、ネむティブ むンタプリタのバむトコヌド生成を通じお機胜したす。 もちろん動䜜は遅いですが、コヌドが肥倧化するこずはありたせん。 確かに、このメカニズムのコルヌチンのサポヌトは独立しお提䟛する必芁がありたした (Asyncify 甚に曞かれたコルヌチンがすでにあり、Emterpreter 甚にほが同じ API の実装があったので、それらを接続するだけで枈みたした)。

珟時点では、コヌドを WASM でコンパむルし、Emterpreter を䜿甚しお解釈するものにただ分割できおいないため、ブロック デバむスはただ機胜したせん (次のシリヌズで説明したす...)。 ぀たり、最終的には次のような面癜い階局構造が埗られるはずです。

  • 解釈されたブロック I/O。 そうですね、ネむティブのパフォヌマンスで゚ミュレヌトされた NVMe を本圓に期埅しおいたしたか? 🙂
  • 静的にコンパむルされたメむン QEMU コヌド (トランスレヌタヌ、他の゚ミュレヌトされたデバむスなど)
  • ゲスト コヌドを動的にコンパむルしお WASM に远加

QEMU゜ヌスの特城

おそらくすでにご想像のずおり、QEMU では、ゲスト アヌキテクチャを゚ミュレヌトするコヌドずホスト マシン呜什を生成するコヌドが分離されおいたす。 実際には、さらに少し耇雑です。

  • ゲストアヌキテクチャがありたす
  • がある 加速噚぀たり、Linux 䞊のハヌドりェア仮想化甚の KVM (盞互に互換性のあるゲスト システムずホスト システム甚)、どこでも JIT コヌド生成甚の TCG です。 QEMU 2.9 以降、Windows での HAXM ハヌドりェア仮想化暙準のサポヌトが登堎したした (詳现)
  • ハヌドりェア仮想化ではなく TCG が䜿甚されおいる堎合、ナニバヌサル むンタプリタだけでなく、ホスト アヌキテクチャごずに個別のコヌド生成サポヌトがありたす。
  • ...そしおこれらすべお - ゚ミュレヌトされた呚蟺機噚、ナヌザヌ むンタヌフェむス、移行、蚘録再生など。

ずころで、次のこずをご存知ですか: QEMU は、コンピュヌタヌ党䜓だけでなく、ホスト カヌネル内の個別のナヌザヌ プロセスのプロセッサヌも゚ミュレヌトできたす。これは、たずえば、バむナリ むンストルメンテヌション甚の AFL ファザヌによっお䜿甚されたす。 おそらく誰かが QEMU のこの動䜜モヌドを JS に移怍したいず考えおいるでしょうか? 😉

ほずんどの長幎にわたるフリヌ ゜フトりェアず同様、QEMU は呌び出しを通じお構築されたす。 configure О make。 TCG バック゚ンド、スレッド実装、その他䜕かを远加するこずにしたずしたす。 Autoconf ず通信できる可胜性を考えお、急いで喜んだり怖がったりしないでください (必芁に応じお䞋線を匕いおください) - 実際、 configure QEMU は明らかに自己蚘述されおおり、䜕かから生成されたものではありたせん。

WebAssembly

では、WebAssembly (別名 WASM) ず呌ばれるものは䜕でしょうか? これは Asm.js の代替品であり、有効な JavaScript コヌドを装うこずはなくなりたした。 それどころか、これは玔粋にバむナリで最適化されおおり、単に敎数を曞き蟌むだけでもそれほど単玔ではありたせん。コンパクトにするために、次の圢匏で保存されたす。 LEB128.

Asm.js の再ルヌプ アルゎリズムに぀いお聞いたこずがあるかもしれたせん。これは、JS ゚ンゞンが蚭蚈されおいる「高レベル」フロヌ制埡呜什 (぀たり、if-then-else、ルヌプなど) を埩元したものです。プロセッサによっお実行されるマシンコヌドに近い、䜎レベルの LLVM IR。 圓然のこずながら、QEMU の䞭間衚珟は XNUMX 番目に近いものになりたす。 バむトコヌド、苊しみの終わりがここにあるように思えたす...そしおブロック、if-then-else、そしおルヌプがありたす!.

これが、Binaryen が圹立぀もう XNUMX ぀の理由です。Binaryen は、WASM に保存されるものに近い高レベルのブロックを自然に受け入れるこずができたす。 ただし、基本ブロックずそれらの間の遷移のグラフからコヌドを生成するこずもできたす。 さお、䟿利な C/C++ API の背埌に WebAssembly ストレヌゞ圢匏が隠蔜されおいるこずはすでに述べたした。

TCG (タむニヌ コヌド ゞェネレヌタヌ)

TCG もずもずあった その埌、明らかに GCC ずの競争に耐えるこずはできたせんでしたが、最終的にはホスト プラットフォヌムのコヌド生成メカニズムずしお QEMU にその地䜍を確立したした。 抜象的なバむトコヌドを生成し、むンタプリタによっお即座に実行される TCG バック゚ンドもありたすが、今回は䜿甚しないこずにしたした。 ただし、QEMU では、関数を通じお生成された TB ぞの移行を有効にするこずがすでに可胜であるずいう事実 tcg_qemu_tb_exec、それは私にずっお非垞に䟿利であるこずがわかりたした。

新しい TCG バック゚ンドを QEMU に远加するには、サブディレクトリを䜜成する必芁がありたす tcg/<ОЌя архОтектуры> この堎合、 tcg/binaryen)、これには XNUMX ぀のファむルが含たれおいたす。 tcg-target.h О tcg-target.inc.c О 凊方する それはすべおです configure。 他のファむルをそこに眮くこずもできたすが、これら XNUMX ぀の名前から掚枬できるように、䞡方ずもどこかにむンクルヌドされたす。XNUMX ぀は通垞のヘッダヌ ファむルずしお ( tcg/tcg.h、そしおそのファむルはすでにディレクトリ内の他のファむルにありたす tcg, accel だけではありたせん)、もう䞀方はコヌドスニペットずしおのみ tcg/tcg.cですが、静的関数にアクセスできたす。

仕組みの詳现な調査に時間がかかりすぎるず刀断し、これら XNUMX ぀のファむルの「スケルトン」を別のバック゚ンド実装からコピヌし、これをラむセンス ヘッダヌに正盎に瀺したした。

ファむル tcg-target.h 䞻にフォヌムの蚭定が含たれおいたす #define-s:

  • タヌゲット アヌキテクチャにレゞスタの数ず幅はどれくらいあるのか (必芁なだけありたす。必芁なだけありたす。問題は、「完党なタヌゲット」アヌキテクチャでブラりザによっお䜕がより効率的なコヌドに生成されるかずいうこずです) ...)
  • ホスト呜什のアラむメント: x86 では、さらには TCI でも、呜什はたったくアラむメントされおいたせんが、コヌド バッファヌには呜什ではなく、Binaryen ラむブラリ構造ぞのポむンタを入れる぀もりなので、次のようにしたす。バむト
  • バック゚ンドが生成できるオプションの呜什 - Binaryen で芋぀かったすべおの呜什を含め、アクセラレヌタが残りをより単玔なものに分割したす。
  • バック゚ンドによっお芁求される TLB キャッシュのおおよそのサむズはどれくらいですか。 実際のずころ、QEMU ではすべおが深刻です。ゲスト MMU を考慮しおロヌド/ストアを実行するヘルパヌ関数はありたすが (これがないずどうなるでしょうか?)、それらは倉換キャッシュを構造䜓の圢匏で保存したす。この凊理はブロヌドキャスト ブロックに盎接埋め蟌むず䟿利です。 問題は、この構造内のどのオフセットが、小さくお高速なコマンド シヌケンスによっお最も効率的に凊理されるかずいうこずです。
  • ここでは、XNUMX ぀たたは XNUMX ぀の予玄枈みレゞスタの目的を埮調敎したり、関数を介しお TB の呌び出しを有効にしたり、オプションでいく぀かの小さなレゞスタを蚘述したりできたす。 inline-次のような機胜 flush_icache_range (ただし、これは私たちのケヌスではありたせん)

ファむル tcg-target.inc.cもちろん、通垞はサむズがはるかに倧きく、いく぀かの必須関数が含たれおいたす。

  • これには、どの呜什がどのオペランドで動䜜できるかに関する制限が含たれたす。 私が別のバック゚ンドから露骚にコピヌしたもの
  • XNUMX ぀の内郚バむトコヌド呜什を取る関数
  • ここに補助関数を眮くこずもできたすし、静的関数を䜿甚するこずもできたす。 tcg/tcg.c

私自身は、次の戊略を遞択したした。次の翻蚳ブロックの最初の単語に、XNUMX ぀のポむンタヌを曞き留めたした。開始マヌク (付近の特定の倀) 0xFFFFFFFFTB)、コンテキスト、生成されたモゞュヌル、およびデバッグ甚のマゞックナンバヌの珟圚の状態を決定したす。 最初にマヌクが付けられたのは、 0xFFFFFFFF - nどこ n - 小さな正の数。むンタヌプリタを通じお実行されるたびに 1 ず぀増加したす。 0xFFFFFFFE、コンパむルが行われ、モゞュヌルが関数テヌブルに保存され、小さな「ランチャヌ」にむンポヌトされ、そこから実行が行われたす。 tcg_qemu_tb_exec、モゞュヌルは QEMU メモリから削陀されたした。

叀兞的な蚀葉を蚀い換えれば、「クラッチ、プロガヌの心をこのサりンドにどれほど巻き蟌んでいるか...」。 しかし、どこかで蚘憶が挏れおいたした。 しかもQEMUで管理されおいるメモリだった 次の呜什぀たりポむンタを曞くずきに、以前にこの堎所にリンクがあった呜什を削陀するコヌドがありたしたが、これは圹に立ちたせんでした。 実際、最も単玔なケヌスでは、QEMU は起動時にメモリを割り圓お、生成されたコヌドをそこに曞き蟌みたす。 バッファがなくなるずコヌドは砎棄され、代わりに次のコヌドが曞き始められたす。

コヌドを研究した埌、マゞック ナンバヌを䜿甚したトリックにより、最初のパスで初期化されおいないバッファにある問題を解攟するこずでヒヌプの砎壊に倱敗しないこずがわかりたした。 しかし、埌で私の関数をバむパスするためにバッファを曞き換えるのは誰でしょうか? Emscripten 開発者がアドバむスしたように、問題が発生したずきは、結果のコヌドをネむティブ アプリケヌションに移怍しお戻し、それに Mozilla Record-Replay を蚭定したした... 䞀般に、最終的には単玔なこずに気付きたした。ブロックごずに、ある struct TranslationBlock その説明付き。 どこにあるか掚枬しおください...そうです、バッファ内のブロックの盎前です。 これに気づいお、私は束葉杖少なくずも䞀郚はを䜿うのをやめるこずに決め、魔法の数字を捚おお、残りの蚀葉を次のこずに移したした。 struct TranslationBlock、翻蚳キャッシュがリセットされたずきにすぐに参照できる単䞀リンクのリストを䜜成し、メモリを解攟したす。

いく぀かの束葉杖は残りたす: たずえば、コヌドバッファ内のマヌクされたポむンタ - それらのいく぀かは単に BinaryenExpressionRef぀たり、生成された基本ブロックに線圢に入れる必芁がある匏を調べたす。䞀郚は BB 間の遷移の条件であり、䞀郚はどこに行くかです。 さお、リルヌパヌ甚のブロックはあらかじめ甚意されおおり、条件に応じお接続する必芁がありたす。 それらを区別するには、すべおのビットが少なくずも XNUMX バむトで敎列しおいるずいう前提が䜿甚されるため、ラベルには最䞋䜍 XNUMX ビットを安党に䜿甚できたす。必芁に応じお忘れずに削陀する必芁がありたす。 ちなみに、このようなラベルは、TCG ルヌプを終了する理由を瀺すために QEMU ですでに䜿甚されおいたす。

バむナリ゚ンの䜿甚

WebAssembly のモゞュヌルには関数が含たれおおり、各関数には匏である本䜓が含たれおいたす。 匏は単項挔算ず二項挔算、他の匏のリストで構成されるブロック、制埡フロヌなどです。 すでに述べたように、ここでの制埡フロヌは、高レベルの分岐、ルヌプ、関数呌び出しなどずしお正確に線成されおいたす。 関数ぞの匕数はスタック䞊ではなく、JS ず同様に明瀺的に枡されたす。 グロヌバル倉数もありたすが、䜿ったこずがないので割愛したす。

関数には、32 から番号が付けられる、int64 / intXNUMX / float / double 型のロヌカル倉数もありたす。 この堎合、最初の n 個のロヌカル倉数が関数に枡される匕数です。 ここでのすべおが制埡フロヌの芳点から完党に䜎レベルであるわけではありたせんが、敎数にはただ「笊号付き/笊号なし」属性が含たれおいないこずに泚意しおください。数倀がどのように動䜜するかはオペレヌション コヌドによっお異なりたす。

䞀般的に蚀えば、Binaryen は次のこずを提䟛したす。 シンプルな C-API: モゞュヌルを䜜成したす。 圌の䞭で 匏の䜜成 - 単項、バむナリ、他の匏からのブロック、制埡フロヌなど。 次に、匏を本䜓ずする関数を䜜成したす。 私ず同じように、䜎レベルの遷移グラフをお持ちの堎合は、relooper コンポヌネントが圹に立ちたす。 私の理解する限り、ブロックの境界を超えない限り、ブロック内の実行フロヌの高床な制埡を䜿甚するこずが可胜です。぀たり、内郚高速パス/䜎速パスを䜜成するこずが可胜です。組み蟌みの TLB キャッシュ凊理コヌド内でパスが分岐したすが、「倖郚」制埡フロヌには干枉したせん。 リルヌパヌを解攟するず、そのブロックも解攟されたす。モゞュヌルを解攟するず、それに割り圓おられおいた匏や関数などが消えたす。 アリヌナ.

ただし、むンタプリタ むンスタンスを䞍必芁に䜜成したり削陀したりせずに、その堎でコヌドを解釈したい堎合は、このロゞックを C++ ファむルに配眮し、そこからラむブラリの C++ API 党䜓を盎接管理し、ready-ラッパヌを䜜りたした。

したがっお、必芁なコヌドを生成するには

// МастрПОть глПбальМые параЌетры (ЌПжМП пПЌеМять пПтПЌ)
BinaryenSetAPITracing(0);

BinaryenSetOptimizeLevel(3);
BinaryenSetShrinkLevel(2);

// сПзЎать ЌПЎуль
BinaryenModuleRef MODULE = BinaryenModuleCreate();

// ПпОсать тОпы фуМкцОй (как сПзЎаваеЌых, так О вызываеЌых)
helper_type  BinaryenAddFunctionType(MODULE, "helper-func", BinaryenTypeInt32(), int32_helper_args, ARRAY_SIZE(int32_helper_args));
// (int23_helper_args прОПб^WсПзЎаются ПтЎельМП)

// скПМструОрПвать супер-Ќега выражеМОе
// ... Му тут уж вы как-МОбуЎь саЌО :)

// пПтПЌ сПзЎать фуМкцОю
BinaryenAddFunction(MODULE, "tb_fun", tb_func_type, func_locals, FUNC_LOCALS_COUNT, expr);
BinaryenAddFunctionExport(MODULE, "tb_fun", "tb_fun");
...
BinaryenSetMemory(MODULE, (1 << 15) - 1, -1, NULL, NULL, NULL, NULL, NULL, 0, 0);
BinaryenAddMemoryImport(MODULE, NULL, "env", "memory", 0);
BinaryenAddTableImport(MODULE, NULL, "env", "tb_funcs");

// запрПсОть валОЎацОю О ПптОЌОзацОю прО желаМОО
assert (BinaryenModuleValidate(MODULE));
BinaryenModuleOptimize(MODULE);

...䜕かを忘れおいた堎合は、申し蚳ありたせんが、これはスケヌルを衚すためのものであり、詳现はドキュメントに蚘茉されおいたす。

そしお今、次のようなクラックフェックスペックスが始たりたす:

static char buf[1 << 20];
BinaryenModuleOptimize(MODULE);
BinaryenSetMemory(MODULE, 0, -1, NULL, NULL, NULL, NULL, NULL, 0, 0);
int sz = BinaryenModuleWrite(MODULE, buf, sizeof(buf));
BinaryenModuleDispose(MODULE);
EM_ASM({
  var module = new WebAssembly.Module(new Uint8Array(wasmMemory.buffer, $0, $1));
  var fptr = $2;
  var instance = new WebAssembly.Instance(module, {
      'env': {
          'memory': wasmMemory,
          // ...
      }
  );
  // О вПт уже у вас есть instance!
}, buf, sz);

QEMU ず JS の䞖界を䜕らかの方法で接続し、同時にコンパむルされた関数にすばやくアクセスするために、配列 (ランチャヌにむンポヌトするための関数のテヌブル) が䜜成され、生成された関数がそこに配眮されたした。 むンデックスを迅速に蚈算するために、最初はれロ単語翻蚳ブロックのむンデックスがむンデックスずしお䜿甚されたしたが、その埌、この匏を䜿甚しお蚈算されたむンデックスが単玔にフィヌルドに適合し始めたした。 struct TranslationBlock.

ずころで、 デモ (珟圚はラむセンスが曖昧です) Firefox でのみ正垞に動䜜したす。 Chrome 開発者は、 どういうわけか準備ができおいない WebAssembly モゞュヌルのむンスタンスを XNUMX 個以䞊䜜成したい人がいるずいう事実に、それぞれのモゞュヌルにギガバむトの仮想アドレス空間を割り圓おただけです...

それは今のずころすべおです。 興味のある人がいたら別の蚘事があるかもしれたせん。 ぀たり、少なくずも残りたす。 ただ ブロックデバむスを動䜜させたす。 たた、JS の䞖界では慣䟋ずなっおいるように、WebAssembly モゞュヌルのコンパむルを非同期にするこずも意味があるかもしれたせん。これは、ネむティブ モゞュヌルの準備ができるたでこれらすべおを実行できるむンタプリタが䟝然ずしお存圚するためです。

最埌になぞなぞ: 32 ビット アヌキテクチャでバむナリをコンパむルしたしたが、コヌドはメモリ操䜜を通じお Binaryen からスタック䞊のどこか、たたは 2 ビット アドレス空間の䞊䜍 32 GB のどこかに移動したす。 問題は、Binaryen の芳点からするず、結果ずしお埗られるアドレスが倧きすぎるこずになりたす。 これを回避するにはどうすればよいでしょうか?

管理者のやり方で

結局これをテストするこずはできたせんでしたが、最初に考えたのは「32 ビット Linux をむンストヌルしたらどうなるだろう?」ずいうこずでした。 その埌、アドレス空間の䞊郚はカヌネルによっお占有されたす。 唯䞀の問題は、どのくらいの量が占有されるかです。1 GB たたは 2 GB です。

プログラマヌのやり方 (実務者向けのオプション)

アドレス空間の䞊郚に泡を吹きたしょう。 私自身もなぜそれが機胜するのか理解できたせん - そこで すでに スタックがあるはずです。 しかし、「私たちは実践者です。すべおがうたくいきたすが、その理由は誰も知りたせん...」

// 2gbubble.c
// Usage: LD_PRELOAD=2gbubble.so <program>

#include <sys/mman.h>
#include <assert.h>

void __attribute__((constructor)) constr(void)
{
  assert(MAP_FAILED != mmap(1u >> 31, (1u >> 31) - (1u >> 20), PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
}

...Valgrind ず互換性がないのは事実ですが、幞いなこずに、Valgrind 自䜓は非垞に効果的に党員をそこから远い出したす :)

おそらく誰かが、私のこのコヌドがどのように機胜するかに぀いおもっず詳しく説明しおくれるでしょう...

出所 habr.com

コメントを远加したす