I'm using ASM 3.1 to generate a dummy class. It only has a simple constructor and no other methods:
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));
}
}
As you can see, I specified the ClassWriter.COMPUTE_FRAMES
flag, which would compute the stack size and local size for all my methods, according to the documentation. But when I run this code, I get an error:
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)
I examined the generated class file using 'javap -c' and found that the stack size and local size are incorrect:
$ 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
}
When I invoked visitMaxs(2, 1)
manually, this error would go away.
But I've no idea why ASM could not compute the right maxs for me. Could anyone give me a hint?
Call mv.visitMaxs(0, 0);
; I did read that somewhere, and found it so weird that I remembered.