* OSECPU-VMはなぜJavaVMと違うのか? -(by [[K]], 2014.06.11) ** (0) -バイトコードのVM方式の代表といえば、やはりJavaだと思う。完成度においては後発の.NETのほうが上かもしれないけど、先駆者はJavaであって、その歴史的偉業の大きさは比較にならない。 -Javaや.NET以外にもたくさんのバイトコードVMがあるけど、それらはみんな似たり寄ったりである、OSECPU-VMと比べれば。・・・ということでここではJavaを代表にして、OSECPU-VMと比べたい。 -決定的に違うのはアプリのサイズである。しかしこれは結果であって原因ではない。 ** (1) -JavaもOSECPU-VMも最初の目的は同じである。CPUやOSに依存しないアプリ実行環境を整備したい。・・・しかしこの目的を達成するためのアプローチが大きく異なる。 -Javaは、まずJavaという高級言語を設計した。.NETもC#などの高級言語を設計した。そしてバイトコードというのは、これらの高級言語のための中間コードでしかない。主役ではないのである。・・・だから気合が入っていない。完成度もそれなりである。 -これに対してOSECPU-VMではまずバイトコードから設計する。そのバイトコードを生成するためのコンパイラもアセンブラもすべて後回しである。そもそもよいバイトコードとは何か?そこから始まる。 --(1-1)よいバイトコードは、命令セットがシンプルでVMが書きやすい。 --(1-2)よいバイトコードは、アプリをコンパクトに記述できる。 --(1-3)よいバイトコードは、アプリバイナリが圧縮しやすい。 -そもそもアプリが簡潔に記述できないというのはどういうことなのか。それは無駄な記述を強いられていることに他ならない。そんなことが許されるだろうか。それは美しいだろうか。それは正しいだろうか。 -高級言語だけをみて、その実現手段を気にしないということはできる。しかしその土台であるバイトコードの完成度がいい加減だとしたら、その上によい高級言語を構築できるだろうか。まずは基礎をしっかりさせるべきではないのか。 -OSECPU-VMはx86やARMやMIPSや68040や6809などの既存のよくできたCPUの機械語の研究から出発した。ここから無くてもかまわない命令を取り除き整理した。 -高級言語の理想とは、人間にとって使いやすいことであろう。そして人間とは非合理的で非効率的な存在である。そんなものに迎合すれば、それなりのものしかできない。一方で機械は合理的で効率的である。これを土台にすればマシになるのは当然だろう。・・・Javaのバイトコード設計者がCPUの機械語にもう少し詳しければ・・・。 -ここまで批判されるほど、Javaはダメなのか。多少は無駄があったかもしれないが、それでも1~2割程度なのではないか。・・・そう思うだろう。いやほんとにそうだったらどんなによかっただろう。現実はとても厳しい。→[[page0066]] -しかも悲しいことに、ダメなのはJavaだけではないのだ。他のバイトコードもJavaと大差ない。つまりJavaが悪いのではなく、高級言語屋が作ったVMは全部ダメなのである。彼らはバイトコード設計には向いてない。そういわざるをえない。 -僕たちのような機械語屋は最近はかなり不人気である。「今どき、そんなこと必要ないでしょ」とバカにされることも少なくない。僕も大勢では彼らの見解に賛成である。・・・しかしそれにしてもこの結果はひどい。ないがしろにしたツケがこんなところにあったのだ。 ** (2) -OSECPU-VMでは、まず小規模なアプリを研究した。これはおそらく一般的なアプローチではない。世間の人たちはまず大規模な事例だけを研究対象にする。確かに大規模なアプリでの1%の改善は小規模なアプリの10%の改善よりも価値があるだろう。 -しかし大規模アプリは、たいていの場合、もはや全体が見えていなくて、局所最適化の集合体になってしまっている。本当はこう書くべきなのに、そうなっていないのだ。そんなプログラムに対して、命令の使用頻度を調べて命令セットを工夫しても、それはダメなプログラムがコンパクトに書けるだけで、よいプログラムが小さくならない。・・・とはいうものの、僕も最初からそれに気づいていたわけではなく、単にすぐには大規模アプリを用意できなかっただけなのであるが。 -小さなアプリを小さく書けるようにするというのは、実は当たり前のことである。単純なものは簡潔に記述できるべきである。「こういう規則にしておけば、小規模なときは不利だけど大規模では有利なはず」みたいなことを設計者はやりがちなのだけど、それはたいてい間違っている。・・・結局は大きなプログラムも小さなプログラムの集合であり、小さなプログラムのための工夫を大きなプログラム内でも積極的に利用できることがわかった。そしてそのように書き直すと、大きなプログラムも劇的に改善するようである。 ** (3) -僕は可逆圧縮のマニアでもある。圧縮アルゴリズムがどれほど苦労して圧縮をしているのか知っているのである。だからそれを邪魔したくはない。むしろ手伝いたい。だから圧縮前からできるだけ小さくしておきたい。余計な情報は最初から取り除いておく。 -処理内容が似ているものはバイトコードも似るべきである。そうすれば圧縮しやすい。 ** (9) メモ -命令セットがシンプル: --メモリにアクセスするのは、ロードストア系のみ。即値を指定できる命令も即値ロード命令のみ。 --フラグレジスタを持たず、レジスタの値によって制御する。比較した結果も普通の整数レジスタに格納させる。 --演算系もたとえば加算はADD命令しかなく、INC/DECなどの命令はない。ビット反転するNOTやCOMみたいな命令もない(それは-1とのXORで行う)。符号反転するNEGみたいな命令もない(それは-1のMULで代用)。 -小規模なアプリから学んだこと: --十分にレジスタが豊富なら、レジスタによる演算が中心となる。メモリを参照する頻度は高くない。 //小さなプログラムの典型的なパターンに配慮してない。レジスタ中心とか。 //小さくする気があるのか?まじめにやっているのか? //人間は非合理・非効率、機械は合理的で効率的。数学的な美しさが正しいのと似ている。 * こめんと欄 #comment