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
64
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
emruby: ブラウザで動くRuby
銀座Rails #32
https://ginza-rails.connpass.com/event/207692/
Yusuke Endoh
April 23, 2021
More Decks by Yusuke Endoh
See All by Yusuke Endoh
Practical TypeProf: Lessons from Analyzing Optcarrot
mame
1
3.2k
型システムを知りたい人のための型検査器作成入門
mame
15
5.4k
TRICK 2025 Results
mame
0
5.8k
Writing Ruby Scripts with TypeProf
mame
1
1.5k
An Invitation to TRICK: How to write weird Ruby programs
mame
1
1.4k
TypeProf進捗
mame
0
130
12年前の『型システム入門』翻訳の思い出話
mame
14
2.8k
Good first issues of TypeProf
mame
4
10k
Revisiting TypeProf - IDE support as a primary feature
mame
1
3.9k
Other Decks in Programming
See All in Programming
Discordを用いたラボオートメーション関連情報収集の自動化
noguhiro2002
0
430
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
170
AIの中の人になってみる
htkym
0
120
「つくるAI」だけではバグは見つからない ~テストに必要な「見つけるAI」を分離させる戦略~
mfunaki
0
180
Loosening the Reins: Go Generics Get More Flexible
kuro_kurorrr
0
330
源内ハンズオン概要編
hideg
0
210
30年振りにコンパイラの定数整数除算を改善した
herumi
9
4.2k
レビュー履歴をAIに食わせて、 Compose移行を加速するs
shihochan
0
210
My Marp Sample
sinoue0108
0
120
PyConJP2026_wat_Python × Signal Processing: How to Draw Pictures with Sound Using Spectrogram Art
wat
0
360
MySQLとPostgreSQLって何が違うの?
akagami
0
140
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
160
Featured
See All Featured
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
430
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
2
400
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
How STYLIGHT went responsive
nonsquared
100
6.2k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Utilizing Notion as your number one productivity tool
mfonobong
4
550
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
3k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
710
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
250
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