JVM Spec 4.10.2.4 version 7, last paragraph,
如果未初始化对象的特殊类型与非自身特殊类型合并,则有效指令序列不得在操作数堆栈上或在向后分支目标的局部变量中具有未初始化对象
以下是验证者拒绝的一个例子 - 我怀疑它应该被接受:
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
在跳跃目标上堆栈上确实存在未初始化的对象;然而,它在我看来,&#34;特殊类型的未初始化对象&#34;正如规范所要求的那样,它与自身合并。
我认为只有一个堆栈映射框架,所以它不能与其他任何东西合并。
有趣的是,JVM Spec version 8删除了对向后分支的限制。
但是,Java 8 VM中的Verifier仍拒绝该示例。
我是否误读了JVM规范,或者该示例是否真的未通过验证?我尝试了1.7.0_60-b19
和1.8.0_05-b13
版本。
问题出现在Scala(bugreport)中。要重现,请使用scala 2.11.1,确保您使用的是JVM&gt; = 1.7并执行以下操作(确保将-target:jvm-1.7
传递给scala):
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 bugreport here,我希望在那里得到答复。
JDK错误已在JDK 8u25
中修复