View Javadoc

1   /*
2    *
3    */
4   package org.softevo.jdynpur.runtime;
5   
6   import org.objectweb.asm.MethodAdapter;
7   import org.objectweb.asm.MethodVisitor;
8   import org.objectweb.asm.Opcodes;
9   import org.softevo.util.ObjectIdMapper;
10  import org.softevo.util.asm.FieldIdentifier;
11  
12  public class FieldWriteTracingVisitor extends MethodAdapter implements Opcodes {
13  
14  	protected boolean isConstructor = false;
15  
16  	protected boolean isAfterConstructorCall = false;
17  
18  	protected String className = null;
19  
20  	protected String superClassName = null;
21  
22  	private ObjectIdMapper<FieldIdentifier> fieldIdentifierMap;
23  
24  	public FieldWriteTracingVisitor(MethodVisitor mv, String methodName, 
25  	                                String className, String superClassName,
26  	                                ObjectIdMapper<FieldIdentifier> fieldIdentifierMap) {
27  		super(mv);
28  		isConstructor = methodName.equals("<init>");
29  		this.className = className;
30  		this.superClassName = superClassName;
31  		this.fieldIdentifierMap = fieldIdentifierMap;
32  	}
33  
34  	@Override
35  	public void visitMethodInsn(int opCode, String owner, String name, String desc) {
36  		if (isConstructor && (opCode == INVOKESPECIAL) && name.equals("<init>")
37  				&& (owner.equals(className) || owner.equals(superClassName))) {
38  			isAfterConstructorCall = true;
39  		}
40  		super.visitMethodInsn(opCode, owner, name, desc);
41  	}
42  
43  	@Override
44  	public void visitFieldInsn(int opCode, String className, String fieldName, String typeDesc) {
45  		if (!isConstructor || isAfterConstructorCall) {
46  			FieldIdentifier identifier = new FieldIdentifier(className, fieldName, typeDesc);
47  			int id;
48  			if (!fieldIdentifierMap.contains(identifier)) {
49  			  id = fieldIdentifierMap.add(identifier);
50  			} else {
51  				id = fieldIdentifierMap.getId(identifier);
52  			}
53  			// we are interested in static and object field writes
54  			if ((opCode == PUTFIELD) || (opCode == PUTSTATIC)) {
55  				if (opCode == PUTFIELD) {
56  					// instructions for 2 word and 1 word fields differ
57  					if (!identifier.isComplexType()) {
58  						if (typeDesc.equals("D") || typeDesc.equals("J")) {
59  							super.visitInsn(DUP2_X1);
60  							super.visitInsn(POP2);
61  							super.visitInsn(DUP_X2);
62  						} else {
63  							super.visitInsn(SWAP);
64  							super.visitInsn(DUP_X1);
65  						}
66  						super.visitMethodInsn(INVOKESTATIC, OnTheFlyInstrumenter.TRACECLASSNAME, "fieldWritten",
67  						"(Ljava/lang/Object;)V");
68  					} else {
69  						super.visitInsn(DUP2);
70  						super.visitLdcInsn(new Integer(id));
71  						super.visitMethodInsn(INVOKESTATIC, OnTheFlyInstrumenter.TRACECLASSNAME, "objectFieldWritten",
72  						"(Ljava/lang/Object;Ljava/lang/Object;I)V");
73  					}
74  				} else {
75  					// trace static field write
76  					super.visitMethodInsn(INVOKESTATIC, OnTheFlyInstrumenter.TRACECLASSNAME, "staticFieldWritten", "()V");
77  				}
78  				// add original instruction
79  				super.visitFieldInsn(opCode, className, fieldName, typeDesc);
80  			} else {
81  				super.visitFieldInsn(opCode, className, fieldName, typeDesc);
82  			}
83  		} else {
84  			super.visitFieldInsn(opCode, className, fieldName, typeDesc);
85  		}
86  	}
87  
88  
89  }