Java Language Specification Java SE 11 Edition (JLS SE 11) 中对 Constant Folding 的描述在哪里?
Where is the description of Constant Folding in the Java Language Specification, Java SE 11 Edition (JLS SE 11)?
据我所知,Java在编译时通过常量折叠来处理常量变量§4.12.4。我已经尽力了,但我无法从 JLS 中找到它的描述。谁能告诉我在哪里可以找到 官方 对 Java 11 的 恒定折叠 过程的描述?
Java 语言规范定义了语言的语义;常量折叠是一种编译器优化,它不会改变 Java 程序的行为,因此它没有在 JLS 中指定,也不需要指定。 Java 的实现允许不这样做,或者在某些情况下而不是其他情况下这样做,只要编译的程序按照 JLS 所说的去做。
也就是说,JLS 确实定义了语言语义,以便在更多情况下 允许 常量折叠而不改变程序的行为。最相关的段落可能是您在 §14.2.4:
中提到的内容
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28). Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1), reachability (§14.21), and definite assignment (§16.1.1).
有关 class 初始化、二进制兼容性、可达性和明确赋值的参考部分专门定义了常量变量与其他变量不同的语义;具体来说,它们定义的行为是您期望折叠常量的编译器的行为。这允许那些实施规范的人进行优化,而不会过度限制他们如何做。
字段的过程链接自问题中链接的页面:https://docs.oracle.com/javase/specs/jls/se11/html/jls-13.html#jls-13.1
A reference to a field that is a constant variable (§4.12.4) must be
resolved at compile time to the value V denoted by the constant
variable's initializer.
If such a field is static, then no reference to the field should be
present in the code in a binary file, including the class or interface
which declared the field. Such a field must always appear to have been
initialized (§12.4.2); the default initial value for the field (if
different than V) must never be observed.
If such a field is non-static, then no reference to the field should
be present in the code in a binary file, except in the class
containing the field. (It will be a class rather than an interface,
since an interface has only static fields.) The class should have code
to set the field's value to V during instance creation (§12.5).
规范不使用常量折叠这个术语。
的定义
A constant expression is an expression denoting a value of primitive type or a String
that does not complete abruptly and is composed using only the following:
[…]
Constant expressions of type String
are always "interned" so as to share unique instances, using the method String.intern
.
A constant expression is always treated as FP-strict (§15.4), even if it occurs in a context where a non-constant expression would not be considered to be FP-strict.
Constant expressions are used as case
labels in switch
statements (§14.11) and have a special significance in assignment contexts (§5.2) and the initialization of a class or interface (§12.4.2). They may also govern the ability of a while
, do
, or for
statement to complete normally (§14.21), and the type of a conditional operator ? :
with numeric operands.
最后一部分确实已经指出了必须预先计算常量表达式的地方。当涉及到 case
标签时,编译器需要报告重复项,因此它必须计算 compile-time 处的值。在计算循环时,它必须计算常量布尔表达式来确定代码可达性。
同样,初始化程序需要预先计算以确定正确性。例如。 short s = 'a' * 2;
是正确的声明,但 short s = Short.MAX_VALUE + 1;
不是。
常量表达式的一个众所周知的用例是常量变量的初始化器。读取常量变量时,会使用常量值代替读取变量,对比Q&A
但这并不意味着“不断折叠”是强制性的。理论上,符合规范的实现仍然可以在使用变量的每个地方执行变量初始值设定项中编写的常量表达式的计算。实际上,字节码格式会导致持续的折叠行为。字节码中用来记录常量变量值的ConstantValue
属性只能保存一个预先计算好的值。针对已编译的 class 文件进行编译时,常量变量的原始表达式对编译器不可用。它只能使用预先计算的值。
同样,compiling a switch
instruction is normally done using either, the tableswitch
or the lookupswitch
指令,都需要为 case
标签预先计算的 int
值。编译器必须花很长时间才能实现不同的策略。
此外,the compiled format for annotation values 只能保存预先计算的表达式。
据我所知,Java在编译时通过常量折叠来处理常量变量§4.12.4。我已经尽力了,但我无法从 JLS 中找到它的描述。谁能告诉我在哪里可以找到 官方 对 Java 11 的 恒定折叠 过程的描述?
Java 语言规范定义了语言的语义;常量折叠是一种编译器优化,它不会改变 Java 程序的行为,因此它没有在 JLS 中指定,也不需要指定。 Java 的实现允许不这样做,或者在某些情况下而不是其他情况下这样做,只要编译的程序按照 JLS 所说的去做。
也就是说,JLS 确实定义了语言语义,以便在更多情况下 允许 常量折叠而不改变程序的行为。最相关的段落可能是您在 §14.2.4:
中提到的内容A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28). Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1), reachability (§14.21), and definite assignment (§16.1.1).
有关 class 初始化、二进制兼容性、可达性和明确赋值的参考部分专门定义了常量变量与其他变量不同的语义;具体来说,它们定义的行为是您期望折叠常量的编译器的行为。这允许那些实施规范的人进行优化,而不会过度限制他们如何做。
字段的过程链接自问题中链接的页面:https://docs.oracle.com/javase/specs/jls/se11/html/jls-13.html#jls-13.1
A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.
If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field. Such a field must always appear to have been initialized (§12.4.2); the default initial value for the field (if different than V) must never be observed.
If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (§12.5).
规范不使用常量折叠这个术语。
的定义A constant expression is an expression denoting a value of primitive type or a
String
that does not complete abruptly and is composed using only the following:[…]
Constant expressions of type
String
are always "interned" so as to share unique instances, using the methodString.intern
.A constant expression is always treated as FP-strict (§15.4), even if it occurs in a context where a non-constant expression would not be considered to be FP-strict.
Constant expressions are used as
case
labels inswitch
statements (§14.11) and have a special significance in assignment contexts (§5.2) and the initialization of a class or interface (§12.4.2). They may also govern the ability of awhile
,do
, orfor
statement to complete normally (§14.21), and the type of a conditional operator? :
with numeric operands.
最后一部分确实已经指出了必须预先计算常量表达式的地方。当涉及到 case
标签时,编译器需要报告重复项,因此它必须计算 compile-time 处的值。在计算循环时,它必须计算常量布尔表达式来确定代码可达性。
同样,初始化程序需要预先计算以确定正确性。例如。 short s = 'a' * 2;
是正确的声明,但 short s = Short.MAX_VALUE + 1;
不是。
常量表达式的一个众所周知的用例是常量变量的初始化器。读取常量变量时,会使用常量值代替读取变量,对比Q&A
但这并不意味着“不断折叠”是强制性的。理论上,符合规范的实现仍然可以在使用变量的每个地方执行变量初始值设定项中编写的常量表达式的计算。实际上,字节码格式会导致持续的折叠行为。字节码中用来记录常量变量值的ConstantValue
属性只能保存一个预先计算好的值。针对已编译的 class 文件进行编译时,常量变量的原始表达式对编译器不可用。它只能使用预先计算的值。
同样,compiling a switch
instruction is normally done using either, the tableswitch
or the lookupswitch
指令,都需要为 case
标签预先计算的 int
值。编译器必须花很长时间才能实现不同的策略。
此外,the compiled format for annotation values 只能保存预先计算的表达式。