先ほどのベンチマークのコードがどのようにコンパイルされたか
参考までに、先ほどのコードがどのようにコンパイルされたか見てみましょう。
元のメソッドは下記のとおりです。
def m1 i = 1 sum = 0 while i <= 10000 sum += i i += 1 end sum end
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進数を正しく認識できないようで、ところどころ色がおかしいですが、気にしないでください。