跳到主要内容

JEP 334:JVM 常量 API

QWen Max 中英对照 JEP 334 JVM Constants API

概述

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

动机

每个 Java 类文件都有一个常量池,其中存储了类中字节码指令的操作数。大体来说,常量池中的条目描述的要么是运行时的产物(例如类和方法),要么是简单的值(例如字符串和整数)。所有这些条目都被称为可加载常量,因为它们可以作为 ldc 指令("load constant",即“加载常量”)的操作数。它们也可能出现在 invokedynamic 指令的引导方法的静态参数列表中。执行 ldcinvokedynamic 指令时,可加载常量会被解析为标准 Java 类型(如 ClassStringint)的“活跃”值。

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

因此,如果程序能够以纯粹的名义和符号形式处理类、方法以及不太为人所知的构造(如方法句柄和动态计算常量),那么涉及可加载常量的程序将会更加简单:

  • 字节码解析和生成库必须以符号形式描述类和方法句柄。如果没有标准机制,它们就不得不采用特定的机制,无论是像 ASM 的 Handle 这样的描述符类型,还是字符串元组(方法拥有者、方法名称、方法描述符),或者是将这些编码为单一字符串的特定(且容易出错)方式。

  • 如果操作字节码(例如 LambdaMetafactory)的 invokedynamic 引导程序能够在符号域中工作,而不是使用“实时”类和方法句柄,那么它们会更加简单。

  • 编译器和离线转换器(例如 jlink 插件)需要描述无法加载到运行时虚拟机中的类及其成员。类似地,编译器插件(例如注解处理器)也需要以符号形式描述程序元素。

这些库和工具都会受益于有一个单一的、标准的方式来描述可加载常量。

描述

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

可以在此处找到 API 规范的草稿快照:这里,关于其与 JEP 303 中特性关系的更多信息,可以在以下配套文档中找到。

依赖关系

此 JEP 最初是 JEP 303(LDC 和 INVOKEDYNAMIC 指令的内在实现) 的一个子功能。现在,JEP 303 依赖于此 JEP。