Обнаружение мутации поля с использованием ASM - PullRequest
0 голосов
/ 09 марта 2012

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

public class Box {
    public Object o;

    public void mutate() {
        o = new Object();
    }
}

Вопрос: изменено ли поле экземпляра o одним из методов класса Box? В этом случае да.

Используя класс MethodNode из библиотеки дерева ASM, я могу получить коды операций методов, которые выглядят следующим образом

-1 -1 25 187 89 183 181 -1 -1 177 -1

Этот массив содержит код операции 181 для putfield, но как я могу сказать, что ему назначено поле Box.o?

Кстати: почему массив содержит значения -1?

Tnx

Ответы [ 2 ]

2 голосов
/ 09 марта 2012

Не уверен, почему вы смотрите на сырой байт-код. Я бы посмотрел на отдельные инструкции.

public class Box {
    public Object o;

    public void mutate() {
        o = new Object();
    }

    public static void main(String... args) throws IOException {
        ClassReader cr = new ClassReader(Box.class.getName());
        ASMifierClassVisitor acv = new ASMifierClassVisitor(new PrintWriter(System.out));
        cr.accept(acv, 0);
    }
}

печать

... lots of code ...
{
mv = cw.visitMethod(ACC_PUBLIC, "mutate", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(11, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitTypeInsn(NEW, "java/lang/Object");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitFieldInsn(PUTFIELD, "Box", "o", "Ljava/lang/Object;");
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(12, l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLocalVariable("this", "LBox;", null, l0, l2, 0);
mv.visitMaxs(3, 1);
mv.visitEnd();
}
... more code ...

вы можете видеть, что посетитель метода вызывается с

mv.visitFieldInsn(PUTFIELD, "Box", "o", "Ljava/lang/Object;");

и это должно сказать вам, что вы хотите знать.


Если у вас есть конструктор (и я предлагаю вам сделать)

private Object o;

public Box(Object o) {
    this.o = o;
}

Возможно, вы захотите трактовать эту «мутацию» иначе, потому что она в конструкторе.

0 голосов
/ 14 марта 2012

Также найдено другое решение с использованием дерева API, которое больше подходит для моего приложения:

private boolean methodMutatesField(List<MethodNode> methods, FieldNode field, ClassNode fieldOwner) {

    for(MethodNode methodNode : methods) {
        Iterator<AbstractInsnNode> instructionIterator = methodNode.instructions.iterator();

        while (instructionIterator.hasNext()) {
            AbstractInsnNode abstractInsNode = instructionIterator.next();

            if(abstractInsNode.getType() != AbstractInsnNode.FIELD_INSN) {  
                continue;
            } 

            FieldInsnNode fieldInsnNode = (FieldInsnNode) abstractInsNode;

            if(fieldInsnNode.getOpcode() != Opcodes.PUTFIELD) {
                continue;
            }

            if(fieldInsnNode.name.equals(field.name) && fieldInsnNode.owner.equals(fieldOwner.name)) {
                return true;
            }
        }
    }

    return false;
}
...