package edu.columbia.cs.psl.vmvm.asm.mvs; import edu.columbia.cs.psl.vmvm.Constants; import edu.columbia.cs.psl.vmvm.Instrumenter; import edu.columbia.cs.psl.vmvm.asm.JUnitResettingClassVisitor; import edu.columbia.cs.psl.vmvm.org.objectweb.asm.MethodVisitor; import edu.columbia.cs.psl.vmvm.org.objectweb.asm.Opcodes; import edu.columbia.cs.psl.vmvm.org.objectweb.asm.Type; import edu.columbia.cs.psl.vmvm.org.objectweb.asm.commons.GeneratorAdapter; import edu.columbia.cs.psl.vmvm.org.objectweb.asm.tree.ClassNode; import edu.columbia.cs.psl.vmvm.org.objectweb.asm.tree.FieldNode; import edu.columbia.cs.psl.vmvm.struct.MutableInstance; public class StaticFinalMutibleizer extends GeneratorAdapter implements Opcodes { private String mName; private String className; public StaticFinalMutibleizer(MethodVisitor mv, int access, String className, String name, String desc) { super(Opcodes.ASM5, mv, access, name, desc); this.mName = name; this.className = className; } private boolean isFinalField(String owner, String name) { if(name.equals(Constants.VMVM_NEEDS_RESET)) return false; if(name.equals(Constants.VMVM_RESET_IN_PROGRESS)) return false; if(JUnitResettingClassVisitor.shouldIgnoreClass(owner)) return false; if(Instrumenter.mutablizedFields.containsKey(owner + "." + name)) return true; ClassNode owningNode = Instrumenter.getClassNodeWithField(owner,name); if(owningNode == null) return false; else if((owningNode.access & Opcodes.ACC_INTERFACE) != 0){ FieldNode fn = Instrumenter.getFieldNode(owner, name); if(fn!= null && fn.value == null) return true; return false; } return false; } @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) { if ((opcode == GETSTATIC || opcode == PUTSTATIC) && isFinalField(owner,name)) { Type originalType = Type.getType(desc); if (opcode == GETSTATIC) { super.visitFieldInsn(opcode, owner, name, Type.getDescriptor(MutableInstance.class)); super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MutableInstance.class), "get", "()Ljava/lang/Object;", false); if (originalType.getSort() == Type.OBJECT || originalType.getSort() == Type.ARRAY) { super.visitTypeInsn(CHECKCAST, originalType.getInternalName()); } else//primitive needs to be cast to the boxed type then unboxed { String checkCastTo = null; switch (originalType.getSort()) { case Type.BYTE: checkCastTo = Type.getInternalName(Byte.class); break; case Type.BOOLEAN: checkCastTo = Type.getInternalName(Boolean.class); break; case Type.SHORT: checkCastTo = Type.getInternalName(Short.class); break; case Type.CHAR: checkCastTo = Type.getInternalName(Character.class); break; case Type.INT: checkCastTo = Type.getInternalName(Integer.class); break; case Type.FLOAT: checkCastTo = Type.getInternalName(Float.class); break; case Type.LONG: checkCastTo = Type.getInternalName(Long.class); break; case Type.DOUBLE: checkCastTo = Type.getInternalName(Double.class); break; } super.visitTypeInsn(CHECKCAST, checkCastTo); unbox(originalType); } } else { if (!(originalType.getSort() == Type.OBJECT || originalType.getSort() == Type.ARRAY)) { super.box(originalType); } super.visitFieldInsn(GETSTATIC, owner, name, Type.getDescriptor(MutableInstance.class)); super.visitInsn(SWAP); super.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(MutableInstance.class), "put", "(Ljava/lang/Object;)V"); } } else super.visitFieldInsn(opcode, owner, name, desc); } }