msumimz's diary

RubyにJITコンパイラを実装する個人プロジェクトの情報発信ブログです。

先ほどのベンチマークのコードがどのようにコンパイルされたか

参考までに、先ほどのコードがどのようにコンパイルされたか見てみましょう。

元のメソッドは下記のとおりです。

def m1
  i = 1
  sum = 0
  while i <= 10000
    sum += i
    i += 1
  end
  sum
end

JITコンパイルされた結果は以下の通りです。*1

03450016  mov         edi,3       ; i = 1(3は整数1のFixnum表現)
0345001B  mov         esi,1       ; sum = 0(1は整数0のFixnum表現)
03450020  jmp         0345007D    ; 条件式にジャンプする
03450025  mov         dword ptr [esp],esi  
03450028  mov         dword ptr [esp+4],2Bh    ; 28h = '+'を表すID
03450030  call        rbjit::rbjit_lookupMethod (1F51FAh)  
03450035  mov         dword ptr [esp+0Ch],edi  
03450039  mov         dword ptr [esp+4],esi  
0345003D  mov         dword ptr [esp],eax  
03450040  mov         dword ptr [esp+8],1  
03450048  call        rbjit::rbjit_callMethod (1F4AF7h)  
0345004D  mov         esi,eax  
0345004F  mov         dword ptr [esp],edi  
03450052  mov         dword ptr [esp+4],2Bh    ; 28h = '+'を表すID  
0345005A  call        rbjit::rbjit_lookupMethod (1F51FAh)  
0345005F  mov         dword ptr [esp+4],edi  
03450063  mov         dword ptr [esp],eax  
03450066  mov         dword ptr [esp+0Ch],3  
0345006E  mov         dword ptr [esp+8],1  
03450076  call        rbjit::rbjit_callMethod (1F4AF7h)  
0345007B  mov         edi,eax  
0345007D  mov         dword ptr [esp],edi  
03450080  mov         dword ptr [esp+4],89h    ; 89h = '<='を表すID  
03450088  call        rbjit::rbjit_lookupMethod (1F51FAh)  
0345008D  mov         dword ptr [esp+4],edi  
03450091  mov         dword ptr [esp],eax  
03450094  mov         dword ptr [esp+0Ch],4E21h    ; 4E21hは整数10000のFixnum表現 
0345009C  mov         dword ptr [esp+8],1  
034500A4  call        rbjit::rbjit_callMethod (1F4AF7h)  
034500A9  test        eax,0FFFFFFFBh               ; 真偽判定(RTEST)
034500AF  jne         03450025  
034500B5  mov         eax,esi  
034500B7  add         esp,10h  
034500BA  pop         esi  
034500BB  pop         edi  
034500BC  ret  

ここで、rbjit::rbjit_lookupMethodとrbjit::rbjit_callMethodは、それぞれメソッド検索及び呼び出しのためのヘルパ関数です。内部では、MRIの対応する関数に転送しています。

ローカル変数をレジスタに割り当ててたり、ジャンプ命令を1回減らすために条件式を後ろに置いたり、LLVMが頑張って最適化してくれていますが、結局はメソッド呼び出しが実行時間の大半を占めることを、なんとなく感じ取っていただけるのではないかと思います。

*1:Visual Studioのデバッガ画面からコピーしました。はてなアセンブラ表記は大文字の16進数を正しく認識できないようで、ところどころ色がおかしいですが、気にしないでください。