Почему 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);
; Я где-то читал это, и нашел это настолько странным, что я вспомнил.