asm.jsに別れを告げる
(spidermonkey.dev)- Firefox 148からSpiderMonkeyのasm.js最適化がデフォルトで無効化され、今後関連コードが削除される予定
- asm.jsはJavaScriptのサブセットであるため既存サイトは引き続き動作するが、通常のJIT経路で実行されるため最適化の利点は失われる
- asm.jsコンテンツはWebAssemblyへ再コンパイルすることで、より高速な実行とより小さなバイナリを得られる
- asm.jsはNaCl・PNaClに対抗し、別個のサンドボックスや代替APIなしでWebコンテンツ内でネイティブに近い実行を可能にした
- 2013年にFirefox 22へ導入されたOdinMonkeyは、Unity・UnrealのようなC/C++のWeb配布を可能にし、WebAssemblyへとつながる土台となった
asm.js最適化の無効化
- Firefox 148からSpiderMonkeyのasm.js最適化がデフォルトで無効化され、今後のリリースで関連コード全体が削除される予定
- asm.jsを使うサイトは引き続き動作する
- asm.jsは通常のJavaScriptのサブセットであるため、既存コードは他のスクリプトと同様に通常のJIT経路で実行される
- ただしasm.js専用の最適化の利点は失われる
- asm.jsコンテンツを引き続き配布しているなら、WebAssemblyへ再コンパイルすることが推奨される
- WebAssemblyへ再コンパイルすれば、より高速な実行とより小さなバイナリを得られる
- SpiderMonkeyのWebAssemblyパイプラインはasm.jsパイプラインよりもはるかに進化している
- WebAssemblyが成功し、asm.jsの利用の大半がすでに移行したことで、両方の経路を同時に維持するコストが大きくなっている
- 保守に継続的な時間が必要
- VM内に追加の攻撃面が残る
asm.jsの役割とOdinMonkeyの終了
- asm.jsは、NaClとPNaClが投げかけた「Web上でコードをネイティブ速度で実行できるか」という問いに対するMozillaの答えだった
- エンジンがその場で認識できる、厳格で静的型付けされたJavaScriptのサブセットを選び、ネイティブコードへコンパイルする方式
- 別個のサンドボックス、IPC、代替APIなしにWebコンテンツ内にとどまり、既存のWeb APIを利用できた
- asm.jsは2013年にFirefox 22へ組み込まれ、UnityやUnrealのようなプロジェクトが標準Web技術だけでC/C++コードベースをWebへ配布できるようにした
- Epic Citadel demoは4日でWebへ移植された
- asm.jsは、標準Web技術だけでほぼネイティブに近い速度のコードを実行できることを実証し、その後のWebAssemblyへの道を開いた
- WebAssemblyは数年後にFirefox 52へ組み込まれ、asm.jsがなければWebAssemblyも存在しなかった可能性が高い
- asm.jsコンパイラの名前はOdinMonkeyで、削除作業はRagnarökバグで「Twilight of OdinMonkey」として追跡されている
- OdinMonkeyから生まれたBaldrMonkeyはWebAssembly最適化コンパイラ
- RabaldrMonkeyはWebAssemblyベースラインコンパイラ
- OdinMonkeyは13年にわたる役目を終え、終了の段階に入る
1件のコメント
Hacker Newsのコメント
asm.jsは、NaClとPNaClが投げかけた「Webでネイティブ並みの速度でコードを実行するには?」という問いに対するMozillaの答えだった。
今だったらChromeはNaClとPNaClをそのまま押し通していて、そうなればみんなSafariとFirefoxがなぜ「Web」標準に追従できないのかと文句を言っていた気がする。
しばらくの間、すべてをブラウザでやるようになると本気で思っていた。ある意味ではだんだんそうなっているが、全体的な体感はこれまでになく悪くなった。WASMは好きだし好きでいたいが、エコシステムの成熟速度は信じがたいほどひどい。
さらに悪いのは、信頼できないAIツールとその出力をまさにそういうサンドボックスの中で実行しなければならないのに、企業はその正反対のホスティングされたサンドボックスやホスティングされたJSベースVMを売っていることだ。
結局、問題はいつも同じだったように思う。クライアント側サンドボックスには金がなかった。
内部的にはFlashプレイヤーをサンドボックス化するのに有用だったが、LLVMベースのアプローチの限界はすぐに関係者全員に明らかになった。
記憶が正しければ、失敗した大きな理由はNaClがあまりに「大きい」技術で、asm.jsがあまりに「小さい」技術だったため、asm.jsのほうが数年遅く始まったにもかかわらず先に本番投入可能な状態に到達したからだ。
ただAppleは規制問題が本格化して以降、この10年でWebKitへの投資を増やしたようなので、今なら結果は違うかもしれない。
だから当時は不満が少なく、今はApp Storeに不利益だという理由でSafariがやらないことに対して不満が出ている。幸いEUは今やAppleをある程度正そうとしている。
悲しいけれど納得はできる。面白いことに、Figmaはもともと完全なC++コードベースとして始まり、asm.jsはデザインツールをブラウザで動かせることを証明するうえで中核だった。
WebAssemblyへ移行したのは有料顧客がついてからで、ロード時間の改善もかなり大きかった。asm.jsは依然としてJSなのでバンドルサイズが大きく、コードをASTとしてパースしなければならないが、WASMはそうではない。
i386-unknown-freebsd1のサポートが外れたことを悲しむのと似たようなものだ。
ついにasm.jsの死が来たのか? 予言の時間線から遠ざかっている。
https://www.destroyallsoftware.com/talks/the-birth-and-death...
まだ見たことがないなら強くおすすめする。「最高」の定義次第では、史上最高の技術講演かもしれない。
いつか戦争の時代を経て、古いプログラミングパラダイムへの心理的執着がほどければ、もっと進歩したやり方に移れるだろう。もちろん、それであなたの銀行が今後少なくとも85年間YavaScriptを動かさなくなるわけではないが。
Gary BernhardtのJavaScript講演を見た瞬間は絶対に忘れない。[0] あれでasm.jsを初めて知り、ブラウザで動くようにコードをコンパイルするというウサギ穴にもはまった。
それから12年経った今、彼のフィクションのどれだけが現実になったのかに驚かされる。
[0] https://www.destroyallsoftware.com/talks/the-birth-and-death...
あの講演を初めて見たとき自分はインターンで、会社は小さな産業用IOボックス向けにコンパイラ、IDE、デバッガをすべて自作していた。コンパイラはCで書かれていて、EmscriptenでJSに変換したあと、IDEとデバッガ部分と一緒に巨大なHTMLファイルへ「コンパイル」(実質的には連結)していた。コードのアップロードとデバッグはイーサネット経由で行い、全部Ajaxで流し込んでいた。
呪われた構成のように聞こえるが、顧客は気に入っていた。EXEではなかったので、顧客企業の過剰な企業ITフィルタに引っかからなかったからだ。だからElectronには移行しなかった。ある意味では、厚いアプリの原始的な要素を備えていたわけだ。
かなり前にWebGLの本でasm.jsに関する短い章を書いたことがある。
https://webglinsights.github.io/
WebAssemblyの前身だったasm.jsの台頭を見るのは楽しかった。初期デモには、ブラウザでUnreal Engineが動くような本当にすごいものもあった。ここで日が沈むのを見るのはほろ苦いが、はるかに良いものへとつながった。
asm.jsからWASMへのトランスパイラが必要かもしれない。
レガシー版Emscriptenでレガシーコードをコンパイルするのはかなりつらい。積み重なったEmscripten ABI変更に合わせてJSコードを更新するのと同じくらい苦痛なこともある。
少なくともasm.js最適化が無効になってもasm.jsコード自体は動き続けるだろうが、変換器があれば助かる。
asm.jsは死んだ! WebAssembly万歳!
個人的には、この決定は間違いだと思う。ただ実際の影響がどれほど大きいかはわからない。自分の知る限り、まだasm.jsを使っている人は多くない。
ただ、wasmはJavaScriptからあまりにも隔離されている。少し使ってみたあと、いっそasm.jsにコンパイルしてみようかと考えた。
Emscriptenがまだ完全に対応しているのかも確信が持てなかった。
wasmではほとんどのWeb APIを呼び出せない。
自分がやろうとしていた作業ではもっと重要なことに、JSからwasmへゼロコピーのバッファを渡せない。
すべてはトレードオフだ。隔離は利点でもあるが欠点でもある。
一方で今どきのwasmにはGC型があり、externrefでJSの値を保持することもできる。
asm.jsでもゼロコピーのバッファは無理な可能性が高い。wasm側にはゼロコピーバッファの提案がある: https://github.com/WebAssembly/memory-control/blob/main/prop...
厳格なasm.jsでも、ほとんどのWeb APIを直接呼び出すことはできない。数値しか扱えず、JSの文字列やオブジェクトは扱えないし、CヒープをWASMと同様にArrayBufferオブジェクト内で管理しているからだ。
ゼロコピーバッファも同じ問題だ。asm.jsから「本物の」JavaScriptへ抜けて呼び出す必要があり、別のArrayBufferをasm.jsヒープに直接マップすることもできないので、コピーが必要になる。「JavaScript FFI」はasm.jsとWASMの間で実質的に大差ない。
Mozillaがasm.jsコードに極端に特化したOdinMonkeyを公開したときのことを覚えている。Chrome/V8チームはその代わり、一般的なJavaScriptをより速く実行しつつasm.jsにも恩恵のある汎用JIT最適化に注力していた。
速度差はFirefoxが2〜4倍有利で、それをかなり大々的に宣伝していた :D
今ではほとんどのブラウザJavaScript VMが非常によく似た設計と最適化へ収束しているので、Odinがなくてもasm.jsコードはどうせかなり速く動くだろう。
実行時にJSコードを生成してアルゴリズムを高速化しようという自分の計画は消えた。これをwasmでやるのはずっと難しそうだ。
テスト用にそうした作業のかなりの部分を扱う小さなライブラリがある: https://searchfox.org/firefox-main/source/js/src/jit-test/li...
JSならおそらく https://www.npmjs.com/package/binaryen を使うことになる。
https://www.assemblyscript.org/
ただしasm.js専用パイプラインのように高速にパースされたり実行されたりはしないだろう。極端に巨大なアプリケーションでなければ、差を大きく感じることはないと思う。