- PR -

神は無駄をしたもうか?

投稿者投稿内容
yu
ベテラン
会議室デビュー日: 2002/09/29
投稿数: 58
お住まい・勤務地: 東京
投稿日時: 2002-12-25 00:28
こんにちは。

前々から疑問なんですが、どなたかご存じないでしょうか。

Java VM では、
182 invokevirtual
183 invokespecial(JDK 1.0 は invokenonvirtual)
184 invokestatic
185 invokeinterface
186 現在は未使用(Oak で使われていた?)

と関数呼び出しのオペコードが分かれています。

しかし、この分け方は無駄だらけです。
まず、Java において、invokevirtual と invokeinterface を分けることに、
何の意味もありません。どちらも、同じアルゴリズムで関数の動的解決をします。

また invokespecial は、
<init> と private 関数という動的解決不要の virtual 関数と、
super 関数という invokevirtual とは異なる動的解決の必要な関数が
1つにまとめられています。
何でこちらは分離していないのでしょうか?

もう一つ、スタックにつまれている呼び出しもとのオブジェクトを見つけ出すのに、
なんで、method signature を構文解析させて、引数の数を計算させる
仕様になっているのでしょうか?
invokeinterface は引数の数をパラメータに渡しているのに。

それと、186 番は何か存在していたのでしょうか?

ほんと、Java VM の関数呼び出しは無駄と謎だらけです。

何でこんな仕様になっているのでしょうか?
何も考えずに作って、悪しき伝統が残ってしまっただけなのでしょうか?
Gosling は11年前に何を考えていたのだろうか…
未記入
ぬし
会議室デビュー日: 2002/03/28
投稿数: 255
投稿日時: 2002-12-25 11:41
>しかし、この分け方は無駄だらけです。
>まず、Java において、invokevirtual と invokeinterface を分けることに、
>何の意味もありません。どちらも、同じアルゴリズムで関数の動的解決をします。
多重継承と単一継承では実装がまるで異なります.
たしかベリファイも違ったはず.

これは割と基本だと思いますが?

>ほんと、Java VM の関数呼び出しは無駄と謎だらけです
少しは命令セットやVMの実装とか最適化手法とかGCとかを勉強した
ことがありますか?その辺を理解していないと謎だらけになるのは
当たり前です.

もっとも,基本を理解したくらいでバイトコードが設計できるかというと,
そんな簡単な代物でもないですが.設計は実に奥が深い.
#もちろん現在のJavaVMの仕様が完璧な代物かというと,多分そうではない.
#それを証明するには,まだまだ研究が必要だろうけど.
yu
ベテラン
会議室デビュー日: 2002/09/29
投稿数: 58
お住まい・勤務地: 東京
投稿日時: 2002-12-25 13:31
こんにちは。レスありがとうございます。

引用:

多重継承と単一継承では実装がまるで異なります.
たしかベリファイも違ったはず.



呼び出し対象のオブジェクトのインスタンス生成時のときのクラスを調べ、
そのクラス(もしくはそのスーパークラスの)の関数を呼び出すだけでは
ないでしょうか?

多重継承かどうかはコンパイル時には必要ですが、
バイトコード実行時にも必要なんでしょうか?

ベリファイアだって、引数や戻り値の型があっているか調べるだけだから、
invokevirtual も invokeinterface もコンスタントプールから
引数情報を調べてきて、確認するだけではないのでしょうか?

引用:

少しは命令セットやVMの実装とか最適化手法とかGCとかを勉強した
ことがありますか?その辺を理解していないと謎だらけになるのは
当たり前です.



僕のレベルは、
・Java VM は1から実装したことがある
・動的クラスローディングが存在しない J2ME CLDC で
 静的クラス解決・メソッド解決をするVMを作ったことがある。
・GC のアルゴリズムは知識としてあるが、実装したことはない。
・プログラミング言語を構文解析するプログラムは作ったことがある。

この程度のレベルですが、それでも、Java VM のバイトコードの仕様は
「一度作ってしまったからそのまま放置」に感じるのですが。

Java VM のバイトコードに最適化なんてほとんど入っていないと思うのですが。
(当然、まったく入っていないというわけではないですが)
バイトコードは古い形そのままにして、HotSpot で最適化するという方針に
なっていませんか?

僕の勘違いなのかなぁ。

下請け
ベテラン
会議室デビュー日: 2002/12/11
投稿数: 50
お住まい・勤務地: 大阪
投稿日時: 2002-12-25 15:53
>何でこんな仕様になっているのでしょうか?
>何も考えずに作って、悪しき伝統が残ってしまっただけなのでしょうか?
>Gosling は11年前に何を考えていたのだろうか…

それは作った本人にしかわからないでしょう・・・
ただ、何も考えずには作らないと思いますが?

ものごとがそうあるのは何かしらの理由があります。
それが今では無駄のようには見えても当時はそうではなかったはず。
それに今は無駄でも設計しなおす無駄と引き換えることも出来ない
ということもあるのではないでしょうか?

ちなみに私はただのユーザーなので深い話はわかりません。
あしからず。
yu
ベテラン
会議室デビュー日: 2002/09/29
投稿数: 58
お住まい・勤務地: 東京
投稿日時: 2002-12-25 18:22
引用:

