0

非静的非コンストラクター メソッドを呼び出す命令を、1 つの統一された命令ではなく、2 つの異なる命令にする理由はありますinvokeinstanceか? ランダムな内部 JVM メカニズムと何か関係がありますか、それとも別の恐ろしいレガシー問題ですか?

コンストラクターの呼び出しにinvokespecialは名前の確認が必要であり、他のコンストラクターが実行されたことをマークするなどの理由があり、新しいスタックフレームにオブジェクトリファレンスをダンプする必要invokestaticがないためです。ただし、Sun がユニバーサル命令をandに分割することを選択した理由を簡単に見つけることはできません。分割しなければ、ASM コードははるかに単純になる可能性があります。これは、すべてのスーパーインターフェイスを調べて、これがインターフェイス メソッドであるかどうかを調べて、コードの複雑さを構築する必要がないためです。invokevirtualinvokeinterface

4

1 に答える 1

2

インターフェイスは実行時にのみ型チェックされるため、Invokeinterface は異なります。仮想メソッドを使用すると、型がメソッドが定義されているクラスのサブタイプであることを静的に判断できます。インターフェイスの場合、値の実行時の型を知らずに、値がそのインターフェイスを実装する型を持っているかどうかを確実に知ることは不可能です。

次の疑似コードを検討してください (これは Java では許可されていませんが、JVM では同等のバイトコードが許可されていることに注意してください)。

class A
class B extends A implements Foo

A a = new B()
a.fooMethod()

静的型 A は Foo を実装していませんが、実際のランタイム型 B は実装しているため、 a が Foo を実装しているかどうかを静的に知る方法はありません。

編集: 上記の例は Java コンパイラによって拒否されますが、JVM では拒否されません。JVM がコンパイラと同じ規則を適用しないのはなぜかと思うかもしれません。違いは、JVM にはローカル変数に関するソース レベルの型情報がないことです。Java で許可されている次の例を考えてみましょう。

class A
class B extends A implements Foo
class C extends A implements Foo

Foo x = null;
if (whatever) {
x = new B();
} else {
x = new C();
}
x.fooMethod();

JVM は x の意図した型を認識していないため (stackmaptables は後で導入されました)、x の型を であると推測しますがA、これは を実装していませんFoo。したがって、検証時にインターフェイスを静的にチェックしようとすると、有効な Java コードが拒否されます。実行可能な唯一の解決策は、インターフェースをタイプチェックしないことです。

インターフェースを安全にチェックするために、JVM は「Foo も実装する A のサブクラス」のような型を推論できなければなりません。したがって、デザイナーがこのルートに行かなかったのは理にかなっています。

PS Invokespecial は、コンストラクターだけでなく、プライベート メソッドやスーパー メソッドの呼び出しにも使用されます。呼び出されたメソッドは、ターゲットの実行時のタイプによって変化するのではなく、ロード時に認識されるため、元は最適化として別の命令であった可能性が最も高いです。実際、もともとは invokenonvirtual と呼ばれていました。

于 2016-01-30T18:51:45.310 に答える