是否有任何理由让指令调用非静态非构造函数方法为两个不同的指令,而不是一个统一的指令,如invokeinstance?它是否与一些随机的内部JVM机制有关,还是又是一个可怕的遗留问题?
我知道我们有invokespecial,因为调用构造函数需要名称敲取,标记另一个构造函数已经执行等等,而invokestatic是因为我们不需要将对象倾倒到新堆栈框架中。然而,它并没有一个容易找到的理由,为什么Sun选择将可能的通用指令扩展到invokevirtual和invokeinterface中。如果不分割它,ASM代码可能会简单得多,因为我们不需要查看所有的超级接口,看看这是否是一个接口方法,从而构建了代码的复杂性。
发布于 2016-01-30 18:51:45
Invokeinterface是不同的,因为接口只在运行时进行类型检查。使用虚拟方法,您可以静态地确定类型是定义方法的类的子类型。对于一个接口,如果不知道该值的运行时类型,就不可能确定该值是否具有实现该接口的类型。
考虑以下伪代码(注意,这在Java中是不允许的,但是JVM允许字节码等效)
class A
class B extends A implements Foo
A a = new B()
a.fooMethod()无法静态地知道是否实现Foo,因为静态类型A没有实现Foo,但是实际的运行时类型B实现了。
编辑:上面的示例将被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类型(没有堆栈映射表,直到很久以后才引入),所以它推断出x的类型是A,它没有实现Foo。因此,如果它试图静态地检查接口作为验证时间,它将拒绝有效的Java代码!唯一可行的解决方案是不使用打字机接口。
为了安全地检查接口,JVM必须能够推断诸如“A的子类也实现Foo”这样的类型,这显然增加了一些必须快速和高效的东西的巨大复杂性。所以设计师没有走这条路线是有道理的。
Invokespecial不只是用于构造函数,它还用于私有和超级方法调用。最有可能的是,它最初是一个单独的优化指令,因为调用的方法是在加载时知道的,而不是随着目标的运行时类型而变化的。事实上,它最初被称为invokenonvirtual。
https://stackoverflow.com/questions/35104738
复制相似问题