"VerifyError: Accessing value from uninitialized register" when using ASM and javaagent to collect method arguments

"VerifyError: Accessing value from uninitialized register" when using ASM and javaagent to collect method arguments

进入一个方法时,我想记录那个方法的所有参数。由于 ASM 很难调试,我写了一些演示代码(使用@apangin 的收集器 class)并测试其有效性。但是,当我使用以下代码时,它报告 java.lang.VerifyError: (class: com/D, method: add signature: (II)I) Accessing value from uninitialized register 2

我认为在创建框架时,局部变量由this 和方法的参数初始化。但是register 2(我猜是局部变量中的第三个元素)应该由第二个int参数初始化,为什么它仍然抛出错误?

com/D代码:

public class D extends C {
    public D() { }

    public int a = 4;

    @Override
    public int p() { return a; }

    public static int add(int a, int b){
        return a+b;
    }
}

我的methodVisitor适配器中的visitCode方法class:

    public void visitCode() {
        mv.visitCode();
        if (needAnalysePurity){
            pushArgArrToStackInMeth();
            mv.visitInsn(POP);
        }
    }
    public void pushArgArrToStackInMeth(){
        Type[] args = Type.getArgumentTypes(this.selfDesc);
        // new ArgumentCollector(N)
        String collector = Type.getInternalName(ArgCollectorLocals.class);
        mv.visitTypeInsn(NEW, collector);
        mv.visitInsn(DUP);
        mv.visitIntInsn(SIPUSH, args.length);
        mv.visitMethodInsn(INVOKESPECIAL, collector, "<init>", "(I)V", false);

        // for each argument call the corresponding collector.add(arg)
        int index = 1;
        for (Type arg : args) {
            String argDesc = arg.getDescriptor();

            if (argDesc.length() > 1) {
                argDesc = "Ljava/lang/Object;";
            }
            mv.visitVarInsn(arg.getOpcode(ILOAD), index);
            mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(" + argDesc + ")L" + collector + ";", false);
            index += arg.getSize();
        }
        // collector.toArray()
        mv.visitMethodInsn(INVOKEVIRTUAL, collector, "toArray", "()[Ljava/lang/Object;", false);
    }

用于收集参数的收集器class:

public class ArgCollectorLocals {
    private final Object[] args;
    private int index;

    public ArgCollectorLocals(int length) {
        this.args = new Object[length];
    }

    public ArgCollectorLocals add(boolean a) {
        args[index++] = a;
        return this;
    }

    public ArgCollectorLocals add(byte a) {
        args[index++] = a;
        return this;
    }

    public ArgCollectorLocals add(char a) {
        args[index++] = a;
        return this;
    }

    public ArgCollectorLocals add(short a) {
        args[index++] = a;
        return this;
    }

    public ArgCollectorLocals add(int a) {
        args[index++] = a;
        return this;
    }

    public ArgCollectorLocals add(long a) {
        args[index++] = a;
        return this;
    }

    public ArgCollectorLocals add(float a) {
        args[index++] = a;
        return this;
    }

    public ArgCollectorLocals add(double a) {
        args[index++] = a;
        return this;
    }

    public ArgCollectorLocals add(Object a) {
        args[index++] = a;
        return this;
    }

    public Object[] toArray() {
        return args;
    }
}

感谢@apangin,我终于解决了这个问题。除了方法参数之外,我还想记录方法所属的实例(如果方法不是静态的),所以我有以下代码:

    public void pushArgArrToStackInMeth(){
        Type[] args = Type.getArgumentTypes(this.selfDesc);
        // new ArgumentCollector(N)
        String collector = Type.getInternalName(ArgCollectorLocals.class);
        mv.visitTypeInsn(NEW, collector);
        mv.visitInsn(DUP);
        if (isStatic){
            mv.visitIntInsn(SIPUSH, args.length);
        }else{
            mv.visitIntInsn(SIPUSH, args.length + 1);  // for this
        }
        mv.visitMethodInsn(INVOKESPECIAL, collector, "<init>", "(I)V", false);

        // record "this" if not static
        if (!isStatic){
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(Ljava/lang/Object;)L" + collector + ";", false);
        }

        // for each argument call the corresponding collector.add(arg)
        int index = 1;
        if (isStatic){
            index = 0;
        }
        for (Type arg : args) {
            String argDesc = arg.getDescriptor();
            if (argDesc.length() > 1) {
                argDesc = "Ljava/lang/Object;";
            }
            mv.visitVarInsn(arg.getOpcode(ILOAD), index);
            mv.visitMethodInsn(INVOKEVIRTUAL, collector, "add", "(" + argDesc + ")L" + collector + ";", false);
            index += arg.getSize();
        }
        // collector.toArray()
        mv.visitMethodInsn(INVOKEVIRTUAL, collector, "toArray", "()[Ljava/lang/Object;", false);
    }