2

我有这个程序可以从 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
4

3 回答 3

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,堆栈操作不足以通过有效性。

于 2013-09-24T15:36:52.650 回答
0

问题是你的字节码不是从偏移量 0 开始的。我不知道前 6 个字节在做什么,但不管它是什么,它都不会验证。

于 2013-09-24T15:23:02.213 回答
0

每个方法都必须max_stack在 .class 中指定其堆栈帧大小 , (此处为两个布尔值/整数)。在 代码属性中,也包含说明。

于 2013-09-24T15:34:35.437 回答