10

JVM 规范的某些部分表明操作JSR (Jump SubRoutine)JSR_W (Jump SubRoutine Wide)RET (RETurn from subroutine)只能在类文件版本 50.0 (JDK 1.6) 之前使用:

3.13 最后编译

(本节假设编译器生成版本号为 50.0 或以下的类文件,因此可以使用 jsr 指令。另见§4.10.2.5。)

然后:

4.10.2.5。例外和finally

为了实现try-finally构造,生成class版本号为 50.0 或更低版本的文件的 Java 编程语言编译器可以使用异常处理工具以及两个特殊指令:jsr(“跳转到子程序”)和ret(“从子程序返回” ”)。

另一方面,操作码描述本身并没有说明这些功能的弃用。引用的文本仅说明了 50.0 之前的版本中的情况,但没有明确说明之后的情况。

此评论(询问有关弃用或删除背后动机的问题)表明类似程度的混乱,所以显然我不是唯一一个寻找这个的人。

4

1 回答 1

11

在为我的问题添加链接时,我注意到§4.10.1.9: Type Checking Instructions中没有相关操作码。所以这表明新的基于 strackframe 的类型验证方案无法处理它们,并且§4.10: Verification of class Files写道:

必须使用类型检查验证来验证class版本号大于或等于 50.0 的文件。

或者在§4.10.1 中更详细地说明:通过类型检查进行验证

class版本号为 50.0 或更高(第4.1节)的文件必须使用本节中给出的类型检查规则进行验证。

当且仅当class文件的版本号等于 50.0 时,如果类型检查失败,Java 虚拟机实现可能会选择尝试通过类型推断执行验证(第 4.10.2 节)。

所以我想说一个 50.0 版本的类可能仍然包含jsrret,但存在一些风险,即 JVM 实现不会验证所述类,因此加载它会失败。

但后来我在§4.9.1中发现了一个更明确的规则:静态约束:

只有§6.5中记录的指令实例可能会出现在code数组中。使用保留操作码(第 6.2 节)或本规范中未记录的任何操作码的指令实例不得出现在code数组中。

如果class文件版本号为 51.0 或更高版本,则jsr操作码或jsr_w操作码都不会出现在code数组中。

第一段与这个问题无关,因为说明在第 6.5 节中列出,并且根据第 6.2 节没有保留。但是第二段明确地将它们标记为在 51.0 及更高版本中被禁止。另一方面,如果没有jsrjsr_w ,则ret操作码是无用的,因为只有这两条指令才能创建类型的堆栈元素(并通过一些存储该类型的局部变量)以供ret使用。returnAddress


我仍然认为应该在 §6.5 中包含一些关于此效果的通知。不幸的是,如果选择 Type: Bug、 Category: Java Platform Standard Edition、 Subcategory: specification , Java bug 报告网页会隐藏Continue按钮。它指出

此子类别用于报告 Java 语言规范和 JVM 规范文本中的技术错误和歧义。它不是提出 Java 语言或 JVM 新特性的场所。正在进行的功能开发是在OpenJDK中进行的;Java 语言规范和 JVM 规范的相应增强是通过Java Community Process管理的。

But going through the JCP just to get some clarifying notes added to the descriptions of these three opcodes feels like massive overkill. So I hope that this post here helps those who on their own fail to find an answer in the specification itself.

于 2016-05-03T20:27:59.630 回答