Code modification with Javassist generate a java.lang.VerifyError: Expecting to find integer on stack

Code modification with Javassist generate a java.lang.VerifyError: Expecting to find integer on stack

我使用 javassist 重写了一个名为 compile 的方法(它以字符串数组作为参数):我创建了一个新方法,其签名为 compile 方法(它是原始的 ) ,将实际的 compile 方法重命名为 compile$Impl 并添加了一些对我的 class 的调用。

复制是这样完成的:

CtMethod interceptMethod = CtNewMethod.copy(method, methodName, ctClass, null);

javassist 重写代码:

try { 
  com.company.CustomClass.instance().preintercept(this);
  boolean result = compile$impl($$);
  result = com.company.CustomClass.instance().dointercept(result, new Object[] { this ,  });
  return result;
 } finally { 
    com.company.CustomClass.instance().postintercept(this);
 }

代码写在一个名为 body 的 StringBuffer 变量中,后面的变量的内容被写为新的 compile 方法的主体,如下所示:

        interceptMethod.setBody(body.toString());
        ctClass.addMethod(interceptMethod);

我的 com.company.CustomClass 有新的 compile 方法调用的方法:

   public Object dointercept(boolean retval, Object.. args) {
        return (Boolean)returned;
    }

public static synchronized CustomClass instance() {
    // _instance is already instanciated when this method is called
    return _instance;
}

public void preintercept(Object arg) {
 // some stuff before
}

public void postintercept(Object arg) {
 // some stuff after

}

执行代码时出现验证错误:

java.lang.VerifyError: (class: org/eclipse/jdt/internal/compiler/batch/Main, method: compile signature: ([Ljava/lang/String;)Z) Expecting to find integer on stack

我已经将修改后的class的字节码写入磁盘,试图找出问题所在。这是我为新的 compile 方法得到的结果:

   public boolean compile(java.lang.String[] arg0) {
        try {
            0 invokestatic 2130;      /* com.company.CustomClass.instance() */
            3 aload_0;
            4 invokevirtual 2134;     /* void preintercept(java.lang.Object arg0) */
            7 aload_0;
            8 aload_1;
            9 invokevirtual 2136;     /* boolean compile$impl(java.lang.String[] arg0) */
            12 istore_2;
            13 invokestatic 2130;     /* com.company.CustomClass.instance() */
            16 iload_2;
            17 iconst_2;
            18 anewarray 4;           /* new java.lang.Object[] */
            21 dup;
            22 iconst_0;
            23 aload_0;
            24 aastore;
            25 dup;
            26 iconst_1;
            27 aload_1;
            28 aastore;
            29 invokevirtual 2140;    /* java.lang.Object dointercept(boolean arg0, java.lang.Object[] arg1) */
            32 istore_2;
            33 iload_2;
            34 istore_3;
            35 goto 17;
            38 iload_3;
            39 ireturn;
        }
        finally {                 /* covers bytes 0 to 40 */
            40 astore 4;
            42 invokestatic 2130;     /* com.company.CustomClass.instance() */
            45 aload_0;
            46 invokevirtual 2143;    /* void postintercept(java.lang.Object arg0) */
            49 aload 4;
            51 athrow;
            52 invokestatic 2130;     /* com.company.CustomClass.instance() */
            55 aload_0;
            56 invokevirtual 2143;    /* void postintercept(java.lang.Object arg0) */
            59 goto -21;
        }
    }

当我对 class 的字节码进行类型分析时,错误出现在第 32 行 istore_2 指令处。分析如下:

Type based analysis: compile([Ljava/lang/String;)Z
Offset  Bytecode        Stack before              Stack after               
----------------------------------------------------------------------------
0       invokestatic    <empty>                   L                         
3       aload_0         L                         L, L                      
4       invokevirtual   L, L                      <empty>                   
7       aload_0         <empty>                   L                         
8       aload_1         L                         L, L                      
9       invokevirtual   L, L                      I                         
12      istore_2        I                         <empty>                   
13      invokestatic    <empty>                   L                         
16      iload_2         L                         L, I                      
17      iconst_2        L, I                      L, I, I                   
18      anewarray       L, I, I                   L, I, L                   
21      dup             L, I, L                   L, I, L, L                
22      iconst_0        L, I, L, L                L, I, L, L, I             
23      aload_0         L, I, L, L, I             L, I, L, L, I, L          
24      aastore         L, I, L, L, I, L          L, I, L                   
25      dup             L, I, L                   L, I, L, L                
26      iconst_1        L, I, L, L                L, I, L, L, I             
27      aload_1         L, I, L, L, I             L, I, L, L, I, L          
28      aastore         L, I, L, L, I, L          L, I, L                   
29      invokevirtual   L, I, L                   L                         
32      istore_2        L                         <empty>                   
                        Error: Expecting to find I on stack, type on stack L. 

33      iload_2         <empty>                   I                         
34      istore_3        I                         <empty>                   
35      goto            <empty>                   <empty>                   
38      iload_3         <empty>                   I                         
39      ireturn         I                         <empty>                   
40      astore          L                         <empty>                   
42      invokestatic    <empty>                   L                         
45      aload_0         L                         L, L                      
46      invokevirtual   L, L                      <empty>                   
49      aload           <empty>                   L                         
51      athrow          L                         L                         
52      invokestatic    <empty>                   L                         
55      aload_0         L                         L, L                      
56      invokevirtual   L, L                      <empty>                   
59      goto            <empty>                   <empty>                   
----------------------------------------------------------------------------

但是我不明白为什么存储一个int会有问题,我知道 我不使用任何整数(我确定遗漏了一些东西)。

谢谢

这是因为 doIntercept 正在返回一个 Boolean Object,并且它被存储为指向对象的指针(即出现在 29 处的 L)。然后它尝试将该值存储到原始 boolean 中,即原始整数 I.

如果使用显式转换,或在末尾添加.booleanValue()

com.company.CustomClass.instance().dointercept(result, new Object[] { this ,  }).booleanValue();

它可能有用吗?

问题是它没有将对象的 'automatic unboxing' 编译为基元。

https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html