4 ポイント 投稿者 GN⁺ 2023-11-04 | 1件のコメント | WhatsAppで共有
  • Java、Kotlin、Dart、Python、C# のような GC言語 を WebAssembly に移植する際、WasmGC は既存 VM の再コンパイルではなく、Wasm 自体の GC 構造体・配列・型システムを活用する
  • 従来の WasmMVP 移植は既存 VM と最適化を再利用しやすい一方、線形メモリ の中に GC や malloc/free を同梱するコストと、スタック参照・循環参照・断片化の制約を抱える
  • WasmGC では VM がオブジェクトとメモリを直接管理するため、バイナリサイズを削減でき、fannkuch ベンチマークでは 2.3K と C/Rust の 6.1〜9.6K より小さかった
  • WasmGC はより高水準の中間表現であるため、Binaryen wasm-opt と V8 ランタイム最適化が重要であり、Java ベンチマーク平均 1.9×、Google Sheets Calc Engine で約 30% の改善事例がある
  • 標準化とブラウザ対応は進んだものの、既存 VM をそのままコンパイルする方式ではないため、言語構造を WasmGC のプリミティブ要素へ落とし込む 新しいツールチェーン作業 が必要である

GC言語を Wasm に移植する2つの方式

  • GC言語の WebAssembly 移植は大きく2系統に分かれる
    • 従来型移植: 既存の言語 VM を、2017年に登場した WebAssembly Minimum Viable Product である WasmMVP にコンパイルする
    • WasmGC移植: GC 提案で定義された Wasm の GC 構造へ言語をコンパイルする
  • 従来型移植は、新しい CPU アーキテクチャへ言語を移植する際のように、VM のパーサー、ライブラリサポート、GC、最適化器を共有し、新しいバックエンドだけを追加するモデルに近い
  • WasmGC移植は、言語を新しいアーキテクチャではなく新しい VM に移植する方法に近い
    • Java を JavaScript にコンパイルする J2CL のように、言語オブジェクトを対象 VM のオブジェクトとして表現し、対象 VM の GC が管理する
    • WasmGC は JavaScript VM、JVM、CLR より低水準を志向するが、VM 管理の構造体・配列・型関係を提供するという点で WasmMVP より高水準である

従来の WasmMVP 移植の利点と限界

  • 既存 VM コードと言語実装、最適化をほぼそのまま再利用できる点が、従来型移植の最大の利点である
    • Python の Pyodide や C# の Blazor が代表例である
    • Blazor は AOT と JIT コンパイルの両方をサポートする
  • WasmMVP の生成物は、線形メモリ、テーブル、関数など WasmMVP の基本構造を使う
  • ブラウザ、Node.jsworkerdDenoBun のように、すでに GC を備えた VM の中で Wasm を実行することは多い
    • この環境で GC 実装を Wasm バイナリに含めると、不要なサイズ増加 が生じる
    • C、C++、Rust のように線形メモリを使う言語でも、意味のある割り当てを行えば malloc/free コードを同梱する必要がある
    • dlmalloc は 6K、サイズ重視の emmalloc でも 1K を超える
  • WasmGC では VM がメモリを自動管理するため、Wasm 内に GC や malloc/free を入れる必要がない
    • 以前の WasmGC 記事の fannkuch ベンチマークでは、WasmGC は 2.3K、C/Rust は 6.1〜9.6K だった

循環回収、スタック参照、断片化

  • ブラウザでは Wasm は JavaScript や Web API と頻繁に相互作用するが、WasmMVP と reference types だけでは、Wasm と JS 間の双方向リンクにおける細かな循環回収が難しい
    • JS オブジェクトへのリンクは Wasm テーブルにしか置けない
    • JS から Wasm に戻るリンクは、Wasm インスタンス全体を1つの大きなオブジェクトのように参照してしまうことがある
    • WasmGC は VM が認識する Wasm オブジェクトを定義するため、Wasm と JavaScript の間に適切な参照を作れる
  • GC言語は、呼び出しスコープのローカル変数のような スタック上の参照 も認識する必要がある
    • 従来型移植では、Wasm のサンドボックス化により、プログラム自身が自分のスタックを検査できない
    • 代替として shadow stack を使うか、JavaScript イベントループのターン間のように、スタックに参照がないときだけ GC を実行できる
    • 今後 Wasm に stack scanning のサポートが入れば、従来型移植の助けになる可能性がある
    • 現時点でスタック参照をオーバーヘッドなしで自動処理できる方式は WasmGC である
  • WasmMVP の線形メモリにおける malloc/free は、長時間動作するプログラムで メモリ断片化 を引き起こしうる
    • 全体として未使用メモリが十分にあっても、連続した大きなブロックがなければ大きな割り当てに失敗する可能性がある
    • 断片化により Wasm モジュールはより頻繁にメモリを拡張するようになり、オーバーヘッドや out-of-memory エラーにつながりうる
    • WasmGC では VM が GC ヒープを圧縮するためにオブジェクトを移動できるため、断片化を回避できる

