Rubyを、以下のオプションでビルドするとYJITのデバッグ機能が使える(rbenvを利用する例)。
$ export CONFIGURE_OPTS="--enable-yjit=dev" $ rbenv install 3.4.2
その中にはISeqが機械語にコンパイルされた結果を確認する RubyVM::YJIT.disasm(isec)
というメソッドがある。いくつかRubyのコードでの結果を試してみた。
試した環境など
- OS: x86_64 Linux、ただし Macbook M3 Pro の環境で、 qemu を使ってエミュレートした環境
- ruby -v --yjit:
ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +YJIT dev +PRISM [x86_64-linux]
検証用のコード
なんちゃない、足し算の最適化。西海岸のいつもの味です。
def target 10 + 20 end 10000.times { target } isec = RubyVM::InstructionSequence.of method(:target) puts RubyVM::YJIT.disasm(isec)
ちなみに一部のメソッドは特別な最適化がされる。今回は Integer#+
をターゲットにする。どれがされるのかは...。
NEWSを直接当たるのが一番わかりやすいらしい。
結果
$ ruby --yjit /tmp/jit.rb == disasm: #<ISeq:target@/tmp/jit.rb:1 (1,0)-(3,3)> 0000 putobject 10 ( 2)[LiCa] 0002 putobject 20 0004 opt_plus <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr] 0006 leave ( 3)[Re] NUM BLOCK VERSIONS: 1 TOTAL INLINE CODE SIZE: 58 bytes == BLOCK 1/1, ISEQ RANGE [0,7), 58 bytes ====================== 0x7b1fdcc110c6: mov esi, 0x15 0x7b1fdcc110cb: mov edi, 0x29 0x7b1fdcc110d0: mov rax, rsi 0x7b1fdcc110d3: sub rax, 1 0x7b1fdcc110d7: add rax, rdi 0x7b1fdcc110da: jo 0x7b1fdcc1310a 0x7b1fdcc110e0: mov rsi, rax 0x7b1fdcc110e3: mov eax, dword ptr [r12 + 0x20] 0x7b1fdcc110e8: test eax, eax 0x7b1fdcc110ea: jne 0x7b1fdcc13132 0x7b1fdcc110f0: add r13, 0x38 0x7b1fdcc110f4: mov qword ptr [r12 + 0x10], r13 0x7b1fdcc110f9: mov rax, rsi 0x7b1fdcc110fc: jmp qword ptr [r13 - 8]
0x7b1fdcc110c6
~ 0x7b1fdcc110d7
までがコンパイルされたコードだねとわかる。ではこれは何?
この区間を翻訳すると以下のようになる。
0x7b1fdcc110c6: mov esi, 0x15 ;; a = 0x15 = 21 0x7b1fdcc110cb: mov edi, 0x29 ;; b = 0x29 = 41 0x7b1fdcc110d0: mov rax, rsi ;; ax = a 0x7b1fdcc110d3: sub rax, 1 ;; ax -= 1 0x7b1fdcc110d7: add rax, rdi ;; ax + b = 61
10 + 20
じゃなくね? ってまず思った。
だが、よく考えたら
21, 41, 61
とは
irb(main):001> 10.object_id => 21 irb(main):002> 20.object_id => 41 irb(main):003> 30.object_id => 61
一般に、 Ruby のInteger N
のobject_idは 2 * N + 1
で求められる*1。すなわち、上記のアセンブラは、object_idを直接演算していたということになる。
どうしてそうしてるのかは不明(もしかしたら誰かの発表を見逃している)だけど、object_idを直接扱うとVMに優しいのかもしれない。
という小ネタ。
*1:あくまで今の仕様?