ASM объединяет два объекта-значения в интерпретаторе

Я продолжаю исследовать эмуляцию метода и получать реальное значение при прохождении инструкции ILOAD. После помощи Хольгера с Интерпретатором и после добавления новых операций с локальной переменной в main() метод, который я застрял с merge(V a, V b) метод, который должен быть переопределен при расширении Interpreter,

@Override
public LocalValue merge(LocalValue valueA, LocalValue valueB) {
    if (Objects.equals(valueA, valueB)) return valueA;
    else return new LocalValue(basicInterpreter.merge(valueA.type, valueB.type), null);
}

Но похоже это не правильно написано. Я могу попробовать разные логические переменные, что возвращать, но не понимая, в каких случаях значения могут сливаться, я не могу этого найти. Там нет полезной информации, которую я пытался найти в учебнике по javadocs и asm-4. Итак, что мне нужно вернуть, когда:
- Одно значение равно нулю, а другое - нет
- Оба значения не нулевые, одного типа, но разные объекты (например, 0 и 5)
- Оба значения не являются нулевыми, разные типы

basicInterpreter:

private BasicInterpreter basicInterpreter = new BasicInterpreter();

LocalValue:

public static class LocalValue implements Value {
    Object value;
    BasicValue type;

    public LocalValue(BasicValue type, Object value) {
        this.value = value;
        this.type = type;
    }
    @Override public int getSize() {return type.getSize();}
    @Override public String toString() {return value == null ? "null" : value.toString();}
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof LocalValue)) return false;
        LocalValue otherV = (LocalValue) obj;
        return Objects.equals(otherV.type, type) && Objects.equals(otherV.value, value);
    }
}

1 ответ

Значения необходимо объединять, когда инструкция может быть достигнута через разные пути кода, например, когда у вас есть условные выражения, циклы или обработчики исключений.

Поэтому, когда значение одинаково, независимо от того, какой путь к коду был выбран, вы можете сохранить его, иначе значение больше не является предсказуемой константой. Так в моем коде, где null был использован для обозначения неизвестных значений, он всегда возвращает null когда значения отличаются.

Так что, когда у вас есть код вроде

void foo(int arg) {
    int i = 1;
    int j = arg%2==0? i: arg;
}

Значения для arg, iи значение в стеке операндов объединяется непосредственно перед присваиванием j, arg уже имеет непредсказуемое значение, i имеет значение 1 в каждом пути кода, но значение в стеке операндов, которое должно быть назначено j имеет разные значения, 1 или "неизвестно", в зависимости от того, какой путь к коду был взят.

Вы можете решить сохранить набор возможных значений, если хотите, но когда одно из возможных значений "неизвестно", результатом объединения будет любое значение, следовательно, "неизвестно".

Другие вопросы по тегам