2

Мне удалось реализовать встроенную оптимизацию метода байт-кода, и сгенерированный код кажется мне удобным. Тем не менее, проверка завершается с сообщением:Построить FrameNode с ASM api

java.lang.VerifyError: Expecting a stackmap frame at branch target 47 
Exception Details: 
    Location: 
    code/sxu/asm/example/Caller.test(II)V @44: goto 
    Reason: 
    Expected stackmap frame at this location. 

И соответствующий байт-код:

public void test(int, int); 
    flags: ACC_PUBLIC 
    Code: 
     stack=4, locals=8, args_size=3 
     0: iload_1  
     1: iload_2  
     2: iadd   
     3: aload_0  
     4: getfield  #14     // Field _callee:Lcode/sxu/asm/example/Callee; 
     7: iload_1  
     8: iload_2  
     9: istore_3  
     10: istore  4 
     12: astore  5 
     14: aload   5 
     16: getfield  #40     // Field code/sxu/asm/example/Callee._a:Ljava/lang/String; 
     19: invokevirtual #46     // Method java/lang/String.length:()I 
     22: aload   5 
     24: getfield  #49     // Field code/sxu/asm/example/Callee._b:Ljava/lang/String; 
     27: invokevirtual #46     // Method java/lang/String.length:()I 
     30: iadd   
     31: istore  6 
     33: iload   6 
     35: iload   4 
     37: iload_3  
     38: iadd   
     39: iadd   
     40: istore  6 
     42: iload   6 
     44: goto   47 
     47: isub   
     48: istore  7 
     50: getstatic  #59     // Field java/lang/System.out:Ljava/io/PrintStream; 
     53: iload   7 
     55: invokevirtual #65     // Method java/io/PrintStream.println:(I)V 
     58: getstatic  #59     // Field java/lang/System.out:Ljava/io/PrintStream; 
     61: ldc   #67     // String 1.......... 
     63: invokevirtual #70     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     66: return   
     LocalVariableTable: 
     Start Length Slot Name Signature 
       14  33  0 this Lcode/sxu/asm/example/Callee; 
       14  33  1  t I 
       14  33  2  p I 
       33  14  7 tmp I 
       0  67  0 this Lcode/sxu/asm/example/Caller; 
       0  67  1  a I 
       0  67  2  b I 
       50  17  7  r I 
     LineNumberTable: 
     line 16: 0 
     line 13: 14 
     line 14: 33 
     line 15: 42 
     line 18: 50 
     line 19: 58 
     line 20: 66 
} 

Line 9-11: хранить сложенных параметры. Строка 14-44: встроенные байт-коды Callee, а последние ireturn заменены на GOTO.

два возможных решения для отказа в проверке Java7:

  • Добавить -XX:-UseSplitVerifier для VM аргумента. Опция работает, но она устарела в Java8.

  • Добавить таблицу таблиц стека перед строкой 44 (перед инструкцией GOTO), которая перечисляет типы в позициях, которые являются объектами прыжков (от Stackmap frame description).

Для меня предпочтительнее вариант 2, но у меня проблема в конструкции рамки. Мой код:

if (opcode == Opcodes.RETURN || opcode == Opcodes.IRETURN) { 
     FrameNode stackMap = new FrameNode(Opcodes.NEW, -1, null, -1, null); 
     stackMap.accept(mv); //Visit The framenode before GOTO 
     super.visitJumpInsn(Opcodes.GOTO, end); 
    } else { 
     super.visitInsn(opcode); 
    } 

Я думаю, что оба Opcodes.NEW/SMAE должны работать здесь. Но невозможно вычислить оставшиеся четыре аргумента, потому что посетитель не посетил целевые коды, и он не знает nStack, nlocals.

Так может кто-нибудь дать предложение в построении FrameNode здесь или примера для обработки этого дело? Благодарю.

Описание для FramNode FrameNode ASM Document:

общественного FrameNode (интермедиат типа, INT nLocal, Object [] локальная, INT nStack, Object [] стека)

Создает новый FrameNode.

Параметры:

type - the type of this frame. Must be Opcodes.F_NEW for expanded frames, or Opcodes.F_FULL, Opcodes.F_APPEND, Opcodes.F_CHOP, Opcodes.F_SAME or Opcodes.F_APPEND, Opcodes.F_SAME1 for compressed frames. 
nLocal - number of local variables of this stack map frame. 
local - the types of the local variables of this stack map frame. Elements of this list can be Integer, String or LabelNode objects (for primitive, reference and uninitialized types respectively - see MethodVisitor). 
nStack - number of operand stack elements of this stack map frame. 
stack - the types of the operand stack elements of this stack map frame. Elements of this list can be Integer, String or LabelNode objects (for primitive, reference and uninitialized types respectively - see MethodVisitor). 

ответ

2

условии, что ваш байт-код правильно, вы можете позволить ASM создать узлы кадров для вас.

Я обычно делаю это так:

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES) 
{ 
    @Override 
    protected String getCommonSuperClass(final String type1, final String type2) 
    { 
     // the default asm merge uses Class.forName(), this prevents that. 
     return "java/lang/Object"; 
    } 
}; 

cn.accept(cw); 

Разъяснение: инициализировать класс писателя с COMPUTE_FRAMES, и, чтобы избежать проблем загрузки классов перезаписать getCommonSuperClass.

Предполагая, что любой маршрут, который вы используете для генерации вашего байт-кода (посетителей, ClassNode и т. Д.), В конечном итоге вы используете ClassWriter для генерации байтов класса.

Если вы действительно хотите сделать это вручную, попробуйте это сначала, а затем используйте asmifier, чтобы узнать, как написать код кадра с помощью asm.

+0

В любом случае, я думаю, что жизнь слишком коротка, чтобы вручную анализировать кадры. –