我正在使用ASM开发一个Java检测引擎,并且有一种情况,评估堆栈顶部有一个值,我想插入一个 ref (这是现有值之前的 getstatic 的结果。即考虑只有一个值的堆栈:value ->
,然后在 getstatic 之后我希望堆栈变成这样:ref, value ->
。
要执行此行为,我必须插入以下字节码: getsatic 和 swap 。使用ASM,我会做类似的事情(考虑mv
类型MethodVisitor
):
mv.visitFieldInsn(Opcodes.GETSTATIC, ...);
mv.visitInsn(Opcodes.SWAP);
问题是 swap 字节码不支持long
和double
值。因此,上面的代码适用于单个单词类型,但它对long
和double
类型无效。
是否有任何简单的解决方案可以解决long
和double
类型的此问题而无需辅助本地值?
答案 0 :(得分:4)
我们有双字值VV和ref值R.要从VV ...到VVR ...你可以将你的R值添加到堆栈的顶部(RVV ...),然后使用dup_x2( RVVR ......)然后弹出(VVR ......)。
答案 1 :(得分:2)
最简单的解决方案是使用局部变量来交换堆栈上的项目。 类似的东西:
DSTORE tmp
GETSTATIC ...
DLOAD tmp
答案 2 :(得分:2)
这里有一个ASM的实用程序函数,它注入字节码以交换堆栈顶部任何类型的操作数:
public static void swap(MethodVisitor mv, Type stackTop, Type belowTop) {
if (stackTop.getNumberSlots() == 1) {
if (belowTop.getNumberSlots() == 1) {
// Top = 1, below = 1
mv.visitInsn(Opcodes.SWAP);
} else {
// Top = 1, below = 2
mv.visitInsn(Opcodes.DUP_X2);
mv.visitInsn(Opcodes.POP);
}
} else {
if (belowTop.getNumberSlots() == 1) {
// Top = 2, below = 1
mv.visitInsn(Opcodes.DUP2_X1);
} else {
// Top = 2, below = 2
mv.visitInsn(Opcodes.DUP2_X2);
}
mv.visitInsn(Opcodes.POP2);
}
}
答案 3 :(得分:1)
使用序列dup2x2,pop2。
从堆栈上的XXYY开始,dup2x2给你YYXXYY,pop2离开YYXX。
答案 4 :(得分:0)
致电org.objectweb.asm.commons.GeneratorAdapter.swap(Type,Type)。它是这样实现的:
public void swap(final Type prev, final Type type) {
if (type.getSize() == 1) {
if (prev.getSize() == 1) {
swap(); // same as dupX1(), pop();
} else {
dupX2();
pop();
}
} else {
if (prev.getSize() == 1) {
dup2X1();
pop2();
} else {
dup2X2();
pop2();
}
}
}
答案 5 :(得分:-1)
我会确保堆栈按其所需的顺序加载而无需交换。
在优化代码方面,我建议您尝试生成尽可能接近javac
生成代码的代码,因为这是JVM优化后的优化。
如果无法做到这一点,您可以将值存储在局部变量中,按下ref
并重新加载值。