I've been trying to understand how stack map frames work in Java by playing around with jumps in ASM. I created a simple method to try some things out: (disassembled with 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
All it does is create a StringBuilder
to join some strings with variables.
Since the invokespecial call at L35 has exactly the same stack as the invokespecial call at L10, I decided to add an ICONST_1; IFEQ L10
sequence just before L35 with ASM.
When I dissassembled (again with Krakatau), I found the results quite strange. ASM had computed the stack frame at L10 to be:
.stack full
locals Object [Ljava/lang/String; Object java/lang/String
stack Object java/io/PrintStream Top Top
.end stack
instead of
stack Object java/io/PrintStream Object java/lang/StringBuilder Object java/lang/StringBuilder
as I had expected.
Furthermore, this class would also not pass verification as one cannot call StringBuilder#<init>
on Top
. According to the ASM manual, Top
refers to an uninitialized value, but it doesn't seem to be uninitialized in code, both from the jump location and the code before. I don't understand what is wrong with the jump.
Is there something wrong with the jump I inserted that somehow makes the class impossible to compute frames for? Is this perhaps a bug with ASM's ClassWriter?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…