用于double和long值的Java字节码SWAP?

时间:2012-07-05 08:14:51

标签: java jvm java-bytecode-asm

我正在使用ASM开发一个Java检测引擎,并且有一种情况,评估堆栈顶部有一个,我想插入一个 ref (这是现有之前的 getstatic 的结果。即考虑只有一个值的堆栈value ->,然后在 getstatic 之后我希望堆栈变成这样:ref, value ->

要执行此行为,我必须插入以下字节码: getsatic swap 。使用ASM,我会做类似的事情(考虑mv类型MethodVisitor):

mv.visitFieldInsn(Opcodes.GETSTATIC, ...);
mv.visitInsn(Opcodes.SWAP);

问题是 swap 字节码不支持longdouble值。因此,上面的代码适用于单个单词类型,但它对longdouble类型无效。

是否有任何简单的解决方案可以解决longdouble类型的此问题而无需辅助本地值?

6 个答案:

答案 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并重新加载值。