确定是否使用了最后一个参数

时间:2015-01-12 01:57:42

标签: java bytecode java-bytecode-asm

我正在使用ASM库并尝试弄清楚它是如何得到它的编号以及如何确定是否使用了最后一个参数..

到目前为止我做的是:

Collection<ClassNode> classes = readJar("...");

for (ClassNode c : classes) {
    for (MethodNode m : c) {

        Type[] types = Type.getArgumentTypes(m.desc);

        if (types.length > 0) {
            for (int i = 0; i < method.instructions.size(); ++i) {
                if (method.instructions.get(i) instanceof VarInsnNode) {
                    VarInsnNode v = ((VarInsnNode) method.instructions.get(i));

                    if (v.var == types.length) { //last parameter is used..

                        System.out.println(v.var);

                    }
                }
            }
        }

    }
}

但是,有些方法的参数命名如下:

static int j(int var0, int var1) {
    return var1 < 0 ? something() : somethingElse();
}

有些是:

void bk(bg var1, int var2, int var3) {
    this.r = var1;
    this.s = var2;
    this.t = var3;
}

我想知道的是,为什么有些人从0开始,有些从1开始。我知道这是因为我使用fernflower反编译jar文件。这使我的功能失败。我的功能适用于功能&#34; bk&#34;但功能失败&#34; j&#34;因为&#34; j&#34;参数从0开始。

这意味着对于某些函数,最后一个参数等同于types.length - 1,其中一些是types.length。

无论如何我可以找出最后一个参数的数量(VarInsnNode)?

1 个答案:

答案 0 :(得分:3)

实例方法将接收者(this)作为第一个参数,而类(static)方法则不然。 JVMS 2.6.1

  

Java虚拟机使用局部变量在方法调用上传递参数。在类方法调用中,任何参数都在从局部变量0开始的连续局部变量中传递。在实例方法调用中,局部变量0总是用于传递对调用实例方法的对象的引用(这在Java中)编程语言)。随后,任何参数都在从局部变量1开始的连续局部变量中传递。

在同一部分中,您将看到类型longdouble的局部变量占用2个局部变量槽,而所有其他JVM类型的变量占用1.因此您可以计算最后一个参数使用的局部变量槽,基于方法的参数类型以及方法是实例还是静态。

ASM的Type.getArgumentsAndReturnSizes方法在这里可能有所帮助,虽然Javadoc说&#34;加上一个用于隐含的&#34;,所以它可能无法正确处理静态方法,并返回总数size,为1或2(取决于最后一个参数类型),大于用于传递参数的最后一个局部变量槽的索引。