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

Determine if last parameter is used

我正在使用 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文件。这使我的功能失败。我的函数对函数 "bk" 有效,但对函数 "j" 无效,因为 "j" 参数从 0 开始。

这意味着对于一些函数,最后一个参数相当于types.length - 1,有些是types.length。

我能算出最后一个参数 (VarInsnNode) 的编号吗?

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

The Java Virtual Machine uses local variables to pass parameters on method invocation. On class method invocation, any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language). Any parameters are subsequently passed in consecutive local variables starting from local variable 1.

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

ASM 的 Type.getArgumentsAndReturnSizes 方法可能在这里有所帮助,尽管 Javadoc 说 "plus one for the implicit this",因此它可能无法正确处理静态方法,并且它 returns 总大小,即 1 或比最后一个用于传递参数的局部变量槽的索引多2(取决于最后一个参数类型)。