JEP 334: JVM Constants API | JVM 常量 API
摘要
引入一个 API 来建模关键类文件和运行时工件的名义描述,特别是那些可从常量池中加载的常量。
动机
每个 Java 类文件都有一个 常量池,它存储了类中字节码指令的操作数。广义上讲,常量池中的条目描述了运行时工件,如类和方法,或者简单的值,如字符串和整数。所有这些条目都被称为 可加载常量,因为它们可以作为 ldc
指令("加载常量")的操作数。它们也可能出现在 invokedynamic
指令的引导方法静态参数列表中。执行 ldc
或 invokedynamic
指令会将可加载常量解析为标准的 Java 类型(如 Class
、String
或 int
)的“活动”值。
处理 class
文件的程序需要模拟字节码指令,进而需要模拟可加载常量。然而,使用标准的 Java 类型来模拟可加载常量是不够的。对于描述字符串的可加载常量(一个 CONSTANT_String_info
条目)来说,可能是可以接受的,因为生成一个“活动”的 String
对象很简单,但对于描述类的可加载常量(一个 CONSTANT_Class_info
条目)来说,则存在问题,因为生成一个“活动”的 Class
对象依赖于类加载的正确性和一致性。不幸的是,类加载具有许多环境依赖和失败模式:所需的类不存在或可能无法被请求者访问;类加载的结果随上下文而变化;加载类具有副作用;有时类加载可能根本无法进行(例如,当被描述的类尚不存在或无法加载时,如在编译这些类时,或在 jlink
时间转换期间)。
因此,如果程序能够以纯名义、符号的形式处理类和方法,以及不太为人所知的工件,如方法句柄和动态计算的常量,那么处理可加载常量的程序将会更简单:
字节码解析和生成库必须以符号形式描述类和方法句柄。如果没有标准机制,它们必须采用特定的机制,无论是如 ASM 的
Handle
这样的描述符类型,还是字符串元组(方法所有者、方法名称、方法描述符),或者将这些信息编码为单个字符串的特定(且容易出错)方式。通过生成字节码来操作的
invokedynamic
引导(如LambdaMetafactory
)如果在符号域中工作而不是使用“活动”的类和方法句柄,将会更简单。编译器和离线转换器(如
jlink
插件)需要描述无法加载到正在运行的 VM 中的类和成员。编译器插件(如注解处理器)同样需要以符号形式描述程序元素。
这些库和工具都将从拥有一个描述可加载常量的单一、标准方式中受益。
描述
我们定义了一组基于值的符号引用(JVMS 5.1)类型,位于新包 java.lang.invoke.constant
中,能够描述每种可加载常量。一个符号引用以纯名义形式描述一个可加载常量,与类加载或访问上下文无关。有些类可以作为它们自己的符号引用(例如,String
);对于可链接的常量,我们定义了一组符号引用类型(ClassDesc
、MethodTypeDesc
、MethodHandleDesc
和 DynamicConstantDesc
),这些类型包含描述这些常量的名义信息。
API 规范的草案快照可以在 这里 找到,关于它与 JEP 303 中特性关系的更多信息可以在这个 配套文档 中找到。
依赖关系
这个 JEP 最初是 JEP 303(LDC 和 INVOKEDYNAMIC 指令的内部函数) 的一个子特性。现在,JEP 303 依赖于这个 JEP。