ふと思い立って YARV からの JIT コンパイラを Xbyak で書き始めてみました。 x86 と x86_64 を両方サポートするつもりだったけど、とりあえず適当にやりすぎて x86_64 に依存しまくってしまったのでとりあえず現状そっちだけ。今度 x86 対応はちゃんとやる。あと Windows と MacOSX もたぶんまだだめ(調べられる環境すらない)。
http://shinh.skr.jp/tmp/yajit.tgz
YA なのはなんか他にやってた人いるみたいだし、私の記憶が確かなら YARV にも昔そういう最適化フラグあったような。実装されてたかは知らんけど。
とりあえず動くコードもあれば動かんコードも…って感じです。速いかというと…遅い気がする。とりあえずブロック呼び出しごとに mprotect してるとかがあまりに問題外すぎる気がする。とりあえずこんなとても恣意的なベンチマークだとさすがに速い。
> time ./rubyjit.rb -e 's=1;i=0;s+=i while 100000000>i+=1;p s' 4999999950000001 ./rubyjit.rb -e 's=1;i=0;s+=i while 100000000>i+=1;p s' 1.62s user 0.01s system 98% cpu 1.647 total > time ruby1.9 -e 's=1;i=0;s+=i while 100000000>i+=1;p s' 4999999950000001 ruby1.9 -e 's=1;i=0;s+=i while 100000000>i+=1;p s' 4.15s user 0.02s system 99% cpu 4.188 total
使いかたは、
require 'yajit' def hello puts "Hello, world!" end jit_func = Yajit.compile(method(:hello)) jit_func.call class C def initialize @v = "world" end def hello puts "Hello, #@v!" end end c = C.new jit_func = Yajit.compile(c.method(:hello)) jit_func.send(c)
など。
とりあえずかなりうざい量の TODO があるけど、まぁ Ruby のフルスペック実装はどう考えてもめどいししない方向で、基本的な機能(だと私が考えているもの)がそれなりにそろったら(それだけでもかなりうざいけど)、最適化遊びをちまちまするオモチャにしたいなぁと思います。
とりあえず最低やる大きな TODO:
- 適当にやってるフレームの構造をちゃんとやって break とか return とか動くように。 YARV の DFP ってスタックの先にあるのがたぶん問題。
- x86 で動くように。それ終わったら Win と MacOSX 。
- optional parameter とか * がからむ演算関係とかそのへん。
- 高速化。遅いってのはどうなんだ。ループの中で毎度 mprotect 呼ぶとかアホ。これなんでかっていうと mprotect が勝手に外れてて、調べてないけどたぶん malloc がそいうことやるのかなとかなんか間違ってるのかなとか。なんにせよ mmap した領域で実行した方が良さげ。
- 定数とかクラス変数とか $1 とか。クラス定義関数定義もできないんだけど、やるべきか悩む。
- 整数演算が bignum になった瞬間たぶん死ぬ。これはなんというか Project Euler を高速に解きたいという欲求があるので、なんか自前で多倍長整数の実装できないかなーとか思うんだがどうなんだろう。
- インターフェイスをもっと使いやすく。というかコンパイルした関数は元の関数置き変えちゃう感じでいいと思う。
たぶんやらなさげ:
やってみて思ったこと。
- 面白い。
- だいぶ YARV の仕組みが見えてきた気がする。やっぱ私はいじらんとわからんのだなーと思った。
- よく考えると JIT の定義とか知らんのでこれを JIT というのか知らん。
- そろそろ飽きそうなのではてなに書こう←いまここ
せっかくだから最初のコードの逆アセンブリとかはっておく。
% ./rubyjit.rb -e 's=1;i=0;s+=i while 100000000>i+=1;p s' -d === Disassemble of <iseq> === /tmp/yajit.out: file format binary Disassembly of section .data: 008e8170 <.data>: 8e8170: 55 push %rbp 8e8171: 48 89 e5 mov %rsp,%rbp 8e8174: 48 83 ec 10 sub $0x10,%rsp 8e8178: 6a 03 pushq $0x3 8e817a: 48 a1 80 1b 0c ab aa mov 0x2aaaab0c1b80,%rax 8e8181: 2a 00 00 8e8184: 5a pop %rdx 8e8185: 48 89 50 18 mov %rdx,0x18(%rax) 8e8189: 6a 01 pushq $0x1 8e818b: 48 a1 80 1b 0c ab aa mov 0x2aaaab0c1b80,%rax 8e8192: 2a 00 00 8e8195: 5a pop %rdx 8e8196: 48 89 50 10 mov %rdx,0x10(%rax) 8e819a: e9 68 00 00 00 jmpq 0x8e8207 8e819f: 48 a1 80 1b 0c ab aa mov 0x2aaaab0c1b80,%rax 8e81a6: 2a 00 00 8e81a9: 48 8b 40 18 mov 0x18(%rax),%rax 8e81ad: 50 push %rax 8e81ae: 48 a1 80 1b 0c ab aa mov 0x2aaaab0c1b80,%rax 8e81b5: 2a 00 00 8e81b8: 48 8b 40 10 mov 0x10(%rax),%rax 8e81bc: 50 push %rax 8e81bd: 59 pop %rcx 8e81be: 48 8b 04 24 mov (%rsp),%rax 8e81c2: 48 21 c8 and %rcx,%rax 8e81c5: 48 83 e0 01 and $0x1,%rax 8e81c9: 74 0a je 0x8e81d5 8e81cb: 58 pop %rax 8e81cc: 48 01 c8 add %rcx,%rax 8e81cf: 48 ff c8 dec %rax 8e81d2: 50 push %rax 8e81d3: eb 23 jmp 0x8e81f8 8e81d5: 5f pop %rdi 8e81d6: 48 be 2b 00 00 00 00 mov $0x2b,%rsi 8e81dd: 00 00 00 8e81e0: 48 ba 01 00 00 00 00 mov $0x1,%rdx 8e81e7: 00 00 00 8e81ea: 49 ba 90 ab 41 00 00 mov $0x41ab90,%r10 8e81f1: 00 00 00 8e81f4: 49 ff d2 rex.WB callq *%r10 8e81f7: 50 push %rax 8e81f8: 48 a1 80 1b 0c ab aa mov 0x2aaaab0c1b80,%rax 8e81ff: 2a 00 00 8e8202: 5a pop %rdx 8e8203: 48 89 50 18 mov %rdx,0x18(%rax) 8e8207: 68 01 c2 eb 0b pushq $0xbebc201 8e820c: 48 a1 80 1b 0c ab aa mov 0x2aaaab0c1b80,%rax 8e8213: 2a 00 00 8e8216: 48 8b 40 10 mov 0x10(%rax),%rax 8e821a: 50 push %rax 8e821b: 6a 03 pushq $0x3 8e821d: 59 pop %rcx 8e821e: 48 8b 04 24 mov (%rsp),%rax 8e8222: 48 21 c8 and %rcx,%rax 8e8225: 48 83 e0 01 and $0x1,%rax 8e8229: 74 0a je 0x8e8235 8e822b: 58 pop %rax 8e822c: 48 01 c8 add %rcx,%rax 8e822f: 48 ff c8 dec %rax 8e8232: 50 push %rax 8e8233: eb 23 jmp 0x8e8258 8e8235: 5f pop %rdi 8e8236: 48 be 2b 00 00 00 00 mov $0x2b,%rsi 8e823d: 00 00 00 8e8240: 48 ba 01 00 00 00 00 mov $0x1,%rdx 8e8247: 00 00 00 8e824a: 49 ba 90 ab 41 00 00 mov $0x41ab90,%r10 8e8251: 00 00 00 8e8254: 49 ff d2 rex.WB callq *%r10 8e8257: 50 push %rax 8e8258: ff 34 24 pushq (%rsp) 8e825b: 48 a1 80 1b 0c ab aa mov 0x2aaaab0c1b80,%rax 8e8262: 2a 00 00 8e8265: 5a pop %rdx 8e8266: 48 89 50 10 mov %rdx,0x10(%rax) 8e826a: 59 pop %rcx 8e826b: 48 8b 04 24 mov (%rsp),%rax 8e826f: 48 21 c8 and %rcx,%rax 8e8272: 48 83 e0 01 and $0x1,%rax 8e8276: 74 13 je 0x8e828b 8e8278: 48 31 c0 xor %rax,%rax 8e827b: 48 39 0c 24 cmp %rcx,(%rsp) 8e827f: 0f 9f c0 setg %al 8e8282: 48 d1 e0 shl %rax 8e8285: 48 89 04 24 mov %rax,(%rsp) 8e8289: eb 23 jmp 0x8e82ae 8e828b: 5f pop %rdi 8e828c: 48 be 3e 00 00 00 00 mov $0x3e,%rsi 8e8293: 00 00 00 8e8296: 48 ba 01 00 00 00 00 mov $0x1,%rdx 8e829d: 00 00 00 8e82a0: 49 ba 90 ab 41 00 00 mov $0x41ab90,%r10 8e82a7: 00 00 00 8e82aa: 49 ff d2 rex.WB callq *%r10 8e82ad: 50 push %rax 8e82ae: 58 pop %rax 8e82af: 48 83 e0 fb and $0xfffffffffffffffb,%rax 8e82b3: 0f 85 e6 fe ff ff jne 0x8e819f 8e82b9: 6a 04 pushq $0x4 8e82bb: 58 pop %rax 8e82bc: 6a 04 pushq $0x4 8e82be: 48 a1 80 1b 0c ab aa mov 0x2aaaab0c1b80,%rax 8e82c5: 2a 00 00 8e82c8: 48 8b 40 18 mov 0x18(%rax),%rax 8e82cc: 50 push %rax 8e82cd: 59 pop %rcx 8e82ce: 5f pop %rdi 8e82cf: 48 be 10 15 00 00 00 mov $0x1510,%rsi 8e82d6: 00 00 00 8e82d9: 48 ba 01 00 00 00 00 mov $0x1,%rdx 8e82e0: 00 00 00 8e82e3: 48 89 df mov %rbx,%rdi 8e82e6: 48 31 c0 xor %rax,%rax 8e82e9: 49 ba 90 ab 41 00 00 mov $0x41ab90,%r10 8e82f0: 00 00 00 8e82f3: 49 ff d2 rex.WB callq *%r10 8e82f6: 50 push %rax 8e82f7: 58 pop %rax 8e82f8: 48 89 ec mov %rbp,%rsp 8e82fb: 5d pop %rbp 8e82fc: c3 retq 8e82fd: cc int3