使用ASM插入FrameNode

时间:2016-04-29 13:35:14

标签: java bytecode java-bytecode-asm

我如何在字节码中插入framenode?

FRAME FULL [java/lang/String [C java/lang/String T I I [C] []

我的第一次尝试是:

mn.instructions.insertBefore(random, new FrameNode(Opcodes.F_FULL, 1 /**IDK**/,
    new Object[]{ "java/lang/String", "[C", "java/lang/String", "T", "I", "I", "[C]" },
    1/**IDK**/, new Object[] { "[C]","[]" }));

效果不佳。输出:

    FRAME FULL [[java/lang/String] [java/lang/String]

1 个答案:

答案 0 :(得分:3)

堆栈帧由许多局部变量和操作数堆栈上的许多值组成。您要重现的内容,显然是将该状态转换为人类可读的字符串形式的结果

FRAME FULL [list of local variables types] [list of operand stack time types]

您要做的第一件事就是从输出格式中识别括号,这需要了解所包含的类型签名,因为以[C开头括号开头的签名表示数组类型,即一个字符数组。换句话说,一些左括号是类型签名的一部分,其他是输出格式的一部分,而右括号始终是输出格式的一部分,并且永远不会出现在类型签名中。

然后,当您确定了两个组中的类型签名时,请提供适当的局部变量和操作数堆栈项的计数。在你的情况下,你有:

FRAME FULL // frame type
[          // start local variables
  java/lang/String
  [C
  java/lang/String
  T
  I
  I
  [C
] // seven local variables specified
[ // start of operand stack
] // empty operand stack

但是你必须开始考虑类型项的含义,遗憾的是它不能从打印输出中导出,只是重现相同的打印输出并不一定意味着正确的代码。

即,项TI可以分别引用具有完全限定名称TI的类,在这种情况下,传递"T"并且"I"FrameNode是正确的。但是,它们更有可能引用非类堆栈帧类型 int,它们必须在ASM中使用预定义的Integer常量引用:

new FrameNode(Opcodes.F_FULL, 7, new Object[] {
    "java/lang/String", "[C", "java/lang/String",
    Opcodes.TOP, Opcodes.INTEGER, Opcodes.INTEGER, "[C" }, 0, new Object[0]);