跳到主要内容

JEP 334:JVM 常量 API

概括

引入 API 来对关键类文件和运行时工件的名义描述进行建模,特别是可从常量池加载的常量。

动机

每个Java类文件都有一个常量池,用于存储类中字节码指令的操作数。从广义上讲,常量池中的条目描述了运行时工件(例如类和方法)或简单值(例如字符串和整数)。所有这些条目都称为_可加载常量,_因为它们可以用作ldc指令的操作数(“加载常量”)。它们也可能出现在指令的引导方法的静态参数列表中invokedynamic。执行ldcorinvokedynamic指令会导致可加载常量被解析为标准 Java 类型的“实时”值,例如ClassStringint

操作class文件的程序需要对字节码指令建模,进而对可加载常量建模。然而,使用标准 Java 类型来建模可加载常量是不够的。对于描述字符串(条目)的可加载常量来说可能是可以接受的CONSTANT_String_info,因为生成“活动”String对象很简单,但是对于描述类(条目)的可加载常量来说是有问题的CONSTANT_Class_info,因为生成“活动”对象Classobject依赖于类加载的正确性和一致性。不幸的是,类加载有许多环境依赖性和失败模式:所需的类不存在或请求者可能无法访问;类加载的结果随上下文的不同而变化;加载类有副作用;有时类加载可能根本不可能(例如,当所描述的类尚不存在或不可加载时,如在编译这些相同的类期间或在jlink-time 转换期间)。

因此,如果处理可加载常量的程序能够以纯粹名义上的符号形式操作类和方法,以及不太知名的工件(例如方法句柄和动态计算常量),那么它们会更简单:

  • 字节码解析和生成库必须以符号形式描述类和方法句柄。如果没有标准机制,它们必须诉诸临时机制,无论是描述符类型(例如 ASM )Handle还是字符串元组(方法所有者、方法名称、方法描述符),还是将这些的临时(且容易出错)编码为单个字符串。

  • 如果引导程序可以在符号域中工作而不是在“实时”类和方法句柄中工作,那么invokedynamic通过旋转字节码(例如)进行操作的引导程序会更简单。LambdaMetafactory

  • 编译器和离线转换器(例如jlink插件)需要描述无法加载到正在运行的VM中的类和类的成员。编译器插件(例如注释处理器)同样需要用符号术语描述程序元素。

这些类型的库和工具都将受益于使用单一的标准方法来描述可加载常量。

描述

我们在新包中定义了一系列基于值的符号引用(JVMS 5.1)类型java.lang.invoke.constant,能够描述每种可加载常量。符号引用以纯粹名义形式描述可加载常量,与类加载或可访问性上下文分开。有些类可以充当它们自己的符号引用(例如,String);对于可链接常量,我们定义了一系列符号引用类型(ClassDescMethodTypeDescMethodHandleDescDynamicConstantDesc),其中包含描述这些常量的名义信息。

您可以在此处找到 API 规范的草稿快照,并且可以在此配套文档中找到有关其与JEP 303中的功能之间的关系的更多信息。

依赖关系

该 JEP 最初是JEP 303(LDC 和 INVOKEDYNAMIC 指令的内在函数)的子功能。 JEP 303 现在依赖于此 JEP。