2
我使用Hibernate運行時類工具。然而 奇怪的錯誤發生的情況:奇怪的java.lang.VerifyError
Caused by: java.lang.VerifyError: Bad type on operand stack in method pkg.model.ValueList$1.<init>(Lpkg/model/ValueList;)V at offset 2
at pkg.model.ValueList.<init>(ValueList.java:24)
我已經創建了自己的類加載器適用的轉換和 用它來的自舉整個應用程序。 這裏是適用的轉換方法:
private byte[] transform(byte[] original) {
for (ClassFileTransformer transformer : transformers) {
try {
byte[] transformed = transformer.transform(this,
className, null, null, original);
if (transformed != null) {
original = transformed;
classReader = new ClassReader(transformed);
try {
CheckClassAdapter.verify(classReader, true,
new PrintWriter(System.out));
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IllegalClassFormatException e) {
throw new RuntimeException(e);
}
}
return original;
}
我這個類裝載器運行應用程序並得到下面的輸出:
<init>(Lpkg/model/ValueList;)V
00000 ValueList$1 ValueList : : ALOAD 0
00001 ValueList$1 ValueList : ValueList$1 : ALOAD 1
00002 ValueList$1 ValueList : ValueList$1 ValueList : INVOKEVIRTUAL pkg/model/ValueList$1.$javassist_write_this$0 (Lpkg/model/ValueList;)V
00003 ValueList$1 ValueList : : ALOAD 0
00004 ValueList$1 ValueList : ValueList$1 : INVOKESPECIAL java/util/AbstractList.<init>()V
00005 ValueList$1 ValueList : : RETURN
我認爲沒有錯的偏移2 我們稱之爲法適當的(ValueList $ 1)和適當的參數(ValueList)。 而且ASM也沒什麼不好,因爲它的驗證器不會引發任何異常。 爲什麼JVM驗證者拒絕這個字節碼?
Hibernate版本是4.1.10.Final。 下面是相關的錯誤代碼的一部分:
public class ValueList {
//...
@Transient
private List<Value> safeValues = new AbstractList<Value>() {
// ...
}
//...
}
該消息是正確的。在構造器鏈接達到java/lang/Object類型之前,索引爲'0'的變量數組值包含JVM類型'undefined'的值。這個類型不知道'$ javassist_write_this $ 0'這個方法(但是你可以設置這個類型的字段)。只有在調用構造函數鏈後,才能調用此類型的方法,因爲它已由實際類型替換。 –
哦,我明白了,我剛剛在VM Spec中發現:「但是,在調用任何實例初始化方法之前,可以指定在當前類中聲明的實例字段。」所以,在調用super構造函數之前,編譯器會生成PUTFIELD來初始化合成域。我想我應該向javassist團隊發佈一個問題。 –
@raphw,是的,如果你知道這些小細節,那就是邏輯。但同意,當你試圖意識到什麼是錯的時候,這個信息是非常混亂的。 –