JITとjavac
んで、JITについて考えてたんだけど、javacの最適化がアレな理由がわかったような。
JITを前提としたスタックマシンのバイトコードっていうのは、バイトコードが命令列なんじゃなくて、あくまで解析木をシリアライズしたものとしてバイトコードを利用してるんじゃないかと。
スタックマシンで
load_const 3 load_local 4 add store_local 0
こんな感じのがあったとしたら、ただ単に、機械語に変換したら、
pushl $3 pushl -20(%ebp) popl %eax addl (%esp), %eax popl %eax movl -4(%ebp), %eax
こんな感じになっちゃう。これはもちろん、糞で、
movl %eax, -20(%ebp) addl %eax, $3 movl -4(%ebp), %eax
このぐらいにはなってほしい。
それだと、スタックマシンの命令→レジスタマシンの命令っていうのが必要になる。それは難しいような気がしないでもない。
そんで、そこで、スタックマシンは、後置記法だと考える。
((loadconst 3; load_local 4; add) store_local 0)
そうすると、スタックマシン命令列から木ができる。
store_local 0 | add / \ / \ / \ const 3 local 4
後置記法→木は簡単なはず。んで、木になれば、それをレジスタマシンの命令に変換するのは、普通のコンパイラと同じやりかたでできる。
もし、ここで、共通部分式とかやりまくってスタックの先頭の入れかえとかしたら、解析木を作るのが非常に面倒。だから、javacは最適化しない、と、そういうのはどうだろうか。
と、すると、つまり、javacの吐いたバイトコードをそのまま使うというのは非常に無駄であって、だから、javacがアレなのは、「JITコンパイルしろよ」というSun様からの啓示なのである。