開発者ツールと言語セマンティクス

  • 従来の WasmMVP 移植では、オブジェクトは線形メモリ上のバイトとして置かれるため、開発者ツールが高水準の型情報を見にくい
  • WasmGC では VM が GC オブジェクトを管理するため、ツール統合が容易になる
    • Chrome DevTools の Memory タブで WasmGC プログラムの heap snapshot を見られる
    • 連結リストの例では、$Node 型名と、次のオブジェクトを参照する $next フィールドが表示される
    • オブジェクト数、shallow size、retained size といった一般的な heap snapshot 情報も提供される
    • Chrome DevTools の debugger も WasmGC オブジェクト上で動作する
  • 従来型移植は既存 VM を再コンパイルするため、期待する言語セマンティクスをそのまま得やすい
  • WasmGC移植では、新しい GC 型である構造体や配列で言語構造を表現しなければならないため、効率化のためにセマンティクス上の妥協が必要になる場合がある
    • WasmGC の構造体フィールドは固定インデックスと型を持つため、より動的にフィールドへアクセスしたい言語は難しさを抱える可能性がある
    • WasmGC には現在 interior pointer がなく、こうした制約は今後改善されることが期待されている
  • 他の対象 VM へのコンパイル事例でも、セマンティクスの選択は存在する
    • dart2js の数値動作 は Dart VM と異なる
    • IronPython の文字列 は C# の文字列のように振る舞う
    • 一方で dart2wasm は、Wasm が Dart に必要な数値型を効率よく表現できるため、数値セマンティクスの妥協なしに動作する

WasmGC移植に必要なツールチェーン作業

  • WasmGC移植は、既存 VM を単純に再コンパイルする方式ではない
    • パーサーロジックや AOT 最適化のように、ランタイム GC と直接統合されない一部コードは再利用できる
    • 一般には、言語構造を WasmGC の構造体や配列へ落とし込む新しいコードが多く必要になる
  • Lua VM のように C で書かれた VM は数分で Wasm にコンパイルできるが、Lua の WasmGC移植では、Lua の構造を WasmGC 型システムの制約の中でどう表現するかを決めて実装しなければならない
  • WasmGC移植の大きな欠点は ツールチェーンの労力 である
  • 理想的な状態は、WasmGC 型システムがあらゆる言語を効率よくサポートし、各言語が WasmGC ポートを実装することだ
    • WasmGC 型システムの今後の追加機能が前者を助ける可能性がある
    • 共通のツールチェーン作業を共有できれば、後者の負担を減らせる

WasmGC がより最適化しやすい理由

  • WasmGC は WasmMVP より高水準の中間表現であるため、最適化の余地が大きい
  • 例の関数では、GC オブジェクトを2回割り当て、フィールドに 10 を保存して返すコードは、論理的には return 10 に縮約できる
    • WasmMVP では割り当てが malloc 呼び出しに変換され、malloc は線形メモリに副作用を持つ複雑な関数なので、最適化器は2回目の割り当てが1回目のオブジェクトフィールドを変更しないと確信しにくい
    • WasmGC では割り当てが struct.new 命令で表現され、VM の操作として推論できるため、参照やフィールド値を追跡できる
  • WasmGC は明示的な関数ポインタ ref.func、それを介した呼び出し call_ref、構造体・配列フィールド型も提供する
  • WasmMVP がネイティブに近い速度を出せる理由は、通常 LLVM のような強力な最適化コンパイラが Wasm 生成前に最適化の大半を行うためである
  • LLVM は WasmGC をサポートしておらず、多くの GC 言語も LLVM を使わないため、WasmGC には別の最適化モデルが必要になる

