我正在使用 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 不能为我计算出正确的最大值。谁能给我一个提示?