3

我正在使用 ASM 3.1 生成一个虚拟类。它只有一个简单的构造函数,没有其他方法:

public class TestAsm {

public static void main(String... args) throws Throwable {
    ClassWriter sw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    sw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, "test/SubCls", null, "test/SuperCls", null);
    sw.visitField(Opcodes.ACC_PUBLIC, "i", "I", null, null);

    MethodVisitor mv = sw.visitMethod(0, "<init>", "()V", null, null);
    // mv.visitMaxs(2, 1);
    mv.visitCode();
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "test/SuperCls", "<init>", "()V");
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitInsn(Opcodes.ICONST_2);
    mv.visitFieldInsn(Opcodes.PUTFIELD, "test/SubCls", "i", "I");
    mv.visitInsn(Opcodes.RETURN);
    mv.visitEnd();

    sw.visitEnd();
    byte[] cls = sw.toByteArray();
    FileOutputStream fos = new FileOutputStream("bin/test/SubCls.class");
    fos.write(cls);
    fos.close();

    SuperCls o = (SuperCls) Class.forName("test.SubCls").newInstance();
    System.out.println(o.i);

    System.out.println(o.getClass().getDeclaredField("i").getInt(o));
    }
}

如您所见,ClassWriter.COMPUTE_FRAMES根据文档,我指定了标志,它将计算我所有方法的堆栈大小和本地大小。但是当我运行这段代码时,我得到一个错误:

Exception in thread "main" java.lang.VerifyError: (class: test/SubCls, method: <init> signature: ()V) Stack size too large
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at test.TestAsm.main(TestAsm.java:33)

我使用'javap -c'检查了生成的类文件,发现堆栈大小和本地大小不正确:

$ javap -c SubCls -verbose
public class test.SubCls extends test.SuperCls
minor version: 0
major version: 50
Constant pool:
const #1 = Asciz    test/SubCls;
const #2 = class    #1; //  test/SubCls
const #3 = Asciz    test/SuperCls;
const #4 = class    #3; //  test/SuperCls
const #5 = Asciz    i;
const #6 = Asciz    I;
const #7 = Asciz    <init>;
const #8 = Asciz    ()V;
const #9 = NameAndType  #7:#8;//  "<init>":()V
const #10 = Method  #4.#9;  //  test/SuperCls."<init>":()V
const #11 = NameAndType #5:#6;//  i:I
const #12 = Field   #2.#11; //  test/SubCls.i:I
const #13 = Asciz   Code;

{
public int i;


test.SubCls();
  Code:
   Stack=0, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #10; //Method test/SuperCls."<init>":()V
   4:   aload_0
   5:   iconst_2
   6:   putfield    #12; //Field i:I
   9:   return

}

当我手动调用时visitMaxs(2, 1),这个错误就会消失。
但我不知道为什么 ASM 不能为我计算出正确的最大值。谁能给我一个提示?

4

1 回答 1

4

打电话mv.visitMaxs(0, 0);;我确实在某个地方读到过,发现它很奇怪,以至于我记得。

于 2013-01-06T10:54:12.847 回答