Binaryen と wasm-opt 最適化

  • WasmGC は一般目的の最適化を Wasm へ落とした後に実行できるため、複数の言語ツールチェーンが共通の Wasm-to-Wasm 最適化器を共有できる
  • V8 チームは WebAssembly ツールチェーン最適化プロジェクト Binaryen の WasmGC サポートに投資している
    • 各ツールチェーンは wasm-opt コマンドラインツールで Binaryen を利用できる
  • Binaryen は既存の WasmMVP 向けに、インライン化、定数伝播、デッドコード削除といった最適化をすでに備えており、その多くは WasmGC にも適用できる
  • WasmGC 向けに追加された主な最適化は以下の通り
  • Binaryen の新しい GC 最適化と使い方は Binaryen docs にまとめられている
  • J2Wasm の出力で Java の性能を測定したところ、wasm-opt は各ベンチマークで速度を向上させ、平均で 1.9× 高速化した

V8 における WasmGC 最適化

  • GC言語は、C、C++、Rust のようにコンパイル時インライン化へ大きく依存する言語とは性能モデルが異なる
    • Java や Dart のような GC 言語では、通常 VM がランタイムでインライン化と最適化を行う
  • Java では、すべての呼び出しは最初は間接呼び出しとして始まる
    • 子クラスは親の関数をオーバーライドでき、親型参照から子を呼び出す場合も同様である
    • ツールチェーンが間接呼び出しを直接呼び出しへ変換できれば有利だが、実際の Java コードには静的に直接呼び出しと推論しにくい経路が多い
  • V8 は WasmGC 向けに speculative inlining を実装している
    • ランタイムで間接呼び出しを観察する
    • 特定の呼び出し地点が少数の呼び出し先に偏るなど単純な振る舞いを示せば、ガードチェック付きでインライン化する
  • Google Sheets Calc Engine はスプレッドシート数式を計算する Java コードベースで、従来は J2CL で JavaScript にコンパイルされていた
    • V8 チームは Sheets と J2CL と協力して、このコードを WasmGC に移植した
    • このコードでは speculative inlining が、V8 が WasmGC に実装した単一の最適化の中で最大の効果を示した
    • 30% の高速化となり、測定可能な他の最適化をすべて合わせたものより大きな改善を見せた
  • V8 のその他の WasmGC 最適化には、load elimination、type-based optimizations、branch elimination、constant folding、escape analysis、common subexpression elimination などが含まれる
  • WasmGC の型情報はランタイム最適化にも利用される
    • ref.test が特定型の検査を通過したなら、同じ型への ref.cast は成功するはずである
    • Java の instanceof の後のダウンキャストのようなパターンでキャストを削除できる
  • WasmMVP ではツールチェーン最適化と VM 最適化の役割分担が比較的明確だったが、WasmGC では GC 言語の特性と WasmGC 表現の最適化可能性により、ツールチェーン最適化と VM 最適化の領域がより重なりうる

現在の状況と出発点

  • WasmGC は W3C で phase 4 に到達し、完全かつ最終化された標準となっている
  • Chrome 119 は WasmGC サポートを含む
  • Firefox 120 も同月末に WasmGC サポート付きでリリースされる見込みである
  • Flutter demo では、WasmGC にコンパイルされた Dart が、ウィジェット、レイアウト、アニメーションを含むアプリケーションロジックを駆動している
  • WasmGC をサポートするツールチェーンは以下の通り
  • 開発者ツール節の小さな例 ソースコード は、手書きの “hello world” WasmGC プログラム例である
    • $Node 型定義と struct.new を使った生成方法を確認できる
  • Binaryen wiki では、コンパイラが最適化しやすい WasmGC コードを出力する方法を扱っている

