我一直在試圖理解通過與ASM跳躍玩耍地圖幀的Java堆棧是如何工作的。我創建了一個簡單的方法來嘗試一些東西出來:(與喀拉喀託拆解):ClassWriter COMPUTE_FRAMES在ASM
L0: ldc 'hello'
L2: astore_1
L3: getstatic Field java/lang/System out Ljava/io/PrintStream;
L6: new java/lang/StringBuilder
L9: dup
L10: invokespecial Method java/lang/StringBuilder <init>()V
L13: ldc 'concat1'
L15: invokevirtual Method java/lang/StringBuilder append (Ljava/lang/String;)Ljava/lang/StringBuilder;
L18: aload_1
L19: invokevirtual Method java/lang/StringBuilder append (Ljava/lang/String;)Ljava/lang/StringBuilder;
L22: invokevirtual Method java/lang/StringBuilder toString()Ljava/lang/String;
L25: invokevirtual Method java/io/PrintStream println (Ljava/lang/String;)V
L28: getstatic Field java/lang/System out Ljava/io/PrintStream;
L31: new java/lang/StringBuilder
L34: dup
L35: invokespecial Method java/lang/StringBuilder <init>()V
L38: ldc 'concat2'
L40: invokevirtual Method java/lang/StringBuilder append (Ljava/lang/String;)Ljava/lang/StringBuilder;
L43: aload_1
L44: invokevirtual Method java/lang/StringBuilder append (Ljava/lang/String;)Ljava/lang/StringBuilder;
L47: invokevirtual Method java/lang/StringBuilder toString()Ljava/lang/String;
L50: invokevirtual Method java/io/PrintStream println (Ljava/lang/String;)V
L53: return
它所做的就是創建一個StringBuilder
加入一些字符串使用變量。由於L35上的invokespecial調用與L10中的invokespecial調用具有完全相同的堆棧,因此我決定在L35之前的ASM中添加一個ICONST_1; IFEQ L10
序列。
當我dissassembled(與喀拉喀託再次),我發現結果很奇怪。 ASM已計算出的堆棧幀,在L10爲:的
.stack full
locals Object [Ljava/lang/String; Object java/lang/String
stack Object java/io/PrintStream Top Top
.end stack
代替
stack Object java/io/PrintStream Object java/lang/StringBuilder Object java/lang/StringBuilder
如我的預期。
此外,這個類也將無法通過驗證爲一個不能Top
打電話StringBuilder#<init>
。根據ASM手冊,Top
引用了一個未初始化的值,但它似乎並未在代碼中初始化,包括跳轉位置和之前的代碼。我不明白跳躍有什麼問題。
是不是有什麼毛病我插入,不知怎的,使該類不可能計算幀的跳躍?這可能是ASM的ClassWriter的一個bug嗎?
謝謝,每個未初始化的值綁定到創建它的NEW語句似乎是這裏的關鍵。 – konsolas