ASM: получение имени и значения локальной переменной внутри метода класса - PullRequest
0 голосов
/ 26 апреля 2018

Я хочу извлечь имя локальной переменной и значения, присутствующие внутри метода класса, используя ASM. Пожалуйста, предоставьте предложение.

1 Ответ

0 голосов
/ 10 июля 2018

В Java Bytecode локальные переменные объединяются в список локальных объектов, который будет содержать в начале параметры метода (включая получатель - ссылку на 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.

...