ASM:在类的方法中获取局部变量名称和值

时间:2018-04-26 20:32:16

标签: java instrumentation java-bytecode-asm

我想使用ASM提取类的方法中存在的局部变量名和值。请提供建议。

1 个答案:

答案 0 :(得分:1)

在Java字节码中,局部变量集中在局部列表中,该列表将在方法参数的开头(包括接收方-对this的引用)包含在内。然后,在声明局部变量时,接下来将分配它们。最后,如果不再要使用局部变量或参数,则会“释放”空间,以便可以将其再次用于另一个变量。

可以从MethodVisitor#visitLocalVariable(...)LocalVariableNode中获得局部变量名称及其在局部变量列表中的位置之间的关系(仅当该类已使用调试信息进行编译时)。

仅通过使用ASM查看字节码不能获得局部变量值,您必须添加指令以在所需的点打印局部变量的值。一种选择是检测商店指令并插入指令以在其之前记录值。

示例(假设所有变量均为int,对于其他类型,则需要调用log的重载版本)。

// In a AdviceAdapter
private static final Type VAR_LOGGER = Type.getInternalName(VarLogger.class);
private static final Method LOG_I = Method.getMethod("void log(int, int)");
private static final Method LOG_L = Method.getMethod("void log(long, int)");
private static final Method LOG_F = Method.getMethod("void log(float, int)");
private static final Method LOG_D = Method.getMethod("void log(double, int)");
private static final Method LOG_A = Method.getMethod("void log(Object, int)");

@Override
public void visitVarInsn(int opcode, int var) {
    if (isStoreOp(opcode)) {
        dup();
        push(var);
        invokeStatic(VAR_LOGGER, getLogMethod(opcode));
    }
    super.visitVarInsn(opcode, var);
}

private boolean isStoreOp(int opcode) {
    switch (opcode) {
        case ISTORE:
        case LSTORE:
        case FSTORE:
        case DSTORE:
        case ASTORE:
            return true;
        default:
            return false;
    }
}

private Method getLogMethod(int opcode) {
    switch (opcode) {
        case ISTORE: return LOG_I;
        case LSTORE: return LOG_L;
        case FSTORE: return LOG_F;
        case DSTORE: return LOG_D;
        case ASTORE: return LOG_A;
        default:
            throw new RuntimeException("Invalid store code: " + opcode);
    }
}

@Override
public void visitMaxs(int maxStack, int maxLocals) {
    super.visitMaxs(maxStack + 3, maxLocals);
}

注意:仅当您不使用visitMaxs时,才有必要覆盖COMPUTE_MAXS