Befunge JIT コンパイラ

http://shinh.skr.jp/koneta/#befjit

理屈はともあれ、それはコンパイラとして認めないっ…とか思ったので自分でも作ってみました。だって100万回ループしたら100万倍のコード生成するとか許せないですよね。それにバイナリを吐けば夢とひきかえに書き易さや可搬性や例外処理を投げ捨てられますし。

Befunge は VM なのに自己書き換え持ってるのと、あとプログラムカウンタがわけわからん4方に向いたりランダムで方向分岐したりするのがコンパイラを書くのが難しい点かと思います。

後者の方は話は簡単で、4方向のバイナリを生成してしまえば問題ありません。方向分岐は適当に goto left_5_3; みたいなコードを埋めてやればいいわけです。

自己書き換えの方は面倒くさくて、なんかしらランタイムに機械語を自己書き換えできないといけません。一命令から生成される命令長を nop でそろえて…ってのも考えたのですが、まぁめんどくさいなーと思ったので自己書き換えが起きたら全命令をコンパイルしなおすことにしました。

まぁそんなこんなで Xbyak を使わせていただきました。上記の前ふりは割とどうでもいいです。要は Xbyak が面白そうすぎて使ってみたかったというだけの話。

http://homepage1.nifty.com/herumi/soft/xbyak.html

なんていうか実に楽しくて良かったです。なんか C++ に普通にアセンブリ書いてるって楽しいですね。完成度すごい高い。

んでもちょい細かい実装メモ。

とりあえず速い。あと前の Ruby で書いたヤツと同じくらいはサンプルが動く。(ただ 80x25 が確保されてる前提の自己書き換えが好きくないので対応してない。してもいいけど)

スタックは CPU のスタックをそのまま使う。おかげさまで Befunge の実行に入ったら exit 以外で帰る手段が無い。スタック好き勝手に使うとか楽しいものです。ちょっとした全能感というか。

自己書き換えが起きたら全部生成しなおして、スタックコピーしてまた走らせる。いずれスタックオーバーフロー。

というのはあんまりなので、 -n をつけると自己書き換え時に再生成が起きないっていうモードもつけておいた。 p を単なるメモリストアとして使う場合は有用。

乱数は rdtsc して取ってきたヤツをタネに線型合同法で…って普通に rand 呼べばいいじゃんと今思った。最初はコンパイラにしようとしてたからライブラリ依存減らしたかったのだった。でも scanf あたりが面倒くさそうでやめたのでした。気が向いたらコンパイラにしたいと思います。

あと -d つけるとバイナリ吐きます。適切にリンクすれば実行できるかな。いやリロケーション情報残してないから無理か。

まぁ Xbyak おもろい。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h