
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>.在上面.根据ASM手册,Top指的是未初始化的值,但是从跳转位置和之前的代码来看,它似乎都没有在代码中未初始化.我不知道跳伞有什么问题.
我插入的跳转是否有问题,从而使该类无法计算帧?这可能是ASM的ClassWriter的错误吗?
Java编程语言无法充分利用所有可能性,但适用于诸如
new Foo(new Foo(new Foo(),new Foo(b?new Foo(a):new Foo(b,c)))),它不应松散地了解哪个Foo实例已初始化,哪些没有初始化,何时分支成立.
因此,每个未初始化实例堆栈帧条目都与创建它的新指令相关联.传输或复制时,所有条目均保留引用(可轻松处理为remembering the byte code offset of the new instruction).仅在invokespecial< init>之后在已对其进行调用之后,指向同一新指令的所有引用都将变为声明类的普通实例,并且随后可以与其他类型兼容的条目合并.
这意味着不可能像您想要实现的那样建立分支.两个相同类型但由不同新指令创建的未初始化实例条目不兼容.并且不兼容的类型将合并到Top条目,这基本上是不可用的条目.如果您不尝试在分支目标上使用该条目,那么它甚至可能是正确的代码,因此ASM在将它们合并到Top时不会抱怨也没有做错任何事情.
注意,这还意味着不允许任何可能导致堆栈帧具有由同一条新指令创建的多个未初始化实例的循环.
转载注明原文:java-ASM中的ClassWriter COMPUTE_FRAMES - 乐贴网