The JVM 规范 4.10.2.4 版本 7,最后一段 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10.2.4, says
如果未初始化对象的特殊类型与除自身以外的特殊类型合并,则有效的指令序列不得在操作数堆栈上或向后分支的目标处的局部变量中包含未初始化的对象
这是一个被验证者拒绝的例子 - 我怀疑它应该被接受:
public scala.Tuple2<scala.runtime.Null$, scala.runtime.Null$> apply(boolean);
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
0: new #12 // class scala/Tuple2
3: dup
4: aconst_null
5: iload_1
6: ifne 5
9: aconst_null
10: invokespecial #16 // Method scala/Tuple2."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
13: areturn
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this LC;
0 14 1 x Z
StackMapTable: number_of_entries = 1
frame_type = 255 /* full_frame */
offset_delta = 5
locals = [ class C, int ]
stack = [ uninitialized 0, uninitialized 0, null ]
错误消息抱怨向后跳转ifne 5
java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
Location:
C.apply(Z)Lscala/Tuple2; @6: ifne
跳转目标处堆栈上确实存在未初始化的对象;然而,在我看来,“未初始化对象的特殊类型”与自身合并,正如规范所要求的那样。
我认为只有一个堆栈映射框架,因此它不能与其他任何内容合并。
有趣的是,对向后分支的限制在JVM 规范版本 8 http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.2.4.
然而,Java 8 VM 中的 Verifier 仍然拒绝该示例。
我是否误读了 JVM 规范,或者该示例确实未通过验证?我尝试过版本1.7.0_60-b19
and 1.8.0_05-b13
.
一般研究
该问题出现在 Scala 中(错误报告 https://issues.scala-lang.org/browse/SI-8645)。要重现,请使用 scala 2.11.1,确保您使用的是 JVM >= 1.7 并运行以下命令(确保通过-target:jvm-1.7
到斯卡拉):
localhost:sandbox luc$ scala -target:jvm-1.7
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class C {
| def apply(x: Boolean) = new Tuple2(null, {
| while (x) { }
| null
| })
| }
defined class C
scala> new C
java.lang.VerifyError: Uninitialized object exists on backward branch 5
Exception Details:
Location:
C.apply(Z)Lscala/Tuple2; @6: ifne
Reason:
Error exists in the bytecode
Bytecode:
0000000: bb00 0959 011b 9aff ff01 b700 0db0
Stackmap Table:
full_frame(@5,{Object[#2],Integer},{Uninitialized[#0],Uninitialized[#0],Null})
... 32 elided
正如刚才提到的 -JDK 错误报告在这里 https://bugs.openjdk.java.net/browse/JDK-8046233,我希望在那里得到回应。
JDK 错误已修复JDK 8u25 http://www.oracle.com/technetwork/java/javase/2col/8u25-bugfixes-2298227.html