Reputation: 129
I want to detect if one of the methods of a class mutates a certain instance field using ASM. For example:
public class Box {
public Object o;
public void mutate() {
o = new Object();
}
}
Question: is instance field o mutated by one of the methods of the class Box? In this case, yes.
Using the MethodNode class from the ASM tree library I can get the opcodes of the methods which look like this
-1 -1 25 187 89 183 181 -1 -1 177 -1
This array contains the opcode 181 for putfield, but how can I tel that it is the field Box.o that is assigned?
BTW: Why does the array contain the -1 values?
Tnx
Upvotes: 0
Views: 658
Reputation: 129
Also found another solution using the tree API, which is more suitable for my application:
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;
}
Upvotes: 0
Reputation: 533500
Not sure why you are looking at the raw byte code. I would look at the individual instructions.
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);
}
}
prints
... 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 ...
you can see that the method visitor is called with
mv.visitFieldInsn(PUTFIELD, "Box", "o", "Ljava/lang/Object;");
and this should tell you what you want to know.
If you have a constructor (and I suggest you do)
private Object o;
public Box(Object o) {
this.o = o;
}
you may want to treat this "mutation" differently because its in the constructor.
Upvotes: 2