Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
emruby: ブラウザで動くRuby
Search
Yusuke Endoh
April 23, 2021
Programming
0
18
emruby: ブラウザで動くRuby
銀座Rails #32
https://ginza-rails.connpass.com/event/207692/
Yusuke Endoh
April 23, 2021
Tweet
Share
More Decks by Yusuke Endoh
See All by Yusuke Endoh
An Invitation to TRICK: How to write weird Ruby programs
mame
1
720
TypeProf進捗
mame
0
21
12年前の『型システム入門』翻訳の思い出話
mame
14
1.9k
Good first issues of TypeProf
mame
4
6.4k
Revisiting TypeProf - IDE support as a primary feature
mame
1
2.3k
error_highlight: User-friendly Error Diagnostics
mame
0
21
TRICK 2022 Results
mame
0
31
クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料
mame
0
30
Enjoy Ruby Programming in IDE and TypeProf
mame
0
29
Other Decks in Programming
See All in Programming
useSyncExternalStoreを使いまくる
ssssota
6
1.4k
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
4
360
fs2-io を試してたらバグを見つけて直した話
chencmd
0
240
Jakarta EE meets AI
ivargrimstad
0
280
情報漏洩させないための設計
kubotak
4
860
ブラウザ単体でmp4書き出すまで - muddy-web - 2024-12
yue4u
3
500
良いユニットテストを書こう
mototakatsu
8
3.1k
Recoilを剥がしている話
kirik
5
7.2k
テストケースの名前はどうつけるべきか?
orgachem
PRO
0
160
nekko cloudにおけるProxmox VE利用事例
irumaru
3
460
DevFest - Serverless 101 with Google Cloud Functions
tunmise
0
130
テストコード書いてみませんか?
onopon
2
210
Featured
See All Featured
How to Think Like a Performance Engineer
csswizardry
22
1.2k
Large-scale JavaScript Application Architecture
addyosmani
510
110k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
810
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
Optimizing for Happiness
mojombo
376
70k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
365
25k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
44
9.3k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
Done Done
chrislema
182
16k
Transcript
emruby: ブラウザで動くRuby 銀座Rails #32 Yusuke Endoh 1
自己紹介:遠藤侑介 (@mametter) • クックパッドで働くフルタイムRubyコミッタ • Ruby 3添付の静的解析ツールTypeProf作ってます • https://github.com/ruby/typeprof •
でも今日はぜんぜん違う話をします 2
emruby: ブラウザの上で動くRuby https://mame.github.io/emruby/ 3
emrubyの狙い • ブラウザでRubyが動くのは楽しい • 頑張ればTryRuby(お試し環境)くらいにはなるか? • 将来的にJavaScriptの代替になるかはWASM次第? • Rust /
Go / KotlinなどもWASM出力に対応してるので • おことわり • この発表にはRailsもRuby言語もほとんど出てきません • Rubyのビルドの知識が少し身につきます 4
Rubyをブラウザで動かす関連研究 • Opal: JavaScriptで書かれたRubyインタプリタ • https://github.com/opal/opal • Artichoke: Rustで書かれたRubyインタプリタ(WASM出力対応) •
https://github.com/artichoke/artichoke • repl.it: Ruby 1.8をEmscriptenしたもの(らしい) • https://github.com/replit-archive/emscripted-ruby • Ruby on WebAssembly: mrubyをEmscriptenしたもの • https://github.com/blacktm/ruby-wasm • RubyのNaClサポート(2012~2017) • よくまとまってる記事 • https://blog.unasuke.com/2021/products-about-webassembly-and-ruby/ 5
アジェンダ • ➔WASM / Emscriptenとは • emrubyが動くまで • まとめ 6
WebAssembly (WASM) • ブラウザの上で動く実行ファイル形式 • 2017年頃からメジャーブラウザが対応している • JavaScriptより速くて (?) 小さいらしい
7
Emscripten • C/C++のプログラムをWASMに変換するコンパイラ • LLVMベース • デモ一覧(古そう):https://github.com/emscripten- core/emscripten/wiki/Porting-Examples-and-Demos • http://kripken.github.io/boon/boon.html
• https://files.unity3d.com/jonas/AngryBots/ • http://coolwanglu.github.io/vim.js/emterpreter/vim.html 8
Emscriptenの基本的な使いかた 9 #include <stdio.h> int main() { printf("hello, world!¥n"); return
0; } emcc hello.c –o hello.js && node hello.js emcc hello.c –o hello.html
アジェンダ • WASM / Emscriptenとは • ➔emrubyが動くまで • まとめ 10
前提知識:Rubyのふつうのビルド • Rubyソースのディレクトリで次のコマンドを打つ • ./configure: 環境ごとにビルド方法を調整する • どのシステム関数が使えるか、コンパイラオプションが使えるか • OS、コンパイラ、バージョンなどの違いを調べる
• make: ソースコードをコンパイルする • まずminirubyという制限版ruby実行ファイルを作る • minirubyを使ってスクリプト(Rubyで書かれている)を動かし、 拡張ライブラリや最終的なruby実行ファイルを作る 11 ./configure && make
話の流れ • minirubyをWASMにする • 本当のrubyをWASMにする • 最終目標:irbを動かす? 12
./configure && makeのEmscripten化 • Emscriptenはconfigure+makeに対応している • emconfigure / emmakeはビルドをうまくだまして Emscriptenコンパイラを使わせる
• これだけ……ではない • 実用プログラムがゼロ変更でビルドできることは無いと思う 13 emconfigure ./configure && emmake make
Emscriptenが未実装のC関数に対処する • 問題:Emscriptenで利用できないC関数がいっぱいある • popenがない • pthread_createはあるがpthread_killはない • pthread_createはあるがpthread_attr_getguardsizeがない •
pthread_sigmaskはあるけど実際には動かない (!) 、など • configureの盲点をつくような未実装がいろいろあった • 対処:Rubyのconfigureを改善して対応した • コミッタなので、Ruby側を直接変更しまくった 14
Rubyは関数の引数の数にルーズだった • C言語では、関数に引数を余分に渡しても良い (!?) • C言語仕様違反だが、 多くのCコンパイラで動く • Rubyはこれに依存していた •
Emscriptenのオプションで 対応した • -s EMULATE_FUNCTION_POINTER_CASTS=1 15 int foo(int a) { printf("%d¥n", a); } int main() { int(*foo2)(int,int) = (int(*)(int,int))foo; foo2(42, 43); // 42 } 1引数の関数fooを2引数で呼び出す例
miniruby.wasmできた! • 2018年はこの段階で公開した • 残念なお知らせ • EMULATE…オプションがEmscirptenから削除された • コンパイルできなくなった •
どうしたか • 放置した → 3年経ったら、Ruby側が直っていた! • 微修正で2021年1月に再ビルドに成功した 16
話の流れ • minirubyをWASMにする • ここまでできた • 本当のrubyをWASMにする • 最終目標:irbを動かす? 17
ruby.wasmを作るには • ふつうのrubyのビルドには、minirubyが必要 • しかしminiruby.wasmはLinuxで実行できない • クロスコンパイルする • ビルド環境とはちがう環境の実行ファイルを作ること •
Linuxでruby.exe(Windowsの実行ファイル)を作る、とか • 今回はLinuxでruby.wasmを作る • emconfigureはかえってややこしくなるのでやめた 18
Rubyのクロスコンパイル • Rubyのconfigureはクロスコンパイルに対応している • minirubyの代わりにビルド環境のrubyを使ってくれる • これで一応ruby.wasmはできた • が、全然動かないのでデバッグ&ドキュメント&ソース読み 19
$ ./configure ¥ --build x86_64-pc-linux-gnu ¥ --host wasm32-unknown-emscripten ¥ CC=emcc LD=emcc AR=emar RANLIB=emranlib $ make ビルド環境 対象環境 Emscripten
問題:Rubyの保守的GC • 保守的GCとは • マシンスタックの値がオブジェクトの参照であると仮定して マーク対象とするガベージコレクタの方式 • https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%BB%E3%82%A2%E3%83%B3%E3%83%89%E3%83%BB%E3%82%B9%E3%82%A4%E3%83%BC%E3% 83%97#%E4%BF%9D%E5%AE%88%E7%9A%84%E3%81%AA%E3%82%AC%E3%83%99%E3%83%BC%E3%82%B8%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%BF •
つまり意図的にC言語仕様違反なメモリアクセスをする • Emscriptenのメモリモデルでは全然動かない • 対処:Emscriptenが保守的GC用のAPIを用意していた • emscripten_scan_stack / emscripten_scan_registers • スタックの先頭と終端がわかる、これらを使うようにした 20
余談:Fiberに対応する(未完) • Rubyは2018年末にFiberの一部をアセンブリで実装した • Emscriptenでx86アセンブリはコンパイルできないので コンパイルエラーになっていた • 対処:EmscriptenのAPIを使って実装した • emscripten_fiber_init
/ emscripten_fiber_swap • コンパイルオプション -s ASYNCIFY と合わせて使う • miniruby.wasmでは動いたが、ruby.wasmでは動かない • 原因未解明、今後の課題 • とりあえずFiber使わなければ問題ない 21
問題:動的リンクができない • つまり、拡張ライブラリの require ができない • require "ripper"したらripper.soを動的リンクする • しかしEmscriptenは動的リンクに未対応(たぶん)
• 解決:ripperを静的リンクした • 他にも必要な拡張ライブラリを色々足した 22 $ ./configure ¥ --with-static-linked-ext --with-ext=ripper … $ make
その他Emscripten特有っぽい話 • リンクが失敗する(htonsが見つからない、とか) • -lcでlibcを明示的にリンクすれば動いた • -fstack-protectorも対応してないようなので消した • すぐメモリ不足エラーになる •
Emscriptenはデフォルトでメモリサイズを固定確保する • サイズ可変にするオプションをつけた (-s ALLOW_MEMORY_GROWTH=1) • stack overflowの検出が動かないので止めた、など 23
ruby.wasmできた! • require "ripper.so"も動く • ある程度複雑なRubyスクリプトも動く 24
話の流れ • minirubyをWASMにする • 本当のrubyをWASMにする • ここまでできた • 最終目標:irbを動かす? 25
irbを動かすのに必要なもの • Rubyインタプリタ(できた) • ripper.soなどの拡張ライブラリ(できた) • irbのソースコード(あるけどまだ組み込んでない) • 端末エミュレータ(無い) 26
仮想ファイルシステム • Emscriptenのfile_packagerツールで作れる • irbやrubygemsなど必要なRubyソースコードをまとめた • fs.jsとfs.dataができた • がんばってロードできるようにした •
コンパイルオプションに-s FORCE_FILESYSTEM=1追加 • fs.jsを<script>で呼ぶだけ……なのだが意外と苦労した 27
xterm.jsを組み込む • xterm.js: ブラウザで動く端末エミュレータ • https://xtermjs.org/ • VS Codeでも使われている •
残念なお知らせ • Emscriptenは標準入出力の実装がいまいち • とりあえずの対応 • ライン編集はxterm.js側でやり、irbには行単位で送る • reline(irbの新しい編集機能)の活用は今後の課題 28
ということで https://mame.github.io/emruby/irb/ 29
CPU 100%を防ぐ • Emscriptenの生成物はほぼ同期で動く(asyncでない) • 入力待ちをポーリングでやるみたい(ゲーム想定?) • 対処:別スレッド(Web Worker)で動かすようにした •
通信方法はvim.wasmに習った(SharedArrayBuffer使用) https://rhysd.hatenablog.com/entry/2019/06/13/090519 • 残念なお知らせ:5月に動かなくなる見込み 30
ということで • (かなり妥協したけど)irbがブラウザで動いた! • rubygems、did_you_meanなども一応動いているっぽい 31
落ち穂拾い • ruby.wasmのサイズ:29 MB • コンパイルオプションで調整して8 MB • -Os: 省サイズ重視で最適化する
• -g0: デバッグ情報を省く 32
Emscripten所感 • 夢の技術ではない • 現実のC言語コードをゼロ変更でビルドできることは無い • いっぱい問題に遭遇する • が、とてもよくできている •
一生懸命調べればたいてい対処方法やAPIがある • 検索に頼らずドキュメントを通して読むのが早道 • 動いたらとても嬉しい 33
まとめ • ブラウザで動くRuby、emrubyを紹介しました • 大体Ruby側で対応したのでたったこれだけでビルドできる 34 $ ./configure ¥ --build
x86_64-pc-linux-gnu ¥ --host wasm32-unknown-emscripten ¥ --with-static-linked-ext ¥ --with-ext=ripper,date,strscan,io/console,…,psych ¥ optflags=-Os debugflags=-g0 ¥ CC=emcc LD=emcc AR=emar RANLIB=emranlib $ make
今後の予定 • ほそぼそとメンテナンスするつもり • WASMが大ヒットする日に備える • そのとき「RubyもWASM対応してます」と言いたい • RubyからJSやDOMを操作できたらいいなあ •
当面はOpalを使うのがいいと思います • WASM版TryRubyができたらいいなあ • Opalであまり問題はないですが 35