this によるメソッド呼び出しは速い
.NET Framework 4.0 で以下のfuncの呼び出しは、this のほうが速い。
遅い方。
var me = this;
me.func();
速いほう。
this.func();
「そりゃ変数代入の分だけ遅い」ではなくて、呼び出し単体で遅いのである。
利用は、NullReferenceException チェックのため。
機械語を見ると分かる。
速いほうは func の呼び出し命令列が下記のようになっている。
00000027 8B 4D F8 mov ecx,dword ptr [ebp-8]
0000002a E8 DD A1 CB FF call FFCBA20C
一行目は、thisポインタをECXレジスタに入れている。.NET JITコンパイラは、ECXレジスタをthisポインタのやり取りに使うようだ。
二行目で、メソッドを呼び出している。
遅い方は、下記のようになっている。
0000004e 8B 4D F4 mov ecx,dword ptr [ebp-0Ch]
00000051 39 09 cmp dword ptr [ecx],ecx
00000053 E8 B4 A1 CB FF call FFCBA20C
一行目と三行目は速いほうと変わらない。問題は二行目が増えていること。
二行目はECXレジスタのメモリから4バイト読み出し、それをECXレジスタと比較している。
こうすれば、ECXレジスタが 0 (NULL) だったときにプロセッサが割り込みを発生させることから、NullReferenceException を起こすことができる。もしこのCMP命令がないと、インスタンスフィールドへアクセスするまでNullReferenceExceptionが発生しなくなるため、プログラムの動作が不確定になる。(たとえば、static 変数を修正した後インスタンスフィールドを修正するコードは、処理途中で意図せず例外が起こってしまう。)実際、.NET 2.0 とか 3.0 あたりでは this についての NULL チェックをしていなかったような記憶があり、変な挙動になっていた。
さて、まあ遅いと言ってもたかが一命令、しかも読み出しである。キャッシュヒットすればたいしたことないだろう。
もしかしたらIntelのすごい技術によって実質的に0サイクルになったりするかもしれない(そこら辺は詳しくないので分からない)。
これが問題になることは?