JVM规范中JSR/RET的状态

10

有些JVM规范的部分暗示了操作JSR (跳转子例程), JSR_W (宽跳转子例程)RET (从子例程返回)只能在50.0(JDK 1.6)之前的类文件版本中使用:

3.13 编译finally语句块

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

之后:

4.10.2.5. 异常和finally

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

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

这条评论(针对一个问题,该问题询问此弃用或删除背后的动机)表明存在类似的困惑,因此显然我不是唯一寻找答案的人。

1个回答

11
在添加链接到我的问题时,我注意到问题中的操作码在§4.10.1.9: 指令类型检查中缺失。因此可以看出,新的基于strackframe的类型验证方案不能处理它们,而§4.10: 类文件验证写道:

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

更详细地介绍在§4.10.1: 类型检查验证中:
一个版本号为50.0或以上的class文件(§4.1)必须使用本节中给出的类型检查规则进行验证。
只有当class文件的版本号等于50.0时,如果类型检查失败,Java虚拟机实现可能会选择尝试通过类型推断来执行验证(§4.10.2)。
因此,我可以说一个版本号为50.0的class文件可能仍然包含jsr和ret,但是运行时存在某些风险,即JVM实现可能无法验证该类文件,并因此无法加载它。

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

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

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

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


我仍然认为在§6.5中应该包含一些相关通知。不幸的是,Java错误报告网页会隐藏继续按钮,如果选择了类型:Bug,类别:Java Platform Standard Edition,子类别:specification。它说明:

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

但是,仅仅为了在这三个操作码的描述中添加一些澄清说明而通过JCP显得过于复杂。因此,我希望本帖可以帮助那些在规范本身找不到答案的人。


干得好!我曾经向Java报告了一个功能请求(https://dev59.com/IYzda4cB1Zd3GeqPlV3P)(虽然可能在错误的地方...),但是*它甚至没有出现在公共URL上,需要Oracle的批准*,这从未发生过... :‑/ 像Android一样,我们必须接受Java的现状,这是神的半完美礼物。 - Ciro Santilli OurBigBook.com
1
此外,即使在类型检查指令中提到了jsr,使用新的基于堆栈帧的验证仍然无法处理它们,因为每个分支目标都需要一个显式的堆栈帧,但是堆栈帧无法表示帧中的返回地址类型。 - Holger

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