Search code examples
javabytecodejava-bytecode-asm

Determine if last parameter is used


I'm using the ASM library and trying to figure out how it gets its numbering and how to determine whether or not the last parameter is used..

What I did so far was:

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);

                    }
                }
            }
        }

    }
}

However, some methods the parameters are named as follows:

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

and some are:

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

What I want to know, is why some of them start with 0 and some start with 1. I know this because I decompiled the jar file using fernflower. This makes my function fail. My function works for function "bk" but fails for function "j" because "j" parameters start at 0.

This means that for some functions, the last parameter is equivalent to types.length - 1 and some are types.length.

Is there anyway I can figure out number of the last parameter (VarInsnNode)?


Solution

  • Instance methods take the receiver (this) as the first argument, while class (static) methods do not. 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.

    From the same section, you'll see that local variables of type long and double take 2 local variable slots, while variables of all other JVM types take 1. Thus you can compute the local variable slot used by the last parameter based on the method's parameter types and whether the method is instance or static.

    ASM's Type.getArgumentsAndReturnSizes method may help here, though the Javadoc says "plus one for the implicit this", so it may not handle static methods correctly, and it returns the total size, which is 1 or 2 (depending on the last parameter type) more than the index of the last local variable slot used to pass parameters.