Почему ASM не может определить правильные максимумы для моего генерирующего класса?

Я использую 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 не смог вычислить правильные максимумы для меня. Кто-нибудь может дать мне подсказку?

1 ответ

Решение

Вызов mv.visitMaxs(0, 0);; Я где-то читал это, и нашел это настолько странным, что я вспомнил.

Другие вопросы по тегам