在JVM规格4.10.2.4版本7,最后一段说:
如果未初始化对象的特殊类型与除自身之外的特殊类型合并,则有效指令序列不得在操作数堆栈上或在向后分支的目标上的局部变量中具有未初始化对象
这是验证者拒绝的一个例子 - 我怀疑它应该被接受:
public scala.Tuple2apply(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." ":(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 Spec版本8中删除了对向后分支的限制.
但是,Java 8 VM中的Verifier仍然拒绝该示例.
我是否误读了JVM规范,或者该示例是否真的未通过验证?我试过版本1.7.0_60-b19
和1.8.0_05-b13
.
这个问题出现在Scala(bugreport)中.要重现,请使用scala 2.11.1,确保您使用的是JVM> = 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在这里,我希望在那里得到回应.
JDK错误已在JDK 8u25中修复