Search code examples
javajava-bytecode-asm

How to get count and types of method parameters using org.objectweb.asm.MethodVisitor?


I'm trying to extract method parameters information from Java class bytecode using asm MethodVisitor. visitParameter method of MethodVisitor is not called (because no parameter names are present in compiled class file). How can i get count of method parameters and their types?

The only thing I've found so far is desc parameter of visitMethod from MethodVisitor. I can copy-paste TraceSignatureVisitor class from asm-util, rewrite about 50 lines of code to store parameters declarations into List/array instead of single StringBuffer.

Another option is suggested by in answer "https://stackoverflow.com/questions/18061588/get-function-arguments-values-using-java-asm-for-bytecode-instrimentation":

The number of arguments to the method can be computed from the method description using the code in the following gist: https://gist.github.com/VijayKrishna/6160036. Using the parseMethodArguments(String desc) method you can easily compute the number of arguments to the method.

From my point of view copy-pasting and rewriting TraceSignatureVisitor is still better.

But i suppose there should be more simple way to work with method signatures in asm-util. Is there?


Solution

  • ASM has an abstract for that purpose, Type.

    Instances of Type may represent a primitive type, a reference type, or a method type. So you can first get a type to represent the method type from the descriptor string, followed by querying it for the parameter types and return type.

    String desc = "(Ljava/lang/String;I[[ZJ)D";
    
    Type methodType = Type.getMethodType(desc);
    int sizes = methodType.getArgumentsAndReturnSizes();
    System.out.println("return type: "
        + methodType.getReturnType().getClassName() + " (" +(sizes & 3) + ')');
    
    Type[] argTypes = methodType.getArgumentTypes();
    System.out.println(argTypes.length + " arguments (" + (sizes >> 2) + ')');
    for (int ix = 0; ix < argTypes.length; ix++) {
        System.out.println("arg" + ix + ": " + argTypes[ix].getClassName());
    }
    

    The sizes returned by getArgumentsAndReturnSizes() refer to local variables and operand stack entries, where long and double count as two. It also accounts for the implied this parameter, which is convenient for an instance method but requires the caller to subtract one for static methods.

    The example prints

    return type: double (2)
    4 arguments (6)
    arg0: java.lang.String
    arg1: int
    arg2: boolean[][]
    arg3: long
    

    If you are interested in one of the features only, you can get it directly using one of the static methods of the Type class.

    int sizes = Type.getArgumentsAndReturnSizes(desc);
    Type ret = Type.getReturnType(desc);
    Type[] argTypes = Type.getArgumentTypes(desc);