Java ASM - 如何在方法

时间:2017-06-21 12:31:09

标签: java java-bytecode-asm

我尝试将AST编译为java类文件,使用ASM创建类本身。当我尝试向函数添加局部变量时(我正确创建了函数),我遇到了一个问题。

F.e。,这样一个简单的函数:

public void test() {
    int a = 10;
    int b = 11;
    int c = 12;
    int d = 1;
}

成为这个,一旦检测(用JD-GUI反编译):

public void test() {
    int i = 10;
    int j = 11;
    int k = 12;
    int m = 4;
}

这个字节码如下所示:

 public test() { //()V
         bipush 10
         istore1
         bipush 11
         istore2
         bipush 12
         istore3
         iconst_4
         istore4
         return
 }

我正在创建这样的局部变量:

methodVisitor.visitVarInsn(Opcodes.BIPUSH, symbol.value);
methodVisitor.visitVarInsn(Opcodes.ISTORE, position);

symbol是当前的局部变量,position是其索引,从1开始。 F.E. a位于1位置,d位于4位置。

我的问题是正确使用Opcodes表示不同的值。我尝试了Opcodes Opcodes.LDC,但是生成的类在其方法中没有任何局部变量,但所有全局定义的变量和函数都在那里两次。

将任意类型的变量和任意值添加到方法的正确方法是什么?

修改

根据评论,我试图将其他问题的答案结合起来:

MethodVisitor methodVisitor = cw.visitMethod(
        access,
        methodName,
        typeDescriptors,
        null,
        null
);

LocalVariablesSorter mv = new LocalVariablesSorter(access, typeDescriptors, methodVisitor);

然后我使用LocalVariablesSorter添加这样的局部变量:

// type is net.bytebuddy.jar.asm.Type.INT_TYPE
net.bytebuddy.jar.asm.Type type = getType(symbol.type);
int id = mv.newLocal(type);
mv.visitVarInsn(Opcodes.ISTORE, id);

反编译为:

/* Error */
public void test()
{
    // Byte code:
    //   0: istore_2
    //   1: istore 4
    //   3: istore 6
    //   5: istore 8
    //   7: return
}

产生这个字节码:

public test() { //()V
    istore2
    istore4
    istore6
    istore8
    return
}

我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

ISTORE指令将堆栈顶部的值存储到寄存器中。堆栈上没有值,这会导致验证错误。

例如,如果要存储值2,则需要先将值加载到堆栈中:

net.bytebuddy.jar.asm.Type type = getType(symbol.type);
int id = mv.newLocal(type);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitVarInsn(Opcodes.ISTORE, id);

"更高"值,还有其他说明,例如BIPUSHSIPUSH。否则,您可以使用LDC从常量池加载值。这通常是存储价值的最有效方式; ASM隐式地重复删除其中的值。