Модификация кода с помощью Javassist генерирует java.lang.VerifyError: ожидается найти целое число в стеке

Я использую javassist, чтобы переписать метод с именем compile (который принимает массив String в качестве аргумента): я создал новый метод, имеющий сигнатуру как метод compile (это копия исходного), переименовал фактический метод compile в compile$Impl и добавлено несколько обращений к классу Mine.

Копия делается так:

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 , $1 });
  return result;
 } finally { 
    com.company.CustomClass.instance().postintercept(this);
 }

Код записывается в переменную StringBuffer с именем body, а содержимое более поздней переменной записывается как тело нового метода 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

}

При выполнении кода я получил verifyError:

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

Я записал байт-код модифицированного класса на диск, чтобы попытаться обнаружить проблему. Вот что я получил для нового метода 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;
        }
    }

Когда я прошел анализ типов байт-кода класса, ошибка была в строке 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, зная, что я не использую целые числа (я уверен, что что-то упускаю).

Спасибо


person Master Mind    schedule 12.11.2015    source источник


Ответы (1)


Это потому, что doIntercept возвращает Boolean Object, и это сохраняется как указатель на объект (то есть L, который появляется в 29). Затем он пытается сохранить это значение в примитиве boolean, то есть в необработанном целом числе I.

Если вы используете явное приведение или добавляете .booleanValue() в конце

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

это может сработать?

Проблема в том, что он не скомпилировал «автоматическую распаковку» объектов в примитивы.

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

person Sanjay Manohar    schedule 12.11.2015