Skip to content

JEP 334: JVM Constants API | JVM 常量 API

摘要

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

动机

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

处理 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);对于可链接的常量,我们定义了一组符号引用类型(ClassDescMethodTypeDescMethodHandleDescDynamicConstantDesc),这些类型包含描述这些常量的名义信息。

API 规范的草案快照可以在 这里 找到,关于它与 JEP 303 中特性关系的更多信息可以在这个 配套文档 中找到。

依赖关系

这个 JEP 最初是 JEP 303(LDC 和 INVOKEDYNAMIC 指令的内部函数) 的一个子特性。现在,JEP 303 依赖于这个 JEP。