gpt4 book ai didi

java - 有什么理由不将 invokevirtual 和 invokeinteface 字节码指令合二为一吗?

转载 作者:行者123 更新时间:2023-12-02 03:58:57 24 4
gpt4 key购买 nike

是否有任何理由将调用非静态非构造函数方法的指令分成两条不同的指令而不是一条统一的指令,例如invokeinstance ?它是否与某些随机的内部 JVM 机制有关,或者它是另一个可怕的遗留问题?

我知道我们有invokespecial因为调用构造函数需要名称检查,标记另一个构造函数已被执行等,并且 invokestatic因为我们不需要将 objectref 转储到新的堆栈帧中。然而,Sun 选择将可能的通用指令分成 invokevirtual 并没有一个容易找到的理由。和invokeinterface 。如果不拆分它,ASM 代码可能会简单得多,因为我们不必查看所有 super 接口(interface)来查看这是否是一个接口(interface)方法,从而增加代码的复杂性。

最佳答案

Invokeinterface 不同,因为接口(interface)仅在运行时进行类型检查。使用虚方法,您可以静态地确定该类型是定义该方法的类的子类型。对于一个接口(interface),如果不知道该值的运行时类型,就不可能确定该值是否具有实现该接口(interface)的类型。

考虑以下伪代码(请注意,Java 中不允许这样做,但 JVM 允许等效的字节码)

class A
class B extends A implements Foo

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

无法静态地知道 a 是否实现了 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 的预期类型(没有 stackmaptables,直到很久以后才引入),因此它推断 x 的类型为 A,而这并没有实现Foo。因此,如果它尝试静态检查接口(interface)作为验证时间,它将拒绝有效的 Java 代码!唯一可行的解​​决方案是不对接口(interface)进行类型检查。

为了安全地检查接口(interface),JVM 必须能够推断出“A 的子类,它也实现了 Foo”之类的类型,这显然给必须快速高效的东西增加了巨大的复杂性。因此,设计师没有走这条路也是有道理的。

附注Invokespecial 不仅适用于构造函数 - 它还可用于私有(private)方法和 super 方法调用。最有可能的是,它最初是一个单独的指令作为优化,因为调用的方法在加载时是已知的,而不是随着目标的运行时类型而变化。事实上,它最初被称为invokenonvirtual。

关于java - 有什么理由不将 invokevirtual 和 invokeinteface 字节码指令合二为一吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35104738/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com