我有这个程序从java文件生成字节码。 对于这个简单的test()方法
public void test()
{
boolean a = false;
if (a || true)
{
boolean b = false;
}
}
,它将生成以下字节码
public void test()
Code:
7: iconst_0
8: istore_1
9: iload_1
10: ifne 13
13: iconst_0
14: istore_2
15: return
当我执行该类时,我不断得到Operand stack underrun in test()
,我无法弄清楚为什么因为生成的字节码看起来不错(对我来说)
有人可以帮我调试吗?
(这是我追踪堆栈所做的事情
public void test()
Code:
7: iconst_0
(1 on the stack)
8: istore_1
(0 on the stack)
9: iload_1
(1 on the stack)
10: ifne 13
(0 on the stack)
13: iconst_0
(1 on the stack)
14: istore_2
(0 on the stack)
15: return
所以是的,堆叠看起来很好!)
编辑:这是javac
public void test();
Code:
0: iconst_0
1: istore_1
2: iload_1
3: ifne 6
6: iconst_0
7: istore_2
8: return
答案 0 :(得分:2)
当我尝试这个时
public class MainDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "Main", null, "java/lang/Object", null);
cw.visitSource("Main.java", null);
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(1, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitInsn(RETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "LMain;", null, l0, l1, 0);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null);
mv.visitCode();
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 1);
mv.visitVarInsn(ILOAD, 1);
Label l2 = new Label();
mv.visitJumpInsn(IFEQ, l2);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 2);
mv.visitLabel(l2);
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[]{Opcodes.INTEGER}, 0, null);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 3);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
public static void main(String... ignored) throws Exception {
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
byte[] dump = dump();
defineClass.invoke(Thread.currentThread().getContextClassLoader(), dump, 0, dump.length);
new Main().test();
}
}
这样可行,但是如果我放弃堆栈帧调整,我会收到此错误
Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch target 8
Exception Details:
Location:
Main.test()V @3: ifeq
Reason:
Expected stackmap frame at this location.
Bytecode:
0000000: 033c 1b99 0005 033d b1
简而言之,对于Java 7,堆栈操作不足以传递有效性。
答案 1 :(得分:0)
问题是你的字节码不是从偏移0开始的。我不知道前6个字节在做什么,但无论它是什么,它都不会验证。
答案 2 :(得分:0)
每个方法必须在.class中指定其堆栈帧大小max_stack
,(此处为两个布尔值/整数)。在code attribute中,其中还包含说明。