lundi 19 mars 2018

If(true) in JVM. How to generate an appropriate instruction?

I'm trying to generate a simple conditional Jump instruction. Here is the class:

public static Class<?> getKlass2(){
    String className = "TestClass";
    ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);

    classWriter.visit(V1_8, ACC_PUBLIC, className, null, getInternalName(Object.class), null);

    MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC + ACC_STATIC, "m", "()Z",null, null);
    Label trueLable = new Label();
    Label afterFalseLable = new Label();
    mv.visitFieldInsn(GETSTATIC, getInternalName(Boolean.class), "TRUE", "Ljava/lang/Boolean;");
    mv.visitMethodInsn(INVOKEVIRTUAL, getInternalName(Boolean.class), "booleanValue", "()Z", false);
    mv.visitJumpInsn(IFEQ, trueLable);
    mv.visitInsn(ICONST_1);
    mv.visitJumpInsn(GOTO, afterFalseLable);
    mv.visitLabel(trueLable);
    mv.visitInsn(ICONST_0);
    mv.visitFrame(F_APPEND, 0, null, 0, null);
    mv.visitLabel(afterFalseLable);
    mv.visitInsn(IRETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();
    //converting classWriter.toByteArray() to Class<?> instance
}

When loading the class I got the following error:

Expecting a stackmap frame at branch target 13

Exception Details:
  Location:
    TestClass.m()Z @6: ifeq
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0x0000000: b200 0cb6 000f 9900 0704 a700 0403 ac  
  Stackmap Table:
    same_frame_extended(@14)

But the code of the class seems ok to me:

public class TestClass {
  public static boolean m();
    Code:
       0: getstatic     #12                 // Field java/lang/Boolean.TRUE:Ljava/lang/Boolean;
       3: invokevirtual #15                 // Method java/lang/Boolean.booleanValue:()Z
       6: ifeq          13
       9: iconst_1
      10: goto          14
      13: iconst_0
      14: ireturn
}

So I tried to add a frame by hand:

mv.visitFrame(F_APPEND, 0, new Object[]{ }, 0, new Object[]{ });

But it also failed with the same exception. Do they expect to recreate a frame with the same operand stack? But this seems non-sense since I cannot get a direct access to opearand stack from Java code.

What did I do wrong?

Aucun commentaire:

Enregistrer un commentaire