Question

I came across a boring error:

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack in method 
         net.madz.lifecycle.demo.standalone.ServiceOrder.allocateResources(JJJ)V at offset 27

I don't quite understand the error mean.

I have wrote a class and generate a class, and they look pretty similar:

Wrote:

    public void allocateResources(long arg0, long truckResourceId, long arg2) {
    /* L23 */
    0 new 2;
    3 dup;
    4 invokespecial 3;        /* net.madz.lifecycle.solutionOne.InterceptorController() */
    7 astore 7;               /* controller */
    /* L24 */
    9 new 4;
    12 dup;
    13 aload_0;               /* this */
    14 invokevirtual 5;       /* java.lang.Class getClass() */
    17 aload_0;               /* this */
    18 ldc 6;                 /* "allocateResources" */
    20 iconst_3;
    21 anewarray 7;           /* new java.lang.Class[] */
    24 dup;
    25 iconst_0;
    26 getstatic 8;           /* java.lang.Long.TYPE */
    29 aastore;
    30 dup;
    31 iconst_1;
    32 getstatic 8;           /* java.lang.Long.TYPE */
    35 aastore;
    36 dup;
    37 iconst_2;
    38 getstatic 8;           /* java.lang.Long.TYPE */
    41 aastore;
    42 invokespecial 9;       /* net.madz.lifecycle.solutionOne.InterceptContext(java.lang.Class summaryPlanId, java.lang.Object arg1, java.lang.String truckResourceId, java.lang.Class[] arg3) */
    45 astore 8;              /* context */
    /* L26 */
    47 aload 7;               /* controller */
    49 aload 8;               /* context */
    51 new 10;
    54 dup;
    55 aload_0;               /* this */
    56 lload_1;               /* summaryPlanId */
    57 lload_3;               /* truckResourceId */
    58 lload 5;               /* plangResourceId */
    60 invokespecial 11;      /* net.madz.lifecycle.solutionOne.ServiceOrder$1(net.madz.lifecycle.solutionOne.ServiceOrder summaryPlanId, long arg1, long truckResourceId, long arg3) */
    63 invokevirtual 12;      /* java.lang.Object exec(net.madz.lifecycle.solutionOne.InterceptContext arg0, java.util.concurrent.Callable truckResourceId) */
    66 pop;
    /* L34 */
    67 return;
}

Generated:

    public void allocateResources(long arg0, long arg1, long arg2) {
    0 new 77;
    3 dup;
    4 invokespecial 78;       /* net.madz.lifecycle.solutionOne.InterceptorController() */
    7 astore 7;
    9 new 80;
    12 dup;
    13 ldc 7;
    15 aload_0;
    16 ldc 81;                /* "allocateResources" */
    18 iconst_3;
    19 anewarray 83;          /* new java.lang.Class[] */
    22 dup;
    23 iconst_0;
    24 getstatic 88;          /* java.lang.Long.TYPE */
    27 aastore;
    28 dup;
    29 iconst_1;
    30 getstatic 88;          /* java.lang.Long.TYPE */
    33 aastore;
    34 dup;
    35 iconst_2;
    36 getstatic 88;          /* java.lang.Long.TYPE */
    39 aastore;
    40 invokespecial 91;      /* net.madz.lifecycle.solutionOne.InterceptContext(java.lang.Class arg0, java.lang.Object arg1, java.lang.String arg2, java.lang.Class[] arg3) */
    43 astore 8;
    45 aload 7;
    47 aload 8;
    49 new 93;
    52 dup;
    53 aload_0;
    54 lload_1;
    55 lload_3;
    56 lload 5;
    58 invokespecial 96;      /* net.madz.lifecycle.demo.standalone.ServiceOrder$5(net.madz.lifecycle.demo.standalone.ServiceOrder arg0, long arg1, long arg2, long arg3) */
    61 invokevirtual 100;     /* java.lang.Object exec(net.madz.lifecycle.solutionOne.InterceptContext arg0, java.util.concurrent.Callable arg1) */
    64 pop;
    65 return;
}

Since it says "Bad type on operand stack in method net.madz.lifecycle.demo.standalone.ServiceOrder.allocateResources(JJJ)V at offset 27"

is it the "27 aastore;" which caused this exception? At the wrote version class, I mean I wrote a java file and compile it into class file. I use this.getClass() to load the class reference, so in wrote version, "offset" 13 and 14 are "aload_0;" and "invokevirtual 5;" But in generated version I use "ldc" at offset 13 to reference the class directly, so the two versions cannot align precisely.

Usually how to diagnose these problems and how to monitoring operand stack at runtime, can BCEL generate LocalVariableTable into class files?

Was it helpful?

Solution

Finally I try to utilize BCELifier to generate Java codes from both generated and wrote class files, and I found the differences between them.

    public static void main(String[] args) throws Throwable {
    final JavaClass outerClass = Repository.lookupClass(ServiceOrder.class.getName());
    StringRepresentation s = new StringRepresentation(outerClass);
    System.out.println(s);
    BCELifier fier = new BCELifier(outerClass, System.out);
    fier.start();

    final JavaClass outer2Class = Repository.lookupClass(net.madz.lifecycle.solutionOne.ServiceOrder.class.getName());
    BCELifier fier2 = new BCELifier(outer2Class, System.out);
    fier2.start();

And then found the difference part:

CORRECT:

il.append(_factory.createFieldAccess("java.lang.Long", "TYPE", new ObjectType("java.lang.Class"), Constants.GETSTATIC));

WRONG:

il.append(_factory.createFieldAccess("java.lang.Long", "TYPE", Type.LONG, Constants.GETSTATIC));

In my code, actually I am using:

ilist.append(ifact.createGetStatic(convertType2ClassName(type), "TYPE", Type.LONG));

Obviously it should be:

ilist.append(ifact.createGetStatic(convertType2ClassName(type), "TYPE", new ObjectType("java.lang.Class")));

In summary, there are two mistakes I made:

  1. I did not use InstructionFactory.createFieldAccess method, but I choose InstructionFactory.createGetStatic, although they can produce same results, but createFieldAccess has documents and createGetStatic does not.
  2. I should use new ObjectType(Class.class.getName()) other than Type.LONG, since it should be the field type, which should match Class[].
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top