読者です 読者をやめる 読者になる 読者になる

Yajit

ふと思い立って YARV からの JIT コンパイラXbyak で書き始めてみました。 x86x86_64 を両方サポートするつもりだったけど、とりあえず適当にやりすぎて x86_64 に依存しまくってしまったのでとりあえず現状そっちだけ。今度 x86 対応はちゃんとやる。あと WindowsMacOSX もたぶんまだだめ(調べられる環境すらない)。

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 とか動くように。 YARVDFP ってスタックの先にあるのがたぶん問題。
  • x86 で動くように。それ終わったら Win と MacOSX
  • optional parameter とか * がからむ演算関係とかそのへん。
  • 高速化。遅いってのはどうなんだ。ループの中で毎度 mprotect 呼ぶとかアホ。これなんでかっていうと mprotect が勝手に外れてて、調べてないけどたぶん malloc がそいうことやるのかなとかなんか間違ってるのかなとか。なんにせよ mmap した領域で実行した方が良さげ。
  • 定数とかクラス変数とか $1 とか。クラス定義関数定義もできないんだけど、やるべきか悩む。
  • 整数演算が bignum になった瞬間たぶん死ぬ。これはなんというか Project Euler を高速に解きたいという欲求があるので、なんか自前で多倍長整数の実装できないかなーとか思うんだがどうなんだろう。
  • インターフェイスをもっと使いやすく。というかコンパイルした関数は元の関数置き変えちゃう感じでいいと思う。

たぶんやらなさげ:

  • Fixnum の定義が変わっていた時の対策とか、そういうお前そんなことすんなよ的なもの。
  • thread
  • シグナル
  • C++ 捨て。(Xbyak無いと無理)
  • x86 以外。(Xbyak無いと無理)

やってみて思ったこと。

  • 面白い。
  • だいぶ 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   
なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h