Oracle JVM:invokespecial指令

4
我���下面这段文字有点困惑(来源:Oracle JVM specification for invokespecial instruction)。

If all of the following are true, let C be the direct superclass of the current class:

  1. The resolved method is not an instance initialization method (§2.9).
  2. If the symbolic reference names a class (not an interface), then that class is a superclass of the current class.
  3. The ACC_SUPER flag is set for the class file (§4.1).

我在 invokespecial 指令描述的第一段中制作了标签(表示为: //label//)。我将在以下问题中使用这些标签。

The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class //current class// (§2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool item at that index must be a symbolic reference to a method or an interface method (§5.1), which gives the name //method name// and descriptor //method descriptor// (§4.3.3) of the method as well as a symbolic reference to the class //referenced class// or interface in which the method is to be found. The named method is resolved //resolved method// (§5.4.3.3, §5.4.3.4).


根据标签,我现在检查了带有条件的段落。

  1. The resolved method is not an instance initialization method (§2.9).

问题1:所以,我需要检查//method name// 是否不等于 "<init>" 或 "<clinit>",是吗?

  1. If the symbolic reference names a class (not an interface), then that class is a superclass of the current class.

问题2:这是什么意思?//Referenced class//必须是直接或非直接超类(超类的超类等等)的//current class//吗?

  1. The ACC_SUPER flag is set for the class file (§4.1).

问题3:哪个类的class文件?//Referenced class//吗?

1个回答

4
  1. 被解析方法不是实例初始化方法(§2.9)。

所以,我需要检查//方法名//是否等于"<init>"或者"<clinit>",对吗?

没错。更准确地说,“不是实例初始化方法”仅意味着该方法名不是<init>。但由于一般情况下禁止调用名为 <clinit> 的方法,因此可以得出结论:该方法名既不能是 <init> 也不能是 <clinit>

  1. 如果符号引用指向的是一个类(而不是接口),那么该类是当前类的超类。

这是什么意思?//引用的类//必须是直接或非直接超类(超类的超类等等)的//当前类//

是的,如果引用的类不是接口,它必须是当前类的超类。请注意,这是一种条件,它暗示了在枚举之前声明“让C成为当前类的直接超类”。有关更多信息,请参见下文。

值得注意的是,对于非接口目标类型,它是必须满足目标类型指示当前类或当前类的超类的结构约束,如4.9.2. 结构约束所定义。

  1. ACC_SUPER标志在类文件(§4.1)中设置。

哪个类的类文件?//引用的类//

当前类的类文件,即包含invokespecial指令的类。请注意,这是一项事实上不存在的要求。当跟随链接到§4.1时,您会注意到这一点:

ACC_SUPER 标志指示了在此类或接口中,invokespecial 指令 (§invokespecial) 表达的两种备选语义中的哪一种。Java虚拟机的指令集编译器应该设置 ACC_SUPER 标志。在 Java SE 8 及以上版本中,Java虚拟机认为每个 class 文件都已经设置了 ACC_SUPER 标志,无论实际上该标志在 class 文件中的值和 class 文件的版本是什么。

ACC_SUPER 标志存在是为了向后兼容由旧版Java编译器编译的代码。在 JDK 1.0.2 之前的版本中,编译器生成的 access_flags 中没有分配任何含义,现在代表 ACC_SUPER 的标志被忽略了。

因此,当JVM“认为每个class文件都已经设置了ACC_SUPER标志”时,不需要检查是否设置了该标志...

历史方面也解释了上述含义。 invokespecial 指令用于实现 super.methodName(…) 调用。在早期的 1.0 实现中,编译器解析包含该方法声明的目标类,JVM 调用该方法,忽略任何重写的方法。这会产生两个问题。首先,恶意代码可以通过使用指向该方法的超类型的适当 invokespecial 指令来绕过类型层次结构中的重写方法。其次,它创建了对超类层次结构的依赖性,限制了可能的更改。

当前规则是编译器将始终将 super.methodName(…) 编码为针对包含该调用的类的直接超类,无论实际声明在编译时在超类层次结构中的位置在哪里。在运行时,当JVM遇到这样的 invokespecial 指令时,它将在超类型层次结构中搜索最具体的方法,并尊重其中的任何重写。这确保了在一个类内,只有对其直接超类的依赖性(除非代码中有其他明确的引用更抽象的类型),并且允许重构,例如将方法上移或下移类型层次结构,而不影响兼容性。

枚举条件的字面意义是,被引用的类可能是任何超类(标准编译器只生成使用直接超类的类文件),以满足在任何情况下都使用直接超类来解析方法的条件。这包括执行为Java 1.0编译的类文件的情况,在该情况下忽略ACC_SUPER的缺失。对于非接口类型,仅支持另一种情况,即目标类型与当前类完全匹配,并用于调用private方法。 ACC_FLAG是为了向后兼容而引入的。它的存在表示应使用新行为,但如上所述,最近的JVM仅支持“新”行为,这是二十年来的最先进状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接