1件のコメント

 
GN⁺ 2023-11-04
Hacker Newsのコメント
  • WASMは薄い腰(thin waist)の例に見え、ガベージコレクタまで加われば、N×MではなくN+Mの構造になる。つまり、N個の言語 + M個の仮想マシン + G個のガベージコレクタへ進めるし、V8にはすでに成熟したガベージコレクタがある。
    WASMからJVMへ行くツールがあるのか気になっていたが、GitHubに1つあった。自分で使ったわけではなく、JVMにも成熟した並列ガベージコレクタがあるので探してみたもの。
    WASMGCがこんなに早く出てくるとは思っていなかったので、今では入出力の並行性だけでなく、本当の並列性のための
    WASM Threads
    にも期待している。
    非同期、並列性、ガベージコレクションを効果的に解決する機会が得られれば、WASMはさらに強くなり、開発者にとって混乱や難しさの源にならずに済むかもしれない。WASIが重要なのも、POSIXと同じくらい安定したAPIを定義する機会だからだと思う。
    1: https://www.oilshell.org/blog/2022/02/diagrams.html
    2: https://github.com/cretz/asmble

    • https://github.com/cretz/asmbleはうまく動作するが、ほとんどは趣味で作ったプロジェクトで、今は事実上メンテナンスしていない。
      WASMの中間表現をJVMバイトコードへどうマッピングしたかについてのアイデアや説明が、より公式な実装を作る人の役に立てばいいと思う。現在、WASM GCサポートの計画はない。
    • GraalVMはWASM実行ファイルを実行できる: https://www.graalvm.org/latest/reference-manual/wasm/
    • 22年遅れでCLRの足跡をたどっているわけだ。
      「20社を超えるプログラミングツール企業が、C++、Perl、Python、Java、COBOL、RPG、Haskellを含む約26のプログラミング言語を.NETで提供している」
      出典: https://news.microsoft.com/2001/10/22/massive-industry-and-d...
    • 少し厳密に言うなら、JVMはガベージコレクタ群よりも大きな概念だ[^1]。ただし、JVMがガベージコレクションの実験場になってきたのは確か。
      学界がJVMにことさら大胆だったというより、JVMプログラムが広く使われ、単一のガベージコレクション手法に圧力をかけるような形でよく使われていたからだ。
      [^1]: https://www.baeldung.com/jvm-garbage-collectors。Azul JVMにも別の独自のガベージコレクタがある。これは私が知っているものだけで、抜けているものもかなりあるはず。
    • 厳密に言えば、スレッドが提供するのは並行性であって、必ずしも並列性ではない。だから本当の並列性と呼ぶのは奇妙に聞こえる。
      コルーチンと比較して言っているのだと思うが、コルーチンは逐次的だ。実行順序は任意になり得ても、同時には実行されないと依存できる。
      wasmがスレッドを採用するなら、また一つ残念な「Worse is Better」の状況になりそうだ。スレッドは、私たちが考案した並行性モデルの中でも最悪に近い。もちろん、concurrent COMEFROMのようなものは別として。
  • Julia WASMツールは、この機能をサポートする、あるいは必要とするアプリを作れる。たとえばODEソルバーをWASMにコンパイルする例が https://tshort.github.io/WebAssemblyCompiler.jl/stable/examp... にある。
    すぐに動作させるにはChrome v119が必要で、このバージョンで初めてガベージコレクションサポートが有効化されたため。WASMコンパイラのトップページ https://tshort.github.io/WebAssemblyCompiler.jl/stable/ にさらに詳しい内容がある。

    • 本当に大きな前進だ。
      新しい Memory{T} 型のおかげで、より多くのコードをコンパイルできるようになるといい。
  • wasm は新しい LLVM」という感じがする。同じように感じている人がいるのか気になる。
    何をしようとしているのかは理解しているし、その力を示すデモも見たが、大半は依然として技術的にかなり低レベルで、実際に使うにはかなり面倒になることが多い。
    現在の方式の代わりにターゲットとして選ばれるほど、より広く採用される準備が整うのはいつ頃だと見ているのか気になる。

    • LLVM は仮想マシンではないが、WASM は仮想マシンである。
      名前のせいでよくある誤解が生じるが、LLVM は初期には仮想マシンを意図していたものの、実際にそうだったことはなく、今もそうではない。ホームページの最初の文でもそれを明確にしている: https://llvm.org/
      基本的には、時間とともに変化する中間表現を実装した C++ ライブラリ群であり、コンパイラを書くのを助けるツールである。
      10年ほど前、Google に WASM と似た領域を狙ったプロジェクトがあったが、この誤解をしていたように思う。LLVM を仮想マシンだと考えていたのだ。おそらく PNaCl のようなものだった。
      LuaJIT が Lua 5.1 で Lua を固定したのと少し似ている。Lua は標準ではなかったが、再実装のために特定バージョンを固定することはできる。ただし、そのアプローチには明らかな問題があり、再実装する側が一緒に時間の中に固定してしまうバグをすべて把握しているわけではないという点だ。
      WASM の「妥協」には眉をひそめたこともあるが、疑いようのないことが一つある。WASM は実際に仮想マシンだという点である。
      WASM GC の発表を見たが、作った人たちは妥協点を率直に話していた。たとえば初期にはランタイムキャストが必要で、測定されたオーバーヘッドは妥当な水準だ、という具合だ。こういう姿勢はむしろ信頼を与える。
      https://old.reddit.com/r/ProgrammingLanguages/comments/17crk...
    • 似たような質問をしようと思って来た。
      正直、wasm がよく分からない。私たちが正確にどんな問題を解こうとしているのかが明確ではない。
      目標が、JavaScript や JavaScript に変換されたコードではない言語でアプリケーションを書くことなのか気になる。それがブラウザの DOM 表示レイヤーと相互作用する部分まで含むのかは分からない。私の理解では、実際にはそれはできないように思うのだが、もしそうなら目標は Flash のように DOM 内の専用キャンバスでアプリケーションを実行することなのかも気になる。だとすると、そのニッチがどれほど大きいのか分からない。
      別のスレッドでは、Cloudflare Workers に wasm を使うという話もあった。おそらくそれが JavaScript インタプリタを通じて動作するからだろう。しかし、人々が任意のランタイムで Cloudflare Workers を書きたいなら、Cloudflare が単に別のランタイムのサポートを追加すればよいのではないかと思う。その程度の能力はあるはずだ。
      あるいは JavaScript エコシステムとの接続以外に、wasm がバイトコードとして固有に優れている点があるのか気になる。
      この技術がなぜ面白いのかを説明する入門資料を見逃した気がするが、今さら聞くのは少し気恥ずかしい。
    • wasmtime のようなものを見ると、基本的に複数の言語をサポートする非常に安全なプラグインを持つネイティブプログラムを作れる。同じ方式でブラウザでも、基本的なセキュリティモデルを維持しながら動作する。
      LLVM は相当なコーディングなしには「基本的に簡単なセキュアサンドボックス」を提供しない。wasmer には LLVM バックエンドがあるにはあるが、個人的にはこの点が WASM の最大の差別化要因だ。
    • 「WASM が新しい LLVM」というより、WASM が新しい JVMに近い。
    • 「wasm は新しい Emscripten」に近い。すべてのブラウザにまたがる、はるかに公式化された標準だ。
      LLVM と同じ方向には進んでいるが、まだそこからはかなり遠い。
  • どれほど素晴らしく、多くの可能性を開くものだとしても、今日のブラウザが極度に複雑で、自作するための参入障壁がほとんど高すぎるという事実を考え続けてしまう。

    • 自分でブラウザを作る難易度曲線は高すぎるどころか、文字どおり不可能だ。OS 全体を作るほうがブラウザよりずっと簡単だ。
    • Google と Apple でさえゼロから始めたわけではなく、WebKit、つまり KDE KHTML を使った。
    • 自分で Linux を作るのも不可能だが、それについて皆が不平を言うわけではない。Android が簡単に自作できないからといって非難もしない。
      世界で最も成功し、アクセスしやすいハイパーメディアプラットフォームが、なぜ簡単に実装可能でなければならないのか分からない。当然ながら、世界で最も成功したオンラインシステムは複雑で機能が多い。だから私たちはそれを使い、だからそれは勝利したのだ。
    • その通りだが、この作業はブラウザエンジン全体なしで実行できる、より単純な代替ランタイムの基盤になる。V8 に依存する Node や Deno を考えればよい。
    • 現代の多くのものはすでにこの地点に達している。自分で車を作ることはできないし、家も完全にゼロから自分で建てるのは事実上不可能だ。建築基準法のような専門知識があまりにも多く必要になる。
  • これが最終的に作られてリリースされたのは印象的。WASM に GC を入れるという計画は何年も前から聞いていたし、本当に実現するのか確信がなかった
    WASM をターゲットにする言語のうち、ランタイムを含めるためにバイナリが大きくなる問題があるものに、どれほど役立つのか気になる。記憶では Blazor は hello world だけでも 1MB くらい必要だったが、WasmGC がこれに役立つのかは分からない

    • WasmGC が .NET で実用的になるまでには時間がかかるかもしれない。議論によると、最初のバージョンの WasmGC にはいくつかの .NET 特有のシナリオを扱う良い方法がなく、それらのシナリオは「post-post-mvp」に分類されている [0]
      もちろん心配なのは、.NET だけが必要とする機能なら、追加する動機があまり大きくない点。その段階では、特定の GC バージョンをキャッシュしておき、別の WASM アセンブリからロードできるような include 的な機能のほうが、苦痛を生むとしてもより有用かもしれない
      [0] - https://github.com/WebAssembly/gc/issues/77
    • Chrome の Wasm チームは、処理中にデータ構造を割り当てる Fannkuch ベンチマークを C、Rust、Java でコンパイルした。C と Rust のバイナリはコンパイラフラグによって 6.1K から 9.6K で、Java 版は 2.3K とずっと小さかった
      C と Rust はガベージコレクタを含まないが、メモリ管理のためにそれでも malloc/free を同梱する必要がある。ここで Java がより小さい理由は、メモリ管理コードをまったく同梱する必要がないから
      https://developer.chrome.com/blog/wasmgc/
      Blazor の場合は GC にだけ効くだろう。記憶では Blazor は dotnet ランタイム全体を一緒に送る必要がある
  • Kotlin の新しい wasm サポートにはかなり期待している。ブラウザをターゲットにできる Compose Multiplatform の実験版があり、これは WASM を使う予定
    Compose Multiplatform は基本的に、Android 向けの Google Jetpack Compose に他プラットフォーム対応を加えたもの
    数日前の時点で iOS 対応はアルファで、来年ベータになる予定。Android とデスクトップ対応はすでに安定版になった。これらが安定すれば、実質的にどのプラットフォームでも動く UI アプリケーションを書ける
    wasm コンパイラは Kotlin の次のメジャーリリースである Kotlin 2.0 と一緒にリリースされる予定で、そこには新コンパイラ k2 が含まれる。来年初めごろには可能になりそう。k2 は現在ベータとして提供されており、Kotlin 1.9.x で有効化できる
    Kotlin マルチプラットフォームエコシステムの利点は、すでに複数プラットフォームで動作するライブラリが多いこと。したがって wasm コンパイラもすぐにその一部となり、良いライブラリ群を引き継ぐだろう。概ねビルド設定をそのエコシステム向けに変え、不足しているプラットフォーム別の動作を実装すればよい
    この領域でもう一つ興味深いのは、異なる言語で書かれたライブラリを使い、つなぎ込むこと。たとえば多くのプラットフォーム別部分は、すでに存在する C や Rust のライブラリに依存する可能性が高い。多くの場合、Kotlin Native が使っているのと同じライブラリかもしれない

    • Web で Compose Multiplatform がどう動くのか気になる。Flutter のように Canvas に描画する方式なのだろうか
      デスクトップ、Web、iOS、Android で同じウィジェットを使うのかも気になる。Android ではネイティブだというのは理解している。他のプラットフォームでは別のスタイルを模倣するのか分からない。核心的な疑問は、Android 以外のプラットフォームで Compose Multiplatform アプリの感触がどんなものかということ
      たとえば Web の Dart は個人的には非常にもたつく感じがあり、デスクトップの Electron もそう。デスクトップの Dart は悪くないが、アプリは全体的にボタンや余白が大きく、本物のネイティブアプリというより、エミュレータ上で動く Android アプリのように感じる
      新しいプロジェクトに Kotlin を言語として勧められるのかも気になる
    • 試すたびに Gradle の混沌のせいで熱意がそがれた
  • このブログ記事と Chrome の発表記事がなぜ Go に言及していないのか、説明できる人がいるのか気になる
    Go もガベージコレクションを使うのに、この変更の恩恵を受けられないという印象を受ける

    • WasmGC は**内部ポインタ(interior pointer)**をサポートしていないので、Go が恩恵を受けるのは難しい。少なくとも fat pointer のような不格好な方法なしには難しい
  • ランタイムが C/C++/Rust から利用できる組み込みのアロケーションライブラリを公開するのは理にかなっているのか気になる
    プログラムは自前のアロケーションライブラリを同梱する代わりに、そのライブラリを選べるはず

    • 空間を少し節約するという実用的な観点では理にかなうかもしれない。しかし設計の観点では、すでにできないことを可能にする「最小限必須の機能」ではないため、標準の一部として定めると理由もなく肥大化するだけになる
      Wasm GC のプリミティブ機能は、できるだけ小さな追加で最大の改善を得られるよう設計されている。SIMD のような他のプリミティブ機能が追加される場合も、その機能を実現するための「おおむね最小のプリミティブ機能」だからだ。ここでは、できるだけ小さなビルディングブロックが必要になる
      しかし malloc/free のようなメモリアロケータ APIは最小機能ではない。メモリアロケータは実際にはポリシーと設計上の判断の束であり、アルゴリズムはそこから導かれる。その領域の基本的なビルディングブロックは「アロケータが所有する線形メモリ片」であり、それは WASM が初日から持っていた線形メモリだ
      個別のランタイムがこれを提供するのは理にかなうかもしれない。たとえば組み込みの wasm import に線形メモリの一部を渡し、ランタイム実装のアロケータに処理させる方式だ。しかし標準化される可能性はほとんどないと思う。また、GC のない Wasm 言語向けツールの多くは、既存コードベースとそのアロケータを移植する方式に合わせて作られている。結局、単発の実装のために保守すべきコードが増えることになり、投入した労力に見合わないかもしれない
    • そのアプローチの難しさは、アロケーションライブラリの挙動が標準化され、決定的でなければならない点にある
      決定的でなければ、プログラムの挙動の差が重要になり得る。たとえば、あるブラウザがメモリをよりうまく再利用する「賢い」アロケータを入れた場合、他のブラウザでは線形メモリの断片化でメモリ不足になるプログラムが、そのブラウザでは成功するかもしれない。ブラウザは歴史的に、こうした差を避けるため挙動の標準化に非常に力を注いできた
      malloc/free 実装の挙動を標準化するのも、いくつかの理由で厄介だ。第一に、free list をどう扱うか、どのチャンクサイズを使うかなど、複雑性が大きい。仕様に入れるには多すぎる。第二に、特定の挙動を標準化すると改善できなくなるが、より良い malloc/free のアイデアは今も出てきている
      こうした理由から、これが wasm 仕様に入る可能性には懐疑的だ
      一方で GC はこうした問題を避けられる。ポインタ値が観測可能ではないため、仕様化すべきことがない
    • これは賢い方向性のように聞こえる。alloc と関連関数をランタイム関数として追加し、従来型のコードがそれを呼び出せるようにして、どんな GC でもその上に積み上げられるようにすればよい
  • この方向性には少し懐疑的です。WebAssembly の複雑さを大きく高めています
    ガベージコレクタは漏れのある抽象化です。内部ポインタをサポートするものもあれば、しないものもあります。メモリを共有する並列処理をサポートするものもあれば、そうでないものもあります。圧縮が必要なため C FFI がより難しくなるものもあれば、そうでないものもあります。グリーンプロセス/スレッドや拡張可能なスタックに使われる仕組みと深く統合する必要があるものもあれば、そうでないものもあります
    Erlang、JavaScript、Python、Go のような言語を見ると、言語レベルでの選択がある程度ガベージコレクタに反映されています
    複数の言語をサポートする汎用/一般的な仮想マシンというアイデアは、JVM、CLR、Parrot などで何度も試みられてきましたが、成功は限定的でした。今回は何が違うのか気になります

    • 今回違うのは、WASM が Sun JVM や Microsoft CLR が試みた方式と時間的な順序を逆転させたことです
      JVM/CLR はまず仮想マシン、中間言語命令仕様、ランタイムを作り、その後できるだけ広く配布して、普遍的なクライアントでの採用を期待しました。つまり「中間言語 VM」があまりに魅力的なので業界全体に広がるだろう、という期待でした。この期待は部分的にしか当たりませんでした。JVM/CLR はデスクトップとサーバーには広がりましたが、Web ブラウザでは Java Applet と Microsoft Silverlight が失敗し、モバイルプラットフォームでも広く採用されませんでした
      WASM は逆の順序です。すでに業界全体に配布され採用されていたもの、つまり JavaScript から逆向きに出発して、「仮想マシン、中間言語命令仕様、ランタイム」を作っています
      この観点では、JavaScript といういわゆる「おもちゃの言語」は、あらゆるクライアントに先に広く配布されるための 20 年がかりのトロイの木馬でした。今や業界が「サーバー+デスクトップ+ブラウザ+モバイルに、普遍的なランタイムである JavaScript がすでにあることに気づいた人はいる? 中間言語ランタイムを作って高速化しよう」と言っているようなものです
      技術的な問題もいくつかありました。Sun JVM には生ポインタがなく、C/C++ のようなポインタベースの言語にとって高性能なターゲットになりにくく、MS CLR は macOS で使えませんでした。Silverlight の最小 CLR は例外です。しかし、こうした技術的制約よりも、JavaScript が害のないトロイの木馬のように配布されてきた時間的順序のほうが、より大きな説明力を持っています
    • JVM と CLR は、複数の言語をサポートするように設計されていたとは言いにくいです。JVM には Java という主言語があり、JVM 上で実行しようとする他の言語は、Java の型システムから離れるほど大きな負担を背負います
      Wasm は上に挙げたバイトコード形式の大半よりも低レベルです。静的型付きの構造体と配列を追加する Wasm GC や、型付き関数を取り込む function-references 提案まで含めてもそうです。Wasm GC にはタグ付きポインタ i31ref への明示的なサポートもあります
      こうした点から、Wasm GC はより低レベルであるがゆえに、上に挙げた試みよりも汎用的です
    • WASM-GC のサポートは、意図的に可能な限りシンプルに保たれています。https://github.com/WebAssembly/gc/blob/main/proposals/gc/MVP... を参照してください
      複数の言語を対等かつシームレスにサポートする「汎用」または「一般的な」VM を作ることは、WASM-GC の明示的な目標ではありません。各実装が WASM の提供する基本的なサポートの上に独自のハックや特殊なセマンティクスを必要とする可能性があると想定しており、FFI と言語間相互運用性はまったく別の問題と見なしているので、それでよいという立場です
    • 違いは、このプロジェクトの重要度だと思います
      JavaScript のガベージコレクションは今後も残り続けるでしょうし、挙げられた例の中で最もしぶとく定着したものに見えます
      多くの場合、より劣っていたとしても、他の言語やアプリケーション/ライブラリはそれに合わせる必要があります
    • wasm がしていることは、以前の試みとは違います。GC 機能は、他言語との相互運用性や、言語ランタイム実装間で開発リソースを共有するために提供されているわけではありません
      wasm は、管理メモリランタイム言語が制約のあるメモリモデルの限界に苦しまずに wasm 環境をターゲットにできるようにするため、また副次的にバンドルサイズを小さくするために GC 機能を提供しています
      wasm は、ゲスト言語の特性によりよく合うよう、より調整可能なGC パラメータをサポートする可能性があります。また、比較対象となっている汎用言語ランタイムとは異なり、言語実装者にはそもそもカスタムランタイムを作る選択肢がありません
  • 現在の WASM GC の実現可能性に関する複数の懸念がここで扱われている。英語の Google 翻訳版:
    https://habr-com.translate.goog/ru/articles/757182/?_x_tr_sl...
    原文:
    https://habr.com/ru/articles/757182/
    Java と JVM コードをブラウザ上で効率的に実行できるようにする取り組みを 10 年続けてきた TeaVM 作者の記事。https://teavm.org/
    TeaVM の既存の Java-to-JavaScript 変換は、ブラウザの JS GC を使いながらも性能がよい。WASM GC がさらに成熟して、それより速くなるかを見守るのは興味深いだろう

    • 興味深い記事。
      記事で扱われている問題についてメモを残すと、手動のシャドウスタックが必要になる問題は WasmGC で解決されている。リンク先で述べられているように、JS で動作する方式と同じである。
      try-catch がない点は、すでにブラウザにリリースされている Wasm 例外処理の提案で解決されている: https://github.com/WebAssembly/exception-handling/blob/main/...
      null チェックも大部分は WasmGC で解決されている。仕様は null 不可のローカル型を定義しており、VM は記事で触れられている手法のようにシグナルを使って最適化できる。たとえば Wizard がそうしている。
      クラス初期化は、記事で述べられているとおり難しい問題である。J2Wasm と Binaryen はツールチェーンレベルの静的解析でこれを最適化しようと取り組んでいる。最近私が作成した PR は、この方向で前進をもたらした: https://github.com/WebAssembly/binaryen/pull/6061
      記事で言及されている vtable のオーバーヘッドは問題になり得る。ただし、よい測定値はまだ分からない。メソッドディスパッチに向けた post-MVP の解決策のアイデアはいくつかあるが、まだ具体的なものはない。
      null チェックと trap については、trap の代わりに例外を投げる GC 命令のバリエーションについて議論があった。しかし測定上、現時点では大きな問題として現れていないため、優先度は低い。
      筆者がスタックウォーキング、シグナル、メモリ制御が重要な領域だと述べているのは正しい。
      全体として、WasmGC と例外処理のおかげで、現在 J2Wasm が出力する Java はかなりよい位置にある。通常は Java を JavaScript にコンパイルする J2CL より速い。それでも改善の余地は確かにある