Проверьте прыжок с ASM в Java - PullRequest
1 голос
/ 14 марта 2019

Я пытаюсь предотвратить бесполезность условных переходов, например, удалив:

if(1 > 10)  {
   return;
}

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

Код, который не работает:

Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);

for (int i = 0; i < frames.length; i++) {
    if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
        if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
            if(frames[i] == null)  {
                System.out.println("This jump is useless");
            }
        }
    }
}

Затем я попытался получить некоторые значения стека для вычисления вручнуюно безуспешно (я обнаружил, что не могу перенести код для его использования при переходах ASM Получить точное значение из стекового фрейма ):

Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);

for (int i = 0; i < frames.length; i++) {
    if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
        if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
            // getStackSize() returns 2 so -> 0 and 1
            frames[i].getStack(0); // this is probably 1
            frames[i].getStack(1); // this is probably 10
            // but it returns a BasicValue so I can't check if the code works or not (we cannot get values)
        }
    }
}

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

На самом деле я пытался создатьметод, который возвращает константу int, чтобы я мог определить, вызывается ли getValue в инструкциях перехода (если я обнаруживаю вызов, я, конечно, удаляю инструкции перехода и сам переход):

Пример:

if(1 > getValue())  { //getValue() returns 10
   return;
}

Код:

Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
ArrayList<AbstractInsnNode> nodesR = new ArrayList<>();

for (int i = 0; i < frames.length; i++) {
    if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
        if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
            ArrayList<AbstractInsnNode> toRemove = new ArrayList<>();

            for (int ia = 1; ia < frames[i].getMaxStackSize() + 2; ia++) { // I started from 1 and added 2 to getMaxStackSize because I wasn't getting all the instructions
                toRemove.add(mn.instructions.get(i - ia));
            }

            toRemove.add(mn.instructions.get(i)); // I add the jump to the list

            for (AbstractInsnNode aaa : toRemove) {
                if (aaa.getOpcode() == INVOKESTATIC) { // the invokestatic is getValue
                    for (AbstractInsnNode aaas : toRemove) {
                        nodesR.add(aaas);
                    }
                    break;
                 }
            }
        }
    }
}

for (AbstractInsnNode aaas : nodesR) {
    mn.instructions.remove(aaas);
}

} catch (AnalyzerException e) {
    e.printStackTrace();
}

Этот код, вероятно, ужасен и не оптимизирован, но я попробовал МНОГО вещей без какого-либо успеха.GetMaxStackSize () не возвращает число, которое является на 100% правильным (иногда оно не требует добавления и т. Д., Поэтому оно удаляет инструкции, такие как метки и т. Д.).

Что я пытаюсь сделать:

Анализ метода и проверка того, будет ли условный переход всегда ложным (поэтому код внутри никогда не будет выполнен), затем удалите его.Я пробовал два разных способа:

  • Используйте BasicInterpreter, чтобы проверить, будет ли этот переход выполняться с постоянными значениями, затем попробуйте, чтобы увидеть, будет ли он всегда ложным
  • Проверьте, еслипереход содержит определенный метод (например, getValue(), который возвращает 10 и сравнивает, если он меньше 1), затем удаляет его. Что я не понимаю:
  • Я думаю, что в каждой инструкции есть кадры и чтоон содержит таблицу локальных переменных и значения, которые использует фрейм - StackMap?- (например, если инструкция сравнится, если int меньше другого, она вернет [II], верно?
  • Я не знаю, смогу ли я использовать BasicInterpreter, чтобы проверить, всегда ли два постоянных целых числавернуть тот же результат
  • StackMap = Stack? или он отличается от StackMap как часть стека, который содержит необходимые значения для инструкции?
...