ASM でジャンプをいじって、スタック マップ フレームが Java でどのように機能するかを理解しようとしています。いくつかのことを試すための簡単な方法を作成しました: (Krakatau で逆アセンブル):
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 呼び出しとまったく同じスタックを持っているため、ICONST_1; IFEQ L10
ASM を使用して L35 の直前にシーケンスを追加することにしました。
分解してみると (再び Krakatau で)、結果が非常に奇妙であることがわかりました。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
私が期待していたように。
さらに、 を呼び出すことができないため、このクラスも検証に合格しませStringBuilder#<init>
んTop
。ASMのマニュアルによるとTop
、初期化されていない値を参照していますが、ジャンプ位置と前のコードの両方から、コードで初期化されていないようです。ジャンプの何が問題なのかわかりません。
挿入したジャンプに何か問題があり、クラスがフレームを計算できなくなりますか? これはおそらく ASM の ClassWriter のバグですか?