x86アセンブラの続き
動的にバイナリを生成して実行できるのでJITアセンブラなわけだが、こいつに簡単な命令をいくつか追加して、ModR/MバイトとSIBバイトも出力できるようにした。これでメモリアクセスやインデックス指定ができるようになったし、ebpやespなども使えるようになったので、できることの幅が一気に広がった。
ついでにラベルの生成と条件ジャンプ命令の一部、相対call命令を追加して、現状このようなソースになっている。
ここまでできれば例えば再帰処理するコードも書けるだろうということで試しにフィボナッチ数列を計算してみた。かなり適当だけど。
hoge = X86ASM.asm([Fiddle::TYPE_INT]) do push ebp mov ebp, esp mov edx, [ebp + 8] push edx call :fib pop edx pop ebp ret L:fib push ecx push edx mov ecx, [esp + 12] cmp ecx, 2 jnc :fib2 mov eax, ecx pop edx pop ecx ret L:fib2 mov edx, ecx sub edx, 2 push edx call :fib pop edx mov edx, eax sub ecx, 1 push ecx call :fib pop ecx add eax, edx pop edx pop ecx ret end p hoge.call(39) #=>63245986
Rubyで書いたコードより30倍ほど速かった。でも思ったほど速くないのは適当すぎるからか。
Cで書いたコードに勝つのはいまどきのCPUでは難しいが、Rubyで書いたコードには適当でも勝てるので、速度が欲しい場合はそれなりに使い道があるのかないのかよくわからん。外部ツール(コンパイラとか)無しで標準のRubyさえあれば動くのは嬉しい。
基本的には大量の計算をするところで用途を見出せるはずだが、その場合は大量のデータが必要になることが多く、アセンブラからRubyのオブジェクトを直接参照することはできないので、packして文字列のポインタを渡すような形になってしまうと、packとunpackのオーバーヘッドで価値が半減してしまう。なんかうまい手は無いものか。