Мне удалось реализовать встроенную оптимизацию метода байт-кода, и сгенерированный код кажется мне удобным. Тем не менее, проверка завершается с сообщением:Построить 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).
В любом случае, я думаю, что жизнь слишком коротка, чтобы вручную анализировать кадры. –