それに今は無駄でも設計しなおす無駄と引き換えることも出来ない
ということもあるのではないでしょうか?



これに関してはそのとおりだと思います。
たとえ、どんなにクラスファイルの構造に無駄があろうとも、
これだけ普及してしまった以上、絶対に変更は許されませんからね。

しかも、僕が指摘した点はどれも、パフォーマンス的に致命的な問題に
なるわけではないですし。

invokeinterface と invokevirtual の違いは、
Oak 時代かそのプロトタイプ時代には、abstract class と interface の違いが無く、
interface は多重継承に使えるだけでなく、関数の実装もできたのではないか、
というのが僕の予想です。

つまり、C++ のように使えたのではないかという予想です。
もし、そうだとすると、invokeinterface と invokevirtual を分ける必要があります。

ひょっとして、将来、Java でも、C++ 的な多重継承を実装する可能性とかも
あったのではないでしょうか?
今では、もう、その可能性はほとんどなさそうですが。

と、ここまで書いて、invokeinterface を勘違いしていたりして...
未記入
ぬし
会議室デビュー日: 2002/03/28
投稿数: 255
投稿日時: 2002-12-25 19:54
>呼び出し対象のオブジェクトのインスタンス生成時のときのクラスを調べ、
>そのクラス(もしくはそのスーパークラスの)の関数を呼び出すだけでは
>ないでしょうか?
....
ひょっとして,まさかメソッドテーブルも使ってないってことは
ないでしょうね?

>ベリファイアだって、引数や戻り値の型があっているか調べるだけだから、

ベリファイに関しては仕様書に全部かいてありますが,
そんな一言で言えるような簡単なものじゃないですよ.

>Java VM のバイトコードに最適化なんてほとんど入っていないと思うのですが。
JavaVM仕様書には最適化については書いていません.
なぜなら最適化は実装依存の話であり,JavaVM仕様書の関知すべき
ものではないからです.
#このこともJavaVM仕様書に書いてあったような気が....

ただし,仕様というものは,最適化に大きく影響します.
多重継承が嫌われる理由の一つは,効率の良い最適化手法が知られていないからです.「多重継承を使う」と仕様で書いたが最後,その仕様に基づく実装は,その分最適化
しにくくなります.
#それこそC++は,多重継承が基本ということがパフォーマンス上
#のネックの一つになっていると.

>バイトコードは古い形そのままにして、HotSpot で最適化するという方針に
>なっていませんか?

「HotSpotで」という部分を「JavaVMで」というならある意味その通りです.
#HotSpotVMはJavaVM実装の一つにすぎない.

バイトコードは最適化できるように設計されているので,
実際の実装でも最適化するのが主流になっています.

もっとも,この辺が難しいところではありますがね.JavaVM設計時になかった
新しい最適化技術が開発され,しかもそれがJavaVM仕様に基づく実装には
適用できなかった場合,その時点でJavaVMの仕様の問題が顕在化します.
とは言え,それこそ,これは予測不可能なことですから.

ところで,次のページを読んだことはありますか?
http://www-6.ibm.com/jp/developerworks/java/jalape-vm-index-j.html
yu
ベテラン
会議室デビュー日: 2002/09/29
投稿数: 58
お住まい・勤務地: 東京
投稿日時: 2002-12-25 20:11
こんにちは。

引用:

悪夢を統べるものさんの書き込み (2002-12-25 19:54) より:
>呼び出し対象のオブジェクトのインスタンス生成時のときのクラスを調べ、
>そのクラス(もしくはそのスーパークラスの)の関数を呼び出すだけでは
>ないでしょうか?
....
ひょっとして,まさかメソッドテーブルも使ってないってことは
ないでしょうね?



もうしわけないんですけど、もう少し説明してもらえないでしょうか。

僕が実装したときは、
「メソッドの実装」を持ちうるクラスは単一継承しかありえないので、
スーパークラスのメソッドテーブルを引き継ぎ、継承するクラスでは、
それをコピーし、上書きして使っています。

その上で、invokevirtual でも、invokeinterface でも、method signature を
入手した後は、そのメソッドテーブルから、メソッドの実装を引き出しています。

僕の理解では、method signature を入手する方法も、
入手した後の処理も、invokevirtual でも、invokeinterface でも
差がないと思うのですが、前後のどちらに差が出るのでしょうか?
t-wata
大ベテラン
会議室デビュー日: 2002/07/12
投稿数: 209
お住まい・勤務地: 東京
投稿日時: 2002-12-26 00:38
私はJVMをあまりよく分かっていないのですが、

引用:

僕の理解では、method signature を入手する方法も、
入手した後の処理も、invokevirtual でも、invokeinterface でも
差がないと思うのですが、



例えば、
-----A.java---------
public interface A{
void amethod();
}
-----Test.java------
public class Test implements A{
public void amethod(){}
public static void main(String[] args){
A a = new Test();
a.amehtod();
}
}
を両方ともコンパイルした後に、A.javaから、void amehtod();を消して、
A.javaのみ再コンパイルして、java Testを実行すると、実行時クラス型に
はamethodがあるにもかかわらず、NoSuchMethodErrorとなります。

invokevirtualでは、単に実行時クラスのメソッドを実行するだけなのに
くらべ、invokeinterfaceの方はやるべきことが多いと思います。

スキルアップ/キャリアアップ(JOB@IT)