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のオーバーヘッドで価値が半減してしまう。なんかうまい手は無いものか。